版本指紋閘(同一版號只准一份原始碼,實測有效)+落帳封測兩病與 md 真相
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"v0.18.9": "8be9260eb542f527"
|
||||
}
|
||||
@@ -33,6 +33,8 @@
|
||||
daemon-version.py --stamp # 把「下一版(未發佈)」戳成正式版號+日期後印出
|
||||
"""
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -45,6 +47,8 @@ CHANGELOG = ROOT / "docs-site/src/content/docs/help/changelog.md"
|
||||
LINE_FILE = ROOT / "DAEMON_LINE"
|
||||
|
||||
UNRELEASED = "## 下一版(未發佈)"
|
||||
# 版本 → 當時原始碼指紋。用來擋「同一個版號、不同的執行檔」。
|
||||
SOURCE_LOCK = HERE / ".version-source.json"
|
||||
RELEASED_RE = re.compile(r"^## v(\d+)\.(\d+)\.(\d+)(", re.M)
|
||||
|
||||
|
||||
@@ -53,6 +57,52 @@ def die(msg):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def source_fingerprint():
|
||||
"""會被編進執行檔的原始碼指紋(已提交的樹 + 未提交的差異)。
|
||||
|
||||
🔴 2026-08-06 補這道閘的由來:
|
||||
戳完版號後我又改了 code,再打一次包,腳本判定「沒有未發佈段=重打同一版」
|
||||
⇒ **兩個內容不同的執行檔都叫 v0.18.9**(實測 sha256 前 20 碼
|
||||
63ec1077a29383b31379 vs 1ca73a5aef5bf4f90bd3)。
|
||||
這正是 leo 08-05 點名的「版本號手寫=說謊溫床」換個形式復發——
|
||||
機械產生版本號還不夠,還要保證**同一個版號只對應一份原始碼**。
|
||||
"""
|
||||
def sh(*args):
|
||||
return subprocess.check_output(args, cwd=ROOT, text=True).strip()
|
||||
try:
|
||||
tree = sh("git", "rev-parse", "HEAD:collector")
|
||||
except subprocess.CalledProcessError:
|
||||
return "" # 不在 git 裡就不擋(例如從 tarball 解出來 build)
|
||||
diff = subprocess.run(["git", "diff", "HEAD", "--", "collector"],
|
||||
cwd=ROOT, text=True, capture_output=True).stdout
|
||||
return hashlib.sha256((tree + diff).encode()).hexdigest()[:16]
|
||||
|
||||
|
||||
def check_or_record(version, stamp):
|
||||
"""同一個版號只准對應一份原始碼;不同就擋下並說怎麼辦。"""
|
||||
fp = source_fingerprint()
|
||||
if not fp:
|
||||
return
|
||||
lock = json.loads(SOURCE_LOCK.read_text()) if SOURCE_LOCK.exists() else {}
|
||||
known = lock.get(version)
|
||||
if known and known != fp:
|
||||
die("""❌ %s 這個版號已經對應過另一份原始碼了(記錄 %s,現在 %s)。
|
||||
|
||||
代表你在戳完版號之後又改了 code。再打一次會產生
|
||||
**兩個內容不同、卻都叫 %s 的執行檔** —— 那就是「版本號說謊」。
|
||||
|
||||
要出新版:在 changelog 最上面加一段
|
||||
|
||||
## 下一版(未發佈)
|
||||
|
||||
- (用戶語言的更新內容)
|
||||
|
||||
然後重跑打包,版號會自動變成下一個。""" % (version, known, fp, version))
|
||||
if stamp and not known:
|
||||
lock[version] = fp
|
||||
SOURCE_LOCK.write_text(json.dumps(lock, indent=1, ensure_ascii=False) + "\n")
|
||||
|
||||
|
||||
def main():
|
||||
stamp = "--stamp" in sys.argv
|
||||
if not CHANGELOG.exists():
|
||||
@@ -74,6 +124,7 @@ def main():
|
||||
if not has_unreleased:
|
||||
# 沒有待發佈內容=重打同一版。冪等,不虛增。
|
||||
version = "v%d.%d.%d" % prev
|
||||
check_or_record(version, stamp)
|
||||
if stamp:
|
||||
print(" ℹ️ changelog 沒有「下一版(未發佈)」段,版本維持 %s(重打同一版)"
|
||||
% version, file=sys.stderr)
|
||||
@@ -89,6 +140,7 @@ def main():
|
||||
version = "v%d.%d.%d" % nxt
|
||||
|
||||
if stamp:
|
||||
check_or_record(version, True)
|
||||
today = datetime.date.today().isoformat()
|
||||
heading = "## %s(%s)" % (version, today)
|
||||
CHANGELOG.write_text(text.replace(UNRELEASED, heading, 1))
|
||||
|
||||
Reference in New Issue
Block a user