From f923badec789b36b8f91aea82eef18851ffda558 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 18 Apr 2026 09:10:09 +0000 Subject: [PATCH] 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 Co-authored-by: silverwind Co-committed-by: silverwind --- .github/workflows/checks.yml | 6 +- .golangci.yml | 183 +++++++++++++----- Makefile | 18 +- cmd/notices.go | 4 +- cmd/root.go | 28 +-- main.go | 3 +- pkg/artifactcache/handler.go | 9 +- pkg/artifactcache/handler_test.go | 26 +-- pkg/artifactcache/storage.go | 5 +- pkg/artifacts/server.go | 13 +- pkg/artifacts/server_test.go | 42 ++-- pkg/common/cartesian.go | 14 +- pkg/common/cartesian_test.go | 6 +- pkg/common/draw.go | 9 +- pkg/common/executor.go | 12 +- pkg/common/executor_max_parallel_test.go | 32 +-- pkg/common/executor_parallel_advanced_test.go | 48 ++--- pkg/common/executor_test.go | 8 +- pkg/common/file.go | 6 +- pkg/common/git/git.go | 23 +-- pkg/common/git/git_test.go | 9 +- pkg/container/container_types.go | 7 +- pkg/container/docker_auth.go | 3 +- pkg/container/docker_build.go | 10 +- pkg/container/docker_cli.go | 24 +-- pkg/container/docker_cli_test.go | 19 +- pkg/container/docker_images.go | 4 +- pkg/container/docker_logger.go | 2 +- pkg/container/docker_network.go | 4 +- pkg/container/docker_pull.go | 6 +- pkg/container/docker_pull_test.go | 1 - pkg/container/docker_run.go | 23 ++- pkg/container/docker_run_test.go | 8 +- pkg/container/docker_socket.go | 4 +- pkg/container/docker_socket_test.go | 8 +- pkg/container/docker_stub.go | 7 +- pkg/container/docker_volume.go | 3 +- pkg/container/executions_environment.go | 2 +- pkg/container/host_environment.go | 29 +-- pkg/container/host_environment_test.go | 28 ++- .../linux_container_environment_extensions.go | 7 +- ...x_container_environment_extensions_test.go | 13 +- pkg/exprparser/functions.go | 25 +-- pkg/exprparser/functions_test.go | 21 +- pkg/exprparser/interpreter.go | 62 +++--- pkg/exprparser/interpreter_test.go | 33 ++-- pkg/filecollector/file_collector.go | 8 +- pkg/filecollector/file_collector_test.go | 2 +- pkg/lookpath/env.go | 3 +- pkg/lookpath/lp_plan9.go | 2 +- pkg/lookpath/lp_unix.go | 2 +- pkg/model/action.go | 2 +- pkg/model/github_context.go | 88 +++++---- pkg/model/github_context_test.go | 50 ++--- pkg/model/planner.go | 23 +-- pkg/model/workflow.go | 74 ++++--- pkg/model/workflow_test.go | 24 +-- pkg/runner/action.go | 44 ++--- pkg/runner/action_cache_test.go | 4 +- pkg/runner/action_composite.go | 9 +- pkg/runner/action_test.go | 3 +- pkg/runner/command.go | 8 +- pkg/runner/command_test.go | 8 +- pkg/runner/container_mock_test.go | 5 +- pkg/runner/expression.go | 52 +++-- pkg/runner/expression_test.go | 29 +-- pkg/runner/job_executor.go | 11 +- pkg/runner/job_executor_test.go | 21 +- pkg/runner/logger.go | 10 +- pkg/runner/max_parallel_test.go | 3 +- pkg/runner/reusable_workflow.go | 26 +-- pkg/runner/run_context.go | 86 ++++---- pkg/runner/run_context_test.go | 30 ++- pkg/runner/runner.go | 20 +- pkg/runner/runner_max_parallel_test.go | 8 +- pkg/runner/runner_test.go | 14 +- pkg/runner/step.go | 7 +- pkg/runner/step_action_local.go | 2 +- pkg/runner/step_action_local_test.go | 5 +- pkg/runner/step_action_remote.go | 11 +- pkg/runner/step_action_remote_test.go | 18 +- pkg/runner/step_docker.go | 11 +- pkg/runner/step_docker_test.go | 1 + pkg/runner/step_factory_test.go | 1 + pkg/runner/step_run.go | 13 +- pkg/runner/step_run_test.go | 6 +- pkg/runner/step_test.go | 1 + pkg/workflowpattern/trace_writer.go | 6 +- pkg/workflowpattern/workflow_pattern.go | 4 +- 89 files changed, 821 insertions(+), 791 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 0a8c0349..b4339994 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -22,10 +22,8 @@ jobs: with: go-version-file: go.mod check-latest: true - - uses: golangci/golangci-lint-action@v3.7.0 - with: - version: v1.53 - only-new-issues: true + - name: lint + run: make lint-go - uses: megalinter/megalinter/flavors/go@v7.8.0 env: DEFAULT_BRANCH: master diff --git a/.golangci.yml b/.golangci.yml index 4082864b..bfdb4421 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,51 +1,146 @@ -# Minimum golangci-lint version required: v1.46.0 -run: - timeout: 3m - -skip-dirs: - - report # megalinter results+fixes - -linters-settings: - gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 15 - gocritic: - disabled-checks: - - ifElseChain - importas: - aliases: - - pkg: 'github.com/sirupsen/logrus' - alias: log - - pkg: 'github.com/stretchr/testify/assert' - alias: assert - depguard: - rules: - main: - deny: - - pkg: github.com/pkg/errors - desc: Please use "errors" package from standard library - - pkg: gotest.tools/v3 - desc: Please keep tests unified using only github.com/stretchr/testify - - pkg: log - desc: Please keep logging unified using only github.com/sirupsen/logrus +version: "2" +output: + sort-order: + - file linters: + default: none enable: - - megacheck - - govet - - revive + - bidichk + - bodyclose + - contextcheck + - depguard + - dupl + - errcheck + - gocheckcompilerdirectives + - gocritic - gocyclo - gosec - - unconvert - - dupl - - nakedret - - prealloc - - exportloopref - - gocritic - - goimports - - whitespace - - misspell - - depguard + - govet - importas - - contextcheck + - ineffassign + - misspell + - mirror + - modernize + - nakedret - nolintlint + - perfsprint - revive + - staticcheck + - unconvert + - unused + - usestdlibvars + - usetesting + - wastedassign + - whitespace + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/pkg/errors + desc: Please use "errors" package from standard library + - pkg: gotest.tools/v3 + desc: Please keep tests unified using only github.com/stretchr/testify + - pkg: log + desc: Please keep logging unified using only github.com/sirupsen/logrus + gocyclo: + min-complexity: 15 + gocritic: + disabled-checks: + - ifElseChain + importas: + alias: + - pkg: github.com/sirupsen/logrus + alias: log + - pkg: github.com/stretchr/testify/assert + alias: assert + nolintlint: + allow-unused: false + require-explanation: true + require-specific: true + revive: + severity: error + rules: + - name: blank-imports + - name: constant-logical-expr + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: empty-lines + - name: error-return + - name: error-strings + - name: exported + - name: identical-branches + - name: if-return + - name: increment-decrement + - name: modifies-value-receiver + - name: package-comments + - name: redefines-builtin-id + - name: superfluous-else + - name: time-naming + - name: unexported-return + - name: var-declaration + - name: var-naming + staticcheck: + checks: + - all + - -ST1003 + - -ST1005 + - -QF1001 + - -QF1006 + - -QF1008 + usetesting: + os-temp-dir: true + perfsprint: + concat-loop: false + govet: + enable: + - nilness + - unusedwrite + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - bodyclose + - dupl + - errcheck + - gosec + - staticcheck + path: _test\.go + - linters: + - gosec + text: 'G115:' + - linters: + - gosec + text: 'G117:' + paths: + - report +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gci + - gofumpt + settings: + gci: + custom-order: true + sections: + - standard + - prefix(github.com/nektos/act) + - blank + - default + gofumpt: + extra-rules: true + exclusions: + generated: lax + paths: + - report + +run: + timeout: 10m diff --git a/Makefile b/Makefile index 97a57f7b..6dc8e794 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,8 @@ endif ACT ?= go run main.go +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 + HAS_TOKEN = $(if $(test -e ~/.config/github/token),true,false) ifeq (true,$(HAS_TOKEN)) export GITHUB_TOKEN := $(shell cat ~/.config/github/token) @@ -27,11 +29,19 @@ build: .PHONY: format format: - go fmt ./... + go run $(GOLANGCI_LINT_PACKAGE) fmt + +.PHONY: format-check +format-check: format + @diff=$$(git diff --color=always); \ + if [ -n "$$diff" ]; then \ + echo "Please run 'make format' and commit the result:"; \ + printf "%s" "$${diff}"; \ + exit 1; \ + fi .PHONY: format-all -format-all: - go fmt ./... +format-all: format npx prettier --write . .PHONY: test @@ -41,7 +51,7 @@ test: .PHONY: lint-go lint-go: - golangci-lint run $(FIX) + go run $(GOLANGCI_LINT_PACKAGE) run $(FIX) .PHONY: lint-js lint-js: diff --git a/cmd/notices.go b/cmd/notices.go index a912bd9f..65fd1c30 100644 --- a/cmd/notices.go +++ b/cmd/notices.go @@ -76,7 +76,7 @@ func getVersionNotices(version string) []Notice { noticeURL.RawQuery = query.Encode() client := &http.Client{} - req, err := http.NewRequest("GET", noticeURL.String(), nil) + req, err := http.NewRequest(http.MethodGet, noticeURL.String(), nil) if err != nil { log.Debug(err) return nil @@ -102,7 +102,7 @@ func getVersionNotices(version string) []Notice { defer resp.Body.Close() notices := []Notice{} - if resp.StatusCode == 304 { + if resp.StatusCode == http.StatusNotModified { log.Debug("No new notices") return nil } diff --git a/cmd/root.go b/cmd/root.go index 3dfd14ed..f5f5eeca 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -4,13 +4,22 @@ import ( "bufio" "context" "fmt" + "maps" "os" "path/filepath" "regexp" "runtime" "runtime/debug" + "strconv" "strings" + "github.com/nektos/act/pkg/artifactcache" + "github.com/nektos/act/pkg/artifacts" + "github.com/nektos/act/pkg/common" + "github.com/nektos/act/pkg/container" + "github.com/nektos/act/pkg/model" + "github.com/nektos/act/pkg/runner" + "github.com/AlecAivazis/survey/v2" "github.com/adrg/xdg" "github.com/andreaskoch/go-fswatch" @@ -20,13 +29,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "go.yaml.in/yaml/v4" - - "github.com/nektos/act/pkg/artifactcache" - "github.com/nektos/act/pkg/artifacts" - "github.com/nektos/act/pkg/common" - "github.com/nektos/act/pkg/container" - "github.com/nektos/act/pkg/model" - "github.com/nektos/act/pkg/runner" ) // Execute is the entry point to running the CLI @@ -147,7 +149,7 @@ func bugReport(ctx context.Context, version string) error { report := sprintf("act version:", version) report += sprintf("GOOS:", runtime.GOOS) report += sprintf("GOARCH:", runtime.GOARCH) - report += sprintf("NumCPU:", fmt.Sprint(runtime.NumCPU())) + report += sprintf("NumCPU:", strconv.Itoa(runtime.NumCPU())) var dockerHost string var exists bool @@ -216,7 +218,7 @@ func bugReport(ctx context.Context, version string) error { report += sprintf("\tOS version:", info.OSVersion) report += sprintf("\tOS arch:", info.Architecture) 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 += fmt.Sprintln("\tSecurity options:") @@ -305,9 +307,7 @@ func readEnvs(path string, envs map[string]string) bool { if err != nil { log.Fatalf("Error loading from %s: %v", path, err) } - for k, v := range env { - envs[k] = v - } + maps.Copy(envs, env) return true } return false @@ -330,7 +330,7 @@ func parseMatrix(matrix []string) map[string]map[string]bool { return matrixes } -//nolint:gocyclo +//nolint:gocyclo // function handles many cases func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { if input.jsonLogger { @@ -511,7 +511,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str log.Warnf(deprecationWarning, "privileged", "--privileged") } 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 { log.Warnf(deprecationWarning, "container-cap-add", fmt.Sprintf("--cap-add=%s", input.containerCapAdd)) diff --git a/main.go b/main.go index 37b0fece..04d2995a 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,13 @@ package main import ( "context" - _ "embed" "os" "os/signal" "syscall" "github.com/nektos/act/cmd" + + _ "embed" ) //go:embed VERSION diff --git a/pkg/artifactcache/handler.go b/pkg/artifactcache/handler.go index 065c7dda..e9e907c2 100644 --- a/pkg/artifactcache/handler.go +++ b/pkg/artifactcache/handler.go @@ -15,12 +15,12 @@ import ( "sync/atomic" "time" + "github.com/nektos/act/pkg/common" + "github.com/julienschmidt/httprouter" "github.com/sirupsen/logrus" "github.com/timshannon/bolthold" "go.etcd.io/bbolt" - - "github.com/nektos/act/pkg/common" ) const ( @@ -74,7 +74,7 @@ func StartHandler(dir, outboundIP string, port uint16, logger logrus.FieldLogger if outboundIP != "" { h.outboundIP = outboundIP } 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 { h.outboundIP = ip.String() } @@ -363,7 +363,7 @@ func findCache(db *bolthold.Store, keys []string, version string) (*Cache, error } return cache, nil } - prefixPattern := fmt.Sprintf("^%s", regexp.QuoteMeta(prefix)) + prefixPattern := "^" + regexp.QuoteMeta(prefix) re, err := regexp.Compile(prefixPattern) if err != nil { continue @@ -415,6 +415,7 @@ const ( keepOld = 5 * time.Minute ) +//nolint:gocyclo // function handles many cases func (h *Handler) gcCache() { if h.gcing.Load() { return diff --git a/pkg/artifactcache/handler_test.go b/pkg/artifactcache/handler_test.go index 252c4209..f1938d21 100644 --- a/pkg/artifactcache/handler_test.go +++ b/pkg/artifactcache/handler_test.go @@ -64,7 +64,7 @@ func TestHandler(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) 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) { body := []byte(`invalid json`) 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) assert.Equal(t, 400, resp.StatusCode) }) @@ -90,7 +90,7 @@ func TestHandler(t *testing.T) { Size: 100, }) 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) assert.Equal(t, 200, resp.StatusCode) @@ -104,7 +104,7 @@ func TestHandler(t *testing.T) { Size: 100, }) 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) 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) { 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) req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Content-Range", "bytes 0-99/*") @@ -151,7 +151,7 @@ func TestHandler(t *testing.T) { Size: 100, }) 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) assert.Equal(t, 200, resp.StatusCode) @@ -202,7 +202,7 @@ func TestHandler(t *testing.T) { Size: 100, }) 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) 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) { { - 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) assert.Equal(t, 400, resp.StatusCode) } @@ -254,7 +254,7 @@ func TestHandler(t *testing.T) { Size: 100, }) 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) assert.Equal(t, 200, resp.StatusCode) @@ -300,7 +300,7 @@ func TestHandler(t *testing.T) { Size: 100, }) 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) 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) { - resp, err := http.Get(fmt.Sprintf("%s/artifacts/invalid_id", base)) + resp, err := http.Get(base + "/artifacts/invalid_id") require.NoError(t, err) 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)), }) 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) assert.Equal(t, 200, resp.StatusCode) @@ -578,7 +578,7 @@ func uploadCacheNormally(t *testing.T, base, key, version string, content []byte archiveLocation = got.ArchiveLocation } { - resp, err := http.Get(archiveLocation) //nolint:gosec + resp, err := http.Get(archiveLocation) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) got, err := io.ReadAll(resp.Body) diff --git a/pkg/artifactcache/storage.go b/pkg/artifactcache/storage.go index 9a2609af..9ded1e4b 100644 --- a/pkg/artifactcache/storage.go +++ b/pkg/artifactcache/storage.go @@ -6,6 +6,7 @@ import ( "net/http" "os" "path/filepath" + "strconv" ) type Storage struct { @@ -103,11 +104,11 @@ func (s *Storage) Remove(id uint64) { } 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 { - 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 { diff --git a/pkg/artifacts/server.go b/pkg/artifacts/server.go index 4b88ea40..1521fc5a 100644 --- a/pkg/artifacts/server.go +++ b/pkg/artifacts/server.go @@ -13,9 +13,9 @@ import ( "strings" "time" - "github.com/julienschmidt/httprouter" - "github.com/nektos/act/pkg/common" + + "github.com/julienschmidt/httprouter" ) type FileContainerResourceURL struct { @@ -55,8 +55,7 @@ type WriteFS interface { OpenAppendable(name string) (WritableFile, error) } -type readWriteFSImpl struct { -} +type readWriteFSImpl struct{} func (fwfs readWriteFSImpl) Open(name string) (fs.File, error) { return os.Open(name) @@ -74,7 +73,6 @@ func (fwfs readWriteFSImpl) OpenAppendable(name string) (WritableFile, error) { return nil, err } file, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR, 0o644) - if err != nil { return nil, err } @@ -88,7 +86,7 @@ func (fwfs readWriteFSImpl) OpenAppendable(name string) (WritableFile, error) { var gzipExtension = ".gz__" -func safeResolve(baseDir string, relPath string) string { +func safeResolve(baseDir, relPath string) string { return filepath.Join(baseDir, filepath.Clean(filepath.Join(string(os.PathSeparator), relPath))) } @@ -127,7 +125,6 @@ func uploads(router *httprouter.Router, baseDir string, fsys WriteFS) { } return fsys.OpenWritable(safePath) }() - if err != nil { panic(err) } @@ -275,7 +272,7 @@ func downloads(router *httprouter.Router, baseDir string, fsys fs.FS) { }) } -func Serve(ctx context.Context, artifactPath string, addr string, port string) context.CancelFunc { +func Serve(ctx context.Context, artifactPath, addr, port string) context.CancelFunc { serverContext, cancel := context.WithCancel(ctx) logger := common.Logger(serverContext) diff --git a/pkg/artifacts/server_test.go b/pkg/artifacts/server_test.go index aeeb0598..c88a6474 100644 --- a/pkg/artifacts/server_test.go +++ b/pkg/artifacts/server_test.go @@ -13,12 +13,12 @@ import ( "testing" "testing/fstest" + "github.com/nektos/act/pkg/model" + "github.com/nektos/act/pkg/runner" + "github.com/julienschmidt/httprouter" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" - - "github.com/nektos/act/pkg/model" - "github.com/nektos/act/pkg/runner" ) type writableMapFile struct { @@ -39,7 +39,7 @@ type writeMapFS struct { } func (fsys writeMapFS) OpenWritable(name string) (WritableFile, error) { - var file = &writableMapFile{ + file := &writableMapFile{ MapFile: fstest.MapFile{ Data: []byte("content2"), }, @@ -50,7 +50,7 @@ func (fsys writeMapFS) OpenWritable(name string) (WritableFile, error) { } func (fsys writeMapFS) OpenAppendable(name string) (WritableFile, error) { - var file = &writableMapFile{ + file := &writableMapFile{ MapFile: fstest.MapFile{ Data: []byte("content2"), }, @@ -63,12 +63,12 @@ func (fsys writeMapFS) OpenAppendable(name string) (WritableFile, error) { func TestNewArtifactUploadPrepare(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + memfs := fstest.MapFS(map[string]*fstest.MapFile{}) router := httprouter.New() 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() router.ServeHTTP(rr, req) @@ -89,12 +89,12 @@ func TestNewArtifactUploadPrepare(t *testing.T) { func TestArtifactUploadBlob(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + memfs := fstest.MapFS(map[string]*fstest.MapFile{}) router := httprouter.New() 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() router.ServeHTTP(rr, req) @@ -116,12 +116,12 @@ func TestArtifactUploadBlob(t *testing.T) { func TestFinalizeArtifactUpload(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + memfs := fstest.MapFS(map[string]*fstest.MapFile{}) router := httprouter.New() 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() router.ServeHTTP(rr, req) @@ -142,7 +142,7 @@ func TestFinalizeArtifactUpload(t *testing.T) { func TestListArtifacts(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + memfs := fstest.MapFS(map[string]*fstest.MapFile{ "artifact/server/path/1/file.txt": { Data: []byte(""), }, @@ -151,7 +151,7 @@ func TestListArtifacts(t *testing.T) { router := httprouter.New() 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() router.ServeHTTP(rr, req) @@ -174,7 +174,7 @@ func TestListArtifacts(t *testing.T) { func TestListArtifactContainer(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + memfs := fstest.MapFS(map[string]*fstest.MapFile{ "artifact/server/path/1/some/file": { Data: []byte(""), }, @@ -183,7 +183,7 @@ func TestListArtifactContainer(t *testing.T) { router := httprouter.New() 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() router.ServeHTTP(rr, req) @@ -207,7 +207,7 @@ func TestListArtifactContainer(t *testing.T) { func TestDownloadArtifactFile(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + memfs := fstest.MapFS(map[string]*fstest.MapFile{ "artifact/server/path/1/some/file": { Data: []byte("content"), }, @@ -216,7 +216,7 @@ func TestDownloadArtifactFile(t *testing.T) { router := httprouter.New() 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() router.ServeHTTP(rr, req) @@ -344,7 +344,7 @@ func TestMkdirFsImplSafeResolve(t *testing.T) { func TestDownloadArtifactFileUnsafePath(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + memfs := fstest.MapFS(map[string]*fstest.MapFile{ "artifact/server/path/some/file": { Data: []byte("content"), }, @@ -353,7 +353,7 @@ func TestDownloadArtifactFileUnsafePath(t *testing.T) { router := httprouter.New() 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() router.ServeHTTP(rr, req) @@ -370,12 +370,12 @@ func TestDownloadArtifactFileUnsafePath(t *testing.T) { func TestArtifactUploadBlobUnsafePath(t *testing.T) { assert := assert.New(t) - var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + memfs := fstest.MapFS(map[string]*fstest.MapFile{}) router := httprouter.New() 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() router.ServeHTTP(rr, req) diff --git a/pkg/common/cartesian.go b/pkg/common/cartesian.go index 9cd60655..f7467c90 100644 --- a/pkg/common/cartesian.go +++ b/pkg/common/cartesian.go @@ -1,9 +1,9 @@ package common // 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) - lists := make([][]interface{}, 0) + lists := make([][]any, 0) for k, v := range mapOfLists { listNames = append(listNames, k) lists = append(lists, v) @@ -11,9 +11,9 @@ func CartesianProduct(mapOfLists map[string][]interface{}) []map[string]interfac listCart := cartN(lists...) - rtn := make([]map[string]interface{}, 0) + rtn := make([]map[string]any, 0) for _, list := range listCart { - vMap := make(map[string]interface{}) + vMap := make(map[string]any) for i, v := range list { vMap[listNames[i]] = v } @@ -22,7 +22,7 @@ func CartesianProduct(mapOfLists map[string][]interface{}) []map[string]interfac return rtn } -func cartN(a ...[]interface{}) [][]interface{} { +func cartN(a ...[]any) [][]any { c := 1 for _, a := range a { c *= len(a) @@ -30,8 +30,8 @@ func cartN(a ...[]interface{}) [][]interface{} { if c == 0 || len(a) == 0 { return nil } - p := make([][]interface{}, c) - b := make([]interface{}, c*len(a)) + p := make([][]any, c) + b := make([]any, c*len(a)) n := make([]int, len(a)) s := 0 for i := range p { diff --git a/pkg/common/cartesian_test.go b/pkg/common/cartesian_test.go index c49de06c..a7f4c02e 100644 --- a/pkg/common/cartesian_test.go +++ b/pkg/common/cartesian_test.go @@ -8,7 +8,7 @@ import ( func TestCartesianProduct(t *testing.T) { assert := assert.New(t) - input := map[string][]interface{}{ + input := map[string][]any{ "foo": {1, 2, 3, 4}, "bar": {"a", "b", "c"}, "baz": {false, true}, @@ -25,7 +25,7 @@ func TestCartesianProduct(t *testing.T) { assert.Contains(v, "baz") } - input = map[string][]interface{}{ + input = map[string][]any{ "foo": {1, 2, 3, 4}, "bar": {}, "baz": {false, true}, @@ -33,7 +33,7 @@ func TestCartesianProduct(t *testing.T) { output = CartesianProduct(input) assert.Len(output, 0) - input = map[string][]interface{}{} + input = map[string][]any{} output = CartesianProduct(input) assert.Len(output, 0) } diff --git a/pkg/common/draw.go b/pkg/common/draw.go index b5b21fe9..998a539d 100644 --- a/pkg/common/draw.go +++ b/pkg/common/draw.go @@ -72,6 +72,7 @@ func (p *Pen) drawTopBars(buf io.Writer, labels ...string) { } fmt.Fprintf(buf, "\n") } + func (p *Pen) drawBottomBars(buf io.Writer, labels ...string) { style := styleDefs[p.style] for _, label := range labels { @@ -83,6 +84,7 @@ func (p *Pen) drawBottomBars(buf io.Writer, labels ...string) { } fmt.Fprintf(buf, "\n") } + func (p *Pen) drawLabels(buf io.Writer, labels ...string) { style := styleDefs[p.style] for _, label := range labels { @@ -125,11 +127,8 @@ func (p *Pen) DrawBoxes(labels ...string) *Drawing { // Draw to writer func (d *Drawing) Draw(writer io.Writer, centerOnWidth int) { - padSize := (centerOnWidth - d.GetWidth()) / 2 - if padSize < 0 { - padSize = 0 - } - for _, l := range strings.Split(d.buf.String(), "\n") { + padSize := max((centerOnWidth-d.GetWidth())/2, 0) + for l := range strings.SplitSeq(d.buf.String(), "\n") { if len(l) > 0 { padding := strings.Repeat(" ", padSize) fmt.Fprintf(writer, "%s%s\n", padding, l) diff --git a/pkg/common/executor.go b/pkg/common/executor.go index 38595c3d..72a8cf31 100644 --- a/pkg/common/executor.go +++ b/pkg/common/executor.go @@ -19,7 +19,7 @@ func (w Warning) Error() string { } // Warningf create a warning -func Warningf(format string, args ...interface{}) Warning { +func Warningf(format string, args ...any) Warning { w := Warning{ Message: fmt.Sprintf(format, args...), } @@ -33,7 +33,7 @@ type Executor func(ctx context.Context) error type Conditional func(ctx context.Context) bool // 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 { logger := Logger(ctx) logger.Infof(format, args...) @@ -42,7 +42,7 @@ func NewInfoExecutor(format string, args ...interface{}) Executor { } // 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 { logger := Logger(ctx) logger.Debugf(format, args...) @@ -69,7 +69,7 @@ func NewPipelineExecutor(executors ...Executor) Executor { } // NewConditionalExecutor creates a new executor based on conditions -func NewConditionalExecutor(conditional Conditional, trueExecutor Executor, falseExecutor Executor) Executor { +func NewConditionalExecutor(conditional Conditional, trueExecutor, falseExecutor Executor) Executor { return func(ctx context.Context) error { if conditional(ctx) { if trueExecutor != nil { @@ -128,14 +128,14 @@ func NewParallelExecutor(parallel int, executors ...Executor) Executor { }(i, work, errs) } - for i := 0; i < len(executors); i++ { + for i := range executors { work <- executors[i] } close(work) // Executor waits all executors to cleanup these resources. var firstErr error - for i := 0; i < len(executors); i++ { + for range executors { err := <-errs if firstErr == nil { firstErr = err diff --git a/pkg/common/executor_max_parallel_test.go b/pkg/common/executor_max_parallel_test.go index 4ec128eb..8c432023 100644 --- a/pkg/common/executor_max_parallel_test.go +++ b/pkg/common/executor_max_parallel_test.go @@ -14,24 +14,24 @@ import ( func TestMaxParallel2Quick(t *testing.T) { ctx := context.Background() - var currentRunning int32 - var maxSimultaneous int32 + var currentRunning atomic.Int32 + var maxSimultaneous atomic.Int32 executors := make([]Executor, 4) - for i := 0; i < 4; i++ { + for i := range 4 { executors[i] = func(ctx context.Context) error { - current := atomic.AddInt32(¤tRunning, 1) + current := currentRunning.Add(1) // Update max if needed for { - maxValue := atomic.LoadInt32(&maxSimultaneous) - if current <= maxValue || atomic.CompareAndSwapInt32(&maxSimultaneous, maxValue, current) { + maxValue := maxSimultaneous.Load() + if current <= maxValue || maxSimultaneous.CompareAndSwap(maxValue, current) { break } } time.Sleep(10 * time.Millisecond) - atomic.AddInt32(¤tRunning, -1) + currentRunning.Add(-1) return nil } } @@ -39,7 +39,7 @@ func TestMaxParallel2Quick(t *testing.T) { err := NewParallelExecutor(2, executors...)(ctx) assert.NoError(t, err) - assert.LessOrEqual(t, atomic.LoadInt32(&maxSimultaneous), int32(2), + assert.LessOrEqual(t, maxSimultaneous.Load(), int32(2), "Should not exceed max-parallel: 2") } @@ -47,16 +47,16 @@ func TestMaxParallel2Quick(t *testing.T) { func TestMaxParallel1Sequential(t *testing.T) { ctx := context.Background() - var currentRunning int32 - var maxSimultaneous int32 + var currentRunning atomic.Int32 + var maxSimultaneous atomic.Int32 var executionOrder []int var orderMutex sync.Mutex executors := make([]Executor, 5) - for i := 0; i < 5; i++ { + for i := range 5 { taskID := i executors[i] = func(ctx context.Context) error { - current := atomic.AddInt32(¤tRunning, 1) + current := currentRunning.Add(1) // Track execution order orderMutex.Lock() @@ -65,14 +65,14 @@ func TestMaxParallel1Sequential(t *testing.T) { // Update max if needed for { - maxValue := atomic.LoadInt32(&maxSimultaneous) - if current <= maxValue || atomic.CompareAndSwapInt32(&maxSimultaneous, maxValue, current) { + maxValue := maxSimultaneous.Load() + if current <= maxValue || maxSimultaneous.CompareAndSwap(maxValue, current) { break } } time.Sleep(20 * time.Millisecond) - atomic.AddInt32(¤tRunning, -1) + currentRunning.Add(-1) return nil } } @@ -80,7 +80,7 @@ func TestMaxParallel1Sequential(t *testing.T) { err := NewParallelExecutor(1, executors...)(ctx) assert.NoError(t, err) - assert.Equal(t, int32(1), atomic.LoadInt32(&maxSimultaneous), + assert.Equal(t, int32(1), maxSimultaneous.Load(), "max-parallel: 1 should only run 1 task at a time") assert.Len(t, executionOrder, 5, "All 5 tasks should have executed") } diff --git a/pkg/common/executor_parallel_advanced_test.go b/pkg/common/executor_parallel_advanced_test.go index b0af1ff3..c3857621 100644 --- a/pkg/common/executor_parallel_advanced_test.go +++ b/pkg/common/executor_parallel_advanced_test.go @@ -13,21 +13,21 @@ import ( // TestMaxParallelJobExecution tests actual job execution with max-parallel func TestMaxParallelJobExecution(t *testing.T) { t.Run("MaxParallel=1 Sequential", func(t *testing.T) { - var currentRunning int32 + var currentRunning atomic.Int32 var maxConcurrent int32 var executionOrder []int var mu sync.Mutex executors := make([]Executor, 5) - for i := 0; i < 5; i++ { + for i := range 5 { taskID := i executors[i] = func(ctx context.Context) error { - current := atomic.AddInt32(¤tRunning, 1) + current := currentRunning.Add(1) // Track max concurrent for { - max := atomic.LoadInt32(&maxConcurrent) - if current <= max || atomic.CompareAndSwapInt32(&maxConcurrent, max, current) { + maxValue := atomic.LoadInt32(&maxConcurrent) + if current <= maxValue || atomic.CompareAndSwapInt32(&maxConcurrent, maxValue, current) { break } } @@ -37,7 +37,7 @@ func TestMaxParallelJobExecution(t *testing.T) { mu.Unlock() time.Sleep(10 * time.Millisecond) - atomic.AddInt32(¤tRunning, -1) + currentRunning.Add(-1) return nil } } @@ -51,23 +51,23 @@ func TestMaxParallelJobExecution(t *testing.T) { }) t.Run("MaxParallel=3 Limited", func(t *testing.T) { - var currentRunning int32 + var currentRunning atomic.Int32 var maxConcurrent int32 executors := make([]Executor, 10) - for i := 0; i < 10; i++ { + for i := range 10 { executors[i] = func(ctx context.Context) error { - current := atomic.AddInt32(¤tRunning, 1) + current := currentRunning.Add(1) for { - max := atomic.LoadInt32(&maxConcurrent) - if current <= max || atomic.CompareAndSwapInt32(&maxConcurrent, max, current) { + maxValue := atomic.LoadInt32(&maxConcurrent) + if current <= maxValue || atomic.CompareAndSwapInt32(&maxConcurrent, maxValue, current) { break } } time.Sleep(20 * time.Millisecond) - atomic.AddInt32(¤tRunning, -1) + currentRunning.Add(-1) return nil } } @@ -82,22 +82,22 @@ func TestMaxParallelJobExecution(t *testing.T) { t.Run("MaxParallel=0 Uses1Worker", func(t *testing.T) { var maxConcurrent int32 - var currentRunning int32 + var currentRunning atomic.Int32 executors := make([]Executor, 5) - for i := 0; i < 5; i++ { + for i := range 5 { executors[i] = func(ctx context.Context) error { - current := atomic.AddInt32(¤tRunning, 1) + current := currentRunning.Add(1) for { - max := atomic.LoadInt32(&maxConcurrent) - if current <= max || atomic.CompareAndSwapInt32(&maxConcurrent, max, current) { + maxValue := atomic.LoadInt32(&maxConcurrent) + if current <= maxValue || atomic.CompareAndSwapInt32(&maxConcurrent, maxValue, current) { break } } time.Sleep(10 * time.Millisecond) - atomic.AddInt32(¤tRunning, -1) + currentRunning.Add(-1) return nil } } @@ -117,7 +117,7 @@ func TestMaxParallelWithErrors(t *testing.T) { var successCount int32 executors := make([]Executor, 5) - for i := 0; i < 5; i++ { + for i := range 5 { taskID := i executors[i] = func(ctx context.Context) error { if taskID == 2 { @@ -143,7 +143,7 @@ func TestMaxParallelWithErrors(t *testing.T) { var startedCount int32 executors := make([]Executor, 10) - for i := 0; i < 10; i++ { + for i := range 10 { executors[i] = func(ctx context.Context) error { atomic.AddInt32(&startedCount, 1) time.Sleep(100 * time.Millisecond) @@ -175,7 +175,7 @@ func TestMaxParallelPerformance(t *testing.T) { t.Run("ParallelFasterThanSequential", func(t *testing.T) { executors := make([]Executor, 10) - for i := 0; i < 10; i++ { + for i := range 10 { executors[i] = func(ctx context.Context) error { time.Sleep(50 * time.Millisecond) return nil @@ -203,7 +203,7 @@ func TestMaxParallelPerformance(t *testing.T) { t.Run("OptimalWorkerCount", func(t *testing.T) { executors := make([]Executor, 20) - for i := 0; i < 20; i++ { + for i := range 20 { executors[i] = func(ctx context.Context) error { time.Sleep(10 * time.Millisecond) return nil @@ -236,7 +236,7 @@ func TestMaxParallelResourceSharing(t *testing.T) { var mu sync.Mutex executors := make([]Executor, 100) - for i := 0; i < 100; i++ { + for i := range 100 { executors[i] = func(ctx context.Context) error { mu.Lock() sharedCounter++ @@ -256,7 +256,7 @@ func TestMaxParallelResourceSharing(t *testing.T) { resultChan := make(chan int, 50) executors := make([]Executor, 50) - for i := 0; i < 50; i++ { + for i := range 50 { taskID := i executors[i] = func(ctx context.Context) error { resultChan <- taskID diff --git a/pkg/common/executor_test.go b/pkg/common/executor_test.go index e70c638e..18110eef 100644 --- a/pkg/common/executor_test.go +++ b/pkg/common/executor_test.go @@ -2,7 +2,7 @@ package common import ( "context" - "fmt" + "errors" "testing" "time" @@ -19,7 +19,7 @@ func TestNewWorkflow(t *testing.T) { assert.Nil(emptyWorkflow(ctx)) // error case - errorWorkflow := NewErrorExecutor(fmt.Errorf("test error")) + errorWorkflow := NewErrorExecutor(errors.New("test error")) assert.NotNil(errorWorkflow(ctx)) // multiple success case @@ -122,7 +122,7 @@ func TestNewParallelExecutorFailed(t *testing.T) { count := 0 errorWorkflow := NewPipelineExecutor(func(ctx context.Context) error { count++ - return fmt.Errorf("fake error") + return errors.New("fake error") }) err := NewParallelExecutor(1, errorWorkflow)(ctx) assert.Equal(1, count) @@ -135,7 +135,7 @@ func TestNewParallelExecutorCanceled(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() - errExpected := fmt.Errorf("fake error") + errExpected := errors.New("fake error") count := 0 successWorkflow := NewPipelineExecutor(func(ctx context.Context) error { diff --git a/pkg/common/file.go b/pkg/common/file.go index 09c21029..243c07e4 100644 --- a/pkg/common/file.go +++ b/pkg/common/file.go @@ -7,7 +7,7 @@ import ( ) // CopyFile copy file -func CopyFile(source string, dest string) (err error) { +func CopyFile(source, dest string) (err error) { sourcefile, err := os.Open(source) if err != nil { return err @@ -30,11 +30,11 @@ func CopyFile(source string, dest string) (err error) { } } - return + return err } // CopyDir recursive copy of directory -func CopyDir(source string, dest string) (err error) { +func CopyDir(source, dest string) (err error) { // get properties of source dir sourceinfo, err := os.Stat(source) if err != nil { diff --git a/pkg/common/git/git.go b/pkg/common/git/git.go index c7ee8897..13681d86 100644 --- a/pkg/common/git/git.go +++ b/pkg/common/git/git.go @@ -11,6 +11,8 @@ import ( "strings" "sync" + "github.com/nektos/act/pkg/common" + "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" @@ -18,8 +20,6 @@ import ( "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/mattn/go-isatty" log "github.com/sirupsen/logrus" - - "github.com/nektos/act/pkg/common" ) var ( @@ -52,7 +52,7 @@ func (e *Error) Commit() string { } // FindGitRevision get the current git revision -func FindGitRevision(ctx context.Context, file string) (shortSha string, sha string, err error) { +func FindGitRevision(ctx context.Context, file string) (shortSha, sha string, err error) { logger := common.Logger(ctx) gitDir, err := git.PlainOpenWithOptions( @@ -62,7 +62,6 @@ func FindGitRevision(ctx context.Context, file string) (shortSha string, sha str EnableDotGitCommonDir: true, }, ) - if err != nil { logger.WithError(err).Error("path", file, "not located inside a git repository") return "", "", err @@ -74,7 +73,7 @@ func FindGitRevision(ctx context.Context, file string) (shortSha string, sha str } 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() @@ -96,8 +95,8 @@ func FindGitRef(ctx context.Context, file string) (string, error) { logger.Debugf("HEAD points to '%s'", ref) // Prefer the git library to iterate over the references and find a matching tag or branch. - var refTag = "" - var refBranch = "" + refTag := "" + refBranch := "" repo, err := git.PlainOpenWithOptions( file, &git.PlainOpenOptions{ @@ -105,7 +104,6 @@ func FindGitRef(ctx context.Context, file string) (string, error) { EnableDotGitCommonDir: true, }, ) - if err != nil { return "", err } @@ -144,7 +142,6 @@ func FindGitRef(ctx context.Context, file string) (string, error) { return nil }) - if err != nil { return "", err } @@ -198,7 +195,7 @@ func findGitRemoteURL(_ context.Context, file, remoteName string) (string, error return remote.Config().URLs[0], nil } -func findGitSlug(url string, githubInstance string) (string, string, error) { +func findGitSlug(url, githubInstance string) (string, string, error) { if matches := codeCommitHTTPRegex.FindStringSubmatch(url); matches != nil { return "CodeCommit", matches[2], nil } else if matches := codeCommitSSHRegex.FindStringSubmatch(url); matches != nil { @@ -209,7 +206,7 @@ func findGitSlug(url string, githubInstance string) (string, string, error) { return "GitHub", fmt.Sprintf("%s/%s", matches[1], matches[2]), nil } else if githubInstance != "github.com" { gheHTTPRegex := regexp.MustCompile(fmt.Sprintf(`^https?://%s/(.+)/(.+?)(?:.git)?$`, githubInstance)) - gheSSHRegex := regexp.MustCompile(fmt.Sprintf(`%s[:/](.+)/(.+?)(?:.git)?$`, githubInstance)) + gheSSHRegex := regexp.MustCompile(githubInstance + "[:/](.+)/(.+?)(?:.git)?$") if matches := gheHTTPRegex.FindStringSubmatch(url); matches != nil { return "GitHubEnterprise", fmt.Sprintf("%s/%s", matches[1], matches[2]), nil } else if matches := gheSSHRegex.FindStringSubmatch(url); matches != nil { @@ -292,7 +289,7 @@ func gitOptions(token string) (fetchOptions git.FetchOptions, pullOptions git.Pu // NewGitCloneExecutor creates an executor to clone git repos // -//nolint:gocyclo +//nolint:gocyclo // function handles many cases func NewGitCloneExecutor(input NewGitCloneExecutorInput) common.Executor { return func(ctx context.Context) error { logger := common.Logger(ctx) @@ -302,7 +299,7 @@ func NewGitCloneExecutor(input NewGitCloneExecutorInput) common.Executor { cloneLock.Lock() 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) if err != nil { return err diff --git a/pkg/common/git/git_test.go b/pkg/common/git/git_test.go index 6ad66b67..5286740b 100644 --- a/pkg/common/git/git_test.go +++ b/pkg/common/git/git_test.go @@ -17,7 +17,7 @@ import ( func TestFindGitSlug(t *testing.T) { assert := assert.New(t) - var slugTests = []struct { + slugTests := []struct { url string // input provider string // expected result slug string // expected result @@ -44,10 +44,7 @@ func TestFindGitSlug(t *testing.T) { } func testDir(t *testing.T) string { - basedir, err := os.MkdirTemp("", "act-test") - require.NoError(t, err) - t.Cleanup(func() { _ = os.RemoveAll(basedir) }) - return basedir + return t.TempDir() } func cleanGitHooks(dir string) error { @@ -163,8 +160,6 @@ func TestGitFindRef(t *testing.T) { }, }, } { - tt := tt - name := name t.Run(name, func(t *testing.T) { dir := filepath.Join(basedir, name) require.NoError(t, os.MkdirAll(dir, 0o755)) diff --git a/pkg/container/container_types.go b/pkg/container/container_types.go index c2be04df..5cc09aa7 100644 --- a/pkg/container/container_types.go +++ b/pkg/container/container_types.go @@ -4,8 +4,9 @@ import ( "context" "io" - "github.com/docker/go-connections/nat" "github.com/nektos/act/pkg/common" + + "github.com/docker/go-connections/nat" ) // NewContainerInput the input for the New function @@ -45,11 +46,11 @@ type FileEntry struct { // Container for managing docker run containers type Container interface { - Create(capAdd []string, capDrop []string) common.Executor + Create(capAdd, capDrop []string) common.Executor ConnectToNetwork(name string) common.Executor Copy(destPath string, files ...*FileEntry) common.Executor CopyTarStream(ctx context.Context, destPath string, tarStream io.Reader) error - CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor + CopyDir(destPath, srcPath string, useGitIgnore bool) common.Executor GetContainerArchive(ctx context.Context, srcPath string) (io.ReadCloser, error) Pull(forcePull bool) common.Executor Start(attach bool) common.Executor diff --git a/pkg/container/docker_auth.go b/pkg/container/docker_auth.go index e8dfb7d5..d7bc6b24 100644 --- a/pkg/container/docker_auth.go +++ b/pkg/container/docker_auth.go @@ -6,10 +6,11 @@ import ( "context" "strings" + "github.com/nektos/act/pkg/common" + "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config/credentials" "github.com/docker/docker/api/types/registry" - "github.com/nektos/act/pkg/common" ) func LoadDockerAuthConfig(ctx context.Context, image string) (registry.AuthConfig, error) { diff --git a/pkg/container/docker_build.go b/pkg/container/docker_build.go index 5f56ec70..2f3a9805 100644 --- a/pkg/container/docker_build.go +++ b/pkg/container/docker_build.go @@ -8,14 +8,13 @@ import ( "os" "path/filepath" + "github.com/nektos/act/pkg/common" + "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/archive" - // github.com/docker/docker/builder/dockerignore is deprecated "github.com/moby/buildkit/frontend/dockerfile/dockerignore" "github.com/moby/patternmatcher" - - "github.com/nektos/act/pkg/common" ) // NewDockerBuildExecutor function to create a run executor for the container @@ -69,7 +68,8 @@ func NewDockerBuildExecutor(input NewDockerBuildExecutorInput) common.Executor { return nil } } -func createBuildContext(ctx context.Context, contextDir string, relDockerfile string) (io.ReadCloser, error) { + +func createBuildContext(ctx context.Context, contextDir, relDockerfile string) (io.ReadCloser, error) { common.Logger(ctx).Debugf("Creating archive for build context dir '%s' with relative dockerfile '%s'", contextDir, relDockerfile) // And canonicalize dockerfile name to a platform-independent one @@ -96,7 +96,7 @@ func createBuildContext(ctx context.Context, contextDir string, relDockerfile st // removed. The daemon will remove them for us, if needed, after it // parses the Dockerfile. Ignore errors here, as they will have been // caught by validateContextDirectory above. - var includes = []string{"."} + includes := []string{"."} keepThem1, _ := patternmatcher.Matches(".dockerignore", excludes) keepThem2, _ := patternmatcher.Matches(relDockerfile, excludes) if keepThem1 || keepThem2 { diff --git a/pkg/container/docker_cli.go b/pkg/container/docker_cli.go index 82d32466..20f42d07 100644 --- a/pkg/container/docker_cli.go +++ b/pkg/container/docker_cli.go @@ -7,7 +7,7 @@ // See DOCKER_LICENSE for the full license text. // -//nolint:unparam,errcheck,depguard,deadcode,unused +//nolint:unparam,errcheck,depguard,unused // verbatim copy from docker/cli with minimal changes package container import ( @@ -19,6 +19,7 @@ import ( "path/filepath" "reflect" "regexp" + "slices" "strconv" "strings" "time" @@ -37,9 +38,7 @@ import ( "github.com/spf13/pflag" ) -var ( - deviceCgroupRuleRegexp = regexp.MustCompile(`^[acb] ([0-9]+|\*):([0-9]+|\*) [rwm]{1,3}$`) -) +var deviceCgroupRuleRegexp = regexp.MustCompile(`^[acb] ([0-9]+|\*):([0-9]+|\*) [rwm]{1,3}$`) // containerOptions is a data object with all the options for creating a container type containerOptions struct { @@ -322,7 +321,7 @@ type containerConfig struct { // a HostConfig and returns them with the specified command. // If the specified args are not valid, it will return an error. // -//nolint:gocyclo +//nolint:gocyclo // function handles many cases func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*containerConfig, error) { var ( attachStdin = copts.attach.Get("stdin") @@ -559,7 +558,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con return nil, errors.Errorf("--health-retries cannot be negative") } 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{ @@ -722,7 +721,6 @@ func parseNetworkOpts(copts *containerOptions) (map[string]*networktypes.Endpoin ) for i, n := range copts.netMode.Value() { - n := n if container.NetworkMode(n.Target).IsUserDefined() { hasUserDefined = true } else { @@ -837,7 +835,7 @@ func convertToStandardNotation(ports []string) ([]string, error) { for _, publish := range ports { if strings.Contains(publish, "=") { params := map[string]string{"protocol": "tcp"} - for _, param := range strings.Split(publish, ",") { + for param := range strings.SplitSeq(publish, ",") { opt := strings.Split(param, "=") if len(opt) < 2 { return optsList, errors.Errorf("invalid publish opts format (should be name=value but got '%s')", param) @@ -988,7 +986,7 @@ func validateDeviceCgroupRule(val string) (string, error) { // validDeviceMode checks if the mode for device is valid or not. // Valid mode is a composition of r (read), w (write), and m (mknod). func validDeviceMode(mode string) bool { - var legalDeviceMode = map[rune]bool{ + legalDeviceMode := map[rune]bool{ 'r': true, 'w': true, 'm': true, @@ -1006,7 +1004,7 @@ func validDeviceMode(mode string) bool { } // validateDevice validates a path for devices -func validateDevice(val string, serverOS string) (string, error) { +func validateDevice(val, serverOS string) (string, error) { switch serverOS { case "linux": return validateLinuxPath(val, validDeviceMode) @@ -1067,10 +1065,8 @@ func validateLinuxPath(val string, validator func(string) bool) (string, error) // validateAttach validates that the specified string is a valid attach option. func validateAttach(val string) (string, error) { s := strings.ToLower(val) - for _, str := range []string{"stdin", "stdout", "stderr"} { - if s == str { - return s, nil - } + if slices.Contains([]string{"stdin", "stdout", "stderr"}, s) { + return s, nil } return val, errors.Errorf("valid streams are STDIN, STDOUT and STDERR") } diff --git a/pkg/container/docker_cli_test.go b/pkg/container/docker_cli_test.go index a6445be6..3c7551a3 100644 --- a/pkg/container/docker_cli_test.go +++ b/pkg/container/docker_cli_test.go @@ -6,7 +6,7 @@ // See DOCKER_LICENSE for the full license text. // -//nolint:unparam,whitespace,depguard,dupl,gocritic +//nolint:unparam,depguard,gocritic // verbatim copy from docker/cli tests package container import ( @@ -135,7 +135,6 @@ func TestParseRunAttach(t *testing.T) { }, } for _, tc := range tests { - tc := tc t.Run(tc.input, func(t *testing.T) { config, _ := mustParse(t, tc.input) assert.Equal(t, config.AttachStdin, tc.expected.AttachStdin) @@ -191,9 +190,8 @@ func TestParseRunWithInvalidArgs(t *testing.T) { } } -//nolint:gocyclo +//nolint:gocyclo // function handles many cases func TestParseWithVolumes(t *testing.T) { - // A single volume arr, tryit := setupPlatformVolume([]string{`/tmp`}, []string{`c:\tmp`}) if config, hostConfig := mustParse(t, tryit); hostConfig.Binds != nil { @@ -261,14 +259,13 @@ func TestParseWithVolumes(t *testing.T) { t.Fatalf("Error parsing %s. Should have a single bind mount and no volumes", arr[0]) } } - } // setupPlatformVolume takes two arrays of volume specs - a Unix style // spec and a Windows style spec. Depending on the platform being unit tested, // it returns one of them, along with a volume string that would be passed // on the docker CLI (e.g. -v /bar -v /foo). -func setupPlatformVolume(u []string, w []string) ([]string, string) { +func setupPlatformVolume(u, w []string) ([]string, string) { var a []string if runtime.GOOS == "windows" { a = w @@ -340,7 +337,7 @@ func TestParseHostname(t *testing.T) { hostnameWithDomain := "--hostname=hostname.domainname" hostnameWithDomainTld := "--hostname=hostname.domainname.tld" 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) } } @@ -462,7 +459,6 @@ func TestParseDevice(t *testing.T) { t.Fatalf("Expected %v, got %v", deviceMapping, hostconfig.Devices) } } - } func TestParseNetworkConfig(t *testing.T) { @@ -634,7 +630,7 @@ func TestParseModes(t *testing.T) { } // uts ko - _, _, _, err = parseRun([]string{"--uts=container:", "img", "cmd"}) //nolint:dogsled + _, _, _, err = parseRun([]string{"--uts=container:", "img", "cmd"}) //nolint:dogsled // ignoring multiple returns in test helpers assert.ErrorContains(t, err, "--uts: invalid UTS mode") // uts ok @@ -678,7 +674,7 @@ func TestParseRestartPolicy(t *testing.T) { }, } 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) } } @@ -695,7 +691,7 @@ func TestParseRestartPolicy(t *testing.T) { func TestParseRestartPolicyAutoRemove(t *testing.T) { expected := "Conflicting options: --restart and --rm" - _, _, _, err := parseRun([]string{"--rm", "--restart=always", "img", "cmd"}) //nolint:dogsled + _, _, _, err := parseRun([]string{"--rm", "--restart=always", "img", "cmd"}) //nolint:dogsled // ignoring multiple returns in test helpers if err == nil || err.Error() != expected { t.Fatalf("Expected error %v, but got none", expected) } @@ -967,7 +963,6 @@ func TestConvertToStandardNotation(t *testing.T) { for key, ports := range valid { convertedPorts, err := convertToStandardNotation(ports) - if err != nil { assert.NilError(t, err) } diff --git a/pkg/container/docker_images.go b/pkg/container/docker_images.go index 50ec68da..5fb3f6fc 100644 --- a/pkg/container/docker_images.go +++ b/pkg/container/docker_images.go @@ -12,7 +12,7 @@ import ( // ImageExistsLocally returns a boolean indicating if an image with the // requested name, tag and architecture exists in the local docker image store -func ImageExistsLocally(ctx context.Context, imageName string, platform string) (bool, error) { +func ImageExistsLocally(ctx context.Context, imageName, platform string) (bool, error) { cli, err := GetDockerClient(ctx) if err != nil { return false, err @@ -35,7 +35,7 @@ func ImageExistsLocally(ctx context.Context, imageName string, platform string) // RemoveImage removes image from local store, the function is used to run different // container image architectures -func RemoveImage(ctx context.Context, imageName string, force bool, pruneChildren bool) (bool, error) { +func RemoveImage(ctx context.Context, imageName string, force, pruneChildren bool) (bool, error) { cli, err := GetDockerClient(ctx) if err != nil { return false, err diff --git a/pkg/container/docker_logger.go b/pkg/container/docker_logger.go index b9eb503e..549d8898 100644 --- a/pkg/container/docker_logger.go +++ b/pkg/container/docker_logger.go @@ -74,7 +74,7 @@ func logDockerResponse(logger logrus.FieldLogger, dockerResponse io.ReadCloser, 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 { logger.Errorf(format, args...) } else { diff --git a/pkg/container/docker_network.go b/pkg/container/docker_network.go index 01df41d9..3b982959 100644 --- a/pkg/container/docker_network.go +++ b/pkg/container/docker_network.go @@ -5,9 +5,9 @@ package container import ( "context" - "github.com/docker/docker/api/types" - "github.com/nektos/act/pkg/common" + + "github.com/docker/docker/api/types" ) func NewDockerNetworkCreateExecutor(name string) common.Executor { diff --git a/pkg/container/docker_pull.go b/pkg/container/docker_pull.go index 7c94c104..b4cded6e 100644 --- a/pkg/container/docker_pull.go +++ b/pkg/container/docker_pull.go @@ -9,11 +9,11 @@ import ( "fmt" "strings" - "github.com/docker/distribution/reference" + "github.com/nektos/act/pkg/common" + + "github.com/distribution/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/registry" - - "github.com/nektos/act/pkg/common" ) // NewDockerPullExecutor function to create a run executor for the container diff --git a/pkg/container/docker_pull_test.go b/pkg/container/docker_pull_test.go index bfbe89dd..cd26002f 100644 --- a/pkg/container/docker_pull_test.go +++ b/pkg/container/docker_pull_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/docker/cli/cli/config" - log "github.com/sirupsen/logrus" assert "github.com/stretchr/testify/assert" ) diff --git a/pkg/container/docker_run.go b/pkg/container/docker_run.go index 51bde0f1..cb379b7e 100644 --- a/pkg/container/docker_run.go +++ b/pkg/container/docker_run.go @@ -16,6 +16,9 @@ import ( "strconv" "strings" + "github.com/nektos/act/pkg/common" + "github.com/nektos/act/pkg/filecollector" + "github.com/Masterminds/semver" "github.com/docker/cli/cli/compose/loader" "github.com/docker/cli/cli/connhelper" @@ -23,7 +26,6 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" - networktypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/go-git/go-billy/v5/helper/polyfill" @@ -36,9 +38,6 @@ import ( specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/pflag" "golang.org/x/term" - - "github.com/nektos/act/pkg/common" - "github.com/nektos/act/pkg/filecollector" ) // NewContainer creates a reference to a container @@ -61,7 +60,7 @@ func (cr *containerReference) ConnectToNetwork(name string) common.Executor { func (cr *containerReference) connectToNetwork(name string, aliases []string) common.Executor { return func(ctx context.Context) error { - return cr.cli.NetworkConnect(ctx, name, cr.input.Name, &networktypes.EndpointSettings{ + return cr.cli.NetworkConnect(ctx, name, cr.input.Name, &network.EndpointSettings{ Aliases: aliases, }) } @@ -85,7 +84,7 @@ func supportsContainerImagePlatform(ctx context.Context, cli client.APIClient) b return constraint.Check(sv) } -func (cr *containerReference) Create(capAdd []string, capDrop []string) common.Executor { +func (cr *containerReference) Create(capAdd, capDrop []string) common.Executor { return common. NewInfoExecutor("%sdocker create image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode). Then( @@ -142,7 +141,7 @@ func (cr *containerReference) Copy(destPath string, files ...*FileEntry) common. ).IfNot(common.Dryrun) } -func (cr *containerReference) CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor { +func (cr *containerReference) CopyDir(destPath, srcPath string, useGitIgnore bool) common.Executor { return common.NewPipelineExecutor( common.NewInfoExecutor("%sdocker cp src=%s dst=%s", logPrefix, srcPath, destPath), cr.copyDir(destPath, srcPath, useGitIgnore), @@ -158,7 +157,7 @@ func (cr *containerReference) CopyDir(destPath string, srcPath string, useGitIgn func (cr *containerReference) GetContainerArchive(ctx context.Context, srcPath string) (io.ReadCloser, error) { 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) return a, err @@ -190,7 +189,7 @@ func (cr *containerReference) Remove() common.Executor { ).IfNot(common.Dryrun) } -func (cr *containerReference) ReplaceLogWriter(stdout io.Writer, stderr io.Writer) (io.Writer, io.Writer) { +func (cr *containerReference) ReplaceLogWriter(stdout, stderr io.Writer) (io.Writer, io.Writer) { out := cr.input.Stdout err := cr.input.Stderr @@ -429,7 +428,7 @@ func (cr *containerReference) mergeContainerConfigs(ctx context.Context, config return config, hostConfig, nil } -func (cr *containerReference) create(capAdd []string, capDrop []string) common.Executor { +func (cr *containerReference) create(capAdd, capDrop []string) common.Executor { return func(ctx context.Context) error { if cr.id != "" { return nil @@ -682,7 +681,7 @@ func (cr *containerReference) tryReadGID() common.Executor { return cr.tryReadID("-g", func(id int) { cr.GID = id }) } -func (cr *containerReference) waitForCommand(ctx context.Context, isTerminal bool, resp types.HijackedResponse, _ types.IDResponse, _ string, _ string) error { +func (cr *containerReference) waitForCommand(ctx context.Context, isTerminal bool, resp types.HijackedResponse, _ types.IDResponse, _, _ string) error { logger := common.Logger(ctx) cmdResponse := make(chan error) @@ -753,7 +752,7 @@ func (cr *containerReference) CopyTarStream(ctx context.Context, destPath string return nil } -func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgnore bool) common.Executor { +func (cr *containerReference) copyDir(dstPath, srcPath string, useGitIgnore bool) common.Executor { return func(ctx context.Context) error { logger := common.Logger(ctx) tarFile, err := os.CreateTemp("", "act") diff --git a/pkg/container/docker_run_test.go b/pkg/container/docker_run_test.go index 3aa542bb..02fc9f7f 100644 --- a/pkg/container/docker_run_test.go +++ b/pkg/container/docker_run_test.go @@ -4,7 +4,7 @@ import ( "bufio" "bytes" "context" - "fmt" + "errors" "io" "net" "strings" @@ -81,7 +81,7 @@ func (m *mockDockerClient) ContainerExecInspect(ctx context.Context, execID stri return args.Get(0).(types.ContainerExecInspect), args.Error(1) } -func (m *mockDockerClient) CopyToContainer(ctx context.Context, id string, path string, content io.Reader, options types.CopyToContainerOptions) error { +func (m *mockDockerClient) CopyToContainer(ctx context.Context, id, path string, content io.Reader, options types.CopyToContainerOptions) error { args := m.Called(ctx, id, path, content, options) return args.Error(0) } @@ -203,7 +203,7 @@ func TestDockerCopyTarStreamErrorInCopyFiles(t *testing.T) { conn := &mockConn{} - merr := fmt.Errorf("Failure") + merr := errors.New("Failure") client := &mockDockerClient{} client.On("CopyToContainer", ctx, "123", "/", mock.Anything, mock.AnythingOfType("types.CopyToContainerOptions")).Return(merr) @@ -228,7 +228,7 @@ func TestDockerCopyTarStreamErrorInMkdir(t *testing.T) { conn := &mockConn{} - merr := fmt.Errorf("Failure") + merr := errors.New("Failure") client := &mockDockerClient{} client.On("CopyToContainer", ctx, "123", "/", mock.Anything, mock.AnythingOfType("types.CopyToContainerOptions")).Return(nil) diff --git a/pkg/container/docker_socket.go b/pkg/container/docker_socket.go index 8b3ed024..273e285f 100644 --- a/pkg/container/docker_socket.go +++ b/pkg/container/docker_socket.go @@ -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 // is not found in the `daemonPath`, the function returns false. func isDockerHostURI(daemonPath string) bool { - if protoIndex := strings.Index(daemonPath, "://"); protoIndex != -1 { - scheme := daemonPath[:protoIndex] + if before, _, ok := strings.Cut(daemonPath, "://"); ok { + scheme := before if strings.IndexFunc(scheme, func(r rune) bool { return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') }) == -1 { diff --git a/pkg/container/docker_socket_test.go b/pkg/container/docker_socket_test.go index 0915a937..63ee92b1 100644 --- a/pkg/container/docker_socket_test.go +++ b/pkg/container/docker_socket_test.go @@ -19,7 +19,7 @@ func TestGetSocketAndHostWithSocket(t *testing.T) { CommonSocketLocations = originalCommonSocketLocations dockerHost := "unix:///my/docker/host.sock" socketURI := "/path/to/my.socket" - os.Setenv("DOCKER_HOST", dockerHost) + t.Setenv("DOCKER_HOST", dockerHost) // Act ret, err := GetSocketAndHost(socketURI) @@ -32,7 +32,7 @@ func TestGetSocketAndHostWithSocket(t *testing.T) { func TestGetSocketAndHostNoSocket(t *testing.T) { // Arrange dockerHost := "unix:///my/docker/host.sock" - os.Setenv("DOCKER_HOST", dockerHost) + t.Setenv("DOCKER_HOST", dockerHost) // Act ret, err := GetSocketAndHost("") @@ -63,7 +63,7 @@ func TestGetSocketAndHostDontMount(t *testing.T) { // Arrange CommonSocketLocations = originalCommonSocketLocations dockerHost := "unix:///my/docker/host.sock" - os.Setenv("DOCKER_HOST", dockerHost) + t.Setenv("DOCKER_HOST", dockerHost) // Act ret, err := GetSocketAndHost("-") @@ -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 func TestGetSocketAndHostNoHostNoSocketDefaultLocation(t *testing.T) { // Arrange - mySocketFile, tmpErr := os.CreateTemp("", "act-*.sock") + mySocketFile, tmpErr := os.CreateTemp(t.TempDir(), "act-*.sock") mySocket := mySocketFile.Name() unixSocket := "unix://" + mySocket defer os.RemoveAll(mySocket) diff --git a/pkg/container/docker_stub.go b/pkg/container/docker_stub.go index d5c5ef12..49ee18b1 100644 --- a/pkg/container/docker_stub.go +++ b/pkg/container/docker_stub.go @@ -6,20 +6,21 @@ import ( "context" "runtime" - "github.com/docker/docker/api/types" "github.com/nektos/act/pkg/common" + + "github.com/docker/docker/api/types" "github.com/pkg/errors" ) // ImageExistsLocally returns a boolean indicating if an image with the // requested name, tag and architecture exists in the local docker image store -func ImageExistsLocally(ctx context.Context, imageName string, platform string) (bool, error) { +func ImageExistsLocally(ctx context.Context, imageName, platform string) (bool, error) { return false, errors.New("Unsupported Operation") } // RemoveImage removes image from local store, the function is used to run different // container image architectures -func RemoveImage(ctx context.Context, imageName string, force bool, pruneChildren bool) (bool, error) { +func RemoveImage(ctx context.Context, imageName string, force, pruneChildren bool) (bool, error) { return false, errors.New("Unsupported Operation") } diff --git a/pkg/container/docker_volume.go b/pkg/container/docker_volume.go index f99c5845..8be45e51 100644 --- a/pkg/container/docker_volume.go +++ b/pkg/container/docker_volume.go @@ -5,9 +5,10 @@ package container import ( "context" + "github.com/nektos/act/pkg/common" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/volume" - "github.com/nektos/act/pkg/common" ) func NewDockerVolumeRemoveExecutor(volumeName string, force bool) common.Executor { diff --git a/pkg/container/executions_environment.go b/pkg/container/executions_environment.go index 41e3b57e..dfc1936e 100644 --- a/pkg/container/executions_environment.go +++ b/pkg/container/executions_environment.go @@ -9,7 +9,7 @@ type ExecutionsEnvironment interface { GetPathVariableName() string DefaultPathVariable() 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 IsEnvironmentCaseInsensitive() bool } diff --git a/pkg/container/host_environment.go b/pkg/container/host_environment.go index bdda16cd..08035cea 100644 --- a/pkg/container/host_environment.go +++ b/pkg/container/host_environment.go @@ -15,14 +15,14 @@ import ( "strings" "time" + "github.com/nektos/act/pkg/common" + "github.com/nektos/act/pkg/filecollector" + "github.com/nektos/act/pkg/lookpath" + "github.com/go-git/go-billy/v5/helper/polyfill" "github.com/go-git/go-billy/v5/osfs" "github.com/go-git/go-git/v5/plumbing/format/gitignore" "golang.org/x/term" - - "github.com/nektos/act/pkg/common" - "github.com/nektos/act/pkg/filecollector" - "github.com/nektos/act/pkg/lookpath" ) type HostEnvironment struct { @@ -35,7 +35,7 @@ type HostEnvironment struct { StdOut io.Writer } -func (e *HostEnvironment) Create(_ []string, _ []string) common.Executor { +func (e *HostEnvironment) Create(_, _ []string) common.Executor { return func(ctx context.Context) error { return nil } @@ -86,7 +86,7 @@ func (e *HostEnvironment) CopyTarStream(ctx context.Context, destPath string, ta continue } 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 { return err @@ -94,7 +94,7 @@ func (e *HostEnvironment) CopyTarStream(ctx context.Context, destPath string, ta } } -func (e *HostEnvironment) CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor { +func (e *HostEnvironment) CopyDir(destPath, srcPath string, useGitIgnore bool) common.Executor { return func(ctx context.Context) error { logger := common.Logger(ctx) srcPrefix := filepath.Dir(srcPath) @@ -227,7 +227,7 @@ func (l *localEnv) Getenv(name string) string { func lookupPathHost(cmd string, env map[string]string, writer io.Writer) (string, error) { f, err := lookpath.LookPath2(cmd, &localEnv{env: env}) 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 { return "", fmt.Errorf("%v: %w", err, _err) } @@ -346,7 +346,7 @@ func (e *HostEnvironment) exec(ctx context.Context, command []string, cmdline st } if tty != nil { 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") } } @@ -408,9 +408,10 @@ func (e *HostEnvironment) GetActPath() string { } func (*HostEnvironment) GetPathVariableName() string { - if runtime.GOOS == "plan9" { + switch runtime.GOOS { + case "plan9": return "path" - } else if runtime.GOOS == "windows" { + case "windows": return "Path" // Actually we need a case insensitive map } return "PATH" @@ -449,8 +450,8 @@ func goOsToActionOs(os string) string { return os } -func (e *HostEnvironment) GetRunnerContext(_ context.Context) map[string]interface{} { - return map[string]interface{}{ +func (e *HostEnvironment) GetRunnerContext(_ context.Context) map[string]any { + return map[string]any{ "os": goOsToActionOs(runtime.GOOS), "arch": goArchToActionArch(runtime.GOARCH), "temp": e.TmpDir, @@ -458,7 +459,7 @@ func (e *HostEnvironment) GetRunnerContext(_ context.Context) map[string]interfa } } -func (e *HostEnvironment) ReplaceLogWriter(stdout io.Writer, _ io.Writer) (io.Writer, io.Writer) { +func (e *HostEnvironment) ReplaceLogWriter(stdout, _ io.Writer) (io.Writer, io.Writer) { org := e.StdOut e.StdOut = stdout return org, org diff --git a/pkg/container/host_environment_test.go b/pkg/container/host_environment_test.go index 2614a2f8..c338db3c 100644 --- a/pkg/container/host_environment_test.go +++ b/pkg/container/host_environment_test.go @@ -16,9 +16,7 @@ import ( var _ ExecutionsEnvironment = &HostEnvironment{} func TestCopyDir(t *testing.T) { - dir, err := os.MkdirTemp("", "test-host-env-*") - assert.NoError(t, err) - defer os.RemoveAll(dir) + dir := t.TempDir() ctx := context.Background() e := &HostEnvironment{ Path: filepath.Join(dir, "path"), @@ -28,18 +26,16 @@ func TestCopyDir(t *testing.T) { StdOut: os.Stdout, Workdir: path.Join("testdata", "scratch"), } - _ = os.MkdirAll(e.Path, 0700) - _ = os.MkdirAll(e.TmpDir, 0700) - _ = os.MkdirAll(e.ToolCache, 0700) - _ = os.MkdirAll(e.ActPath, 0700) - err = e.CopyDir(e.Workdir, e.Path, true)(ctx) + _ = os.MkdirAll(e.Path, 0o700) + _ = os.MkdirAll(e.TmpDir, 0o700) + _ = os.MkdirAll(e.ToolCache, 0o700) + _ = os.MkdirAll(e.ActPath, 0o700) + err := e.CopyDir(e.Workdir, e.Path, true)(ctx) assert.NoError(t, err) } func TestGetContainerArchive(t *testing.T) { - dir, err := os.MkdirTemp("", "test-host-env-*") - assert.NoError(t, err) - defer os.RemoveAll(dir) + dir := t.TempDir() ctx := context.Background() e := &HostEnvironment{ Path: filepath.Join(dir, "path"), @@ -49,12 +45,12 @@ func TestGetContainerArchive(t *testing.T) { StdOut: os.Stdout, Workdir: path.Join("testdata", "scratch"), } - _ = os.MkdirAll(e.Path, 0700) - _ = os.MkdirAll(e.TmpDir, 0700) - _ = os.MkdirAll(e.ToolCache, 0700) - _ = os.MkdirAll(e.ActPath, 0700) + _ = os.MkdirAll(e.Path, 0o700) + _ = os.MkdirAll(e.TmpDir, 0o700) + _ = os.MkdirAll(e.ToolCache, 0o700) + _ = os.MkdirAll(e.ActPath, 0o700) expectedContent := []byte("sdde/7sh") - err = os.WriteFile(filepath.Join(e.Path, "action.yml"), expectedContent, 0600) + err := os.WriteFile(filepath.Join(e.Path, "action.yml"), expectedContent, 0o600) assert.NoError(t, err) archive, err := e.GetContainerArchive(ctx, e.Path) assert.NoError(t, err) diff --git a/pkg/container/linux_container_environment_extensions.go b/pkg/container/linux_container_environment_extensions.go index d6734511..76a41c8a 100644 --- a/pkg/container/linux_container_environment_extensions.go +++ b/pkg/container/linux_container_environment_extensions.go @@ -10,8 +10,7 @@ import ( log "github.com/sirupsen/logrus" ) -type LinuxContainerEnvironmentExtensions struct { -} +type LinuxContainerEnvironmentExtensions struct{} // Resolves the equivalent host path inside the container // This is required for windows and WSL 2 to translate things like C:\Users\Myproject to /mnt/users/Myproject @@ -63,8 +62,8 @@ func (*LinuxContainerEnvironmentExtensions) JoinPathVariable(paths ...string) st return strings.Join(paths, ":") } -func (*LinuxContainerEnvironmentExtensions) GetRunnerContext(ctx context.Context) map[string]interface{} { - return map[string]interface{}{ +func (*LinuxContainerEnvironmentExtensions) GetRunnerContext(ctx context.Context) map[string]any { + return map[string]any{ "os": "Linux", "arch": RunnerArch(ctx), "temp": "/tmp", diff --git a/pkg/container/linux_container_environment_extensions_test.go b/pkg/container/linux_container_environment_extensions_test.go index 38111714..c0633403 100644 --- a/pkg/container/linux_container_environment_extensions_test.go +++ b/pkg/container/linux_container_environment_extensions_test.go @@ -31,22 +31,17 @@ func TestContainerPath(t *testing.T) { for _, v := range []containerPathJob{ {"/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/c/windows/to/unix", "windows\\to\\unix", fmt.Sprintf("%s\\", rootDrive)}, - {fmt.Sprintf("/mnt/%v/act", rootDriveLetter), "act", fmt.Sprintf("%s\\", rootDrive)}, + {"/mnt/c/windows/to/unix", "windows\\to\\unix", rootDrive + "\\"}, + {fmt.Sprintf("/mnt/%v/act", rootDriveLetter), "act", rootDrive + "\\"}, } { if v.workDir != "" { - if err := os.Chdir(v.workDir); err != nil { - log.Error(err) - t.Fail() - } + t.Chdir(v.workDir) } assert.Equal(t, v.destinationPath, linuxcontainerext.ToContainerPath(v.sourcePath)) } - if err := os.Chdir(cwd); err != nil { - log.Error(err) - } + t.Chdir(cwd) } else { cwd, err := os.Getwd() if err != nil { diff --git a/pkg/exprparser/functions.go b/pkg/exprparser/functions.go index 83b2a080..14c95060 100644 --- a/pkg/exprparser/functions.go +++ b/pkg/exprparser/functions.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "fmt" "io" "io/fs" @@ -13,9 +14,9 @@ import ( "strconv" "strings" - "github.com/go-git/go-git/v5/plumbing/format/gitignore" - "github.com/nektos/act/pkg/model" + + "github.com/go-git/go-git/v5/plumbing/format/gitignore" "github.com/rhysd/actionlint" ) @@ -66,7 +67,7 @@ const ( func (impl *interperterImpl) format(str reflect.Value, replaceValue ...reflect.Value) (string, error) { input := impl.coerceToString(str).String() - output := "" + var output strings.Builder replacementIndex := "" state := passThrough @@ -81,13 +82,13 @@ func (impl *interperterImpl) format(str reflect.Value, replaceValue ...reflect.V state = bracketClose default: - output += string(character) + output.WriteRune(character) } case bracketOpen: // found { switch character { case '{': - output += "{" + output.WriteString("{") replacementIndex = "" state = passThrough @@ -103,7 +104,7 @@ func (impl *interperterImpl) format(str reflect.Value, replaceValue ...reflect.V return "", fmt.Errorf("The following format string references more arguments than were supplied: '%s'", input) } - output += impl.coerceToString(replaceValue[index]).String() + output.WriteString(impl.coerceToString(replaceValue[index]).String()) state = passThrough @@ -114,7 +115,7 @@ func (impl *interperterImpl) format(str reflect.Value, replaceValue ...reflect.V case bracketClose: // found } switch character { case '}': - output += "}" + output.WriteString("}") replacementIndex = "" state = passThrough @@ -134,10 +135,10 @@ func (impl *interperterImpl) format(str reflect.Value, replaceValue ...reflect.V } } - return output, nil + return output.String(), nil } -func (impl *interperterImpl) join(array reflect.Value, sep reflect.Value) (string, error) { +func (impl *interperterImpl) join(array, sep reflect.Value) (string, error) { separator := impl.coerceToString(sep).String() switch array.Kind() { case reflect.Slice: @@ -165,12 +166,12 @@ func (impl *interperterImpl) toJSON(value reflect.Value) (string, error) { return string(json), nil } -func (impl *interperterImpl) fromJSON(value reflect.Value) (interface{}, error) { +func (impl *interperterImpl) fromJSON(value reflect.Value) (any, error) { if value.Kind() != reflect.String { return nil, fmt.Errorf("Cannot parse non-string type %v as JSON", value.Kind()) } - var data interface{} + var data any err := json.Unmarshal([]byte(value.String()), &data) if err != nil { @@ -195,7 +196,7 @@ func (impl *interperterImpl) hashFiles(paths ...reflect.Value) (string, error) { } ps = append(ps, gitignore.ParsePattern(cleanPath, nil)) } else { - return "", fmt.Errorf("Non-string path passed to hashFiles") + return "", errors.New("Non-string path passed to hashFiles") } } diff --git a/pkg/exprparser/functions_test.go b/pkg/exprparser/functions_test.go index ea51a2bc..207b8ea3 100644 --- a/pkg/exprparser/functions_test.go +++ b/pkg/exprparser/functions_test.go @@ -5,13 +5,14 @@ import ( "testing" "github.com/nektos/act/pkg/model" + "github.com/stretchr/testify/assert" ) func TestFunctionContains(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"contains('search', 'item') }}", false, "contains-str-str"}, @@ -48,7 +49,7 @@ func TestFunctionContains(t *testing.T) { func TestFunctionStartsWith(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"startsWith('search', 'se') }}", true, "startswith-string"}, @@ -77,7 +78,7 @@ func TestFunctionStartsWith(t *testing.T) { func TestFunctionEndsWith(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"endsWith('search', 'ch') }}", true, "endsWith-string"}, @@ -106,7 +107,7 @@ func TestFunctionEndsWith(t *testing.T) { func TestFunctionJoin(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"join(fromJSON('[\"a\", \"b\"]'), ',')", "a,b", "join-arr"}, @@ -133,7 +134,7 @@ func TestFunctionJoin(t *testing.T) { func TestFunctionToJSON(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"toJSON(env) }}", "{\n \"key\": \"value\"\n}", "toJSON"}, @@ -159,10 +160,10 @@ func TestFunctionToJSON(t *testing.T) { func TestFunctionFromJSON(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ - {"fromJSON('{\"foo\":\"bar\"}') }}", map[string]interface{}{ + {"fromJSON('{\"foo\":\"bar\"}') }}", map[string]any{ "foo": "bar", }, "fromJSON"}, } @@ -182,7 +183,7 @@ func TestFunctionFromJSON(t *testing.T) { func TestFunctionHashFiles(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"hashFiles('**/non-extant-files') }}", "", "hash-non-existing-file"}, @@ -212,8 +213,8 @@ func TestFunctionHashFiles(t *testing.T) { func TestFunctionFormat(t *testing.T) { table := []struct { input string - expected interface{} - error interface{} + expected any + error any name string }{ {"format('text')", "text", nil, "format-plain-string"}, diff --git a/pkg/exprparser/interpreter.go b/pkg/exprparser/interpreter.go index 6c661b7b..d6582d33 100644 --- a/pkg/exprparser/interpreter.go +++ b/pkg/exprparser/interpreter.go @@ -2,12 +2,14 @@ package exprparser import ( "encoding" + "errors" "fmt" "math" "reflect" "strings" "github.com/nektos/act/pkg/model" + "github.com/rhysd/actionlint" ) @@ -17,14 +19,14 @@ type EvaluationEnvironment struct { Job *model.JobContext Jobs *map[string]*model.WorkflowCallResult Steps map[string]*model.StepResult - Runner map[string]interface{} + Runner map[string]any Secrets map[string]string Vars map[string]string - Strategy map[string]interface{} - Matrix map[string]interface{} + Strategy map[string]any + Matrix map[string]any Needs map[string]Needs - Inputs map[string]interface{} - HashFiles func([]reflect.Value) (interface{}, error) + Inputs map[string]any + HashFiles func([]reflect.Value) (any, error) } type Needs struct { @@ -63,7 +65,7 @@ func (dsc DefaultStatusCheck) String() string { } type Interpreter interface { - Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (interface{}, error) + Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (any, error) } type interperterImpl struct { @@ -78,7 +80,7 @@ func NewInterpeter(env *EvaluationEnvironment, config Config) Interpreter { } } -func (impl *interperterImpl) Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (interface{}, error) { +func (impl *interperterImpl) Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (any, error) { input = strings.TrimPrefix(input, "${{") if defaultStatusCheck != DefaultStatusCheckNone && input == "" { input = "success()" @@ -117,7 +119,7 @@ func (impl *interperterImpl) Evaluate(input string, defaultStatusCheck DefaultSt return result, err2 } -func (impl *interperterImpl) evaluateNode(exprNode actionlint.ExprNode) (interface{}, error) { +func (impl *interperterImpl) evaluateNode(exprNode actionlint.ExprNode) (any, error) { switch node := exprNode.(type) { case *actionlint.VariableNode: return impl.evaluateVariable(node) @@ -150,8 +152,8 @@ func (impl *interperterImpl) evaluateNode(exprNode actionlint.ExprNode) (interfa } } -//nolint:gocyclo -func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableNode) (interface{}, error) { +//nolint:gocyclo // function handles many cases +func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableNode) (any, error) { switch strings.ToLower(variableNode.Name) { case "github": return impl.env.Github, nil @@ -163,7 +165,7 @@ func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableN return impl.env.Job, nil case "jobs": if impl.env.Jobs == nil { - return nil, fmt.Errorf("Unavailable context: jobs") + return nil, errors.New("Unavailable context: jobs") } return impl.env.Jobs, nil case "steps": @@ -191,7 +193,7 @@ func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableN } } -func (impl *interperterImpl) evaluateIndexAccess(indexAccessNode *actionlint.IndexAccessNode) (interface{}, error) { +func (impl *interperterImpl) evaluateIndexAccess(indexAccessNode *actionlint.IndexAccessNode) (any, error) { left, err := impl.evaluateNode(indexAccessNode.Operand) if err != nil { return nil, err @@ -226,7 +228,7 @@ func (impl *interperterImpl) evaluateIndexAccess(indexAccessNode *actionlint.Ind } } -func (impl *interperterImpl) evaluateObjectDeref(objectDerefNode *actionlint.ObjectDerefNode) (interface{}, error) { +func (impl *interperterImpl) evaluateObjectDeref(objectDerefNode *actionlint.ObjectDerefNode) (any, error) { left, err := impl.evaluateNode(objectDerefNode.Receiver) if err != nil { return nil, err @@ -235,7 +237,7 @@ func (impl *interperterImpl) evaluateObjectDeref(objectDerefNode *actionlint.Obj return impl.getPropertyValue(reflect.ValueOf(left), objectDerefNode.Property) } -func (impl *interperterImpl) evaluateArrayDeref(arrayDerefNode *actionlint.ArrayDerefNode) (interface{}, error) { +func (impl *interperterImpl) evaluateArrayDeref(arrayDerefNode *actionlint.ArrayDerefNode) (any, error) { left, err := impl.evaluateNode(arrayDerefNode.Receiver) if err != nil { return nil, err @@ -244,17 +246,17 @@ func (impl *interperterImpl) evaluateArrayDeref(arrayDerefNode *actionlint.Array return impl.getSafeValue(reflect.ValueOf(left)), nil } -func (impl *interperterImpl) getPropertyValue(left reflect.Value, property string) (value interface{}, err error) { +func (impl *interperterImpl) getPropertyValue(left reflect.Value, property string) (value any, err error) { switch left.Kind() { case reflect.Ptr: return impl.getPropertyValue(left.Elem(), property) case reflect.Struct: leftType := left.Type() - for i := 0; i < leftType.NumField(); i++ { - jsonName := leftType.Field(i).Tag.Get("json") + for field := range leftType.Fields() { + jsonName := field.Tag.Get("json") if jsonName == property { - property = leftType.Field(i).Name + property = field.Name break } } @@ -298,7 +300,7 @@ func (impl *interperterImpl) getPropertyValue(left reflect.Value, property strin return nil, nil case reflect.Slice: - var values []interface{} + var values []any for i := 0; i < left.Len(); i++ { value, err := impl.getPropertyValue(left.Index(i).Elem(), property) @@ -315,7 +317,7 @@ func (impl *interperterImpl) getPropertyValue(left reflect.Value, property strin return nil, nil } -func (impl *interperterImpl) getMapValue(value reflect.Value) (interface{}, error) { +func (impl *interperterImpl) getMapValue(value reflect.Value) (any, error) { if value.Kind() == reflect.Ptr { return impl.getMapValue(value.Elem()) } @@ -323,7 +325,7 @@ func (impl *interperterImpl) getMapValue(value reflect.Value) (interface{}, erro return value.Interface(), nil } -func (impl *interperterImpl) evaluateNot(notNode *actionlint.NotOpNode) (interface{}, error) { +func (impl *interperterImpl) evaluateNot(notNode *actionlint.NotOpNode) (any, error) { operand, err := impl.evaluateNode(notNode.Operand) if err != nil { return nil, err @@ -332,7 +334,7 @@ func (impl *interperterImpl) evaluateNot(notNode *actionlint.NotOpNode) (interfa return !IsTruthy(operand), nil } -func (impl *interperterImpl) evaluateCompare(compareNode *actionlint.CompareOpNode) (interface{}, error) { +func (impl *interperterImpl) evaluateCompare(compareNode *actionlint.CompareOpNode) (any, error) { left, err := impl.evaluateNode(compareNode.Left) if err != nil { return nil, err @@ -349,7 +351,7 @@ func (impl *interperterImpl) evaluateCompare(compareNode *actionlint.CompareOpNo return impl.compareValues(leftValue, rightValue, compareNode.Kind) } -func (impl *interperterImpl) compareValues(leftValue reflect.Value, rightValue reflect.Value, kind actionlint.CompareOpNodeKind) (interface{}, error) { +func (impl *interperterImpl) compareValues(leftValue, rightValue reflect.Value, kind actionlint.CompareOpNodeKind) (any, error) { if leftValue.Kind() != rightValue.Kind() { if !impl.isNumber(leftValue) { leftValue = impl.coerceToNumber(leftValue) @@ -461,7 +463,7 @@ func (impl *interperterImpl) coerceToString(value reflect.Value) reflect.Value { return value } -func (impl *interperterImpl) compareString(left string, right string, kind actionlint.CompareOpNodeKind) (bool, error) { +func (impl *interperterImpl) compareString(left, right string, kind actionlint.CompareOpNodeKind) (bool, error) { switch kind { case actionlint.CompareOpNodeKindLess: return left < right, nil @@ -480,7 +482,7 @@ func (impl *interperterImpl) compareString(left string, right string, kind actio } } -func (impl *interperterImpl) compareNumber(left float64, right float64, kind actionlint.CompareOpNodeKind) (bool, error) { +func (impl *interperterImpl) compareNumber(left, right float64, kind actionlint.CompareOpNodeKind) (bool, error) { switch kind { case actionlint.CompareOpNodeKindLess: return left < right, nil @@ -499,7 +501,7 @@ func (impl *interperterImpl) compareNumber(left float64, right float64, kind act } } -func IsTruthy(input interface{}) bool { +func IsTruthy(input any) bool { value := reflect.ValueOf(input) switch value.Kind() { case reflect.Bool: @@ -535,7 +537,7 @@ func (impl *interperterImpl) isNumber(value reflect.Value) bool { } } -func (impl *interperterImpl) getSafeValue(value reflect.Value) interface{} { +func (impl *interperterImpl) getSafeValue(value reflect.Value) any { switch value.Kind() { case reflect.Invalid: return nil @@ -549,7 +551,7 @@ func (impl *interperterImpl) getSafeValue(value reflect.Value) interface{} { return value.Interface() } -func (impl *interperterImpl) evaluateLogicalCompare(compareNode *actionlint.LogicalOpNode) (interface{}, error) { +func (impl *interperterImpl) evaluateLogicalCompare(compareNode *actionlint.LogicalOpNode) (any, error) { left, err := impl.evaluateNode(compareNode.Left) if err != nil { return nil, err @@ -578,8 +580,8 @@ func (impl *interperterImpl) evaluateLogicalCompare(compareNode *actionlint.Logi return nil, fmt.Errorf("Unable to compare incompatibles types '%s' and '%s'", leftValue.Kind(), rightValue.Kind()) } -//nolint:gocyclo -func (impl *interperterImpl) evaluateFuncCall(funcCallNode *actionlint.FuncCallNode) (interface{}, error) { +//nolint:gocyclo // function handles many cases +func (impl *interperterImpl) evaluateFuncCall(funcCallNode *actionlint.FuncCallNode) (any, error) { args := make([]reflect.Value, 0) for _, arg := range funcCallNode.Args { diff --git a/pkg/exprparser/interpreter_test.go b/pkg/exprparser/interpreter_test.go index f45851d1..33705846 100644 --- a/pkg/exprparser/interpreter_test.go +++ b/pkg/exprparser/interpreter_test.go @@ -5,13 +5,14 @@ import ( "testing" "github.com/nektos/act/pkg/model" + "github.com/stretchr/testify/assert" ) func TestLiterals(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"true", true, "true"}, @@ -40,7 +41,7 @@ func TestLiterals(t *testing.T) { func TestOperators(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string error string }{ @@ -68,7 +69,7 @@ func TestOperators(t *testing.T) { {`true && false`, false, "and", ""}, {`true || false`, true, "or", ""}, {`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.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", ""}, @@ -79,15 +80,15 @@ func TestOperators(t *testing.T) { env := &EvaluationEnvironment{ Github: &model.GithubContext{ Action: "push", - Event: map[string]interface{}{ - "commits": []interface{}{ - map[string]interface{}{ - "author": map[string]interface{}{ + Event: map[string]any{ + "commits": []any{ + map[string]any{ + "author": map[string]any{ "username": "someone", }, }, - map[string]interface{}{ - "author": map[string]interface{}{ + map[string]any{ + "author": map[string]any{ "username": "someone-else", }, }, @@ -114,7 +115,7 @@ func TestOperators(t *testing.T) { func TestOperatorsCompare(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"!null", true, "not-null"}, @@ -162,7 +163,7 @@ func TestOperatorsCompare(t *testing.T) { func TestOperatorsBooleanEvaluation(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ // true && @@ -529,7 +530,7 @@ func TestOperatorsBooleanEvaluation(t *testing.T) { func TestContexts(t *testing.T) { table := []struct { input string - expected interface{} + expected any name string }{ {"github.action", "push", "github-context"}, @@ -586,7 +587,7 @@ func TestContexts(t *testing.T) { Conclusion: model.StepStatusSkipped, }, }, - Runner: map[string]interface{}{ + Runner: map[string]any{ "os": "Linux", "temp": "/tmp", "tool_cache": "/opt/hostedtoolcache", @@ -597,10 +598,10 @@ func TestContexts(t *testing.T) { Vars: map[string]string{ "name": "value", }, - Strategy: map[string]interface{}{ + Strategy: map[string]any{ "fail-fast": true, }, - Matrix: map[string]interface{}{ + Matrix: map[string]any{ "os": "Linux", }, Needs: map[string]Needs{ @@ -611,7 +612,7 @@ func TestContexts(t *testing.T) { Result: "success", }, }, - Inputs: map[string]interface{}{ + Inputs: map[string]any{ "name": "value", }, } diff --git a/pkg/filecollector/file_collector.go b/pkg/filecollector/file_collector.go index 8547bb7c..468a9eb7 100644 --- a/pkg/filecollector/file_collector.go +++ b/pkg/filecollector/file_collector.go @@ -3,6 +3,7 @@ package filecollector import ( "archive/tar" "context" + "errors" "fmt" "io" "io/fs" @@ -97,8 +98,7 @@ type Fs interface { Readlink(path string) (string, error) } -type DefaultFs struct { -} +type DefaultFs struct{} func (*DefaultFs) Walk(root string, fn filepath.WalkFunc) error { return filepath.Walk(root, fn) @@ -124,7 +124,7 @@ func (*DefaultFs) Readlink(path string) (string, error) { return os.Readlink(path) } -//nolint:gocyclo +//nolint:gocyclo // function handles many cases func (fc *FileCollector) CollectFiles(ctx context.Context, submodulePath []string) filepath.WalkFunc { i, _ := fc.Fs.OpenGitIndex(path.Join(fc.SrcPath, path.Join(submodulePath...))) return func(file string, fi os.FileInfo, err error) error { @@ -134,7 +134,7 @@ func (fc *FileCollector) CollectFiles(ctx context.Context, submodulePath []strin if ctx != nil { select { case <-ctx.Done(): - return fmt.Errorf("copy cancelled") + return errors.New("copy cancelled") default: } } diff --git a/pkg/filecollector/file_collector_test.go b/pkg/filecollector/file_collector_test.go index 60a8d4dd..a15729dd 100644 --- a/pkg/filecollector/file_collector_test.go +++ b/pkg/filecollector/file_collector_test.go @@ -27,7 +27,7 @@ func (mfs *memoryFs) walk(root string, fn filepath.WalkFunc) error { if err != nil { return err } - for i := 0; i < len(dir); i++ { + for i := range dir { filename := filepath.Join(root, dir[i].Name()) err = fn(filename, dir[i], nil) if dir[i].IsDir() { diff --git a/pkg/lookpath/env.go b/pkg/lookpath/env.go index dc376e7b..b7e61f8c 100644 --- a/pkg/lookpath/env.go +++ b/pkg/lookpath/env.go @@ -6,8 +6,7 @@ type Env interface { Getenv(name string) string } -type defaultEnv struct { -} +type defaultEnv struct{} func (*defaultEnv) Getenv(name string) string { return os.Getenv(name) diff --git a/pkg/lookpath/lp_plan9.go b/pkg/lookpath/lp_plan9.go index a201b715..18db2d88 100644 --- a/pkg/lookpath/lp_plan9.go +++ b/pkg/lookpath/lp_plan9.go @@ -20,7 +20,7 @@ func findExecutable(file string) error { if err != nil { return err } - if m := d.Mode(); !m.IsDir() && m&0111 != 0 { + if m := d.Mode(); !m.IsDir() && m&0o111 != 0 { return nil } return fs.ErrPermission diff --git a/pkg/lookpath/lp_unix.go b/pkg/lookpath/lp_unix.go index 233e21f9..f8bc60c5 100644 --- a/pkg/lookpath/lp_unix.go +++ b/pkg/lookpath/lp_unix.go @@ -22,7 +22,7 @@ func findExecutable(file string) error { if err != nil { return err } - if m := d.Mode(); !m.IsDir() && m&0111 != 0 { + if m := d.Mode(); !m.IsDir() && m&0o111 != 0 { return nil } return fs.ErrPermission diff --git a/pkg/model/action.go b/pkg/model/action.go index f6571606..af00949d 100644 --- a/pkg/model/action.go +++ b/pkg/model/action.go @@ -11,7 +11,7 @@ import ( // ActionRunsUsing is the type of runner for the action type ActionRunsUsing string -func (a *ActionRunsUsing) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (a *ActionRunsUsing) UnmarshalYAML(unmarshal func(any) error) error { var using string if err := unmarshal(&using); err != nil { return err diff --git a/pkg/model/github_context.go b/pkg/model/github_context.go index 53e23077..76d80f56 100644 --- a/pkg/model/github_context.go +++ b/pkg/model/github_context.go @@ -10,41 +10,41 @@ import ( ) type GithubContext struct { - Event map[string]interface{} `json:"event"` - EventPath string `json:"event_path"` - Workflow string `json:"workflow"` - RunID string `json:"run_id"` - RunNumber string `json:"run_number"` - Actor string `json:"actor"` - Repository string `json:"repository"` - EventName string `json:"event_name"` - Sha string `json:"sha"` - Ref string `json:"ref"` - RefName string `json:"ref_name"` - RefType string `json:"ref_type"` - HeadRef string `json:"head_ref"` - BaseRef string `json:"base_ref"` - Token string `json:"token"` - Workspace string `json:"workspace"` - Action string `json:"action"` - ActionPath string `json:"action_path"` - ActionRef string `json:"action_ref"` - ActionRepository string `json:"action_repository"` - Job string `json:"job"` - JobName string `json:"job_name"` - RepositoryOwner string `json:"repository_owner"` - RetentionDays string `json:"retention_days"` - RunnerPerflog string `json:"runner_perflog"` - RunnerTrackingID string `json:"runner_tracking_id"` - ServerURL string `json:"server_url"` - APIURL string `json:"api_url"` - GraphQLURL string `json:"graphql_url"` + Event map[string]any `json:"event"` + EventPath string `json:"event_path"` + Workflow string `json:"workflow"` + RunID string `json:"run_id"` + RunNumber string `json:"run_number"` + Actor string `json:"actor"` + Repository string `json:"repository"` + EventName string `json:"event_name"` + Sha string `json:"sha"` + Ref string `json:"ref"` + RefName string `json:"ref_name"` + RefType string `json:"ref_type"` + HeadRef string `json:"head_ref"` + BaseRef string `json:"base_ref"` + Token string `json:"token"` + Workspace string `json:"workspace"` + Action string `json:"action"` + ActionPath string `json:"action_path"` + ActionRef string `json:"action_ref"` + ActionRepository string `json:"action_repository"` + Job string `json:"job"` + JobName string `json:"job_name"` + RepositoryOwner string `json:"repository_owner"` + RetentionDays string `json:"retention_days"` + RunnerPerflog string `json:"runner_perflog"` + RunnerTrackingID string `json:"runner_tracking_id"` + ServerURL string `json:"server_url"` + APIURL string `json:"api_url"` + GraphQLURL string `json:"graphql_url"` // For Gitea RunAttempt string `json:"run_attempt"` } -func asString(v interface{}) string { +func asString(v any) string { if v == nil { return "" } else if s, ok := v.(string); ok { @@ -53,7 +53,7 @@ func asString(v interface{}) string { return "" } -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 @@ -63,20 +63,20 @@ 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:]...) } } -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"] 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 { common.Logger(ctx).Warnf("unable to set default branch to %v", b) return event @@ -93,29 +93,31 @@ func withDefaultBranch(ctx context.Context, b string, event map[string]interface return event } -var findGitRef = git.FindGitRef -var findGitRevision = git.FindGitRevision +var ( + findGitRef = git.FindGitRef + findGitRevision = git.FindGitRevision +) -func (ghc *GithubContext) SetRef(ctx context.Context, defaultBranch string, repoPath string) { +func (ghc *GithubContext) SetRef(ctx context.Context, defaultBranch, repoPath string) { logger := common.Logger(ctx) // https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows // https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads switch ghc.EventName { 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": ghc.Ref = fmt.Sprintf("refs/pull/%.0f/merge", ghc.Event["number"]) case "deployment", "deployment_status": ghc.Ref = asString(nestedMapLookup(ghc.Event, "deployment", "ref")) 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": ghc.Ref = asString(ghc.Event["ref"]) default: defaultBranch := asString(nestedMapLookup(ghc.Event, "repository", "default_branch")) if defaultBranch != "" { - ghc.Ref = fmt.Sprintf("refs/heads/%s", defaultBranch) + ghc.Ref = "refs/heads/" + defaultBranch } } @@ -136,7 +138,7 @@ func (ghc *GithubContext) SetRef(ctx context.Context, defaultBranch string, repo } 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")) } } } @@ -167,7 +169,7 @@ func (ghc *GithubContext) SetSha(ctx context.Context, repoPath string) { } } -func (ghc *GithubContext) SetRepositoryAndOwner(ctx context.Context, githubInstance string, remoteName string, repoPath string) { +func (ghc *GithubContext) SetRepositoryAndOwner(ctx context.Context, githubInstance, remoteName, repoPath string) { if ghc.Repository == "" { repo, err := git.FindGithubRepo(ctx, repoPath, githubInstance, remoteName) if err != nil { diff --git a/pkg/model/github_context_test.go b/pkg/model/github_context_test.go index ed08e231..0ee5a6d3 100644 --- a/pkg/model/github_context_test.go +++ b/pkg/model/github_context_test.go @@ -2,7 +2,7 @@ package model import ( "context" - "fmt" + "errors" "testing" log "github.com/sirupsen/logrus" @@ -27,19 +27,19 @@ func TestSetRef(t *testing.T) { tables := []struct { eventName string - event map[string]interface{} + event map[string]any ref string refName string }{ { eventName: "pull_request_target", - event: map[string]interface{}{}, + event: map[string]any{}, ref: "refs/heads/master", refName: "master", }, { eventName: "pull_request", - event: map[string]interface{}{ + event: map[string]any{ "number": 1234., }, ref: "refs/pull/1234/merge", @@ -47,8 +47,8 @@ func TestSetRef(t *testing.T) { }, { eventName: "deployment", - event: map[string]interface{}{ - "deployment": map[string]interface{}{ + event: map[string]any{ + "deployment": map[string]any{ "ref": "refs/heads/somebranch", }, }, @@ -57,8 +57,8 @@ func TestSetRef(t *testing.T) { }, { eventName: "release", - event: map[string]interface{}{ - "release": map[string]interface{}{ + event: map[string]any{ + "release": map[string]any{ "tag_name": "v1.0.0", }, }, @@ -67,7 +67,7 @@ func TestSetRef(t *testing.T) { }, { eventName: "push", - event: map[string]interface{}{ + event: map[string]any{ "ref": "refs/heads/somebranch", }, ref: "refs/heads/somebranch", @@ -75,8 +75,8 @@ func TestSetRef(t *testing.T) { }, { eventName: "unknown", - event: map[string]interface{}{ - "repository": map[string]interface{}{ + event: map[string]any{ + "repository": map[string]any{ "default_branch": "main", }, }, @@ -85,7 +85,7 @@ func TestSetRef(t *testing.T) { }, { eventName: "no-event", - event: map[string]interface{}{}, + event: map[string]any{}, ref: "refs/heads/master", refName: "master", }, @@ -109,12 +109,12 @@ func TestSetRef(t *testing.T) { t.Run("no-default-branch", func(t *testing.T) { findGitRef = func(ctx context.Context, file string) (string, error) { - return "", fmt.Errorf("no default branch") + return "", errors.New("no default branch") } ghc := &GithubContext{ EventName: "no-default-branch", - Event: map[string]interface{}{}, + Event: map[string]any{}, } ghc.SetRef(context.Background(), "", "/some/dir") @@ -141,14 +141,14 @@ func TestSetSha(t *testing.T) { tables := []struct { eventName string - event map[string]interface{} + event map[string]any sha string }{ { eventName: "pull_request_target", - event: map[string]interface{}{ - "pull_request": map[string]interface{}{ - "base": map[string]interface{}{ + event: map[string]any{ + "pull_request": map[string]any{ + "base": map[string]any{ "sha": "pr-base-sha", }, }, @@ -157,15 +157,15 @@ func TestSetSha(t *testing.T) { }, { eventName: "pull_request", - event: map[string]interface{}{ + event: map[string]any{ "number": 1234., }, sha: "1234fakesha", }, { eventName: "deployment", - event: map[string]interface{}{ - "deployment": map[string]interface{}{ + event: map[string]any{ + "deployment": map[string]any{ "sha": "deployment-sha", }, }, @@ -173,12 +173,12 @@ func TestSetSha(t *testing.T) { }, { eventName: "release", - event: map[string]interface{}{}, + event: map[string]any{}, sha: "1234fakesha", }, { eventName: "push", - event: map[string]interface{}{ + event: map[string]any{ "after": "push-sha", "deleted": false, }, @@ -186,12 +186,12 @@ func TestSetSha(t *testing.T) { }, { eventName: "unknown", - event: map[string]interface{}{}, + event: map[string]any{}, sha: "1234fakesha", }, { eventName: "no-event", - event: map[string]interface{}{}, + event: map[string]any{}, sha: "1234fakesha", }, } diff --git a/pkg/model/planner.go b/pkg/model/planner.go index 2d681456..4d6a0dff 100644 --- a/pkg/model/planner.go +++ b/pkg/model/planner.go @@ -1,6 +1,7 @@ package model import ( + "errors" "fmt" "io" "io/fs" @@ -8,7 +9,7 @@ import ( "os" "path/filepath" "regexp" - "sort" + "slices" log "github.com/sirupsen/logrus" ) @@ -57,7 +58,7 @@ type WorkflowFiles struct { // NewWorkflowPlanner will load a specific workflow, all workflows from a directory or all workflows from a directory and its subdirectories // -//nolint:gocyclo +//nolint:gocyclo // function handles many cases func NewWorkflowPlanner(path string, noWorkflowRecurse bool) (WorkflowPlanner, error) { path, err := filepath.Abs(path) if err != nil { @@ -115,9 +116,6 @@ func NewWorkflowPlanner(path string, noWorkflowRecurse bool) (WorkflowPlanner, e workflowDirEntry: fs.FileInfoToDirEntry(fi), }) } - if err != nil { - return nil, err - } wp := new(workflowPlanner) for _, wf := range workflows { @@ -288,11 +286,8 @@ func (wp *workflowPlanner) GetEvents() []string { for _, w := range wp.workflows { found := false for _, e := range events { - for _, we := range w.On() { - if e == we { - found = true - break - } + if slices.Contains(w.On(), e) { + found = true } if found { break @@ -305,9 +300,7 @@ func (wp *workflowPlanner) GetEvents() []string { } // sort the list based on depth of dependencies - sort.Slice(events, func(i, j int) bool { - return events[i] < events[j] - }) + slices.Sort(events) return events } @@ -338,7 +331,7 @@ func (s *Stage) GetJobIDs() []string { // Merge stages with existing stages in plan func (p *Plan) mergeStages(stages []*Stage) { 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) if i >= len(p.Stages) { newStages[i].Runs = append(newStages[i].Runs, stages[i].Runs...) @@ -390,7 +383,7 @@ func createStages(w *Workflow, jobIDs ...string) ([]*Stage, error) { } if len(stages) == 0 { - return nil, 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") + return nil, 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") } return stages, nil diff --git a/pkg/model/workflow.go b/pkg/model/workflow.go index f1e2e22f..62326702 100644 --- a/pkg/model/workflow.go +++ b/pkg/model/workflow.go @@ -4,15 +4,17 @@ import ( "crypto/sha256" "fmt" "io" + "maps" "reflect" "regexp" + "slices" "strconv" "strings" + "github.com/nektos/act/pkg/common" + log "github.com/sirupsen/logrus" "go.yaml.in/yaml/v4" - - "github.com/nektos/act/pkg/common" ) // Workflow is the structure of the files in .github/workflows @@ -45,7 +47,7 @@ func (w *Workflow) On() []string { } return val case yaml.MappingNode: - var val map[string]interface{} + var val map[string]any err := w.RawOn.Decode(&val) if err != nil { log.Fatal(err) @@ -59,9 +61,9 @@ func (w *Workflow) On() []string { return nil } -func (w *Workflow) OnEvent(event string) interface{} { +func (w *Workflow) OnEvent(event string) any { if w.RawOn.Kind == yaml.MappingNode { - var val map[string]interface{} + var val map[string]any if !decodeNode(w.RawOn, &val) { return nil } @@ -77,10 +79,10 @@ func (w *Workflow) OnSchedule() []string { } switch val := schedules.(type) { - case []interface{}: + case []any: allSchedules := []string{} for _, v := range val { - for k, cron := range v.(map[string]interface{}) { + for k, cron := range v.(map[string]any) { if k != "cron" { continue } @@ -121,10 +123,8 @@ func (w *Workflow) WorkflowDispatchConfig() *WorkflowDispatch { if !decodeNode(w.RawOn, &val) { return nil } - for _, v := range val { - if v == "workflow_dispatch" { - return &WorkflowDispatch{} - } + if slices.Contains(val, "workflow_dispatch") { + return &WorkflowDispatch{} } case yaml.MappingNode: var val map[string]yaml.Node @@ -199,7 +199,7 @@ type Job struct { Defaults Defaults `yaml:"defaults"` Outputs map[string]string `yaml:"outputs"` Uses string `yaml:"uses"` - With map[string]interface{} `yaml:"with"` + With map[string]any `yaml:"with"` RawSecrets yaml.Node `yaml:"secrets"` RawPermissions yaml.Node `yaml:"permissions"` Result string @@ -378,9 +378,9 @@ func (j *Job) Environment() map[string]string { } // 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 { - var val map[string][]interface{} + var val map[string][]any if !decodeNode(j.Strategy.RawMatrix, &val) { return nil } @@ -392,22 +392,22 @@ func (j *Job) Matrix() map[string][]interface{} { // GetMatrixes returns the matrix cross product // It skips includes and hard fails excludes for non-existing keys // -//nolint:gocyclo -func (j *Job) GetMatrixes() ([]map[string]interface{}, error) { - matrixes := make([]map[string]interface{}, 0) +//nolint:gocyclo // function handles many cases +func (j *Job) GetMatrixes() ([]map[string]any, error) { + matrixes := make([]map[string]any, 0) if j.Strategy != nil { // Always set these values, even if there's an error later j.Strategy.FailFast = j.Strategy.GetFailFast() j.Strategy.MaxParallel = j.Strategy.GetMaxParallel() if m := j.Matrix(); m != nil { - includes := make([]map[string]interface{}, 0) - extraIncludes := make([]map[string]interface{}, 0) + includes := make([]map[string]any, 0) + extraIncludes := make([]map[string]any, 0) for _, v := range m["include"] { switch t := v.(type) { - case []interface{}: + case []any: for _, i := range t { - i := i.(map[string]interface{}) + i := i.(map[string]any) extraInclude := true for k := range i { if _, ok := m[k]; ok { @@ -420,8 +420,8 @@ func (j *Job) GetMatrixes() ([]map[string]interface{}, error) { extraIncludes = append(extraIncludes, i) } } - case interface{}: - v := v.(map[string]interface{}) + case any: + v := v.(map[string]any) extraInclude := true for k := range v { if _, ok := m[k]; ok { @@ -437,9 +437,9 @@ func (j *Job) GetMatrixes() ([]map[string]interface{}, error) { } delete(m, "include") - excludes := make([]map[string]interface{}, 0) + excludes := make([]map[string]any, 0) for _, e := range m["exclude"] { - e := e.(map[string]interface{}) + e := e.(map[string]any) for k := range e { if _, ok := m[k]; ok { excludes = append(excludes, e) @@ -468,9 +468,7 @@ func (j *Job) GetMatrixes() ([]map[string]interface{}, error) { if commonKeysMatch2(matrix, include, m) { matched = true log.Debugf("Adding include values '%v' to existing entry", include) - for k, v := range include { - matrix[k] = v - } + maps.Copy(matrix, include) } } if !matched { @@ -482,19 +480,19 @@ func (j *Job) GetMatrixes() ([]map[string]interface{}, error) { matrixes = append(matrixes, include) } if len(matrixes) == 0 { - matrixes = append(matrixes, make(map[string]interface{})) + matrixes = append(matrixes, make(map[string]any)) } } else { - matrixes = append(matrixes, make(map[string]interface{})) + matrixes = append(matrixes, make(map[string]any)) } } else { - matrixes = append(matrixes, make(map[string]interface{})) + matrixes = append(matrixes, make(map[string]any)) log.Debugf("Empty Strategy, matrixes=%v", matrixes) } return matrixes, nil } -func commonKeysMatch(a map[string]interface{}, b map[string]interface{}) bool { +func commonKeysMatch(a, b map[string]any) bool { for aKey, aVal := range a { if bVal, ok := b[aKey]; ok && !reflect.DeepEqual(aVal, bVal) { return false @@ -503,7 +501,7 @@ func commonKeysMatch(a map[string]interface{}, b map[string]interface{}) bool { return true } -func commonKeysMatch2(a map[string]interface{}, b map[string]interface{}, m map[string][]interface{}) bool { +func commonKeysMatch2(a, b map[string]any, m map[string][]any) bool { for aKey, aVal := range a { _, useKey := m[aKey] if bVal, ok := b[aKey]; useKey && ok && !reflect.DeepEqual(aVal, bVal) { @@ -623,7 +621,7 @@ func (s *Step) GetEnv() map[string]string { for k, v := range s.With { 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 } return env @@ -631,7 +629,7 @@ func (s *Step) GetEnv() map[string]string { // ShellCommand returns the command for the shell func (s *Step) ShellCommand() string { - shellCommand := "" + var shellCommand string // Reference: https://github.com/actions/runner/blob/8109c962f09d9acc473d92c595ff43afceddb347/src/Runner.Worker/Handlers/ScriptHandlerHelpers.cs#L9-L17 switch s.Shell { @@ -760,11 +758,11 @@ func (w *Workflow) GetJobIDs() []string { 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) } -func decodeNode(node yaml.Node, out interface{}) bool { +func decodeNode(node yaml.Node, out any) bool { if err := node.Decode(out); err != nil { if OnDecodeNodeError != nil { OnDecodeNodeError(node, out, err) @@ -791,7 +789,7 @@ func (r *RawConcurrency) UnmarshalYAML(n *yaml.Node) error { return n.Decode((*objectConcurrency)(r)) } -func (r *RawConcurrency) MarshalYAML() (interface{}, error) { +func (r *RawConcurrency) MarshalYAML() (any, error) { if r.RawExpression != "" { return r.RawExpression, nil } diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go index 7e4f9753..ca4212c7 100644 --- a/pkg/model/workflow_test.go +++ b/pkg/model/workflow_test.go @@ -430,24 +430,24 @@ func TestReadWorkflow_Strategy(t *testing.T) { job := wf.Jobs["strategy-only-max-parallel"] matrixes, err := job.GetMatrixes() assert.NoError(t, err) - assert.Equal(t, matrixes, []map[string]interface{}{{}}) - assert.Equal(t, job.Matrix(), map[string][]interface{}(nil)) + assert.Equal(t, matrixes, []map[string]any{{}}) + assert.Equal(t, job.Matrix(), map[string][]any(nil)) assert.Equal(t, job.Strategy.MaxParallel, 2) assert.Equal(t, job.Strategy.FailFast, true) job = wf.Jobs["strategy-only-fail-fast"] matrixes, err = job.GetMatrixes() assert.NoError(t, err) - assert.Equal(t, matrixes, []map[string]interface{}{{}}) - assert.Equal(t, job.Matrix(), map[string][]interface{}(nil)) + assert.Equal(t, matrixes, []map[string]any{{}}) + assert.Equal(t, job.Matrix(), map[string][]any(nil)) assert.Equal(t, job.Strategy.MaxParallel, 4) assert.Equal(t, job.Strategy.FailFast, false) job = wf.Jobs["strategy-no-matrix"] matrixes, err = job.GetMatrixes() assert.NoError(t, err) - assert.Equal(t, matrixes, []map[string]interface{}{{}}) - assert.Equal(t, job.Matrix(), map[string][]interface{}(nil)) + assert.Equal(t, matrixes, []map[string]any{{}}) + assert.Equal(t, job.Matrix(), map[string][]any(nil)) assert.Equal(t, job.Strategy.MaxParallel, 2) assert.Equal(t, job.Strategy.FailFast, false) @@ -455,7 +455,7 @@ func TestReadWorkflow_Strategy(t *testing.T) { matrixes, err = job.GetMatrixes() assert.NoError(t, err) assert.Equal(t, matrixes, - []map[string]interface{}{ + []map[string]any{ {"datacenter": "site-c", "node-version": "14.x", "site": "staging"}, {"datacenter": "site-c", "node-version": "16.x", "site": "staging"}, {"datacenter": "site-d", "node-version": "16.x", "site": "staging"}, @@ -465,15 +465,15 @@ func TestReadWorkflow_Strategy(t *testing.T) { }, ) assert.Equal(t, job.Matrix(), - map[string][]interface{}{ + map[string][]any{ "datacenter": {"site-c", "site-d"}, "exclude": { - map[string]interface{}{"datacenter": "site-d", "node-version": "14.x", "site": "staging"}, + map[string]any{"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"}, + 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"}, diff --git a/pkg/runner/action.go b/pkg/runner/action.go index 87190a22..5e5bac58 100644 --- a/pkg/runner/action.go +++ b/pkg/runner/action.go @@ -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)} diff --git a/pkg/runner/action_cache_test.go b/pkg/runner/action_cache_test.go index 58fac5bd..2a7b6111 100644 --- a/pkg/runner/action_cache_test.go +++ b/pkg/runner/action_cache_test.go @@ -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" diff --git a/pkg/runner/action_composite.go b/pkg/runner/action_composite.go index fc173de4..a53108dd 100644 --- a/pkg/runner/action_composite.go +++ b/pkg/runner/action_composite.go @@ -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 diff --git a/pkg/runner/action_test.go b/pkg/runner/action_test.go index 36ee14f7..f979b6b9 100644 --- a/pkg/runner/action_test.go +++ b/pkg/runner/action_test.go @@ -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 } diff --git a/pkg/runner/command.go b/pkg/runner/command.go index 6ea53548..096993f3 100644 --- a/pkg/runner/command.go +++ b/pkg/runner/command.go @@ -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] diff --git a/pkg/runner/command_test.go b/pkg/runner/command_test.go index 57c7de5f..5a98eee0 100644 --- a/pkg/runner/command_test.go +++ b/pkg/runner/command_test.go @@ -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") diff --git a/pkg/runner/container_mock_test.go b/pkg/runner/container_mock_test.go index 04d6261b..1fc6320d 100644 --- a/pkg/runner/container_mock_test.go +++ b/pkg/runner/container_mock_test.go @@ -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) } diff --git a/pkg/runner/expression.go b/pkg/runner/expression.go index 894ebbfa..be46c400 100644 --- a/pkg/runner/expression.go +++ b/pkg/runner/expression.go @@ -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() diff --git a/pkg/runner/expression_test.go b/pkg/runner/expression_test.go index 0bc0bf0d..058fa742 100644 --- a/pkg/runner/expression_test.go +++ b/pkg/runner/expression_test.go @@ -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) } diff --git a/pkg/runner/job_executor.go b/pkg/runner/job_executor.go index 5cf3b6c6..94e9ef09 100644 --- a/pkg/runner/job_executor.go +++ b/pkg/runner/job_executor.go @@ -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 diff --git a/pkg/runner/job_executor_test.go b/pkg/runner/job_executor_test.go index ac7725f6..3b536238 100644 --- a/pkg/runner/job_executor_test.go +++ b/pkg/runner/job_executor_test.go @@ -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") diff --git a/pkg/runner/logger.go b/pkg/runner/logger.go index ef93a02b..51f1ed31 100644 --- a/pkg/runner/logger.go +++ b/pkg/runner/logger.go @@ -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 diff --git a/pkg/runner/max_parallel_test.go b/pkg/runner/max_parallel_test.go index 5be2beae..515c34b2 100644 --- a/pkg/runner/max_parallel_test.go +++ b/pkg/runner/max_parallel_test.go @@ -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}, } diff --git a/pkg/runner/reusable_workflow.go b/pkg/runner/reusable_workflow.go index c0d079e5..56625824 100644 --- a/pkg/runner/reusable_workflow.go +++ b/pkg/runner/reusable_workflow.go @@ -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 { diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index ad97ca06..ea2c6362 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -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 diff --git a/pkg/runner/run_context_test.go b/pkg/runner/run_context_test.go index 7a7ffbaa..1ccba0e1 100644 --- a/pkg/runner/run_context_test.go +++ b/pkg/runner/run_context_test.go @@ -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) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index c79bfcd5..53cd9c97 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -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 diff --git a/pkg/runner/runner_max_parallel_test.go b/pkg/runner/runner_max_parallel_test.go index c1a7097f..7b5e47c9 100644 --- a/pkg/runner/runner_max_parallel_test.go +++ b/pkg/runner/runner_max_parallel_test.go @@ -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() diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index a73ab5f4..47f43d80 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -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) diff --git a/pkg/runner/step.go b/pkg/runner/step.go index d74a7567..7fd60026 100644 --- a/pkg/runner/step.go +++ b/pkg/runner/step.go @@ -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) } } diff --git a/pkg/runner/step_action_local.go b/pkg/runner/step_action_local.go index f8daf5cb..a50fb16c 100644 --- a/pkg/runner/step_action_local.go +++ b/pkg/runner/step_action_local.go @@ -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 diff --git a/pkg/runner/step_action_local_test.go b/pkg/runner/step_action_local_test.go index 8a80a1c6..ed125089 100644 --- a/pkg/runner/step_action_local_test.go +++ b/pkg/runner/step_action_local_test.go @@ -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) }) diff --git a/pkg/runner/step_action_remote.go b/pkg/runner/step_action_remote.go index 0fe5d62b..9eaf6dd8 100644 --- a/pkg/runner/step_action_remote.go +++ b/pkg/runner/step_action_remote.go @@ -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 } diff --git a/pkg/runner/step_action_remote_test.go b/pkg/runner/step_action_remote_test.go index 055f4c9d..4588d5a3 100644 --- a/pkg/runner/step_action_remote_test.go +++ b/pkg/runner/step_action_remote_test.go @@ -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) }) diff --git a/pkg/runner/step_docker.go b/pkg/runner/step_docker.go index 2f239866..fabe4418 100644 --- a/pkg/runner/step_docker.go +++ b/pkg/runner/step_docker.go @@ -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, diff --git a/pkg/runner/step_docker_test.go b/pkg/runner/step_docker_test.go index 3d90ac34..c10b5f46 100644 --- a/pkg/runner/step_docker_test.go +++ b/pkg/runner/step_docker_test.go @@ -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" ) diff --git a/pkg/runner/step_factory_test.go b/pkg/runner/step_factory_test.go index c981ef55..c00581af 100644 --- a/pkg/runner/step_factory_test.go +++ b/pkg/runner/step_factory_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/nektos/act/pkg/model" + "github.com/stretchr/testify/assert" ) diff --git a/pkg/runner/step_run.go b/pkg/runner/step_run.go index 054ed702..0b97b271 100644 --- a/pkg/runner/step_run.go +++ b/pkg/runner/step_run.go @@ -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 diff --git a/pkg/runner/step_run_test.go b/pkg/runner/step_run_test.go index fc5e6595..d80db4c9 100644 --- a/pkg/runner/step_run_test.go +++ b/pkg/runner/step_run_test.go @@ -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) { diff --git a/pkg/runner/step_test.go b/pkg/runner/step_test.go index e2882529..b1a0a903 100644 --- a/pkg/runner/step_test.go +++ b/pkg/runner/step_test.go @@ -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" diff --git a/pkg/workflowpattern/trace_writer.go b/pkg/workflowpattern/trace_writer.go index d5d990f6..675aa187 100644 --- a/pkg/workflowpattern/trace_writer.go +++ b/pkg/workflowpattern/trace_writer.go @@ -3,16 +3,16 @@ package workflowpattern import "fmt" type TraceWriter interface { - Info(string, ...interface{}) + Info(string, ...any) } type EmptyTraceWriter struct{} -func (*EmptyTraceWriter) Info(string, ...interface{}) { +func (*EmptyTraceWriter) Info(string, ...any) { } type StdOutTraceWriter struct{} -func (*StdOutTraceWriter) Info(format string, args ...interface{}) { +func (*StdOutTraceWriter) Info(format string, args ...any) { fmt.Printf(format+"\n", args...) } diff --git a/pkg/workflowpattern/workflow_pattern.go b/pkg/workflowpattern/workflow_pattern.go index cc03e405..f1324307 100644 --- a/pkg/workflowpattern/workflow_pattern.go +++ b/pkg/workflowpattern/workflow_pattern.go @@ -34,7 +34,7 @@ func CompilePattern(rawpattern string) (*WorkflowPattern, error) { }, nil } -//nolint:gocyclo +//nolint:gocyclo // function handles many cases func PatternToRegex(pattern string) (string, error) { var rpattern strings.Builder rpattern.WriteString("^") @@ -127,7 +127,7 @@ func PatternToRegex(pattern string) (string, error) { if errorMessage.Len() > 0 { 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()) }