Skip to content

Commit 60235c9

Browse files
authored
chore(ci): use golangci-lint (#167)
## Description Swaps over from `revive` to `golangci-lint` as it includes revive and is a much stronger linter + formatter. ## Related Issue Fixes #41 --------- Signed-off-by: Harry Randazzo <[email protected]>
1 parent 2d3105f commit 60235c9

23 files changed

+352
-188
lines changed

.github/CONTRIBUTING.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
```bash
2020
make test
2121
make lint
22-
make fmt
2322
```
2423

2524
5. Commit your changes.

.github/workflows/lint.yaml

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,40 @@ concurrency:
1818
cancel-in-progress: true
1919

2020
jobs:
21-
lint:
21+
detect-modules:
2222
runs-on: ubuntu-latest
23+
outputs:
24+
modules: ${{ steps.set-modules.outputs.modules }}
2325
steps:
2426
- name: Checkout
2527
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
2628

2729
- name: Install tools
2830
uses: ./.github/actions/install-tools
2931

30-
- name: ensure proper go formatting
31-
run: make check-fmt
32+
- id: set-modules
33+
run: |
34+
MODULES_JSON=$(find . -mindepth 2 -maxdepth 4 -type f -name 'go.mod' | cut -c 3- | sed 's|/go.mod$||' | sort -u | jq -R . | jq -c -s . || echo "[\".\"]")
35+
echo "modules=$MODULES_JSON" >> $GITHUB_OUTPUT
36+
echo "Found modules: $MODULES_JSON"
37+
38+
lint:
39+
needs: detect-modules
40+
runs-on: ubuntu-latest
41+
strategy:
42+
matrix:
43+
modules: ${{ fromJSON(needs.detect-modules.outputs.modules) }}
44+
steps:
45+
- name: Checkout
46+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
47+
48+
- name: Install tools
49+
uses: ./.github/actions/install-tools
3250

3351
- name: ensure all modules are on the same go version
3452
run: make check-go-version-consistency
3553

36-
- name: Run Revive Action by pulling pre-built image
37-
uses: docker://morphy/revive-action@sha256:087d4e61077087755711ab7e9fae3cc899b7bb07ff8f6a30c3dfb240b1620ae8 #v2.5.7
54+
- name: golangci-lint ${{ matrix.modules }}
55+
uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0
3856
with:
39-
config: revive.toml
40-
path: "./..."
57+
working-directory: ${{ matrix.modules }}

.golangci.yaml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
version: "2"
2+
linters:
3+
default: none
4+
enable:
5+
- errcheck
6+
- errorlint
7+
- goheader
8+
- govet
9+
- ineffassign
10+
- nolintlint
11+
- revive
12+
- staticcheck
13+
- testifylint
14+
- unused
15+
- whitespace
16+
settings:
17+
errcheck:
18+
check-type-assertions: true
19+
goheader:
20+
template: |-
21+
SPDX-License-Identifier: Apache-2.0
22+
SPDX-FileCopyrightText: 2024-Present Defense Unicorns
23+
govet:
24+
disable:
25+
- shadow
26+
- fieldalignment
27+
- unusedwrite
28+
- printf
29+
enable-all: true
30+
nolintlint:
31+
require-specific: true
32+
revive:
33+
rules:
34+
- name: blank-imports
35+
- name: context-as-argument
36+
- name: context-keys-type
37+
- name: dot-imports
38+
- name: error-return
39+
- name: error-strings
40+
- name: error-naming
41+
- name: exported
42+
- name: if-return
43+
- name: increment-decrement
44+
- name: var-naming
45+
- name: var-declaration
46+
- name: package-comments
47+
- name: range
48+
- name: receiver-naming
49+
- name: time-naming
50+
- name: unexported-return
51+
- name: indent-error-flow
52+
- name: errorf
53+
- name: empty-block
54+
- name: superfluous-else
55+
- name: unused-parameter
56+
- name: unreachable-code
57+
- name: redefines-builtin-id
58+
testifylint:
59+
enable-all: true
60+
exclusions:
61+
generated: lax
62+
presets:
63+
- common-false-positives
64+
- legacy
65+
- std-error-handling
66+
paths:
67+
- third_party$
68+
- builtin$
69+
- examples$
70+
formatters:
71+
enable:
72+
- goimports
73+
settings:
74+
goimports:
75+
local-prefixes:
76+
- github.com/defenseunicorns
77+
exclusions:
78+
generated: lax
79+
paths:
80+
- third_party$
81+
- builtin$
82+
- examples$

.pre-commit-config.yaml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,8 @@ repos:
2020

2121
- repo: local
2222
hooks:
23-
24-
- id: fmt
25-
name: go fmt
26-
entry: make fmt
27-
language: system
28-
pass_filenames: false
29-
3023
- id: lint
31-
name: go lint
24+
name: golangci-lint
3225
entry: make lint
3326
language: system
3427
pass_filenames: false

Makefile

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,23 @@ tidy:
1212
tidy-%:
1313
cd $(subst :,/,$*); go mod tidy
1414

15-
fmt:
16-
$(MAKE) $(addprefix fmt-, $(MODULES))
17-
18-
fmt-%:
19-
cd $(subst :,/,$*); go fmt ./...
20-
21-
check-fmt:
22-
$(MAKE) $(addprefix check-fmt-, $(MODULES))
23-
24-
check-fmt-%:
25-
cd $(subst :,/,$*); test -z "$$(gofmt -l .)"
26-
27-
vet:
28-
$(MAKE) $(addprefix vet-, $(MODULES))
29-
30-
vet-%:
31-
cd $(subst :,/,$*); go vet ./... ;\
32-
3315
test:
3416
$(MAKE) $(addprefix test-, $(MODULES))
3517

3618
test-%:
3719
cd $(subst :,/,$*); go test ./... -coverprofile cover.out ;
3820

3921
lint:
40-
revive -config revive.toml ./...
22+
$(MAKE) $(addprefix lint-, $(MODULES))
23+
24+
lint-fix:
25+
$(MAKE) $(addprefix lint-fix-, $(MODULES))
26+
27+
lint-%:
28+
cd $(subst :,/,$*); golangci-lint run ./...
29+
30+
lint-fix-%:
31+
cd $(subst :,/,$*); golangci-lint run --fix ./...
4132

4233
scan:
4334
$(MAKE) $(addprefix scan-, $(MODULES))

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ View the [`Makefile`](Makefile) for available targets.
2323

2424
```bash
2525
# Run all formatters
26-
make fmt
26+
make lint-fix
2727

2828
# Run all linters
2929
make lint
@@ -36,7 +36,7 @@ To run any of the above against an individual module, append `-<module name>` to
3636

3737
```bash
3838
# Run all formatters for the helpers module
39-
make fmt-helpers
39+
make lint-fix-helpers
4040

4141
# Run all linters for the helpers module
4242
make lint-helpers

hack/check_go_version.sh

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
set -euo pipefail
44

55
first_version=""
6-
# Find and iterate over all go.mod files, excluding the vendor directory
7-
find . -name go.mod | while read -r mod; do
6+
while read -r mod; do
87
current_version=$(grep '^go 1\.' "$mod" | cut -d ' ' -f 2)
98

109
if [[ -z "$first_version" ]]; then
11-
first_version=$current_version
10+
first_version=$current_version
1211
elif [[ "$current_version" != "$first_version" ]]; then
13-
echo "Inconsistency found: $mod uses Go version $current_version, this differs from another found version $first_version."
14-
exit 1
12+
echo "Inconsistency found: $mod uses Go version $current_version, this differs from another found version $first_version."
13+
exit 1
1514
fi
16-
done
15+
done < <(find . -name go.mod -not -path '*/vendor/*')
1716

1817
echo "All modules use the same Go version: $first_version."

helpers/files.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ func CreateFile(filepath string) error {
3838
}
3939

4040
return nil
41-
4241
}
4342

4443
// InvalidPath checks if the given path is valid (if it is a permissions error it is there we just don't have access)
@@ -68,7 +67,6 @@ func ListDirectories(directory string) ([]string, error) {
6867
// If skipHidden is true, hidden directories will be skipped.
6968
func RecursiveFileList(dir string, pattern *regexp.Regexp, skipHidden bool) (files []string, err error) {
7069
err = filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
71-
7270
// Return errors
7371
if err != nil {
7472
return err
@@ -132,11 +130,7 @@ func ReadFileByChunks(path string, chunkSizeBytes int) (chunks [][]byte, sha256s
132130
sha256sum = fmt.Sprintf("%x", sha256.Sum256(file))
133131

134132
// Loop over the tarball breaking it into chunks based on the payloadChunkSize
135-
for {
136-
if len(file) == 0 {
137-
break
138-
}
139-
133+
for len(file) != 0 {
140134
// don't bust slice length
141135
if len(file) < chunkSizeBytes {
142136
chunkSizeBytes = len(file)

helpers/misc.go

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func RetryWithContext(ctx context.Context, fn func() error, attempts int, delay
3333
var err error
3434
timer := time.NewTimer(0)
3535
defer timer.Stop()
36-
for r := 0; r < attempts; r++ {
36+
for r := range attempts {
3737
select {
3838
case <-ctx.Done():
3939
return ctx.Err()
@@ -92,17 +92,13 @@ func TransformAndMergeMap[T any](m1, m2 map[string]T, transform func(string) str
9292
}
9393

9494
// MergeMapRecursive recursively (nestedly) merges map m2 with m1 overwriting common values with m2's values.
95-
func MergeMapRecursive(m1, m2 map[string]interface{}) (r map[string]interface{}) {
96-
r = map[string]interface{}{}
97-
98-
for key, value := range m1 {
99-
r[key] = value
100-
}
95+
func MergeMapRecursive(m1, m2 map[string]any) (r map[string]any) {
96+
r = maps.Clone(m1)
10197

10298
for key, value := range m2 {
103-
if value, ok := value.(map[string]interface{}); ok {
99+
if value, ok := value.(map[string]any); ok {
104100
if nestedValue, ok := r[key]; ok {
105-
if nestedValue, ok := nestedValue.(map[string]interface{}); ok {
101+
if nestedValue, ok := nestedValue.(map[string]any); ok {
106102
r[key] = MergeMapRecursive(nestedValue, value)
107103
continue
108104
}
@@ -140,31 +136,42 @@ func IsNotZeroAndNotEqual[T any](given T, equal T) bool {
140136
return true
141137
}
142138

143-
for i := 0; i < givenValue.NumField(); i++ {
139+
for i := range givenValue.NumField() {
144140
if !givenValue.Field(i).IsZero() &&
145141
givenValue.Field(i).CanInterface() &&
146142
givenValue.Field(i).Interface() != equalValue.Field(i).Interface() {
147-
148143
return true
149144
}
150145
}
151146
return false
152147
}
153148

154149
// MergeNonZero is used to merge non-zero overrides from one struct into another of the same type
155-
func MergeNonZero[T any](original T, overrides T) T {
156-
originalValue := reflect.ValueOf(&original)
157-
overridesValue := reflect.ValueOf(&overrides)
150+
func MergeNonZero[T any](original, overrides T) T {
151+
// Create a copy of original that we'll modify
152+
result := original
158153

159-
for i := 0; i < originalValue.Elem().NumField(); i++ {
160-
if !overridesValue.Elem().Field(i).IsZero() &&
161-
overridesValue.Elem().Field(i).CanSet() {
154+
// Get reflect values, using the actual values not pointers to them
155+
resultValue := reflect.ValueOf(&result).Elem()
156+
overridesValue := reflect.ValueOf(overrides)
162157

163-
overrideField := overridesValue.Elem().Field(i)
164-
originalValue.Elem().Field(i).Set(overrideField)
158+
// Ensure we're working with structs
159+
if resultValue.Kind() != reflect.Struct || overridesValue.Kind() != reflect.Struct {
160+
return original // Can't merge non-structs
161+
}
162+
163+
// Iterate through fields
164+
for i := range resultValue.NumField() {
165+
resultField := resultValue.Field(i)
166+
overrideField := overridesValue.Field(i)
167+
168+
// Check if override field is non-zero and result field can be set
169+
if !overrideField.IsZero() && resultField.CanSet() {
170+
resultField.Set(overrideField)
165171
}
166172
}
167-
return originalValue.Elem().Interface().(T)
173+
174+
return result
168175
}
169176

170177
// MergePathAndValueIntoMap takes a path in dot notation as a string and a value (also as a string for simplicity),

0 commit comments

Comments
 (0)