@biffo/cli 0.304.0 → 0.304.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.
- package/dist/index.js +72 -7
- package/package.json +1 -1
- package/scripts/verify.sh +118 -2
package/dist/index.js
CHANGED
|
@@ -717,12 +717,28 @@ function checkCoreOwnership({
|
|
|
717
717
|
isInstance,
|
|
718
718
|
branch = "",
|
|
719
719
|
commitMessage = "",
|
|
720
|
-
warnOnly = []
|
|
720
|
+
warnOnly = [],
|
|
721
|
+
templateShippedPaths = null
|
|
721
722
|
}) {
|
|
722
|
-
const empty = {
|
|
723
|
+
const empty = {
|
|
724
|
+
blocked: [],
|
|
725
|
+
warned: [],
|
|
726
|
+
divergenceReason: null,
|
|
727
|
+
convergenceReason: null,
|
|
728
|
+
knownOrphans: []
|
|
729
|
+
};
|
|
723
730
|
if (!isInstance) return { skipped: "template", ...empty };
|
|
724
731
|
if (branch.startsWith(UPGRADE_BRANCH_PREFIX)) return { skipped: "upgrade-branch", ...empty };
|
|
725
|
-
const
|
|
732
|
+
const manifestTemplateOwned = changedFiles.filter((f) => isTemplateOwned(f, manifest));
|
|
733
|
+
const knownOrphans = [];
|
|
734
|
+
const templateOwned = [];
|
|
735
|
+
for (const path of manifestTemplateOwned) {
|
|
736
|
+
if (templateShippedPaths != null && !templateShippedPaths.has(path)) {
|
|
737
|
+
knownOrphans.push(path);
|
|
738
|
+
} else {
|
|
739
|
+
templateOwned.push(path);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
726
742
|
const acknowledged = (path) => warnOnly.filter((entry) => path.startsWith(entry.prefix)).reduce(
|
|
727
743
|
(best, entry) => !best || entry.prefix.length > best.prefix.length ? entry : best,
|
|
728
744
|
void 0
|
|
@@ -743,7 +759,8 @@ function checkCoreOwnership({
|
|
|
743
759
|
blocked: [],
|
|
744
760
|
warned,
|
|
745
761
|
divergenceReason,
|
|
746
|
-
convergenceReason: null
|
|
762
|
+
convergenceReason: null,
|
|
763
|
+
knownOrphans
|
|
747
764
|
};
|
|
748
765
|
}
|
|
749
766
|
if (convergenceReason !== null) {
|
|
@@ -752,7 +769,8 @@ function checkCoreOwnership({
|
|
|
752
769
|
blocked: [],
|
|
753
770
|
warned,
|
|
754
771
|
divergenceReason: null,
|
|
755
|
-
convergenceReason
|
|
772
|
+
convergenceReason,
|
|
773
|
+
knownOrphans
|
|
756
774
|
};
|
|
757
775
|
}
|
|
758
776
|
}
|
|
@@ -761,7 +779,8 @@ function checkCoreOwnership({
|
|
|
761
779
|
blocked: offending,
|
|
762
780
|
warned,
|
|
763
781
|
divergenceReason: null,
|
|
764
|
-
convergenceReason: null
|
|
782
|
+
convergenceReason: null,
|
|
783
|
+
knownOrphans
|
|
765
784
|
};
|
|
766
785
|
}
|
|
767
786
|
|
|
@@ -12255,6 +12274,37 @@ async function runCoreDirectPathsCheck(opts = {}) {
|
|
|
12255
12274
|
console.log(`\u2713 core-direct-paths guard: ${report.summary}`);
|
|
12256
12275
|
}
|
|
12257
12276
|
|
|
12277
|
+
// src/lib/template-shipped-paths.ts
|
|
12278
|
+
var TEMPLATE_UPSTREAM_OWNER = "keiranholloway";
|
|
12279
|
+
var TEMPLATE_UPSTREAM_REPO = "biffo-template";
|
|
12280
|
+
var TEMPLATE_UPSTREAM_BRANCH = "dev";
|
|
12281
|
+
var defaultRunner = async (args, cwd) => {
|
|
12282
|
+
const result = await execa("git", args, { cwd, reject: false, timeout: 15e3 });
|
|
12283
|
+
return { stdout: String(result.stdout ?? ""), exitCode: result.exitCode ?? null };
|
|
12284
|
+
};
|
|
12285
|
+
async function fetchTemplateShippedPaths(repoRoot, runner = defaultRunner) {
|
|
12286
|
+
const url = `https://github.com/${TEMPLATE_UPSTREAM_OWNER}/${TEMPLATE_UPSTREAM_REPO}.git`;
|
|
12287
|
+
let fetched;
|
|
12288
|
+
try {
|
|
12289
|
+
fetched = await runner(
|
|
12290
|
+
["fetch", "--depth", "1", "--quiet", url, TEMPLATE_UPSTREAM_BRANCH],
|
|
12291
|
+
repoRoot
|
|
12292
|
+
);
|
|
12293
|
+
} catch {
|
|
12294
|
+
return null;
|
|
12295
|
+
}
|
|
12296
|
+
if (fetched.exitCode !== 0) return null;
|
|
12297
|
+
let tree;
|
|
12298
|
+
try {
|
|
12299
|
+
tree = await runner(["ls-tree", "-r", "--name-only", "FETCH_HEAD"], repoRoot);
|
|
12300
|
+
} catch {
|
|
12301
|
+
return null;
|
|
12302
|
+
}
|
|
12303
|
+
if (tree.exitCode !== 0) return null;
|
|
12304
|
+
const paths = tree.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
12305
|
+
return paths.length > 0 ? new Set(paths) : null;
|
|
12306
|
+
}
|
|
12307
|
+
|
|
12258
12308
|
// src/scripts/check-core-ownership.ts
|
|
12259
12309
|
var BOLD = "\x1B[1m";
|
|
12260
12310
|
var DIM = "\x1B[2m";
|
|
@@ -12310,14 +12360,29 @@ async function runOwnershipCheck(argv) {
|
|
|
12310
12360
|
reject: false
|
|
12311
12361
|
});
|
|
12312
12362
|
const branch = resolveBranch(process.env, gitBranch);
|
|
12363
|
+
const templateShippedPaths = staged ? null : await fetchTemplateShippedPaths(root);
|
|
12364
|
+
if (!staged && templateShippedPaths === null) {
|
|
12365
|
+
console.error(
|
|
12366
|
+
`${YELLOW}\u26A0 core ownership guard: could not fetch biffo-template's dev tree (offline, network failure, or timeout) \u2014 falling back to the manifest prefix list alone, which cannot tell an instance-only file from a real template file under the same prefix (#1912).${OFF}`
|
|
12367
|
+
);
|
|
12368
|
+
}
|
|
12313
12369
|
const result = checkCoreOwnership({
|
|
12314
12370
|
changedFiles,
|
|
12315
12371
|
manifest: readCoreManifest(root),
|
|
12316
12372
|
isInstance: true,
|
|
12317
12373
|
branch,
|
|
12318
12374
|
commitMessage,
|
|
12319
|
-
warnOnly: readDivergenceConfig(root).warnOnly
|
|
12375
|
+
warnOnly: readDivergenceConfig(root).warnOnly,
|
|
12376
|
+
templateShippedPaths
|
|
12320
12377
|
});
|
|
12378
|
+
if (result.knownOrphans.length > 0) {
|
|
12379
|
+
console.log(
|
|
12380
|
+
`${DIM}\u2139 ${result.knownOrphans.length} path(s) matched a template-owned prefix, but biffo-template's dev branch does not ship them \u2014 treated as instance-owned, no Core-Divergence trailer needed (#1912):${OFF}`
|
|
12381
|
+
);
|
|
12382
|
+
for (const path of result.knownOrphans) {
|
|
12383
|
+
console.log(` ${DIM}${path}${OFF}`);
|
|
12384
|
+
}
|
|
12385
|
+
}
|
|
12321
12386
|
for (const { path, entry } of result.warned) {
|
|
12322
12387
|
console.error(
|
|
12323
12388
|
`${YELLOW}\u26A0 ${path}${OFF} ${DIM}\u2014 known divergence in ${entry.prefix} (${entry.upstream}); still conflicts at the next core upgrade.${OFF}`
|
package/package.json
CHANGED
package/scripts/verify.sh
CHANGED
|
@@ -1630,6 +1630,118 @@ if ci_has "gitleaks"; then
|
|
|
1630
1630
|
fi
|
|
1631
1631
|
fi
|
|
1632
1632
|
|
|
1633
|
+
# Resolve the exact `pnpm` invocation every JS check below runs through
|
|
1634
|
+
# (biffo-template#1920).
|
|
1635
|
+
#
|
|
1636
|
+
# ## The defect
|
|
1637
|
+
#
|
|
1638
|
+
# Modern `pnpm` self-manages its own version: it reads the nearest ancestor
|
|
1639
|
+
# `package.json`'s `packageManager` field and, if the field pins a version
|
|
1640
|
+
# other than the binary currently running, re-execs that pinned version
|
|
1641
|
+
# instead (no `corepack enable` required -- this is `pnpm`'s own built-in
|
|
1642
|
+
# behaviour, confirmed by direct experiment against the actual binary this
|
|
1643
|
+
# machine has installed, not by reading its source). That resolution walks
|
|
1644
|
+
# UP from the invoking process's cwd, so it silently stops applying the
|
|
1645
|
+
# moment a check's working directory has no ancestor `package.json`
|
|
1646
|
+
# declaring the field at all -- which is exactly what
|
|
1647
|
+
# `cli/src/lib/verify-toolchain-missing.test.ts`'s own fixtures are: bare,
|
|
1648
|
+
# isolated tmp git repos with a minimal `package.json` (deliberately, to
|
|
1649
|
+
# simulate a fresh worktree before `pnpm install`) that carries no
|
|
1650
|
+
# `packageManager` field. On a machine whose globally-installed `pnpm`
|
|
1651
|
+
# binary is any OTHER version -- observed: v12.3.4, against this repo's own
|
|
1652
|
+
# pin of v9.15.9 -- the fixture's checks silently run under that OTHER
|
|
1653
|
+
# version instead.
|
|
1654
|
+
#
|
|
1655
|
+
# `run_check_js`'s own INCONCLUSIVE/FAILED split below is a grep against
|
|
1656
|
+
# wording pnpm 9.15.9 specifically prints for a missing toolchain
|
|
1657
|
+
# (`node_modules missing, did you mean to install?`), which a different
|
|
1658
|
+
# major does not necessarily print at all: confirmed live, pnpm 12.3.4 skips
|
|
1659
|
+
# that WARN entirely for the identical missing-toolchain scenario, so the
|
|
1660
|
+
# fixture's real "binary not found" failure reads as an ordinary FAILED
|
|
1661
|
+
# instead of INCONCLUSIVE -- not because detection is wrong, but because two
|
|
1662
|
+
# different pnpm versions produced two different diagnoses of the same
|
|
1663
|
+
# state, and only one of them was ever read.
|
|
1664
|
+
#
|
|
1665
|
+
# ## The fix
|
|
1666
|
+
#
|
|
1667
|
+
# Make the version actually executed impossible to disagree with the
|
|
1668
|
+
# version the detection regex was written against, rather than occasionally
|
|
1669
|
+
# undetected: every `pnpm run`/`pnpm --dir` call in this file is eligible to
|
|
1670
|
+
# be pinned to the EXACT version PINNED IN THE REPO THIS COPY OF verify.sh
|
|
1671
|
+
# LIVES IN, via `corepack`, which forces a specific `pnpm@<version>`
|
|
1672
|
+
# regardless of the PATH order on the invoking machine or of the checked
|
|
1673
|
+
# directory's own `package.json`. Node ships `corepack` alongside itself
|
|
1674
|
+
# from Node 16.9 onward -- this repo's own `engines.node` requires >=22 --
|
|
1675
|
+
# so it is resolved relative to `node` rather than assumed to already be on
|
|
1676
|
+
# PATH (`corepack enable` symlinks it onto PATH but is not required for
|
|
1677
|
+
# `corepack pnpm@<version> ...` to work directly). "Eligible": the pin is
|
|
1678
|
+
# only actually forced when bare `pnpm` would not already resolve to it
|
|
1679
|
+
# unassisted -- see the ambient-version check below for why forcing it
|
|
1680
|
+
# unconditionally is itself a regression, not just unnecessary.
|
|
1681
|
+
#
|
|
1682
|
+
# Deliberately NOT `package.json` in `$PWD`: every real invocation happens
|
|
1683
|
+
# with cwd already at the repo root (`.githooks/pre-push` itself `cd`s there
|
|
1684
|
+
# first), so cwd and "the repo this script belongs to" are the same
|
|
1685
|
+
# directory on every real path -- but the toolchain-missing fixtures above
|
|
1686
|
+
# invoke this exact file with cwd pointed at an isolated, unrelated tmp repo
|
|
1687
|
+
# on purpose, to simulate a fresh worktree of SOME OTHER project before
|
|
1688
|
+
# `pnpm install`. That target has no reason to carry (and must not need to
|
|
1689
|
+
# carry) this repo's own pnpm pin merely to be checked correctly, so the pin
|
|
1690
|
+
# is read from where `$0` says this script actually lives, not from
|
|
1691
|
+
# whatever happens to be checked.
|
|
1692
|
+
PNPM_RUN="pnpm"
|
|
1693
|
+
if [ -z "$LIST" ]; then
|
|
1694
|
+
_verify_script_dir=$(cd "$(dirname "$0")" 2>/dev/null && pwd) || _verify_script_dir=""
|
|
1695
|
+
_verify_repo_root=""
|
|
1696
|
+
[ -n "$_verify_script_dir" ] && _verify_repo_root="$_verify_script_dir/.."
|
|
1697
|
+
if [ -z "$_verify_repo_root" ] || [ ! -f "$_verify_repo_root/package.json" ]; then
|
|
1698
|
+
# Could not resolve $0 to a real path (e.g. sourced from stdin) -- cwd is
|
|
1699
|
+
# the only fallback left, and matches every real invocation anyway.
|
|
1700
|
+
_verify_repo_root="."
|
|
1701
|
+
fi
|
|
1702
|
+
if [ -f "$_verify_repo_root/package.json" ]; then
|
|
1703
|
+
_pnpm_pin=$(grep -oE '"packageManager"[[:space:]]*:[[:space:]]*"pnpm@[0-9][^"]*"' "$_verify_repo_root/package.json" |
|
|
1704
|
+
sed -E 's/.*"pnpm@([^"]*)".*/\1/')
|
|
1705
|
+
# Ask bare `pnpm` what it would already resolve to from $PWD before ever
|
|
1706
|
+
# reaching for corepack. On every REAL check this already equals
|
|
1707
|
+
# `$_pnpm_pin` -- self-management (above) finds this repo's own pin by
|
|
1708
|
+
# walking up from cwd, which is always the repo root -- and in that case
|
|
1709
|
+
# `PNPM_RUN` is deliberately left as plain `pnpm`. This matters beyond
|
|
1710
|
+
# tidiness: `pnpm run test` fans out through turbo, which shells back out
|
|
1711
|
+
# to a bare `pnpm` of its own for each workspace package, and pnpm
|
|
1712
|
+
# refuses to self-manage a SECOND time once corepack has already forced
|
|
1713
|
+
# a version once in the process tree (`ERR_PNPM_BAD_PM_VERSION`,
|
|
1714
|
+
# confirmed live -- ordinary `pnpm run test` segfaulted under a
|
|
1715
|
+
# corepack-wrapped outer call). Reaching for corepack is therefore
|
|
1716
|
+
# reserved for the one case it actually fixes: bare `pnpm` disagreeing
|
|
1717
|
+
# with our pin because nothing above cwd declares one at all (the
|
|
1718
|
+
# toolchain-missing fixtures' isolated tmp repos) -- never the ordinary
|
|
1719
|
+
# path where self-management was already correct on its own.
|
|
1720
|
+
if [ -n "$_pnpm_pin" ] && [ "$(pnpm --version 2>/dev/null)" != "$_pnpm_pin" ]; then
|
|
1721
|
+
_corepack=$(command -v corepack 2>/dev/null)
|
|
1722
|
+
if [ -z "$_corepack" ]; then
|
|
1723
|
+
_node_path=$(command -v node 2>/dev/null)
|
|
1724
|
+
if [ -n "$_node_path" ]; then
|
|
1725
|
+
# `node` on PATH is routinely a symlink into a version manager's
|
|
1726
|
+
# real install directory (nvm, a `~/.local/bin` shim, etc.) --
|
|
1727
|
+
# `corepack` ships as node's OWN sibling in THAT real directory, not
|
|
1728
|
+
# next to wherever the symlink happens to sit, so the link must be
|
|
1729
|
+
# resolved before taking dirname. `readlink -f` is GNU/Linux (every
|
|
1730
|
+
# machine this runs on -- workstation and `ubuntu-24.04` CI alike);
|
|
1731
|
+
# falling back to the unresolved path costs nothing worse than the
|
|
1732
|
+
# `command -v corepack` miss this branch already handles above.
|
|
1733
|
+
_node_real=$(readlink -f "$_node_path" 2>/dev/null) || _node_real="$_node_path"
|
|
1734
|
+
_node_bin_dir=$(dirname "$_node_real")
|
|
1735
|
+
[ -x "$_node_bin_dir/corepack" ] && _corepack="$_node_bin_dir/corepack"
|
|
1736
|
+
fi
|
|
1737
|
+
fi
|
|
1738
|
+
if [ -n "$_corepack" ] && "$_corepack" "pnpm@$_pnpm_pin" --version >/dev/null 2>&1; then
|
|
1739
|
+
PNPM_RUN="$_corepack pnpm@$_pnpm_pin"
|
|
1740
|
+
fi
|
|
1741
|
+
fi
|
|
1742
|
+
fi
|
|
1743
|
+
fi
|
|
1744
|
+
|
|
1633
1745
|
# JS, cheapest first; `test` last because it is slowest and the most likely to
|
|
1634
1746
|
# be interrupted by an impatient reader.
|
|
1635
1747
|
JS_DIRS=$(js_dirs)
|
|
@@ -1646,9 +1758,13 @@ if [ -n "$JS_DIRS" ]; then
|
|
|
1646
1758
|
label="$(printf '%s' "$s" | tr -d ':')$suffix"
|
|
1647
1759
|
if have_script "$s" "$d"; then
|
|
1648
1760
|
if [ "$d" = "." ]; then
|
|
1649
|
-
|
|
1761
|
+
# shellcheck disable=SC2086 # $PNPM_RUN is a deliberately unquoted,
|
|
1762
|
+
# internally-computed word list (corepack + pnpm@<version>, or the
|
|
1763
|
+
# single word "pnpm") -- never external input.
|
|
1764
|
+
run_check_js "$label" $PNPM_RUN run "$s"
|
|
1650
1765
|
else
|
|
1651
|
-
|
|
1766
|
+
# shellcheck disable=SC2086 # see above
|
|
1767
|
+
run_check_js "$label" $PNPM_RUN --dir "$d" run "$s"
|
|
1652
1768
|
fi
|
|
1653
1769
|
else
|
|
1654
1770
|
skip "$label" "no \"$s\" script"
|