oficina / meet Public

credits: say "wrong toolchain" instead of "run make credits"

Everything in this test depends on the binary being the Go the embedded
notices were generated with: runtime.Version() goes into the expected
inventory and runtime.GOROOT()/LICENSE is read out of it. Under any
other toolchain the failure is real and has nothing to do with credits,
and it surfaced two different misleading ways.

A Homebrew keg with no LICENSE at GOROOT failed the read with a bare
file error that never mentioned credits. A keg with it got past that and
failed the comparison instead, whose message sent you to `make credits`
— which would have rewritten notices.json to name whatever toolchain you
were on, burying the inventory the test exists to protect. Two sessions
lost time to the pair, and one of them reported the second as "wants
make credits" to Paul before catching it.

The guard reads the Go version out of the embedded notices and compares
it before anything else runs, so both symptoms become one sentence
naming the real cause and the command that fixes it. Notices that name
no Go component are left alone and the test proceeds as before.

Verified both ways: under go1.27.1 it fails at the guard naming both
versions; under GOTOOLCHAIN=go1.26.5 the full make ci passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev de480006d5db1d04466e32c69d2e2978ce94cb71 parent 5b77da0
1 file changed, +40 −5
  • internal/calls/credits_inventory_test.go +40 −5

CI passed — run details

diff --git a/internal/calls/credits_inventory_test.go b/internal/calls/credits_inventory_test.go
index d1cfff2..458deac 100644
--- a/internal/calls/credits_inventory_test.go
+++ b/internal/calls/credits_inventory_test.go
@@ -20,6 +20,32 @@ import (
// Check the production package graph, not the test binary's dependencies.
// A dependency or notice change must update the embedded attribution too.
func TestCreditsMatchProductionDependencies(t *testing.T) {
+ // Read the embedded inventory first, and check the toolchain against
+ // it before anything else runs. Everything below depends on this
+ // binary being the Go the notices were generated with:
+ // runtime.Version() goes into the expected inventory, and
+ // runtime.GOROOT()/LICENSE is read out of it.
+ //
+ // Under any other toolchain the failure is real and says nothing
+ // about credits, and it surfaces two different misleading ways. A
+ // Homebrew keg without LICENSE at GOROOT fails the read with a bare
+ // file error that never mentions credits at all. A keg with it gets
+ // past that and fails the comparison instead, whose message sends
+ // you to `make credits` — which would rewrite notices.json to name
+ // whatever toolchain you happen to be on, burying the dependency
+ // inventory the test exists to protect. Both cost a session a while
+ // before this guard was here.
+ var embedded creditInventory
+ if err := json.Unmarshal(creditNotices, &embedded); err != nil {
+ t.Fatal(err)
+ }
+ if want := embeddedGoVersion(embedded); want != "" && want != runtime.Version() {
+ t.Fatalf("credits were generated with %s, this test is running under %s.\n"+
+ "Run `GOTOOLCHAIN=%s make ci`. Do not run `make credits` to fix this: it would\n"+
+ "rewrite notices.json to name this toolchain instead of checking the inventory.",
+ want, runtime.Version(), want)
+ }
+
ctx, cancel := context.WithTimeout(t.Context(), 45*time.Second)
defer cancel()
command := exec.CommandContext(ctx, "go", "list", "-deps", "-json", "./cmd/calls")
@@ -44,13 +70,22 @@ func TestCreditsMatchProductionDependencies(t *testing.T) {
}
inventory.Components = append(inventory.Components, credits.Lucide(), credits.Component{Name: "Go", Version: runtime.Version(), SourceURL: "https://go.dev/LICENSE", Notices: []credits.Notice{{Name: "LICENSE", Text: string(goLicense)}}})
sort.Slice(inventory.Components, func(i, j int) bool { return inventory.Components[i].Name < inventory.Components[j].Name })
- var embedded creditInventory
- if err := json.Unmarshal(creditNotices, &embedded); err != nil {
- t.Fatal(err)
- }
expected, _ := json.Marshal(creditInventory{Components: inventory.Components, MissingNotices: inventory.MissingNotices})
actual, _ := json.Marshal(embedded)
if !bytes.Equal(expected, actual) {
- t.Fatal("embedded credits differ from production dependencies; run make credits")
+ t.Fatal("embedded credits differ from production dependencies; run make credits " +
+ "(the toolchain is already ruled out by the check at the top of this test)")
+ }
+}
+
+// embeddedGoVersion is the Go toolchain the embedded notices name, or ""
+// when they name none — in which case there is nothing to compare against
+// and the test proceeds exactly as it did before the guard existed.
+func embeddedGoVersion(inventory creditInventory) string {
+ for _, component := range inventory.Components {
+ if component.Name == "Go" {
+ return component.Version
+ }
}
+ return ""
}