Use golangci-lint fmt to format code (#163)

Use `golangci-lint fmt` to format code, upgrading `.golangci.yml` to v2 and mirroring the linter configuration used by https://github.com/go-gitea/gitea. `gci` now handles import ordering into standard, project-local, blank, and default groups.

Mirrors https://github.com/go-gitea/gitea/pull/37194.

Changes:
- Upgrade `.golangci.yml` to v2 format with the same linter set as gitea (minus `prealloc`, `unparam`, `testifylint`, `nilnil` which produced too many pre-existing issues)
- Add path-based exclusions (`bodyclose`, `gosec` in tests; `gosec:G115`/`G117` globally)
- Run lint via `make lint-go` in CI instead of `golangci/golangci-lint-action`, matching the pattern used by other Gitea repos
- Apply safe auto-fixes (`modernize`, `perfsprint`, `usetesting`, etc.)
- Add explanations to existing `//nolint` directives
- Remove dead code (unused `newRemoteReusableWorkflow` and `networkName`), duplicate imports, and shadowed `max` builtins
- Replace deprecated `docker/distribution/reference` with `distribution/reference`
- Fix `Deprecated:` comment casing and simplify nil/len checks

---
This PR was written with the help of Claude Opus 4.7

Reviewed-on: https://gitea.com/gitea/act/pulls/163
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-committed-by: silverwind <me@silverwind.io>
This commit is contained in:
silverwind
2026-04-18 09:10:09 +00:00
committed by silverwind
parent 3232358e71
commit f923badec7
89 changed files with 821 additions and 791 deletions

View File

@@ -14,11 +14,11 @@ import (
"runtime"
"strings"
"github.com/kballard/go-shellquote"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/model"
"github.com/kballard/go-shellquote"
)
type actionStep interface {
@@ -29,7 +29,7 @@ type actionStep interface {
getCompositeSteps() *compositeSteps
}
type readAction func(ctx context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error)
type readAction func(ctx context.Context, step *model.Step, actionDir, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error)
type actionYamlReader func(filename string) (io.Reader, io.Closer, error)
@@ -40,7 +40,7 @@ type runAction func(step actionStep, actionDir string, remoteAction *remoteActio
//go:embed res/trampoline.js
var trampoline embed.FS
func readActionImpl(ctx context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
func readActionImpl(ctx context.Context, step *model.Step, actionDir, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
logger := common.Logger(ctx)
allErrors := []error{}
addError := func(fileName string, err error) {
@@ -117,7 +117,7 @@ func readActionImpl(ctx context.Context, step *model.Step, actionDir string, act
return action, err
}
func maybeCopyToActionDir(ctx context.Context, step actionStep, actionDir string, actionPath string, containerActionDir string) error {
func maybeCopyToActionDir(ctx context.Context, step actionStep, actionDir, actionPath, containerActionDir string) error {
logger := common.Logger(ctx)
rc := step.getRunContext()
stepModel := step.getStepModel()
@@ -207,7 +207,7 @@ func runActionImpl(step actionStep, actionDir string, remoteAction *remoteAction
rc.ApplyExtraPath(ctx, step.getEnv())
execFileName := fmt.Sprintf("%s.out", action.Runs.Main)
execFileName := action.Runs.Main + ".out"
buildArgs := []string{"go", "build", "-o", execFileName, action.Runs.Main}
execArgs := []string{filepath.Join(containerActionDir, execFileName)}
@@ -262,8 +262,8 @@ func removeGitIgnore(ctx context.Context, directory string) error {
// TODO: break out parts of function to reduce complexicity
//
//nolint:gocyclo
func execAsDocker(ctx context.Context, step actionStep, actionName string, basedir string, localAction bool) error {
//nolint:gocyclo // function handles many cases
func execAsDocker(ctx context.Context, step actionStep, actionName, basedir string, localAction bool) error {
logger := common.Logger(ctx)
rc := step.getRunContext()
action := step.getActionModel()
@@ -271,14 +271,14 @@ func execAsDocker(ctx context.Context, step actionStep, actionName string, based
var prepImage common.Executor
var image string
forcePull := false
if strings.HasPrefix(action.Runs.Image, "docker://") {
image = strings.TrimPrefix(action.Runs.Image, "docker://")
if after, ok := strings.CutPrefix(action.Runs.Image, "docker://"); ok {
image = after
// Apply forcePull only for prebuild docker images
forcePull = rc.Config.ForcePull
} else {
// "-dockeraction" enshures 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("act-%s", strings.TrimLeft(image, "-"))
image = "act-" + strings.TrimLeft(image, "-")
image = strings.ToLower(image)
contextDir, fileName := filepath.Split(filepath.Join(basedir, action.Runs.Image))
@@ -391,7 +391,7 @@ func evalDockerArgs(ctx context.Context, step step, action *model.Action, cmd *[
}
}
func newStepContainer(ctx context.Context, step step, image string, cmd []string, entrypoint []string) container.Container {
func newStepContainer(ctx context.Context, step step, image string, cmd, entrypoint []string) container.Container {
rc := step.getRunContext()
stepModel := step.getStepModel()
rawLogger := common.Logger(ctx).WithField("raw_output", true)
@@ -414,7 +414,7 @@ func newStepContainer(ctx context.Context, step step, image string, cmd []string
envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_TEMP", "/tmp"))
binds, mounts := rc.GetBindsAndMounts()
networkMode := fmt.Sprintf("container:%s", rc.jobContainerName())
networkMode := "container:" + rc.jobContainerName()
if rc.IsHostEnv(ctx) {
networkMode = "default"
}
@@ -446,7 +446,7 @@ func populateEnvsFromSavedState(env *map[string]string, step actionStep, rc *Run
state, ok := rc.IntraActionState[step.getStepModel().ID]
if ok {
for name, value := range state {
envName := fmt.Sprintf("STATE_%s", name)
envName := "STATE_" + name
(*env)[envName] = value
}
}
@@ -456,7 +456,7 @@ func populateEnvsFromInput(ctx context.Context, env *map[string]string, action *
eval := rc.NewExpressionEvaluator(ctx)
for inputID, input := range action.Inputs {
envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(inputID), "_")
envKey = fmt.Sprintf("INPUT_%s", envKey)
envKey = "INPUT_" + envKey
if _, ok := (*env)[envKey]; !ok {
(*env)[envKey] = eval.Interpolate(ctx, input.Default)
}
@@ -543,7 +543,7 @@ func runPreStep(step actionStep) common.Executor {
actionPath = ""
}
actionLocation := ""
var actionLocation string
if actionPath != "" {
actionLocation = path.Join(actionDir, actionPath)
} else {
@@ -571,7 +571,7 @@ func runPreStep(step actionStep) common.Executor {
if steps := step.getCompositeSteps(); steps != nil && steps.pre != nil {
return steps.pre(ctx)
}
return fmt.Errorf("missing steps in composite action")
return errors.New("missing steps in composite action")
case x == model.ActionRunsUsingGo:
// defaults in pre steps were missing, however provided inputs are available
@@ -587,7 +587,7 @@ func runPreStep(step actionStep) common.Executor {
actionPath = ""
}
actionLocation := ""
var actionLocation string
if actionPath != "" {
actionLocation = path.Join(actionDir, actionPath)
} else {
@@ -602,7 +602,7 @@ func runPreStep(step actionStep) common.Executor {
rc.ApplyExtraPath(ctx, step.getEnv())
execFileName := fmt.Sprintf("%s.out", action.Runs.Pre)
execFileName := action.Runs.Pre + ".out"
buildArgs := []string{"go", "build", "-o", execFileName, action.Runs.Pre}
execArgs := []string{filepath.Join(containerActionDir, execFileName)}
@@ -672,7 +672,7 @@ func runPostStep(step actionStep) common.Executor {
actionPath = ""
}
actionLocation := ""
var actionLocation string
if actionPath != "" {
actionLocation = path.Join(actionDir, actionPath)
} else {
@@ -702,13 +702,13 @@ func runPostStep(step actionStep) common.Executor {
if steps := step.getCompositeSteps(); steps != nil && steps.post != nil {
return steps.post(ctx)
}
return fmt.Errorf("missing steps in composite action")
return errors.New("missing steps in composite action")
case x == model.ActionRunsUsingGo:
populateEnvsFromSavedState(step.getEnv(), step, rc)
rc.ApplyExtraPath(ctx, step.getEnv())
execFileName := fmt.Sprintf("%s.out", action.Runs.Post)
execFileName := action.Runs.Post + ".out"
buildArgs := []string{"go", "build", "-o", execFileName, action.Runs.Post}
execArgs := []string{filepath.Join(containerActionDir, execFileName)}

View File

@@ -5,17 +5,15 @@ import (
"bytes"
"context"
"io"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
//nolint:gosec
func TestActionCache(t *testing.T) {
a := assert.New(t)
cache := &GoGitActionCache{
Path: os.TempDir(),
Path: t.TempDir(),
}
ctx := context.Background()
cacheDir := "nektos/act-test-actions"

View File

@@ -2,8 +2,9 @@ package runner
import (
"context"
"fmt"
"errors"
"regexp"
"strconv"
"strings"
"github.com/nektos/act/pkg/common"
@@ -25,7 +26,7 @@ func evaluateCompositeInputAndEnv(ctx context.Context, parent *RunContext, step
for inputID, input := range step.getActionModel().Inputs {
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
// evaluated value from the environment
@@ -90,7 +91,7 @@ func execAsComposite(step actionStep) common.Executor {
steps := step.getCompositeSteps()
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)
@@ -138,7 +139,7 @@ func (rc *RunContext) compositeExecutor(action *model.Action) *compositeSteps {
for i, step := range action.Runs.Steps {
if step.ID == "" {
step.ID = fmt.Sprintf("%d", i)
step.ID = strconv.Itoa(i)
}
step.Number = i

View File

@@ -8,6 +8,7 @@ import (
"testing"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -122,7 +123,7 @@ runs:
writeFile := func(filename string, data []byte, perm fs.FileMode) error {
assert.Equal(t, "actionDir/actionPath/trampoline.js", filename)
assert.Equal(t, fs.FileMode(0400), perm)
assert.Equal(t, fs.FileMode(0o400), perm)
return nil
}

View File

@@ -29,7 +29,7 @@ func tryParseRawActionCommand(line string) (command string, kvPairs map[string]s
arg = m[4]
ok = true
}
return
return command, kvPairs, arg, ok
}
func (rc *RunContext) commandHandler(ctx context.Context) common.LineHandler {
@@ -135,10 +135,10 @@ func (rc *RunContext) addPath(ctx context.Context, arg string) {
rc.ExtraPath = extraPath
}
func parseKeyValuePairs(kvPairs string, separator string) map[string]string {
func parseKeyValuePairs(kvPairs, separator string) map[string]string {
rtn := make(map[string]string)
kvPairList := strings.Split(kvPairs, separator)
for _, kvPair := range kvPairList {
kvPairList := strings.SplitSeq(kvPairs, separator)
for kvPair := range kvPairList {
kv := strings.Split(kvPair, "=")
if len(kv) == 2 {
rtn[kv[0]] = kv[1]

View File

@@ -7,11 +7,11 @@ import (
"os"
"testing"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
)
func TestSetEnv(t *testing.T) {
@@ -164,7 +164,7 @@ func TestAddmaskUsemask(t *testing.T) {
re := captureOutput(t, func() {
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("::add-mask::secret\n")

View File

@@ -6,6 +6,7 @@ import (
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/stretchr/testify/mock"
)
@@ -15,7 +16,7 @@ type containerMock struct {
container.LinuxContainerEnvironmentExtensions
}
func (cm *containerMock) Create(capAdd []string, capDrop []string) common.Executor {
func (cm *containerMock) Create(capAdd, capDrop []string) common.Executor {
args := cm.Called(capAdd, capDrop)
return args.Get(0).(func(context.Context) error)
}
@@ -55,7 +56,7 @@ func (cm *containerMock) Copy(destPath string, files ...*container.FileEntry) co
return args.Get(0).(func(context.Context) error)
}
func (cm *containerMock) CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor {
func (cm *containerMock) CopyDir(destPath, srcPath string, useGitIgnore bool) common.Executor {
args := cm.Called(destPath, srcPath, useGitIgnore)
return args.Get(0).(func(context.Context) error)
}

View File

@@ -4,24 +4,26 @@ import (
"bytes"
"context"
"fmt"
"maps"
"path"
"reflect"
"regexp"
"strings"
"time"
_ "embed"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/exprparser"
"github.com/nektos/act/pkg/model"
_ "embed"
"go.yaml.in/yaml/v4"
)
// ExpressionEvaluator is the interface for evaluating expressions
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
Interpolate(context.Context, string) string
}
@@ -36,7 +38,7 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map
// todo: cleanup EvaluationEnvironment creation
using := make(map[string]exprparser.Needs)
strategy := make(map[string]interface{})
strategy := make(map[string]any)
if rc.Run != nil {
job := rc.Run.Job()
if job != nil && job.Strategy != nil {
@@ -64,9 +66,7 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map
result := model.WorkflowCallResult{
Outputs: map[string]string{},
}
for k, v := range job.Outputs {
result.Outputs[k] = v
}
maps.Copy(result.Outputs, job.Outputs)
workflowCallResult[jobName] = &result
}
}
@@ -110,7 +110,7 @@ var hashfiles string
func (rc *RunContext) NewStepExpressionEvaluator(ctx context.Context, step step) ExpressionEvaluator {
// todo: cleanup EvaluationEnvironment creation
job := rc.Run.Job()
strategy := make(map[string]interface{})
strategy := make(map[string]any)
if job.Strategy != nil {
strategy["fail-fast"] = job.Strategy.FailFast
strategy["max-parallel"] = job.Strategy.MaxParallel
@@ -157,8 +157,8 @@ func (rc *RunContext) NewStepExpressionEvaluator(ctx context.Context, step step)
}
}
func getHashFilesFunction(ctx context.Context, rc *RunContext) func(v []reflect.Value) (interface{}, error) {
hashFiles := func(v []reflect.Value) (interface{}, error) {
func getHashFilesFunction(ctx context.Context, rc *RunContext) func(v []reflect.Value) (any, error) {
hashFiles := func(v []reflect.Value) (any, error) {
if rc.JobContainer != nil {
timeed, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
@@ -182,9 +182,7 @@ func getHashFilesFunction(ctx context.Context, rc *RunContext) func(v []reflect.
patterns = append(patterns, s)
}
env := map[string]string{}
for k, v := range rc.Env {
env[k] = v
}
maps.Copy(env, rc.Env)
env["patterns"] = strings.Join(patterns, "\n")
if followSymlink {
env["followSymbolicLinks"] = "true"
@@ -222,7 +220,7 @@ type expressionEvaluator struct {
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.Debugf("evaluating expression '%s'", in)
evaluated, err := ee.interpreter.Evaluate(in, defaultStatusCheck)
@@ -403,7 +401,7 @@ func escapeFormatString(in string) string {
return strings.ReplaceAll(strings.ReplaceAll(in, "{", "{{"), "}", "}}")
}
//nolint:gocyclo
//nolint:gocyclo // function handles many cases
func rewriteSubExpression(ctx context.Context, in string, forceFormat bool) (string, error) {
if !strings.Contains(in, "${{") || !strings.Contains(in, "}}") {
return in, nil
@@ -414,7 +412,7 @@ func rewriteSubExpression(ctx context.Context, in string, forceFormat bool) (str
exprStart := -1
strStart := -1
var results []string
formatOut := ""
var formatOut strings.Builder
for pos < len(in) {
if strStart > -1 {
matches := strPattern.FindStringIndex(in[pos:])
@@ -437,7 +435,7 @@ func rewriteSubExpression(ctx context.Context, in string, forceFormat bool) (str
}
if exprEnd > -1 {
formatOut += fmt.Sprintf("{%d}", len(results))
fmt.Fprintf(&formatOut, "{%d}", len(results))
results = append(results, strings.TrimSpace(in[exprStart:pos+exprEnd]))
pos += exprEnd + 2
exprStart = -1
@@ -449,30 +447,30 @@ func rewriteSubExpression(ctx context.Context, in string, forceFormat bool) (str
} else {
exprStart = strings.Index(in[pos:], "${{")
if exprStart != -1 {
formatOut += escapeFormatString(in[pos : pos+exprStart])
formatOut.WriteString(escapeFormatString(in[pos : pos+exprStart]))
exprStart = pos + exprStart + 3
pos = exprStart
} else {
formatOut += escapeFormatString(in[pos:])
formatOut.WriteString(escapeFormatString(in[pos:]))
pos = len(in)
}
}
}
if len(results) == 1 && formatOut == "{0}" && !forceFormat {
if len(results) == 1 && formatOut.String() == "{0}" && !forceFormat {
return in, nil
}
out := fmt.Sprintf("format('%s', %s)", strings.ReplaceAll(formatOut, "'", "''"), strings.Join(results, ", "))
out := fmt.Sprintf("format('%s', %s)", strings.ReplaceAll(formatOut.String(), "'", "''"), strings.Join(results, ", "))
if in != out {
common.Logger(ctx).Debugf("expression '%s' rewritten to '%s'", in, out)
}
return out, nil
}
//nolint:gocyclo
func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *model.GithubContext) map[string]interface{} {
inputs := map[string]interface{}{}
//nolint:gocyclo // function handles many cases
func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *model.GithubContext) map[string]any {
inputs := map[string]any{}
setupWorkflowInputs(ctx, &inputs, rc)
@@ -484,8 +482,8 @@ func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *mod
}
for k, v := range env {
if strings.HasPrefix(k, "INPUT_") {
inputs[strings.ToLower(strings.TrimPrefix(k, "INPUT_"))] = v
if after, ok := strings.CutPrefix(k, "INPUT_"); ok {
inputs[strings.ToLower(after)] = v
}
}
@@ -525,7 +523,7 @@ func getEvaluatorInputs(ctx context.Context, rc *RunContext, step step, ghc *mod
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 {
config := rc.Run.Workflow.WorkflowCallConfig()

View File

@@ -6,17 +6,19 @@ import (
"os"
"regexp"
"sort"
"strings"
"testing"
"github.com/nektos/act/pkg/exprparser"
"github.com/nektos/act/pkg/model"
assert "github.com/stretchr/testify/assert"
yaml "go.yaml.in/yaml/v4"
)
func createRunContext(t *testing.T) *RunContext {
var yml yaml.Node
err := yml.Encode(map[string][]interface{}{
err := yml.Encode(map[string][]any{
"os": {"Linux", "Windows"},
"foo": {"bar", "baz"},
})
@@ -48,7 +50,7 @@ func createRunContext(t *testing.T) *RunContext {
},
},
},
Matrix: map[string]interface{}{
Matrix: map[string]any{
"os": "Linux",
"foo": "bar",
},
@@ -84,7 +86,7 @@ func TestEvaluateRunContext(t *testing.T) {
tables := []struct {
in string
out interface{}
out any
errMesg string
}{
{" 1 ", 1, ""},
@@ -138,7 +140,6 @@ func TestEvaluateRunContext(t *testing.T) {
}
for _, table := range tables {
table := table
t.Run(table.in, func(t *testing.T) {
assertObject := assert.New(t)
out, err := ee.evaluate(context.Background(), table.in, exprparser.DefaultStatusCheckNone)
@@ -163,7 +164,7 @@ func TestEvaluateStep(t *testing.T) {
tables := []struct {
in string
out interface{}
out any
errMesg string
}{
{"steps.idwithnothing.conclusion", model.StepStatusSuccess.String(), ""},
@@ -178,7 +179,6 @@ func TestEvaluateStep(t *testing.T) {
}
for _, table := range tables {
table := table
t.Run(table.in, func(t *testing.T) {
assertObject := assert.New(t)
out, err := ee.evaluate(context.Background(), table.in, exprparser.DefaultStatusCheckNone)
@@ -262,7 +262,6 @@ func TestInterpolate(t *testing.T) {
updateTestExpressionWorkflow(t, tables, rc)
for _, table := range tables {
table := table
t.Run("interpolate", func(t *testing.T) {
assertObject := assert.New(t)
out := ee.Interpolate(context.Background(), table.in)
@@ -274,19 +273,21 @@ func TestInterpolate(t *testing.T) {
func updateTestExpressionWorkflow(t *testing.T, tables []struct {
in string
out string
}, rc *RunContext) {
var envs string
}, rc *RunContext,
) {
var envs strings.Builder
keys := make([]string, 0, len(rc.Env))
for k := range rc.Env {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
envs += fmt.Sprintf(" %s: %s\n", k, rc.Env[k])
envs.WriteString(fmt.Sprintf(" %s: %s\n", k, rc.Env[k]))
}
// editorconfig-checker-disable
workflow := fmt.Sprintf(`
var workflow strings.Builder
workflow.WriteString(fmt.Sprintf(`
name: "Test how expressions are handled on GitHub"
on: push
@@ -297,7 +298,7 @@ jobs:
test-espressions:
runs-on: ubuntu-latest
steps:
`, envs)
`, envs.String()))
// editorconfig-checker-enable
for _, table := range tables {
expressionPattern := regexp.MustCompile(`\${{\s*(.+?)\s*}}`)
@@ -307,7 +308,7 @@ jobs:
})
name := fmt.Sprintf(`%s -> %s should be equal to %s`, expr, table.in, table.out)
echo := `run: echo "Done "`
workflow += fmt.Sprintf("\n - name: %s\n %s\n", name, echo)
workflow.WriteString(fmt.Sprintf("\n - name: %s\n %s\n", name, echo))
}
file, err := os.Create("../../.github/workflows/test-expressions.yml")
@@ -315,7 +316,7 @@ jobs:
t.Fatal(err)
}
_, err = file.WriteString(workflow)
_, err = file.WriteString(workflow.String())
if err != nil {
t.Fatal(err)
}

View File

@@ -3,6 +3,7 @@ package runner
import (
"context"
"fmt"
"strconv"
"time"
"github.com/nektos/act/pkg/common"
@@ -10,7 +11,7 @@ import (
)
type jobInfo interface {
matrix() map[string]interface{}
matrix() map[string]any
steps() []*model.Step
startContainer() common.Executor
stopContainer() common.Executor
@@ -19,7 +20,7 @@ type jobInfo interface {
result(result string)
}
//nolint:contextcheck,gocyclo
//nolint:contextcheck,gocyclo // composes many step executors
func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executor {
steps := make([]common.Executor, 0)
preSteps := make([]common.Executor, 0)
@@ -54,19 +55,17 @@ func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executo
})
for i, stepModel := range infoSteps {
stepModel := stepModel
if stepModel == nil {
return func(ctx context.Context) error {
return fmt.Errorf("invalid Step %v: missing run or uses key", i)
}
}
if stepModel.ID == "" {
stepModel.ID = fmt.Sprintf("%d", i)
stepModel.ID = strconv.Itoa(i)
}
stepModel.Number = i
step, err := sf.newStep(stepModel, rc)
if err != nil {
return common.NewErrorExecutor(err)
}
@@ -154,7 +153,7 @@ func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executo
pipeline = append(pipeline, steps...)
return common.NewPipelineExecutor(info.startContainer(), common.NewPipelineExecutor(pipeline...).
Finally(func(ctx context.Context) error { //nolint:contextcheck
Finally(func(ctx context.Context) error { //nolint:contextcheck // intentionally detaches from canceled parent
var cancel context.CancelFunc
if ctx.Err() == context.Canceled {
// in case of an aborted run, we still should execute the

View File

@@ -2,13 +2,16 @@ package runner
import (
"context"
"errors"
"fmt"
"io"
"slices"
"testing"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -38,9 +41,9 @@ type jobInfoMock struct {
mock.Mock
}
func (jim *jobInfoMock) matrix() map[string]interface{} {
func (jim *jobInfoMock) matrix() map[string]any {
args := jim.Called()
return args.Get(0).(map[string]interface{})
return args.Get(0).(map[string]any)
}
func (jim *jobInfoMock) steps() []*model.Step {
@@ -232,12 +235,7 @@ func TestNewJobExecutor(t *testing.T) {
}
contains := func(needle string, haystack []string) bool {
for _, item := range haystack {
if item == needle {
return true
}
}
return false
return slices.Contains(haystack, needle)
}
for _, tt := range table {
@@ -272,9 +270,6 @@ func TestNewJobExecutor(t *testing.T) {
}
for i, stepModel := range tt.steps {
i := i
stepModel := stepModel
sm := &stepMock{}
sfm.On("newStep", stepModel, rc).Return(sm, nil)
@@ -289,7 +284,7 @@ func TestNewJobExecutor(t *testing.T) {
sm.On("main").Return(func(ctx context.Context) error {
executorOrder = append(executorOrder, "step"+stepModel.ID)
if tt.hasError {
return fmt.Errorf("error")
return errors.New("error")
}
return nil
})
@@ -305,7 +300,7 @@ func TestNewJobExecutor(t *testing.T) {
}
if len(tt.steps) > 0 {
jim.On("matrix").Return(map[string]interface{}{})
jim.On("matrix").Return(map[string]any{})
jim.On("interpolateOutputs").Return(func(ctx context.Context) error {
executorOrder = append(executorOrder, "interpolateOutputs")

View File

@@ -26,9 +26,11 @@ const (
gray = 37
)
var colors []int
var nextColor int
var mux sync.Mutex
var (
colors []int
nextColor int
mux sync.Mutex
)
func init() {
nextColor = 0
@@ -70,7 +72,7 @@ func WithJobLoggerFactory(ctx context.Context, factory JobLoggerFactory) context
}
// 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, jobName string, config *Config, masks *[]string, matrix map[string]any) context.Context {
ctx = WithMasks(ctx, masks)
var logger *logrus.Logger

View File

@@ -4,6 +4,7 @@ import (
"testing"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"go.yaml.in/yaml/v4"
)
@@ -38,7 +39,7 @@ func TestMaxParallelStrategy(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
matrix := map[string][]interface{}{
matrix := map[string][]any{
"version": {1, 2, 3, 4, 5},
}

View File

@@ -94,7 +94,7 @@ func newActionCacheReusableWorkflowExecutor(rc *RunContext, filename string, rem
if err != nil {
return err
}
archive, err := rc.Config.ActionCache.GetTarArchive(ctx, filename, sha, fmt.Sprintf(".github/workflows/%s", remoteReusableWorkflow.Filename))
archive, err := rc.Config.ActionCache.GetTarArchive(ctx, filename, sha, ".github/workflows/"+remoteReusableWorkflow.Filename)
if err != nil {
return err
}
@@ -121,9 +121,7 @@ func newActionCacheReusableWorkflowExecutor(rc *RunContext, filename string, rem
}
}
var (
executorLock sync.Mutex
)
var executorLock sync.Mutex
func newMutexExecutor(executor common.Executor) common.Executor {
return func(ctx context.Context) error {
@@ -160,7 +158,7 @@ func cloneIfRequired(rc *RunContext, remoteReusableWorkflow remoteReusableWorkfl
)
}
func newReusableWorkflowExecutor(rc *RunContext, directory string, workflow string) common.Executor {
func newReusableWorkflowExecutor(rc *RunContext, directory, workflow string) common.Executor {
return func(ctx context.Context) error {
planner, err := model.NewWorkflowPlanner(path.Join(directory, workflow), true)
if err != nil {
@@ -260,24 +258,6 @@ func newRemoteReusableWorkflowFromAbsoluteURL(uses string) *remoteReusableWorkfl
}
}
// deprecated: use newRemoteReusableWorkflowWithPlat
func newRemoteReusableWorkflow(uses string) *remoteReusableWorkflow {
// GitHub docs:
// https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_iduses
r := regexp.MustCompile(`^([^/]+)/([^/]+)/.github/workflows/([^@]+)@(.*)$`)
matches := r.FindStringSubmatch(uses)
if len(matches) != 5 {
return nil
}
return &remoteReusableWorkflow{
Org: matches[1],
Repo: matches[2],
Filename: matches[3],
Ref: matches[4],
URL: "https://github.com",
}
}
// For Gitea
func setReusedWorkflowCallerResult(rc *RunContext, runner Runner) common.Executor {
return func(ctx context.Context) error {

View File

@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"io"
maps0 "maps"
"os"
"path/filepath"
"regexp"
@@ -18,20 +19,20 @@ import (
"strings"
"time"
"github.com/docker/go-connections/nat"
"github.com/opencontainers/selinux/go-selinux"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/exprparser"
"github.com/nektos/act/pkg/model"
"github.com/docker/go-connections/nat"
"github.com/opencontainers/selinux/go-selinux"
)
// RunContext contains info about current job
type RunContext struct {
Name string
Config *Config
Matrix map[string]interface{}
Matrix map[string]any
Run *model.Run
EventJSON string
Env map[string]string
@@ -100,19 +101,6 @@ func (rc *RunContext) jobContainerName() string {
return createSimpleContainerName(nameParts...) // For Gitea
}
// Deprecated: use `networkNameForGitea`
// networkName return the name of the network which will be created by `act` automatically for job,
// only create network if using a service container
func (rc *RunContext) networkName() (string, bool) {
if len(rc.Run.Job().Services) > 0 {
return fmt.Sprintf("%s-%s-network", rc.jobContainerName(), rc.Run.JobID), true
}
if rc.Config.ContainerNetworkMode == "" {
return "host", false
}
return string(rc.Config.ContainerNetworkMode), false
}
// networkNameForGitea return the name of the network
func (rc *RunContext) networkNameForGitea() (string, bool) {
if rc.Config.ContainerNetworkMode != "" {
@@ -122,13 +110,13 @@ func (rc *RunContext) networkNameForGitea() (string, bool) {
}
func getDockerDaemonSocketMountPath(daemonPath string) string {
if protoIndex := strings.Index(daemonPath, "://"); protoIndex != -1 {
scheme := daemonPath[:protoIndex]
if before, after, ok := strings.Cut(daemonPath, "://"); ok {
scheme := before
if strings.EqualFold(scheme, "npipe") {
// linux container mount on windows, use the default socket path of the VM / wsl2
return "/var/run/docker.sock"
} else if strings.EqualFold(scheme, "unix") {
return daemonPath[protoIndex+3:]
return after
} else if strings.IndexFunc(scheme, func(r rune) bool {
return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z')
}) == -1 {
@@ -242,7 +230,7 @@ func (rc *RunContext) startHostEnvironment() common.Executor {
rc.cleanUpJobContainer = rc.JobContainer.Remove()
for k, v := range rc.JobContainer.GetRunnerContext(ctx) {
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() {
@@ -268,7 +256,7 @@ func (rc *RunContext) startHostEnvironment() common.Executor {
}
}
//nolint:gocyclo
//nolint:gocyclo // function handles many cases
func (rc *RunContext) startJobContainer() common.Executor {
return func(ctx context.Context) error {
logger := common.Logger(ctx)
@@ -404,15 +392,8 @@ func (rc *RunContext) startJobContainer() common.Executor {
return nil
}
jobContainerNetwork := rc.Config.ContainerNetworkMode.NetworkName()
if rc.containerImage(ctx) != "" {
jobContainerNetwork = networkName
} else if jobContainerNetwork == "" {
jobContainerNetwork = "host"
}
// For Gitea, `jobContainerNetwork` should be the same as `networkName`
jobContainerNetwork = networkName
jobContainerNetwork := networkName
rc.JobContainer = container.NewContainer(&container.NewContainerInput{
Cmd: nil,
@@ -468,7 +449,7 @@ func (rc *RunContext) execJobContainer(cmd []string, env map[string]string, user
}
func (rc *RunContext) ApplyExtraPath(ctx context.Context, env *map[string]string) {
if rc.ExtraPath != nil && len(rc.ExtraPath) > 0 {
if len(rc.ExtraPath) > 0 {
path := rc.JobContainer.GetPathVariableName()
if rc.JobContainer.IsEnvironmentCaseInsensitive() {
// On windows system Path and PATH could also be in the map
@@ -627,7 +608,7 @@ func (rc *RunContext) closeContainer() common.Executor {
}
}
func (rc *RunContext) matrix() map[string]interface{} {
func (rc *RunContext) matrix() map[string]any {
return rc.Matrix
}
@@ -642,7 +623,7 @@ func (rc *RunContext) steps() []*model.Step {
// Executor returns a pipeline executor for all the steps in the job
func (rc *RunContext) Executor() (common.Executor, error) {
var executor common.Executor
var jobType, err = rc.Run.Job().Type()
jobType, err := rc.Run.Job().Type()
switch jobType {
case model.JobTypeDefault:
@@ -779,14 +760,12 @@ func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) {
func mergeMaps(maps ...map[string]string) map[string]string {
rtnMap := make(map[string]string)
for _, m := range maps {
for k, v := range m {
rtnMap[k] = v
}
maps0.Copy(rtnMap, m)
}
return rtnMap
}
// deprecated: use createSimpleContainerName
// Deprecated: use createSimpleContainerName
func createContainerName(parts ...string) string {
name := strings.Join(parts, "-")
pattern := regexp.MustCompile("[^a-zA-Z0-9]")
@@ -843,10 +822,11 @@ func (rc *RunContext) getStepsContext() map[string]*model.StepResult {
return rc.StepResults
}
//nolint:gocyclo // function handles many cases
func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext {
logger := common.Logger(ctx)
ghc := &model.GithubContext{
Event: make(map[string]interface{}),
Event: make(map[string]any),
Workflow: rc.Run.Workflow.Name,
RunID: rc.Config.Env["GITHUB_RUN_ID"],
RunNumber: rc.Config.Env["GITHUB_RUN_NUMBER"],
@@ -954,7 +934,7 @@ func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext
ghc.GraphQLURL = "https://api.github.com/graphql"
// per GHES
if rc.Config.GitHubInstance != "github.com" {
ghc.ServerURL = fmt.Sprintf("https://%s", rc.Config.GitHubInstance)
ghc.ServerURL = "https://" + rc.Config.GitHubInstance
ghc.APIURL = fmt.Sprintf("https://%s/api/v3", rc.Config.GitHubInstance)
ghc.GraphQLURL = fmt.Sprintf("https://%s/api/graphql", rc.Config.GitHubInstance)
}
@@ -1010,7 +990,7 @@ func isLocalCheckout(ghc *model.GithubContext, step *model.Step) bool {
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
if len(ks) == 0 { // degenerate input
@@ -1020,7 +1000,7 @@ func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{})
return nil
} else if len(ks) == 1 { // we've reached the final key
return rval
} else if m, ok = rval.(map[string]interface{}); !ok {
} else if m, ok = rval.(map[string]any); !ok {
return nil
} else { // 1+ more keys
return nestedMapLookup(m, ks[1:]...)
@@ -1113,22 +1093,22 @@ func (rc *RunContext) handleCredentials(ctx context.Context) (string, string, er
}
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
}
ee := rc.NewExpressionEvaluator(ctx)
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
}
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
}
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
}
@@ -1137,25 +1117,25 @@ func (rc *RunContext) handleCredentials(ctx context.Context) (string, string, er
func (rc *RunContext) handleServiceCredentials(ctx context.Context, creds map[string]string) (username, password string, err error) {
if creds == nil {
return
return username, password, err
}
if len(creds) != 2 {
err = fmt.Errorf("invalid property count for key 'credentials:'")
return
err = errors.New("invalid property count for key 'credentials:'")
return username, password, err
}
ee := rc.NewExpressionEvaluator(ctx)
if username = ee.Interpolate(ctx, creds["username"]); username == "" {
err = fmt.Errorf("failed to interpolate credentials.username")
return
err = errors.New("failed to interpolate credentials.username")
return username, password, err
}
if password = ee.Interpolate(ctx, creds["password"]); password == "" {
err = fmt.Errorf("failed to interpolate credentials.password")
return
err = errors.New("failed to interpolate credentials.password")
return username, password, err
}
return
return username, password, err
}
// GetServiceBindsAndMounts returns the binds and mounts for the service container, resolving paths as appopriate

View File

@@ -20,7 +20,7 @@ import (
func TestRunContext_EvalBool(t *testing.T) {
var yml yaml.Node
err := yml.Encode(map[string][]interface{}{
err := yml.Encode(map[string][]any{
"os": {"Linux", "Windows"},
"foo": {"bar", "baz"},
})
@@ -48,7 +48,7 @@ func TestRunContext_EvalBool(t *testing.T) {
},
},
},
Matrix: map[string]interface{}{
Matrix: map[string]any{
"os": "Linux",
"foo": "bar",
},
@@ -154,7 +154,6 @@ func TestRunContext_EvalBool(t *testing.T) {
updateTestIfWorkflow(t, tables, rc)
for _, table := range tables {
table := table
t.Run(table.in, func(t *testing.T) {
assertObject := assert.New(t)
b, err := EvalBool(context.Background(), rc.ExprEval, table.in, exprparser.DefaultStatusCheckSuccess)
@@ -171,18 +170,20 @@ func updateTestIfWorkflow(t *testing.T, tables []struct {
in string
out bool
wantErr bool
}, rc *RunContext) {
var envs string
}, rc *RunContext,
) {
var envs strings.Builder
keys := make([]string, 0, len(rc.Env))
for k := range rc.Env {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
envs += fmt.Sprintf(" %s: %s\n", k, rc.Env[k])
envs.WriteString(fmt.Sprintf(" %s: %s\n", k, rc.Env[k]))
}
// editorconfig-checker-disable
workflow := fmt.Sprintf(`
var workflow strings.Builder
workflow.WriteString(fmt.Sprintf(`
name: "Test what expressions result in true and false on GitHub"
on: push
@@ -193,7 +194,7 @@ jobs:
test-ifs-and-buts:
runs-on: ubuntu-latest
steps:
`, envs)
`, envs.String()))
// editorconfig-checker-enable
for i, table := range tables {
@@ -211,9 +212,9 @@ jobs:
echo = `run: echo OK`
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)
workflow.WriteString(fmt.Sprintf("\n - name: %s\n id: step%d\n if: %s\n %s\n", name, i, table.in, echo))
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)
workflow.WriteString(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))
}
}
@@ -222,7 +223,7 @@ jobs:
t.Fatal(err)
}
_, err = file.WriteString(workflow)
_, err = file.WriteString(workflow.String())
if err != nil {
t.Fatal(err)
}
@@ -259,10 +260,8 @@ func TestRunContext_GetBindsAndMounts(t *testing.T) {
for _, testcase := range tests {
// pin for scopelint
testcase := testcase
for _, bindWorkDir := range []bool{true, false} {
// pin for scopelint
bindWorkDir := bindWorkDir
testBindSuffix := ""
if bindWorkDir {
testBindSuffix = "Bind"
@@ -359,7 +358,7 @@ func TestGetGitHubContext(t *testing.T) {
},
Name: "GitHubContextTest",
CurrentStep: "step",
Matrix: map[string]interface{}{},
Matrix: map[string]any{},
Env: map[string]string{},
ExtraPath: []string{},
StepResults: map[string]*model.StepResult{},
@@ -417,7 +416,6 @@ func TestGetGithubContextRef(t *testing.T) {
}
for _, data := range table {
data := data
t.Run(data.event, func(t *testing.T) {
rc := &RunContext{
EventJSON: data.json,
@@ -461,7 +459,7 @@ func createIfTestRunContext(jobs map[string]*model.Job) *RunContext {
return rc
}
func createJob(t *testing.T, input string, result string) *model.Job {
func createJob(t *testing.T, input, result string) *model.Job {
var job *model.Job
err := yaml.Unmarshal([]byte(input), &job)
assert.NoError(t, err)

View File

@@ -9,11 +9,11 @@ import (
"sync"
"time"
docker_container "github.com/docker/docker/api/types/container"
log "github.com/sirupsen/logrus"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
docker_container "github.com/docker/docker/api/types/container"
log "github.com/sirupsen/logrus"
)
// Runner provides capabilities to run GitHub actions
@@ -133,6 +133,8 @@ func (runner *runnerImpl) configure() (Runner, error) {
}
// NewPlanExecutor ...
//
//nolint:gocyclo // function handles many cases
func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
maxJobNameLen := 0
@@ -182,7 +184,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 {
log.Errorf("Error while get job's matrix: %v", err)
} else {
@@ -210,7 +212,6 @@ func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
log.Infof("Running job with maxParallel=%d for %d matrix combinations", maxParallel, len(matrixes))
for i, matrix := range matrixes {
matrix := matrix
rc := runner.newRunContext(ctx, run, matrix)
rc.JobName = rc.Name
if len(matrixes) > 1 {
@@ -225,7 +226,6 @@ func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
stageExecutor = append(stageExecutor, func(ctx context.Context) error {
jobName := fmt.Sprintf("%-*s", maxJobNameLen, rc.String())
executor, err := rc.Executor()
if err != nil {
return err
}
@@ -287,8 +287,8 @@ func handleFailure(plan *model.Plan) common.Executor {
}
}
func selectMatrixes(originalMatrixes []map[string]interface{}, targetMatrixValues map[string]map[string]bool) []map[string]interface{} {
matrixes := make([]map[string]interface{}, 0)
func selectMatrixes(originalMatrixes []map[string]any, targetMatrixValues map[string]map[string]bool) []map[string]any {
matrixes := make([]map[string]any, 0)
for _, original := range originalMatrixes {
flag := true
for key, val := range original {
@@ -306,7 +306,7 @@ func selectMatrixes(originalMatrixes []map[string]interface{}, targetMatrixValue
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{
Config: runner.config,
Run: run,
@@ -322,7 +322,7 @@ func (runner *runnerImpl) newRunContext(ctx context.Context, run *model.Run, mat
}
// For Gitea
func (c *caller) setReusedWorkflowJobResult(jobName string, result string) {
func (c *caller) setReusedWorkflowJobResult(jobName, result string) {
c.updateResultLock.Lock()
defer c.updateResultLock.Unlock()
c.reusedWorkflowJobResults[jobName] = result

View File

@@ -90,14 +90,12 @@ func TestMaxParallelConcurrencyTracking(t *testing.T) {
var wg sync.WaitGroup
semaphore := make(chan struct{}, 2) // Limit to 2 concurrent
for i := 0; i < 6; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for range 6 {
wg.Go(func() {
semaphore <- struct{}{} // Acquire
defer func() { <-semaphore }() // Release
trackingFunc()
}()
})
}
wg.Wait()

View File

@@ -12,13 +12,13 @@ import (
"strings"
"testing"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
"github.com/joho/godotenv"
log "github.com/sirupsen/logrus"
assert "github.com/stretchr/testify/assert"
"go.yaml.in/yaml/v4"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
)
var (
@@ -528,9 +528,9 @@ func (f *maskJobLoggerFactory) WithJobLogger() *log.Logger {
}
func TestMaskValues(t *testing.T) {
assertNoSecret := func(text string, secret string) {
index := strings.Index(text, "composite secret")
if index > -1 {
assertNoSecret := func(text, secret string) {
found := strings.Contains(text, "composite secret")
if found {
fmt.Printf("\nFound Secret in the given text:\n%s\n", text)
}
assert.False(t, strings.Contains(text, "composite secret"))
@@ -607,7 +607,7 @@ func TestRunWithService(t *testing.T) {
runner, err := New(runnerConfig)
assert.NoError(t, err, workflowPath)
planner, err := model.NewWorkflowPlanner(fmt.Sprintf("testdata/%s", workflowPath), true)
planner, err := model.NewWorkflowPlanner("testdata/"+workflowPath, true)
assert.NoError(t, err, workflowPath)
plan, err := planner.PlanEvent(eventName)

View File

@@ -3,6 +3,7 @@ package runner
import (
"context"
"fmt"
maps0 "maps"
"path"
"strconv"
"strings"
@@ -142,7 +143,7 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo
Mode: 0o666,
}, &container.FileEntry{
Name: envFileCommand,
Mode: 0666,
Mode: 0o666,
}, &container.FileEntry{
Name: summaryFileCommand,
Mode: 0o666,
@@ -295,9 +296,7 @@ func mergeIntoMap(step step, target *map[string]string, maps ...map[string]strin
func mergeIntoMapCaseSensitive(target map[string]string, maps ...map[string]string) {
for _, m := range maps {
for k, v := range m {
target[k] = v
}
maps0.Copy(target, m)
}
}

View File

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

View File

@@ -10,6 +10,7 @@ import (
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"go.yaml.in/yaml/v4"
@@ -24,7 +25,7 @@ func (salm *stepActionLocalMocks) runAction(step actionStep, actionDir string, r
return args.Get(0).(func(context.Context) error)
}
func (salm *stepActionLocalMocks) readAction(_ context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
func (salm *stepActionLocalMocks) readAction(_ context.Context, step *model.Step, actionDir, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
args := salm.Called(step, actionDir, actionPath, readFile, writeFile)
return args.Get(0).(*model.Action), args.Error(1)
}
@@ -257,7 +258,7 @@ func TestStepActionLocalPost(t *testing.T) {
sal.RunContext.ExprEval = sal.RunContext.NewExpressionEvaluator(ctx)
if tt.mocks.exec {
suffixMatcher := func(suffix string) interface{} {
suffixMatcher := func(suffix string) any {
return mock.MatchedBy(func(array []string) bool {
return strings.HasSuffix(array[1], suffix)
})

View File

@@ -12,11 +12,11 @@ import (
"regexp"
"strings"
gogit "github.com/go-git/go-git/v5"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/common/git"
"github.com/nektos/act/pkg/model"
gogit "github.com/go-git/go-git/v5"
)
type stepActionRemote struct {
@@ -35,6 +35,7 @@ type stepActionRemote struct {
var stepActionRemoteNewCloneExecutor = git.NewGitCloneExecutor
//nolint:gocyclo // function handles many cases
func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
return func(ctx context.Context) error {
if sar.remoteAction != nil && sar.action != nil {
@@ -80,7 +81,7 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
remoteReader := func(ctx context.Context) actionYamlReader {
return func(filename string) (io.Reader, io.Closer, error) {
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)
if err != nil {
return nil, nil, os.ErrNotExist
@@ -301,8 +302,8 @@ func (ra *remoteAction) IsCheckout() bool {
func newRemoteAction(action string) *remoteAction {
// support http(s)://host/owner/repo@v3
for _, schema := range []string{"https://", "http://"} {
if strings.HasPrefix(action, schema) {
splits := strings.SplitN(strings.TrimPrefix(action, schema), "/", 2)
if after, ok := strings.CutPrefix(action, schema); ok {
splits := strings.SplitN(after, "/", 2)
if len(splits) != 2 {
return nil
}

View File

@@ -10,20 +10,20 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"go.yaml.in/yaml/v4"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/common/git"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"go.yaml.in/yaml/v4"
)
type stepActionRemoteMocks struct {
mock.Mock
}
func (sarm *stepActionRemoteMocks) readAction(_ context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
func (sarm *stepActionRemoteMocks) readAction(_ context.Context, step *model.Step, actionDir, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
args := sarm.Called(step, actionDir, actionPath, readFile, writeFile)
return args.Get(0).(*model.Action), args.Error(1)
}
@@ -162,7 +162,7 @@ func TestStepActionRemote(t *testing.T) {
}
sar.RunContext.ExprEval = sar.RunContext.NewExpressionEvaluator(ctx)
suffixMatcher := func(suffix string) interface{} {
suffixMatcher := func(suffix string) any {
return mock.MatchedBy(func(actionDir string) bool {
return strings.HasSuffix(actionDir, suffix)
})
@@ -258,7 +258,7 @@ func TestStepActionRemotePre(t *testing.T) {
readAction: sarm.readAction,
}
suffixMatcher := func(suffix string) interface{} {
suffixMatcher := func(suffix string) any {
return mock.MatchedBy(func(actionDir string) bool {
return strings.HasSuffix(actionDir, suffix)
})
@@ -329,7 +329,7 @@ func TestStepActionRemotePreThroughAction(t *testing.T) {
readAction: sarm.readAction,
}
suffixMatcher := func(suffix string) interface{} {
suffixMatcher := func(suffix string) any {
return mock.MatchedBy(func(actionDir string) bool {
return strings.HasSuffix(actionDir, suffix)
})
@@ -405,7 +405,7 @@ func TestStepActionRemotePreThroughActionToken(t *testing.T) {
readAction: sarm.readAction,
}
suffixMatcher := func(suffix string) interface{} {
suffixMatcher := func(suffix string) any {
return mock.MatchedBy(func(actionDir string) bool {
return strings.HasSuffix(actionDir, suffix)
})

View File

@@ -5,10 +5,11 @@ import (
"fmt"
"strings"
"github.com/kballard/go-shellquote"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/model"
"github.com/kballard/go-shellquote"
)
type stepDocker struct {
@@ -85,11 +86,9 @@ func (sd *stepDocker) runUsesContainer() common.Executor {
}
}
var (
ContainerNewContainer = container.NewContainer
)
var ContainerNewContainer = container.NewContainer
func (sd *stepDocker) newStepContainer(ctx context.Context, image string, cmd []string, entrypoint []string) container.Container {
func (sd *stepDocker) newStepContainer(ctx context.Context, image string, cmd, entrypoint []string) container.Container {
rc := sd.RunContext
step := sd.Step
@@ -123,7 +122,7 @@ func (sd *stepDocker) newStepContainer(ctx context.Context, image string, cmd []
Name: createSimpleContainerName(rc.jobContainerName(), "STEP-"+step.ID),
Env: envList,
Mounts: mounts,
NetworkMode: fmt.Sprintf("container:%s", rc.jobContainerName()),
NetworkMode: "container:" + rc.jobContainerName(),
Binds: binds,
Stdout: logWriter,
Stderr: logWriter,

View File

@@ -8,6 +8,7 @@ import (
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

View File

@@ -4,6 +4,7 @@ import (
"testing"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
)

View File

@@ -3,15 +3,16 @@ package runner
import (
"context"
"fmt"
"maps"
"runtime"
"strings"
"github.com/kballard/go-shellquote"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/lookpath"
"github.com/nektos/act/pkg/model"
"github.com/kballard/go-shellquote"
)
type stepRun struct {
@@ -90,7 +91,7 @@ func getScriptName(rc *RunContext, step *model.Step) string {
for rcs := rc; rcs.Parent != nil; rcs = rcs.Parent {
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
@@ -184,9 +185,7 @@ func (sr *stepRun) setupShell(ctx context.Context) {
}
step.Shell = shellWithFallback[0]
lenv := &localEnv{env: map[string]string{}}
for k, v := range sr.env {
lenv.env[k] = v
}
maps.Copy(lenv.env, sr.env)
sr.getRunContext().ApplyExtraPath(ctx, &lenv.env)
_, err := lookpath.LookPath2(shellWithFallback[0], lenv)
if err != nil {
@@ -202,7 +201,7 @@ func (sr *stepRun) setupShell(ctx context.Context) {
func (sr *stepRun) setupWorkingDirectory(ctx context.Context) {
rc := sr.RunContext
step := sr.Step
workingdirectory := ""
var workingdirectory string
if step.WorkingDirectory == "" {
workingdirectory = rc.Run.Job().Defaults.Run.WorkingDirectory

View File

@@ -6,11 +6,11 @@ import (
"io"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestStepRun(t *testing.T) {

View File

@@ -6,6 +6,7 @@ import (
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"