Last updated 2026-05-07
Affected Test Runner
stax test runs only the tests for projects whose code
actually changed, and skips any project whose inputs hash matches a
previous green run. The implementation lives under
platform/cli-go/internal/affected/ and
internal/testcache/.
How "affected" is computed
-
Detect projects via
registry.LoadOrDetect(). Either a hand-writtenregistry.tomlat the repo root, or auto-discovery via marker files (go.mod,package.json,pyproject.toml,Cargo.toml,pubspec.yaml, etc.). -
Diff
HEADagainst--base(defaultmain) to get the list of changed files. - Direct match: mark any project whose
pathcontains a changed file as affected. - Transitive propagation: walk the dependency graph to a fixed point — anything that depends on an affected project is itself affected.
changed files: platform/cli-go/internal/api/api.go
┌─ platform/cli-go ◀── direct match │ └─ <projects depending on cli-go> ◀── transitively affectedregistry.toml
Optional. When present, it overrides auto-detection.
[packages.cli]path = "platform/cli-go"type = "go"test = "go test ./..."build = "go build ./..."
[packages.runner]path = "platform/runner"type = "node"test = "npm test"build = "npm run build"depends_on = ["cli"] # transitive: changes to cli mark runner affected tooCaching
Each test invocation hashes everything that influences the result: project path contents, transitive dependency contents, the test command itself, and the configured cache namespace. The hash is the cache key.
- A hit short-circuits the test command and replays the cached log. Output is still printed so CI consumers see green.
- A miss runs the test command and, if it passes, writes the result + log to the cache.
-
Failures are cached too so flaky retries don't waste time. Use
--retry-failedto force a re-run.
Cache backends
The cache layer is pluggable. Backends live in
internal/testcache/backends/:
| Backend | Purpose |
|---|---|
local_dir | Local filesystem (default). |
http | Generic HTTP store with GET/PUT. |
s3 | AWS S3 (via aws-sdk-go-v2). |
gcs | Google Cloud Storage. |
azure | Azure Blob Storage. |
layered | Read from one backend, write to another (e.g. local + remote). |
Common invocations
# Run only what changed since mainstax test
# Run everything (CI seeding, release verification)stax test --all
# Test a single project, ignoring the affected graphstax test --project runner
# Bypass the cache for an authoritative runstax test --no-cache
# Force-update cache entriesstax test --update-cache
# Inspect the cachestax test --cache-stats
# Clear itstax test --cache-clear # everythingstax test --cache-clear runner # one projectUse it in a workflow
name: Teston: [push, pull_request, workflow_dispatch]jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - run: | curl -fsSL https://raw.githubusercontent.com/elloloop/stax/main/install.sh | sh export PATH=$HOME/.local/bin:$PATH stax test --base ${{ github.base_ref || 'main' }}