Documentation
¶
Overview ¶
affected prints the Go packages whose test outcome could change given what differs between the working tree and a base ref, the way `nx affected` scopes a JavaScript monorepo. It is the default scope for `make test`, the git hooks, the red and coverage sweeps, and CI's pull-request run; `scripts/test-all.sh` and GOFASTR_TEST_ALL=1 are the explicit "test everything" spellings.
A package is affected when any of these hold:
- a changed file sits in the package's directory or anywhere below it that is not itself a package (testdata, embedded assets, fixtures);
- one of the package's //go:embed patterns covers a changed file, deleted ones included, which can sit inside a nested package: cmd/gofastr embeds the app spec's packages/ trees, each its own package, so editing a template never selected the generator or the gates that run it;
- the package imports an affected package, transitively (go list's Deps);
- the package's test files import an affected package (TestImports and XTestImports, whose own transitive deps the first rule covers);
- a changed file matches a pattern one of the package's test files declares it reads (see "Files a test reads" below).
Some changes make the graph meaningless and widen the set to every package: go.mod, go.sum, go.work, and this tool's own source. A base ref that cannot be resolved, or a merge base that cannot be computed, also widens to everything, so a misconfigured checkout degrades to the full run and never to a skipped one. -all-if-changed adds callers' own triggers (the vet step passes internal/analyzers: a new rule can flag code nobody touched).
The change set is the working tree against the merge base of HEAD and the base ref: staged, unstaged and untracked files all count, and a deleted file still marks the package it left. With -diff-base the base ref is diffed directly instead; CI uses that with the pull request's base SHA, where the checkout is the PR's merge commit and no history is fetched.
Files a test reads: a gate that walks the repo (every _test.go, every package.json, every exported symbol) depends on files no import edge reaches. internal/chromedptest's launch-allowance gate reads every test file in the module, so a new hand-booted Chrome in another package never selected it, and #536's missing allowance reached main. Such a test names its inputs with a directive at the start of a comment line in the test file:
//gofastr:test-reads *_test.go //gofastr:test-reads framework/ui/ /README.md core-ui/**/*.js
A pattern ending in "/" is a directory prefix; one with no "/" matches the base name anywhere ("*_test.go", "package.json"); one starting with "/" is anchored at the repo root ("/README.md" is the root README only); any other is a repo-relative glob where "**" spans directories. "importers:<import path>" matches a change in any package that imports that path directly, and any changed .go file whose text, now or at the base, names it in quotes: a nested module's file, a deleted file, or one that dropped the import still changes what a gate reading "every caller of this API" sees (core-ui/runtime/internal/treegate's registry gates). Patterns are space-separated and a file may carry several directive lines. A match selects the declaring package only: nothing imports a test. scripts/test-reads-audit.sh finds the tests that need a directive: it records the files each test opens and fails on one whose change would not select its reader.
Usage:
go run ./cmd/affected # one import path per line go run ./cmd/affected -format dir # ./relative/dir per line go run ./cmd/affected -- go test -short # run with the set appended go run ./cmd/affected -tags red -format dir go run ./cmd/affected -exclude 'examples/site$' -- go test -p 2 go run ./cmd/affected -match '/framework(/|$)' -- go test go run ./cmd/affected -coverage-dir # where wrapped commands keep coverage manifests
With a command after `--`, an empty set skips the command and exits 0 with a note on stderr: `go test` with no packages would test the current directory, which is never what a caller meant. The command's own exit code is propagated otherwise. The command also learns what the set came from: GOFASTR_AFFECTED_FILES holds the change set, one repo-relative path per line, or, when the set is every package, GOFASTR_TEST_ALL=1 is set instead (see changeEnv).
The affected set is the first half of what nx affected does; Go's test cache is the second. A package in the set whose binary and recorded inputs (files read, env vars) match a previous pass replays "(cached)" instead of running. That only holds while tests read nothing the suite itself rewrites, so the wrapped command gets GOFASTR_AXE_COVERAGE_DIR pointed outside the module (see commandEnv), and CI fails a second run over the same tree that re-runs any package (scripts/test-cache-replay.sh).
Environment:
GOFASTR_TEST_ALL=1 every package, no graph walk (same as -all) GOFASTR_AFFECTED_BASE base ref when -base is not given GOFASTR_AFFECTED_DIFF_BASE=1 same as -diff-base
Without a base, origin/main is used when that ref exists, then main.
Exits 0 on success (including an empty set), 2 on infrastructure error, or with the wrapped command's status.