3f622ba646
+ 每次結案都留下估多久/花多久/差多少(inkstone/ISEP#85) #84:scripts/release-manifest freeze 前每一格都真的去 Gitea 抓過(抓不到不給凍結);凍結後不准再加東西; rollback 一定吐出整份清單的每一格,--only 指名單一 repo 會被擋下 ——那正是票上那個病:剩下的還停在新版 ⇒ 一組從來沒測過的組合。 清單與 INDEX.md 寫在專案根的 releases/(不是 plugin 目錄,plugin update 會清掉)。 #85:scripts/milestone-account + hooks/milestone-account-guard.sh 三個數字自己算(取自 Gitea 的 created_at/due_on/closed_at,不用手填); 差超過 ±25%(超時或提早都算)就要從七個固定代號裡挑一個,挑不出來不准結案; 代號要有 Gitea 時間軸撐得住——訊號不成立的代號直接拒收(不採信自述)。 閘擋的是「直接 curl PATCH state=closed 但還沒記帳」,正門走 milestone-account close。 盤點數字在本樹實數(ls hooks/*.sh|grep -c '"command":'): hooks 53→54 支、註冊 68→69 條、scripts 39 支(描述欄舊的 38 把三個目錄也數進去了)。 順手修掉 docs/hooks-inventory.md「一句話結論」被貼兩次、且標頭 52/內文 53 互相矛盾。 測試(全部離線,不打 Gitea、不留測試票/不關真的 milestone): scripts/test-release-manifest.sh 21/21 scripts/test-milestone-account.sh 23/23 hooks/tests/milestone-account-guard.test.sh 22/22 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZBu4Sa1cGntKFRBYNZ6xs
99 lines
5.6 KiB
Bash
Executable File
99 lines
5.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# scripts/release-manifest 的迴歸測試(inkstone/ISEP#84)
|
||
#
|
||
# 兩個方向都要有證據:
|
||
# A 群「該擋」——版本號在 Gitea 抓不到/清單已凍結還想加東西/退版只退一個
|
||
# B 群「該過」——版本號真的存在就凍結得起來、退版吐出整份、diff 看得出差在哪
|
||
# C 群「leo 打開看得懂」——INDEX.md 真的被重寫,而且第一份標著「現在手上的這一版」
|
||
#
|
||
# 🔴 全程離線(RELEASE_MANIFEST_FIXTURE),不打 Gitea、不建任何真的 release。
|
||
# 清單寫在 mktemp 的目錄(RELEASE_MANIFEST_DIR),不碰 repo 裡的 releases/。
|
||
set -u
|
||
TOOL="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/release-manifest}"
|
||
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
|
||
PASS=0; FAIL=0; N=0
|
||
|
||
FX="$TMP/fx.json"
|
||
cat > "$FX" <<'JSON'
|
||
{"versions": {
|
||
"inkstone/Arcrun@v1.4.52": {"kind":"release","url":"u1","commit":"aaaaaaaaaaaa"},
|
||
"inkstone/Arcrun@v1.4.51": {"kind":"release","url":"u2","commit":"bbbbbbbbbbbb"},
|
||
"inkstone/arcrun-collector@v0.18.36": {"kind":"tag","url":"u3","commit":"cccccccccccc"},
|
||
"inkstone/arcrun-collector@v0.18.35": {"kind":"tag","url":"u4","commit":"dddddddddddd"}
|
||
}}
|
||
JSON
|
||
|
||
run() { RELEASE_MANIFEST_FIXTURE="$FX" RELEASE_MANIFEST_DIR="$TMP/rel" python3 "$TOOL" "$@" 2>&1; }
|
||
|
||
# t <期望 exit> <說明> <必須出現的字串(可空)> -- <參數…>
|
||
t() {
|
||
want="$1"; desc="$2"; must="$3"; shift 4
|
||
N=$((N+1))
|
||
out=$(run "$@"); rc=$?
|
||
ok=1
|
||
[ "$rc" -eq "$want" ] || ok=0
|
||
if [ -n "$must" ] && ! printf '%s' "$out" | grep -qF "$must"; then ok=0; fi
|
||
if [ "$ok" -eq 1 ]; then printf ' ✅ %s\n' "$desc"; PASS=$((PASS+1))
|
||
else
|
||
printf ' ❌ %s —— 期望 exit=%s%s,實得 exit=%s\n' "$desc" "$want" \
|
||
"${must:+ 且輸出含「$must」}" "$rc"
|
||
printf '%s\n' "$out" | sed -n '1,8p' | sed 's/^/ /'; FAIL=$((FAIL+1))
|
||
fi
|
||
}
|
||
|
||
echo "── B 群:該過 ──────────────────────────────────────────────"
|
||
t 0 "① 兩個 repo 的版本都真的存在 ⇒ 凍結得起來" "已凍結(2 個 repo" -- \
|
||
freeze R-2026.08.29 --part inkstone/Arcrun@v1.4.51 --part inkstone/arcrun-collector@v0.18.35
|
||
t 0 "② 單一 repo 的交貨不必特例(清單退化成一格)" "已凍結(1 個 repo" -- \
|
||
freeze R-single --part inkstone/Arcrun@v1.4.51
|
||
t 0 "③ 再凍一份新的(這才是「新的需求進下一版」)" "已凍結(2 個 repo" -- \
|
||
freeze R-2026.08.30 --part inkstone/Arcrun@v1.4.52 --part inkstone/arcrun-collector@v0.18.36
|
||
t 0 "④ current 答得出「我現在手上是哪一版」" "R-2026.08.30" -- current
|
||
t 0 "⑤ verify:每一格都還抓得到" "全部 2 格都還抓得到" -- verify R-2026.08.30
|
||
t 0 "⑥ diff 看得出兩份差在哪一格" "v1.4.51 → v1.4.52" -- diff R-2026.08.29 R-2026.08.30
|
||
t 0 "⑦ --dry-run 不寫檔" "一個檔都沒有真的寫出去" -- \
|
||
freeze R-dryrun --part inkstone/Arcrun@v1.4.52 --dry-run
|
||
t 2 "⑧ 承上:--dry-run 那份真的沒被寫出去" "沒有這份清單" -- show R-dryrun
|
||
|
||
echo "── A 群:該擋 ──────────────────────────────────────────────"
|
||
t 2 "⑨ 版本號在 Gitea 抓不到 ⇒ 不給凍結(驗收 1)" "在 Gitea 上抓不到" -- \
|
||
freeze R-bad --part inkstone/Arcrun@v9.9.9
|
||
t 2 "⑩ 承上:整份都不寫(不會留下半份清單)" "沒有這份清單" -- show R-bad
|
||
t 2 "⑪ 一格都不給 ⇒ 擋" "至少要有一格" -- freeze R-empty
|
||
t 2 "⑫ 同名清單已凍結 ⇒ 不准再加東西" "新的需求進下一版" -- \
|
||
freeze R-2026.08.30 --part inkstone/Arcrun@v1.4.51
|
||
t 2 "⑬ 同一個 repo 出現兩次 ⇒ 擋" "出現兩次" -- \
|
||
freeze R-dup --part inkstone/Arcrun@v1.4.51 --part inkstone/Arcrun@v1.4.52
|
||
t 2 "⑭ 清單名亂寫 ⇒ 擋" "清單名只准" -- freeze "R 2026/08" --part inkstone/Arcrun@v1.4.51
|
||
t 2 "⑮ part 寫法不對 ⇒ 擋" "寫法是 owner/repo@版本號" -- \
|
||
freeze R-x --part Arcrun-v1.4.52
|
||
|
||
echo "── 驗收 2/3:退版 ─────────────────────────────────────────"
|
||
t 0 "⑯ 退版吐出整份清單的每一格(驗收 2)" "這 2 格是一組" -- rollback R-2026.08.29
|
||
t 0 "⑰ 承上:兩個 repo 都被列進「要動的」" "arcrun-collector" -- rollback R-2026.08.29
|
||
t 2 "⑱ 試著只退其中一個 ⇒ 被擋下來(驗收 3)" "沒有「只退一個」這個選項" -- \
|
||
rollback R-2026.08.29 --only inkstone/Arcrun
|
||
t 0 "⑲ 已經在目標版本的那幾格也要列出來(沒有一格被漏掉)" "不必動" -- \
|
||
rollback R-2026.08.30
|
||
|
||
echo "── 驗收 4:leo 打開那份清單看得懂 ──────────────────────────"
|
||
N=$((N+1))
|
||
IDX="$TMP/rel/INDEX.md"
|
||
if [ -f "$IDX" ] && grep -q "現在手上的這一版" "$IDX" \
|
||
&& grep -q "R-2026.08.30" "$IDX" && grep -q "從來沒測過的組合" "$IDX"; then
|
||
printf ' ✅ ⑳ INDEX.md 被重寫,標出「現在手上的這一版」與為什麼要有它\n'; PASS=$((PASS+1))
|
||
else
|
||
printf ' ❌ ⑳ INDEX.md 內容不對\n'; sed -n '1,20p' "$IDX" 2>/dev/null | sed 's/^/ /'
|
||
FAIL=$((FAIL+1))
|
||
fi
|
||
N=$((N+1))
|
||
if head -20 "$IDX" 2>/dev/null | grep -A2 "R-2026.08.30" | grep -q "現在手上的這一版"; then
|
||
printf ' ✅ ㉑ 最新那一份(不是最舊那份)才被標成「現在手上的」\n'; PASS=$((PASS+1))
|
||
else
|
||
printf ' ❌ ㉑ 標錯了哪一份是現在手上的\n'; FAIL=$((FAIL+1))
|
||
fi
|
||
|
||
echo
|
||
echo "通過 $PASS 條,失敗 $FAIL 條(共 $N 條)"
|
||
[ "$FAIL" -eq 0 ]
|