Skip to content

feat: update standard list to go1.27 - #250

Open
osamingo wants to merge 3 commits into
daixiang0:masterfrom
osamingo:feat/standard-list-go1.27
Open

osamingo wants to merge 3 commits into
daixiang0:masterfrom
osamingo:feat/standard-list-go1.27

Conversation

@osamingo

@osamingo osamingo commented Sep 2, 2026

Copy link
Copy Markdown

Regenerate the standard package list with Go 1.27, and stop the generator from
breaking on every Go release.

Why

Go 1.27 adds standard packages that gci does not know about. The most visible
one is uuid: gci currently sorts it into the third-party group, while
goimports, gofumpt and golangci-lint fmt all keep it in the standard
group. Projects running gci next to any of those end up with two formatters
fighting over the same import block.

While updating the list I hit a second problem: make generate does not work on
Go 1.27 at all. The GOEXPERIMENT value is hardcoded and includes synctest,
which is no longer a known experiment:

$ make generate
go: unknown GOEXPERIMENT synctest
make: *** [generate] Error 2

This is not a one-off. The hardcoded value has needed manual repair on every
recent release: synctest added for 1.24 (#227), jsonv2 added for 1.25
(#233), synctest removed for 1.26 (#245), simd added for 1.27. It is also
duplicated between the Makefile and internal/generate.go, and the two had
already drifted apart before #233 resynced them. Because CI only runs
make test, nothing catches any of this.

What changed

1. Generation no longer hardcodes GOEXPERIMENT (internal/generate.go,
Makefile)

The generator now probes which of the candidate experiments the toolchain in use
accepts, and passes only those. An experiment the toolchain explicitly rejects
is skipped, so make generate keeps working on future Go versions without
edits. Any other probe failure aborts generation, so a broken environment cannot
quietly rewrite the list with a narrower one.

The generated header now records the experiments explicitly, since they are no
longer implied by the binary's own runtime.Version():

// Code generated based on go1.27.0 with GOEXPERIMENT=arenas,boringcrypto,jsonv2,simd. DO NOT EDIT.

2. Regenerated pkg/section/standard_list.go with Go 1.27.

Newly listed packages, nothing removed:

crypto/hpke
crypto/mldsa
crypto/mlkem/mlkemtest
simd
simd/archsimd
testing/cryptotest
uuid

3. Added a CI job that regenerates the list and fails if it is stale
(.github/workflows/build.yml)

The check ignores the generated header line, so a patch release such as
go1.27.0 to go1.27.1 does not turn it red on its own — only an actual change in
the package set does.

Note this job runs on stable, so it will go red once Go 1.28 ships and the
list needs refreshing. That is the intent, but it does mean unrelated PRs are
blocked until someone refreshes the list, and a contributor on an older
toolchain cannot fix it by running make generate locally. If you would prefer,
it can be pinned to the generating version, made non-blocking, or moved to a
scheduled run. Happy to change it.

The job is named for the root module because it only covers
pkg/section/standard_list.go. v2/pkg/section/standard_list.go is a separate,
hand-maintained map with no generator, and it is currently 27 entries behind the
root list — including cmp, iter, math/rand/v2, unique, weak,
crypto/sha3 and encoding/json/v2 — so gci/v2 sorts those into the
third-party group. That is out of scope here; #245 is the change that would put
v2 under the generator.

Test

  • Added a uuid case to TestStandardPackageSpecificity.
  • go test ./... passes.
  • End to end: a file importing "uuid" in the standard group is moved to the
    third-party group by the current release, and is left alone after this change.

Relation to #245

#245 updates the list to Go 1.26 and additionally refactors the generator so it
also emits v2/pkg/section/standard_list.go. This PR targets Go 1.27 and leaves
v2 alone, so the two overlap in pkg/section/standard_list.go.

If you would rather land #245 first, I am happy to close this and re-send the
Go 1.27 delta on top of it.

The three concerns are in separate commits, so if you only want the refreshed
list you can take the middle one on its own and leave the generator and CI
changes out.

- probe each candidate experiment with `go env` and keep only the accepted ones
- drop the hardcoded GOEXPERIMENT from the generate target
- record the experiments used in the generated header
- fail loudly when a probe breaks for any reason other than a rejected
  experiment, so a broken environment cannot silently narrow the list

make generate failed on Go 1.27 with "unknown GOEXPERIMENT synctest", and the
hardcoded value has needed manual repair on every recent Go release.

Signed-off-by: osamingo <1390409+osamingo@users.noreply.github.com>
- add crypto/hpke, crypto/mldsa, crypto/mlkem/mlkemtest, simd, simd/archsimd,
  testing/cryptotest and uuid
- cover uuid in TestStandardPackageSpecificity

uuid was sorted into the third-party group, which conflicts with goimports,
gofumpt and golangci-lint fmt.

Signed-off-by: osamingo <1390409+osamingo@users.noreply.github.com>
- regenerate the list with stable Go and diff it on every pull request
- ignore the generated header line so patch releases do not fail the job
- scope the job name to the root module, since v2 keeps its own list

Signed-off-by: osamingo <1390409+osamingo@users.noreply.github.com>
@osamingo
osamingo force-pushed the feat/standard-list-go1.27 branch from e899dc8 to 881366c Compare September 2, 2026 09:43
@osamingo
osamingo marked this pull request as ready for review September 2, 2026 10:01
@lancerushing

Copy link
Copy Markdown

+1 on the uuid sort. I have imports that are:

import (
	"database/sql"
	"errors"
	"net/http"

	"github.com/jackc/pgx/v5/pgtype"
	"github.com/rs/zerolog/log"
	"uuid"
)

But I would expect

import (
	"database/sql"
	"errors"
	"net/http"
	"uuid"

	"github.com/jackc/pgx/v5/pgtype"
	"github.com/rs/zerolog/log"

)

@osamingo

osamingo commented Sep 7, 2026

Copy link
Copy Markdown
Author

@daixiang0 friendly ping on this one — the build and lint workflows are
still waiting on approval, so they have not run here yet.

For what it is worth, the same workflows are green on my fork for an identical
tree (8/8, including the new job). The only change since that run was adding the
DCO sign-off trailers:
https://github.com/osamingo/gci/actions/runs/33615407676

DCO passes and the branch is still mergeable.

If the scope is more than you want, the three concerns are in separate commits —
taking only feat(pkg/section): update standard list to go1.27 would fix the
misclassification that #250 and the comment above are about, and leave the
generator and CI changes out.

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