forked from bchanot/claude
BSD userland rejects or silently ignores several GNU spellings the repo used: - `timeout` is not in a stock macOS at all (Homebrew installs it, and also as `gtimeout`). Without it every gates.sh check exited 127 and was recorded NOT-MET whatever the check actually did — a systematic false negative. The binary is now resolved once, with a pure-bash deadline behind it so the 124 contract still holds where neither binary exists. GATES_TIMEOUT_BIN is overridable with `-` not `:-`, so an empty value forces that fallback: the suite passes 64/64 both ways, timeout cases included. - `touch -d '10 days ago'` is GNU-only; perl's utime is the one spelling both platforms ship. - BSD `wc -l` pads its count with leading spaces, so string compares failed as got[ 48] want[48]. - `sed -i` needs a suffix argument on BSD AND does not expand \n in the replacement, so the release-candidate CHANGELOG edit silently did nothing and the assertion failed for the wrong reason. Rewritten in awk; the RC_TAG=0 mode still REDs on the absent tag, so the test keeps its teeth. - `/bin/grep` does not exist on macOS (grep lives in /usr/bin), and `stat -c` is GNU-only. fast-libs 11/11, seo-data 221/221, release-candidate 5 GREEN / 0 RED.
66 lines
4.2 KiB
Bash
66 lines
4.2 KiB
Bash
#!/usr/bin/env bash
|
|
# run-release-candidate.sh — TDD harness for /release-candidate.
|
|
#
|
|
# The skill is an ORCHESTRATOR over the existing gitflow release mechanic + the ONE
|
|
# piece the lib lacks: the version tag. This harness replays the skill's prescribed
|
|
# sequence on a throwaway repo (gitflow-test style) and asserts the release outcome.
|
|
#
|
|
# RED (RC_TAG=0): run start→prep→finish only (the existing mechanic) → the tag
|
|
# assertion REDS, proving gitflow fans out main+develop but never tags.
|
|
# GREEN(RC_TAG=1): the skill's flow adds `git tag` → tag present on main's merge commit.
|
|
set -uo pipefail
|
|
|
|
GREP=/usr/bin/grep # LRN-074: pin grep
|
|
LIBDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # repo lib/
|
|
GITFLOW="$LIBDIR/gitflow.sh"
|
|
RC_TAG="${RC_TAG:-0}" # 0=RED (no tag), 1=GREEN
|
|
WORK="${RC_WORK:?set RC_WORK to a throwaway dir}"
|
|
|
|
pass=0; fail=0
|
|
ok(){ echo "GREEN ✓ $*"; pass=$((pass+1)); }
|
|
no(){ echo "RED ✗ $*"; fail=$((fail+1)); }
|
|
|
|
# ── seed a throwaway repo: main (v3.5.0) + develop ahead ──────────────────────
|
|
rm -rf "$WORK"; mkdir -p "$WORK"
|
|
git -C "$WORK" init -q
|
|
git -C "$WORK" config user.email t@t; git -C "$WORK" config user.name T
|
|
printf '3.5.0\n' > "$WORK/version.txt"
|
|
printf '# Changelog\n\n## [Unreleased]\n\n### Added\n- new skill foo\n\n## [3.4.0] — 2026-04-15\n- prev\n' > "$WORK/CHANGELOG.md"
|
|
git -C "$WORK" add -A; git -C "$WORK" commit -qm "initial"
|
|
git -C "$WORK" branch -M main
|
|
git -C "$WORK" branch develop
|
|
git -C "$WORK" checkout -q develop
|
|
printf 'feature work\n' > "$WORK/feat.txt"; git -C "$WORK" add -A; git -C "$WORK" commit -qm "feat on develop"
|
|
echo "setup: develop +$(git -C "$WORK" rev-list --count main..develop) vs main, version.txt=$(cat "$WORK/version.txt"), tags=$(git -C "$WORK" tag | wc -l)"
|
|
echo
|
|
|
|
# ── the /release-candidate flow (what the skill prescribes) ──────────────────
|
|
( cd "$WORK" || exit 1
|
|
bash "$GITFLOW" start release 4.0.0 >/dev/null # base develop → release/4.0.0 (lib L49/L71)
|
|
printf '4.0.0\n' > version.txt # prep: version bump
|
|
# awk, not `sed -i`: BSD sed (macOS) needs a suffix argument after -i AND
|
|
# does not expand \n in the replacement — the edit silently did nothing
|
|
# there, so the CHANGELOG assertion below failed for the wrong reason.
|
|
awk '{ print; if ($0 == "## [Unreleased]") { print ""; print "## [4.0.0] — 2026-06-30" } }' \
|
|
CHANGELOG.md > CHANGELOG.tmp && cat CHANGELOG.tmp > CHANGELOG.md && rm -f CHANGELOG.tmp
|
|
git commit -qam "chore(release): 4.0.0 — version.txt + CHANGELOG"
|
|
bash "$GITFLOW" finish >/dev/null # fan-out main+develop+delete (lib L108-111)
|
|
# TAG = the gap. Lives in the SKILL (lib untouched). RED skips it, GREEN does it.
|
|
if [ "$RC_TAG" = "1" ]; then git tag -a v4.0.0 main -m "release 4.0.0"; fi
|
|
)
|
|
|
|
# ── assertions: fan-out (existing mechanic) + the tag (the new piece) ─────────
|
|
echo "=== assertions (RC_TAG=$RC_TAG) ==="
|
|
if [ "$(git -C "$WORK" show main:version.txt 2>/dev/null)" = "4.0.0" ]; then ok "fan-out: main carries the release (version.txt 4.0.0)"; else no "fan-out: main version.txt != 4.0.0"; fi
|
|
if [ "$(git -C "$WORK" show develop:version.txt 2>/dev/null)" = "4.0.0" ]; then ok "merge-back: develop carries 4.0.0"; else no "merge-back failed"; fi
|
|
if git -C "$WORK" show-ref --verify -q refs/heads/release/4.0.0; then no "release/4.0.0 NOT deleted"; else ok "release/4.0.0 branch deleted"; fi
|
|
if git -C "$WORK" show main:CHANGELOG.md | $GREP -q '## \[4.0.0\]'; then ok "CHANGELOG [4.0.0] on main"; else no "CHANGELOG not finalized"; fi
|
|
if git -C "$WORK" rev-parse -q --verify refs/tags/v4.0.0 >/dev/null; then
|
|
if [ "$(git -C "$WORK" rev-list -n1 v4.0.0)" = "$(git -C "$WORK" rev-parse main)" ]; then ok "tag v4.0.0 on main's release-merge commit"; else no "tag v4.0.0 exists but not on main HEAD"; fi
|
|
else
|
|
no "tag v4.0.0 ABSENT — gitflow finish fans out but does NOT tag (the gap /release-candidate fills)"
|
|
fi
|
|
|
|
echo; echo "================ $pass GREEN / $fail RED (RC_TAG=$RC_TAG) ================"
|
|
[ "$fail" -eq 0 ] && exit 0 || exit 1
|