@biffo/cli 0.238.3 → 0.239.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,19 @@
35
35
  set -eu
36
36
 
37
37
  root=$(git rev-parse --show-toplevel)
38
+
39
+ # Where the CALLER stood, before this script normalises to the repo root.
40
+ #
41
+ # Some packaged scripts take their target from the working directory rather than
42
+ # from a repo layout -- the dependency audits are invoked from a CI job's
43
+ # `working-directory: apps/frontend`, and one byte-identical script is correct
44
+ # at a repo root, in a sibling's frontend and in a service directory alike. The
45
+ # `cd` below would silently retarget them at the repo root, which is a wrong
46
+ # ANSWER rather than an error: the audit would pass, having audited the wrong
47
+ # tree. packagedScriptCommand() spawns each script back in this directory.
48
+ BIFFO_ORIGINAL_CWD=$PWD
49
+ export BIFFO_ORIGINAL_CWD
50
+
38
51
  cd "$root"
39
52
 
40
53
  # Satellites (sibling apps, plugin repos, runner fleets) carry neither
@@ -35,6 +35,19 @@
35
35
  set -eu
36
36
 
37
37
  root=$(git rev-parse --show-toplevel)
38
+
39
+ # Where the CALLER stood, before this script normalises to the repo root.
40
+ #
41
+ # Some packaged scripts take their target from the working directory rather than
42
+ # from a repo layout -- the dependency audits are invoked from a CI job's
43
+ # `working-directory: apps/frontend`, and one byte-identical script is correct
44
+ # at a repo root, in a sibling's frontend and in a service directory alike. The
45
+ # `cd` below would silently retarget them at the repo root, which is a wrong
46
+ # ANSWER rather than an error: the audit would pass, having audited the wrong
47
+ # tree. packagedScriptCommand() spawns each script back in this directory.
48
+ BIFFO_ORIGINAL_CWD=$PWD
49
+ export BIFFO_ORIGINAL_CWD
50
+
38
51
  cd "$root"
39
52
 
40
53
  # Satellites (sibling apps, plugin repos, runner fleets) carry neither
package/dist/index.js CHANGED
@@ -10808,7 +10808,8 @@ function packagedScriptCommand(spec) {
10808
10808
  }
10809
10809
  const at = process.argv.indexOf(spec.name);
10810
10810
  const args = at === -1 ? [] : process.argv.slice(at + 1);
10811
- const result = spawnSync("sh", [script, ...args], { stdio: "inherit" });
10811
+ const cwd = process.env["BIFFO_ORIGINAL_CWD"] || process.cwd();
10812
+ const result = spawnSync("sh", [script, ...args], { stdio: "inherit", cwd });
10812
10813
  process.exit(result.status === null ? 2 : result.status);
10813
10814
  });
10814
10815
  }
@@ -10834,6 +10835,13 @@ var rewriteScopeCheckCommand = packagedScriptCommand({
10834
10835
  description: "Refuse a push whose rewrite scope absorbs merged work from another branch"
10835
10836
  });
10836
10837
 
10838
+ // src/commands/gate-coverage.ts
10839
+ var gateCoverageCommand = packagedScriptCommand({
10840
+ name: "gate-coverage",
10841
+ script: "scripts/gate-coverage.sh",
10842
+ description: "Report how much of CI the local gate actually mirrors"
10843
+ });
10844
+
10837
10845
  // src/commands/branch-health.ts
10838
10846
  var branchHealthCommand = packagedScriptCommand({
10839
10847
  name: "branch-health",
@@ -10873,6 +10881,7 @@ program.addCommand(teardownCommand);
10873
10881
  program.addCommand(waitForChecksCommand);
10874
10882
  program.addCommand(branchHealthCommand);
10875
10883
  program.addCommand(claimCommand);
10884
+ program.addCommand(gateCoverageCommand);
10876
10885
  program.addCommand(hookAuditCommand);
10877
10886
  program.addCommand(pgTestDbCommand);
10878
10887
  program.addCommand(rewriteScopeCheckCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.238.3",
3
+ "version": "0.239.0",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,7 +29,8 @@
29
29
  "scripts/claim.sh",
30
30
  "scripts/hook-audit.sh",
31
31
  "scripts/pg-test-db.sh",
32
- "scripts/rewrite-scope-check.sh"
32
+ "scripts/rewrite-scope-check.sh",
33
+ "scripts/gate-coverage.sh"
33
34
  ],
34
35
  "scripts": {
35
36
  "build": "tsup src/index.ts --format esm --dts --clean",
@@ -1,131 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # Does each repo's local gate actually cover that repo's CI?
4
- #
5
- # ## Why this exists
6
- #
7
- # `hook-audit.sh` answers "will a hook execute here". That question hit 100%
8
- # across the estate on 2026-07-29 while eight repos had a gate that checked
9
- # **nothing they were written in** — `tabsii-crm` ran one check, terraform-fmt,
10
- # on a 700-line TypeScript-and-Python change, and printed `verify passed`.
11
- #
12
- # Arming was a proxy and it was reported as the outcome. This is the metric that
13
- # can actually fail: for every repo, the set of check *kinds* its CI runs, minus
14
- # the ones deliberately excluded, must be covered by the set its gate runs.
15
- #
16
- # The parity test in `cli/src/lib/verify-parity.test.ts` compares the gate to CI
17
- # too — but it runs only in `biffo-template`, the single repo with both a root
18
- # `package.json` and a root `pyproject.toml`, i.e. the one place the root-only
19
- # assumption held. It validated the gate where the gate was already correct.
20
- # This runs everywhere, which is the whole point.
21
- #
22
- # Usage:
23
- # sh scripts/gate-coverage.sh # this repo
24
- # sh scripts/gate-coverage.sh --estate ~/code # every repo under a directory
25
- #
26
- # Exits non-zero if any repo's gate misses a check kind its CI runs.
27
-
28
- set -uo pipefail
29
-
30
- ESTATE=""
31
- [ "${1:-}" = "--estate" ] && ESTATE="${2:-}"
32
-
33
- # Deliberately excluded from local gates, with the reason. Kept in step with
34
- # verify-parity.test.ts. An exclusion here must describe what the CI step
35
- # actually DOES, not what it was assumed to do — the bandit exclusion claimed
36
- # "the finding gate is the upload step" when `bandit -ll` exits non-zero and it
37
- # is the run step that fails (#855).
38
- EXCLUDED_KINDS="pytest build audit gitleaks codeql e2e playwright release-subject ownership"
39
-
40
- # Reduce a command to the KIND of check it is. Comparing raw command strings is
41
- # hopeless across repos — CI uses `working-directory:` where the gate uses
42
- # `--dir` — and what matters is "does a lint run locally where CI runs a lint".
43
- kind_of() {
44
- case "$1" in
45
- *"run lint"*) echo lint ;;
46
- *"run typecheck"*) echo typecheck ;;
47
- *"run format:check"*) echo format ;;
48
- *"run e2e"*) echo e2e ;;
49
- *"run build"*|*"portal build"*) echo build ;;
50
- *"run test"*) echo test ;;
51
- *"ruff check"*) echo ruff-check ;;
52
- *"ruff format"*) echo ruff-format ;;
53
- *pyright*) echo pyright ;;
54
- *pytest*) echo pytest ;;
55
- *bandit*) echo bandit ;;
56
- *"terraform fmt"*) echo terraform-fmt ;;
57
- *playwright*) echo playwright ;;
58
- *"dependency-audit"*|*"pnpm audit"*|*"pip-audit"*) echo audit ;;
59
- *gitleaks*) echo gitleaks ;;
60
- *"check release-subject"*) echo release-subject ;;
61
- *"check ownership"*) echo ownership ;;
62
- *"check plugin-terraform"*) echo plugin-terraform ;;
63
- *"check plugin-collisions"*) echo plugin-collisions ;;
64
- *install*|*"uv sync"*) echo "" ;;
65
- *) echo "" ;;
66
- esac
67
- }
68
-
69
- kinds_from_ci() {
70
- d="$1"
71
- f="$d/.github/workflows/ci.yml"
72
- [ -f "$f" ] || return 0
73
- grep -hoE "run: (pnpm|uv|terraform|sh scripts/)[^\"']*" "$f" 2>/dev/null |
74
- sed 's/^run: //' | while read -r cmd; do kind_of "$cmd"; done | grep -v '^$' | sort -u
75
- }
76
-
77
- kinds_from_gate() {
78
- d="$1"
79
- [ -f "$d/scripts/verify.sh" ] || return 0
80
- (cd "$d" && sh scripts/verify.sh --list 2>/dev/null) |
81
- while read -r cmd; do kind_of "$cmd"; done | grep -v '^$' | sort -u
82
- }
83
-
84
- failed=0
85
- report() {
86
- d="$1"
87
- label="$2"
88
- if [ ! -f "$d/scripts/verify.sh" ]; then
89
- printf '%-26s \033[33mNO GATE\033[0m\n' "$label"
90
- return
91
- fi
92
- ci=$(kinds_from_ci "$d")
93
- gate=$(kinds_from_gate "$d")
94
- if [ -z "$ci" ]; then
95
- printf '%-26s \033[90mno CI to mirror\033[0m (gate runs %s)\n' "$label" "$(echo "$gate" | grep -cv '^$')"
96
- return
97
- fi
98
- missing=""
99
- total=0
100
- covered=0
101
- for k in $ci; do
102
- case " $EXCLUDED_KINDS " in *" $k "*) continue ;; esac
103
- total=$((total + 1))
104
- if echo "$gate" | grep -qx "$k"; then covered=$((covered + 1)); else missing="$missing $k"; fi
105
- done
106
- if [ -n "$missing" ]; then
107
- failed=1
108
- printf '%-26s \033[31m%s/%s\033[0m missing:%s\n' "$label" "$covered" "$total" "$missing"
109
- else
110
- printf '%-26s \033[32m%s/%s\033[0m\n' "$label" "$covered" "$total"
111
- fi
112
- }
113
-
114
- printf '\ngate coverage - CI check kinds mirrored by the local gate\n\n'
115
- if [ -n "$ESTATE" ]; then
116
- for d in "$ESTATE"/*/; do
117
- [ -e "$d/.git" ] || continue
118
- report "${d%/}" "$(basename "${d%/}")"
119
- done
120
- else
121
- root=$(git rev-parse --show-toplevel 2>/dev/null) || { echo "not a git repo" >&2; exit 2; }
122
- report "$root" "$(basename "$root")"
123
- fi
124
-
125
- printf '\n'
126
- if [ "$failed" -ne 0 ]; then
127
- printf '\033[31mSome gates do not cover their own CI.\033[0m A gate that misses the language a\n'
128
- printf 'change is written in reports `verify passed` on work it never checked.\n\n'
129
- exit 1
130
- fi
131
- printf '\033[32mEvery gate covers its own CI.\033[0m\n\n'