Skip to content

v2.67.0 — audit through GitHub Action and GitLab CI, audit --coverage, dynamic-import analysis

Choose a tag to compare

@BartWaardenburg BartWaardenburg released this 07 May 20:10
· 3955 commits to main since this release
v2.67.0
36a5ab1

Highlights

  • fallow audit is now a first-class command in the GitHub Action and GitLab CI template. No more dropping to a manual npx fallow audit step; command: audit (Action) and FALLOW_COMMAND=audit (GitLab) accept the full set of audit inputs (gate, coverage, coverage-root, max-crap, and the three per-analysis baselines), gate on the severity-aware verdict instead of raw counts, and render verdict + per-category attribution tables in PR comments.
  • fallow audit --coverage plus --coverage-root forward Istanbul data to the embedded health analysis so audit's CRAP threshold check sees measured coverage instead of the static estimate. PRs touching well-tested code stop drawing noisy --max-crap violations.
  • Statically analyzable dynamic imports (import('./foo'), import('@scope/pkg')) now flow through the unresolved, unlisted, member-usage, and external-style analyzers exactly like static imports. Literal dynamic imports to missing files or unlisted packages no longer slip past the per-finding reports.

Features

command: audit in CI wrappers

Wrapping the severity-aware new-only PR gate previously meant ignoring the action's command: validation and writing a custom step. Both wrappers now accept audit as a first-class command and forward:

  • gate (new-only / all)
  • coverage and coverage-root (Istanbul JSON path + optional absolute strip prefix)
  • max-crap
  • dead-code-baseline, health-baseline, dupes-baseline

outputs.issues for audit returns the gate-aware introduced-finding count (sums attribution.*_introduced under gate: new-only, sums summary.* totals under gate: all), so downstream workflows comparing outputs.issues > N keep working without changes.

PR comments render the verdict banner, per-category attribution tables (dead-code, complexity, duplication), and a coverage-model footer that hints at --coverage-root when Istanbul match rate is low. Annotations and review comments fan out per category through the existing comment and annotation jq scripts.

GitLab CI mirrors the Action: FALLOW_COVERAGE, FALLOW_AUDIT_GATE, and the three FALLOW_AUDIT_*_BASELINE variables forward to the CLI; vendored CI templates under crates/cli/templates/ stay in lockstep.

Thanks @hc-12 for the report. (Closes #302)

fallow audit --coverage / --coverage-root

fallow audit --coverage coverage/coverage-final.json
fallow audit --coverage <path> --coverage-root /home/runner/work/myapp
FALLOW_COVERAGE=coverage/coverage-final.json fallow audit

Audit's CRAP threshold previously saw the static estimate even when the project had real coverage data; --coverage closes that loop. The base-snapshot cache key folds in a content hash of the coverage file so cache entries invalidate when coverage changes.

As a side fix, relative --coverage paths now resolve against --root rather than the process cwd, matching every other path-shaped CLI input (this also covers standalone fallow health --coverage). Empty-string MCP Option<String> params (coverage: "", etc.) are dropped before reaching clap, so agents that emit empty-string-for-no-value no longer end up with --coverage "".

(Closes #300)

Bug fixes

  • Statically analyzable dynamic imports flow through every per-finding analyzer. A literal import('./missing') or import('@unlisted-pkg') was silently elided from unresolved-import, unlisted-dependency, dependency-usage, unused-class-member, and external-CSS-package reports because those walkers only consumed static_imports + requires. A shared ResolvedModule::all_resolved_imports() iterator now unifies the three import shapes; pattern-shaped dynamic imports and graph-edge construction are unchanged. Suppression directives apply uniformly. Thanks @hussainarslan for the patch and @filipw01 for the report. (Closes #304)
  • Cross-package consumers of a namespace re-exported through an object literal credit the original member. Barrel import * as foo from './bar'; export const API = { foo } plus downstream API.foo.bar no longer reports bar as unused-export. Star-barrel namespace targets (./foo/index.ts doing export * from './bar') reuse the existing synthetic-export helper so credit propagates through Phase 4 chain resolution. Same-file aliases keep working unchanged; nested suffixes such as motionNet.adEngine are handled via dotted-path matching. Bumps the extract CACHE_VERSION so warm caches do not retain pre-fix data. Thanks @filipw01 for the report and the clean reproduction repo. (Closes #303)
  • Structured fallow errors no longer slip past the GitHub Action and GitLab CI wrappers as a green run. Both wrappers now check jq -e '.error == true' fallow-results.json after capture and before counting, surface the structured error message, and exit with the CLI's reported exit_code. The same path intercepts the audit + generic baseline / save-baseline misuse pre-spawn with a message pointing at the three audit-specific baseline inputs (audit's three sub-analyses use incompatible baseline formats).
  • Threshold gates branch on the audit verdict, not the raw introduced-finding count. A project with unused-exports: warn and the action default fail-on-issues: true no longer fails CI on every PR that touches a warn-tier finding. The Check threshold step branches on command=audit: gates on VERDICT==fail for audit, falls through to the existing ISSUES>0 logic for every other command. Fail-tier still fails as expected.
  • --coverage-root rejects relative paths with an actionable error instead of silently no-op'ing. --coverage-root is a strip-prefix argument applied to absolute paths inside Istanbul coverage data; relative values cannot match those paths and used to absolutise against --root and proceed, producing zero coverage matches with no signal. The validator now exits 2 with a message that names the expected shape and runs at every entry point that accepts the flag (audit, health, combined-mode bare run, the NAPI binding, plus a defence-in-depth check at the Istanbul load site).

Full Changelog: v2.66.2...v2.67.0