Skip to content

build(ci): migrate .golangci.yml to v2 schema (closes #62)#89

Merged
dipto0321 merged 1 commit into
mainfrom
fix/ci/golangci-v2
Jul 3, 2026
Merged

build(ci): migrate .golangci.yml to v2 schema (closes #62)#89
dipto0321 merged 1 commit into
mainfrom
fix/ci/golangci-v2

Conversation

@dipto0321

Copy link
Copy Markdown
Owner

Summary

.golangci.yml targets the v2 schema (version: "2") — fixing the silent-parse-failure mode that made make lint and make ci completely unusable for any contributor with a current Homebrew (which ships v2.x by default today). CI bumps golangci/lint-action@v6 → @v8 and pins version: v2.12.2 to match what Homebrew installs locally. The Makefile lint target now checks for the binary and prints the exact go install ...@v2.12.2 command matching the CI pin when missing.

Same lint set + exclusion rules + presets that v1 ran with still apply — confirmed by make ci showing 0 issues locally on a Homebrew v2.12.2 install.

Linked issues

Closes #62

Type of change

  • feat — new feature (MINOR bump)
  • fix — bug fix (PATCH bump)
  • refactor — no behavior change
  • perf — performance improvement
  • docs — documentation only
  • test — tests only
  • chore — maintenance / dependency bump
  • ci — CI/CD only
  • build — build system only
  • Breaking change (MAJOR bump) — explain below

Checklist

  • Title follows Conventional Commits (feat(scope): subject)
  • I ran make ci locally and it passes (tidy/fmt/vet/lint/test all green, 0 lint issues)
  • I added or updated tests for the change (not applicable — CI schema change)
  • I updated relevant docs (README, docs/, inline comments)
  • No new linter warnings
  • If breaking: I documented the migration path in the PR body and updated CHANGELOG.md

Screenshots / output

Pre-fix reproduction (Homebrew's stock v2.12.2):

$ make lint
golangci-lint run ./...
Error: can't load config: can't unmarshal config by viper (flags, file): 1 error(s) decoding:

* 'output.formats' expected a map, got 'slice'
The command is terminated due to an error: can't load config: can't unmarshal config by viper (flags, file): 1 error(s) decoding:

* 'output.formats' expected a map, got 'slice'
make: *** [lint] Error 3

make ci had the same blocker (lint is in its dependency chain), so the documented local-dev workflow was effectively broken for any contributor with Homebrew's current default — they could only run vet/test, never lint.

Post-fix (same Homebrew v2.12.2):

$ make ci
go mod tidy
gofmt -s -w .
goimports not installed, skipping (...)
go vet ./...
golangci-lint run ./...
0 issues.
go test -race -coverprofile=coverage.out -covermode=atomic ./...
ok  	github.com/dipto0321/nodeup/internal/cli	coverage: 29.2%
ok  	github.com/dipto0321/nodeup/internal/config	coverage: 81.0%
ok  	github.com/dipto0321/nodeup/internal/detector	coverage: 76.8%
ok  	github.com/dipto0321/nodeup/internal/node	coverage: 71.5%
ok  	github.com/dipto0321/nodeup/internal/packages	coverage: 37.4%
ok  	github.com/dipto0321/nodeup/internal/platform	coverage: 55.6%

Missing-binary case (handy because contributors won't always have golangci-lint installed):

$ make lint
golangci-lint not installed.
Install the version pinned in .github/workflows/ci.yml with:
  go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2
(or update both this Makefile and ci.yml together when bumping).
make: *** [lint] Error 1

Files touched

  • .golangci.yml — migrated to the v2 schema with golangci-lint migrate. Top-of-file comments (which migrate warns it strips) were re-added by hand to preserve the rationale for the lint set + exclusion paths. Schema-level diff:
    • version: "2" field added.
    • output.formats is now a map (text:), not a list — fixing the v1-vs-v2 parse failure.
    • linters.disable-all: truelinters.default: none.
    • linters-settings:linters.settings:.
    • gofmt / goimports moved from linters.enable: into a new top-level formatters: block (v2's grammar for fmt-vs-lint).
    • goimports.local-prefixes is now a list, not a single string.
    • New linters.exclusions: block preserves v1's per-rule exclusions (test files, windows-only symbols, upgrade.go cross-file refs) and adds v2's presets: [comments, common-false-positives, legacy, std-error-handling] for the broader exclusion grammar.
    • gosimple is removed from enable: (folded into staticcheck in v2). Everything else (bodyclose, contextcheck, errcheck, gocritic, govet, ineffassign, misspell, staticcheck, unused) stays.
  • .github/workflows/ci.yml
  • Makefilelint: target now checks for the binary first; if missing, prints the exact go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 command (matching the CI pin) so a missing-install surfaces a fix-it hint, not an exec failure.
  • CHANGELOG.md### Fixed entry under [Unreleased] documenting the migration with the build(lint): .golangci.yml v1 schema incompatible with golangci-lint v2 (brew installs v2, make lint fails to even parse config) #62 reference.

The pre-fix .golangci.yml targeted the golangci-lint v1 schema
(no `version:` field, flat `linters.enable`, `output.formats`
as a slice). The Makefile told contributors to `brew install
golangci-lint` — which installs the current major version,
v2.x, today. Any contributor with a current Homebrew got:

  Error: can't load config: can't unmarshal config by viper
  (flags, file): 1 error(s) decoding:
  * 'output.formats' expected a map, got 'slice'

… instead of a lint failure, blocking `make lint` and
`make ci` end-to-end. CI was unaffected because the GitHub
Action pinned to v1.64.8, but the local dev workflow was
effectively broken for anyone following the documented install
steps.

Migration via `golangci-lint migrate` plus a hand-rewrite
to preserve the descriptive comments (migrate strips them).
Net schema changes:

- `version: "2"` added
- `output.formats` is now a map (`text:`), not a list
- `linters.disable-all: true` → `linters.default: none`
- `gofmt` / `goimports` linters moved into the new
  `formatters:` section (with `local-prefixes` now a list)
- `linters-settings:` → `linters.settings:`
- New `linters.exclusions:` block with the same per-rule
  exclusions the v1 file had (test files, windows-only
  files, upgrade.go cross-file refs), plus a presets list
  (`comments`, `common-false-positives`, `legacy`,
  `std-error-handling`) for v2's broader exclusion grammar

gosimple was folded into staticcheck in v2; the linters list
is otherwise the same (bodyclose, contextcheck, errcheck,
gocritic, govet, ineffassign, misspell, staticcheck, unused).

CI bumps:

- golangci/golangci-lint-action@v6 → @v8
- version: v1.64.8 → v2.12.2 (matches the version Homebrew
  currently ships, so local `make lint` agrees byte-for-byte
  with CI)

Makefile `lint` target now checks for the binary and prints
the exact `go install github.com/golangci/golangci-lint/v2/...
@v2.12.2` command matching the CI pin when it's missing —
so a contributor without golangci-lint gets a fix-the-install
hint instead of a confusing exec failure.

Confirmed locally: `make ci` is now green on a Homebrew
v2.12.2 install (lint + vet + test all pass, 0 issues).

Refs #62
@cocogitto-bot

cocogitto-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

✔️ b00b991 - Conventional commits check succeeded.

@dipto0321 dipto0321 merged commit e02ee9c into main Jul 3, 2026
10 checks passed
@dipto0321 dipto0321 deleted the fix/ci/golangci-v2 branch July 3, 2026 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build(lint): .golangci.yml v1 schema incompatible with golangci-lint v2 (brew installs v2, make lint fails to even parse config)

1 participant