Skip to content

Commit b308b6b

Browse files
authored
chore: Lint everything when linting (#5344)
* fix: Ensuring that we don't skip lints because of build flags * chore: Addressing ignored lints * chore: Lint on major OS'es * fix: Fixing cache paths for golangci-lint * fix: Ensure that it always runs in bash * fix: Windows, you had your chance * fix: Fixing typo
1 parent 84e1a0e commit b308b6b

11 files changed

+76
-27
lines changed

.github/workflows/lint.yml

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@ on:
55

66
jobs:
77
lint:
8-
runs-on: ubuntu-latest
8+
name: Lint (${{ matrix.os }})
9+
runs-on: ${{ matrix.os }}-latest
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
# Windows doesn't get to be linted continuously because it annoyingly requires
14+
# that all files use \r\n line endings.
15+
# os: [ubuntu, macos, windows]
16+
os: [ubuntu, macos]
917

1018
steps:
1119
- uses: actions/checkout@v6
1220

13-
- id: go-version
14-
run: |
15-
go version
16-
1721
- name: Set up mise
1822
uses: jdx/mise-action@v2
1923
with:
@@ -24,12 +28,25 @@ jobs:
2428
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2529

2630
- id: go-cache-paths
31+
shell: bash
2732
run: |
2833
echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
2934
echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
3035
31-
# TODO: Make this less brittle.
32-
echo "golanci-lint-cache=/home/runner/.cache/golangci-lint" >> "$GITHUB_OUTPUT"
36+
if [ "$RUNNER_OS" == "Windows" ]; then
37+
echo "golangci-lint-cache=$LOCALAPPDATA/golangci-lint" >> "$GITHUB_OUTPUT"
38+
exit 0
39+
fi
40+
41+
if [ "$RUNNER_OS" == "macOS" ]; then
42+
echo "golangci-lint-cache=$HOME/Library/Caches/golangci-lint" >> "$GITHUB_OUTPUT"
43+
exit 0
44+
fi
45+
46+
if [ "$RUNNER_OS" == "Linux" ]; then
47+
echo "golangci-lint-cache=$HOME/.cache/golangci-lint" >> "$GITHUB_OUTPUT"
48+
exit 0
49+
fi
3350
3451
- name: Go Build Cache
3552
uses: actions/cache@v5
@@ -46,7 +63,7 @@ jobs:
4663
- name: golangci-lint Cache
4764
uses: actions/cache@v5
4865
with:
49-
path: ${{ steps.go-cache-paths.outputs.golanci-lint-cache }}
66+
path: ${{ steps.go-cache-paths.outputs.golangci-lint-cache }}
5067
key: ${{ runner.os }}-golangci-lint-${{ hashFiles('**/go.sum') }}-linux-amd64
5168

5269
- name: Lint

Makefile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,19 @@ terragrunt: $(shell find . \( -type d -name 'vendor' -prune \) \
2525
clean:
2626
rm -f terragrunt
2727

28+
IGNORE_TAGS := windows|linux|darwin|freebsd|openbsd|netbsd|dragonfly|solaris|plan9|js|wasip1|aix|android|illumos|ios|386|amd64|arm|arm64|mips|mips64|mips64le|mipsle|ppc64|ppc64le|riscv64|s390x|wasm
29+
30+
LINT_TAGS := $(shell grep -rh 'go:build' . | \
31+
sed 's/.*go:build\s*//' | \
32+
tr -cs '[:alnum:]_' '\n' | \
33+
grep -vE '^($(IGNORE_TAGS))$$' | \
34+
sed '/^$$/d' | \
35+
sort -u | \
36+
paste -sd, -)
37+
2838
run-lint:
29-
golangci-lint run -v --timeout=10m ./...
39+
@echo "Linting with feature flags: [$(LINT_TAGS)]"
40+
GOFLAGS="-tags=$(LINT_TAGS)" golangci-lint run -v --timeout=10m ./...
3041

3142
run-strict-lint:
3243
golangci-lint run -v --timeout=10m -c .strict.golangci.yml --new-from-rev origin/main ./...

internal/tf/getproviders/lock_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func mockProviderUpdateLock(t *testing.T, ctrl *gomock.Controller, address, vers
3737
hasher := sha256.New()
3838
_, err := hasher.Write([]byte(packageName))
3939
require.NoError(t, err)
40+
4041
sha := hex.EncodeToString(hasher.Sum(nil))
4142
document += fmt.Sprintf("%s %s\n", sha, packageName)
4243
}

test/integration_aws_oidc_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ const (
4040
func TestAwsAssumeRoleWebIdentityFile(t *testing.T) {
4141
// t.Parallel() cannot be used together with t.Setenv()
4242
// t.Parallel()
43-
4443
token := fetchGitHubOIDCToken(t)
4544

4645
// These tests need to be run without the static key + secret
@@ -94,7 +93,6 @@ func TestAwsAssumeRoleWebIdentityFile(t *testing.T) {
9493
func TestAwsAssumeRoleWebIdentityFlag(t *testing.T) {
9594
// t.Parallel() cannot be used together with t.Setenv()
9695
// t.Parallel()
97-
9896
token := fetchGitHubOIDCToken(t)
9997

10098
// These tests need to be run without the static key + secret
@@ -121,7 +119,6 @@ func TestAwsAssumeRoleWebIdentityFlag(t *testing.T) {
121119
func TestAwsReadTerragruntAuthProviderCmdWithOIDC(t *testing.T) {
122120
// t.Parallel() cannot be used together with t.Setenv()
123121
// t.Parallel()
124-
125122
token := fetchGitHubOIDCToken(t)
126123

127124
t.Setenv("OIDC_TOKEN", token)
@@ -137,7 +134,6 @@ func TestAwsReadTerragruntAuthProviderCmdWithOIDC(t *testing.T) {
137134
func TestAwsReadTerragruntAuthProviderCmdWithOIDCRemoteState(t *testing.T) {
138135
// t.Parallel() cannot be used together with t.Setenv()
139136
// t.Parallel()
140-
141137
token := fetchGitHubOIDCToken(t)
142138

143139
// These tests need to be run without the static key + secret
@@ -223,23 +219,27 @@ func fetchGitHubOIDCToken(t *testing.T) string {
223219

224220
resp, err := client.Do(req)
225221
require.NoError(t, err, "Failed to execute OIDC token request to %s", requestURL)
222+
226223
defer resp.Body.Close()
227224

228225
if resp.StatusCode != http.StatusOK {
229226
bodyBytes, readErr := io.ReadAll(resp.Body)
230227
if readErr != nil {
231228
t.Fatalf("OIDC token request to %s failed with status %s. Additionally, failed to read response body: %v", requestURL, resp.Status, readErr)
232229
}
230+
233231
t.Fatalf("OIDC token request to %s failed with status %s. Response: %s", requestURL, resp.Status, string(bodyBytes))
234232
}
235233

236234
body, err := io.ReadAll(resp.Body)
237235
require.NoError(t, err, "Failed to read OIDC token response body from %s", requestURL)
238236

239237
var tokenResp oidcTokenResponse
238+
240239
err = json.Unmarshal(body, &tokenResp)
241240
require.NoError(t, err, "Failed to unmarshal OIDC token response JSON from %s. Response: %s", requestURL, string(body))
242241

243242
require.NotEmpty(t, tokenResp.Value, "OIDC token 'value' field is empty in response from %s. Response: %s", requestURL, string(body))
243+
244244
return tokenResp.Value
245245
}

test/integration_aws_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ func TestAwsBootstrapBackendWithoutVersioning(t *testing.T) {
294294
// Add skip_bucket_versioning to disable_versioning feature
295295
contents, err := util.ReadFileAsString(dualLockingConfigPath)
296296
require.NoError(t, err)
297+
297298
anchorText := " enable_lock_table_ssencryption = feature.enable_lock_table_ssencryption.value"
298299
require.Contains(t, contents, anchorText, "Expected anchor text not found in %s", dualLockingConfigPath)
299300
newContents := strings.ReplaceAll(contents, anchorText, anchorText+"\n skip_bucket_versioning = true")
@@ -315,6 +316,7 @@ func TestAwsBootstrapBackendWithoutVersioning(t *testing.T) {
315316
// Add skip_bucket_versioning for disable_versioning feature
316317
contents, err = util.ReadFileAsString(useLockfileConfigPath)
317318
require.NoError(t, err)
319+
318320
anchorText = " use_lockfile = true"
319321
require.Contains(t, contents, anchorText, "Expected anchor text not found in %s", useLockfileConfigPath)
320322
newContents = strings.ReplaceAll(contents, anchorText, anchorText+"\n skip_bucket_versioning = true")

test/integration_engine_test.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ func TestEngineChecksumVerification(t *testing.T) {
162162
// open the file and write some data
163163
file, err := os.OpenFile(fullPath, os.O_APPEND|os.O_WRONLY, 0600)
164164
require.NoError(t, err)
165+
165166
nonExecutableData := []byte{0x00}
166167
if _, err := file.Write(nonExecutableData); err != nil {
167168
require.NoError(t, err)
@@ -186,12 +187,14 @@ func TestEngineDisableChecksumCheck(t *testing.T) {
186187
if err != nil {
187188
return err
188189
}
190+
189191
if strings.HasSuffix(filepath.Base(path), "_SHA256SUMS") {
190192
// clean checksum list
191193
if err := os.Truncate(path, 0); err != nil {
192194
return err
193195
}
194196
}
197+
195198
return nil
196199
})
197200
require.NoError(t, err)
@@ -291,14 +294,14 @@ func TestNoEngineFlagDisablesEngine(t *testing.T) {
291294
rootPath := filepath.Join(tmpEnvPath, testFixtureOpenTofuEngine)
292295

293296
// First, verify engine is used when experiment is enabled
294-
stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --working-dir "+rootPath)
297+
_, stderr, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --working-dir "+rootPath)
295298
require.NoError(t, err)
296299
assert.Contains(t, stderr, "Tofu Initialization started")
297300
assert.Contains(t, stderr, "Tofu Initialization completed")
298301
assert.Contains(t, stderr, "Tofu Shutdown completed")
299302

300303
// Then, verify engine is NOT used when --no-engine flag is set
301-
stdout, stderr, err = helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --no-engine --working-dir "+rootPath)
304+
stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --no-engine --working-dir "+rootPath)
302305
require.NoError(t, err)
303306
assert.NotContains(t, stderr, "Tofu Initialization started")
304307
assert.NotContains(t, stderr, "Tofu Initialization completed")
@@ -313,14 +316,14 @@ func TestNoEngineFlagWithExperimentFlag(t *testing.T) {
313316
rootPath := filepath.Join(tmpEnvPath, testFixtureOpenTofuEngine)
314317

315318
// Verify engine is used when --experiment iac-engine is set
316-
stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --experiment iac-engine --working-dir "+rootPath)
319+
_, stderr, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --experiment iac-engine --working-dir "+rootPath)
317320
require.NoError(t, err)
318321
assert.Contains(t, stderr, "Tofu Initialization started")
319322
assert.Contains(t, stderr, "Tofu Initialization completed")
320323
assert.Contains(t, stderr, "Tofu Shutdown completed")
321324

322325
// Verify engine is NOT used when both --experiment iac-engine and --no-engine are set
323-
stdout, stderr, err = helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --experiment iac-engine --no-engine --working-dir "+rootPath)
326+
stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --non-interactive --tf-forward-stdout --experiment iac-engine --no-engine --working-dir "+rootPath)
324327
require.NoError(t, err)
325328
assert.NotContains(t, stderr, "Tofu Initialization started")
326329
assert.NotContains(t, stderr, "Tofu Initialization completed")
@@ -337,14 +340,14 @@ func TestNoEngineFlagWithRunAll(t *testing.T) {
337340
rootPath := filepath.Join(tmpEnvPath, testFixtureOpenTofuRunAll)
338341

339342
// Verify engine is used in run --all when experiment is enabled
340-
stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run --all --non-interactive --tf-forward-stdout --working-dir %s -- plan -no-color", rootPath))
343+
_, stderr, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run --all --non-interactive --tf-forward-stdout --working-dir %s -- plan -no-color", rootPath))
341344
require.NoError(t, err)
342345
assert.Contains(t, stderr, "Tofu Initialization started")
343346
assert.Contains(t, stderr, "Tofu Initialization completed")
344347
assert.Contains(t, stderr, "Tofu Shutdown completed")
345348

346349
// Verify engine is NOT used in run --all when --no-engine is set
347-
stdout, stderr, err = helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run --all --non-interactive --tf-forward-stdout --no-engine --working-dir %s -- plan -no-color", rootPath))
350+
stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run --all --non-interactive --tf-forward-stdout --no-engine --working-dir %s -- plan -no-color", rootPath))
348351
require.NoError(t, err)
349352
assert.NotContains(t, stderr, "Tofu Initialization started")
350353
assert.NotContains(t, stderr, "Tofu Initialization completed")
@@ -362,6 +365,7 @@ func setupEngineCache(t *testing.T) (string, string) {
362365
helpers.CleanupTerraformFolder(t, testFixtureOpenTofuRunAll)
363366
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureOpenTofuRunAll)
364367
rootPath := filepath.Join(tmpEnvPath, testFixtureOpenTofuRunAll)
368+
365369
return cacheDir, rootPath
366370
}
367371

@@ -379,12 +383,14 @@ func setupLocalEngine(t *testing.T) string {
379383
if err := os.MkdirAll(engineDir, 0755); err != nil {
380384
require.NoError(t, err)
381385
}
386+
382387
_, err := getter.GetAny(t.Context(), engineDir, downloadURL)
383388
require.NoError(t, err)
384389

385390
helpers.CopyAndFillMapPlaceholders(t, filepath.Join(testFixtureLocalEngine, "terragrunt.hcl"), filepath.Join(rootPath, config.DefaultTerragruntConfigPath), map[string]string{
386391
"__engine_source__": filepath.Join(engineDir, engineAssetName),
387392
})
393+
388394
return rootPath
389395
}
390396

@@ -394,5 +400,6 @@ func testEngineVersion() string {
394400
if !found {
395401
return "v0.0.16"
396402
}
403+
397404
return value
398405
}

test/integration_parse_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,11 @@ func TestParseFindListAllComponentsWithDAGAndExternal(t *testing.T) {
237237
if aDepLine >= 0 && bDepLine >= 0 {
238238
assert.Greater(t, aDepLine, bDepLine, "a-dependent should come after b-dependency")
239239
}
240+
240241
if dDepsLine >= 0 && bDepLine >= 0 {
241242
assert.Greater(t, dDepsLine, bDepLine, "d-dependencies-only should come after b-dependency")
242243
}
244+
243245
if cMixedLine >= 0 && aDepLine >= 0 && dDepsLine >= 0 {
244246
assert.Greater(t, cMixedLine, aDepLine, "c-mixed-deps should come after a-dependent")
245247
assert.Greater(t, cMixedLine, dDepsLine, "c-mixed-deps should come after d-dependencies-only")

test/integration_private_registry_test.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
package test_test
44

55
import (
6-
"fmt"
76
"net/url"
87
"os"
98
"path/filepath"
@@ -24,17 +23,17 @@ func setupPrivateRegistryTest(t *testing.T) (string, string, string) {
2423
registryToken := os.Getenv("PRIVATE_REGISTRY_TOKEN")
2524

2625
// the private registry test is recommended to be a clone of gruntwork-io/terraform-null-terragrunt-registry-test
27-
registryUrl := os.Getenv("PRIVATE_REGISTRY_URL")
26+
registryURL := os.Getenv("PRIVATE_REGISTRY_URL")
2827

29-
if registryToken == "" || registryUrl == "" {
28+
if registryToken == "" || registryURL == "" {
3029
t.Skip("Skipping test because it requires a valid Terraform registry token and url")
3130
}
3231

3332
helpers.CleanupTerraformFolder(t, privateRegistryFixturePath)
3433
tmpEnvPath := helpers.CopyEnvironment(t, privateRegistryFixturePath)
3534
rootPath := filepath.Join(tmpEnvPath, privateRegistryFixturePath)
3635

37-
URL, err := url.Parse("tfr://" + registryUrl)
36+
URL, err := url.Parse("tfr://" + registryURL)
3837
if err != nil {
3938
t.Fatalf("REGISTRY_URL is invalid: %v", err)
4039
}
@@ -44,7 +43,7 @@ func setupPrivateRegistryTest(t *testing.T) (string, string, string) {
4443
}
4544

4645
helpers.CopyAndFillMapPlaceholders(t, filepath.Join(privateRegistryFixturePath, "terragrunt.hcl"), filepath.Join(rootPath, "terragrunt.hcl"), map[string]string{
47-
"__registry_url__": registryUrl,
46+
"__registry_url__": registryURL,
4847
})
4948

5049
return rootPath, URL.Hostname(), registryToken
@@ -73,7 +72,7 @@ func TestPrivateRegistryWithEnvToken(t *testing.T) {
7372
// This is based on the tf/cliconfig/credentials.go collectCredentialsFromEnv
7473
host = strings.ReplaceAll(strings.ReplaceAll(host, ".", "_"), "-", "__")
7574

76-
t.Setenv(fmt.Sprintf("TF_TOKEN_%s", host), token)
75+
t.Setenv("TF_TOKEN_"+host, token)
7776

7877
_, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt init --non-interactive --log-level=trace --working-dir="+rootPath)
7978

test/integration_scaffold_ssh_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ SourceUrlType: "git-ssh"
112112
require.NoError(t, err)
113113
assert.Contains(t, stderr, "git::ssh://git@github.com/gruntwork-io/terragrunt.git//test/fixtures/inputs?ref=v0.67.4")
114114
assert.Contains(t, stderr, "Scaffolding completed")
115+
115116
content, err := util.ReadFileAsString(tmpEnvPath + "/terragrunt.hcl")
116117
require.NoError(t, err)
117118
assert.NotContains(t, content, "find_in_parent_folders")

test/integration_tflint_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func TestTflintInitSameModule(t *testing.T) {
9595
t.Cleanup(func() {
9696
helpers.RemoveFolder(t, rootPath)
9797
})
98+
9899
modulePath := filepath.Join(rootPath, testFixtureParallelRun)
99100
runPath := filepath.Join(rootPath, testFixtureParallelRun, "dev")
100101
appTemplate := filepath.Join(rootPath, testFixtureParallelRun, "dev", "app")
@@ -104,6 +105,7 @@ func TestTflintInitSameModule(t *testing.T) {
104105
err := util.CopyFolderContents(createLogger(), appTemplate, appPath, ".terragrunt-test", []string{}, []string{})
105106
require.NoError(t, err)
106107
}
108+
107109
helpers.RunTerragrunt(t, "terragrunt run --all init --log-level trace --non-interactive --working-dir "+runPath)
108110
}
109111

@@ -117,6 +119,7 @@ func TestTflintFindsNoIssuesWithValidCodeDifferentDownloadDir(t *testing.T) {
117119
t.Cleanup(func() {
118120
helpers.RemoveFolder(t, rootPath)
119121
})
122+
120123
modulePath := filepath.Join(rootPath, testFixtureTflintNoIssuesFound)
121124
err := helpers.RunTerragruntCommand(t, fmt.Sprintf("terragrunt plan --log-level trace --working-dir %s --download-dir %s", modulePath, downloadDir), out, errOut)
122125
require.NoError(t, err)
@@ -140,6 +143,7 @@ func TestTflintExternalTflint(t *testing.T) {
140143
t.Cleanup(func() {
141144
helpers.RemoveFolder(t, rootPath)
142145
})
146+
143147
runPath := filepath.Join(rootPath, testFixtureTflintExternalTflint)
144148
err := helpers.RunTerragruntCommand(t, "terragrunt plan --log-level trace --working-dir "+runPath, out, errOut)
145149
require.NoError(t, err)
@@ -156,6 +160,7 @@ func TestTflintTfvarsArePassedToTflint(t *testing.T) {
156160
t.Cleanup(func() {
157161
helpers.RemoveFolder(t, rootPath)
158162
})
163+
159164
runPath := filepath.Join(rootPath, testFixtureTflintTfvarPassing)
160165
err := helpers.RunTerragruntCommand(t, "terragrunt plan --log-level trace --working-dir "+runPath, out, errOut)
161166
require.NoError(t, err)
@@ -172,6 +177,7 @@ func TestTflintArgumentsPassedIn(t *testing.T) {
172177
t.Cleanup(func() {
173178
helpers.RemoveFolder(t, rootPath)
174179
})
180+
175181
runPath := filepath.Join(rootPath, testFixtureTflintArgs)
176182
err := helpers.RunTerragruntCommand(t, "terragrunt plan --log-level trace --working-dir "+runPath, out, errOut)
177183
require.NoError(t, err)
@@ -188,6 +194,7 @@ func TestTflintCustomConfig(t *testing.T) {
188194
t.Cleanup(func() {
189195
helpers.RemoveFolder(t, rootPath)
190196
})
197+
191198
runPath := filepath.Join(rootPath, testFixtureTflintCustomConfig)
192199
err := helpers.RunTerragruntCommand(t, "terragrunt plan --log-level trace --working-dir "+runPath, out, errOut)
193200
require.NoError(t, err)

0 commit comments

Comments
 (0)