Skip to Content

gofasta verify

Runs every quality gate that CI runs, in order, and fails fast on the first failure. Acts as the single “am I done?” check for both humans and AI coding agents — one command, structured JSON output, non-zero exit on any check failure.

Usage

gofasta verify [flags]

Run this command from the root directory of your Gofasta project.

Flags

FlagTypeDefaultDescription
--no-lintboolfalseSkip golangci-lint (use if not installed or to speed up)
--no-raceboolfalseSkip the race detector in go test
--keep-goingboolfalseContinue after the first failure and report every result
--sincestring(none)Scope gofmt, go vet, golangci-lint, go test, and go build to only the packages affected by files changed since <git-ref> (e.g. HEAD~1, main, a SHA). Wire drift + routes always run full-project — they’re whole-project invariants.
--changedboolfalseShortcut for “scope to working-tree + staged + untracked changes” (no committed comparison). Same scoping as --since but no ref needed.

Inherits the global --json flag to emit one JSON object per check, suitable for agent consumption and CI automation.

Scoped verify (--since / --changed)

By default gofasta verify runs every step against ./.... Pass --since=<ref> or --changed to scope the per-package steps (fmt, vet, lint, test, build) to only the packages touched by your changeset — and the packages that transitively depend on them via the reverse-import graph. This is the per-PR fast path that drops a 90-second full preflight to ~10 seconds on a small change.

How it picks the package set:

  1. git diff --name-only <ref> (or working-tree state for --changed) → changed files
  2. Filter to .go files → derive unique directories → go list ./<dir> → root package set
  3. go list -deps ./... → build the reverse-import graph → expand to every package that imports any of the roots

The test set is the expanded reverse-dep set; the build/vet/lint set is just the root packages. Files outside Go (.sql, .yaml, etc.) make scope.NonGoOnly=true and the per-package Go steps short-circuit as skip — only wire drift and routes still run.

Linter scope uses golangci-lint --new-from-rev=<ref> natively, so existing lint debt outside your change doesn’t fail the run.

Steps, in order

  1. gofmt -s -l . — formatting
  2. go vet ./... — compiler static checks
  3. golangci-lint run — aggregate linter (skipped if not on $PATH)
  4. go test -race ./... — tests with the race detector
  5. go build ./... — every package compiles
  6. Wire drift — app/di/wire_gen.go is in sync with its inputs
  7. Routes — app/rest/routes/ parses and has at least one entry

Each step blocks the next; fail-fast is the default. Pass --keep-going to run every step regardless of failures.

Examples

Full preflight, text output:

$ gofasta verify ✓ gofmt (12ms) ✓ go vet (240ms) ✓ golangci-lint (3421ms) ✓ go test (8920ms) ✓ go build (1810ms) ✓ wire drift (4ms) ✓ routes (6ms) 7 passed · 0 failed · 0 skipped · 14413ms

Structured JSON for agent consumption:

$ gofasta verify --json | jq '.checks[] | select(.status == "fail")'

Skip the linter on a machine without golangci-lint installed:

gofasta verify --no-lint

Run every check and report every result (useful for diagnosing multiple issues at once):

gofasta verify --keep-going

Output shape (JSON)

{ "checks": [ { "name": "gofmt", "status": "pass", "duration_ms": 12 }, { "name": "go vet", "status": "pass", "duration_ms": 240 }, { "name": "go test", "status": "fail", "message": "tests failed", "output": "--- FAIL: TestFoo ...", "duration_ms": 3200 } ], "passed": 2, "failed": 1, "skipped": 0, "duration_ms": 3452 }

Fields are stable API — AI agents and CI pipelines consume them.

Why this exists

Agents and humans commonly finish a task having run only one of the quality gates (usually go test). gofasta verify collapses every gate into one invocation, so the pre-commit check is always complete. Mirrors the make preflight target in the CLI and library repos — same contract, same mental model.

Last updated on