affected

command
v0.94.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 19 Imported by: 0

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 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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL