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>
This commit is contained in:
Executable
+91
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env sh
|
||||
# build-test.sh — 偵測並執行專案的建置與測試,先建置再測試。
|
||||
# 用法:build-test.sh <ecosystem> <project-dir>
|
||||
# ecosystem:nodejs | python | dotnet
|
||||
# 偵測方式:
|
||||
# nodejs → package.json 的 scripts.build 與 scripts.test(npm init 產生的佔位 test 視為沒有)
|
||||
# python → pytest 設定(pytest.ini、setup.cfg、tox.ini、pyproject.toml)或 tests 目錄與 test_*.py
|
||||
# dotnet → *.sln 或 *.csproj,建置與測試都用 dotnet
|
||||
# 輸出:底層指令的原始輸出。
|
||||
# 結束碼(慣例見 README「工具」章的結束碼總表):
|
||||
# 0 建置與測試都通過
|
||||
# 1 參數個數不對
|
||||
# 2 ecosystem 不認識
|
||||
# 4 需要的指令不存在(npm、python3、pytest、dotnet)
|
||||
# 5 推不出任何建置或測試指令——呼叫方要改問使用者
|
||||
# 6 找不到專案目錄——呼叫方停手
|
||||
# 其他 建置或測試失敗,帶回失敗指令的結束碼
|
||||
# 本工具不用 3:3 保留給「該 ecosystem 沒有來源檔案」,這支改用 5 表達推不出指令。
|
||||
set -u
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "用法:build-test.sh <ecosystem> <project-dir>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eco="$1"
|
||||
DIR="$2"
|
||||
|
||||
NO_COMMAND=5
|
||||
|
||||
[ -d "$DIR" ] || { echo "project dir not found: $DIR" >&2; exit 6; }
|
||||
|
||||
case "$eco" in
|
||||
nodejs)
|
||||
[ -f "$DIR/package.json" ] || { echo "no build or test command inferred for $DIR" >&2; exit "$NO_COMMAND"; }
|
||||
# package.json 靠 python3 解析。少了 python3 會解出空字串,被誤判成推不出指令,所以先擋。
|
||||
command -v python3 >/dev/null 2>&1 || { echo "python3 not found" >&2; exit 4; }
|
||||
scripts=$(python3 - "$DIR/package.json" <<'EOF'
|
||||
import json,sys
|
||||
try:
|
||||
d=json.load(open(sys.argv[1],encoding="utf-8"))
|
||||
except Exception:
|
||||
sys.exit(0)
|
||||
s=(d.get("scripts") or {})
|
||||
if s.get("build"): print("build")
|
||||
t=s.get("test") or ""
|
||||
if t and "no test specified" not in t: print("test")
|
||||
EOF
|
||||
)
|
||||
[ -n "$scripts" ] || { echo "no build or test command inferred for $DIR" >&2; exit "$NO_COMMAND"; }
|
||||
command -v npm >/dev/null 2>&1 || { echo "npm not found" >&2; exit 4; }
|
||||
for s in $scripts; do
|
||||
( cd "$DIR" && npm run --if-present "$s" ) || exit $?
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
|
||||
python)
|
||||
has_tests=0
|
||||
for f in pytest.ini setup.cfg tox.ini pyproject.toml; do
|
||||
if [ -f "$DIR/$f" ] && grep -q 'pytest' "$DIR/$f" 2>/dev/null; then has_tests=1; fi
|
||||
done
|
||||
[ -d "$DIR/tests" ] && has_tests=1
|
||||
if [ "$has_tests" -eq 0 ]; then
|
||||
found=$(find "$DIR" -maxdepth 3 -name 'test_*.py' 2>/dev/null | head -n 1)
|
||||
[ -n "$found" ] && has_tests=1
|
||||
fi
|
||||
[ "$has_tests" -eq 1 ] || { echo "no build or test command inferred for $DIR" >&2; exit "$NO_COMMAND"; }
|
||||
if command -v pytest >/dev/null 2>&1; then
|
||||
( cd "$DIR" && pytest )
|
||||
exit $?
|
||||
elif command -v python3 >/dev/null 2>&1 && python3 -m pytest --version >/dev/null 2>&1; then
|
||||
( cd "$DIR" && python3 -m pytest )
|
||||
exit $?
|
||||
else
|
||||
echo "pytest not found" >&2
|
||||
exit 4
|
||||
fi
|
||||
;;
|
||||
|
||||
dotnet)
|
||||
projs=$(find "$DIR" -maxdepth 3 \( -name '*.sln' -o -name '*.csproj' \) 2>/dev/null)
|
||||
[ -n "$projs" ] || { echo "no build or test command inferred for $DIR" >&2; exit "$NO_COMMAND"; }
|
||||
command -v dotnet >/dev/null 2>&1 || { echo "dotnet not found" >&2; exit 4; }
|
||||
( cd "$DIR" && dotnet build ) || exit $?
|
||||
( cd "$DIR" && dotnet test ) || exit $?
|
||||
exit 0
|
||||
;;
|
||||
|
||||
*) echo "unknown ecosystem: $eco" >&2; exit 2 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user