Repository navigation
refactor: run the Go 1.27 modernizer (go fix) across the repo - #448
Conversation
Phase 3 of the SDK maturity plan asks for a modernizer pass per repo,
reviewed as its own PR. This is that pass for bomly-cli.
Tool: `go fix` from the Go 1.27.0 toolchain (cmd/fix, which since Go 1.26
carries the modernizer analyzers that used to live in gopls). Run as
`go fix -embedlit=false -omitzero=false -stringsbuilder=false ./...` after
reviewing every category in `-diff` mode first.
Categories applied (sites rewritten per analyzer):
63x slicescontains loop -> slices.Contains / slices.ContainsFunc
29x minmax if/else clamp -> min() / max()
28x rangeint 3-clause counting loop -> for range n
28x stringsseq range strings.Split -> strings.SplitSeq
22x mapsloop copy loop -> maps.Copy
8x stringscutprefix HasPrefix+TrimPrefix -> CutPrefix / CutSuffix
7x stditerators reflect NumField/Field(i) -> Type.Fields()
7x stringscut Index + slicing -> strings.Cut
6x reflecttypefor reflect.TypeOf(T{}) -> reflect.TypeFor[T]()
4x errorsastype errors.As -> errors.AsType[T]
4x slicesbackward reverse index loop -> slices.Backward
3x waitgroupgo Add/go/Done -> wg.Go
2x forvar drop redundant loop-variable re-declaration
1x any interface{} -> any
Declined, with the reason recorded next to the code where it will be
offered again:
- embedlit (119 sites): flattens `Coordinates: sdk.Coordinates{...}` into
the surrounding literal. Coordinates is a named identity concept
(dev-docs/MODELS.md, ADR-0041); the explicit wrapper is documentation,
not redundancy, and the rewrite also reflows multi-line literals badly.
- omitzero (2 sites): drops `omitempty` from struct-valued JSON fields in
golden- and schema-backed output types. No behavior gain, and it moves
a published output contract.
- stringsbuilder (2 sites): rewrites small bounded concatenations in the
TUI into strings.Builder while still concatenating inside WriteString.
- maps.Copy in mergeBunDependencyMaps: the parameter is named `maps`, so
the fix imports the package as `maps0`.
- max() in cycloneDXDocumentAssertions: swallows the ADR-0037 comment
that explains the default into the middle of the call.
No behavior changes. `make verify` passes (fmt, lint, vet on both build
variants, vet on the smoke tag, both builds, `go test ./...`, and
`make generate` with no docs drift).
Co-Authored-By: Claude Opus 5 <[email protected]>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (88)
💤 Files with no reviewable changes (2)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThis pull request modernizes Go code across detectors, pipelines, registries, output, TUI rendering, and tests. It adopts iterator APIs, collection helpers, reflection APIs, range-over-integer loops, and built-in bounds functions without intended behavior changes. ChangesGo API modernization
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~15 minutes Change: Refactor Merge Risk: ⚪ Minimal · up to The modernization changes preserve existing behavior across the reviewed parsing, rendering, collection, reflection, and concurrency paths, with no actionable merge risk identified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 100 functions across 50 files. (36 skipped: 36 over the file limit.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Bomly Diff SummaryCompared Overview
Dependency Changes✅ No dependency changes. Vulnerabilities✅ No vulnerability changes. License Changes✅ No license changes. Project Posture✅ No project posture changes ( Policy Findings✅ No policy differences were identified. |
Codex checked the merged pass and found my note wrong. #448 ran `go fix -embedlit=false -omitzero=false -stringsbuilder=false ./...` and I recorded one of the three, so an agent following the note would have reintroduced the other two -- a note that is worse than none, because it looks authoritative. omitzero is the one that matters. It drops omitempty from struct-valued JSON fields in golden- and schema-backed output types. The bytes do not move, so no test, linter or API gate objects -- and the tag is the published schema, so a consumer generating one by reflection starts reading the field as required. The SDK took that rewrite in its own pass and spent four review rounds undoing the consequences. The same analyzer was one command away from doing it here. Also says what `go fix` does: it applies in place, and `-diff` prints instead. A reader who assumed it previewed would find out afterwards. Co-Authored-By: Claude Opus 5 <[email protected]>
…451) * docs: record the declined modernizer analyzer in both guidance files The Go 1.27 modernizer pass here rejected the embedlit analyzer; the SDK's pass applied it. The same question went on record with two different answers, and undoing it cost 43 hunks in the SDK. Nothing mechanical objects to embedlit -- it is behaviour-identical and gorelease is indifferent -- so the only thing that can keep the two repositories agreeing is a written reason where the next run will look. Running `go fix ./...` without the flag proposes all 119 hunks here again, silently. Both CLAUDE.md and AGENTS.md carry it, since they are maintained as copies of each other, and bomly-sdk's AGENTS.md carries the matching note. [skip release] Co-Authored-By: Claude Opus 5 <[email protected]> * docs: record all three declined analyzers, not just the one Codex checked the merged pass and found my note wrong. #448 ran `go fix -embedlit=false -omitzero=false -stringsbuilder=false ./...` and I recorded one of the three, so an agent following the note would have reintroduced the other two -- a note that is worse than none, because it looks authoritative. omitzero is the one that matters. It drops omitempty from struct-valued JSON fields in golden- and schema-backed output types. The bytes do not move, so no test, linter or API gate objects -- and the tag is the published schema, so a consumer generating one by reflection starts reading the field as required. The SDK took that rewrite in its own pass and spent four review rounds undoing the consequences. The same analyzer was one command away from doing it here. Also says what `go fix` does: it applies in place, and `-diff` prints instead. A reader who assumed it previewed would find out afterwards. Co-Authored-By: Claude Opus 5 <[email protected]> --------- Co-authored-by: Claude Opus 5 <[email protected]>
Phase 3 of the SDK maturity plan (
dev-docs/SDK_MATURITY_PLAN.md) asks for a modernizer pass per repo, reviewed as its own PR. This is that pass forbomly-cli.Tool
go fixfrom the Go 1.27.0 toolchain — i.e.cmd/fix, which since Go 1.26 carries the modernizer analyzers that previously lived ingolang.org/x/tools/gopls/internal/analysis/modernize. There is no separatemodernizebinary to fetch on this toolchain;go tool fix helplists the 27 registered analyzers, andgo fix -diffprints the patch without applying it.Every category was reviewed in
-diffmode first, per analyzer, before anything was applied. The final command was:What changed
88 files, no behavior changes. Sites rewritten per analyzer:
slicescontainsslices.Contains/slices.ContainsFuncminmaxmin()/max()rangeintfor range nstringsseqrange strings.Split(...)→strings.SplitSeqmapsloopmaps.CopystringscutprefixHasPrefix+TrimPrefix→CutPrefix/CutSuffixstditeratorsreflectNumField/Field(i)→Type.Fields()stringscutIndex+ slicing →strings.Cutreflecttypeforreflect.TypeOf(T{})→reflect.TypeFor[T]()errorsastypeerrors.As→errors.AsType[T]slicesbackwardslices.BackwardwaitgroupgoAdd(1)/go/Done()→wg.Goforvaranyinterface{}→anystringsseqis the one with a real runtime effect: it drops the intermediate slice allocation in the lockfile and build-tool output parsers, which run per line over untrusted input.What was rejected
The three disabled analyzers, plus two individual hunks. Each declined hunk that
go fixwill offer again now carries a short comment at the call site saying so, so the next pass does not re-litigate it from scrollback.embedlit(119 sites) — flattensCoordinates: sdk.Coordinates{...}into the surrounding literal at all 119 sites.Coordinatesis a named identity concept (dev-docs/MODELS.md, ADR-0041); writing it explicitly is documentation, not redundancy. The rewrite also reflows multi-line literals badly (dangling})and lost key alignment), and it would churn 49 files — 4 of them underinternal/detectors/node/— for no behavior or performance gain.omitzero(2 sites) — dropsomitemptyfrom struct-valued JSON fields ininternal/output/view.goandinternal/benchmark/summary.go. The tool's own preferred fix (omitempty→omitzero) is a behavior change it declines to make; the fallback it does offer has no upside and moves a published output contract thatdocs/schemas/*and the goldens key on.stringsbuilder(2 sites) — rewrites small bounded TUI concatenations intostrings.Builderwhile still concatenating insideWriteString(" " + x). Readability loss, no allocation win.maps.CopyinmergeBunDependencyMaps(internal/detectors/node/bun/bun_lockfile_parser.go) — the variadic parameter is namedmaps, so the fix imports the stdlib package asmaps0. The explicit loop reads better than the alias.max()incycloneDXDocumentAssertions(internal/sbom/cyclonedx_assertions.go) — the rewrite hoists the ADR-0037 comment that explains the default into the middle of themax(...)call arguments.Golden-backed areas
internal/sbomandinternal/outputwere reviewed hunk by hunk. What landed there isslices.Contains,maps.Copy, andstrings.SplitSeqin lookup/clone helpers — nothing that touches field ordering, tags, or emitted values. Confirmed by the suite and bymake generateproducing no drift.Verification
make verifypasses end to end:fmt-check,golangci-lint(0 issues),go veton the default and lite build tags,go vet -tags smoke, both builds,go test ./..., andmake generatewith a cleangit diff -- docs/.Note for reviewers: overlap with the in-flight
internal/detectorswork19 files under
internal/detectors/are touched here, in case a concurrent branch is routing purl-type literals through the SDK:All of it is line-local (
slices.Contains,strings.Cut/CutPrefix,SplitSeq,maps.Copy,max()) inside parser and helper functions. Rejectingembedlitkept thesdk.Coordinatesliterals — the construct that branch is most likely editing — untouched.🤖 Generated with Claude Code
Summary by CodeRabbit
Refactor
Tests