From 6f832ab9f72807134e0b729ab731f41b2e66e52b Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Mon, 26 Oct 2026 23:43:53 -0300 Subject: [PATCH] mutate: a file this machine's build leaves out is not asked about spin's browser terminal is a js/wasm program, cmd/term; a change to it planned edits there, and asking them listed the package from its directory, where on linux go list finds no package at all ("build constraints exclude all Go files"), and the run failed. No test run on this machine compiles such a file, so none could refuse an edit of it: Changed leaves it out, by the build's own rule (go/build's MatchFile - its constraint, or a name like _js.go), and the page says so. Co-Authored-By: Claude Opus 5.5 --- internal/mutate/mutate.go | 9 +++++++-- internal/mutate/mutate_test.go | 8 ++++++++ site/src/content/docs/mutate.mdx | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/internal/mutate/mutate.go b/internal/mutate/mutate.go index 47362f5..829ef31 100644 --- a/internal/mutate/mutate.go +++ b/internal/mutate/mutate.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" "go/ast" + "go/build" "go/parser" "go/token" "os" @@ -111,7 +112,9 @@ func Changed(base string) (map[string]map[int]bool, error) { // asked is whether a changed file is one this asks the tests about: Go that is not a test, in a // directory the go command builds. Under testdata, or a directory named with a leading . or _, // it is a fixture go never compiles into the package - one written to fail on purpose, as -// cmd/mutate's example is. +// cmd/mutate's example is. And a file this machine's build leaves out - a js/wasm program's, +// behind its constraint or its _js.go name - is one no test run here compiles: asked, its +// package is one go list does not find at all. func asked(path string) bool { if !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") { return false @@ -121,7 +124,9 @@ func asked(path string) bool { return false } } - return true + // A file that cannot be read is one a later step says so of; built, it is asked. + built, err := build.Default.MatchFile(pathpkg.Dir(path), pathpkg.Base(path)) + return err != nil || built } // hunk is the range of the new file a hunk header names: @@ -old,n +new,m @@. diff --git a/internal/mutate/mutate_test.go b/internal/mutate/mutate_test.go index fb4a236..88f619b 100644 --- a/internal/mutate/mutate_test.go +++ b/internal/mutate/mutate_test.go @@ -344,6 +344,11 @@ func TestTheLinesAChangeTouchesAreTheOnesItChanged(t *testing.T) { require.NoError(t, os.WriteFile(filepath.Join(dir, "fixture.go"), []byte("package fixture\n\nfunc F() int { return 1 }\n"), 0o600)) } run("add", "testdata") + // And a browser's Go, new: behind its constraint, and by its name - what this machine never + // builds, so no test here could refuse an edit of it. + require.NoError(t, os.MkdirAll("term", 0o750)) + require.NoError(t, os.WriteFile(filepath.Join("term", "main.go"), []byte("//go:build js && wasm\n\npackage main\n\nfunc main() {}\n"), 0o600)) + require.NoError(t, os.WriteFile(filepath.Join("term", "page_js.go"), []byte("package main\n\nfunc page() int { return 1 }\n"), 0o600)) // A file that is not Go, changed in the same diff: its hunks are nobody's lines. require.NoError(t, os.WriteFile("notes.txt", []byte("a\nb\n"), 0o600)) run("add", "notes.txt") @@ -356,6 +361,9 @@ func TestTheLinesAChangeTouchesAreTheOnesItChanged(t *testing.T) { for _, fixture := range []string{"testdata/example/fixture.go", "_scratch/fixture.go", ".hidden/fixture.go"} { assert.NotContains(t, changed, fixture, "a fixture the go command never builds was broken") } + for _, browser := range []string{"term/main.go", "term/page_js.go"} { + assert.NotContains(t, changed, browser, "a file this machine's build leaves out was broken") + } require.Contains(t, changed, "sample.go") assert.Equal(t, map[int]bool{12: true, 33: true, 34: true}, changed["sample.go"], "the lines the change touched are not the lines reported") require.Contains(t, changed, "new.go", "a file that is not committed yet is not in any diff, and is all new code") diff --git a/site/src/content/docs/mutate.mdx b/site/src/content/docs/mutate.mdx index 5b67602..b2ce8e5 100644 --- a/site/src/content/docs/mutate.mdx +++ b/site/src/content/docs/mutate.mdx @@ -100,6 +100,10 @@ conditions of branches that only log, generated code, and lines with a `mutate-e the last, these used to be answered with exemptions by hand, often enough that `mutate` now skips them itself. +It also leaves out files the machine running it does not build: a `//go:build js && wasm` +program, or a file named `_windows.go` on Linux. No test that runs there compiles them, so none +could refuse an edit. + ## How a run stays fast Mutation testing has a reputation for being slow, because the naive approach builds and tests the