Skip to content

Commit e66de90

Browse files
authored
lint: Use golangci-lint (#56)
Similarly to Zap, switch to using golangci-lint to run linters. In CI, lint will now run in a separate job than the tests. This obviates the need for staticcheck in tools/. Exclusions were added for lint rules that cannot be fixed in generated code. Specifically, revive was opted out for generated code in general because its pedantic style requirements cannot be met easily in generated code. <details> <summary>Lint issues fixed</summary> ``` cmd/cff/main.go:1:1: package-comments: should have a package comment (revive) internal/aquaregia_test.go:1:1: package-comments: should have a package comment (revive) internal/buildtag_test.go:224:17: Error return value of `io.WriteString` is not checked (errcheck) internal/buildtag_test.go:233:17: Error return value of `io.WriteString` is not checked (errcheck) internal/buildtag_test.go:234:17: Error return value of `io.WriteString` is not checked (errcheck) internal/emittertest/gen.go:1:1: package-comments: should have a package comment (revive) internal/flag/flag.go:1:1: package-comments: should have a package comment (revive) internal/flow_modifier.go:115:2: if-return: redundant if ...; err != nil check, just return error instead. (revive) internal/gen.go:221:10: Error return value of `w.Write` is not checked (errcheck) internal/gen.go:226:9: Error return value of `w.Write` is not checked (errcheck) internal/gen.go:394:13: Error return value of `format.Node` is not checked (errcheck) internal/gendirectives/main.go:64:17: Error return value of `out.Close` is not checked (errcheck) internal/gendirectives/main_test.go:15:20: Error return value of `os.RemoveAll` is not checked (errcheck) internal/gendirectives/main_test.go:53:20: Error return value of `os.RemoveAll` is not checked (errcheck) internal/modifier/concurrency.go:1:1: package-comments: should have a package comment (revive) internal/modifier/concurrency.go:44:2: if-return: redundant if ...; err != nil check, just return error instead. (revive) internal/modifier/factory.go:86:2: if-return: redundant if ...; err != nil check, just return error instead. (revive) internal/pkg/gopackages.go:1:1: package-comments: should have a package comment (revive) scheduler/scheduler_test.go:208:22: Error return value of `blocker.Run` is not checked (errcheck) scheduler/scheduler_test.go:268:22: Error return value of `blocker.Run` is not checked (errcheck) ``` </details>
1 parent 34284e1 commit e66de90

23 files changed

Lines changed: 295 additions & 199 deletions

File tree

.github/workflows/ci.yml

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,28 @@ on:
88

99
jobs:
1010

11-
# Checks that the generated code is up-to-date.
12-
# Runs in parallel with the other job that runs tests.
13-
check-generated:
14-
name: Check generated code
11+
lint:
12+
name: Lint
1513
runs-on: ubuntu-latest
1614

1715
steps:
18-
- name: Checkout code
19-
uses: actions/checkout@v4
20-
21-
- name: Setup Go
22-
uses: actions/setup-go@v4
16+
- uses: actions/checkout@v4
17+
name: Check out repository
18+
- uses: actions/setup-go@v4
19+
name: Set up Go
2320
with:
2421
go-version: 1.21.x
22+
cache: false # managed by golangci-lint
2523

26-
- name: Download Dependencies
27-
run: go mod download
24+
- uses: golangci/golangci-lint-action@v3
25+
name: Install golangci-lint
26+
with:
27+
version: latest
28+
args: --version # make lint will run the linter
2829

30+
# Verify that all generated code is up-to-date.
2931
- name: Regenerate code
3032
run: make generate
31-
3233
- name: Verify unchanged
3334
run: |
3435
if ! git diff --quiet; then
@@ -37,6 +38,9 @@ jobs:
3738
exit 1
3839
fi
3940
41+
- run: make lint
42+
name: Lint
43+
4044
build-test:
4145
name: Build and test
4246

@@ -45,10 +49,6 @@ jobs:
4549
matrix:
4650
os: ["ubuntu-latest"]
4751
go: ["1.20.x", "1.21.x"]
48-
include:
49-
- go: 1.21.x
50-
os: "ubuntu-latest"
51-
latest: true
5252

5353
steps:
5454
- name: Checkout code
@@ -62,10 +62,6 @@ jobs:
6262
- name: Download Dependencies
6363
run: go mod download
6464

65-
- name: Lint
66-
run: make lint
67-
if: matrix.latest
68-
6965
- name: Test
7066
run: make cover
7167

.golangci.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
output:
2+
# Make output more digestible with quickfix in vim/emacs/etc.
3+
sort-results: true
4+
print-issued-lines: false
5+
6+
linters:
7+
# We'll track the golangci-lint default linters manually
8+
# instead of letting them change without our control.
9+
disable-all: true
10+
enable:
11+
# golangci-lint defaults:
12+
- errcheck
13+
- gosimple
14+
- govet
15+
- ineffassign
16+
- staticcheck
17+
- unused
18+
19+
# Our own extras:
20+
- gofmt
21+
- nolintlint # lints nolint directives
22+
- revive
23+
24+
linters-settings:
25+
govet:
26+
# These govet checks are disabled by default, but they're useful.
27+
enable:
28+
- niliness
29+
- reflectvaluecompare
30+
- sortslice
31+
- unusedwrite
32+
33+
issues:
34+
# Print all issues reported by all linters.
35+
max-issues-per-linter: 0
36+
max-same-issues: 0
37+
38+
# Don't ignore some of the issues that golangci-lint considers okay.
39+
# This includes documenting all exported entities.
40+
exclude-use-default: false
41+
42+
exclude-rules:
43+
# Don't warn on unused parameters.
44+
# Parameter names are useful; replacing them with '_' is undesirable.
45+
- linters: [revive]
46+
text: 'unused-parameter: parameter \S+ seems to be unused, consider removing or renaming it as _'
47+
48+
# staticcheck already has smarter checks for empty blocks.
49+
# revive's empty-block linter has false positives.
50+
# For example, as of writing this, the following is not allowed.
51+
# for foo() { }
52+
- linters: [revive]
53+
text: 'empty-block: this block is empty, you can remove it'
54+
55+
# We're using a pretty pedantic style for revive.
56+
# Generated files cannot always comply with it, so omit them.
57+
- linters: [revive]
58+
path: '_gen.go$'
59+
60+
# Also opt-out revive for source files used in examples.
61+
# The contents of those source files affect the documentation,
62+
# so we want to control their contents.
63+
- linters: [revive]
64+
path: 'docs/ex/.*.go$'
65+
66+
# magic_gen has some generated code that writes to fields of a struct
67+
# that eventually goes unused.
68+
# This is a false positive -- that struct is intentionally unused.
69+
- linters: [govet]
70+
path: examples/magic_gen.go
71+
text: 'unusedwrite: unused write to field'

Makefile

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ MDOX = bin/mdox
1818
# We run that separately explicitly on a specific platform.
1919
COVER_MODULES ?= $(filter-out ./docs ./tools,$(MODULES))
2020

21+
# 'make lint' should not run on internal/tests or tools.
22+
LINT_MODULES ?= $(filter-out ./internal/tests ./tools,$(MODULES))
23+
2124
SRC_FILES = $(shell find . '(' -path './.*' -o -path '*test*' -o -path '*/examples/*' -o -path './docs/*' -prune ')' -o -name '*.go' -print)
2225

2326
# All go files are in scope for formatting -- even if they're generated.
@@ -66,20 +69,15 @@ fmt:
6669
@gofmt -w -l $(GOFMT_FILES)
6770

6871
.PHONY: lint
69-
lint: staticcheck checkfmt docs-check
70-
71-
.PHONY: staticcheck
72-
staticcheck: $(STATICCHECK)
73-
$(STATICCHECK) ./...
74-
75-
.PHONY: checkfmt
76-
checkfmt:
77-
@DIFF=$$(gofmt -d $(GOFMT_FILES)); \
78-
if [[ -n "$$DIFF" ]]; then \
79-
echo "--- gofmt would cause changes:"; \
80-
echo "$$DIFF"; \
81-
exit 1; \
82-
fi
72+
lint: golangci-lint docs-check
73+
74+
.PHONY: golangci-lint
75+
golangci-lint:
76+
@$(foreach mod,$(LINT_MODULES), \
77+
(cd $(mod) && \
78+
echo "[lint] golangci-lint: $(mod)" && \
79+
golangci-lint run --path-prefix $(mod)) &&) true
80+
8381

8482
.PHONY: docs
8583
docs:

cmd/cff/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
// cff is a library and code generator for Go
2+
// that makes it easy to write concurrent code.
3+
//
4+
// It allows you to write panic-safe code with bounded resource consumption,
5+
// operating on a complex dependency graph of interdependent tasks,
6+
// or a simple collection of independent tasks.
7+
//
8+
// See the documentation at https://uber-go.github.io/cff/ for more details.
19
package main
210

311
import (

examples/gen.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Package example holds test examples for cff.
2+
//
3+
// In the future, this may hold user-facing examples.
14
package example
25

36
//go:generate cff -file magic.go -genmode source-map .

examples/magic.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ type Response struct {
2121
MessageIDs []string
2222
}
2323

24-
type fooHandler struct {
24+
// FooHandler does things.
25+
type FooHandler struct {
2526
mgr *ManagerRepository
2627
users *UserRepository
2728
ses *SESClient
2829
}
2930

30-
func (h *fooHandler) HandleFoo(ctx context.Context, req *Request) (*Response, error) {
31+
// HandleFoo handles foo requests.
32+
func (h *FooHandler) HandleFoo(ctx context.Context, req *Request) (*Response, error) {
3133
var res *Response
3234
err := cff.Flow(ctx,
3335
cff.Params(req),
@@ -74,6 +76,9 @@ func (h *fooHandler) HandleFoo(ctx context.Context, req *Request) (*Response, er
7476
}),
7577
),
7678
)
79+
if err != nil {
80+
return nil, err
81+
}
7782

7883
err = cff.Parallel(
7984
ctx,
@@ -130,7 +135,11 @@ func (h *fooHandler) HandleFoo(ctx context.Context, req *Request) (*Response, er
130135
map[string]int{"a": 1, "b": 2, "c": 3},
131136
),
132137
)
133-
return res, err
138+
if err != nil {
139+
return nil, err
140+
}
141+
142+
return res, nil
134143
}
135144

136145
// ManagerRepository TODO

0 commit comments

Comments
 (0)