refactor(extension): one definition of what ships in the XPI
CI / lint (push) Successful in 3s
CI / extension-version (push) Successful in 4s
extension / lint (push) Successful in 20s
CI / frontend-build (push) Successful in 23s
CI / backend-lint-and-test (push) Successful in 44s
CI / integration (push) Successful in 3m59s
CI / lint (push) Successful in 3s
CI / extension-version (push) Successful in 4s
extension / lint (push) Successful in 20s
CI / frontend-build (push) Successful in 23s
CI / backend-lint-and-test (push) Successful in 44s
CI / integration (push) Successful in 3m59s
Milestone #271 step 1. Groundwork for deriving the extension version from git;
no behavior change yet -- nothing consumes `version` so far.
"Which files end up in the XPI" was stated in two places and about to become
three. Three hand-kept copies of one fact is what allowed #2397, where the
publish path could republish a stale XPI because its cache key had no link to
the content it stood for.
New extension/scripts/packaging.sh holds the single declaration and exposes:
ignore web-ext --ignore-files values
pathspec :(exclude)extension/... for git
version <MAJOR.MINOR from manifest>.<commit count over packaged files>
major-minor / patch
Consumers now delegate instead of restating it:
- extension/package.json -- all four web-ext scripts
- .forgejo/workflows/ci.yml -- the extension-version guard's exclusions
- (step 4) the rev-list that derives the version
scripts/** joins the non-packaged set; the script must not ship to users.
Two shell hazards, both load-bearing:
The script runs `set -euf`. Its lists are iterated with deliberate word
splitting, and without -f the shell ALSO globs them -- invoking `pathspec`
from a directory where test/ exists (exactly how ci.yml calls it) would expand
`test/**` into the individual spec files and silently stop covering anything
added later. A caller's own `set -f` cannot prevent this: the script is a
separate sh process and does not inherit it.
Callers additionally need their own `set -f` for the substituted RESULT, which
is a different expansion. version.spec.js asserts every --ignore-files caller
sets it, that the pathspec comes through with `test/**` literal and no
.spec.js paths, and that neither consumer has reinstated a hardcoded list --
the easy future regression is "simplifying" by inlining one again.
Verified: all five subcommands plus the usage/exit-2 path. Derived version on
main (8300029) is 1.0.19, matching dev. Last published is 1.0.10, so the
eventual cutover moves strictly upward and needs no offset -- Firefox refuses
downgrades. (An earlier note recorded 18; that was measured against a stale
origin/main from before the PR #234 merge.)
Refs #2398
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/bin/sh
|
||||
# Single source of truth for "what ships inside the XPI", plus the version
|
||||
# derived from it.
|
||||
#
|
||||
# Three consumers used to hand-maintain their own copy of this list, and
|
||||
# keeping three copies of one fact in sync by hand is how issue #2397 happened:
|
||||
#
|
||||
# 1. web-ext's --ignore-files (extension/package.json's four scripts)
|
||||
# 2. the :(exclude) pathspec (ci.yml's extension-version guard)
|
||||
# 3. the rev-list pathspec (the derived version, below)
|
||||
#
|
||||
# They now all read from here. POSIX sh only — CI's run shell is busybox.
|
||||
#
|
||||
# -f (no pathname expansion) is set for the whole script and is load-bearing:
|
||||
# the lists below are iterated with deliberate word-splitting, and without -f
|
||||
# the shell would also GLOB them, expanding `test/**` into whatever files
|
||||
# happen to exist and corrupting the output. A caller's own `set -f` does not
|
||||
# help here — this runs as a separate sh process and does not inherit it.
|
||||
# Callers still need their own `set -f` for the substituted result; the two
|
||||
# guards protect different expansions.
|
||||
set -euf
|
||||
|
||||
# Paths under extension/ that are NOT packaged into the XPI.
|
||||
#
|
||||
# Split by whether git tracks them: node_modules and web-ext-artifacts are
|
||||
# build/dependency output that never appears in a commit, so they belong in
|
||||
# web-ext's ignore list but would be meaningless in a git pathspec.
|
||||
NOT_PACKAGED_TRACKED='package.json package-lock.json README.md .gitignore vitest.config.js scripts/** test/**'
|
||||
NOT_PACKAGED_BUILD='web-ext-artifacts node_modules'
|
||||
|
||||
usage() {
|
||||
echo "usage: packaging.sh {ignore|pathspec|version|major-minor|patch}" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
# web-ext --ignore-files values, space-separated.
|
||||
#
|
||||
# Callers MUST disable pathname expansion first (`set -f`), or the shell will
|
||||
# glob `test/**` against the working tree before web-ext ever sees the pattern
|
||||
# and silently narrow it to whatever happens to exist right now.
|
||||
cmd_ignore() {
|
||||
echo "$NOT_PACKAGED_TRACKED $NOT_PACKAGED_BUILD"
|
||||
}
|
||||
|
||||
# git pathspec excluding the non-packaged tracked files, e.g.
|
||||
# :(exclude)extension/package.json :(exclude)extension/test/**
|
||||
# Same `set -f` requirement as above.
|
||||
cmd_pathspec() {
|
||||
for entry in $NOT_PACKAGED_TRACKED; do
|
||||
printf ':(exclude)extension/%s ' "$entry"
|
||||
done
|
||||
echo
|
||||
}
|
||||
|
||||
# MAJOR.MINOR stays hand-set in manifest.json — it's the part that carries
|
||||
# deliberate meaning. Only the patch component is derived.
|
||||
cmd_major_minor() {
|
||||
root=$(git rev-parse --show-toplevel)
|
||||
grep -E '"version"' "$root/extension/manifest.json" \
|
||||
| head -1 \
|
||||
| sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([0-9]+)\.([0-9]+).*/\1.\2/'
|
||||
}
|
||||
|
||||
# Count of commits that touched a PACKAGED extension file. Monotonic on a
|
||||
# branch (the count only grows), which is a correctness requirement, not a
|
||||
# nicety: Firefox refuses to install a version lower than the one present.
|
||||
#
|
||||
# Merge commits need no special handling — git's history simplification already
|
||||
# prunes merges that don't change the pathspec, so --no-merges is a no-op here
|
||||
# (verified on main: both forms return the same count).
|
||||
cmd_patch() {
|
||||
root=$(git rev-parse --show-toplevel)
|
||||
# Unquoted on purpose: the pathspec must word-split into separate args.
|
||||
# Globbing is already off script-wide (set -euf above).
|
||||
# shellcheck disable=SC2046
|
||||
count=$(cd "$root" && git rev-list --count HEAD -- extension/ $(cmd_pathspec))
|
||||
echo "$count"
|
||||
}
|
||||
|
||||
cmd_version() {
|
||||
echo "$(cmd_major_minor).$(cmd_patch)"
|
||||
}
|
||||
|
||||
[ $# -ge 1 ] || usage
|
||||
case "$1" in
|
||||
ignore) cmd_ignore ;;
|
||||
pathspec) cmd_pathspec ;;
|
||||
version) cmd_version ;;
|
||||
major-minor) cmd_major_minor ;;
|
||||
patch) cmd_patch ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user