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

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

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

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

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

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

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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(&currentRunning, 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(&currentRunning, -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(&currentRunning, 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(&currentRunning, -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")
}

View File

@@ -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(&currentRunning, 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(&currentRunning, -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(&currentRunning, 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(&currentRunning, -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(&currentRunning, 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(&currentRunning, -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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))