test: root-commit fixtures — (none) base, D2 loud-death pin, e2e chain

facts.test.sh: greenfield fixtures for all-zeros and empty event.before,
the bare root establishing labeled=no, and the D2 pin (an unresolvable
MERGE_SHA exits 128 and never reports base_ver=(none) — the test that
|| true would fail). release-chain.test.sh: chain() gains optional
repo/stub args; a -dev root commit is a green NOTICE ceremony=no, a bare
unlabeled root still refuses. Plus changelog.d/134.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
claude-bot-andresmgsl 2026-07-24 12:16:04 +00:00
parent 7477d3ec95
commit a17e49737f
3 changed files with 90 additions and 4 deletions

1
changelog.d/134.md Normal file
View file

@ -0,0 +1 @@
- `lib/facts.sh` — a repository's first push to `main` (a root commit with no first parent) now reads `base_ver=(none)` and lets decide's table govern, instead of dying at exit 128 before establishing a fact; the no-base path skips the base fetch and `git show`, and an unresolvable head still fails loudly (#134).

View file

@ -146,6 +146,42 @@ adoptb_head="$(commit adoption-bare VERSION 0.1.0)"
check "absent-at-base with a bare head still asks for the label" 0 "labeled=yes" \ check "absent-at-base with a bare head still asks for the label" 0 "labeled=yes" \
facts_in adoption-bare VERSION_SOURCE=file MERGE_SHA="$adoptb_head" EVENT_BEFORE="$adoptb_base" GH_STUB=labeled-yes facts_in adoption-bare VERSION_SOURCE=file MERGE_SHA="$adoptb_head" EVENT_BEFORE="$adoptb_base" GH_STUB=labeled-yes
# --- a root commit: no base tree at all (the repository's first push) --------
# The first push to main IS a branch-create push (event.before all-zeros)
# whose head has no first parent — there is no base, and the honest fact is
# "(none)", not an exit-128 death at rev-parse. Both 0.2.0 drills hit the
# death independently (#134). The -dev row consults no API (stub default),
# which also asserts the no-base path runs no base fetch/show at all.
repo greenfield
green_head="$(commit greenfield VERSION 0.1.0-dev)"
check "root commit, all-zeros event.before: base_ver=(none)" 0 "base_ver=(none)" \
facts_in greenfield VERSION_SOURCE=file MERGE_SHA="$green_head" EVENT_BEFORE="$ZEROS"
check "root commit, empty event.before: base_ver=(none)" 0 "base_ver=(none)" \
facts_in greenfield VERSION_SOURCE=file MERGE_SHA="$green_head" EVENT_BEFORE=
repo greenfield-bare
greenb_head="$(commit greenfield-bare VERSION 0.1.0)"
check "bare root commit still establishes labeled, so decide can refuse" 0 "labeled=no" \
facts_in greenfield-bare VERSION_SOURCE=file MERGE_SHA="$greenb_head" EVENT_BEFORE="$ZEROS" GH_STUB=labeled-no
# The D2 pin: "no first parent" is detected, never inferred from a failed
# command — an unresolvable MERGE_SHA is a loud death, not "(none)". A
# `|| true` around the fallback would pass every case above and fail here.
BAD_SHA="1111111111111111111111111111111111111111"
check "an unresolvable MERGE_SHA still dies loudly" 128 "bad object" \
facts_in greenfield VERSION_SOURCE=file MERGE_SHA="$BAD_SHA" EVENT_BEFORE="$ZEROS"
bad_out="$(facts_in greenfield VERSION_SOURCE=file MERGE_SHA="$BAD_SHA" EVENT_BEFORE="$ZEROS" 2>&1)"
if printf '%s' "$bad_out" | grep -qF "base_ver=(none)"; then
echo "FAIL: an unresolvable MERGE_SHA must not be reported as base_ver=(none)"
printf '%s\n' "$bad_out" | sed 's/^/ /'
FAIL=$((FAIL + 1))
else
echo "ok: an unresolvable MERGE_SHA is not reported as base_ver=(none)"
PASS=$((PASS + 1))
fi
# --- the package-json backend ------------------------------------------------ # --- the package-json backend ------------------------------------------------
repo pkg repo pkg

View file

@ -69,12 +69,14 @@ git -C "$TMP/repo" add VERSION CHANGELOG.md
git -C "$TMP/repo" commit -qm "release: 0.7.0" git -C "$TMP/repo" commit -qm "release: 0.7.0"
MERGE_SHA="$(git -C "$TMP/repo" rev-parse HEAD)" MERGE_SHA="$(git -C "$TMP/repo" rev-parse HEAD)"
# chain <merge_sha> <event_before> — facts, then decide fed from facts' # chain <merge_sha> <event_before> [repo_dir] [stub_dir] — facts, then
# output lines, then the notes extraction, printing each stage's result. # decide fed from facts' output lines, then the notes extraction, printing
# each stage's result. The optional dirs default to the main fixture; the
# greenfield cases below (#134) bring their own repo and stub.
chain() { chain() {
( (
cd "$TMP/repo" || exit 1 cd "${3:-$TMP/repo}" || exit 1
facts_out="$(env PATH="$TMP/stub:$PATH" GITHUB_REPOSITORY=fixture/fixture \ facts_out="$(env PATH="${4:-$TMP/stub}:$PATH" GITHUB_REPOSITORY=fixture/fixture \
GH_TOKEN=stub VERSION_SOURCE=file MERGE_SHA="$1" EVENT_BEFORE="$2" \ GH_TOKEN=stub VERSION_SOURCE=file MERGE_SHA="$1" EVENT_BEFORE="$2" \
bash "$FACTS")" || exit 1 bash "$FACTS")" || exit 1
printf '%s\n' "$facts_out" printf '%s\n' "$facts_out"
@ -150,4 +152,51 @@ check "the post-release bump decides ceremony=no" 0 "ceremony=no" \
check "an ordinary -dev merge decides ceremony=no" 0 "ceremony=no" \ check "an ordinary -dev merge decides ceremony=no" 0 "ceremony=no" \
chain "$WORK2_SHA" "$BUMP_SHA" chain "$WORK2_SHA" "$BUMP_SHA"
# --- the repository's first push to main: a root commit, no base (#134) ------
# event.before is all-zeros and the head has no first parent. facts reads
# base_ver=(none) instead of dying at rev-parse, and decide's table governs
# from there: the guided bootstrap (-dev first commit, what CONSUMERS.md
# tells a new repo to write) is a green NOTICE no-op — the doctrine's
# promise held at the exact moment a consumer adopts the ceremony.
ZEROS="0000000000000000000000000000000000000000"
git init -q "$TMP/greenfield"
git -C "$TMP/greenfield" config user.email fixture@example.invalid
git -C "$TMP/greenfield" config user.name fixture
printf '0.1.0-dev\n' >"$TMP/greenfield/VERSION"
git -C "$TMP/greenfield" add VERSION
git -C "$TMP/greenfield" commit -qm "root: adopt the ceremony at 0.1.0-dev"
GREEN_SHA="$(git -C "$TMP/greenfield" rev-parse HEAD)"
check "a greenfield -dev root commit decides ceremony=no, not a red run" 0 "ceremony=no" \
chain "$GREEN_SHA" "$ZEROS" "$TMP/greenfield"
check "the greenfield no-op is a NOTICE" 0 "NOTICE:" \
chain "$GREEN_SHA" "$ZEROS" "$TMP/greenfield"
# A bare first commit with no merged release-labeled PR must still refuse —
# the reason the crash could not be `|| true`-ed away: a greenfield adoption
# must never become a silent release. This stub answers the labeled query
# with false.
mkdir -p "$TMP/stub-unlabeled"
cat >"$TMP/stub-unlabeled/gh" <<'EOF'
#!/usr/bin/env bash
if [ "$1" = api ]; then echo false; exit 0; fi
echo "gh stub: unexpected call: gh $*" >&2
exit 97
EOF
chmod +x "$TMP/stub-unlabeled/gh"
git init -q "$TMP/greenfield-bare"
git -C "$TMP/greenfield-bare" config user.email fixture@example.invalid
git -C "$TMP/greenfield-bare" config user.name fixture
printf '0.1.0\n' >"$TMP/greenfield-bare/VERSION"
git -C "$TMP/greenfield-bare" add VERSION
git -C "$TMP/greenfield-bare" commit -qm "root: bare 0.1.0, nobody declared a release"
GREENB_SHA="$(git -C "$TMP/greenfield-bare" rev-parse HEAD)"
check "a bare unlabeled root commit still refuses, creating nothing" 1 \
"no merged, release-labeled PR" \
chain "$GREENB_SHA" "$ZEROS" "$TMP/greenfield-bare" "$TMP/stub-unlabeled"
summary summary