Files
pkg/tools/apply-version.sh
T
jiantw83andClaude Opus 5 ea11ca0590 fix(pkg): 補齊稽核缺失並修掉護欄失效
What:依 jsc-meta:skill-check 的稽核結果修正技能與工具——補上每個步驟的可檢核完成條件、
把留在內文的標準輸入輸出流程下放 tools/、修正查表與退碼路由造成的誤判。

Why:稽核發現這些缺失會讓技能在實際執行時走錯分支或靜默通過。
完成條件缺漏是最常被違反的一項;退碼誤判與查表錯誤則會讓良性狀況被當成失敗。

How:逐項對照 references/guidelines.md 的審核檢查清單修正,新增的工具都有
documented exit codes,並以真實執行驗證每條路徑。

Who:jsc-meta:skill-check 例行稽核(2026-08-25)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 14:58:54 +08:00

150 lines
4.9 KiB
Bash
Executable File
Raw 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.
#!/usr/bin/env sh
# apply-version.sh — 改寫版本來源檔案,把套件釘選到指定版本。
# 用法:apply-version.sh <ecosystem> <project-dir> <name> <version>
# ecosystem:nodejs | python | dotnet
# 對應檔案(與 list-packages.sh 相同的解析邏輯):
# nodejs → package.json(dependencies / devDependencies)
# python → requirements.txt(優先)或 pyproject.toml 的 [project] dependencies
# dotnet → *.csproj 的 PackageReference
# 結束碼(慣例見 README「工具」章的結束碼總表):
# 0 改寫成功
# 1 參數個數不對
# 2 ecosystem 不認識
# 3 找不到對應的版本來源檔案——呼叫方跳過這個套件
# 4 檔案中找不到該套件——呼叫方跳過這個套件
# 5 需要的指令不存在(python3)
# 6 找不到專案目錄——呼叫方停手,不要當成跳過
set -u
if [ "$#" -ne 4 ]; then
echo "用法:apply-version.sh <ecosystem> <project-dir> <name> <version>" >&2
exit 1
fi
eco="$1"
DIR="$2"
name="$3"
version="$4"
# 先擋找不到專案目錄。少了這道,壞路徑會被報成「沒有版本來源檔案」,然後被當成跳過藏起來。
[ -d "$DIR" ] || { echo "project dir not found: $DIR" >&2; exit 6; }
# 三種來源檔案都靠 python3 改寫。少了 python3 會被誤判成檔案中找不到該套件,所以先擋。
command -v python3 >/dev/null 2>&1 || { echo "python3 not found" >&2; exit 5; }
case "$eco" in
nodejs)
[ -f "$DIR/package.json" ] || { echo "package.json not found in $DIR" >&2; exit 3; }
python3 - "$DIR/package.json" "$name" "$version" <<'EOF'
import json,sys
path,name,version=sys.argv[1],sys.argv[2],sys.argv[3]
d=json.load(open(path,encoding="utf-8"))
found=False
for k in ("dependencies","devDependencies"):
if name in (d.get(k) or {}):
d[k][name]=version
found=True
if not found:
sys.exit(4)
with open(path,"w",encoding="utf-8") as f:
json.dump(d,f,indent=2,ensure_ascii=False)
f.write("\n")
EOF
rc=$?
[ "$rc" -eq 0 ] || { echo "$name not found in $DIR/package.json" >&2; exit "$rc"; }
;;
python)
if [ -f "$DIR/requirements.txt" ]; then
python3 - "$DIR/requirements.txt" "$name" "$version" <<'EOF'
import re,sys
path,name,version=sys.argv[1],sys.argv[2],sys.argv[3]
pat=re.compile(r"([A-Za-z0-9_.\-\[\]]+)\s*(?:(?:==|>=|<=|~=|!=|>|<)\s*([^,;\s]+))?")
lname=name.split("[")[0].lower()
lines=open(path,encoding="utf-8").readlines()
out=[]
found=False
for line in lines:
body=line.split("#")[0].strip()
m=pat.match(body)
if m and m.group(1).split("[")[0].lower()==lname:
out.append(f"{m.group(1)}=={version}\n")
found=True
else:
out.append(line)
if not found:
sys.exit(4)
open(path,"w",encoding="utf-8").writelines(out)
EOF
rc=$?
[ "$rc" -eq 0 ] || { echo "$name not found in $DIR/requirements.txt" >&2; exit "$rc"; }
elif [ -f "$DIR/pyproject.toml" ]; then
python3 - "$DIR/pyproject.toml" "$name" "$version" <<'EOF'
import re,sys
path,name,version=sys.argv[1],sys.argv[2],sys.argv[3]
pat=re.compile(r"([A-Za-z0-9_.\-\[\]]+)\s*(?:(?:==|>=|<=|~=|!=|>|<)\s*([^,;\s\"']+))?")
lname=name.split("[")[0].lower()
lines=open(path,encoding="utf-8").readlines()
out=[]
found=False
for line in lines:
m=re.search(r'"([^"]+)"', line)
if m:
dep=m.group(1)
dm=pat.match(dep)
if dm and dm.group(1).split("[")[0].lower()==lname:
newdep=f"{dm.group(1)}=={version}"
line=line.replace(dep,newdep,1)
found=True
out.append(line)
if not found:
sys.exit(4)
open(path,"w",encoding="utf-8").writelines(out)
EOF
rc=$?
[ "$rc" -eq 0 ] || { echo "$name not found in $DIR/pyproject.toml" >&2; exit "$rc"; }
else
echo "requirements.txt or pyproject.toml not found in $DIR" >&2
exit 3
fi
;;
dotnet)
projs=$(find "$DIR" -maxdepth 3 -name '*.csproj' 2>/dev/null)
[ -n "$projs" ] || { echo "*.csproj not found in $DIR" >&2; exit 3; }
found=0
for proj in $projs; do
python3 - "$proj" "$name" "$version" <<'EOF'
import re,sys
path,name,version=sys.argv[1],sys.argv[2],sys.argv[3]
text=open(path,encoding="utf-8").read()
hit=[False]
def repl(m):
tag=m.group(0)
inc=re.search(r'Include="([^"]+)"',tag)
if inc and inc.group(1)==name:
hit[0]=True
if re.search(r'Version="[^"]*"',tag):
tag=re.sub(r'Version="[^"]*"', 'Version="%s"'%version, tag)
elif tag.endswith("/>"):
tag=tag[:-2]+' Version="%s" />'%version
else:
tag=tag[:-1]+' Version="%s">'%version
return tag
new_text=re.sub(r"<PackageReference\b[^>]*>", repl, text)
if not hit[0]:
sys.exit(4)
open(path,"w",encoding="utf-8").write(new_text)
EOF
if [ $? -eq 0 ]; then
found=1
break
fi
done
[ "$found" -eq 1 ] || { echo "PackageReference $name not found under $DIR" >&2; exit 4; }
;;
*) echo "unknown ecosystem: $eco" >&2; exit 2 ;;
esac
exit 0