Files
ISEP/scripts/check-version-consistency.sh
T
Leo e4e3d69acf fix(release): 版本只有 Gitea Releases 答得出來,不再靠 README 自報(inkstone/ISEP#6)
現況:README.md 宣稱「狀態 0.1.0」,但 repo release_counter=0、一個 tag
都沒打。leo 當場指出這是違規,命中規範自己的 E12(宣稱交付但沒有 tag);
leo 補充:「release 不是寫在 readme,要放在 release 裡」。

改法(結構性防漂移,不是靠人記得同步):
- README.md 不再自行宣告版本號,改成指向 Gitea Releases 頁面
- .claude-plugin/plugin.json 的 version 改回哨兵值 0.0.0
  (=誠實承認目前沒有一個經過驗證、掛在 Releases 上的版本;
  真正打 tag 那天才跟 tag 一起同步成那個號碼)
- 新增 scripts/check-version-consistency.sh:隨時可跑的一致性檢查
  (plugin.json version 是否等於最新 tag/README 是否偷偷自報版本)
- 新增 hooks/release-tag-guard.sh:PreToolUse Bash 閘,在真正打 git tag
  的那一刻擋下與 plugin.json 不一致的版本號,註冊進 hooks.json

紅線:本次不打 tag、不建 release——那是總管驗過整個 milestone 之後的動作,
這裡交的是機制與草稿。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 13:10:00 +08:00

88 lines
4.1 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# check-version-consistency.sh — ISEP 版本一致性檢查(inkstone/ISEP#6
#
# 立這支的來由(2026-08-20):README.md 曾寫死「狀態:0.1.0」,
# 但這個 repo `release_counter=0`、一個 tag 都沒打。leo 當場指出這是違規,
# 且命中規範自己的 E12(宣稱交付但沒有 tag);leo 補充:
# 「release 不是寫在 readme,要放在 release 裡」。
#
# 判準只有一句:**「ISEP 現在是哪一版」只有一個地方答得出來= Gitea Releasesgit tag)。**
# 其他地方要嘛指過去、要嘛跟它機械同步,不准各自宣告一個號碼。
#
# 1. `.claude-plugin/plugin.json` 的 `version` 欄位,必須跟「最新的 tag」完全一致。
# 還沒打過任何 tag 時(現在就是這個狀態),version 欄位必須是哨兵值 `0.0.0`
# ──意思是「這份 manifest 誠實承認:目前沒有一個經過驗證、掛在 Gitea Releases
# 上的版本」。不准提前寫一個沒人驗過的號碼(那正是這張票抓到的違規本身)。
# 真正打 tag 的那天,`.claude-plugin/plugin.json` 的 version 要跟那個 tag
# 同一個 commit 就改掉,兩者一起進 release。
# 2. `README.md` 不准再自己宣告版本號(例如「- 0.1.0 —」這種樣式的行)。
# 讀者要查現在是哪一版,去 Releases 頁面,不是讀 README。
#
# 用法:scripts/check-version-consistency.sh
# 離開碼:0=一致(可以放心說「這裡查得到版本」);1=不一致(stderr 講清楚錯在哪、
# 該改哪個檔案)。可以隨時手動跑,也是 hooks/release-tag-guard.sh 在打 tag
# 那一刻用來擋下不一致 tag 的同一套判準(複製了一份精簡邏輯,避免 hook
# 每次 Bash 呼叫都要 fork 這支腳本)。
set -eu
PROJ="$(cd "$(dirname "$0")/.." && pwd)"
PLUGIN_JSON="$PROJ/.claude-plugin/plugin.json"
README="$PROJ/README.md"
FAIL=0
# --- 1. plugin.json 讀得到、version 欄位存在 ---
if [ ! -f "$PLUGIN_JSON" ]; then
echo "❌ 找不到 $PLUGIN_JSON" >&2
exit 1
fi
PJVER=$(python3 -c "import json;print(json.load(open('$PLUGIN_JSON')).get('version',''))" 2>/dev/null || printf '')
if [ -z "$PJVER" ]; then
echo "❌ .claude-plugin/plugin.json 沒有 version 欄位(或不是合法 JSON" >&2
exit 1
fi
# --- 2. 跟最新 tag 比對 ---
LATEST_TAG=$(cd "$PROJ" && git tag --list 'v*' --sort=-v:refname 2>/dev/null | head -1 || printf '')
if [ -z "$LATEST_TAG" ]; then
# 沒有任何 tag:唯一合法的 plugin.json version 是哨兵值 0.0.0
if [ "$PJVER" != "0.0.0" ]; then
echo "❌ 版本不一致:" >&2
echo " repo 裡沒有任何 tagrelease_counter=0,還沒有一個正式 release" >&2
echo " 但 .claude-plugin/plugin.json 的 version 卻宣稱「$PJVER」" >&2
echo " → 這就是 inkstone/ISEP#6 抓到的違規本身:宣稱一個版本,卻沒有 tag 撐它。" >&2
echo " → 修法:version 改回 0.0.0(=尚未發過正式版),等真正打 tag 那天再同步改成那個號碼。" >&2
FAIL=1
fi
else
TAGVER=${LATEST_TAG#v}
if [ "$PJVER" != "$TAGVER" ]; then
echo "❌ 版本不一致:" >&2
echo " Gitea 上最新的 tag 是 $LATEST_TAG(版本 $TAGVER" >&2
echo " 但 .claude-plugin/plugin.json 的 version 是「$PJVER」" >&2
echo " → 兩者必須完全一致,不然「ISEP 現在是哪一版」又變成各說各話。" >&2
FAIL=1
fi
fi
# --- 3. README 不准自己宣告版本號 ---
HIT=$(grep -nE '^\s*-\s*v?[0-9]+\.[0-9]+\.[0-9]+\s*(—|-)' "$README" 2>/dev/null || printf '')
if [ -f "$README" ] && [ -n "$HIT" ]; then
echo "❌ README.md 還在自己宣告版本號(不准,release 只放在 Gitea Releases):" >&2
echo "$HIT" >&2
FAIL=1
fi
if [ "$FAIL" -eq 0 ]; then
if [ -n "$LATEST_TAG" ]; then
echo "✅ 版本一致:plugin.json$PJVER,最新 tag$LATEST_TAG,README 沒有自行宣告版本。"
else
echo "✅ 版本一致:plugin.json$PJVER(哨兵值,尚無 tag 是合法狀態),README 沒有自行宣告版本。"
fi
fi
exit "$FAIL"