@biffo/cli 0.172.0 → 0.172.2

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.
@@ -48,11 +48,28 @@
48
48
  #
49
49
  # Usage:
50
50
  # sh scripts/verify.sh # everything applicable to this repo
51
+ # sh scripts/verify.sh --list # print the checks it WOULD run, and stop
51
52
  # pnpm run verify # same
52
53
  # BIFFO_SKIP_VERIFY=1 git push # escape hatch, for when you mean it
54
+ #
55
+ # `--list` exists so parity with CI can be tested against what this script
56
+ # actually does, rather than against its source text. The checks are assembled
57
+ # at runtime from what the repo has, so grepping the file for `pnpm run lint`
58
+ # proves nothing -- and a parity test that can be satisfied by a comment is not
59
+ # a parity test.
60
+ #
61
+ # `--list` reports what THIS REPO requires, deliberately ignoring whether the
62
+ # tooling happens to be installed here. Parity with CI is a property of the
63
+ # repository; "can this machine run it" is a property of the machine. Conflating
64
+ # them made the parity test pass locally and fail on a CI runner that has no
65
+ # `uv` or `terraform` -- the gate-green/CI-red split this whole exercise exists
66
+ # to remove, reproduced inside its own guard.
53
67
 
54
68
  set -u
55
69
 
70
+ LIST=""
71
+ [ "${1:-}" = "--list" ] && LIST=1
72
+
56
73
  FAILED=""
57
74
  PASSED=""
58
75
  SKIPPED=""
@@ -60,13 +77,62 @@ SKIPPED=""
60
77
  PYTEST="${BIFFO_VERIFY_PYTEST:-}"
61
78
 
62
79
  have_script() {
63
- [ -f package.json ] || return 1
64
- node -e "process.exit(JSON.parse(require('fs').readFileSync('package.json','utf8')).scripts?.['$1']?0:1)" 2>/dev/null
80
+ [ -f "$2/package.json" ] || return 1
81
+ # grep rather than node: --list must work on a machine with no toolchain at
82
+ # all, because what it reports is a property of the repo, not of the machine.
83
+ # Deliberately NOT anchored to line start: that only matches a pretty-printed
84
+ # package.json, and a minified one would silently report "no lint script" --
85
+ # a skip that looks like a considered decision. A false positive here costs a
86
+ # loud `pnpm run` failure; a false negative costs an unchecked push.
87
+ grep -qE "\"$1\"[[:space:]]*:" "$2/package.json"
88
+ }
89
+
90
+ # Every directory holding a JS package this repo owns.
91
+ #
92
+ # A repo with a root package.json is a workspace: `turbo run lint` fans out and
93
+ # running per-package as well would double the work. A repo WITHOUT one keeps
94
+ # its JS in subdirectories -- web/ and web-admin/ in the plugin repos,
95
+ # apps/frontend/ in the siblings -- and their CI runs the same scripts there
96
+ # with `working-directory:`.
97
+ #
98
+ # ## Why this exists (#852)
99
+ #
100
+ # The gate used to check the repo root and nothing else. In the ten repos with
101
+ # no root package.json -- every plugin, every sibling, both runner repos -- it
102
+ # printed `javascript n/a - no package.json in this repo` and then
103
+ # `verify passed`, on repos whose entire frontend is JS. A 100% TypeScript
104
+ # change pushed green with zero JavaScript verification.
105
+ #
106
+ # That is worse than the missing hooks this gate was built to fix. A repo with
107
+ # no hooks makes no claim; this one claimed to have checked. And the standard
108
+ # it was written to enforce says exactly that inapplicable and absent must not
109
+ # look the same -- while reporting "not applicable" for the language the change
110
+ # was written in.
111
+ js_dirs() {
112
+ if [ -f package.json ]; then
113
+ echo "."
114
+ return
115
+ fi
116
+ # `.terraform/` is a DOWNLOAD CACHE of third-party modules, and the two runner
117
+ # repos carry eight vendored lambda packages in it -- each declaring lint and
118
+ # test scripts. Linting someone else's vendored code is slow, always red, and
119
+ # not this repo's business. It is gitignored, so a fresh worktree never has
120
+ # it and the omission was invisible until a primary checkout was audited.
121
+ find . -name package.json \
122
+ -not -path "*/node_modules/*" -not -path "*/dist/*" -not -path "*/.next/*" \
123
+ -not -path "*/.turbo/*" -not -path "*/.worktrees/*" -not -path "*/out/*" \
124
+ -not -path "*/coverage/*" -not -path "*/.venv/*" \
125
+ -not -path "*/.terraform/*" -not -path "*/vendor/*" 2>/dev/null |
126
+ sed 's|/package.json$||' | sort
65
127
  }
66
128
 
67
129
  run_check() {
68
130
  name="$1"
69
131
  shift
132
+ if [ -n "$LIST" ]; then
133
+ echo "$*"
134
+ return 0
135
+ fi
70
136
  start=$(date +%s)
71
137
  if "$@" >"/tmp/biffo-verify.$$" 2>&1; then
72
138
  PASSED="$PASSED $name"
@@ -80,16 +146,17 @@ run_check() {
80
146
  }
81
147
 
82
148
  skip() {
149
+ [ -n "$LIST" ] && return 0
83
150
  SKIPPED="$SKIPPED $1"
84
151
  printf ' \033[90m-- %-16s n/a - %s\033[0m\n' "$1" "$2"
85
152
  }
86
153
 
87
- printf '\nverify - the checks CI runs, before the push\n\n'
154
+ [ -n "$LIST" ] || printf '\nverify - the checks CI runs, before the push\n\n'
88
155
 
89
156
  # Python first: ruff is near-instant, so the cheapest feedback on the largest
90
157
  # single class of failure comes back immediately.
91
158
  if [ -f pyproject.toml ]; then
92
- if command -v uv >/dev/null 2>&1; then
159
+ if [ -n "$LIST" ] || command -v uv >/dev/null 2>&1; then
93
160
  run_check ruff-check uv run ruff check .
94
161
  run_check ruff-format uv run ruff format --check .
95
162
  run_check pyright uv run pyright
@@ -107,7 +174,7 @@ fi
107
174
 
108
175
  # Terraform, wherever this repo keeps it: modules/ in the template and
109
176
  # instances, infra/ and modules/ in siblings.
110
- if command -v terraform >/dev/null 2>&1; then
177
+ if [ -n "$LIST" ] || command -v terraform >/dev/null 2>&1; then
111
178
  # Scope must match this repo's CI, not exceed it. The template and instances
112
179
  # deliberately fmt-check modules/ ONLY: infra/environments/ is user-owned, and
113
180
  # a template-shipped check asserting over paths the template does not own is
@@ -138,20 +205,34 @@ fi
138
205
 
139
206
  # JS, cheapest first; `test` last because it is slowest and the most likely to
140
207
  # be interrupted by an impatient reader.
141
- if [ -f package.json ]; then
208
+ JS_DIRS=$(js_dirs)
209
+ if [ -n "$JS_DIRS" ]; then
142
210
  skip build "excluded - a full app build is too slow for a push gate"
143
- for s in lint typecheck format:check test; do
144
- label=$(printf '%s' "$s" | tr -d ':')
145
- if have_script "$s"; then
146
- run_check "$label" pnpm run "$s"
147
- else
148
- skip "$label" "no \"$s\" script in package.json"
149
- fi
211
+ for d in $JS_DIRS; do
212
+ # Name the package in the label when there is more than one, so a failure
213
+ # says WHERE. A single unlabelled "lint" across three packages is how you
214
+ # end up fixing the wrong one.
215
+ suffix=""
216
+ [ "$d" != "." ] && suffix="(${d#./})"
217
+ for s in lint typecheck format:check test; do
218
+ label="$(printf '%s' "$s" | tr -d ':')$suffix"
219
+ if have_script "$s" "$d"; then
220
+ if [ "$d" = "." ]; then
221
+ run_check "$label" pnpm run "$s"
222
+ else
223
+ run_check "$label" pnpm --dir "$d" run "$s"
224
+ fi
225
+ else
226
+ skip "$label" "no \"$s\" script"
227
+ fi
228
+ done
150
229
  done
151
230
  else
152
- skip javascript "no package.json in this repo"
231
+ skip javascript "no package.json anywhere in this repo"
153
232
  fi
154
233
 
234
+ [ -n "$LIST" ] && exit 0
235
+
155
236
  printf '\n'
156
237
  if [ -n "$FAILED" ]; then
157
238
  printf '\033[31mverify failed:\033[0m%s\n' "$FAILED"
@@ -48,11 +48,28 @@
48
48
  #
49
49
  # Usage:
50
50
  # sh scripts/verify.sh # everything applicable to this repo
51
+ # sh scripts/verify.sh --list # print the checks it WOULD run, and stop
51
52
  # pnpm run verify # same
52
53
  # BIFFO_SKIP_VERIFY=1 git push # escape hatch, for when you mean it
54
+ #
55
+ # `--list` exists so parity with CI can be tested against what this script
56
+ # actually does, rather than against its source text. The checks are assembled
57
+ # at runtime from what the repo has, so grepping the file for `pnpm run lint`
58
+ # proves nothing -- and a parity test that can be satisfied by a comment is not
59
+ # a parity test.
60
+ #
61
+ # `--list` reports what THIS REPO requires, deliberately ignoring whether the
62
+ # tooling happens to be installed here. Parity with CI is a property of the
63
+ # repository; "can this machine run it" is a property of the machine. Conflating
64
+ # them made the parity test pass locally and fail on a CI runner that has no
65
+ # `uv` or `terraform` -- the gate-green/CI-red split this whole exercise exists
66
+ # to remove, reproduced inside its own guard.
53
67
 
54
68
  set -u
55
69
 
70
+ LIST=""
71
+ [ "${1:-}" = "--list" ] && LIST=1
72
+
56
73
  FAILED=""
57
74
  PASSED=""
58
75
  SKIPPED=""
@@ -60,13 +77,62 @@ SKIPPED=""
60
77
  PYTEST="${BIFFO_VERIFY_PYTEST:-}"
61
78
 
62
79
  have_script() {
63
- [ -f package.json ] || return 1
64
- node -e "process.exit(JSON.parse(require('fs').readFileSync('package.json','utf8')).scripts?.['$1']?0:1)" 2>/dev/null
80
+ [ -f "$2/package.json" ] || return 1
81
+ # grep rather than node: --list must work on a machine with no toolchain at
82
+ # all, because what it reports is a property of the repo, not of the machine.
83
+ # Deliberately NOT anchored to line start: that only matches a pretty-printed
84
+ # package.json, and a minified one would silently report "no lint script" --
85
+ # a skip that looks like a considered decision. A false positive here costs a
86
+ # loud `pnpm run` failure; a false negative costs an unchecked push.
87
+ grep -qE "\"$1\"[[:space:]]*:" "$2/package.json"
88
+ }
89
+
90
+ # Every directory holding a JS package this repo owns.
91
+ #
92
+ # A repo with a root package.json is a workspace: `turbo run lint` fans out and
93
+ # running per-package as well would double the work. A repo WITHOUT one keeps
94
+ # its JS in subdirectories -- web/ and web-admin/ in the plugin repos,
95
+ # apps/frontend/ in the siblings -- and their CI runs the same scripts there
96
+ # with `working-directory:`.
97
+ #
98
+ # ## Why this exists (#852)
99
+ #
100
+ # The gate used to check the repo root and nothing else. In the ten repos with
101
+ # no root package.json -- every plugin, every sibling, both runner repos -- it
102
+ # printed `javascript n/a - no package.json in this repo` and then
103
+ # `verify passed`, on repos whose entire frontend is JS. A 100% TypeScript
104
+ # change pushed green with zero JavaScript verification.
105
+ #
106
+ # That is worse than the missing hooks this gate was built to fix. A repo with
107
+ # no hooks makes no claim; this one claimed to have checked. And the standard
108
+ # it was written to enforce says exactly that inapplicable and absent must not
109
+ # look the same -- while reporting "not applicable" for the language the change
110
+ # was written in.
111
+ js_dirs() {
112
+ if [ -f package.json ]; then
113
+ echo "."
114
+ return
115
+ fi
116
+ # `.terraform/` is a DOWNLOAD CACHE of third-party modules, and the two runner
117
+ # repos carry eight vendored lambda packages in it -- each declaring lint and
118
+ # test scripts. Linting someone else's vendored code is slow, always red, and
119
+ # not this repo's business. It is gitignored, so a fresh worktree never has
120
+ # it and the omission was invisible until a primary checkout was audited.
121
+ find . -name package.json \
122
+ -not -path "*/node_modules/*" -not -path "*/dist/*" -not -path "*/.next/*" \
123
+ -not -path "*/.turbo/*" -not -path "*/.worktrees/*" -not -path "*/out/*" \
124
+ -not -path "*/coverage/*" -not -path "*/.venv/*" \
125
+ -not -path "*/.terraform/*" -not -path "*/vendor/*" 2>/dev/null |
126
+ sed 's|/package.json$||' | sort
65
127
  }
66
128
 
67
129
  run_check() {
68
130
  name="$1"
69
131
  shift
132
+ if [ -n "$LIST" ]; then
133
+ echo "$*"
134
+ return 0
135
+ fi
70
136
  start=$(date +%s)
71
137
  if "$@" >"/tmp/biffo-verify.$$" 2>&1; then
72
138
  PASSED="$PASSED $name"
@@ -80,16 +146,17 @@ run_check() {
80
146
  }
81
147
 
82
148
  skip() {
149
+ [ -n "$LIST" ] && return 0
83
150
  SKIPPED="$SKIPPED $1"
84
151
  printf ' \033[90m-- %-16s n/a - %s\033[0m\n' "$1" "$2"
85
152
  }
86
153
 
87
- printf '\nverify - the checks CI runs, before the push\n\n'
154
+ [ -n "$LIST" ] || printf '\nverify - the checks CI runs, before the push\n\n'
88
155
 
89
156
  # Python first: ruff is near-instant, so the cheapest feedback on the largest
90
157
  # single class of failure comes back immediately.
91
158
  if [ -f pyproject.toml ]; then
92
- if command -v uv >/dev/null 2>&1; then
159
+ if [ -n "$LIST" ] || command -v uv >/dev/null 2>&1; then
93
160
  run_check ruff-check uv run ruff check .
94
161
  run_check ruff-format uv run ruff format --check .
95
162
  run_check pyright uv run pyright
@@ -107,7 +174,7 @@ fi
107
174
 
108
175
  # Terraform, wherever this repo keeps it: modules/ in the template and
109
176
  # instances, infra/ and modules/ in siblings.
110
- if command -v terraform >/dev/null 2>&1; then
177
+ if [ -n "$LIST" ] || command -v terraform >/dev/null 2>&1; then
111
178
  # Scope must match this repo's CI, not exceed it. The template and instances
112
179
  # deliberately fmt-check modules/ ONLY: infra/environments/ is user-owned, and
113
180
  # a template-shipped check asserting over paths the template does not own is
@@ -138,20 +205,34 @@ fi
138
205
 
139
206
  # JS, cheapest first; `test` last because it is slowest and the most likely to
140
207
  # be interrupted by an impatient reader.
141
- if [ -f package.json ]; then
208
+ JS_DIRS=$(js_dirs)
209
+ if [ -n "$JS_DIRS" ]; then
142
210
  skip build "excluded - a full app build is too slow for a push gate"
143
- for s in lint typecheck format:check test; do
144
- label=$(printf '%s' "$s" | tr -d ':')
145
- if have_script "$s"; then
146
- run_check "$label" pnpm run "$s"
147
- else
148
- skip "$label" "no \"$s\" script in package.json"
149
- fi
211
+ for d in $JS_DIRS; do
212
+ # Name the package in the label when there is more than one, so a failure
213
+ # says WHERE. A single unlabelled "lint" across three packages is how you
214
+ # end up fixing the wrong one.
215
+ suffix=""
216
+ [ "$d" != "." ] && suffix="(${d#./})"
217
+ for s in lint typecheck format:check test; do
218
+ label="$(printf '%s' "$s" | tr -d ':')$suffix"
219
+ if have_script "$s" "$d"; then
220
+ if [ "$d" = "." ]; then
221
+ run_check "$label" pnpm run "$s"
222
+ else
223
+ run_check "$label" pnpm --dir "$d" run "$s"
224
+ fi
225
+ else
226
+ skip "$label" "no \"$s\" script"
227
+ fi
228
+ done
150
229
  done
151
230
  else
152
- skip javascript "no package.json in this repo"
231
+ skip javascript "no package.json anywhere in this repo"
153
232
  fi
154
233
 
234
+ [ -n "$LIST" ] && exit 0
235
+
155
236
  printf '\n'
156
237
  if [ -n "$FAILED" ]; then
157
238
  printf '\033[31mverify failed:\033[0m%s\n' "$FAILED"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.172.0",
3
+ "version": "0.172.2",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",