auto adjust code

This commit is contained in:
Christopher Homberger
2026-02-22 20:58:46 +01:00
parent 949a40c7a5
commit d187ac2fc1
86 changed files with 617 additions and 617 deletions

View File

@@ -5,12 +5,14 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
"strconv"
"strings" "strings"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
@@ -176,7 +178,7 @@ func bugReport(ctx context.Context, version string) error {
report += sprintf("Variant:", "https://gitea.com/actions-oss/act-cli / https://github.com/actions-oss/act-cli") report += sprintf("Variant:", "https://gitea.com/actions-oss/act-cli / https://github.com/actions-oss/act-cli")
report += sprintf("GOOS:", runtime.GOOS) report += sprintf("GOOS:", runtime.GOOS)
report += sprintf("GOARCH:", runtime.GOARCH) report += sprintf("GOARCH:", runtime.GOARCH)
report += sprintf("NumCPU:", fmt.Sprint(runtime.NumCPU())) report += sprintf("NumCPU:", strconv.Itoa(runtime.NumCPU()))
var dockerHost string var dockerHost string
var exists bool var exists bool
@@ -199,15 +201,21 @@ func bugReport(ctx context.Context, version string) error {
} }
report += sprintf("Config files:", "") report += sprintf("Config files:", "")
var reportSb202 strings.Builder
var reportSb205 strings.Builder
for _, c := range configLocations() { for _, c := range configLocations() {
args := readArgsFile(c, false) args := readArgsFile(c, false)
if len(args) > 0 { if len(args) > 0 {
report += fmt.Sprintf("\t%s:\n", c) fmt.Fprintf(&reportSb202, "\t%s:\n", c)
var reportSb206 strings.Builder
for _, l := range args { for _, l := range args {
report += fmt.Sprintf("\t\t%s\n", l) fmt.Fprintf(&reportSb206, "\t\t%s\n", l)
} }
reportSb205.WriteString(reportSb206.String())
} }
} }
report += reportSb205.String()
report += reportSb202.String()
vcs, ok := debug.ReadBuildInfo() vcs, ok := debug.ReadBuildInfo()
if ok && vcs != nil { if ok && vcs != nil {
@@ -220,9 +228,11 @@ func bugReport(ctx context.Context, version string) error {
report += sprintf("\tMain checksum:", vcs.Main.Sum) report += sprintf("\tMain checksum:", vcs.Main.Sum)
report += fmt.Sprintln("\tBuild settings:") report += fmt.Sprintln("\tBuild settings:")
var reportSb223 strings.Builder
for _, set := range vcs.Settings { for _, set := range vcs.Settings {
report += sprintf(fmt.Sprintf("\t\t%s:", set.Key), set.Value) reportSb223.WriteString(sprintf(fmt.Sprintf("\t\t%s:", set.Key), set.Value))
} }
report += reportSb223.String()
} }
info, err := container.GetHostInfo(ctx) info, err := container.GetHostInfo(ctx)
@@ -245,13 +255,15 @@ func bugReport(ctx context.Context, version string) error {
report += sprintf("\tOS version:", info.OSVersion) report += sprintf("\tOS version:", info.OSVersion)
report += sprintf("\tOS arch:", info.Architecture) report += sprintf("\tOS arch:", info.Architecture)
report += sprintf("\tOS kernel:", info.KernelVersion) report += sprintf("\tOS kernel:", info.KernelVersion)
report += sprintf("\tOS CPU:", fmt.Sprint(info.NCPU)) report += sprintf("\tOS CPU:", strconv.Itoa(info.NCPU))
report += sprintf("\tOS memory:", fmt.Sprintf("%d MB", info.MemTotal/1024/1024)) report += sprintf("\tOS memory:", fmt.Sprintf("%d MB", info.MemTotal/1024/1024))
report += fmt.Sprintln("\tSecurity options:") report += fmt.Sprintln("\tSecurity options:")
var reportSb252 strings.Builder
for _, secopt := range info.SecurityOptions { for _, secopt := range info.SecurityOptions {
report += fmt.Sprintf("\t\t%s\n", secopt) fmt.Fprintf(&reportSb252, "\t\t%s\n", secopt)
} }
report += reportSb252.String()
fmt.Println(report) fmt.Println(report)
return nil return nil
@@ -261,7 +273,7 @@ func generateManPage(cmd *cobra.Command) error {
header := &doc.GenManHeader{ header := &doc.GenManHeader{
Title: "act", Title: "act",
Section: "1", Section: "1",
Source: fmt.Sprintf("act %s", cmd.Version), Source: "act " + cmd.Version,
} }
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
cobra.CheckErr(doc.GenMan(cmd, header, buf)) cobra.CheckErr(doc.GenMan(cmd, header, buf))
@@ -575,7 +587,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
} }
if plan != nil { if plan != nil {
if len(plan.Stages) == 0 { if len(plan.Stages) == 0 {
plannerErr = fmt.Errorf("could not find any stages to run. View the valid jobs with `act --list`. Use `act --help` to find how to filter by Job ID/Workflow/Event Name") plannerErr = errors.New("could not find any stages to run. View the valid jobs with `act --list`. Use `act --help` to find how to filter by Job ID/Workflow/Event Name")
} }
} }
if plan == nil && plannerErr != nil { if plan == nil && plannerErr != nil {
@@ -611,7 +623,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
log.Warnf(deprecationWarning, "privileged", "--privileged") log.Warnf(deprecationWarning, "privileged", "--privileged")
} }
if len(input.usernsMode) > 0 { if len(input.usernsMode) > 0 {
log.Warnf(deprecationWarning, "userns", fmt.Sprintf("--userns=%s", input.usernsMode)) log.Warnf(deprecationWarning, "userns", "--userns="+input.usernsMode)
} }
if len(input.containerCapAdd) > 0 { if len(input.containerCapAdd) > 0 {
log.Warnf(deprecationWarning, "container-cap-add", fmt.Sprintf("--cap-add=%s", input.containerCapAdd)) log.Warnf(deprecationWarning, "container-cap-add", fmt.Sprintf("--cap-add=%s", input.containerCapAdd))
@@ -699,9 +711,9 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
var r runner.Runner var r runner.Runner
if eventName == "workflow_call" { if eventName == "workflow_call" {
// Do not use the totally broken code and instead craft a fake caller // Do not use the totally broken code and instead craft a fake caller
convertedInputs := make(map[string]interface{}) convertedInputs := make(map[string]any)
for k, v := range inputs { for k, v := range inputs {
var raw interface{} var raw any
if err := yaml.Unmarshal([]byte(v), &raw); err != nil { if err := yaml.Unmarshal([]byte(v), &raw); err != nil {
return fmt.Errorf("failed to unmarshal input %s: %w", k, err) return fmt.Errorf("failed to unmarshal input %s: %w", k, err)
} }

View File

@@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"maps" "maps"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"sync" "sync"
@@ -145,7 +146,7 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
var stepIds []string var stepIds []string
for i, v := range job.Steps { for i, v := range job.Steps {
if v.ID == "" { if v.ID == "" {
v.ID = fmt.Sprint(i) v.ID = strconv.Itoa(i)
} }
stepIds = append(stepIds, v.ID) stepIds = append(stepIds, v.ID)
} }
@@ -204,7 +205,7 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
// maxLifetime = time.Until(deadline) // maxLifetime = time.Until(deadline)
// } // }
actCtx := map[string]interface{}{} actCtx := map[string]any{}
forgeCtx := task.Context.AsMap() forgeCtx := task.Context.AsMap()
actCtx["github"] = forgeCtx actCtx["github"] = forgeCtx
actCtx["gitea"] = forgeCtx actCtx["gitea"] = forgeCtx

View File

@@ -10,7 +10,7 @@ import (
// It behaves like the C# implementation in the repository // It behaves like the C# implementation in the repository
// it supports escaped braces and numeric argument indices. // it supports escaped braces and numeric argument indices.
// Format specifiers (e.g. :D) are recognised but currently ignored. // Format specifiers (e.g. :D) are recognised but currently ignored.
func Format(formatStr string, args ...interface{}) (string, error) { func Format(formatStr string, args ...any) (string, error) {
var sb strings.Builder var sb strings.Builder
i := 0 i := 0
for i < len(formatStr) { for i < len(formatStr) {
@@ -47,7 +47,7 @@ func Format(formatStr string, args ...interface{}) (string, error) {
} }
// append argument (format specifier is ignored here) // append argument (format specifier is ignored here)
arg := args[idx] arg := args[idx]
sb.WriteString(fmt.Sprintf("%v", arg)) fmt.Fprintf(&sb, "%v", arg)
if spec != "" { if spec != "" {
// placeholder for future specifier handling // placeholder for future specifier handling
_ = spec _ = spec

View File

@@ -93,14 +93,14 @@ func (o CaseSensitiveObject[T]) GetEnumerator() map[string]T {
type EvaluationResult struct { type EvaluationResult struct {
context *EvaluationContext context *EvaluationContext
level int level int
value interface{} value any
kind ValueKind kind ValueKind
raw interface{} raw any
omitTracing bool omitTracing bool
} }
// NewEvaluationResult creates a new EvaluationResult. // NewEvaluationResult creates a new EvaluationResult.
func NewEvaluationResult(context *EvaluationContext, level int, val interface{}, kind ValueKind, raw interface{}, omitTracing bool) *EvaluationResult { func NewEvaluationResult(context *EvaluationContext, level int, val any, kind ValueKind, raw any, omitTracing bool) *EvaluationResult {
er := &EvaluationResult{context: context, level: level, value: val, kind: kind, raw: raw, omitTracing: omitTracing} er := &EvaluationResult{context: context, level: level, value: val, kind: kind, raw: raw, omitTracing: omitTracing}
if !omitTracing { if !omitTracing {
er.traceValue() er.traceValue()
@@ -112,10 +112,10 @@ func NewEvaluationResult(context *EvaluationContext, level int, val interface{},
func (er *EvaluationResult) Kind() ValueKind { return er.kind } func (er *EvaluationResult) Kind() ValueKind { return er.kind }
// Raw returns the raw value that was passed to the constructor. // Raw returns the raw value that was passed to the constructor.
func (er *EvaluationResult) Raw() interface{} { return er.raw } func (er *EvaluationResult) Raw() any { return er.raw }
// Value returns the canonical value. // Value returns the canonical value.
func (er *EvaluationResult) Value() interface{} { return er.value } func (er *EvaluationResult) Value() any { return er.value }
// IsFalsy implements the logic from the C# class. // IsFalsy implements the logic from the C# class.
func (er *EvaluationResult) IsFalsy() bool { func (er *EvaluationResult) IsFalsy() bool {
@@ -195,7 +195,7 @@ func (er *EvaluationResult) ConvertToString() string {
} }
// TryGetCollectionInterface returns the underlying collection if the value is an array or object. // TryGetCollectionInterface returns the underlying collection if the value is an array or object.
func (er *EvaluationResult) TryGetCollectionInterface() (interface{}, bool) { func (er *EvaluationResult) TryGetCollectionInterface() (any, bool) {
switch v := er.value.(type) { switch v := er.value.(type) {
case ReadOnlyArray[any]: case ReadOnlyArray[any]:
return v, true return v, true
@@ -207,7 +207,7 @@ func (er *EvaluationResult) TryGetCollectionInterface() (interface{}, bool) {
} }
// CreateIntermediateResult creates an EvaluationResult from an arbitrary object. // CreateIntermediateResult creates an EvaluationResult from an arbitrary object.
func CreateIntermediateResult(context *EvaluationContext, obj interface{}) *EvaluationResult { func CreateIntermediateResult(context *EvaluationContext, obj any) *EvaluationResult {
val, kind, raw := convertToCanonicalValue(obj) val, kind, raw := convertToCanonicalValue(obj)
return NewEvaluationResult(context, 0, val, kind, raw, true) return NewEvaluationResult(context, 0, val, kind, raw, true)
} }
@@ -226,7 +226,7 @@ var ExpressionConstants = struct {
} }
// convertToCanonicalValue converts an arbitrary Go value to a canonical form. // convertToCanonicalValue converts an arbitrary Go value to a canonical form.
func convertToCanonicalValue(obj interface{}) (interface{}, ValueKind, interface{}) { func convertToCanonicalValue(obj any) (any, ValueKind, any) {
switch v := obj.(type) { switch v := obj.(type) {
case nil: case nil:
return nil, ValueKindNull, nil return nil, ValueKindNull, nil
@@ -243,11 +243,11 @@ func convertToCanonicalValue(obj interface{}) (interface{}, ValueKind, interface
return f, ValueKindNumber, f return f, ValueKindNumber, f
case string: case string:
return v, ValueKindString, v return v, ValueKindString, v
case []interface{}: case []any:
return BasicArray[any](v), ValueKindArray, v return BasicArray[any](v), ValueKindArray, v
case ReadOnlyArray[any]: case ReadOnlyArray[any]:
return v, ValueKindArray, v return v, ValueKindArray, v
case map[string]interface{}: case map[string]any:
return CaseInsensitiveObject[any](v), ValueKindObject, v return CaseInsensitiveObject[any](v), ValueKindObject, v
case ReadOnlyObject[any]: case ReadOnlyObject[any]:
return v, ValueKindObject, v return v, ValueKindObject, v
@@ -257,7 +257,7 @@ func convertToCanonicalValue(obj interface{}) (interface{}, ValueKind, interface
} }
} }
func toInt64(v interface{}) int64 { func toInt64(v any) int64 {
switch i := v.(type) { switch i := v.(type) {
case int: case int:
return int64(i) return int64(i)
@@ -274,7 +274,7 @@ func toInt64(v interface{}) int64 {
} }
} }
func toUint64(v interface{}) uint64 { func toUint64(v any) uint64 {
switch i := v.(type) { switch i := v.(type) {
case uint: case uint:
return uint64(i) return uint64(i)
@@ -291,7 +291,7 @@ func toUint64(v interface{}) uint64 {
} }
} }
func toFloat64(v interface{}) float64 { func toFloat64(v any) float64 {
switch f := v.(type) { switch f := v.(type) {
case float32: case float32:
return float64(f) return float64(f)
@@ -304,7 +304,7 @@ func toFloat64(v interface{}) float64 {
// coerceTypes implements the C# CoerceTypes logic. // coerceTypes implements the C# CoerceTypes logic.
// It converts values to compatible types before comparison. // It converts values to compatible types before comparison.
func coerceTypes(left, right interface{}) (interface{}, interface{}, ValueKind, ValueKind) { func coerceTypes(left, right any) (any, any, ValueKind, ValueKind) {
leftKind := getKind(left) leftKind := getKind(left)
rightKind := getKind(right) rightKind := getKind(right)
@@ -340,7 +340,7 @@ func coerceTypes(left, right interface{}) (interface{}, interface{}, ValueKind,
} }
// abstractEqual uses coerceTypes before comparing. // abstractEqual uses coerceTypes before comparing.
func abstractEqual(left, right interface{}) bool { func abstractEqual(left, right any) bool {
left, right, leftKind, rightKind := coerceTypes(left, right) left, right, leftKind, rightKind := coerceTypes(left, right)
if leftKind != rightKind { if leftKind != rightKind {
return false return false
@@ -367,7 +367,7 @@ func abstractEqual(left, right interface{}) bool {
} }
// abstractGreaterThan uses coerceTypes before comparing. // abstractGreaterThan uses coerceTypes before comparing.
func abstractGreaterThan(left, right interface{}) bool { func abstractGreaterThan(left, right any) bool {
left, right, leftKind, rightKind := coerceTypes(left, right) left, right, leftKind, rightKind := coerceTypes(left, right)
if leftKind != rightKind { if leftKind != rightKind {
return false return false
@@ -389,7 +389,7 @@ func abstractGreaterThan(left, right interface{}) bool {
} }
// abstractLessThan uses coerceTypes before comparing. // abstractLessThan uses coerceTypes before comparing.
func abstractLessThan(left, right interface{}) bool { func abstractLessThan(left, right any) bool {
left, right, leftKind, rightKind := coerceTypes(left, right) left, right, leftKind, rightKind := coerceTypes(left, right)
if leftKind != rightKind { if leftKind != rightKind {
return false return false
@@ -411,7 +411,7 @@ func abstractLessThan(left, right interface{}) bool {
} }
// convertToNumber converts a value to a float64 following JavaScript rules. // convertToNumber converts a value to a float64 following JavaScript rules.
func convertToNumber(v interface{}) float64 { func convertToNumber(v any) float64 {
switch val := v.(type) { switch val := v.(type) {
case nil: case nil:
return 0 return 0
@@ -447,7 +447,7 @@ func convertToNumber(v interface{}) float64 {
} }
// getKind returns the ValueKind for a Go value. // getKind returns the ValueKind for a Go value.
func getKind(v interface{}) ValueKind { func getKind(v any) ValueKind {
switch v.(type) { switch v.(type) {
case nil: case nil:
return ValueKindNull return ValueKindNull
@@ -457,9 +457,9 @@ func getKind(v interface{}) ValueKind {
return ValueKindNumber return ValueKindNumber
case string: case string:
return ValueKindString return ValueKindString
case []interface{}: case []any:
return ValueKindArray return ValueKindArray
case map[string]interface{}: case map[string]any:
return ValueKindObject return ValueKindObject
default: default:
return ValueKindObject return ValueKindObject

View File

@@ -56,11 +56,11 @@ func (e *Evaluator) EvaluateBoolean(expr string) (bool, error) {
return result.IsTruthy(), nil return result.IsTruthy(), nil
} }
func (e *Evaluator) ToRaw(result *EvaluationResult) (interface{}, error) { func (e *Evaluator) ToRaw(result *EvaluationResult) (any, error) {
if col, ok := result.TryGetCollectionInterface(); ok { if col, ok := result.TryGetCollectionInterface(); ok {
switch node := col.(type) { switch node := col.(type) {
case ReadOnlyObject[any]: case ReadOnlyObject[any]:
rawMap := map[string]interface{}{} rawMap := map[string]any{}
for k, v := range node.GetEnumerator() { for k, v := range node.GetEnumerator() {
rawRes, err := e.ToRaw(CreateIntermediateResult(e.Context(), v)) rawRes, err := e.ToRaw(CreateIntermediateResult(e.Context(), v))
if err != nil { if err != nil {
@@ -70,7 +70,7 @@ func (e *Evaluator) ToRaw(result *EvaluationResult) (interface{}, error) {
} }
return rawMap, nil return rawMap, nil
case ReadOnlyArray[any]: case ReadOnlyArray[any]:
rawArray := []interface{}{} rawArray := []any{}
for _, v := range node.GetEnumerator() { for _, v := range node.GetEnumerator() {
rawRes, err := e.ToRaw(CreateIntermediateResult(e.Context(), v)) rawRes, err := e.ToRaw(CreateIntermediateResult(e.Context(), v))
if err != nil { if err != nil {
@@ -85,7 +85,7 @@ func (e *Evaluator) ToRaw(result *EvaluationResult) (interface{}, error) {
} }
// Evaluate parses and evaluates the expression, returning a boolean result. // Evaluate parses and evaluates the expression, returning a boolean result.
func (e *Evaluator) EvaluateRaw(expr string) (interface{}, error) { func (e *Evaluator) EvaluateRaw(expr string) (any, error) {
root, err := exprparser.Parse(expr) root, err := exprparser.Parse(expr)
if err != nil { if err != nil {
return false, fmt.Errorf("parse error: %w", err) return false, fmt.Errorf("parse error: %w", err)
@@ -97,16 +97,16 @@ func (e *Evaluator) EvaluateRaw(expr string) (interface{}, error) {
return e.ToRaw(result) return e.ToRaw(result)
} }
type FilteredArray []interface{} type FilteredArray []any
func (a FilteredArray) GetAt(i int64) interface{} { func (a FilteredArray) GetAt(i int64) any {
if int(i) > len(a) { if int(i) > len(a) {
return nil return nil
} }
return a[i] return a[i]
} }
func (a FilteredArray) GetEnumerator() []interface{} { func (a FilteredArray) GetEnumerator() []any {
return a return a
} }
@@ -244,7 +244,7 @@ func (e *Evaluator) evalUnaryNode(node *exprparser.UnaryNode) (*EvaluationResult
} }
} }
func processIndex(col interface{}, right *EvaluationResult) interface{} { func processIndex(col any, right *EvaluationResult) any {
if mapVal, ok := col.(ReadOnlyObject[any]); ok { if mapVal, ok := col.(ReadOnlyObject[any]); ok {
key, ok := right.Value().(string) key, ok := right.Value().(string)
if !ok { if !ok {
@@ -264,7 +264,7 @@ func processIndex(col interface{}, right *EvaluationResult) interface{} {
return nil return nil
} }
func processStar(subcol interface{}, ret FilteredArray) FilteredArray { func processStar(subcol any, ret FilteredArray) FilteredArray {
if array, ok := subcol.(ReadOnlyArray[any]); ok { if array, ok := subcol.(ReadOnlyArray[any]); ok {
ret = append(ret, array.GetEnumerator()...) ret = append(ret, array.GetEnumerator()...)
} else if obj, ok := subcol.(ReadOnlyObject[any]); ok { } else if obj, ok := subcol.(ReadOnlyObject[any]); ok {

View File

@@ -6,7 +6,7 @@ import (
// Test boolean and comparison operations using the evaluator. // Test boolean and comparison operations using the evaluator.
func TestEvaluator_BooleanOps(t *testing.T) { func TestEvaluator_BooleanOps(t *testing.T) {
ctx := &EvaluationContext{Variables: CaseInsensitiveObject[any](map[string]interface{}{"a": 5, "b": 3})} ctx := &EvaluationContext{Variables: CaseInsensitiveObject[any](map[string]any{"a": 5, "b": 3})}
eval := NewEvaluator(ctx) eval := NewEvaluator(ctx)
tests := []struct { tests := []struct {
@@ -44,7 +44,7 @@ func TestEvaluator_Raw(t *testing.T) {
tests := []struct { tests := []struct {
expr string expr string
want interface{} want any
}{ }{
{"a.b['x']", nil}, {"a.b['x']", nil},
{"(a.b).c['x']", nil}, {"(a.b).c['x']", nil},

View File

@@ -113,7 +113,7 @@ func (Format) Evaluate(eval *Evaluator, args []exprparser.Node) (*EvaluationResu
return nil, err return nil, err
} }
sargs := []interface{}{} sargs := []any{}
for _, arg := range args[1:] { for _, arg := range args[1:] {
el, err := eval.Evaluate(arg) el, err := eval.Evaluate(arg)
if err != nil { if err != nil {

View File

@@ -20,7 +20,7 @@ type Node interface {
type ValueNode struct { type ValueNode struct {
Kind TokenKind Kind TokenKind
Value interface{} Value any
} }
// FunctionNode represents a function call with arguments. // FunctionNode represents a function call with arguments.

View File

@@ -51,7 +51,7 @@ const (
type Token struct { type Token struct {
Kind TokenKind Kind TokenKind
Raw string Raw string
Value interface{} Value any
Index int Index int
} }
@@ -256,7 +256,7 @@ func (l *Lexer) readNumber() *Token {
} }
} }
// Try to parse as float64 // Try to parse as float64
var val interface{} = raw var val any = raw
if f, err := strconv.ParseFloat(raw, 64); err == nil { if f, err := strconv.ParseFloat(raw, 64); err == nil {
val = f val = f
} }

View File

@@ -12,7 +12,7 @@ func TestLexerMultiple(t *testing.T) {
cases := []struct { cases := []struct {
expr string expr string
expected []TokenKind expected []TokenKind
values []interface{} // optional, nil if not checking values values []any // optional, nil if not checking values
}{ }{
{ {
expr: "github.event_name == 'push'", expr: "github.event_name == 'push'",
@@ -67,12 +67,12 @@ func TestLexerMultiple(t *testing.T) {
{ {
expr: "true", expr: "true",
expected: []TokenKind{TokenKindBoolean}, expected: []TokenKind{TokenKindBoolean},
values: []interface{}{true}, values: []any{true},
}, },
{ {
expr: "123", expr: "123",
expected: []TokenKind{TokenKindNumber}, expected: []TokenKind{TokenKindNumber},
values: []interface{}{123.0}, values: []any{123.0},
}, },
{ {
expr: "(a && b)", expr: "(a && b)",
@@ -85,7 +85,7 @@ func TestLexerMultiple(t *testing.T) {
{ {
expr: "'Hello i''s escaped'", expr: "'Hello i''s escaped'",
expected: []TokenKind{TokenKindString}, expected: []TokenKind{TokenKindString},
values: []interface{}{"Hello i's escaped"}, values: []any{"Hello i's escaped"},
}, },
} }
@@ -99,7 +99,7 @@ func TestLexerMultiple(t *testing.T) {
} }
tokens = append(tokens, tok) tokens = append(tokens, tok)
} }
assert.Equal(t, len(tc.expected), len(tokens), "expression: %s", tc.expr) assert.Len(t, tokens, len(tc.expected), "expression: %s", tc.expr)
for i, kind := range tc.expected { for i, kind := range tc.expected {
assert.Equal(t, kind, tokens[i].Kind, "expr %s token %d", tc.expr, i) assert.Equal(t, kind, tokens[i].Kind, "expr %s token %d", tc.expr, i)
} }

View File

@@ -22,13 +22,13 @@ func TestLexer(t *testing.T) {
for i, tok := range tokens { for i, tok := range tokens {
t.Logf("Token %d: Kind=%v, Value=%v", i, tok.Kind, tok.Value) t.Logf("Token %d: Kind=%v, Value=%v", i, tok.Kind, tok.Value)
} }
assert.Equal(t, tokens[1].Kind, TokenKindDereference) assert.Equal(t, TokenKindDereference, tokens[1].Kind)
} }
func TestLexerNumbers(t *testing.T) { func TestLexerNumbers(t *testing.T) {
table := []struct { table := []struct {
in string in string
out interface{} out any
}{ }{
{"-Infinity", math.Inf(-1)}, {"-Infinity", math.Inf(-1)},
{"Infinity", math.Inf(1)}, {"Infinity", math.Inf(1)},

View File

@@ -2,7 +2,7 @@ package model
import ( import (
"errors" "errors"
"fmt" "maps"
"strings" "strings"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@@ -11,7 +11,7 @@ import (
// TraceWriter is an interface for logging trace information. // TraceWriter is an interface for logging trace information.
// Implementations can write to console, file, or any other sink. // Implementations can write to console, file, or any other sink.
type TraceWriter interface { type TraceWriter interface {
Info(format string, args ...interface{}) Info(format string, args ...any)
} }
// StrategyResult holds the result of expanding a strategy. // StrategyResult holds the result of expanding a strategy.
@@ -46,14 +46,14 @@ func (strategyContext *strategyContext) handleInclude() error {
if len(strategyContext.include) > 0 { if len(strategyContext.include) > 0 {
for _, incNode := range strategyContext.include { for _, incNode := range strategyContext.include {
if incNode.Kind != yaml.MappingNode { if incNode.Kind != yaml.MappingNode {
return fmt.Errorf("include entry is not a mapping node") return errors.New("include entry is not a mapping node")
} }
incMap := make(map[string]yaml.Node) incMap := make(map[string]yaml.Node)
for i := 0; i < len(incNode.Content); i += 2 { for i := 0; i < len(incNode.Content); i += 2 {
keyNode := incNode.Content[i] keyNode := incNode.Content[i]
valNode := incNode.Content[i+1] valNode := incNode.Content[i+1]
if keyNode.Kind != yaml.ScalarNode { if keyNode.Kind != yaml.ScalarNode {
return fmt.Errorf("include key is not scalar") return errors.New("include key is not scalar")
} }
incMap[keyNode.Value] = *valNode incMap[keyNode.Value] = *valNode
} }
@@ -94,7 +94,7 @@ func (strategyContext *strategyContext) handleExclude() error {
for _, exNode := range strategyContext.exclude { for _, exNode := range strategyContext.exclude {
// exNode is expected to be a mapping node // exNode is expected to be a mapping node
if exNode.Kind != yaml.MappingNode { if exNode.Kind != yaml.MappingNode {
return fmt.Errorf("exclude entry is not a mapping node") return errors.New("exclude entry is not a mapping node")
} }
// Convert mapping to map[string]yaml.Node // Convert mapping to map[string]yaml.Node
exMap := make(map[string]yaml.Node) exMap := make(map[string]yaml.Node)
@@ -102,7 +102,7 @@ func (strategyContext *strategyContext) handleExclude() error {
keyNode := exNode.Content[i] keyNode := exNode.Content[i]
valNode := exNode.Content[i+1] valNode := exNode.Content[i+1]
if keyNode.Kind != yaml.ScalarNode { if keyNode.Kind != yaml.ScalarNode {
return fmt.Errorf("exclude key is not scalar") return errors.New("exclude key is not scalar")
} }
exMap[keyNode.Value] = *valNode exMap[keyNode.Value] = *valNode
} }
@@ -158,9 +158,7 @@ func ExpandStrategy(strategy *Strategy, jobTraceWriter TraceWriter) (*StrategyRe
for _, row := range strategyContext.flatMatrix { for _, row := range strategyContext.flatMatrix {
for _, val := range values { for _, val := range values {
newRow := make(map[string]yaml.Node) newRow := make(map[string]yaml.Node)
for k, v := range row { maps.Copy(newRow, row)
newRow[k] = v
}
newRow[key] = val newRow[key] = val
next = append(next, newRow) next = append(next, newRow)
} }

View File

@@ -10,7 +10,7 @@ import (
type EmptyTraceWriter struct { type EmptyTraceWriter struct {
} }
func (e *EmptyTraceWriter) Info(_ string, _ ...interface{}) { func (e *EmptyTraceWriter) Info(_ string, _ ...any) {
} }
func TestStrategy(t *testing.T) { func TestStrategy(t *testing.T) {

View File

@@ -96,7 +96,7 @@ func (a *On) UnmarshalYAML(node *yaml.Node) error {
return nil return nil
} }
func (a *On) MarshalYAML() (interface{}, error) { func (a *On) MarshalYAML() (any, error) {
return a.Data, nil return a.Data, nil
} }

View File

@@ -75,7 +75,7 @@ func StartHandler(dir, outboundIP string, port uint16, logger logrus.FieldLogger
if outboundIP != "" { if outboundIP != "" {
h.outboundIP = outboundIP h.outboundIP = outboundIP
} else if ip := common.GetOutboundIP(); ip == nil { } else if ip := common.GetOutboundIP(); ip == nil {
return nil, fmt.Errorf("unable to determine outbound IP address") return nil, errors.New("unable to determine outbound IP address")
} else { } else {
h.outboundIP = ip.String() h.outboundIP = ip.String()
} }
@@ -144,7 +144,7 @@ func CreateHandler(dir, externalAddress string, logger logrus.FieldLogger) (*Han
if externalAddress != "" { if externalAddress != "" {
h.externalAddress = externalAddress h.externalAddress = externalAddress
} else if ip := common.GetOutboundIP(); ip == nil { } else if ip := common.GetOutboundIP(); ip == nil {
return nil, nil, fmt.Errorf("unable to determine outbound IP address") return nil, nil, errors.New("unable to determine outbound IP address")
} else { } else {
h.outboundIP = ip.String() h.outboundIP = ip.String()
} }
@@ -420,7 +420,7 @@ func findCache(db *bolthold.Store, keys []string, version string) (*Cache, error
} }
return cache, nil return cache, nil
} }
prefixPattern := fmt.Sprintf("^%s", regexp.QuoteMeta(prefix)) prefixPattern := "^" + regexp.QuoteMeta(prefix)
re, err := regexp.Compile(prefixPattern) re, err := regexp.Compile(prefixPattern)
if err != nil { if err != nil {
continue continue

View File

@@ -64,7 +64,7 @@ func TestHandler(t *testing.T) {
}) })
t.Run("clean", func(t *testing.T) { t.Run("clean", func(t *testing.T) {
resp, err := http.Post(fmt.Sprintf("%s/clean", base), "", nil) resp, err := http.Post(base+"/clean", "", nil)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)
}) })
@@ -72,7 +72,7 @@ func TestHandler(t *testing.T) {
t.Run("reserve with bad request", func(t *testing.T) { t.Run("reserve with bad request", func(t *testing.T) {
body := []byte(`invalid json`) body := []byte(`invalid json`)
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 400, resp.StatusCode) assert.Equal(t, 400, resp.StatusCode)
}) })
@@ -90,7 +90,7 @@ func TestHandler(t *testing.T) {
Size: 100, Size: 100,
}) })
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)
@@ -104,7 +104,7 @@ func TestHandler(t *testing.T) {
Size: 100, Size: 100,
}) })
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)
@@ -117,7 +117,7 @@ func TestHandler(t *testing.T) {
t.Run("upload with bad id", func(t *testing.T) { t.Run("upload with bad id", func(t *testing.T) {
req, err := http.NewRequest(http.MethodPatch, req, err := http.NewRequest(http.MethodPatch,
fmt.Sprintf("%s/caches/invalid_id", base), bytes.NewReader(nil)) base+"/caches/invalid_id", bytes.NewReader(nil))
require.NoError(t, err) require.NoError(t, err)
req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Content-Type", "application/octet-stream")
req.Header.Set("Content-Range", "bytes 0-99/*") req.Header.Set("Content-Range", "bytes 0-99/*")
@@ -151,7 +151,7 @@ func TestHandler(t *testing.T) {
Size: 100, Size: 100,
}) })
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)
@@ -202,7 +202,7 @@ func TestHandler(t *testing.T) {
Size: 100, Size: 100,
}) })
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)
@@ -226,7 +226,7 @@ func TestHandler(t *testing.T) {
t.Run("commit with bad id", func(t *testing.T) { t.Run("commit with bad id", func(t *testing.T) {
{ {
resp, err := http.Post(fmt.Sprintf("%s/caches/invalid_id", base), "", nil) resp, err := http.Post(base+"/caches/invalid_id", "", nil)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 400, resp.StatusCode) assert.Equal(t, 400, resp.StatusCode)
} }
@@ -254,7 +254,7 @@ func TestHandler(t *testing.T) {
Size: 100, Size: 100,
}) })
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)
@@ -300,7 +300,7 @@ func TestHandler(t *testing.T) {
Size: 100, Size: 100,
}) })
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)
@@ -328,7 +328,7 @@ func TestHandler(t *testing.T) {
}) })
t.Run("get with bad id", func(t *testing.T) { t.Run("get with bad id", func(t *testing.T) {
resp, err := http.Get(fmt.Sprintf("%s/artifacts/invalid_id", base)) resp, err := http.Get(base + "/artifacts/invalid_id")
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 400, resp.StatusCode) require.Equal(t, 400, resp.StatusCode)
}) })
@@ -537,7 +537,7 @@ func uploadCacheNormally(t *testing.T, base, key, version string, content []byte
Size: int64(len(content)), Size: int64(len(content)),
}) })
require.NoError(t, err) require.NoError(t, err)
resp, err := http.Post(fmt.Sprintf("%s/caches", base), "application/json", bytes.NewReader(body)) resp, err := http.Post(base+"/caches", "application/json", bytes.NewReader(body))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, 200, resp.StatusCode)

View File

@@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
) )
type Storage struct { type Storage struct {
@@ -103,11 +104,11 @@ func (s *Storage) Remove(id uint64) {
} }
func (s *Storage) filename(id uint64) string { func (s *Storage) filename(id uint64) string {
return filepath.Join(s.rootDir, fmt.Sprintf("%02x", id%0xff), fmt.Sprint(id)) return filepath.Join(s.rootDir, fmt.Sprintf("%02x", id%0xff), strconv.FormatUint(id, 10))
} }
func (s *Storage) tempDir(id uint64) string { func (s *Storage) tempDir(id uint64) string {
return filepath.Join(s.rootDir, "tmp", fmt.Sprint(id)) return filepath.Join(s.rootDir, "tmp", strconv.FormatUint(id, 10))
} }
func (s *Storage) tempName(id uint64, offset int64) string { func (s *Storage) tempName(id uint64, offset int64) string {

View File

@@ -126,15 +126,15 @@ func artifactNameToID(s string) int64 {
return int64(h.Sum32()) return int64(h.Sum32())
} }
func (c ArtifactContext) Error(status int, _ ...interface{}) { func (c ArtifactContext) Error(status int, _ ...any) {
c.Resp.WriteHeader(status) c.Resp.WriteHeader(status)
} }
func (c ArtifactContext) JSON(status int, _ ...interface{}) { func (c ArtifactContext) JSON(status int, _ ...any) {
c.Resp.WriteHeader(status) c.Resp.WriteHeader(status)
} }
func validateRunIDV4(ctx *ArtifactContext, rawRunID string) (interface{}, int64, bool) { func validateRunIDV4(ctx *ArtifactContext, rawRunID string) (any, int64, bool) {
runID, err := strconv.ParseInt(rawRunID, 10, 64) runID, err := strconv.ParseInt(rawRunID, 10, 64)
if err != nil /* || task.Job.RunID != runID*/ { if err != nil /* || task.Job.RunID != runID*/ {
log.Error("Error runID not match") log.Error("Error runID not match")
@@ -210,7 +210,7 @@ func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, tas
func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID int64) string { func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID int64) string {
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST") expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
uploadURL := "http://" + strings.TrimSuffix(r.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") + uploadURL := "http://" + strings.TrimSuffix(r.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") +
"/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID) "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + strconv.FormatInt(taskID, 10)
return uploadURL return uploadURL
} }
@@ -278,7 +278,7 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
artifactName := req.Name artifactName := req.Name
safeRunPath := safeResolve(r.baseDir, fmt.Sprint(runID)) safeRunPath := safeResolve(r.baseDir, strconv.FormatInt(runID, 10))
safePath := safeResolve(safeRunPath, artifactName) safePath := safeResolve(safeRunPath, artifactName)
safePath = safeResolve(safePath, artifactName+".zip") safePath = safeResolve(safePath, artifactName+".zip")
file, err := r.fs.OpenWritable(safePath) file, err := r.fs.OpenWritable(safePath)
@@ -305,7 +305,7 @@ func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
switch comp { switch comp {
case "block", "appendBlock": case "block", "appendBlock":
safeRunPath := safeResolve(r.baseDir, fmt.Sprint(task)) safeRunPath := safeResolve(r.baseDir, strconv.FormatInt(task, 10))
safePath := safeResolve(safeRunPath, artifactName) safePath := safeResolve(safeRunPath, artifactName)
safePath = safeResolve(safePath, artifactName+".zip") safePath = safeResolve(safePath, artifactName+".zip")
@@ -365,7 +365,7 @@ func (r *artifactV4Routes) listArtifacts(ctx *ArtifactContext) {
return return
} }
safePath := safeResolve(r.baseDir, fmt.Sprint(runID)) safePath := safeResolve(r.baseDir, strconv.FormatInt(runID, 10))
entries, err := fs.ReadDir(r.rfs, safePath) entries, err := fs.ReadDir(r.rfs, safePath)
if err != nil { if err != nil {
@@ -424,7 +424,7 @@ func (r *artifactV4Routes) downloadArtifact(ctx *ArtifactContext) {
return return
} }
safeRunPath := safeResolve(r.baseDir, fmt.Sprint(task)) safeRunPath := safeResolve(r.baseDir, strconv.FormatInt(task, 10))
safePath := safeResolve(safeRunPath, artifactName) safePath := safeResolve(safeRunPath, artifactName)
safePath = safeResolve(safePath, artifactName+".zip") safePath = safeResolve(safePath, artifactName+".zip")
@@ -443,7 +443,7 @@ func (r *artifactV4Routes) deleteArtifact(ctx *ArtifactContext) {
if !ok { if !ok {
return return
} }
safeRunPath := safeResolve(r.baseDir, fmt.Sprint(runID)) safeRunPath := safeResolve(r.baseDir, strconv.FormatInt(runID, 10))
safePath := safeResolve(safeRunPath, req.Name) safePath := safeResolve(safeRunPath, req.Name)
_ = os.RemoveAll(safePath) _ = os.RemoveAll(safePath)

View File

@@ -68,7 +68,7 @@ func TestNewArtifactUploadPrepare(t *testing.T) {
router := httprouter.New() router := httprouter.New()
uploads(router, "artifact/server/path", writeMapFS{memfs}) uploads(router, "artifact/server/path", writeMapFS{memfs})
req, _ := http.NewRequest("POST", "http://localhost/_apis/pipelines/workflows/1/artifacts", nil) req, _ := http.NewRequest(http.MethodPost, "http://localhost/_apis/pipelines/workflows/1/artifacts", nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)
@@ -94,7 +94,7 @@ func TestArtifactUploadBlob(t *testing.T) {
router := httprouter.New() router := httprouter.New()
uploads(router, "artifact/server/path", writeMapFS{memfs}) uploads(router, "artifact/server/path", writeMapFS{memfs})
req, _ := http.NewRequest("PUT", "http://localhost/upload/1?itemPath=some/file", strings.NewReader("content")) req, _ := http.NewRequest(http.MethodPut, "http://localhost/upload/1?itemPath=some/file", strings.NewReader("content"))
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)
@@ -121,7 +121,7 @@ func TestFinalizeArtifactUpload(t *testing.T) {
router := httprouter.New() router := httprouter.New()
uploads(router, "artifact/server/path", writeMapFS{memfs}) uploads(router, "artifact/server/path", writeMapFS{memfs})
req, _ := http.NewRequest("PATCH", "http://localhost/_apis/pipelines/workflows/1/artifacts", nil) req, _ := http.NewRequest(http.MethodPatch, "http://localhost/_apis/pipelines/workflows/1/artifacts", nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)
@@ -151,7 +151,7 @@ func TestListArtifacts(t *testing.T) {
router := httprouter.New() router := httprouter.New()
downloads(router, "artifact/server/path", memfs) downloads(router, "artifact/server/path", memfs)
req, _ := http.NewRequest("GET", "http://localhost/_apis/pipelines/workflows/1/artifacts", nil) req, _ := http.NewRequest(http.MethodGet, "http://localhost/_apis/pipelines/workflows/1/artifacts", nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)
@@ -183,7 +183,7 @@ func TestListArtifactContainer(t *testing.T) {
router := httprouter.New() router := httprouter.New()
downloads(router, "artifact/server/path", memfs) downloads(router, "artifact/server/path", memfs)
req, _ := http.NewRequest("GET", "http://localhost/download/1?itemPath=some/file", nil) req, _ := http.NewRequest(http.MethodGet, "http://localhost/download/1?itemPath=some/file", nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)
@@ -198,7 +198,7 @@ func TestListArtifactContainer(t *testing.T) {
panic(err) panic(err)
} }
assert.Equal(1, len(response.Value)) assert.Len(response.Value, 1)
assert.Equal("some/file", response.Value[0].Path) assert.Equal("some/file", response.Value[0].Path)
assert.Equal("file", response.Value[0].ItemType) assert.Equal("file", response.Value[0].ItemType)
assert.Equal("http://localhost/artifact/1/some/file/.", response.Value[0].ContentLocation) assert.Equal("http://localhost/artifact/1/some/file/.", response.Value[0].ContentLocation)
@@ -216,7 +216,7 @@ func TestDownloadArtifactFile(t *testing.T) {
router := httprouter.New() router := httprouter.New()
downloads(router, "artifact/server/path", memfs) downloads(router, "artifact/server/path", memfs)
req, _ := http.NewRequest("GET", "http://localhost/artifact/1/some/file", nil) req, _ := http.NewRequest(http.MethodGet, "http://localhost/artifact/1/some/file", nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)
@@ -283,7 +283,7 @@ func runTestJobFile(ctx context.Context, t *testing.T, tjfi TestJobFileInfo) {
} }
workdir, err := filepath.Abs(tjfi.workdir) workdir, err := filepath.Abs(tjfi.workdir)
assert.Nil(t, err, workdir) assert.NoError(t, err, workdir)
fullWorkflowPath := filepath.Join(workdir, tjfi.workflowPath) fullWorkflowPath := filepath.Join(workdir, tjfi.workflowPath)
runnerConfig := &runner.Config{ runnerConfig := &runner.Config{
Workdir: workdir, Workdir: workdir,
@@ -299,16 +299,16 @@ func runTestJobFile(ctx context.Context, t *testing.T, tjfi TestJobFileInfo) {
} }
runner, err := runner.New(runnerConfig) runner, err := runner.New(runnerConfig)
assert.Nil(t, err, tjfi.workflowPath) assert.NoError(t, err, tjfi.workflowPath)
planner, err := model.NewWorkflowPlanner(fullWorkflowPath, model.PlannerConfig{}) planner, err := model.NewWorkflowPlanner(fullWorkflowPath, model.PlannerConfig{})
assert.Nil(t, err, fullWorkflowPath) assert.NoError(t, err, fullWorkflowPath)
plan, err := planner.PlanEvent(tjfi.eventName) plan, err := planner.PlanEvent(tjfi.eventName)
if err == nil { if err == nil {
err = runner.NewPlanExecutor(plan)(ctx) err = runner.NewPlanExecutor(plan)(ctx)
if tjfi.errorMessage == "" { if tjfi.errorMessage == "" {
assert.Nil(t, err, fullWorkflowPath) assert.NoError(t, err, fullWorkflowPath)
} else { } else {
assert.Error(t, err, tjfi.errorMessage) assert.Error(t, err, tjfi.errorMessage)
} }
@@ -356,7 +356,7 @@ func TestDownloadArtifactFileUnsafePath(t *testing.T) {
router := httprouter.New() router := httprouter.New()
downloads(router, "artifact/server/path", memfs) downloads(router, "artifact/server/path", memfs)
req, _ := http.NewRequest("GET", "http://localhost/artifact/2/../../some/file", nil) req, _ := http.NewRequest(http.MethodGet, "http://localhost/artifact/2/../../some/file", nil)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)
@@ -378,7 +378,7 @@ func TestArtifactUploadBlobUnsafePath(t *testing.T) {
router := httprouter.New() router := httprouter.New()
uploads(router, "artifact/server/path", writeMapFS{memfs}) uploads(router, "artifact/server/path", writeMapFS{memfs})
req, _ := http.NewRequest("PUT", "http://localhost/upload/1?itemPath=../../some/file", strings.NewReader("content")) req, _ := http.NewRequest(http.MethodPut, "http://localhost/upload/1?itemPath=../../some/file", strings.NewReader("content"))
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
router.ServeHTTP(rr, req) router.ServeHTTP(rr, req)

View File

@@ -5,6 +5,7 @@ package common
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
@@ -78,7 +79,7 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
parts := strings.SplitN(h, " ", 2) parts := strings.SplitN(h, " ", 2)
if len(parts) != 2 { if len(parts) != 2 {
log.Errorf("split token failed: %s", h) log.Errorf("split token failed: %s", h)
return 0, fmt.Errorf("split token failed") return 0, errors.New("split token failed")
} }
token, err := jwt.ParseWithClaims(parts[1], &actionsClaims{}, func(t *jwt.Token) (any, error) { token, err := jwt.ParseWithClaims(parts[1], &actionsClaims{}, func(t *jwt.Token) (any, error) {
@@ -93,7 +94,7 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
c, ok := token.Claims.(*actionsClaims) c, ok := token.Claims.(*actionsClaims)
if !token.Valid || !ok { if !token.Valid || !ok {
return 0, fmt.Errorf("invalid token claim") return 0, errors.New("invalid token claim")
} }
return c.TaskID, nil return c.TaskID, nil

View File

@@ -15,13 +15,13 @@ import (
func TestCreateAuthorizationToken(t *testing.T) { func TestCreateAuthorizationToken(t *testing.T) {
var taskID int64 = 23 var taskID int64 = 23
token, err := CreateAuthorizationToken(taskID, 1, 2) token, err := CreateAuthorizationToken(taskID, 1, 2)
assert.Nil(t, err) assert.NoError(t, err)
assert.NotEqual(t, "", token) assert.NotEmpty(t, token)
claims := jwt.MapClaims{} claims := jwt.MapClaims{}
_, err = jwt.ParseWithClaims(token, claims, func(_ *jwt.Token) (interface{}, error) { _, err = jwt.ParseWithClaims(token, claims, func(_ *jwt.Token) (any, error) {
return []byte{}, nil return []byte{}, nil
}) })
assert.Nil(t, err) assert.NoError(t, err)
scp, ok := claims["scp"] scp, ok := claims["scp"]
assert.True(t, ok, "Has scp claim in jwt token") assert.True(t, ok, "Has scp claim in jwt token")
assert.Contains(t, scp, "Actions.Results:1:2") assert.Contains(t, scp, "Actions.Results:1:2")
@@ -41,14 +41,14 @@ func TestCreateAuthorizationToken(t *testing.T) {
func TestParseAuthorizationToken(t *testing.T) { func TestParseAuthorizationToken(t *testing.T) {
var taskID int64 = 23 var taskID int64 = 23
token, err := CreateAuthorizationToken(taskID, 1, 2) token, err := CreateAuthorizationToken(taskID, 1, 2)
assert.Nil(t, err) assert.NoError(t, err)
assert.NotEqual(t, "", token) assert.NotEmpty(t, token)
headers := http.Header{} headers := http.Header{}
headers.Set("Authorization", "Bearer "+token) headers.Set("Authorization", "Bearer "+token)
rTaskID, err := ParseAuthorizationToken(&http.Request{ rTaskID, err := ParseAuthorizationToken(&http.Request{
Header: headers, Header: headers,
}) })
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, taskID, rTaskID) assert.Equal(t, taskID, rTaskID)
} }
@@ -57,6 +57,6 @@ func TestParseAuthorizationTokenNoAuthHeader(t *testing.T) {
rTaskID, err := ParseAuthorizationToken(&http.Request{ rTaskID, err := ParseAuthorizationToken(&http.Request{
Header: headers, Header: headers,
}) })
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, int64(0), rTaskID) assert.Equal(t, int64(0), rTaskID)
} }

View File

@@ -1,9 +1,9 @@
package common package common
// CartesianProduct takes map of lists and returns list of unique tuples // CartesianProduct takes map of lists and returns list of unique tuples
func CartesianProduct(mapOfLists map[string][]interface{}) []map[string]interface{} { func CartesianProduct(mapOfLists map[string][]any) []map[string]any {
listNames := make([]string, 0) listNames := make([]string, 0)
lists := make([][]interface{}, 0) lists := make([][]any, 0)
for k, v := range mapOfLists { for k, v := range mapOfLists {
listNames = append(listNames, k) listNames = append(listNames, k)
lists = append(lists, v) lists = append(lists, v)
@@ -11,9 +11,9 @@ func CartesianProduct(mapOfLists map[string][]interface{}) []map[string]interfac
listCart := cartN(lists...) listCart := cartN(lists...)
rtn := make([]map[string]interface{}, 0) rtn := make([]map[string]any, 0)
for _, list := range listCart { for _, list := range listCart {
vMap := make(map[string]interface{}) vMap := make(map[string]any)
for i, v := range list { for i, v := range list {
vMap[listNames[i]] = v vMap[listNames[i]] = v
} }
@@ -22,7 +22,7 @@ func CartesianProduct(mapOfLists map[string][]interface{}) []map[string]interfac
return rtn return rtn
} }
func cartN(a ...[]interface{}) [][]interface{} { func cartN(a ...[]any) [][]any {
c := 1 c := 1
for _, a := range a { for _, a := range a {
c *= len(a) c *= len(a)
@@ -30,8 +30,8 @@ func cartN(a ...[]interface{}) [][]interface{} {
if c == 0 || len(a) == 0 { if c == 0 || len(a) == 0 {
return nil return nil
} }
p := make([][]interface{}, c) p := make([][]any, c)
b := make([]interface{}, c*len(a)) b := make([]any, c*len(a))
n := make([]int, len(a)) n := make([]int, len(a))
s := 0 s := 0
for i := range p { for i := range p {

View File

@@ -8,7 +8,7 @@ import (
func TestCartesianProduct(t *testing.T) { func TestCartesianProduct(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
input := map[string][]interface{}{ input := map[string][]any{
"foo": {1, 2, 3, 4}, "foo": {1, 2, 3, 4},
"bar": {"a", "b", "c"}, "bar": {"a", "b", "c"},
"baz": {false, true}, "baz": {false, true},
@@ -25,15 +25,15 @@ func TestCartesianProduct(t *testing.T) {
assert.Contains(v, "baz") assert.Contains(v, "baz")
} }
input = map[string][]interface{}{ input = map[string][]any{
"foo": {1, 2, 3, 4}, "foo": {1, 2, 3, 4},
"bar": {}, "bar": {},
"baz": {false, true}, "baz": {false, true},
} }
output = CartesianProduct(input) output = CartesianProduct(input)
assert.Len(output, 0) assert.Empty(output)
input = map[string][]interface{}{} input = map[string][]any{}
output = CartesianProduct(input) output = CartesianProduct(input)
assert.Len(output, 0) assert.Empty(output)
} }

View File

@@ -125,11 +125,8 @@ func (p *Pen) DrawBoxes(labels ...string) *Drawing {
// Draw to writer // Draw to writer
func (d *Drawing) Draw(writer io.Writer, centerOnWidth int) { func (d *Drawing) Draw(writer io.Writer, centerOnWidth int) {
padSize := (centerOnWidth - d.GetWidth()) / 2 padSize := max((centerOnWidth-d.GetWidth())/2, 0)
if padSize < 0 { for l := range strings.SplitSeq(d.buf.String(), "\n") {
padSize = 0
}
for _, l := range strings.Split(d.buf.String(), "\n") {
if len(l) > 0 { if len(l) > 0 {
padding := strings.Repeat(" ", padSize) padding := strings.Repeat(" ", padSize)
fmt.Fprintf(writer, "%s%s\n", padding, l) fmt.Fprintf(writer, "%s%s\n", padding, l)

View File

@@ -19,7 +19,7 @@ func (w Warning) Error() string {
} }
// Warningf create a warning // Warningf create a warning
func Warningf(format string, args ...interface{}) Warning { func Warningf(format string, args ...any) Warning {
w := Warning{ w := Warning{
Message: fmt.Sprintf(format, args...), Message: fmt.Sprintf(format, args...),
} }
@@ -33,7 +33,7 @@ type Executor func(ctx context.Context) error
type Conditional func(ctx context.Context) bool type Conditional func(ctx context.Context) bool
// NewInfoExecutor is an executor that logs messages // NewInfoExecutor is an executor that logs messages
func NewInfoExecutor(format string, args ...interface{}) Executor { func NewInfoExecutor(format string, args ...any) Executor {
return func(ctx context.Context) error { return func(ctx context.Context) error {
logger := Logger(ctx) logger := Logger(ctx)
logger.Infof(format, args...) logger.Infof(format, args...)
@@ -42,7 +42,7 @@ func NewInfoExecutor(format string, args ...interface{}) Executor {
} }
// NewDebugExecutor is an executor that logs messages // NewDebugExecutor is an executor that logs messages
func NewDebugExecutor(format string, args ...interface{}) Executor { func NewDebugExecutor(format string, args ...any) Executor {
return func(ctx context.Context) error { return func(ctx context.Context) error {
logger := Logger(ctx) logger := Logger(ctx)
logger.Debugf(format, args...) logger.Debugf(format, args...)
@@ -110,14 +110,14 @@ func NewParallelExecutor(parallel int, executors ...Executor) Executor {
}(work, errs) }(work, errs)
} }
for i := 0; i < len(executors); i++ { for i := range executors {
work <- executors[i] work <- executors[i]
} }
close(work) close(work)
// Executor waits all executors to cleanup these resources. // Executor waits all executors to cleanup these resources.
var firstErr error var firstErr error
for i := 0; i < len(executors); i++ { for range executors {
err := <-errs err := <-errs
if firstErr == nil { if firstErr == nil {
firstErr = err firstErr = err
@@ -131,7 +131,7 @@ func NewParallelExecutor(parallel int, executors ...Executor) Executor {
} }
} }
func NewFieldExecutor(name string, value interface{}, exec Executor) Executor { func NewFieldExecutor(name string, value any, exec Executor) Executor {
return func(ctx context.Context) error { return func(ctx context.Context) error {
return exec(WithLogger(ctx, Logger(ctx).WithField(name, value))) return exec(WithLogger(ctx, Logger(ctx).WithField(name, value)))
} }

View File

@@ -2,7 +2,7 @@ package common
import ( import (
"context" "context"
"fmt" "errors"
"testing" "testing"
"time" "time"
@@ -16,11 +16,11 @@ func TestNewWorkflow(t *testing.T) {
// empty // empty
emptyWorkflow := NewPipelineExecutor() emptyWorkflow := NewPipelineExecutor()
assert.Nil(emptyWorkflow(ctx)) assert.NoError(emptyWorkflow(ctx))
// error case // error case
errorWorkflow := NewErrorExecutor(fmt.Errorf("test error")) errorWorkflow := NewErrorExecutor(errors.New("test error"))
assert.NotNil(errorWorkflow(ctx)) assert.Error(errorWorkflow(ctx))
// multiple success case // multiple success case
runcount := 0 runcount := 0
@@ -33,7 +33,7 @@ func TestNewWorkflow(t *testing.T) {
runcount++ runcount++
return nil return nil
}) })
assert.Nil(successWorkflow(ctx)) assert.NoError(successWorkflow(ctx))
assert.Equal(2, runcount) assert.Equal(2, runcount)
} }
@@ -55,7 +55,7 @@ func TestNewConditionalExecutor(t *testing.T) {
return nil return nil
})(ctx) })(ctx)
assert.Nil(err) assert.NoError(err)
assert.Equal(0, trueCount) assert.Equal(0, trueCount)
assert.Equal(1, falseCount) assert.Equal(1, falseCount)
@@ -69,7 +69,7 @@ func TestNewConditionalExecutor(t *testing.T) {
return nil return nil
})(ctx) })(ctx)
assert.Nil(err) assert.NoError(err)
assert.Equal(1, trueCount) assert.Equal(1, trueCount)
assert.Equal(1, falseCount) assert.Equal(1, falseCount)
} }
@@ -99,7 +99,7 @@ func TestNewParallelExecutor(t *testing.T) {
assert.Equal(3, count, "should run all 3 executors") assert.Equal(3, count, "should run all 3 executors")
assert.Equal(2, maxCount, "should run at most 2 executors in parallel") assert.Equal(2, maxCount, "should run at most 2 executors in parallel")
assert.Nil(err) assert.NoError(err)
// Reset to test running the executor with 0 parallelism // Reset to test running the executor with 0 parallelism
count = 0 count = 0
@@ -110,7 +110,7 @@ func TestNewParallelExecutor(t *testing.T) {
assert.Equal(3, count, "should run all 3 executors") assert.Equal(3, count, "should run all 3 executors")
assert.Equal(1, maxCount, "should run at most 1 executors in parallel") assert.Equal(1, maxCount, "should run at most 1 executors in parallel")
assert.Nil(errSingle) assert.NoError(errSingle)
} }
func TestNewParallelExecutorFailed(t *testing.T) { func TestNewParallelExecutorFailed(t *testing.T) {
@@ -122,7 +122,7 @@ func TestNewParallelExecutorFailed(t *testing.T) {
count := 0 count := 0
errorWorkflow := NewPipelineExecutor(func(_ context.Context) error { errorWorkflow := NewPipelineExecutor(func(_ context.Context) error {
count++ count++
return fmt.Errorf("fake error") return errors.New("fake error")
}) })
err := NewParallelExecutor(1, errorWorkflow)(ctx) err := NewParallelExecutor(1, errorWorkflow)(ctx)
assert.Equal(1, count) assert.Equal(1, count)
@@ -135,7 +135,7 @@ func TestNewParallelExecutorCanceled(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
cancel() cancel()
errExpected := fmt.Errorf("fake error") errExpected := errors.New("fake error")
count := 0 count := 0
successWorkflow := NewPipelineExecutor(func(_ context.Context) error { successWorkflow := NewPipelineExecutor(func(_ context.Context) error {
@@ -148,5 +148,5 @@ func TestNewParallelExecutorCanceled(t *testing.T) {
}) })
err := NewParallelExecutor(3, errorWorkflow, successWorkflow, successWorkflow)(ctx) err := NewParallelExecutor(3, errorWorkflow, successWorkflow, successWorkflow)(ctx)
assert.Equal(3, count) assert.Equal(3, count)
assert.Error(errExpected, err) assert.ErrorIs(errExpected, err)
} }

View File

@@ -74,7 +74,7 @@ func FindGitRevision(ctx context.Context, file string) (shortSha string, sha str
} }
if head.Hash().IsZero() { if head.Hash().IsZero() {
return "", "", fmt.Errorf("head sha1 could not be resolved") return "", "", errors.New("head sha1 could not be resolved")
} }
hash := head.Hash().String() hash := head.Hash().String()
@@ -319,7 +319,7 @@ func NewGitCloneExecutor(input NewGitCloneExecutorInput) common.Executor {
cloneLock.Lock() cloneLock.Lock()
defer cloneLock.Unlock() defer cloneLock.Unlock()
refName := plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", input.Ref)) refName := plumbing.ReferenceName("refs/heads/" + input.Ref)
r, err := CloneIfRequired(ctx, refName, input, logger) r, err := CloneIfRequired(ctx, refName, input, logger)
if err != nil { if err != nil {
return err return err

View File

@@ -216,7 +216,7 @@ func TestGitCloneExecutor(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, tt.Err, err) assert.Equal(t, tt.Err, err)
} else { } else {
assert.Empty(t, err) assert.NoError(t, err)
} }
}) })
} }

View File

@@ -19,6 +19,7 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"regexp" "regexp"
"slices"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -559,7 +560,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
return nil, errors.Errorf("--health-retries cannot be negative") return nil, errors.Errorf("--health-retries cannot be negative")
} }
if copts.healthStartPeriod < 0 { if copts.healthStartPeriod < 0 {
return nil, fmt.Errorf("--health-start-period cannot be negative") return nil, errors.New("--health-start-period cannot be negative")
} }
healthConfig = &container.HealthConfig{ healthConfig = &container.HealthConfig{
@@ -836,7 +837,7 @@ func convertToStandardNotation(ports []string) ([]string, error) {
for _, publish := range ports { for _, publish := range ports {
if strings.Contains(publish, "=") { if strings.Contains(publish, "=") {
params := map[string]string{"protocol": "tcp"} params := map[string]string{"protocol": "tcp"}
for _, param := range strings.Split(publish, ",") { for param := range strings.SplitSeq(publish, ",") {
opt := strings.Split(param, "=") opt := strings.Split(param, "=")
if len(opt) < 2 { if len(opt) < 2 {
return optsList, errors.Errorf("invalid publish opts format (should be name=value but got '%s')", param) return optsList, errors.Errorf("invalid publish opts format (should be name=value but got '%s')", param)
@@ -1066,10 +1067,8 @@ func validateLinuxPath(val string, validator func(string) bool) (string, error)
// validateAttach validates that the specified string is a valid attach option. // validateAttach validates that the specified string is a valid attach option.
func validateAttach(val string) (string, error) { func validateAttach(val string) (string, error) {
s := strings.ToLower(val) s := strings.ToLower(val)
for _, str := range []string{"stdin", "stdout", "stderr"} { if slices.Contains([]string{"stdin", "stdout", "stderr"}, s) {
if s == str { return s, nil
return s, nil
}
} }
return val, errors.Errorf("valid streams are STDIN, STDOUT and STDERR") return val, errors.Errorf("valid streams are STDIN, STDOUT and STDERR")
} }

View File

@@ -339,7 +339,7 @@ func TestParseHostname(t *testing.T) {
hostnameWithDomain := "--hostname=hostname.domainname" hostnameWithDomain := "--hostname=hostname.domainname"
hostnameWithDomainTld := "--hostname=hostname.domainname.tld" hostnameWithDomainTld := "--hostname=hostname.domainname.tld"
for hostname, expectedHostname := range validHostnames { for hostname, expectedHostname := range validHostnames {
if config, _, _ := mustParse(t, fmt.Sprintf("--hostname=%s", hostname)); config.Hostname != expectedHostname { if config, _, _ := mustParse(t, "--hostname="+hostname); config.Hostname != expectedHostname {
t.Fatalf("Expected the config to have 'hostname' as %q, got %q", expectedHostname, config.Hostname) t.Fatalf("Expected the config to have 'hostname' as %q, got %q", expectedHostname, config.Hostname)
} }
} }
@@ -677,7 +677,7 @@ func TestParseRestartPolicy(t *testing.T) {
}, },
} }
for restart, expectedError := range invalids { for restart, expectedError := range invalids {
if _, _, _, err := parseRun([]string{fmt.Sprintf("--restart=%s", restart), "img", "cmd"}); err == nil || err.Error() != expectedError { if _, _, _, err := parseRun([]string{"--restart=" + restart, "img", "cmd"}); err == nil || err.Error() != expectedError {
t.Fatalf("Expected an error with message '%v' for %v, got %v", expectedError, restart, err) t.Fatalf("Expected an error with message '%v' for %v, got %v", expectedError, restart, err)
} }
} }

View File

@@ -26,17 +26,17 @@ func TestImageExistsLocally(t *testing.T) {
// Test if image exists with specific tag // Test if image exists with specific tag
invalidImageTag, err := ImageExistsLocally(ctx, "library/alpine:this-random-tag-will-never-exist", "linux/amd64") invalidImageTag, err := ImageExistsLocally(ctx, "library/alpine:this-random-tag-will-never-exist", "linux/amd64")
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, false, invalidImageTag) assert.False(t, invalidImageTag)
// Test if image exists with specific architecture (image platform) // Test if image exists with specific architecture (image platform)
invalidImagePlatform, err := ImageExistsLocally(ctx, "alpine:latest", "windows/amd64") invalidImagePlatform, err := ImageExistsLocally(ctx, "alpine:latest", "windows/amd64")
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, false, invalidImagePlatform) assert.False(t, invalidImagePlatform)
// pull an image // pull an image
cli, err := client.NewClientWithOpts(client.FromEnv) cli, err := client.NewClientWithOpts(client.FromEnv)
assert.Nil(t, err) assert.NoError(t, err)
cli.NegotiateAPIVersion(context.Background()) cli.NegotiateAPIVersion(context.Background())
// Chose alpine latest because it's so small // Chose alpine latest because it's so small
@@ -44,14 +44,14 @@ func TestImageExistsLocally(t *testing.T) {
readerDefault, err := cli.ImagePull(ctx, "node:16-buster-slim", image.PullOptions{ readerDefault, err := cli.ImagePull(ctx, "node:16-buster-slim", image.PullOptions{
Platform: "linux/amd64", Platform: "linux/amd64",
}) })
assert.Nil(t, err) assert.NoError(t, err)
defer readerDefault.Close() defer readerDefault.Close()
_, err = io.ReadAll(readerDefault) _, err = io.ReadAll(readerDefault)
assert.Nil(t, err) assert.NoError(t, err)
imageDefaultArchExists, err := ImageExistsLocally(ctx, "node:16-buster-slim", "linux/amd64") imageDefaultArchExists, err := ImageExistsLocally(ctx, "node:16-buster-slim", "linux/amd64")
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, true, imageDefaultArchExists) assert.True(t, imageDefaultArchExists)
} }
func TestImageExistsLocallyQemu(t *testing.T) { func TestImageExistsLocallyQemu(t *testing.T) {
@@ -66,19 +66,19 @@ func TestImageExistsLocallyQemu(t *testing.T) {
// pull an image // pull an image
cli, err := client.NewClientWithOpts(client.FromEnv) cli, err := client.NewClientWithOpts(client.FromEnv)
assert.Nil(t, err) assert.NoError(t, err)
cli.NegotiateAPIVersion(context.Background()) cli.NegotiateAPIVersion(context.Background())
// Validate if another architecture platform can be pulled // Validate if another architecture platform can be pulled
readerArm64, err := cli.ImagePull(ctx, "node:16-buster-slim", image.PullOptions{ readerArm64, err := cli.ImagePull(ctx, "node:16-buster-slim", image.PullOptions{
Platform: "linux/arm64", Platform: "linux/arm64",
}) })
assert.Nil(t, err) assert.NoError(t, err)
defer readerArm64.Close() defer readerArm64.Close()
_, err = io.ReadAll(readerArm64) _, err = io.ReadAll(readerArm64)
assert.Nil(t, err) assert.NoError(t, err)
imageArm64Exists, err := ImageExistsLocally(ctx, "node:16-buster-slim", "linux/arm64") imageArm64Exists, err := ImageExistsLocally(ctx, "node:16-buster-slim", "linux/arm64")
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, true, imageArm64Exists) assert.True(t, imageArm64Exists)
} }

View File

@@ -74,7 +74,7 @@ func logDockerResponse(logger logrus.FieldLogger, dockerResponse io.ReadCloser,
return nil return nil
} }
func writeLog(logger logrus.FieldLogger, isError bool, format string, args ...interface{}) { func writeLog(logger logrus.FieldLogger, isError bool, format string, args ...any) {
if isError { if isError {
logger.Errorf(format, args...) logger.Errorf(format, args...)
} else { } else {

View File

@@ -40,15 +40,15 @@ func TestGetImagePullOptions(t *testing.T) {
config.SetDir("/non-existent/docker") config.SetDir("/non-existent/docker")
options, err := getImagePullOptions(ctx, NewDockerPullExecutorInput{}) options, err := getImagePullOptions(ctx, NewDockerPullExecutorInput{})
assert.Nil(t, err, "Failed to create ImagePullOptions") assert.NoError(t, err, "Failed to create ImagePullOptions")
assert.Equal(t, "", options.RegistryAuth, "RegistryAuth should be empty if no username or password is set") assert.Empty(t, options.RegistryAuth, "RegistryAuth should be empty if no username or password is set")
options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{ options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{
Image: "", Image: "",
Username: "username", Username: "username",
Password: "password", Password: "password",
}) })
assert.Nil(t, err, "Failed to create ImagePullOptions") assert.NoError(t, err, "Failed to create ImagePullOptions")
assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9", options.RegistryAuth, "Username and Password should be provided") assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9", options.RegistryAuth, "Username and Password should be provided")
config.SetDir("testdata/docker-pull-options") config.SetDir("testdata/docker-pull-options")
@@ -56,6 +56,6 @@ func TestGetImagePullOptions(t *testing.T) {
options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{ options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{
Image: "nektos/act", Image: "nektos/act",
}) })
assert.Nil(t, err, "Failed to create ImagePullOptions") assert.NoError(t, err, "Failed to create ImagePullOptions")
assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZFxuIiwic2VydmVyYWRkcmVzcyI6Imh0dHBzOi8vaW5kZXguZG9ja2VyLmlvL3YxLyJ9", options.RegistryAuth, "RegistryAuth should be taken from local docker config") assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZFxuIiwic2VydmVyYWRkcmVzcyI6Imh0dHBzOi8vaW5kZXguZG9ja2VyLmlvL3YxLyJ9", options.RegistryAuth, "RegistryAuth should be taken from local docker config")
} }

View File

@@ -137,7 +137,7 @@ func (cr *containerReference) CopyDir(destPath string, srcPath string, useGitIgn
func (cr *containerReference) GetContainerArchive(ctx context.Context, srcPath string) (io.ReadCloser, error) { func (cr *containerReference) GetContainerArchive(ctx context.Context, srcPath string) (io.ReadCloser, error) {
if common.Dryrun(ctx) { if common.Dryrun(ctx) {
return nil, fmt.Errorf("dryrun is not supported in GetContainerArchive") return nil, errors.New("dryrun is not supported in GetContainerArchive")
} }
a, _, err := cr.cli.CopyFromContainer(ctx, cr.id, srcPath) a, _, err := cr.cli.CopyFromContainer(ctx, cr.id, srcPath)
return a, err return a, err

View File

@@ -4,7 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"fmt" "errors"
"io" "io"
"net" "net"
"strings" "strings"
@@ -216,7 +216,7 @@ func TestDockerCopyTarStreamErrorInCopyFiles(t *testing.T) {
conn := &mockConn{} conn := &mockConn{}
merr := fmt.Errorf("failure") merr := errors.New("failure")
client := &mockDockerClient{} client := &mockDockerClient{}
client.On("CopyToContainer", ctx, "123", "/", mock.Anything, mock.AnythingOfType("container.CopyToContainerOptions")).Return(merr) client.On("CopyToContainer", ctx, "123", "/", mock.Anything, mock.AnythingOfType("container.CopyToContainerOptions")).Return(merr)
@@ -241,7 +241,7 @@ func TestDockerCopyTarStreamErrorInMkdir(t *testing.T) {
conn := &mockConn{} conn := &mockConn{}
merr := fmt.Errorf("failure") merr := errors.New("failure")
client := &mockDockerClient{} client := &mockDockerClient{}
client.On("CopyToContainer", ctx, "123", "/", mock.Anything, mock.AnythingOfType("container.CopyToContainerOptions")).Return(nil) client.On("CopyToContainer", ctx, "123", "/", mock.Anything, mock.AnythingOfType("container.CopyToContainerOptions")).Return(nil)

View File

@@ -43,8 +43,8 @@ func socketLocation() (string, bool) {
// indicating that the `daemonPath` is a Docker host URI. If it doesn't, or if the "://" delimiter // indicating that the `daemonPath` is a Docker host URI. If it doesn't, or if the "://" delimiter
// is not found in the `daemonPath`, the function returns false. // is not found in the `daemonPath`, the function returns false.
func isDockerHostURI(daemonPath string) bool { func isDockerHostURI(daemonPath string) bool {
if protoIndex := strings.Index(daemonPath, "://"); protoIndex != -1 { if before, _, ok := strings.Cut(daemonPath, "://"); ok {
scheme := daemonPath[:protoIndex] scheme := before
if strings.IndexFunc(scheme, func(r rune) bool { if strings.IndexFunc(scheme, func(r rune) bool {
return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z')
}) == -1 { }) == -1 {

View File

@@ -25,7 +25,7 @@ func TestGetSocketAndHostWithSocket(t *testing.T) {
ret, err := GetSocketAndHost(socketURI) ret, err := GetSocketAndHost(socketURI)
// Assert // Assert
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, SocketAndHost{socketURI, dockerHost}, ret) assert.Equal(t, SocketAndHost{socketURI, dockerHost}, ret)
} }
@@ -38,7 +38,7 @@ func TestGetSocketAndHostNoSocket(t *testing.T) {
ret, err := GetSocketAndHost("") ret, err := GetSocketAndHost("")
// Assert // Assert
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, SocketAndHost{dockerHost, dockerHost}, ret) assert.Equal(t, SocketAndHost{dockerHost, dockerHost}, ret)
} }
@@ -54,7 +54,7 @@ func TestGetSocketAndHostOnlySocket(t *testing.T) {
// Assert // Assert
assert.NoError(t, err, "Expected no error from GetSocketAndHost") assert.NoError(t, err, "Expected no error from GetSocketAndHost")
assert.Equal(t, true, defaultSocketFound, "Expected to find default socket") assert.True(t, defaultSocketFound, "Expected to find default socket")
assert.Equal(t, socketURI, ret.Socket, "Expected socket to match common location") assert.Equal(t, socketURI, ret.Socket, "Expected socket to match common location")
assert.Equal(t, defaultSocket, ret.Host, "Expected ret.Host to match default socket location") assert.Equal(t, defaultSocket, ret.Host, "Expected ret.Host to match default socket location")
} }
@@ -69,7 +69,7 @@ func TestGetSocketAndHostDontMount(t *testing.T) {
ret, err := GetSocketAndHost("-") ret, err := GetSocketAndHost("-")
// Assert // Assert
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, SocketAndHost{"-", dockerHost}, ret) assert.Equal(t, SocketAndHost{"-", dockerHost}, ret)
} }
@@ -83,8 +83,8 @@ func TestGetSocketAndHostNoHostNoSocket(t *testing.T) {
ret, err := GetSocketAndHost("") ret, err := GetSocketAndHost("")
// Assert // Assert
assert.Equal(t, true, found, "Expected a default socket to be found") assert.True(t, found, "Expected a default socket to be found")
assert.Nil(t, err, "Expected no error from GetSocketAndHost") assert.NoError(t, err, "Expected no error from GetSocketAndHost")
assert.Equal(t, SocketAndHost{defaultSocket, defaultSocket}, ret, "Expected to match default socket location") assert.Equal(t, SocketAndHost{defaultSocket, defaultSocket}, ret, "Expected to match default socket location")
} }
@@ -93,7 +93,7 @@ func TestGetSocketAndHostNoHostNoSocket(t *testing.T) {
// > This happens if neither DOCKER_HOST nor --container-daemon-socket has a value, but socketLocation() returns a URI // > This happens if neither DOCKER_HOST nor --container-daemon-socket has a value, but socketLocation() returns a URI
func TestGetSocketAndHostNoHostNoSocketDefaultLocation(t *testing.T) { func TestGetSocketAndHostNoHostNoSocketDefaultLocation(t *testing.T) {
// Arrange // Arrange
mySocketFile, tmpErr := os.CreateTemp("", "act-*.sock") mySocketFile, tmpErr := os.CreateTemp(t.TempDir(), "act-*.sock")
mySocket := mySocketFile.Name() mySocket := mySocketFile.Name()
unixSocket := "unix://" + mySocket unixSocket := "unix://" + mySocket
defer os.RemoveAll(mySocket) defer os.RemoveAll(mySocket)
@@ -108,8 +108,8 @@ func TestGetSocketAndHostNoHostNoSocketDefaultLocation(t *testing.T) {
// Assert // Assert
assert.Equal(t, unixSocket, defaultSocket, "Expected default socket to match common socket location") assert.Equal(t, unixSocket, defaultSocket, "Expected default socket to match common socket location")
assert.Equal(t, true, found, "Expected default socket to be found") assert.True(t, found, "Expected default socket to be found")
assert.Nil(t, err, "Expected no error from GetSocketAndHost") assert.NoError(t, err, "Expected no error from GetSocketAndHost")
assert.Equal(t, SocketAndHost{unixSocket, unixSocket}, ret, "Expected to match default socket location") assert.Equal(t, SocketAndHost{unixSocket, unixSocket}, ret, "Expected to match default socket location")
} }
@@ -124,8 +124,8 @@ func TestGetSocketAndHostNoHostInvalidSocket(t *testing.T) {
ret, err := GetSocketAndHost(mySocket) ret, err := GetSocketAndHost(mySocket)
// Assert // Assert
assert.Equal(t, false, found, "Expected no default socket to be found") assert.False(t, found, "Expected no default socket to be found")
assert.Equal(t, "", defaultSocket, "Expected no default socket to be found") assert.Empty(t, defaultSocket, "Expected no default socket to be found")
assert.Equal(t, SocketAndHost{}, ret, "Expected to match default socket location") assert.Equal(t, SocketAndHost{}, ret, "Expected to match default socket location")
assert.Error(t, err, "Expected an error in invalid state") assert.Error(t, err, "Expected an error in invalid state")
} }
@@ -142,9 +142,9 @@ func TestGetSocketAndHostOnlySocketValidButUnusualLocation(t *testing.T) {
// Assert // Assert
// Default socket locations // Default socket locations
assert.Equal(t, "", defaultSocket, "Expect default socket location to be empty") assert.Empty(t, defaultSocket, "Expect default socket location to be empty")
assert.Equal(t, false, found, "Expected no default socket to be found") assert.False(t, found, "Expected no default socket to be found")
// Sane default // Sane default
assert.Nil(t, err, "Expect no error from GetSocketAndHost") assert.NoError(t, err, "Expect no error from GetSocketAndHost")
assert.Equal(t, socketURI, ret.Host, "Expect host to default to unusual socket") assert.Equal(t, socketURI, ret.Host, "Expect host to default to unusual socket")
} }

View File

@@ -9,7 +9,7 @@ type ExecutionsEnvironment interface {
GetPathVariableName() string GetPathVariableName() string
DefaultPathVariable() string DefaultPathVariable() string
JoinPathVariable(...string) string JoinPathVariable(...string) string
GetRunnerContext(ctx context.Context) map[string]interface{} GetRunnerContext(ctx context.Context) map[string]any
// On windows PATH and Path are the same key // On windows PATH and Path are the same key
IsEnvironmentCaseInsensitive() bool IsEnvironmentCaseInsensitive() bool
} }

View File

@@ -83,7 +83,7 @@ func (e *HostEnvironment) CopyTarStream(ctx context.Context, destPath string, ta
continue continue
} }
if ctx.Err() != nil { if ctx.Err() != nil {
return fmt.Errorf("copyTarStream has been cancelled") return errors.New("copyTarStream has been cancelled")
} }
if err := cp.WriteFile(ti.Name, ti.FileInfo(), ti.Linkname, tr); err != nil { if err := cp.WriteFile(ti.Name, ti.FileInfo(), ti.Linkname, tr); err != nil {
return err return err
@@ -224,7 +224,7 @@ func (l *localEnv) Getenv(name string) string {
func lookupPathHost(cmd string, env map[string]string, writer io.Writer) (string, error) { func lookupPathHost(cmd string, env map[string]string, writer io.Writer) (string, error) {
f, err := lookpath.LookPath2(cmd, &localEnv{env: env}) f, err := lookpath.LookPath2(cmd, &localEnv{env: env})
if err != nil { if err != nil {
err := "Cannot find: " + fmt.Sprint(cmd) + " in PATH" err := "Cannot find: " + cmd + " in PATH"
if _, _err := writer.Write([]byte(err + "\n")); _err != nil { if _, _err := writer.Write([]byte(err + "\n")); _err != nil {
return "", fmt.Errorf("%v: %w", err, _err) return "", fmt.Errorf("%v: %w", err, _err)
} }
@@ -343,7 +343,7 @@ func (e *HostEnvironment) exec(ctx context.Context, command []string, cmdline st
} }
if tty != nil { if tty != nil {
writer.AutoStop = true writer.AutoStop = true
if _, err := tty.Write([]byte("\x04")); err != nil { if _, err := tty.WriteString("\x04"); err != nil {
common.Logger(ctx).Debug("Failed to write EOT") common.Logger(ctx).Debug("Failed to write EOT")
} }
} }
@@ -451,8 +451,8 @@ func goOsToActionOs(os string) string {
return os return os
} }
func (e *HostEnvironment) GetRunnerContext(_ context.Context) map[string]interface{} { func (e *HostEnvironment) GetRunnerContext(_ context.Context) map[string]any {
return map[string]interface{}{ return map[string]any{
"os": goOsToActionOs(runtime.GOOS), "os": goOsToActionOs(runtime.GOOS),
"arch": goArchToActionArch(runtime.GOARCH), "arch": goArchToActionArch(runtime.GOARCH),
"temp": e.TmpDir, "temp": e.TmpDir,

View File

@@ -63,8 +63,8 @@ func (*LinuxContainerEnvironmentExtensions) JoinPathVariable(paths ...string) st
return strings.Join(paths, ":") return strings.Join(paths, ":")
} }
func (*LinuxContainerEnvironmentExtensions) GetRunnerContext(ctx context.Context) map[string]interface{} { func (*LinuxContainerEnvironmentExtensions) GetRunnerContext(ctx context.Context) map[string]any {
return map[string]interface{}{ return map[string]any{
"os": "Linux", "os": "Linux",
"arch": RunnerArch(ctx), "arch": RunnerArch(ctx),
"temp": "/tmp", "temp": "/tmp",

View File

@@ -31,8 +31,8 @@ func TestContainerPath(t *testing.T) {
for _, v := range []containerPathJob{ for _, v := range []containerPathJob{
{"/mnt/c/Users/act/go/src/github.com/nektos/act", "C:\\Users\\act\\go\\src\\github.com\\nektos\\act\\", ""}, {"/mnt/c/Users/act/go/src/github.com/nektos/act", "C:\\Users\\act\\go\\src\\github.com\\nektos\\act\\", ""},
{"/mnt/f/work/dir", `F:\work\dir`, ""}, {"/mnt/f/work/dir", `F:\work\dir`, ""},
{"/mnt/c/windows/to/unix", "windows\\to\\unix", fmt.Sprintf("%s\\", rootDrive)}, {"/mnt/c/windows/to/unix", "windows\\to\\unix", rootDrive + "\\"},
{fmt.Sprintf("/mnt/%v/act", rootDriveLetter), "act", fmt.Sprintf("%s\\", rootDrive)}, {fmt.Sprintf("/mnt/%v/act", rootDriveLetter), "act", rootDrive + "\\"},
} { } {
if v.workDir != "" { if v.workDir != "" {
if err := os.Chdir(v.workDir); err != nil { if err := os.Chdir(v.workDir); err != nil {

View File

@@ -13,11 +13,11 @@ func (impl *interperterImpl) getNeedsTransitive(job *model.Job) []string {
return needs return needs
} }
func (impl *interperterImpl) always() (interface{}, error) { func (impl *interperterImpl) always() (any, error) {
return true, nil return true, nil
} }
func (impl *interperterImpl) jobSuccess() (interface{}, error) { func (impl *interperterImpl) jobSuccess() (any, error) {
jobs := impl.config.Run.Workflow.Jobs jobs := impl.config.Run.Workflow.Jobs
jobNeeds := impl.getNeedsTransitive(impl.config.Run.Job()) jobNeeds := impl.getNeedsTransitive(impl.config.Run.Job())
@@ -30,11 +30,11 @@ func (impl *interperterImpl) jobSuccess() (interface{}, error) {
return true, nil return true, nil
} }
func (impl *interperterImpl) stepSuccess() (interface{}, error) { func (impl *interperterImpl) stepSuccess() (any, error) {
return impl.env.Job.Status == "success", nil return impl.env.Job.Status == "success", nil
} }
func (impl *interperterImpl) jobFailure() (interface{}, error) { func (impl *interperterImpl) jobFailure() (any, error) {
jobs := impl.config.Run.Workflow.Jobs jobs := impl.config.Run.Workflow.Jobs
jobNeeds := impl.getNeedsTransitive(impl.config.Run.Job()) jobNeeds := impl.getNeedsTransitive(impl.config.Run.Job())
@@ -47,10 +47,10 @@ func (impl *interperterImpl) jobFailure() (interface{}, error) {
return false, nil return false, nil
} }
func (impl *interperterImpl) stepFailure() (interface{}, error) { func (impl *interperterImpl) stepFailure() (any, error) {
return impl.env.Job.Status == "failure", nil return impl.env.Job.Status == "failure", nil
} }
func (impl *interperterImpl) cancelled() (interface{}, error) { func (impl *interperterImpl) cancelled() (any, error) {
return impl.env.Job.Status == "cancelled", nil return impl.env.Job.Status == "cancelled", nil
} }

View File

@@ -18,16 +18,16 @@ type EvaluationEnvironment struct {
Job *model.JobContext Job *model.JobContext
Jobs *map[string]*model.WorkflowCallResult Jobs *map[string]*model.WorkflowCallResult
Steps map[string]*model.StepResult Steps map[string]*model.StepResult
Runner map[string]interface{} Runner map[string]any
Secrets map[string]string Secrets map[string]string
Vars map[string]string Vars map[string]string
Strategy map[string]interface{} Strategy map[string]any
Matrix map[string]interface{} Matrix map[string]any
Needs map[string]Needs Needs map[string]Needs
Inputs map[string]interface{} Inputs map[string]any
HashFiles func([]reflect.Value) (interface{}, error) HashFiles func([]reflect.Value) (any, error)
EnvCS bool EnvCS bool
CtxData map[string]interface{} CtxData map[string]any
} }
type CaseSensitiveDict map[string]string type CaseSensitiveDict map[string]string
@@ -69,7 +69,7 @@ func (dsc DefaultStatusCheck) String() string {
} }
type Interpreter interface { type Interpreter interface {
Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (interface{}, error) Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (any, error)
} }
type interperterImpl struct { type interperterImpl struct {
@@ -151,7 +151,7 @@ func toRaw(left reflect.Value) any {
// All values are evaluated as string, funcs that takes objects are implemented elsewhere // All values are evaluated as string, funcs that takes objects are implemented elsewhere
type externalFunc struct { type externalFunc struct {
f func([]reflect.Value) (interface{}, error) f func([]reflect.Value) (any, error)
} }
func (e externalFunc) Evaluate(ev *eval.Evaluator, args []exprparser.Node) (*eval.EvaluationResult, error) { func (e externalFunc) Evaluate(ev *eval.Evaluator, args []exprparser.Node) (*eval.EvaluationResult, error) {
@@ -170,7 +170,7 @@ func (e externalFunc) Evaluate(ev *eval.Evaluator, args []exprparser.Node) (*eva
return eval.CreateIntermediateResult(ev.Context(), res), nil return eval.CreateIntermediateResult(ev.Context(), res), nil
} }
func (impl *interperterImpl) Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (interface{}, error) { func (impl *interperterImpl) Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (any, error) {
input = strings.TrimPrefix(input, "${{") input = strings.TrimPrefix(input, "${{")
input = strings.TrimSuffix(input, "}}") input = strings.TrimSuffix(input, "}}")
if defaultStatusCheck != DefaultStatusCheckNone && input == "" { if defaultStatusCheck != DefaultStatusCheckNone && input == "" {
@@ -226,10 +226,10 @@ func (impl *interperterImpl) GetFunctions() eval.CaseInsensitiveObject[eval.Func
if impl.env.HashFiles != nil { if impl.env.HashFiles != nil {
functions["hashfiles"] = &externalFunc{impl.env.HashFiles} functions["hashfiles"] = &externalFunc{impl.env.HashFiles}
} }
functions["always"] = &externalFunc{func(_ []reflect.Value) (interface{}, error) { functions["always"] = &externalFunc{func(_ []reflect.Value) (any, error) {
return impl.always() return impl.always()
}} }}
functions["success"] = &externalFunc{func(_ []reflect.Value) (interface{}, error) { functions["success"] = &externalFunc{func(_ []reflect.Value) (any, error) {
if impl.config.Context == "job" { if impl.config.Context == "job" {
return impl.jobSuccess() return impl.jobSuccess()
} }
@@ -238,7 +238,7 @@ func (impl *interperterImpl) GetFunctions() eval.CaseInsensitiveObject[eval.Func
} }
return nil, fmt.Errorf("context '%s' must be one of 'job' or 'step'", impl.config.Context) return nil, fmt.Errorf("context '%s' must be one of 'job' or 'step'", impl.config.Context)
}} }}
functions["failure"] = &externalFunc{func(_ []reflect.Value) (interface{}, error) { functions["failure"] = &externalFunc{func(_ []reflect.Value) (any, error) {
if impl.config.Context == "job" { if impl.config.Context == "job" {
return impl.jobFailure() return impl.jobFailure()
} }
@@ -247,7 +247,7 @@ func (impl *interperterImpl) GetFunctions() eval.CaseInsensitiveObject[eval.Func
} }
return nil, fmt.Errorf("context '%s' must be one of 'job' or 'step'", impl.config.Context) return nil, fmt.Errorf("context '%s' must be one of 'job' or 'step'", impl.config.Context)
}} }}
functions["cancelled"] = &externalFunc{func(_ []reflect.Value) (interface{}, error) { functions["cancelled"] = &externalFunc{func(_ []reflect.Value) (any, error) {
return impl.cancelled() return impl.cancelled()
}} }}
return functions return functions
@@ -287,7 +287,7 @@ func (impl *interperterImpl) GetVariables() eval.ReadOnlyObject[any] {
res := eval.CreateIntermediateResult(eval.NewEvaluationContext(), rawOtherCtx) res := eval.CreateIntermediateResult(eval.NewEvaluationContext(), rawOtherCtx)
if rOtherCd, ok := res.TryGetCollectionInterface(); ok { if rOtherCd, ok := res.TryGetCollectionInterface(); ok {
if otherCd, ok := rOtherCd.(eval.ReadOnlyObject[any]); ok { if otherCd, ok := rOtherCd.(eval.ReadOnlyObject[any]); ok {
if rawPayload, ok := cd.(map[string]interface{}); ok { if rawPayload, ok := cd.(map[string]any); ok {
for k, v := range rawPayload { for k, v := range rawPayload {
// skip empty values, because github.workspace was set by Gitea Actions to an empty string // skip empty values, because github.workspace was set by Gitea Actions to an empty string
if mk, _ := otherCd.GetKv(k); v != "" && v != nil { if mk, _ := otherCd.GetKv(k); v != "" && v != nil {
@@ -304,7 +304,7 @@ func (impl *interperterImpl) GetVariables() eval.ReadOnlyObject[any] {
return vars return vars
} }
func IsTruthy(input interface{}) bool { func IsTruthy(input any) bool {
value := reflect.ValueOf(input) value := reflect.ValueOf(input)
switch value.Kind() { switch value.Kind() {
case reflect.Bool: case reflect.Bool:

View File

@@ -11,7 +11,7 @@ import (
func TestLiterals(t *testing.T) { func TestLiterals(t *testing.T) {
table := []struct { table := []struct {
input string input string
expected interface{} expected any
name string name string
}{ }{
{"true", true, "true"}, {"true", true, "true"},
@@ -30,7 +30,7 @@ func TestLiterals(t *testing.T) {
for _, tt := range table { for _, tt := range table {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, tt.expected, output) assert.Equal(t, tt.expected, output)
}) })
@@ -40,7 +40,7 @@ func TestLiterals(t *testing.T) {
func TestOperators(t *testing.T) { func TestOperators(t *testing.T) {
table := []struct { table := []struct {
input string input string
expected interface{} expected any
name string name string
error string error string
}{ }{
@@ -69,7 +69,7 @@ func TestOperators(t *testing.T) {
{`true && false`, false, "and", ""}, {`true && false`, false, "and", ""},
{`true || false`, true, "or", ""}, {`true || false`, true, "or", ""},
{`fromJSON('{}') && true`, true, "and-boolean-object", ""}, {`fromJSON('{}') && true`, true, "and-boolean-object", ""},
{`fromJSON('{}') || false`, make(map[string]interface{}), "or-boolean-object", ""}, {`fromJSON('{}') || false`, make(map[string]any), "or-boolean-object", ""},
{"github.event.commits[0].author.username != github.event.commits[1].author.username", true, "property-comparison1", ""}, {"github.event.commits[0].author.username != github.event.commits[1].author.username", true, "property-comparison1", ""},
{"github.event.commits[0].author.username1 != github.event.commits[1].author.username", true, "property-comparison2", ""}, {"github.event.commits[0].author.username1 != github.event.commits[1].author.username", true, "property-comparison2", ""},
{"github.event.commits[0].author.username != github.event.commits[1].author.username1", true, "property-comparison3", ""}, {"github.event.commits[0].author.username != github.event.commits[1].author.username1", true, "property-comparison3", ""},
@@ -81,15 +81,15 @@ func TestOperators(t *testing.T) {
env := &EvaluationEnvironment{ env := &EvaluationEnvironment{
Github: &model.GithubContext{ Github: &model.GithubContext{
Action: "push", Action: "push",
Event: map[string]interface{}{ Event: map[string]any{
"commits": []interface{}{ "commits": []any{
map[string]interface{}{ map[string]any{
"author": map[string]interface{}{ "author": map[string]any{
"username": "someone", "username": "someone",
}, },
}, },
map[string]interface{}{ map[string]any{
"author": map[string]interface{}{ "author": map[string]any{
"username": "someone-else", "username": "someone-else",
}, },
}, },
@@ -102,10 +102,10 @@ func TestOperators(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone)
if tt.error != "" { if tt.error != "" {
assert.NotNil(t, err) assert.Error(t, err)
assert.Equal(t, tt.error, err.Error()) assert.Equal(t, tt.error, err.Error())
} else { } else {
assert.Nil(t, err) assert.NoError(t, err)
} }
assert.Equal(t, tt.expected, output) assert.Equal(t, tt.expected, output)
@@ -116,7 +116,7 @@ func TestOperators(t *testing.T) {
func TestOperatorsCompare(t *testing.T) { func TestOperatorsCompare(t *testing.T) {
table := []struct { table := []struct {
input string input string
expected interface{} expected any
name string name string
}{ }{
{"!null", true, "not-null"}, {"!null", true, "not-null"},
@@ -154,7 +154,7 @@ func TestOperatorsCompare(t *testing.T) {
for _, tt := range table { for _, tt := range table {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, tt.expected, output) assert.Equal(t, tt.expected, output)
}) })
@@ -164,7 +164,7 @@ func TestOperatorsCompare(t *testing.T) {
func TestOperatorsBooleanEvaluation(t *testing.T) { func TestOperatorsBooleanEvaluation(t *testing.T) {
table := []struct { table := []struct {
input string input string
expected interface{} expected any
name string name string
}{ }{
// true && // true &&
@@ -517,7 +517,7 @@ func TestOperatorsBooleanEvaluation(t *testing.T) {
for _, tt := range table { for _, tt := range table {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone)
assert.Nil(t, err) assert.NoError(t, err)
// Normalize int => float64 // Normalize int => float64
if i, ok := tt.expected.(int); ok { if i, ok := tt.expected.(int); ok {
@@ -536,15 +536,15 @@ func TestOperatorsBooleanEvaluation(t *testing.T) {
func TestContexts(t *testing.T) { func TestContexts(t *testing.T) {
table := []struct { table := []struct {
input string input string
expected interface{} expected any
name string name string
caseSensitiveEnv bool caseSensitiveEnv bool
ctxdata map[string]interface{} ctxdata map[string]any
}{ }{
{input: "github.action", expected: "push", name: "github-context"}, {input: "github.action", expected: "push", name: "github-context"},
{input: "github.action", expected: "push", name: "github-context", ctxdata: map[string]interface{}{"github": map[string]interface{}{"ref": "refs/heads/test-data"}}}, {input: "github.action", expected: "push", name: "github-context", ctxdata: map[string]any{"github": map[string]any{"ref": "refs/heads/test-data"}}},
{input: "github.ref", expected: "refs/heads/test-data", name: "github-context", ctxdata: map[string]interface{}{"github": map[string]interface{}{"ref": "refs/heads/test-data"}}}, {input: "github.ref", expected: "refs/heads/test-data", name: "github-context", ctxdata: map[string]any{"github": map[string]any{"ref": "refs/heads/test-data"}}},
{input: "github.custom-field", expected: "custom-value", name: "github-context", ctxdata: map[string]interface{}{"github": map[string]interface{}{"custom-field": "custom-value"}}}, {input: "github.custom-field", expected: "custom-value", name: "github-context", ctxdata: map[string]any{"github": map[string]any{"custom-field": "custom-value"}}},
{input: "github.event.commits[0].message", expected: nil, name: "github-context-noexist-prop"}, {input: "github.event.commits[0].message", expected: nil, name: "github-context-noexist-prop"},
{input: "fromjson('{\"commits\":[]}').commits[0].message", expected: nil, name: "github-context-noexist-prop"}, {input: "fromjson('{\"commits\":[]}').commits[0].message", expected: nil, name: "github-context-noexist-prop"},
{input: "github.event.pull_request.labels.*.name", expected: nil, name: "github-context-noexist-prop"}, {input: "github.event.pull_request.labels.*.name", expected: nil, name: "github-context-noexist-prop"},
@@ -581,8 +581,8 @@ func TestContexts(t *testing.T) {
{input: "contains(needs.*.result, 'success')", expected: true, name: "needs-wildcard-context-contains-success"}, {input: "contains(needs.*.result, 'success')", expected: true, name: "needs-wildcard-context-contains-success"},
{input: "contains(needs.*.result, 'failure')", expected: false, name: "needs-wildcard-context-contains-failure"}, {input: "contains(needs.*.result, 'failure')", expected: false, name: "needs-wildcard-context-contains-failure"},
{input: "inputs.name", expected: "value", name: "inputs-context"}, {input: "inputs.name", expected: "value", name: "inputs-context"},
{input: "vars.MY_VAR", expected: "refs/heads/test-data", name: "vars-context", ctxdata: map[string]interface{}{"vars": map[string]interface{}{"MY_VAR": "refs/heads/test-data"}}}, {input: "vars.MY_VAR", expected: "refs/heads/test-data", name: "vars-context", ctxdata: map[string]any{"vars": map[string]any{"MY_VAR": "refs/heads/test-data"}}},
{input: "vars.MY_VAR", expected: "refs/heads/test-data", name: "vars-context", ctxdata: map[string]interface{}{"vars": map[string]interface{}{"my_var": "refs/heads/test-data"}}}, {input: "vars.MY_VAR", expected: "refs/heads/test-data", name: "vars-context", ctxdata: map[string]any{"vars": map[string]any{"my_var": "refs/heads/test-data"}}},
} }
env := EvaluationEnvironment{ env := EvaluationEnvironment{
@@ -606,7 +606,7 @@ func TestContexts(t *testing.T) {
Conclusion: model.StepStatusSkipped, Conclusion: model.StepStatusSkipped,
}, },
}, },
Runner: map[string]interface{}{ Runner: map[string]any{
"os": "Linux", "os": "Linux",
"temp": "/tmp", "temp": "/tmp",
"tool_cache": "/opt/hostedtoolcache", "tool_cache": "/opt/hostedtoolcache",
@@ -617,10 +617,10 @@ func TestContexts(t *testing.T) {
Vars: map[string]string{ Vars: map[string]string{
"name": "value", "name": "value",
}, },
Strategy: map[string]interface{}{ Strategy: map[string]any{
"fail-fast": true, "fail-fast": true,
}, },
Matrix: map[string]interface{}{ Matrix: map[string]any{
"os": "Linux", "os": "Linux",
}, },
Needs: map[string]Needs{ Needs: map[string]Needs{
@@ -637,7 +637,7 @@ func TestContexts(t *testing.T) {
Result: "success", Result: "success",
}, },
}, },
Inputs: map[string]interface{}{ Inputs: map[string]any{
"name": "value", "name": "value",
}, },
} }
@@ -648,7 +648,7 @@ func TestContexts(t *testing.T) {
tenv.EnvCS = tt.caseSensitiveEnv tenv.EnvCS = tt.caseSensitiveEnv
tenv.CtxData = tt.ctxdata tenv.CtxData = tt.ctxdata
output, err := NewInterpeter(&tenv, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) output, err := NewInterpeter(&tenv, Config{}).Evaluate(tt.input, DefaultStatusCheckNone)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, tt.expected, output) assert.Equal(t, tt.expected, output)
}) })

View File

@@ -3,6 +3,7 @@ package filecollector
import ( import (
"archive/tar" "archive/tar"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs" "io/fs"
@@ -134,7 +135,7 @@ func (fc *FileCollector) CollectFiles(ctx context.Context, submodulePath []strin
if ctx != nil { if ctx != nil {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return fmt.Errorf("copy cancelled") return errors.New("copy cancelled")
default: default:
} }
} }

View File

@@ -27,7 +27,7 @@ func (mfs *memoryFs) walk(root string, fn filepath.WalkFunc) error {
if err != nil { if err != nil {
return err return err
} }
for i := 0; i < len(dir); i++ { for i := range dir {
filename := filepath.Join(root, dir[i].Name()) filename := filepath.Join(root, dir[i].Name())
err = fn(filename, dir[i], nil) err = fn(filename, dir[i], nil)
if dir[i].IsDir() { if dir[i].IsDir() {

View File

@@ -12,7 +12,7 @@ import (
// ActionRunsUsing is the type of runner for the action // ActionRunsUsing is the type of runner for the action
type ActionRunsUsing string type ActionRunsUsing string
func (a *ActionRunsUsing) UnmarshalYAML(unmarshal func(interface{}) error) error { func (a *ActionRunsUsing) UnmarshalYAML(unmarshal func(any) error) error {
var using string var using string
if err := unmarshal(&using); err != nil { if err := unmarshal(&using); err != nil {
return err return err

View File

@@ -10,39 +10,39 @@ import (
) )
type GithubContext struct { type GithubContext struct {
Event map[string]interface{} `json:"event"` Event map[string]any `json:"event"`
EventPath string `json:"event_path"` EventPath string `json:"event_path"`
Workflow string `json:"workflow"` Workflow string `json:"workflow"`
RunAttempt string `json:"run_attempt"` RunAttempt string `json:"run_attempt"`
RunID string `json:"run_id"` RunID string `json:"run_id"`
RunNumber string `json:"run_number"` RunNumber string `json:"run_number"`
Actor string `json:"actor"` Actor string `json:"actor"`
Repository string `json:"repository"` Repository string `json:"repository"`
EventName string `json:"event_name"` EventName string `json:"event_name"`
Sha string `json:"sha"` Sha string `json:"sha"`
Ref string `json:"ref"` Ref string `json:"ref"`
RefName string `json:"ref_name"` RefName string `json:"ref_name"`
RefType string `json:"ref_type"` RefType string `json:"ref_type"`
HeadRef string `json:"head_ref"` HeadRef string `json:"head_ref"`
BaseRef string `json:"base_ref"` BaseRef string `json:"base_ref"`
Token string `json:"token"` Token string `json:"token"`
Workspace string `json:"workspace"` Workspace string `json:"workspace"`
Action string `json:"action"` Action string `json:"action"`
ActionPath string `json:"action_path"` ActionPath string `json:"action_path"`
ActionRef string `json:"action_ref"` ActionRef string `json:"action_ref"`
ActionRepository string `json:"action_repository"` ActionRepository string `json:"action_repository"`
Job string `json:"job"` Job string `json:"job"`
JobName string `json:"job_name"` JobName string `json:"job_name"`
RepositoryOwner string `json:"repository_owner"` RepositoryOwner string `json:"repository_owner"`
RetentionDays string `json:"retention_days"` RetentionDays string `json:"retention_days"`
RunnerPerflog string `json:"runner_perflog"` RunnerPerflog string `json:"runner_perflog"`
RunnerTrackingID string `json:"runner_tracking_id"` RunnerTrackingID string `json:"runner_tracking_id"`
ServerURL string `json:"server_url"` ServerURL string `json:"server_url"`
APIURL string `json:"api_url"` APIURL string `json:"api_url"`
GraphQLURL string `json:"graphql_url"` GraphQLURL string `json:"graphql_url"`
} }
func asString(v interface{}) string { func asString(v any) string {
if v == nil { if v == nil {
return "" return ""
} else if s, ok := v.(string); ok { } else if s, ok := v.(string); ok {
@@ -51,7 +51,7 @@ func asString(v interface{}) string {
return "" return ""
} }
func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{}) { func nestedMapLookup(m map[string]any, ks ...string) (rval any) {
var ok bool var ok bool
if len(ks) == 0 { // degenerate input if len(ks) == 0 { // degenerate input
@@ -61,20 +61,20 @@ func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{})
return nil return nil
} else if len(ks) == 1 { // we've reached the final key } else if len(ks) == 1 { // we've reached the final key
return rval return rval
} else if m, ok = rval.(map[string]interface{}); !ok { } else if m, ok = rval.(map[string]any); !ok {
return nil return nil
} }
// 1+ more keys // 1+ more keys
return nestedMapLookup(m, ks[1:]...) return nestedMapLookup(m, ks[1:]...)
} }
func withDefaultBranch(ctx context.Context, b string, event map[string]interface{}) map[string]interface{} { func withDefaultBranch(ctx context.Context, b string, event map[string]any) map[string]any {
repoI, ok := event["repository"] repoI, ok := event["repository"]
if !ok { if !ok {
repoI = make(map[string]interface{}) repoI = make(map[string]any)
} }
repo, ok := repoI.(map[string]interface{}) repo, ok := repoI.(map[string]any)
if !ok { if !ok {
common.Logger(ctx).Warnf("unable to set default branch to %v", b) common.Logger(ctx).Warnf("unable to set default branch to %v", b)
return event return event
@@ -101,19 +101,19 @@ func (ghc *GithubContext) SetRef(ctx context.Context, defaultBranch string, repo
// https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads // https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads
switch ghc.EventName { switch ghc.EventName {
case "pull_request_target": case "pull_request_target":
ghc.Ref = fmt.Sprintf("refs/heads/%s", ghc.BaseRef) ghc.Ref = "refs/heads/" + ghc.BaseRef
case "pull_request", "pull_request_review", "pull_request_review_comment": case "pull_request", "pull_request_review", "pull_request_review_comment":
ghc.Ref = fmt.Sprintf("refs/pull/%.0f/merge", ghc.Event["number"]) ghc.Ref = fmt.Sprintf("refs/pull/%.0f/merge", ghc.Event["number"])
case "deployment", "deployment_status": case "deployment", "deployment_status":
ghc.Ref = asString(nestedMapLookup(ghc.Event, "deployment", "ref")) ghc.Ref = asString(nestedMapLookup(ghc.Event, "deployment", "ref"))
case "release": case "release":
ghc.Ref = fmt.Sprintf("refs/tags/%s", asString(nestedMapLookup(ghc.Event, "release", "tag_name"))) ghc.Ref = "refs/tags/" + asString(nestedMapLookup(ghc.Event, "release", "tag_name"))
case "push", "create", "workflow_dispatch": case "push", "create", "workflow_dispatch":
ghc.Ref = asString(ghc.Event["ref"]) ghc.Ref = asString(ghc.Event["ref"])
default: default:
defaultBranch := asString(nestedMapLookup(ghc.Event, "repository", "default_branch")) defaultBranch := asString(nestedMapLookup(ghc.Event, "repository", "default_branch"))
if defaultBranch != "" { if defaultBranch != "" {
ghc.Ref = fmt.Sprintf("refs/heads/%s", defaultBranch) ghc.Ref = "refs/heads/" + defaultBranch
} }
} }
@@ -134,7 +134,7 @@ func (ghc *GithubContext) SetRef(ctx context.Context, defaultBranch string, repo
} }
if ghc.Ref == "" { if ghc.Ref == "" {
ghc.Ref = fmt.Sprintf("refs/heads/%s", asString(nestedMapLookup(ghc.Event, "repository", "default_branch"))) ghc.Ref = "refs/heads/" + asString(nestedMapLookup(ghc.Event, "repository", "default_branch"))
} }
} }
} }

View File

@@ -2,7 +2,7 @@ package model
import ( import (
"context" "context"
"fmt" "errors"
"testing" "testing"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -27,19 +27,19 @@ func TestSetRef(t *testing.T) {
tables := []struct { tables := []struct {
eventName string eventName string
event map[string]interface{} event map[string]any
ref string ref string
refName string refName string
}{ }{
{ {
eventName: "pull_request_target", eventName: "pull_request_target",
event: map[string]interface{}{}, event: map[string]any{},
ref: "refs/heads/master", ref: "refs/heads/master",
refName: "master", refName: "master",
}, },
{ {
eventName: "pull_request", eventName: "pull_request",
event: map[string]interface{}{ event: map[string]any{
"number": 1234., "number": 1234.,
}, },
ref: "refs/pull/1234/merge", ref: "refs/pull/1234/merge",
@@ -47,8 +47,8 @@ func TestSetRef(t *testing.T) {
}, },
{ {
eventName: "deployment", eventName: "deployment",
event: map[string]interface{}{ event: map[string]any{
"deployment": map[string]interface{}{ "deployment": map[string]any{
"ref": "refs/heads/somebranch", "ref": "refs/heads/somebranch",
}, },
}, },
@@ -57,8 +57,8 @@ func TestSetRef(t *testing.T) {
}, },
{ {
eventName: "release", eventName: "release",
event: map[string]interface{}{ event: map[string]any{
"release": map[string]interface{}{ "release": map[string]any{
"tag_name": "v1.0.0", "tag_name": "v1.0.0",
}, },
}, },
@@ -67,7 +67,7 @@ func TestSetRef(t *testing.T) {
}, },
{ {
eventName: "push", eventName: "push",
event: map[string]interface{}{ event: map[string]any{
"ref": "refs/heads/somebranch", "ref": "refs/heads/somebranch",
}, },
ref: "refs/heads/somebranch", ref: "refs/heads/somebranch",
@@ -75,8 +75,8 @@ func TestSetRef(t *testing.T) {
}, },
{ {
eventName: "unknown", eventName: "unknown",
event: map[string]interface{}{ event: map[string]any{
"repository": map[string]interface{}{ "repository": map[string]any{
"default_branch": "main", "default_branch": "main",
}, },
}, },
@@ -85,7 +85,7 @@ func TestSetRef(t *testing.T) {
}, },
{ {
eventName: "no-event", eventName: "no-event",
event: map[string]interface{}{}, event: map[string]any{},
ref: "refs/heads/master", ref: "refs/heads/master",
refName: "master", refName: "master",
}, },
@@ -109,12 +109,12 @@ func TestSetRef(t *testing.T) {
t.Run("no-default-branch", func(t *testing.T) { t.Run("no-default-branch", func(t *testing.T) {
findGitRef = func(_ context.Context, _ string) (string, error) { findGitRef = func(_ context.Context, _ string) (string, error) {
return "", fmt.Errorf("no default branch") return "", errors.New("no default branch")
} }
ghc := &GithubContext{ ghc := &GithubContext{
EventName: "no-default-branch", EventName: "no-default-branch",
Event: map[string]interface{}{}, Event: map[string]any{},
} }
ghc.SetRef(context.Background(), "", "/some/dir") ghc.SetRef(context.Background(), "", "/some/dir")
@@ -141,14 +141,14 @@ func TestSetSha(t *testing.T) {
tables := []struct { tables := []struct {
eventName string eventName string
event map[string]interface{} event map[string]any
sha string sha string
}{ }{
{ {
eventName: "pull_request_target", eventName: "pull_request_target",
event: map[string]interface{}{ event: map[string]any{
"pull_request": map[string]interface{}{ "pull_request": map[string]any{
"base": map[string]interface{}{ "base": map[string]any{
"sha": "pr-base-sha", "sha": "pr-base-sha",
}, },
}, },
@@ -157,15 +157,15 @@ func TestSetSha(t *testing.T) {
}, },
{ {
eventName: "pull_request", eventName: "pull_request",
event: map[string]interface{}{ event: map[string]any{
"number": 1234., "number": 1234.,
}, },
sha: "1234fakesha", sha: "1234fakesha",
}, },
{ {
eventName: "deployment", eventName: "deployment",
event: map[string]interface{}{ event: map[string]any{
"deployment": map[string]interface{}{ "deployment": map[string]any{
"sha": "deployment-sha", "sha": "deployment-sha",
}, },
}, },
@@ -173,12 +173,12 @@ func TestSetSha(t *testing.T) {
}, },
{ {
eventName: "release", eventName: "release",
event: map[string]interface{}{}, event: map[string]any{},
sha: "1234fakesha", sha: "1234fakesha",
}, },
{ {
eventName: "push", eventName: "push",
event: map[string]interface{}{ event: map[string]any{
"after": "push-sha", "after": "push-sha",
"deleted": false, "deleted": false,
}, },
@@ -186,12 +186,12 @@ func TestSetSha(t *testing.T) {
}, },
{ {
eventName: "unknown", eventName: "unknown",
event: map[string]interface{}{}, event: map[string]any{},
sha: "1234fakesha", sha: "1234fakesha",
}, },
{ {
eventName: "no-event", eventName: "no-event",
event: map[string]interface{}{}, event: map[string]any{},
sha: "1234fakesha", sha: "1234fakesha",
}, },
} }

View File

@@ -8,7 +8,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sort" "slices"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -288,11 +288,8 @@ func (wp *workflowPlanner) GetEvents() []string {
for _, w := range wp.workflows { for _, w := range wp.workflows {
found := false found := false
for _, e := range events { for _, e := range events {
for _, we := range w.On() { if slices.Contains(w.On(), e) {
if e == we { found = true
found = true
break
}
} }
if found { if found {
break break
@@ -305,9 +302,7 @@ func (wp *workflowPlanner) GetEvents() []string {
} }
// sort the list based on depth of dependencies // sort the list based on depth of dependencies
sort.Slice(events, func(i, j int) bool { slices.Sort(events)
return events[i] < events[j]
})
return events return events
} }
@@ -338,7 +333,7 @@ func (s *Stage) GetJobIDs() []string {
// Merge stages with existing stages in plan // Merge stages with existing stages in plan
func (p *Plan) mergeStages(stages []*Stage) { func (p *Plan) mergeStages(stages []*Stage) {
newStages := make([]*Stage, int(math.Max(float64(len(p.Stages)), float64(len(stages))))) newStages := make([]*Stage, int(math.Max(float64(len(p.Stages)), float64(len(stages)))))
for i := 0; i < len(newStages); i++ { for i := range newStages {
newStages[i] = new(Stage) newStages[i] = new(Stage)
if i >= len(p.Stages) { if i >= len(p.Stages) {
newStages[i].Runs = append(newStages[i].Runs, stages[i].Runs...) newStages[i].Runs = append(newStages[i].Runs, stages[i].Runs...)

View File

@@ -55,6 +55,6 @@ func TestWorkflow(t *testing.T) {
// Check that a valid job id returns non-error // Check that a valid job id returns non-error
result, err := createStages(&workflow, "valid_job") result, err := createStages(&workflow, "valid_job")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, result) assert.NotNil(t, result)
} }

View File

@@ -4,8 +4,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"maps"
"reflect" "reflect"
"regexp" "regexp"
"slices"
"strconv" "strconv"
"strings" "strings"
@@ -61,7 +63,7 @@ func (w *Workflow) On() []string {
} }
return val return val
case yaml.MappingNode: case yaml.MappingNode:
var val map[string]interface{} var val map[string]any
err := w.RawOn.Decode(&val) err := w.RawOn.Decode(&val)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -75,9 +77,9 @@ func (w *Workflow) On() []string {
return nil return nil
} }
func (w *Workflow) OnEvent(event string) interface{} { func (w *Workflow) OnEvent(event string) any {
if w.RawOn.Kind == yaml.MappingNode { if w.RawOn.Kind == yaml.MappingNode {
var val map[string]interface{} var val map[string]any
if !decodeNode(w.RawOn, &val) { if !decodeNode(w.RawOn, &val) {
return nil return nil
} }
@@ -128,10 +130,8 @@ func (w *Workflow) WorkflowDispatchConfig() *WorkflowDispatch {
if !decodeNode(w.RawOn, &val) { if !decodeNode(w.RawOn, &val) {
return nil return nil
} }
for _, v := range val { if slices.Contains(val, "workflow_dispatch") {
if v == "workflow_dispatch" { return &WorkflowDispatch{}
return &WorkflowDispatch{}
}
} }
case yaml.MappingNode: case yaml.MappingNode:
var val map[string]yaml.Node var val map[string]yaml.Node
@@ -206,7 +206,7 @@ type Job struct {
Defaults Defaults `yaml:"defaults"` Defaults Defaults `yaml:"defaults"`
Outputs map[string]string `yaml:"outputs"` Outputs map[string]string `yaml:"outputs"`
Uses string `yaml:"uses"` Uses string `yaml:"uses"`
With map[string]interface{} `yaml:"with"` With map[string]any `yaml:"with"`
RawSecrets yaml.Node `yaml:"secrets"` RawSecrets yaml.Node `yaml:"secrets"`
Result string Result string
} }
@@ -384,9 +384,9 @@ func (j *Job) Environment() map[string]string {
} }
// Matrix decodes RawMatrix YAML node // Matrix decodes RawMatrix YAML node
func (j *Job) Matrix() map[string][]interface{} { func (j *Job) Matrix() map[string][]any {
if j.Strategy.RawMatrix.Kind == yaml.MappingNode { if j.Strategy.RawMatrix.Kind == yaml.MappingNode {
var val map[string][]interface{} var val map[string][]any
if !decodeNode(j.Strategy.RawMatrix, &val) { if !decodeNode(j.Strategy.RawMatrix, &val) {
return nil return nil
} }
@@ -397,32 +397,32 @@ func (j *Job) Matrix() map[string][]interface{} {
// GetMatrixes returns the matrix cross product // GetMatrixes returns the matrix cross product
// It skips includes and hard fails excludes for non-existing keys // It skips includes and hard fails excludes for non-existing keys
func (j *Job) GetMatrixes() ([]map[string]interface{}, error) { func (j *Job) GetMatrixes() ([]map[string]any, error) {
matrixes := make([]map[string]interface{}, 0) matrixes := make([]map[string]any, 0)
if j.Strategy != nil { if j.Strategy != nil {
j.Strategy.FailFast = j.Strategy.GetFailFast() j.Strategy.FailFast = j.Strategy.GetFailFast()
j.Strategy.MaxParallel = j.Strategy.GetMaxParallel() j.Strategy.MaxParallel = j.Strategy.GetMaxParallel()
if m := j.Matrix(); m != nil { if m := j.Matrix(); m != nil {
includes := make([]map[string]interface{}, 0) includes := make([]map[string]any, 0)
extraIncludes := make([]map[string]interface{}, 0) extraIncludes := make([]map[string]any, 0)
for _, v := range m["include"] { for _, v := range m["include"] {
switch t := v.(type) { switch t := v.(type) {
case []interface{}: case []any:
for _, i := range t { for _, i := range t {
i := i.(map[string]interface{}) i := i.(map[string]any)
includes = append(includes, i) includes = append(includes, i)
} }
case interface{}: case any:
v := v.(map[string]interface{}) v := v.(map[string]any)
includes = append(includes, v) includes = append(includes, v)
} }
} }
delete(m, "include") delete(m, "include")
excludes := make([]map[string]interface{}, 0) excludes := make([]map[string]any, 0)
for _, e := range m["exclude"] { for _, e := range m["exclude"] {
e := e.(map[string]interface{}) e := e.(map[string]any)
for k := range e { for k := range e {
if _, ok := m[k]; ok { if _, ok := m[k]; ok {
excludes = append(excludes, e) excludes = append(excludes, e)
@@ -451,9 +451,7 @@ func (j *Job) GetMatrixes() ([]map[string]interface{}, error) {
if commonKeysMatch2(matrix, include, m) { if commonKeysMatch2(matrix, include, m) {
matched = true matched = true
log.Debugf("Adding include values '%v' to existing entry", include) log.Debugf("Adding include values '%v' to existing entry", include)
for k, v := range include { maps.Copy(matrix, include)
matrix[k] = v
}
} }
} }
if !matched { if !matched {
@@ -465,19 +463,19 @@ func (j *Job) GetMatrixes() ([]map[string]interface{}, error) {
matrixes = append(matrixes, include) matrixes = append(matrixes, include)
} }
if len(matrixes) == 0 { if len(matrixes) == 0 {
matrixes = append(matrixes, make(map[string]interface{})) matrixes = append(matrixes, make(map[string]any))
} }
} else { } else {
matrixes = append(matrixes, make(map[string]interface{})) matrixes = append(matrixes, make(map[string]any))
} }
} else { } else {
matrixes = append(matrixes, make(map[string]interface{})) matrixes = append(matrixes, make(map[string]any))
log.Debugf("Empty Strategy, matrixes=%v", matrixes) log.Debugf("Empty Strategy, matrixes=%v", matrixes)
} }
return matrixes, nil return matrixes, nil
} }
func commonKeysMatch(a map[string]interface{}, b map[string]interface{}) bool { func commonKeysMatch(a map[string]any, b map[string]any) bool {
for aKey, aVal := range a { for aKey, aVal := range a {
if bVal, ok := b[aKey]; ok && !reflect.DeepEqual(aVal, bVal) { if bVal, ok := b[aKey]; ok && !reflect.DeepEqual(aVal, bVal) {
return false return false
@@ -486,7 +484,7 @@ func commonKeysMatch(a map[string]interface{}, b map[string]interface{}) bool {
return true return true
} }
func commonKeysMatch2(a map[string]interface{}, b map[string]interface{}, m map[string][]interface{}) bool { func commonKeysMatch2(a map[string]any, b map[string]any, m map[string][]any) bool {
for aKey, aVal := range a { for aKey, aVal := range a {
_, useKey := m[aKey] _, useKey := m[aKey]
if bVal, ok := b[aKey]; useKey && ok && !reflect.DeepEqual(aVal, bVal) { if bVal, ok := b[aKey]; useKey && ok && !reflect.DeepEqual(aVal, bVal) {
@@ -604,7 +602,7 @@ func (s *Step) GetEnv() map[string]string {
for k, v := range s.With { for k, v := range s.With {
envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(k), "_") envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(k), "_")
envKey = fmt.Sprintf("INPUT_%s", strings.ToUpper(envKey)) envKey = "INPUT_" + strings.ToUpper(envKey)
env[envKey] = v env[envKey] = v
} }
return env return env
@@ -752,11 +750,11 @@ func (w *Workflow) GetJobIDs() []string {
return ids return ids
} }
var OnDecodeNodeError = func(node yaml.Node, out interface{}, err error) { var OnDecodeNodeError = func(node yaml.Node, out any, err error) {
log.Fatalf("Failed to decode node %v into %T: %v", node, out, err) log.Fatalf("Failed to decode node %v into %T: %v", node, out, err)
} }
func decodeNode(node yaml.Node, out interface{}) bool { func decodeNode(node yaml.Node, out any) bool {
if err := node.Decode(out); err != nil { if err := node.Decode(out); err != nil {
if OnDecodeNodeError != nil { if OnDecodeNodeError != nil {
OnDecodeNodeError(node, out, err) OnDecodeNodeError(node, out, err)

View File

@@ -87,7 +87,7 @@ jobs:
workflow, err := ReadWorkflow(strings.NewReader(yaml), WorkflowConfig{}) workflow, err := ReadWorkflow(strings.NewReader(yaml), WorkflowConfig{})
assert.NoError(t, err, "read workflow should succeed") assert.NoError(t, err, "read workflow should succeed")
assert.Equal(t, workflow.Jobs["test"].RunsOn(), []string{"ubuntu-latest"}) assert.Equal(t, []string{"ubuntu-latest"}, workflow.Jobs["test"].RunsOn())
} }
func TestReadWorkflow_RunsOnLabelsWithGroup(t *testing.T) { func TestReadWorkflow_RunsOnLabelsWithGroup(t *testing.T) {
@@ -105,7 +105,7 @@ jobs:
workflow, err := ReadWorkflow(strings.NewReader(yaml), WorkflowConfig{}) workflow, err := ReadWorkflow(strings.NewReader(yaml), WorkflowConfig{})
assert.NoError(t, err, "read workflow should succeed") assert.NoError(t, err, "read workflow should succeed")
assert.Equal(t, workflow.Jobs["test"].RunsOn(), []string{"ubuntu-latest", "linux"}) assert.Equal(t, []string{"ubuntu-latest", "linux"}, workflow.Jobs["test"].RunsOn())
} }
func TestReadWorkflow_StringContainer(t *testing.T) { func TestReadWorkflow_StringContainer(t *testing.T) {
@@ -201,27 +201,27 @@ jobs:
assert.Len(t, workflow.Jobs, 6) assert.Len(t, workflow.Jobs, 6)
jobType, err := workflow.Jobs["default-job"].Type() jobType, err := workflow.Jobs["default-job"].Type()
assert.Equal(t, nil, err) assert.NoError(t, err)
assert.Equal(t, JobTypeDefault, jobType) assert.Equal(t, JobTypeDefault, jobType)
jobType, err = workflow.Jobs["remote-reusable-workflow-yml"].Type() jobType, err = workflow.Jobs["remote-reusable-workflow-yml"].Type()
assert.Equal(t, nil, err) assert.NoError(t, err)
assert.Equal(t, JobTypeReusableWorkflowRemote, jobType) assert.Equal(t, JobTypeReusableWorkflowRemote, jobType)
jobType, err = workflow.Jobs["remote-reusable-workflow-yaml"].Type() jobType, err = workflow.Jobs["remote-reusable-workflow-yaml"].Type()
assert.Equal(t, nil, err) assert.NoError(t, err)
assert.Equal(t, JobTypeReusableWorkflowRemote, jobType) assert.Equal(t, JobTypeReusableWorkflowRemote, jobType)
jobType, err = workflow.Jobs["remote-reusable-workflow-custom-path"].Type() jobType, err = workflow.Jobs["remote-reusable-workflow-custom-path"].Type()
assert.Equal(t, nil, err) assert.NoError(t, err)
assert.Equal(t, JobTypeReusableWorkflowRemote, jobType) assert.Equal(t, JobTypeReusableWorkflowRemote, jobType)
jobType, err = workflow.Jobs["local-reusable-workflow-yml"].Type() jobType, err = workflow.Jobs["local-reusable-workflow-yml"].Type()
assert.Equal(t, nil, err) assert.NoError(t, err)
assert.Equal(t, JobTypeReusableWorkflowLocal, jobType) assert.Equal(t, JobTypeReusableWorkflowLocal, jobType)
jobType, err = workflow.Jobs["local-reusable-workflow-yaml"].Type() jobType, err = workflow.Jobs["local-reusable-workflow-yaml"].Type()
assert.Equal(t, nil, err) assert.NoError(t, err)
assert.Equal(t, JobTypeReusableWorkflowLocal, jobType) assert.Equal(t, JobTypeReusableWorkflowLocal, jobType)
} }
@@ -246,19 +246,19 @@ jobs:
jobType, err := workflow.Jobs["remote-reusable-workflow-missing-version"].Type() jobType, err := workflow.Jobs["remote-reusable-workflow-missing-version"].Type()
assert.Equal(t, JobTypeInvalid, jobType) assert.Equal(t, JobTypeInvalid, jobType)
assert.NotEqual(t, nil, err) assert.Error(t, err)
jobType, err = workflow.Jobs["remote-reusable-workflow-bad-extension"].Type() jobType, err = workflow.Jobs["remote-reusable-workflow-bad-extension"].Type()
assert.Equal(t, JobTypeInvalid, jobType) assert.Equal(t, JobTypeInvalid, jobType)
assert.NotEqual(t, nil, err) assert.Error(t, err)
jobType, err = workflow.Jobs["local-reusable-workflow-bad-extension"].Type() jobType, err = workflow.Jobs["local-reusable-workflow-bad-extension"].Type()
assert.Equal(t, JobTypeInvalid, jobType) assert.Equal(t, JobTypeInvalid, jobType)
assert.NotEqual(t, nil, err) assert.Error(t, err)
jobType, err = workflow.Jobs["local-reusable-workflow-bad-path"].Type() jobType, err = workflow.Jobs["local-reusable-workflow-bad-path"].Type()
assert.Equal(t, JobTypeInvalid, jobType) assert.Equal(t, JobTypeInvalid, jobType)
assert.NotEqual(t, nil, err) assert.Error(t, err)
} }
func TestReadWorkflow_StepsTypes(t *testing.T) { func TestReadWorkflow_StepsTypes(t *testing.T) {
@@ -335,71 +335,69 @@ func TestReadWorkflow_Strategy(t *testing.T) {
p, err := w.PlanJob("strategy-only-max-parallel") p, err := w.PlanJob("strategy-only-max-parallel")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, len(p.Stages), 1) assert.Len(t, p.Stages, 1)
assert.Equal(t, len(p.Stages[0].Runs), 1) assert.Len(t, p.Stages[0].Runs, 1)
wf := p.Stages[0].Runs[0].Workflow wf := p.Stages[0].Runs[0].Workflow
job := wf.Jobs["strategy-only-max-parallel"] job := wf.Jobs["strategy-only-max-parallel"]
matrixes, err := job.GetMatrixes() matrixes, err := job.GetMatrixes()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, matrixes, []map[string]interface{}{{}}) assert.Equal(t, []map[string]any{{}}, matrixes)
assert.Equal(t, job.Matrix(), map[string][]interface{}(nil)) assert.Equal(t, job.Matrix(), map[string][]any(nil))
assert.Equal(t, job.Strategy.MaxParallel, 2) assert.Equal(t, 2, job.Strategy.MaxParallel)
assert.Equal(t, job.Strategy.FailFast, true) assert.True(t, job.Strategy.FailFast)
job = wf.Jobs["strategy-only-fail-fast"] job = wf.Jobs["strategy-only-fail-fast"]
matrixes, err = job.GetMatrixes() matrixes, err = job.GetMatrixes()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, matrixes, []map[string]interface{}{{}}) assert.Equal(t, []map[string]any{{}}, matrixes)
assert.Equal(t, job.Matrix(), map[string][]interface{}(nil)) assert.Equal(t, job.Matrix(), map[string][]any(nil))
assert.Equal(t, job.Strategy.MaxParallel, 4) assert.Equal(t, 4, job.Strategy.MaxParallel)
assert.Equal(t, job.Strategy.FailFast, false) assert.False(t, job.Strategy.FailFast)
job = wf.Jobs["strategy-no-matrix"] job = wf.Jobs["strategy-no-matrix"]
matrixes, err = job.GetMatrixes() matrixes, err = job.GetMatrixes()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, matrixes, []map[string]interface{}{{}}) assert.Equal(t, []map[string]any{{}}, matrixes)
assert.Equal(t, job.Matrix(), map[string][]interface{}(nil)) assert.Equal(t, job.Matrix(), map[string][]any(nil))
assert.Equal(t, job.Strategy.MaxParallel, 2) assert.Equal(t, 2, job.Strategy.MaxParallel)
assert.Equal(t, job.Strategy.FailFast, false) assert.False(t, job.Strategy.FailFast)
job = wf.Jobs["strategy-all"] job = wf.Jobs["strategy-all"]
matrixes, err = job.GetMatrixes() matrixes, err = job.GetMatrixes()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, matrixes, assert.Equal(t, []map[string]any{
[]map[string]interface{}{ {"datacenter": "site-c", "node-version": "14.x", "site": "staging", "php-version": 5.4},
{"datacenter": "site-c", "node-version": "14.x", "site": "staging", "php-version": 5.4}, {"datacenter": "site-c", "node-version": "16.x", "site": "staging", "php-version": 5.4},
{"datacenter": "site-c", "node-version": "16.x", "site": "staging", "php-version": 5.4}, {"datacenter": "site-d", "node-version": "16.x", "site": "staging", "php-version": 5.4},
{"datacenter": "site-d", "node-version": "16.x", "site": "staging", "php-version": 5.4}, {"datacenter": "site-a", "node-version": "10.x", "site": "prod"},
{"datacenter": "site-a", "node-version": "10.x", "site": "prod"}, {"datacenter": "site-b", "node-version": "12.x", "site": "dev"},
{"datacenter": "site-b", "node-version": "12.x", "site": "dev"}, }, matrixes,
},
) )
assert.Equal(t, job.Matrix(), assert.Equal(t, map[string][]any{
map[string][]interface{}{ "datacenter": {"site-c", "site-d"},
"datacenter": {"site-c", "site-d"}, "exclude": {
"exclude": { map[string]any{"datacenter": "site-d", "node-version": "14.x", "site": "staging"},
map[string]interface{}{"datacenter": "site-d", "node-version": "14.x", "site": "staging"},
},
"include": {
map[string]interface{}{"php-version": 5.4},
map[string]interface{}{"datacenter": "site-a", "node-version": "10.x", "site": "prod"},
map[string]interface{}{"datacenter": "site-b", "node-version": "12.x", "site": "dev"},
},
"node-version": {"14.x", "16.x"},
"site": {"staging"},
}, },
"include": {
map[string]any{"php-version": 5.4},
map[string]any{"datacenter": "site-a", "node-version": "10.x", "site": "prod"},
map[string]any{"datacenter": "site-b", "node-version": "12.x", "site": "dev"},
},
"node-version": {"14.x", "16.x"},
"site": {"staging"},
}, job.Matrix(),
) )
assert.Equal(t, job.Strategy.MaxParallel, 2) assert.Equal(t, 2, job.Strategy.MaxParallel)
assert.Equal(t, job.Strategy.FailFast, false) assert.False(t, job.Strategy.FailFast)
} }
func TestMatrixOnlyIncludes(t *testing.T) { func TestMatrixOnlyIncludes(t *testing.T) {
matrix := map[string][]interface{}{ matrix := map[string][]any{
"include": []interface{}{ "include": []any{
map[string]interface{}{"a": "1", "b": "2"}, map[string]any{"a": "1", "b": "2"},
map[string]interface{}{"a": "3", "b": "4"}, map[string]any{"a": "3", "b": "4"},
}, },
} }
rN := yaml.Node{} rN := yaml.Node{}
@@ -413,11 +411,10 @@ func TestMatrixOnlyIncludes(t *testing.T) {
assert.Equal(t, job.Matrix(), matrix) assert.Equal(t, job.Matrix(), matrix)
matrixes, err := job.GetMatrixes() matrixes, err := job.GetMatrixes()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, matrixes, assert.Equal(t, []map[string]any{
[]map[string]interface{}{ {"a": "1", "b": "2"},
{"a": "1", "b": "2"}, {"a": "3", "b": "4"},
{"a": "3", "b": "4"}, }, matrixes,
},
) )
} }
@@ -436,7 +433,7 @@ func TestStep_ShellCommand(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.shell, func(t *testing.T) { t.Run(tt.shell, func(t *testing.T) {
got := (&Step{Shell: tt.shell, WorkflowShell: tt.workflowShell}).ShellCommand() got := (&Step{Shell: tt.shell, WorkflowShell: tt.workflowShell}).ShellCommand()
assert.Equal(t, got, tt.want) assert.Equal(t, tt.want, got)
}) })
} }
} }

View File

@@ -154,14 +154,14 @@ func execAsDocker(ctx context.Context, step actionStep, actionName, subpath stri
var prepImage common.Executor var prepImage common.Executor
var image string var image string
forcePull := false forcePull := false
if strings.HasPrefix(action.Runs.Image, "docker://") { if after, ok := strings.CutPrefix(action.Runs.Image, "docker://"); ok {
image = strings.TrimPrefix(action.Runs.Image, "docker://") image = after
// Apply forcePull only for prebuild docker images // Apply forcePull only for prebuild docker images
forcePull = rc.Config.ForcePull forcePull = rc.Config.ForcePull
} else { } else {
// "-dockeraction" ensures that "./", "./test " won't get converted to "act-:latest", "act-test-:latest" which are invalid docker image names // "-dockeraction" ensures that "./", "./test " won't get converted to "act-:latest", "act-test-:latest" which are invalid docker image names
image = fmt.Sprintf("%s-dockeraction:%s", regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(actionName, "-"), "latest") image = fmt.Sprintf("%s-dockeraction:%s", regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(actionName, "-"), "latest")
image = fmt.Sprintf("act-%s", strings.TrimLeft(image, "-")) image = "act-" + strings.TrimLeft(image, "-")
image = strings.ToLower(image) image = strings.ToLower(image)
contextDir, fileName := path.Split(path.Join(subpath, action.Runs.Image)) contextDir, fileName := path.Split(path.Join(subpath, action.Runs.Image))
@@ -298,7 +298,7 @@ func newStepContainer(ctx context.Context, step step, image string, cmd []string
envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_TEMP", "/tmp")) envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_TEMP", "/tmp"))
binds, mounts := rc.GetBindsAndMounts() binds, mounts := rc.GetBindsAndMounts()
networkMode := fmt.Sprintf("container:%s", rc.jobContainerName()) networkMode := "container:" + rc.jobContainerName()
var workdir string var workdir string
if rc.IsHostEnv(ctx) { if rc.IsHostEnv(ctx) {
networkMode = "default" networkMode = "default"
@@ -333,7 +333,7 @@ func populateEnvsFromSavedState(env *map[string]string, step actionStep, rc *Run
state, ok := rc.IntraActionState[step.getStepModel().ID] state, ok := rc.IntraActionState[step.getStepModel().ID]
if ok { if ok {
for name, value := range state { for name, value := range state {
envName := fmt.Sprintf("STATE_%s", name) envName := "STATE_" + name
(*env)[envName] = value (*env)[envName] = value
} }
} }
@@ -343,7 +343,7 @@ func populateEnvsFromInput(ctx context.Context, env *map[string]string, action *
eval := rc.NewExpressionEvaluator(ctx) eval := rc.NewExpressionEvaluator(ctx)
for inputID, input := range action.Inputs { for inputID, input := range action.Inputs {
envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(inputID), "_") envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(inputID), "_")
envKey = fmt.Sprintf("INPUT_%s", envKey) envKey = "INPUT_" + envKey
if _, ok := (*env)[envKey]; !ok { if _, ok := (*env)[envKey]; !ok {
(*env)[envKey] = eval.Interpolate(ctx, input.Default) (*env)[envKey] = eval.Interpolate(ctx, input.Default)
} }
@@ -429,7 +429,7 @@ func runPreStep(step actionStep) common.Executor {
if steps := step.getCompositeSteps(); steps != nil && steps.pre != nil { if steps := step.getCompositeSteps(); steps != nil && steps.pre != nil {
return steps.pre(ctx) return steps.pre(ctx)
} }
return fmt.Errorf("missing steps in composite action") return errors.New("missing steps in composite action")
default: default:
return nil return nil
@@ -512,7 +512,7 @@ func runPostStep(step actionStep) common.Executor {
if steps := step.getCompositeSteps(); steps != nil && steps.post != nil { if steps := step.getCompositeSteps(); steps != nil && steps.post != nil {
return steps.post(ctx) return steps.post(ctx)
} }
return fmt.Errorf("missing steps in composite action") return errors.New("missing steps in composite action")
default: default:
return nil return nil

View File

@@ -2,8 +2,9 @@ package runner
import ( import (
"context" "context"
"fmt" "errors"
"regexp" "regexp"
"strconv"
"strings" "strings"
"gitea.com/gitea/act_runner/pkg/common" "gitea.com/gitea/act_runner/pkg/common"
@@ -25,7 +26,7 @@ func evaluateCompositeInputAndEnv(ctx context.Context, parent *RunContext, step
for inputID, input := range step.getActionModel().Inputs { for inputID, input := range step.getActionModel().Inputs {
envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(inputID), "_") envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(inputID), "_")
envKey = fmt.Sprintf("INPUT_%s", strings.ToUpper(envKey)) envKey = "INPUT_" + strings.ToUpper(envKey)
// lookup if key is defined in the step but the already // lookup if key is defined in the step but the already
// evaluated value from the environment // evaluated value from the environment
@@ -77,7 +78,7 @@ func newCompositeRunContext(ctx context.Context, parent *RunContext, step action
nodeToolFullPath: parent.nodeToolFullPath, nodeToolFullPath: parent.nodeToolFullPath,
} }
if parent.ContextData != nil { if parent.ContextData != nil {
compositerc.ContextData = map[string]interface{}{} compositerc.ContextData = map[string]any{}
for k, v := range parent.ContextData { for k, v := range parent.ContextData {
if !strings.EqualFold("inputs", k) { if !strings.EqualFold("inputs", k) {
compositerc.ContextData[k] = v compositerc.ContextData[k] = v
@@ -99,7 +100,7 @@ func execAsComposite(step actionStep) common.Executor {
steps := step.getCompositeSteps() steps := step.getCompositeSteps()
if steps == nil || steps.main == nil { if steps == nil || steps.main == nil {
return fmt.Errorf("missing steps in composite action") return errors.New("missing steps in composite action")
} }
ctx = WithCompositeLogger(ctx, &compositeRC.Masks) ctx = WithCompositeLogger(ctx, &compositeRC.Masks)
@@ -147,7 +148,7 @@ func (rc *RunContext) compositeExecutor(action *model.Action) *compositeSteps {
for i, step := range action.Runs.Steps { for i, step := range action.Runs.Steps {
if step.ID == "" { if step.ID == "" {
step.ID = fmt.Sprintf("%d", i) step.ID = strconv.Itoa(i)
} }
// create a copy of the step, since this composite action could // create a copy of the step, since this composite action could

View File

@@ -99,7 +99,7 @@ runs:
action, err := readActionImpl(context.Background(), tt.step, readFile, model.ActionConfig{}) action, err := readActionImpl(context.Background(), tt.step, readFile, model.ActionConfig{})
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, tt.expected, action) assert.Equal(t, tt.expected, action)
closerMock.AssertExpectations(t) closerMock.AssertExpectations(t)
@@ -218,7 +218,7 @@ func TestActionRunner(t *testing.T) {
err := runActionImpl(tt.step)(ctx) err := runActionImpl(tt.step)(ctx)
assert.Nil(t, err) assert.NoError(t, err)
cm.AssertExpectations(t) cm.AssertExpectations(t)
}) })
} }

View File

@@ -133,8 +133,8 @@ func (rc *RunContext) addPath(ctx context.Context, arg string) {
func parseKeyValuePairs(kvPairs string, separator string) map[string]string { func parseKeyValuePairs(kvPairs string, separator string) map[string]string {
rtn := make(map[string]string) rtn := make(map[string]string)
kvPairList := strings.Split(kvPairs, separator) kvPairList := strings.SplitSeq(kvPairs, separator)
for _, kvPair := range kvPairList { for kvPair := range kvPairList {
kv := strings.Split(kvPair, "=") kv := strings.Split(kvPair, "=")
if len(kv) == 2 { if len(kv) == 2 {
rtn[kv[0]] = kv[1] rtn[kv[0]] = kv[1]

View File

@@ -164,7 +164,7 @@ func TestAddmaskUsemask(t *testing.T) {
re := captureOutput(t, func() { re := captureOutput(t, func() {
ctx := context.Background() ctx := context.Background()
ctx = WithJobLogger(ctx, "0", "testjob", config, &rc.Masks, map[string]interface{}{}) ctx = WithJobLogger(ctx, "0", "testjob", config, &rc.Masks, map[string]any{})
handler := rc.commandHandler(ctx) handler := rc.commandHandler(ctx)
handler("::add-mask::secret\n") handler("::add-mask::secret\n")

View File

@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"maps"
"path" "path"
"reflect" "reflect"
"regexp" "regexp"
@@ -21,7 +22,7 @@ import (
// ExpressionEvaluator is the interface for evaluating expressions // ExpressionEvaluator is the interface for evaluating expressions
type ExpressionEvaluator interface { type ExpressionEvaluator interface {
evaluate(context.Context, string, exprparser.DefaultStatusCheck) (interface{}, error) evaluate(context.Context, string, exprparser.DefaultStatusCheck) (any, error)
EvaluateYamlNode(context.Context, *yaml.Node) error EvaluateYamlNode(context.Context, *yaml.Node) error
Interpolate(context.Context, string) string Interpolate(context.Context, string) string
} }
@@ -36,7 +37,7 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map
// todo: cleanup EvaluationEnvironment creation // todo: cleanup EvaluationEnvironment creation
using := make(map[string]exprparser.Needs) using := make(map[string]exprparser.Needs)
strategy := make(map[string]interface{}) strategy := make(map[string]any)
if rc.Run != nil { if rc.Run != nil {
job := rc.Run.Job() job := rc.Run.Job()
if job != nil && job.Strategy != nil { if job != nil && job.Strategy != nil {
@@ -64,9 +65,7 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map
result := model.WorkflowCallResult{ result := model.WorkflowCallResult{
Outputs: map[string]string{}, Outputs: map[string]string{},
} }
for k, v := range job.Outputs { maps.Copy(result.Outputs, job.Outputs)
result.Outputs[k] = v
}
workflowCallResult[jobName] = &result workflowCallResult[jobName] = &result
} }
} }
@@ -123,10 +122,10 @@ func (rc *RunContext) NewStepExpressionEvaluatorExt(ctx context.Context, step st
return rc.newStepExpressionEvaluator(ctx, step, ghc, getEvaluatorInputs(ctx, rc, step, ghc)) return rc.newStepExpressionEvaluator(ctx, step, ghc, getEvaluatorInputs(ctx, rc, step, ghc))
} }
func (rc *RunContext) newStepExpressionEvaluator(ctx context.Context, step step, _ *model.GithubContext, inputs map[string]interface{}) ExpressionEvaluator { func (rc *RunContext) newStepExpressionEvaluator(ctx context.Context, step step, _ *model.GithubContext, inputs map[string]any) ExpressionEvaluator {
// todo: cleanup EvaluationEnvironment creation // todo: cleanup EvaluationEnvironment creation
job := rc.Run.Job() job := rc.Run.Job()
strategy := make(map[string]interface{}) strategy := make(map[string]any)
if job.Strategy != nil { if job.Strategy != nil {
strategy["fail-fast"] = job.Strategy.FailFast strategy["fail-fast"] = job.Strategy.FailFast
strategy["max-parallel"] = job.Strategy.MaxParallel strategy["max-parallel"] = job.Strategy.MaxParallel
@@ -173,8 +172,8 @@ func (rc *RunContext) newStepExpressionEvaluator(ctx context.Context, step step,
} }
} }
func getHashFilesFunction(ctx context.Context, rc *RunContext) func(v []reflect.Value) (interface{}, error) { func getHashFilesFunction(ctx context.Context, rc *RunContext) func(v []reflect.Value) (any, error) {
hashFiles := func(v []reflect.Value) (interface{}, error) { hashFiles := func(v []reflect.Value) (any, error) {
if rc.JobContainer != nil { if rc.JobContainer != nil {
timeed, cancel := context.WithTimeout(ctx, time.Minute) timeed, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel() defer cancel()
@@ -198,9 +197,7 @@ func getHashFilesFunction(ctx context.Context, rc *RunContext) func(v []reflect.
patterns = append(patterns, s) patterns = append(patterns, s)
} }
env := map[string]string{} env := map[string]string{}
for k, v := range rc.Env { maps.Copy(env, rc.Env)
env[k] = v
}
env["patterns"] = strings.Join(patterns, "\n") env["patterns"] = strings.Join(patterns, "\n")
if followSymlink { if followSymlink {
env["followSymbolicLinks"] = "true" env["followSymbolicLinks"] = "true"
@@ -238,7 +235,7 @@ type expressionEvaluator struct {
interpreter exprparser.Interpreter interpreter exprparser.Interpreter
} }
func (ee expressionEvaluator) evaluate(ctx context.Context, in string, defaultStatusCheck exprparser.DefaultStatusCheck) (interface{}, error) { func (ee expressionEvaluator) evaluate(ctx context.Context, in string, defaultStatusCheck exprparser.DefaultStatusCheck) (any, error) {
logger := common.Logger(ctx) logger := common.Logger(ctx)
logger.Debugf("evaluating expression '%s'", in) logger.Debugf("evaluating expression '%s'", in)
evaluated, err := ee.interpreter.Evaluate(in, defaultStatusCheck) evaluated, err := ee.interpreter.Evaluate(in, defaultStatusCheck)
@@ -485,8 +482,8 @@ func rewriteSubExpression(ctx context.Context, in string, forceFormat bool) (str
return out, nil return out, nil
} }
func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *model.GithubContext) map[string]interface{} { func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *model.GithubContext) map[string]any {
inputs := map[string]interface{}{} inputs := map[string]any{}
setupWorkflowInputs(ctx, &inputs, rc) setupWorkflowInputs(ctx, &inputs, rc)
@@ -498,8 +495,8 @@ func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *mod
} }
for k, v := range env { for k, v := range env {
if strings.HasPrefix(k, "INPUT_") { if after, ok := strings.CutPrefix(k, "INPUT_"); ok {
inputs[strings.ToLower(strings.TrimPrefix(k, "INPUT_"))] = v inputs[strings.ToLower(after)] = v
} }
} }
@@ -523,7 +520,7 @@ func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *mod
return inputs return inputs
} }
func setupWorkflowInputs(ctx context.Context, inputs *map[string]interface{}, rc *RunContext) { func setupWorkflowInputs(ctx context.Context, inputs *map[string]any, rc *RunContext) {
if rc.caller != nil { if rc.caller != nil {
config := rc.Run.Workflow.WorkflowCallConfig() config := rc.Run.Workflow.WorkflowCallConfig()

View File

@@ -6,6 +6,7 @@ import (
"os" "os"
"regexp" "regexp"
"sort" "sort"
"strings"
"testing" "testing"
"gitea.com/gitea/act_runner/pkg/exprparser" "gitea.com/gitea/act_runner/pkg/exprparser"
@@ -16,7 +17,7 @@ import (
func createRunContext(t *testing.T) *RunContext { func createRunContext(t *testing.T) *RunContext {
var yml yaml.Node var yml yaml.Node
err := yml.Encode(map[string][]interface{}{ err := yml.Encode(map[string][]any{
"os": {"Linux", "Windows"}, "os": {"Linux", "Windows"},
"foo": {"bar", "baz"}, "foo": {"bar", "baz"},
}) })
@@ -48,7 +49,7 @@ func createRunContext(t *testing.T) *RunContext {
}, },
}, },
}, },
Matrix: map[string]interface{}{ Matrix: map[string]any{
"os": "Linux", "os": "Linux",
"foo": "bar", "foo": "bar",
}, },
@@ -84,7 +85,7 @@ func TestEvaluateRunContext(t *testing.T) {
tables := []struct { tables := []struct {
in string in string
out interface{} out any
errMesg string errMesg string
}{ }{
{" 1 ", 1, ""}, {" 1 ", 1, ""},
@@ -165,7 +166,7 @@ func TestEvaluateStep(t *testing.T) {
tables := []struct { tables := []struct {
in string in string
out interface{} out any
errMesg string errMesg string
}{ }{
{"steps.idwithnothing.conclusion", model.StepStatusSuccess.String(), ""}, {"steps.idwithnothing.conclusion", model.StepStatusSuccess.String(), ""},
@@ -281,9 +282,11 @@ func updateTestExpressionWorkflow(t *testing.T, tables []struct {
keys = append(keys, k) keys = append(keys, k)
} }
sort.Strings(keys) sort.Strings(keys)
var envsSb284 strings.Builder
for _, k := range keys { for _, k := range keys {
envs += fmt.Sprintf(" %s: %s\n", k, rc.Env[k]) fmt.Fprintf(&envsSb284, " %s: %s\n", k, rc.Env[k])
} }
envs += envsSb284.String()
// editorconfig-checker-disable // editorconfig-checker-disable
workflow := fmt.Sprintf(` workflow := fmt.Sprintf(`
@@ -299,6 +302,7 @@ jobs:
steps: steps:
`, envs) `, envs)
// editorconfig-checker-enable // editorconfig-checker-enable
var workflowSb302 strings.Builder
for _, table := range tables { for _, table := range tables {
expressionPattern := regexp.MustCompile(`\${{\s*(.+?)\s*}}`) expressionPattern := regexp.MustCompile(`\${{\s*(.+?)\s*}}`)
@@ -307,8 +311,9 @@ jobs:
}) })
name := fmt.Sprintf(`%s -> %s should be equal to %s`, expr, table.in, table.out) name := fmt.Sprintf(`%s -> %s should be equal to %s`, expr, table.in, table.out)
echo := `run: echo "Done "` echo := `run: echo "Done "`
workflow += fmt.Sprintf("\n - name: %s\n %s\n", name, echo) fmt.Fprintf(&workflowSb302, "\n - name: %s\n %s\n", name, echo)
} }
workflow += workflowSb302.String()
file, err := os.Create("../../.github/workflows/test-expressions.yml") file, err := os.Create("../../.github/workflows/test-expressions.yml")
if err != nil { if err != nil {

View File

@@ -3,6 +3,7 @@ package runner
import ( import (
"context" "context"
"fmt" "fmt"
"strconv"
"time" "time"
"gitea.com/gitea/act_runner/pkg/common" "gitea.com/gitea/act_runner/pkg/common"
@@ -10,7 +11,7 @@ import (
) )
type jobInfo interface { type jobInfo interface {
matrix() map[string]interface{} matrix() map[string]any
steps() []*model.Step steps() []*model.Step
startContainer() common.Executor startContainer() common.Executor
stopContainer() common.Executor stopContainer() common.Executor
@@ -70,7 +71,7 @@ func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executo
} }
} }
if stepModel.ID == "" { if stepModel.ID == "" {
stepModel.ID = fmt.Sprintf("%d", i) stepModel.ID = strconv.Itoa(i)
} }
step, err := sf.newStep(stepModel, rc) step, err := sf.newStep(stepModel, rc)

View File

@@ -2,8 +2,10 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"slices"
"testing" "testing"
"gitea.com/gitea/act_runner/pkg/common" "gitea.com/gitea/act_runner/pkg/common"
@@ -38,9 +40,9 @@ type jobInfoMock struct {
mock.Mock mock.Mock
} }
func (jim *jobInfoMock) matrix() map[string]interface{} { func (jim *jobInfoMock) matrix() map[string]any {
args := jim.Called() args := jim.Called()
return args.Get(0).(map[string]interface{}) return args.Get(0).(map[string]any)
} }
func (jim *jobInfoMock) steps() []*model.Step { func (jim *jobInfoMock) steps() []*model.Step {
@@ -232,12 +234,7 @@ func TestNewJobExecutor(t *testing.T) {
} }
contains := func(needle string, haystack []string) bool { contains := func(needle string, haystack []string) bool {
for _, item := range haystack { return slices.Contains(haystack, needle)
if item == needle {
return true
}
}
return false
} }
for _, tt := range table { for _, tt := range table {
@@ -287,7 +284,7 @@ func TestNewJobExecutor(t *testing.T) {
sm.On("main").Return(func(_ context.Context) error { sm.On("main").Return(func(_ context.Context) error {
executorOrder = append(executorOrder, "step"+stepModel.ID) executorOrder = append(executorOrder, "step"+stepModel.ID)
if tt.hasError { if tt.hasError {
return fmt.Errorf("error") return errors.New("error")
} }
return nil return nil
}) })
@@ -303,7 +300,7 @@ func TestNewJobExecutor(t *testing.T) {
} }
if len(tt.steps) > 0 { if len(tt.steps) > 0 {
jim.On("matrix").Return(map[string]interface{}{}) jim.On("matrix").Return(map[string]any{})
jim.On("interpolateOutputs").Return(func(_ context.Context) error { jim.On("interpolateOutputs").Return(func(_ context.Context) error {
executorOrder = append(executorOrder, "interpolateOutputs") executorOrder = append(executorOrder, "interpolateOutputs")
@@ -327,7 +324,7 @@ func TestNewJobExecutor(t *testing.T) {
executor := newJobExecutor(jim, sfm, rc) executor := newJobExecutor(jim, sfm, rc)
err := executor(ctx) err := executor(ctx)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, tt.executedSteps, executorOrder) assert.Equal(t, tt.executedSteps, executorOrder)
jim.AssertExpectations(t) jim.AssertExpectations(t)

View File

@@ -70,7 +70,7 @@ func WithJobLoggerFactory(ctx context.Context, factory JobLoggerFactory) context
} }
// WithJobLogger attaches a new logger to context that is aware of steps // WithJobLogger attaches a new logger to context that is aware of steps
func WithJobLogger(ctx context.Context, jobID string, jobName string, config *Config, masks *[]string, matrix map[string]interface{}) context.Context { func WithJobLogger(ctx context.Context, jobID string, jobName string, config *Config, masks *[]string, matrix map[string]any) context.Context {
ctx = WithMasks(ctx, masks) ctx = WithMasks(ctx, masks)
var logger *logrus.Logger var logger *logrus.Logger

View File

@@ -40,7 +40,7 @@ func newActionCacheReusableWorkflowExecutor(rc *RunContext, filename string, rem
if err != nil { if err != nil {
return err return err
} }
archive, err := cache.GetTarArchive(ctx, filename, sha, fmt.Sprintf(".github/workflows/%s", remoteReusableWorkflow.Filename)) archive, err := cache.GetTarArchive(ctx, filename, sha, ".github/workflows/"+remoteReusableWorkflow.Filename)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -12,6 +12,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
maps0 "maps"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
@@ -34,7 +35,7 @@ import (
type RunContext struct { type RunContext struct {
Name string Name string
Config *Config Config *Config
Matrix map[string]interface{} Matrix map[string]any
Run *model.Run Run *model.Run
EventJSON string EventJSON string
Env map[string]string Env map[string]string
@@ -54,7 +55,7 @@ type RunContext struct {
cleanUpJobContainer common.Executor cleanUpJobContainer common.Executor
caller *caller // job calling this RunContext (reusable workflows) caller *caller // job calling this RunContext (reusable workflows)
Cancelled bool Cancelled bool
ContextData map[string]interface{} ContextData map[string]any
nodeToolFullPath string nodeToolFullPath string
} }
@@ -109,13 +110,13 @@ func (rc *RunContext) networkName() (string, bool) {
} }
func getDockerDaemonSocketMountPath(daemonPath string) string { func getDockerDaemonSocketMountPath(daemonPath string) string {
if protoIndex := strings.Index(daemonPath, "://"); protoIndex != -1 { if before, after, ok := strings.Cut(daemonPath, "://"); ok {
scheme := daemonPath[:protoIndex] scheme := before
if strings.EqualFold(scheme, "npipe") { if strings.EqualFold(scheme, "npipe") {
// linux container mount on windows, use the default socket path of the VM / wsl2 // linux container mount on windows, use the default socket path of the VM / wsl2
return "/var/run/docker.sock" return "/var/run/docker.sock"
} else if strings.EqualFold(scheme, "unix") { } else if strings.EqualFold(scheme, "unix") {
return daemonPath[protoIndex+3:] return after
} else if strings.IndexFunc(scheme, func(r rune) bool { } else if strings.IndexFunc(scheme, func(r rune) bool {
return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z')
}) == -1 { }) == -1 {
@@ -244,7 +245,7 @@ func (rc *RunContext) startHostEnvironment() common.Executor {
}).Finally(rc.JobContainer.Remove()) }).Finally(rc.JobContainer.Remove())
for k, v := range rc.JobContainer.GetRunnerContext(ctx) { for k, v := range rc.JobContainer.GetRunnerContext(ctx) {
if v, ok := v.(string); ok { if v, ok := v.(string); ok {
rc.Env[fmt.Sprintf("RUNNER_%s", strings.ToUpper(k))] = v rc.Env["RUNNER_"+strings.ToUpper(k)] = v
} }
} }
for _, env := range os.Environ() { for _, env := range os.Environ() {
@@ -635,7 +636,7 @@ func (rc *RunContext) waitForServiceContainer(c container.ExecutionsEnvironment)
if health == container.HealthHealthy { if health == container.HealthHealthy {
return nil return nil
} }
return fmt.Errorf("service container failed to start") return errors.New("service container failed to start")
} }
} }
@@ -741,7 +742,7 @@ func (rc *RunContext) closeContainer() common.Executor {
} }
} }
func (rc *RunContext) matrix() map[string]interface{} { func (rc *RunContext) matrix() map[string]any {
return rc.Matrix return rc.Matrix
} }
@@ -891,9 +892,7 @@ func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) {
func mergeMaps(maps ...map[string]string) map[string]string { func mergeMaps(maps ...map[string]string) map[string]string {
rtnMap := make(map[string]string) rtnMap := make(map[string]string)
for _, m := range maps { for _, m := range maps {
for k, v := range m { maps0.Copy(rtnMap, m)
rtnMap[k] = v
}
} }
return rtnMap return rtnMap
} }
@@ -945,7 +944,7 @@ func (rc *RunContext) getStepsContext() map[string]*model.StepResult {
func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext { func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext {
logger := common.Logger(ctx) logger := common.Logger(ctx)
ghc := &model.GithubContext{ ghc := &model.GithubContext{
Event: make(map[string]interface{}), Event: make(map[string]any),
Workflow: rc.Run.Workflow.Name, Workflow: rc.Run.Workflow.Name,
RunAttempt: rc.Config.Env["GITHUB_RUN_ATTEMPT"], RunAttempt: rc.Config.Env["GITHUB_RUN_ATTEMPT"],
RunID: rc.Config.Env["GITHUB_RUN_ID"], RunID: rc.Config.Env["GITHUB_RUN_ID"],
@@ -1049,9 +1048,9 @@ func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext
func (rc *RunContext) mergeGitHubContextWithContextData(ghc *model.GithubContext) { func (rc *RunContext) mergeGitHubContextWithContextData(ghc *model.GithubContext) {
if rnout, ok := rc.ContextData["github"]; ok { if rnout, ok := rc.ContextData["github"]; ok {
nout, ok := rnout.(map[string]interface{}) nout, ok := rnout.(map[string]any)
if ok { if ok {
var out map[string]interface{} var out map[string]any
content, _ := json.Marshal(ghc) content, _ := json.Marshal(ghc)
_ = json.Unmarshal(content, &out) _ = json.Unmarshal(content, &out)
for k, v := range nout { for k, v := range nout {
@@ -1092,7 +1091,7 @@ func isLocalCheckout(ghc *model.GithubContext, step *model.Step) bool {
return true return true
} }
func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{}) { func nestedMapLookup(m map[string]any, ks ...string) (rval any) {
var ok bool var ok bool
if len(ks) == 0 { // degenerate input if len(ks) == 0 { // degenerate input
@@ -1102,7 +1101,7 @@ func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{})
return nil return nil
} else if len(ks) == 1 { // we've reached the final key } else if len(ks) == 1 { // we've reached the final key
return rval return rval
} else if m, ok = rval.(map[string]interface{}); !ok { } else if m, ok = rval.(map[string]any); !ok {
return nil return nil
} }
// 1+ more keys // 1+ more keys
@@ -1200,22 +1199,22 @@ func (rc *RunContext) handleCredentials(ctx context.Context) (string, string, er
} }
if container.Credentials != nil && len(container.Credentials) != 2 { if container.Credentials != nil && len(container.Credentials) != 2 {
err := fmt.Errorf("invalid property count for key 'credentials:'") err := errors.New("invalid property count for key 'credentials:'")
return "", "", err return "", "", err
} }
ee := rc.NewExpressionEvaluator(ctx) ee := rc.NewExpressionEvaluator(ctx)
if username = ee.Interpolate(ctx, container.Credentials["username"]); username == "" { if username = ee.Interpolate(ctx, container.Credentials["username"]); username == "" {
err := fmt.Errorf("failed to interpolate container.credentials.username") err := errors.New("failed to interpolate container.credentials.username")
return "", "", err return "", "", err
} }
if password = ee.Interpolate(ctx, container.Credentials["password"]); password == "" { if password = ee.Interpolate(ctx, container.Credentials["password"]); password == "" {
err := fmt.Errorf("failed to interpolate container.credentials.password") err := errors.New("failed to interpolate container.credentials.password")
return "", "", err return "", "", err
} }
if container.Credentials["username"] == "" || container.Credentials["password"] == "" { if container.Credentials["username"] == "" || container.Credentials["password"] == "" {
err := fmt.Errorf("container.credentials cannot be empty") err := errors.New("container.credentials cannot be empty")
return "", "", err return "", "", err
} }
@@ -1227,18 +1226,18 @@ func (rc *RunContext) handleServiceCredentials(ctx context.Context, creds map[st
return return
} }
if len(creds) != 2 { if len(creds) != 2 {
err = fmt.Errorf("invalid property count for key 'credentials:'") err = errors.New("invalid property count for key 'credentials:'")
return return
} }
ee := rc.NewExpressionEvaluator(ctx) ee := rc.NewExpressionEvaluator(ctx)
if username = ee.Interpolate(ctx, creds["username"]); username == "" { if username = ee.Interpolate(ctx, creds["username"]); username == "" {
err = fmt.Errorf("failed to interpolate credentials.username") err = errors.New("failed to interpolate credentials.username")
return return
} }
if password = ee.Interpolate(ctx, creds["password"]); password == "" { if password = ee.Interpolate(ctx, creds["password"]); password == "" {
err = fmt.Errorf("failed to interpolate credentials.password") err = errors.New("failed to interpolate credentials.password")
return return
} }

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"fmt"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
@@ -85,7 +84,7 @@ func (rc *RunContext) startTartEnvironment() common.Executor {
rc.cleanUpJobContainer = rc.JobContainer.Remove() rc.cleanUpJobContainer = rc.JobContainer.Remove()
for k, v := range rc.JobContainer.GetRunnerContext(ctx) { for k, v := range rc.JobContainer.GetRunnerContext(ctx) {
if v, ok := v.(string); ok { if v, ok := v.(string); ok {
rc.Env[fmt.Sprintf("RUNNER_%s", strings.ToUpper(k))] = v rc.Env["RUNNER_"+strings.ToUpper(k)] = v
} }
} }

View File

@@ -21,7 +21,7 @@ import (
func TestRunContext_EvalBool(t *testing.T) { func TestRunContext_EvalBool(t *testing.T) {
var yml yaml.Node var yml yaml.Node
err := yml.Encode(map[string][]interface{}{ err := yml.Encode(map[string][]any{
"os": {"Linux", "Windows"}, "os": {"Linux", "Windows"},
"foo": {"bar", "baz"}, "foo": {"bar", "baz"},
}) })
@@ -49,7 +49,7 @@ func TestRunContext_EvalBool(t *testing.T) {
}, },
}, },
}, },
Matrix: map[string]interface{}{ Matrix: map[string]any{
"os": "Linux", "os": "Linux",
"foo": "bar", "foo": "bar",
}, },
@@ -162,7 +162,7 @@ func TestRunContext_EvalBool(t *testing.T) {
assertObject.Error(err) assertObject.Error(err)
} }
assertObject.Equal(table.out, b, fmt.Sprintf("Expected %s to be %v, was %v", table.in, table.out, b)) assertObject.Equal(table.out, b, "Expected %s to be %v, was %v", table.in, table.out, b)
}) })
} }
} }
@@ -178,9 +178,11 @@ func updateTestIfWorkflow(t *testing.T, tables []struct {
keys = append(keys, k) keys = append(keys, k)
} }
sort.Strings(keys) sort.Strings(keys)
var envsSb181 strings.Builder
for _, k := range keys { for _, k := range keys {
envs += fmt.Sprintf(" %s: %s\n", k, rc.Env[k]) fmt.Fprintf(&envsSb181, " %s: %s\n", k, rc.Env[k])
} }
envs += envsSb181.String()
// editorconfig-checker-disable // editorconfig-checker-disable
workflow := fmt.Sprintf(` workflow := fmt.Sprintf(`
name: "Test what expressions result in true and false on GitHub" name: "Test what expressions result in true and false on GitHub"
@@ -196,6 +198,7 @@ jobs:
`, envs) `, envs)
// editorconfig-checker-enable // editorconfig-checker-enable
var workflowSb199 strings.Builder
for i, table := range tables { for i, table := range tables {
if table.wantErr || strings.HasPrefix(table.in, "github.actor") { if table.wantErr || strings.HasPrefix(table.in, "github.actor") {
continue continue
@@ -211,11 +214,12 @@ jobs:
echo = `run: echo OK` echo = `run: echo OK`
name = fmt.Sprintf(`"✅ I should run, expr: %s"`, expr) name = fmt.Sprintf(`"✅ I should run, expr: %s"`, expr)
} }
workflow += fmt.Sprintf("\n - name: %s\n id: step%d\n if: %s\n %s\n", name, i, table.in, echo) fmt.Fprintf(&workflowSb199, "\n - name: %s\n id: step%d\n if: %s\n %s\n", name, i, table.in, echo)
if table.out { if table.out {
workflow += fmt.Sprintf("\n - name: \"Double checking expr: %s\"\n if: steps.step%d.conclusion == 'skipped'\n run: echo \"%s should have been true, but wasn't\"\n", expr, i, table.in) fmt.Fprintf(&workflowSb199, "\n - name: \"Double checking expr: %s\"\n if: steps.step%d.conclusion == 'skipped'\n run: echo \"%s should have been true, but wasn't\"\n", expr, i, table.in)
} }
} }
workflow += workflowSb199.String()
file, err := os.Create("../../.github/workflows/test-if.yml") file, err := os.Create("../../.github/workflows/test-if.yml")
if err != nil { if err != nil {
@@ -281,7 +285,7 @@ func TestRunContext_GetBindsAndMounts(t *testing.T) {
assert.Contains(t, gotbind, fullBind) assert.Contains(t, gotbind, fullBind)
} else { } else {
mountkey := testcase.rc.jobContainerName() mountkey := testcase.rc.jobContainerName()
assert.EqualValues(t, testcase.wantmount, gotmount[mountkey]) assert.Equal(t, testcase.wantmount, gotmount[mountkey])
} }
}) })
} }
@@ -341,7 +345,7 @@ func TestGetGitHubContext(t *testing.T) {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
cwd, err := os.Getwd() cwd, err := os.Getwd()
assert.Nil(t, err) assert.NoError(t, err)
rc := &RunContext{ rc := &RunContext{
Config: &Config{ Config: &Config{
@@ -355,7 +359,7 @@ func TestGetGitHubContext(t *testing.T) {
}, },
Name: "GitHubContextTest", Name: "GitHubContextTest",
CurrentStep: "step", CurrentStep: "step",
Matrix: map[string]interface{}{}, Matrix: map[string]any{},
Env: map[string]string{}, Env: map[string]string{},
ExtraPath: []string{}, ExtraPath: []string{},
StepResults: map[string]*model.StepResult{}, StepResults: map[string]*model.StepResult{},
@@ -397,7 +401,7 @@ func TestGetGitHubContextOverlay(t *testing.T) {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
cwd, err := os.Getwd() cwd, err := os.Getwd()
assert.Nil(t, err) assert.NoError(t, err)
rc := &RunContext{ rc := &RunContext{
Config: &Config{ Config: &Config{
@@ -411,13 +415,13 @@ func TestGetGitHubContextOverlay(t *testing.T) {
}, },
Name: "GitHubContextTest", Name: "GitHubContextTest",
CurrentStep: "step", CurrentStep: "step",
Matrix: map[string]interface{}{}, Matrix: map[string]any{},
Env: map[string]string{}, Env: map[string]string{},
ExtraPath: []string{}, ExtraPath: []string{},
StepResults: map[string]*model.StepResult{}, StepResults: map[string]*model.StepResult{},
OutputMappings: map[MappableOutput]MappableOutput{}, OutputMappings: map[MappableOutput]MappableOutput{},
ContextData: map[string]interface{}{ ContextData: map[string]any{
"github": map[string]interface{}{ "github": map[string]any{
"actor": "me", "actor": "me",
"repository": "myowner/myrepo", "repository": "myowner/myrepo",
"repository_owner": "myowner", "repository_owner": "myowner",
@@ -721,7 +725,7 @@ func TestRunContextGetEnv(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.description, func(t *testing.T) { t.Run(test.description, func(t *testing.T) {
envMap := test.rc.GetEnv() envMap := test.rc.GetEnv()
assert.EqualValues(t, test.want, envMap[test.targetEnv]) assert.Equal(t, test.want, envMap[test.targetEnv])
}) })
} }
} }
@@ -744,7 +748,7 @@ func TestSetRuntimeVariables(t *testing.T) {
tkn, _, err := jwt.NewParser().ParseUnverified(runtimeToken, jwt.MapClaims{}) tkn, _, err := jwt.NewParser().ParseUnverified(runtimeToken, jwt.MapClaims{})
assert.NotNil(t, tkn) assert.NotNil(t, tkn)
assert.Nil(t, err) assert.NoError(t, err)
} }
func TestSetRuntimeVariablesWithRunID(t *testing.T) { func TestSetRuntimeVariablesWithRunID(t *testing.T) {
@@ -769,7 +773,7 @@ func TestSetRuntimeVariablesWithRunID(t *testing.T) {
claims := jwt.MapClaims{} claims := jwt.MapClaims{}
tkn, _, err := jwt.NewParser().ParseUnverified(runtimeToken, &claims) tkn, _, err := jwt.NewParser().ParseUnverified(runtimeToken, &claims)
assert.NotNil(t, tkn) assert.NotNil(t, tkn)
assert.Nil(t, err) assert.NoError(t, err)
scp, ok := claims["scp"] scp, ok := claims["scp"]
assert.True(t, ok, "scp claim exists") assert.True(t, ok, "scp claim exists")
assert.Equal(t, "Actions.Results:45:45", scp, "contains expected scp claim") assert.Equal(t, "Actions.Results:45:45", scp, "contains expected scp claim")

View File

@@ -74,7 +74,7 @@ type Config struct {
Planner model.PlannerConfig // Configuration for the workflow planner Planner model.PlannerConfig // Configuration for the workflow planner
Action model.ActionConfig // Configuration for action reading Action model.ActionConfig // Configuration for action reading
MainContextNames []string // e.g. "github", "gitea", "forgejo" MainContextNames []string // e.g. "github", "gitea", "forgejo"
ContextData map[string]interface{} ContextData map[string]any
EventJSON string EventJSON string
} }
@@ -82,7 +82,7 @@ func (runnerConfig *Config) GetGitHubServerURL() string {
if len(runnerConfig.GitHubServerURL) > 0 { if len(runnerConfig.GitHubServerURL) > 0 {
return runnerConfig.GitHubServerURL return runnerConfig.GitHubServerURL
} }
return fmt.Sprintf("https://%s", runnerConfig.GitHubInstance) return "https://" + runnerConfig.GitHubInstance
} }
func (runnerConfig *Config) GetGitHubAPIServerURL() string { func (runnerConfig *Config) GetGitHubAPIServerURL() string {
if len(runnerConfig.GitHubAPIServerURL) > 0 { if len(runnerConfig.GitHubAPIServerURL) > 0 {
@@ -203,7 +203,7 @@ func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
} }
} }
var matrixes []map[string]interface{} var matrixes []map[string]any
if m, err := job.GetMatrixes(); err != nil { if m, err := job.GetMatrixes(); err != nil {
log.Errorf("error while get job's matrix: %v", err) log.Errorf("error while get job's matrix: %v", err)
} else { } else {
@@ -247,10 +247,7 @@ func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
if runner.config.Parallel != 0 { if runner.config.Parallel != 0 {
return common.NewParallelExecutor(len(pipeline), pipeline...)(ctx) return common.NewParallelExecutor(len(pipeline), pipeline...)(ctx)
} }
ncpu := runtime.NumCPU() ncpu := max(1, runtime.NumCPU())
if 1 > ncpu {
ncpu = 1
}
log.Debugf("Detected CPUs: %d", ncpu) log.Debugf("Detected CPUs: %d", ncpu)
return common.NewParallelExecutor(ncpu, pipeline...)(ctx) return common.NewParallelExecutor(ncpu, pipeline...)(ctx)
}) })
@@ -272,8 +269,8 @@ func handleFailure(plan *model.Plan) common.Executor {
} }
} }
func selectMatrixes(originalMatrixes []map[string]interface{}, targetMatrixValues map[string]map[string]bool) []map[string]interface{} { func selectMatrixes(originalMatrixes []map[string]any, targetMatrixValues map[string]map[string]bool) []map[string]any {
matrixes := make([]map[string]interface{}, 0) matrixes := make([]map[string]any, 0)
for _, original := range originalMatrixes { for _, original := range originalMatrixes {
flag := true flag := true
for key, val := range original { for key, val := range original {
@@ -291,7 +288,7 @@ func selectMatrixes(originalMatrixes []map[string]interface{}, targetMatrixValue
return matrixes return matrixes
} }
func (runner *runnerImpl) newRunContext(ctx context.Context, run *model.Run, matrix map[string]interface{}) *RunContext { func (runner *runnerImpl) newRunContext(ctx context.Context, run *model.Run, matrix map[string]any) *RunContext {
rc := &RunContext{ rc := &RunContext{
Config: runner.config, Config: runner.config,
Run: run, Run: run,

View File

@@ -5,6 +5,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@@ -87,7 +88,7 @@ func TestGraphMissingEvent(t *testing.T) {
plan, err := planner.PlanEvent("push") plan, err := planner.PlanEvent("push")
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, plan) assert.NotNil(t, plan)
assert.Equal(t, 0, len(plan.Stages)) assert.Empty(t, plan.Stages)
assert.Contains(t, buf.String(), "no events found for workflow: no-event.yml") assert.Contains(t, buf.String(), "no events found for workflow: no-event.yml")
log.SetOutput(out) log.SetOutput(out)
@@ -100,7 +101,7 @@ func TestGraphMissingFirst(t *testing.T) {
plan, err := planner.PlanEvent("push") plan, err := planner.PlanEvent("push")
assert.EqualError(t, err, "unable to build dependency graph for no first (no-first.yml)") assert.EqualError(t, err, "unable to build dependency graph for no first (no-first.yml)")
assert.NotNil(t, plan) assert.NotNil(t, plan)
assert.Equal(t, 0, len(plan.Stages)) assert.Empty(t, plan.Stages)
} }
func TestGraphWithMissing(t *testing.T) { func TestGraphWithMissing(t *testing.T) {
@@ -114,7 +115,7 @@ func TestGraphWithMissing(t *testing.T) {
plan, err := planner.PlanEvent("push") plan, err := planner.PlanEvent("push")
assert.NotNil(t, plan) assert.NotNil(t, plan)
assert.Equal(t, 0, len(plan.Stages)) assert.Empty(t, plan.Stages)
assert.EqualError(t, err, "unable to build dependency graph for missing (missing.yml)") assert.EqualError(t, err, "unable to build dependency graph for missing (missing.yml)")
assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)") assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)")
log.SetOutput(out) log.SetOutput(out)
@@ -134,7 +135,7 @@ func TestGraphWithSomeMissing(t *testing.T) {
plan, err := planner.PlanAll() plan, err := planner.PlanAll()
assert.Error(t, err, "unable to build dependency graph for no first (no-first.yml)") assert.Error(t, err, "unable to build dependency graph for no first (no-first.yml)")
assert.NotNil(t, plan) assert.NotNil(t, plan)
assert.Equal(t, 1, len(plan.Stages)) assert.Len(t, plan.Stages, 1)
assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)") assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)")
assert.Contains(t, buf.String(), "unable to build dependency graph for no first (no-first.yml)") assert.Contains(t, buf.String(), "unable to build dependency graph for no first (no-first.yml)")
log.SetOutput(out) log.SetOutput(out)
@@ -148,18 +149,18 @@ func TestGraphEvent(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, plan) assert.NotNil(t, plan)
assert.NotNil(t, plan.Stages) assert.NotNil(t, plan.Stages)
assert.Equal(t, len(plan.Stages), 3, "stages") assert.Len(t, plan.Stages, 3, "stages")
assert.Equal(t, len(plan.Stages[0].Runs), 1, "stage0.runs") assert.Len(t, plan.Stages[0].Runs, 1, "stage0.runs")
assert.Equal(t, len(plan.Stages[1].Runs), 1, "stage1.runs") assert.Len(t, plan.Stages[1].Runs, 1, "stage1.runs")
assert.Equal(t, len(plan.Stages[2].Runs), 1, "stage2.runs") assert.Len(t, plan.Stages[2].Runs, 1, "stage2.runs")
assert.Equal(t, plan.Stages[0].Runs[0].JobID, "check", "jobid") assert.Equal(t, "check", plan.Stages[0].Runs[0].JobID, "jobid")
assert.Equal(t, plan.Stages[1].Runs[0].JobID, "build", "jobid") assert.Equal(t, "build", plan.Stages[1].Runs[0].JobID, "jobid")
assert.Equal(t, plan.Stages[2].Runs[0].JobID, "test", "jobid") assert.Equal(t, "test", plan.Stages[2].Runs[0].JobID, "jobid")
plan, err = planner.PlanEvent("release") plan, err = planner.PlanEvent("release")
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, plan) assert.NotNil(t, plan)
assert.Equal(t, 0, len(plan.Stages)) assert.Empty(t, plan.Stages)
} }
type TestJobFileInfo struct { type TestJobFileInfo struct {
@@ -177,7 +178,7 @@ func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config
log.SetLevel(logLevel) log.SetLevel(logLevel)
workdir, err := filepath.Abs(j.workdir) workdir, err := filepath.Abs(j.workdir)
assert.Nil(t, err, workdir) assert.NoError(t, err, workdir)
fullWorkflowPath := filepath.Join(workdir, j.workflowPath) fullWorkflowPath := filepath.Join(workdir, j.workflowPath)
runnerConfig := &Config{ runnerConfig := &Config{
@@ -198,18 +199,18 @@ func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config
} }
runner, err := New(runnerConfig) runner, err := New(runnerConfig)
assert.Nil(t, err, j.workflowPath) assert.NoError(t, err, j.workflowPath)
planner, err := model.NewWorkflowPlanner(fullWorkflowPath, model.PlannerConfig{}) planner, err := model.NewWorkflowPlanner(fullWorkflowPath, model.PlannerConfig{})
if j.errorMessage != "" && err != nil { if j.errorMessage != "" && err != nil {
assert.Error(t, err, j.errorMessage) assert.Error(t, err, j.errorMessage)
} else if assert.Nil(t, err, fullWorkflowPath) { } else if assert.NoError(t, err, fullWorkflowPath) {
plan, err := planner.PlanEvent(j.eventName) plan, err := planner.PlanEvent(j.eventName)
assert.True(t, (err == nil) != (plan == nil), "PlanEvent should return either a plan or an error") assert.NotEqual(t, (err == nil), (plan == nil), "PlanEvent should return either a plan or an error")
if err == nil && plan != nil { if err == nil && plan != nil {
err = runner.NewPlanExecutor(plan)(ctx) err = runner.NewPlanExecutor(plan)(ctx)
if j.errorMessage == "" { if j.errorMessage == "" {
assert.Nil(t, err, fullWorkflowPath) assert.NoError(t, err, fullWorkflowPath)
} else { } else {
assert.Error(t, err, j.errorMessage) assert.Error(t, err, j.errorMessage)
} }
@@ -434,7 +435,7 @@ func TestPullAndPostStepFailureIsJobFailure(t *testing.T) {
var hasJobResult, hasStepResult bool var hasJobResult, hasStepResult bool
for scan.Scan() { for scan.Scan() {
t.Log(scan.Text()) t.Log(scan.Text())
entry := map[string]interface{}{} entry := map[string]any{}
if json.Unmarshal(scan.Bytes(), &entry) == nil { if json.Unmarshal(scan.Bytes(), &entry) == nil {
if val, ok := entry["jobResult"]; ok { if val, ok := entry["jobResult"]; ok {
assert.Equal(t, "failure", val) assert.Equal(t, "failure", val)
@@ -461,14 +462,14 @@ func (c mockCache) Fetch(ctx context.Context, cacheDir string, url string, ref s
_ = url _ = url
_ = ref _ = ref
_ = token _ = token
return "", fmt.Errorf("fetch failure") return "", errors.New("fetch failure")
} }
func (c mockCache) GetTarArchive(ctx context.Context, cacheDir string, sha string, includePrefix string) (io.ReadCloser, error) { func (c mockCache) GetTarArchive(ctx context.Context, cacheDir string, sha string, includePrefix string) (io.ReadCloser, error) {
_ = ctx _ = ctx
_ = cacheDir _ = cacheDir
_ = sha _ = sha
_ = includePrefix _ = includePrefix
return nil, fmt.Errorf("fetch failure") return nil, errors.New("fetch failure")
} }
func TestFetchFailureIsJobFailure(t *testing.T) { func TestFetchFailureIsJobFailure(t *testing.T) {
@@ -504,7 +505,7 @@ func TestFetchFailureIsJobFailure(t *testing.T) {
var hasJobResult bool var hasJobResult bool
for scan.Scan() { for scan.Scan() {
t.Log(scan.Text()) t.Log(scan.Text())
entry := map[string]interface{}{} entry := map[string]any{}
if json.Unmarshal(scan.Bytes(), &entry) == nil { if json.Unmarshal(scan.Bytes(), &entry) == nil {
if val, ok := entry["jobResult"]; ok { if val, ok := entry["jobResult"]; ok {
assert.Equal(t, "failure", val) assert.Equal(t, "failure", val)
@@ -735,11 +736,11 @@ func (f *maskJobLoggerFactory) WithJobLogger() *log.Logger {
func TestMaskValues(t *testing.T) { func TestMaskValues(t *testing.T) {
assertNoSecret := func(text string, _ string) { assertNoSecret := func(text string, _ string) {
index := strings.Index(text, "composite secret") found := strings.Contains(text, "composite secret")
if index > -1 { if found {
fmt.Printf("\nFound Secret in the given text:\n%s\n", text) fmt.Printf("\nFound Secret in the given text:\n%s\n", text)
} }
assert.False(t, strings.Contains(text, "composite secret")) assert.NotContains(t, text, "composite secret")
} }
if testing.Short() { if testing.Short() {

View File

@@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
maps0 "maps"
"path" "path"
"strconv" "strconv"
"strings" "strings"
@@ -336,9 +337,7 @@ func mergeIntoMap(step step, target *map[string]string, maps ...map[string]strin
func mergeIntoMapCaseSensitive(target map[string]string, maps ...map[string]string) { func mergeIntoMapCaseSensitive(target map[string]string, maps ...map[string]string) {
for _, m := range maps { for _, m := range maps {
for k, v := range m { maps0.Copy(target, m)
target[k] = v
}
} }
} }

View File

@@ -43,7 +43,7 @@ func (sal *stepActionLocal) main() common.Executor {
_, cpath := sal.getContainerActionPaths() _, cpath := sal.getContainerActionPaths()
return func(filename string) (io.Reader, io.Closer, error) { return func(filename string) (io.Reader, io.Closer, error) {
spath := path.Join(cpath, filename) spath := path.Join(cpath, filename)
for i := 0; i < maxSymlinkDepth; i++ { for range maxSymlinkDepth {
tars, err := sal.RunContext.JobContainer.GetContainerArchive(ctx, spath) tars, err := sal.RunContext.JobContainer.GetContainerArchive(ctx, spath)
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
return nil, nil, err return nil, nil, err

View File

@@ -92,10 +92,10 @@ func TestStepActionLocalTest(t *testing.T) {
}) })
err := sal.pre()(ctx) err := sal.pre()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
err = sal.main()(ctx) err = sal.main()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
cm.AssertExpectations(t) cm.AssertExpectations(t)
salm.AssertExpectations(t) salm.AssertExpectations(t)
@@ -258,7 +258,7 @@ func TestStepActionLocalPost(t *testing.T) {
sal.RunContext.ExprEval = sal.RunContext.NewExpressionEvaluator(ctx) sal.RunContext.ExprEval = sal.RunContext.NewExpressionEvaluator(ctx)
if tt.mocks.exec { if tt.mocks.exec {
suffixMatcher := func(suffix string) interface{} { suffixMatcher := func(suffix string) any {
return mock.MatchedBy(func(array []string) bool { return mock.MatchedBy(func(array []string) bool {
return strings.HasSuffix(array[1], suffix) return strings.HasSuffix(array[1], suffix)
}) })
@@ -288,7 +288,7 @@ func TestStepActionLocalPost(t *testing.T) {
err := sal.post()(ctx) err := sal.post()(ctx)
assert.Equal(t, tt.err, err) assert.Equal(t, tt.err, err)
assert.Equal(t, sal.RunContext.StepResults["post-step"], (*model.StepResult)(nil)) assert.Equal(t, (*model.StepResult)(nil), sal.RunContext.StepResults["post-step"])
cm.AssertExpectations(t) cm.AssertExpectations(t)
}) })
} }

View File

@@ -69,7 +69,7 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
remoteReader := func(_ context.Context) actionYamlReader { remoteReader := func(_ context.Context) actionYamlReader {
return func(filename string) (io.Reader, io.Closer, error) { return func(filename string) (io.Reader, io.Closer, error) {
spath := path.Join(sar.remoteAction.Path, filename) spath := path.Join(sar.remoteAction.Path, filename)
for i := 0; i < maxSymlinkDepth; i++ { for range maxSymlinkDepth {
tars, err := cache.GetTarArchive(ctx, sar.cacheDir, sar.resolvedSha, spath) tars, err := cache.GetTarArchive(ctx, sar.cacheDir, sar.resolvedSha, spath)
if err != nil { if err != nil {
return nil, nil, os.ErrNotExist return nil, nil, os.ErrNotExist

View File

@@ -290,7 +290,7 @@ func TestStepActionRemotePre(t *testing.T) {
err := sar.pre()(ctx) err := sar.pre()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
sarm.AssertExpectations(t) sarm.AssertExpectations(t)
cacheMock.AssertExpectations(t) cacheMock.AssertExpectations(t)
@@ -343,7 +343,7 @@ func TestStepActionRemotePreThroughAction(t *testing.T) {
err := sar.pre()(ctx) err := sar.pre()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
sarm.AssertExpectations(t) sarm.AssertExpectations(t)
cacheMock.AssertExpectations(t) cacheMock.AssertExpectations(t)
@@ -397,7 +397,7 @@ func TestStepActionRemotePreThroughActionToken(t *testing.T) {
err := sar.pre()(ctx) err := sar.pre()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
sarm.AssertExpectations(t) sarm.AssertExpectations(t)
cacheMock.AssertExpectations(t) cacheMock.AssertExpectations(t)
@@ -611,7 +611,7 @@ func TestStepActionRemotePost(t *testing.T) {
} }
} }
// Ensure that StepResults is nil in this test // Ensure that StepResults is nil in this test
assert.Equal(t, sar.RunContext.StepResults["post-step"], (*model.StepResult)(nil)) assert.Equal(t, (*model.StepResult)(nil), sar.RunContext.StepResults["post-step"])
cm.AssertExpectations(t) cm.AssertExpectations(t)
}) })
} }

View File

@@ -123,7 +123,7 @@ func (sd *stepDocker) newStepContainer(ctx context.Context, image string, cmd []
Name: createContainerName(rc.jobContainerName(), step.ID), Name: createContainerName(rc.jobContainerName(), step.ID),
Env: envList, Env: envList,
Mounts: mounts, Mounts: mounts,
NetworkMode: fmt.Sprintf("container:%s", rc.jobContainerName()), NetworkMode: "container:" + rc.jobContainerName(),
Binds: binds, Binds: binds,
Stdout: logWriter, Stdout: logWriter,
Stderr: logWriter, Stderr: logWriter,

View File

@@ -97,7 +97,7 @@ func TestStepDockerMain(t *testing.T) {
cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil)
err := sd.main()(ctx) err := sd.main()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, "node:14", input.Image) assert.Equal(t, "node:14", input.Image)
@@ -109,8 +109,8 @@ func TestStepDockerPrePost(t *testing.T) {
sd := &stepDocker{} sd := &stepDocker{}
err := sd.pre()(ctx) err := sd.pre()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
err = sd.post()(ctx) err = sd.post()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
} }

View File

@@ -62,7 +62,7 @@ func TestStepFactoryNewStep(t *testing.T) {
step, err := sf.newStep(tt.model, &RunContext{}) step, err := sf.newStep(tt.model, &RunContext{})
assert.True(t, tt.check((step))) assert.True(t, tt.check((step)))
assert.Nil(t, err) assert.NoError(t, err)
}) })
} }
} }

View File

@@ -3,6 +3,7 @@ package runner
import ( import (
"context" "context"
"fmt" "fmt"
"maps"
"runtime" "runtime"
"strings" "strings"
@@ -90,7 +91,7 @@ func getScriptName(rc *RunContext, step *model.Step) string {
for rcs := rc; rcs.Parent != nil; rcs = rcs.Parent { for rcs := rc; rcs.Parent != nil; rcs = rcs.Parent {
scriptName = fmt.Sprintf("%s-composite-%s", rcs.Parent.CurrentStep, scriptName) scriptName = fmt.Sprintf("%s-composite-%s", rcs.Parent.CurrentStep, scriptName)
} }
return fmt.Sprintf("workflow/%s", scriptName) return "workflow/" + scriptName
} }
// TODO: Currently we just ignore top level keys, BUT we should return proper error on them // TODO: Currently we just ignore top level keys, BUT we should return proper error on them
@@ -186,9 +187,7 @@ func (sr *stepRun) setupShell(ctx context.Context) {
} }
step.Shell = shellWithFallback[0] step.Shell = shellWithFallback[0]
lenv := &localEnv{env: map[string]string{}} lenv := &localEnv{env: map[string]string{}}
for k, v := range sr.env { maps.Copy(lenv.env, sr.env)
lenv.env[k] = v
}
sr.getRunContext().ApplyExtraPath(ctx, &lenv.env) sr.getRunContext().ApplyExtraPath(ctx, &lenv.env)
_, err := lookpath.LookPath2(shellWithFallback[0], lenv) _, err := lookpath.LookPath2(shellWithFallback[0], lenv)
if err != nil { if err != nil {

View File

@@ -78,7 +78,7 @@ func TestStepRun(t *testing.T) {
cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil)
err := sr.main()(ctx) err := sr.main()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
cm.AssertExpectations(t) cm.AssertExpectations(t)
} }
@@ -88,8 +88,8 @@ func TestStepRunPrePost(t *testing.T) {
sr := &stepRun{} sr := &stepRun{}
err := sr.pre()(ctx) err := sr.pre()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
err = sr.post()(ctx) err = sr.post()(ctx)
assert.Nil(t, err) assert.NoError(t, err)
} }

View File

@@ -152,7 +152,7 @@ func TestSetupEnv(t *testing.T) {
sm.On("getEnv").Return(&env) sm.On("getEnv").Return(&env)
err := setupEnv(context.Background(), sm) err := setupEnv(context.Background(), sm)
assert.Nil(t, err) assert.NoError(t, err)
// These are commit or system specific // These are commit or system specific
delete((env), "GITHUB_REF") delete((env), "GITHUB_REF")
@@ -313,37 +313,37 @@ func TestIsContinueOnError(t *testing.T) {
step := createTestStep(t, "name: test") step := createTestStep(t, "name: test")
continueOnError, err := isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) continueOnError, err := isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
assertObject.False(continueOnError) assertObject.False(continueOnError)
assertObject.Nil(err) assertObject.NoError(err)
// explicit true // explicit true
step = createTestStep(t, "continue-on-error: true") step = createTestStep(t, "continue-on-error: true")
continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
assertObject.True(continueOnError) assertObject.True(continueOnError)
assertObject.Nil(err) assertObject.NoError(err)
// explicit false // explicit false
step = createTestStep(t, "continue-on-error: false") step = createTestStep(t, "continue-on-error: false")
continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
assertObject.False(continueOnError) assertObject.False(continueOnError)
assertObject.Nil(err) assertObject.NoError(err)
// expression true // expression true
step = createTestStep(t, "continue-on-error: ${{ 'test' == 'test' }}") step = createTestStep(t, "continue-on-error: ${{ 'test' == 'test' }}")
continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
assertObject.True(continueOnError) assertObject.True(continueOnError)
assertObject.Nil(err) assertObject.NoError(err)
// expression false // expression false
step = createTestStep(t, "continue-on-error: ${{ 'test' != 'test' }}") step = createTestStep(t, "continue-on-error: ${{ 'test' != 'test' }}")
continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
assertObject.False(continueOnError) assertObject.False(continueOnError)
assertObject.Nil(err) assertObject.NoError(err)
// expression parse error // expression parse error
step = createTestStep(t, "continue-on-error: ${{ 'test' != test }}") step = createTestStep(t, "continue-on-error: ${{ 'test' != test }}")
continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
assertObject.False(continueOnError) assertObject.False(continueOnError)
assertObject.NotNil(err) assertObject.Error(err)
} }
func TestSymlinkJoin(t *testing.T) { func TestSymlinkJoin(t *testing.T) {

View File

@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"math" "math"
"regexp" "regexp"
"slices"
"strconv" "strconv"
"strings" "strings"
@@ -53,7 +54,7 @@ type ValidationErrorCollection struct {
} }
func indent(builder *strings.Builder, in string) { func indent(builder *strings.Builder, in string) {
for _, v := range strings.Split(in, "\n") { for v := range strings.SplitSeq(in, "\n") {
if v != "" { if v != "" {
builder.WriteString(" ") builder.WriteString(" ")
builder.WriteString(v) builder.WriteString(v)
@@ -242,7 +243,7 @@ func (s *Node) checkSingleExpression(exprNode exprparser.Node) error {
case *exprparser.ValueNode: case *exprparser.ValueNode:
return nil return nil
default: default:
return fmt.Errorf("expressions are not allowed here") return errors.New("expressions are not allowed here")
} }
} }
@@ -290,8 +291,8 @@ func (s *Node) GetFunctions() []FunctionInfo {
}, },
}) })
for _, v := range s.Context { for _, v := range s.Context {
i := strings.Index(v, "(") found := strings.Contains(v, "(")
if i == -1 { if !found {
continue continue
} }
smatch := functions.FindStringSubmatch(v) smatch := functions.FindStringSubmatch(v)
@@ -348,7 +349,7 @@ func (s *Node) checkExpression(node *yaml.Node) (bool, error) {
if parseErr != nil { if parseErr != nil {
err = errors.Join(err, ValidationError{ err = errors.Join(err, ValidationError{
Location: toLocation(node), Location: toLocation(node),
Message: fmt.Sprintf("failed to parse: %s", parseErr.Error()), Message: "failed to parse: " + parseErr.Error(),
}) })
continue continue
} }
@@ -409,10 +410,8 @@ func (s *Node) UnmarshalYAML(node *yaml.Node) error {
return node.Decode(&b) return node.Decode(&b)
} else if def.AllowedValues != nil { } else if def.AllowedValues != nil {
s := node.Value s := node.Value
for _, v := range *def.AllowedValues { if slices.Contains(*def.AllowedValues, s) {
if s == v { return nil
return nil
}
} }
return ValidationError{ return ValidationError{
Location: toLocation(node), Location: toLocation(node),
@@ -448,7 +447,7 @@ func (s *Node) checkString(node *yaml.Node, def Definition) error {
if parseErr != nil { if parseErr != nil {
return ValidationError{ return ValidationError{
Location: toLocation(node), Location: toLocation(node),
Message: fmt.Sprintf("failed to parse: %s", parseErr.Error()), Message: "failed to parse: " + parseErr.Error(),
} }
} }
cerr := s.checkSingleExpression(exprNode) cerr := s.checkSingleExpression(exprNode)
@@ -650,7 +649,7 @@ func (s *Node) checkMapping(node *yaml.Node, def Definition) error {
if col := AsValidationErrorCollection(err); col != nil { if col := AsValidationErrorCollection(err); col != nil {
allErrors.AddError(ValidationError{ allErrors.AddError(ValidationError{
Location: toLocation(node.Content[i+1]), Location: toLocation(node.Content[i+1]),
Message: fmt.Sprintf("error found in value of key %s", k.Value), Message: "error found in value of key " + k.Value,
}) })
allErrors.Collections = append(allErrors.Collections, *col) allErrors.Collections = append(allErrors.Collections, *col)
continue continue
@@ -669,7 +668,7 @@ func (s *Node) checkMapping(node *yaml.Node, def Definition) error {
allErrors.AddError(ValidationError{ allErrors.AddError(ValidationError{
Location: toLocation(node), Location: toLocation(node),
Kind: ValidationKindMissingProperty, Kind: ValidationKindMissingProperty,
Message: fmt.Sprintf("missing property %s", k), Message: "missing property " + k,
}) })
} }
} }

View File

@@ -161,9 +161,11 @@ func (e *Environment) exec(ctx context.Context, command []string, _ string, env
wd = e.ToContainerPath(e.Path) wd = e.ToContainerPath(e.Path)
} }
envs := "" envs := ""
var envsSb164 strings.Builder
for k, v := range env { for k, v := range env {
envs += shellquote.Join(k) + "=" + shellquote.Join(v) + " " envsSb164.WriteString(shellquote.Join(k) + "=" + shellquote.Join(v) + " ")
} }
envs += envsSb164.String()
return e.execRaw(ctx, "cd "+shellquote.Join(wd)+"\nenv "+envs+shellquote.Join(command...)+"\nexit $?") return e.execRaw(ctx, "cd "+shellquote.Join(wd)+"\nenv "+envs+shellquote.Join(command...)+"\nexit $?")
} }
@@ -224,7 +226,7 @@ func (e *Environment) GetContainerArchive(ctx context.Context, srcPath string) (
return e.HostEnvironment.GetContainerArchive(ctx, e.ToHostPath(srcPath)) return e.HostEnvironment.GetContainerArchive(ctx, e.ToHostPath(srcPath))
} }
func (e *Environment) GetRunnerContext(ctx context.Context) map[string]interface{} { func (e *Environment) GetRunnerContext(ctx context.Context) map[string]any {
rctx := e.HostEnvironment.GetRunnerContext(ctx) rctx := e.HostEnvironment.GetRunnerContext(ctx)
rctx["temp"] = e.ToContainerPath(e.TmpDir) rctx["temp"] = e.ToContainerPath(e.TmpDir)
rctx["tool_cache"] = e.ToContainerPath(e.ToolCache) rctx["tool_cache"] = e.ToContainerPath(e.ToolCache)

View File

@@ -235,7 +235,7 @@ func ExecWithEnv(
func firstNonEmptyLine(outputs ...string) string { func firstNonEmptyLine(outputs ...string) string {
for _, output := range outputs { for _, output := range outputs {
for _, line := range strings.Split(output, "\n") { for line := range strings.SplitSeq(output, "\n") {
if line != "" { if line != "" {
return line return line
} }
@@ -246,5 +246,5 @@ func firstNonEmptyLine(outputs ...string) string {
} }
func (vm *VM) tartRunOutputPath() string { func (vm *VM) tartRunOutputPath() string {
return filepath.Join(os.TempDir(), fmt.Sprintf("%s-tart-run-output.log", vm.id)) return filepath.Join(os.TempDir(), vm.id+"-tart-run-output.log")
} }

View File

@@ -3,16 +3,16 @@ package workflowpattern
import "fmt" import "fmt"
type TraceWriter interface { type TraceWriter interface {
Info(string, ...interface{}) Info(string, ...any)
} }
type EmptyTraceWriter struct{} type EmptyTraceWriter struct{}
func (*EmptyTraceWriter) Info(string, ...interface{}) { func (*EmptyTraceWriter) Info(string, ...any) {
} }
type StdOutTraceWriter struct{} type StdOutTraceWriter struct{}
func (*StdOutTraceWriter) Info(format string, args ...interface{}) { func (*StdOutTraceWriter) Info(format string, args ...any) {
fmt.Printf(format+"\n", args...) fmt.Printf(format+"\n", args...)
} }

View File

@@ -127,7 +127,7 @@ func PatternToRegex(pattern string) (string, error) {
if errorMessage.Len() > 0 { if errorMessage.Len() > 0 {
errorMessage.WriteString(", ") errorMessage.WriteString(", ")
} }
errorMessage.WriteString(fmt.Sprintf("Position: %d Error: %s", position, err)) fmt.Fprintf(&errorMessage, "Position: %d Error: %s", position, err)
} }
return "", fmt.Errorf("invalid Pattern '%s': %s", pattern, errorMessage.String()) return "", fmt.Errorf("invalid Pattern '%s': %s", pattern, errorMessage.String())
} }

View File

@@ -407,8 +407,8 @@ func TestMatchPattern(t *testing.T) {
patterns, err := CompilePatterns(kase.patterns...) patterns, err := CompilePatterns(kase.patterns...)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, kase.skipResult, Skip(patterns, kase.inputs, &StdOutTraceWriter{}), "skipResult") assert.Equal(t, kase.skipResult, Skip(patterns, kase.inputs, &StdOutTraceWriter{}), "skipResult")
assert.EqualValues(t, kase.filterResult, Filter(patterns, kase.inputs, &StdOutTraceWriter{}), "filterResult") assert.Equal(t, kase.filterResult, Filter(patterns, kase.inputs, &StdOutTraceWriter{}), "filterResult")
}) })
} }
} }