Skip to content

chore: upgrade to Go 1.27 and golangci-lint 2.13.1 - #1830

Open
swwind wants to merge 12 commits into
mainfrom
chore/upgrade-go-1.27
Open

chore: upgrade to Go 1.27 and golangci-lint 2.13.1#1830
swwind wants to merge 12 commits into
mainfrom
chore/upgrade-go-1.27

Conversation

@swwind

@swwind swwind commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Moves the toolchain to Go 1.27 and golangci-lint v2.13.1, and takes the three cleanups that unblocks.

Toolchain

  • go.mod and go.work move to go 1.27.0, with go.work's toolchain line following. shim/* and the typescript-go submodule stay on go 1.26.
  • All 15 go-version pins across the workflows move to 1.27.0.
  • golangci-lint moves to v2.13.1, the first release built with go1.27; 2.12.x refuses to load a module targeting 1.27 at all.

internal/utils/unicode17 is deleted

The package carried the case mappings, foldings and general categories Unicode 16 and 17 added on top of the 15.0 tables Go 1.26 shipped, and named go1.27 as the release that would retire it. Go 1.27 is unicode.Version 17.0.0 and golang.org/x/text/cases selects its own 17.0.0 tables under //go:build go1.27. That is what ties the deletion to the go directive bump: built on 1.26, the same code silently reads Unicode 15.

A rule now asks the standard library for a general category directly. depguard no longer denies unicode under internal/rules/** and internal/plugins/**, and forbidigo denies the calls that still disagree with JavaScript: unicode.To*, SimpleFold and IsSpace.

esregexp.buildCaseTables walks a patched copy of unicode.CaseRanges. Six characters whose only uppercase is a sequence — ΐ, ΰ, ſt, st — have no case range of their own, yet simple case folding still brings each onto another character, so a walk over the standard library's table alone cannot reach them.

SA5011 workarounds reverted

#1337, #1441 and #1448 added return after t.Fatal/t.Fatalf in test nil guards to silence staticcheck SA5011 false positives from golangci-lint v2.12.2. The cause is fixed in v2.13.0, so the 76 dead returns are gone.

golangci-lint fmt now formats

v2 keeps formatters in their own top-level section, which this config never had, so golangci-lint fmt was a no-op and 82 files under cmd/ and internal/ had drifted out of gofmt. formatters.enable gets gofmt, and those files are formatted. Four doc comments held JavaScript snippets whose quoting gofmt rewrites, and are reworded to survive it.

The CI step ran the formatter in write mode, where it can never fail; it now runs --diff. errcheck and paralleltest leave the enable list, which the disable block above it had been overriding all along.

Related Links

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

swwind added 9 commits August 21, 2026 14:04
Go 1.27's unicode tables are Unicode 17.0.0 and golang.org/x/text/cases
selects its own 17.0.0 tables under //go:build go1.27, so the delta
internal/utils/unicode17 carried on top of Go 1.26's Unicode 15.0 tables
is gone. Its category predicates move to internal/utils/ecmascript, which
keeps depguard denying the standard library's unicode under a rule.
Go 1.27's unicode tables are the edition Node reads, so a rule asks
unicode.IsLetter and its siblings directly. depguard no longer denies the
package; forbidigo denies the calls that still disagree with JavaScript,
which are unicode.To*, SimpleFold and IsSpace.

buildCaseTables walks a patched copy of unicode.CaseRanges rather than that
table plus a second list: the six characters whose only uppercase is a
sequence have no case range of their own, yet still fold onto another
character.
v2 keeps formatters in their own top-level section, which this config never
had, so golangci-lint fmt was a no-op and 82 files under cmd/ and internal/
had drifted out of gofmt. Enable gofmt there and format them.

Four doc comments held JavaScript snippets whose quoting gofmt rewrites --
'' becomes a closing curly quote, as does a doubled backtick -- so they are
reworded to survive the formatter.

CI ran the formatter in write mode, where it can never fail; it now runs
--diff. errcheck and paralleltest leave the enable list, which the disable
block above it had been overriding all along.
… had

internal/fourslash lives in the typescript-go submodule, which is a module
of its own and outside the ./cmd/... ./internal/... scope this config is
ever run against.
@swwind
swwind marked this pull request as ready for review August 21, 2026 07:21
Copilot AI lite review requested due to automatic review settings August 21, 2026 07:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@swwind
swwind requested a review from elecmonkey August 21, 2026 08:40

@elecmonkey elecmonkey left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The toolchain and Unicode changes otherwise appear behaviorally consistent, but the upgraded lint tool causes the required Lint&Check job to fail deterministically with five staticcheck errors. The patch is therefore not currently mergeable.

  • [P1] Resolve SA1019 errors exposed by v2.13.1 — .github/workflows/ci.yml:126
    With this version pinned, every Lint&Check run fails before reaching the remaining checks: staticcheck reports five SA1019 errors for deprecated ESModuleInterop and RangeLength fields in internal/config/all_rules_test.go, internal/lsp/document_changes_test.go, and internal/plugins/import/utils/export_map_test.go. Update or explicitly suppress those usages as part of the upgrade so the required CI job can pass.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 21, 2026

Copy link
Copy Markdown

Deploying rslint with  Cloudflare Pages  Cloudflare Pages

Latest commit: 34aef04
Status:🚫  Build failed.

View logs

@swwind

swwind commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author
  • Resolve SA1019 errors

Added //nolint to bypass check on those lines.

@swwind

swwind commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Go 1.26 → Go 1.27 benchmark results

I benchmarked the same PR source (c53fc204) with the exact Go 1.26.0 and Go 1.27.0 toolchains. For the Go 1.26 builds, only the go.mod/go.work version declarations were temporarily lowered; they were restored before the Go 1.27 builds.

Focused Go benchmarks

GOMAXPROCS=8 go test -run='^$' -bench='.' -benchtime=2s -count=8 ./tests/bench-go/
Benchmark Go 1.26 Go 1.27 Change
Linter syntax rules 225.8 µs 230.0 µs +1.87% (p=0.001)
Type-aware rules 481.7 µs 490.6 µs No significant change (p=0.234)
Semantic diagnostics 4.535 ms 4.585 ms +1.11% (p=0.038)
Geomean 790.1 µs 802.8 µs +1.61%

A second interleaved confirmation using prebuilt benchmark binaries, ten paired samples, and a one-second benchmark time produced:

Benchmark Change
Linter syntax rules +2.07% (p=0.043)
Type-aware rules +1.77% (p=0.005)
Semantic diagnostics No significant change (p=0.971)
Geomean +1.50%

Bytes allocated per operation were unchanged. Allocation counts were unchanged for syntax and type-aware linting; semantic diagnostics used approximately 0.05% fewer allocations under Go 1.27.

End-to-end CLI benchmark

I also ran the repository's complete benchmark-cli setup:

  • Built the N-API parser and JavaScript CLI artifacts.
  • Used the pinned VS Code fixture at 41dd792b5e652393e7787322889ed5fdc58bd75b.
  • Built separate CLI binaries from the same PR source.
  • Ran 30 alternating paired samples.
  • Used the CI configuration, GOMAXPROCS=8.
  • Separated total CLI latency from Node startup before the Go binary was executed.
Benchmark Go 1.26 Go 1.27 Change
Full cli@vscode latency 2.634 s 2.613 s −0.80% (p=0.719)
Go execution and lint portion 2.588 s 2.567 s −0.81% (p=0.786)

Neither difference is statistically significant, so there is no observable end-to-end CLI regression under the CI configuration.

As a supplementary check, 30 pairs using the machine's default processor count showed Go 1.27 faster by 2.06% for total CLI latency (p=0.016) and 2.14% for the Go execution and lint portion (p=0.013).

Binary size

Default binaries:

Toolchain Size
Go 1.26 49,183,028 bytes
Go 1.27 48,487,591 bytes

Go 1.27 is 695,437 bytes smaller (−1.41%).

Binaries built with -ldflags="-s -w":

Toolchain Size
Go 1.26 35,049,634 bytes
Go 1.27 34,238,624 bytes

The stripped Go 1.27 binary is 811,010 bytes smaller (−2.31%). Stripping reduced the Go 1.26 binary by 28.74% and the Go 1.27 binary by 29.39%.

Conclusion

The focused inner-loop benchmarks show a reproducible CPU slowdown of roughly 1.5–2%. However, the representative end-to-end VS Code CLI workload does not reproduce that regression and is nominally slightly faster under Go 1.27. Memory usage is unchanged, and both regular and stripped binaries are smaller.

# Conflicts:
#	internal/plugins/react_hooks/rules/rules_of_hooks/rules_of_hooks_extras_test.go
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.

3 participants