feat(normalize): add an opt-in vaar normalize command - #65
Nitjsefnie wants to merge 1 commit into
Conversation
lint --fix is strictly finding-scoped: each rule's fix half runs only when that rule actually reports a finding. A file with uniform CRLF (or lone CR) line endings has no line-ending finding, so --fix now leaves its endings alone by design. Add vaar normalize as the explicit opt-in surface for the blunt whole-file pass that behavior removed. It applies StripBOM, NormalizeLineEndings, TrimTrailingWhitespace, CollapseBlankLines and TrimFinalBlankLines unconditionally, honours --target and --target-dir, reports each rewritten path and skips files that are already normalized so repeated runs are stable. lint --fix semantics are untouched. Closes envaar#63 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds an opt-in ChangesDotenv normalization
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant normalize
participant lint.Normalize
participant DotenvFiles
User->>normalize: run normalize with optional target scope
normalize->>lint.Normalize: pass lint.Options
lint.Normalize->>DotenvFiles: discover and read dotenv files
lint.Normalize->>DotenvFiles: write changed normalized content
lint.Normalize-->>normalize: return rewritten paths
normalize-->>User: print normalized paths
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/cli/normalize.go`:
- Line 39: Update the normalize command’s Cobra argument configuration from
rejecting positional arguments to accepting path arguments, then pass those
arguments into the normalization scope used by the command. Revise
TestNormalizeCommandRejectsPositionalArguments to assert the new accepted-path
behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: dbdc82d2-2b1a-4b52-9456-e09f996302ad
📒 Files selected for processing (5)
internal/cli/normalize.gointernal/cli/normalize_test.gointernal/cli/root.gointernal/lint/normalize.gointernal/lint/normalize_test.go
There was a problem hiding this comment.
Pull request overview
Adds an opt-in vaar normalize CLI subcommand that performs a blunt, whole-file dotenv normalization pass (independent of lint findings), addressing the post-#54 gap where uniform CRLF/lone-CR files are intentionally untouched by lint --fix.
Changes:
- Introduces a
lint.NormalizeDatapipeline that always applies the canonical envfile transforms (BOM stripping, line ending normalization to LF, whitespace trimming, blank-line collapsing, final newline normalization). - Adds
lint.Normalize(opts)to discover target files and rewrite only when bytes change (idempotent; reports rewritten paths). - Adds
vaar normalizesubcommand with--target/--target-dirsupport and comprehensive unit/CLI tests covering the blunt-vs-scoped behavior and idempotence.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| internal/lint/normalize.go | Implements the unconditional normalization pipeline and file-rewrite loop with idempotent behavior and path reporting. |
| internal/lint/normalize_test.go | Tests blunt normalization vs finding-scoped fixes, full pipeline composition, rewrite reporting, and stability across runs. |
| internal/cli/root.go | Registers the new normalize subcommand on the root command. |
| internal/cli/normalize.go | Implements the Cobra subcommand, help text, and --target/--target-dir flag wiring, printing rewritten files to stdout. |
| internal/cli/normalize_test.go | End-to-end CLI tests for rewrite behavior, idempotence, scoping flags, and argument validation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Adds
vaar normalize— the blunt whole-file formatting pass, as its own opt-in surface.Why
Since #54 made
--fixstrictly finding-scoped, a uniform CRLF file produces no line-ending finding, so--fixcorrectly leaves it alone. This gives that normalization an explicit home instead of folding it back into--fix, so a blunt rewrite is always something you asked for by name.I went with a subcommand rather than a
--fix --normalizeflag because it matches howdiffis structured — samediscoverPathshandling, same--target/--target-dirshape, same report style.Closes #63
Type
None of the listed types fits cleanly — this adds a new CLI subcommand rather than a rule, parser or reporter change. Tell me which you'd file it under and I'll tick it.
Breaking change
lint --fixis untouched.Changes
internal/lint/normalize.go(+84) — composes the existingenvfiletransforms unconditionally: line endings (uniform CRLF and lone CR forced to LF), BOM, trailing whitespace, blank-run collapsinginternal/cli/normalize.go(+62) — the subcommand, with--target/--target-dirinternal/cli/root.go(+1) — registrationinternal/lint/normalize_test.go(+131),internal/cli/normalize_test.go(+169) — 11 new testsFiles already normalized are left byte-identical and produce no output, so it is idempotent and safe to run repeatedly.
User-visible changes
A new subcommand. On
KEY=value\r\nNEXT=2\r\n, verified end-to-end with the built binary:Validation
Commands run:
gofmt -w <touched Go files>—gofmt -lemptymake lintgo test ./...go run ./cmd/vaar lint ...Additional commands:
TestLintCommandTargetFileReportsUnreadablePathandTestLintCommandReturnsInternalErrorWhenDiscoveryFailsfail in my environment, but they fail identically on a clean checkout: I'm running as uid 0 andchmod 0doesn't block root. Unrelated to this change.Tests
11 new, covering the blunt-vs-scoped divergence at both the
NormalizeData/FixDatalevel and through the CLI (the regression guard for #54's behavior), the full transform pipeline on a BOM+CRLF+trailing-whitespace+blank-run fixture, already-normalized files left byte-identical, idempotence, and the--target/--target-dir/ both-flags-rejected / positional-args paths.They were checked against a revert rather than just observed passing: dropping
NormalizeLineEndingsfrom the pipeline produces 5 failures (got "KEY=value\r\nNEXT=2\r\n" want "KEY=value\nNEXT=2\n"), and removing the feature entirely fails them withundefined: lint.NormalizeData.The existing
--fixtests are unmodified and passing.No docs entry, since
diffdoesn't have one either — happy to add both if you'd like.Footer
Generated by Claude Opus 5 (implementation), Claude Opus 4.8 (brief, review)
Summary by CodeRabbit
normalizeCLI command for whole-file dotenv formatting.