Skip to content

Commit fa89418

Browse files
committed
Move analyzer to golangci-lint-v2's module system.
1 parent 08d7587 commit fa89418

File tree

13 files changed

+213
-72
lines changed

13 files changed

+213
-72
lines changed

.custom-gcl.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
version: v2.0.2
2+
destination: .
3+
plugins:
4+
- module: 'github.com/cschleiden/go-workflows/analyzer'
5+
path: ./analyzer

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
vendor
66
plugin.so
77

8-
web/app/node_modules
8+
web/app/node_modules
9+
10+
custom-gcl

.golangci.yml

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,52 @@
1+
version: "2"
2+
13
run:
2-
tests: false
4+
allow-parallel-runners: true
35

46
linters:
57
enable:
6-
- goworkflows
7-
8-
linters-settings:
9-
custom:
10-
goworkflows:
11-
path: ./plugin.so
12-
description: go-workflows
13-
original-url: github.com/cschleiden/go-workflows/analyzer
8+
- bidichk
9+
- bodyclose
10+
- errcheck
11+
- errname
12+
- errorlint
13+
- goprintffuncname
14+
- govet
15+
- importas
16+
- ineffassign
17+
- makezero
18+
- prealloc
19+
- predeclared
20+
- promlinter
21+
- rowserrcheck
22+
- staticcheck
23+
- tagalign
24+
- testifylint
25+
- tparallel
26+
- unconvert
27+
- usetesting
28+
- wastedassign
29+
- whitespace
30+
- unused
31+
- goworkflows
32+
settings:
33+
staticcheck:
34+
checks:
35+
- "all"
36+
- "-ST1003"
37+
custom:
38+
goworkflows:
39+
type: "module"
40+
original-url: "github.com/cschleiden/go-workflows/analyzer"
41+
settings:
42+
checkprivatereturnvalues: true
43+
44+
45+
formatters:
46+
enable:
47+
- gofmt
48+
- goimports
49+
settings:
50+
goimports:
51+
local-prefixes:
52+
- "github.com/cschleiden/go-workflows"

.vscode/settings.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
// Some integration tests take quite long to run, increase the overall limit for now
3-
"go.testFlags": ["-timeout", "120s", "-race", "-count", "1" , "-short"],
3+
"go.testFlags": ["-timeout", "120s", "-race", "-count", "1", "-short"],
44
"files.exclude": {
55
"**/.git": true,
66
"**/.svn": true,
@@ -13,6 +13,9 @@
1313
"github-actions.workflows.pinned.workflows": [],
1414
"go.testExplorer.showDynamicSubtestsInEditor": true,
1515
"go.lintTool": "golangci-lint-v2",
16-
"Lua.diagnostics.globals": ["KEYS", "ARGV", "redis", "cjson"],
17-
16+
// "go.lintFlags": ["--path-mode=abs", "--fast-only"],
17+
// "go.alternateTools": {
18+
// "golangci-lint-v2": "${workspaceFolder}/custom-gcl"
19+
// },
20+
"Lua.diagnostics.globals": ["KEYS", "ARGV", "redis", "cjson"]
1821
}

Makefile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ GOGET=$(GOCMD) get
99
GOMOD=$(GOCMD) mod
1010
GOFMT=gofmt
1111
GOLINT=golangci-lint
12+
CUSTOM_GOLINT=./custom-gcl
1213

1314
# Test parameters
1415
TEST_TIMEOUT=240s
@@ -59,12 +60,16 @@ test-monoprocess:
5960
# Run all backend tests
6061
test-backends: test-redis test-mysql test-sqlite test-monoprocess
6162

62-
# Lint the code
63-
lint:
63+
custom-gcl:
6464
@echo "Checking if golangci-lint is installed..."
6565
@which $(GOLINT) > /dev/null || (echo "golangci-lint is not installed. Please install it first." && exit 1)
66+
@echo "Building custom linter plugin..."
67+
$(GOLINT) custom
68+
69+
# Lint the code
70+
lint: custom-gcl
6671
@echo "Running linter..."
67-
$(GOLINT) run
72+
$(CUSTOM_GOLINT) run
6873

6974
# Format the code
7075
fmt:

analyzer/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,18 @@
22

33
This package implements a basic analyzer for checking various common workflow error conditions.
44

5-
It can be used with golangci-lint as a custom linter to provide feedback in editors or in CI runs.
5+
In your own .golangci.yaml configuration file, you can enable it like this:
6+
7+
```yaml
8+
version: "2"
9+
10+
linters:
11+
enable:
12+
- goworkflows
13+
14+
settings:
15+
custom:
16+
goworkflows:
17+
type: module
18+
original-url: github.com/cschleiden/go-workflows/analyzer
19+
```

analyzer/analyzer.go

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,55 @@ import (
44
"go/ast"
55
"go/types"
66

7+
"github.com/golangci/plugin-module-register/register"
78
"golang.org/x/tools/go/analysis"
89
"golang.org/x/tools/go/analysis/passes/inspect"
910
"golang.org/x/tools/go/ast/inspector"
1011
)
1112

12-
var checkPrivateReturnValues bool
13+
func init() {
14+
register.Plugin("goworkflows", New)
15+
}
1316

14-
func New() *analysis.Analyzer {
15-
a := &analysis.Analyzer{
16-
Name: "goworkflows",
17-
Doc: "Checks for common errors when writing workflows",
18-
Run: run,
19-
Requires: []*analysis.Analyzer{inspect.Analyzer},
17+
func New(settings any) (register.LinterPlugin, error) {
18+
// The configuration type will be map[string]any or []interface, it depends on your configuration.
19+
// You can use https://github.com/go-viper/mapstructure to convert map to struct.
20+
s, err := register.DecodeSettings[Settings](settings)
21+
if err != nil {
22+
return nil, err
2023
}
2124

22-
a.Flags.BoolVar(&checkPrivateReturnValues, "checkprivatereturnvalues", false, "Check return values of workflows which aren't exported")
25+
return &GoWorkflowsPlugin{Settings: s}, nil
26+
}
27+
28+
type GoWorkflowsPlugin struct {
29+
Settings Settings
30+
}
31+
32+
type Settings struct {
33+
CheckPrivateReturnValues bool `json:"checkprivatereturnvalues"`
34+
}
35+
36+
func (w *GoWorkflowsPlugin) BuildAnalyzers() ([]*analysis.Analyzer, error) {
37+
return []*analysis.Analyzer{
38+
{
39+
Name: "goworkflows",
40+
Doc: "Checks for common errors when writing workflows",
41+
Run: w.run,
42+
Requires: []*analysis.Analyzer{inspect.Analyzer},
43+
},
44+
}, nil
45+
}
46+
47+
func (w *GoWorkflowsPlugin) GetLoadMode() string {
48+
// NOTE: the mode can be `register.LoadModeSyntax` or `register.LoadModeTypesInfo`.
49+
// - `register.LoadModeSyntax`: if the linter doesn't use types information.
50+
// - `register.LoadModeTypesInfo`: if the linter uses types information.
2351

24-
return a
52+
return register.LoadModeSyntax
2553
}
2654

27-
func run(pass *analysis.Pass) (interface{}, error) {
55+
func (w *GoWorkflowsPlugin) run(pass *analysis.Pass) (interface{}, error) {
2856
inspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
2957

3058
// Expect workflows to be top level functions in a file. Therefore it should be enough to just keep track if the current
@@ -84,7 +112,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
84112
inWorkflow = true
85113

86114
// Check return types
87-
if n.Name.IsExported() || checkPrivateReturnValues {
115+
if n.Name.IsExported() || w.Settings.CheckPrivateReturnValues {
88116
if n.Type.Results == nil || len(n.Type.Results.List) == 0 {
89117
pass.Reportf(n.Pos(), "workflow `%v` doesn't return anything. needs to return at least `error`", n.Name.Name)
90118
} else {

analyzer/analyzer_test.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,39 @@ package analyzer
33
import (
44
"testing"
55

6+
"github.com/golangci/plugin-module-register/register"
67
"github.com/stretchr/testify/require"
78
"golang.org/x/tools/go/analysis/analysistest"
89
)
910

1011
func TestAll(t *testing.T) {
11-
a := New()
12-
a.Flags.Set("checkprivatereturnvalues", "true")
13-
analysistest.Run(t, analysistest.TestData(), a, "p", "q")
12+
newPlugin, err := register.GetPlugin("goworkflows")
13+
require.NoError(t, err)
14+
15+
plugin, err := newPlugin(map[string]any{
16+
"checkprivatereturnvalues": true,
17+
})
18+
require.NoError(t, err)
19+
20+
analyzers, err := plugin.BuildAnalyzers()
21+
require.NoError(t, err)
22+
23+
analysistest.Run(t, analysistest.TestData(), analyzers[0], "p", "q")
1424
}
1525

1626
func TestComplex(t *testing.T) {
17-
a := New()
18-
a.Flags.Set("checkprivatereturnvalues", "true")
19-
result := analysistest.Run(t, analysistest.TestData(), a, "q")
27+
newPlugin, err := register.GetPlugin("goworkflows")
28+
require.NoError(t, err)
29+
30+
plugin, err := newPlugin(map[string]any{
31+
"checkprivatereturnvalues": true,
32+
})
33+
require.NoError(t, err)
34+
35+
analyzers, err := plugin.BuildAnalyzers()
36+
require.NoError(t, err)
37+
38+
result := analysistest.Run(t, analysistest.TestData(), analyzers[0], "q")
2039
for _, r := range result {
2140
require.NoError(t, r.Err)
2241
require.Equal(t, 1, len(r.Diagnostics))

analyzer/go.mod

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module github.com/cschleiden/go-workflows/analyzer
2+
3+
go 1.24.5
4+
5+
require (
6+
github.com/golangci/plugin-module-register v0.1.2
7+
github.com/stretchr/testify v1.10.0
8+
golang.org/x/tools v0.37.0
9+
)
10+
11+
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/pmezard/go-difflib v1.0.0 // indirect
14+
golang.org/x/mod v0.28.0 // indirect
15+
golang.org/x/sync v0.17.0 // indirect
16+
gopkg.in/yaml.v3 v3.0.1 // indirect
17+
)

analyzer/go.sum

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg=
4+
github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw=
5+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
6+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
7+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
8+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
9+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
10+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
11+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
12+
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
13+
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
14+
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
15+
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
16+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
17+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
18+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
19+
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
20+
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
21+
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
22+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
23+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
24+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
25+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)