Merge pull request 'release: v0.0.6 develop 到 master' (#9) from develop into master

Reviewed-on: #9
Reviewed-by: 系統管理員 <1+admin@noreply.localhost>
This commit was merged in pull request #9.
This commit is contained in:
2026-08-27 02:08:02 +00:00
12 changed files with 319 additions and 42 deletions
+3 -3
View File
@@ -43,7 +43,7 @@
"source": "url", "source": "url",
"url": "https://gitea.jsc.idv.tw/plugins/hooks.git" "url": "https://gitea.jsc.idv.tw/plugins/hooks.git"
}, },
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄" "description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查"
}, },
{ {
"name": "jsc-log", "name": "jsc-log",
@@ -75,7 +75,7 @@
"source": "url", "source": "url",
"url": "https://gitea.jsc.idv.tw/plugins/review.git" "url": "https://gitea.jsc.idv.tw/plugins/review.git"
}, },
"description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組" "description": "程式碼審查:Refactoring 壞味道六組、註解規範、淺模組"
}, },
{ {
"name": "jsc-sdlc", "name": "jsc-sdlc",
@@ -83,7 +83,7 @@
"source": "url", "source": "url",
"url": "https://gitea.jsc.idv.tw/plugins/sdlc.git" "url": "https://gitea.jsc.idv.tw/plugins/sdlc.git"
}, },
"description": "開發生命週期:規劃/分析/實作/維護(wiki 追蹤)" "description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)"
} }
] ]
} }
+3 -3
View File
@@ -43,7 +43,7 @@
"source": "url", "source": "url",
"url": "https://gitea.jsc.idv.tw/plugins/hooks.git" "url": "https://gitea.jsc.idv.tw/plugins/hooks.git"
}, },
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄" "description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查"
}, },
{ {
"name": "jsc-log", "name": "jsc-log",
@@ -75,7 +75,7 @@
"source": "url", "source": "url",
"url": "https://gitea.jsc.idv.tw/plugins/review.git" "url": "https://gitea.jsc.idv.tw/plugins/review.git"
}, },
"description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組" "description": "程式碼審查:Refactoring 壞味道六組、註解規範、淺模組"
}, },
{ {
"name": "jsc-sdlc", "name": "jsc-sdlc",
@@ -83,7 +83,7 @@
"source": "url", "source": "url",
"url": "https://gitea.jsc.idv.tw/plugins/sdlc.git" "url": "https://gitea.jsc.idv.tw/plugins/sdlc.git"
}, },
"description": "開發生命週期:規劃/分析/實作/維護(wiki 追蹤)" "description": "開發生命週期:規劃、分析、實作、維護(wiki 追蹤)"
} }
] ]
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-pkg", "name": "jsc-pkg",
"version": "0.0.3", "version": "0.0.6",
"description": "套件批次更新(nodejs/python/dotnet),失敗還原", "description": "套件批次更新(nodejs/python/dotnet),失敗還原",
"skills": "./skills", "skills": "./skills",
"author": { "author": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-pkg", "name": "jsc-pkg",
"version": "0.0.3", "version": "0.0.6",
"description": "套件批次更新(nodejs/python/dotnet),失敗還原", "description": "套件批次更新(nodejs/python/dotnet),失敗還原",
"skills": "./skills" "skills": "./skills"
} }
+32 -5
View File
@@ -20,11 +20,36 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
## 工具 ## 工具
| 工具 | 用途 | 五支工具都靠 python3 解析或改寫檔案。少了 python3,每一支都回報「需要的指令不存在」,不會裝成查無套件。
| --- | --- |
| `tools/list-packages.sh` | 偵測專案類型並列出所有外部套件與目前版本(TSV:ecosystem / name / current) | | 工具 | 用途 | 需要的指令 |
| `tools/latest-version.sh` | `latest-version.sh <ecosystem> <name>` 查最新穩定版(npm / pypi / nuget),查無 exit 4 | | --- | --- | --- |
| `tools/apply-version.sh` | `apply-version.sh <ecosystem> <project dir> <name> <version>` 改寫版本來源檔案,把套件釘選到指定版本 | | `tools/list-packages.sh` | `list-packages.sh [專案目錄]` 偵測專案類型並列出所有外部套件與目前版本(TSV:ecosystem / name / current) | python3 |
| `tools/latest-version.sh` | `latest-version.sh <ecosystem> <name>` 查最新穩定版(npm / pypi / nuget) | curl、python3 |
| `tools/apply-version.sh` | `apply-version.sh <ecosystem> <project dir> <name> <version>` 改寫版本來源檔案,把套件釘選到指定版本 | python3 |
| `tools/install-deps.sh` | `install-deps.sh <ecosystem> <project dir>` 重新解析並安裝相依套件(npm install、pip install、dotnet restore) | npm、pip、dotnet |
| `tools/build-test.sh` | `build-test.sh <ecosystem> <project dir>` 偵測並執行建置與測試 | npm、python3、pytest、dotnet |
### 結束碼總表
一個數字只有一個意思,五支工具共用。新增工具請沿用這張表,不要自己編號。
| 碼 | 意思 | 呼叫方的動作 |
| --- | --- | --- |
| 0 | 成功 | 繼續 |
| 1 | 參數個數不對 | 停手 |
| 2 | ecosystem 不認識 | 停手 |
| 3 | 該 ecosystem 沒有來源檔案 | 跳過這個 ecosystem 或套件 |
| 4 | 依工具而定:`list-packages.sh`、`build-test.sh`、`install-deps.sh` 是指令不存在(停手);`latest-version.sh`、`apply-version.sh` 是查不到該套件(跳過) | 見左欄 |
| 5 | 依工具而定:`latest-version.sh`、`apply-version.sh` 是指令不存在(停手);`build-test.sh` 是推不出建置或測試指令(改問使用者) | 見左欄 |
| 6 | 找不到專案目錄 | 停手 |
| 其他 | 底層指令的結束碼 | 只有 `install-deps.sh`、`build-test.sh` 會走還原 |
6 不與 3 合併:找不到專案目錄是輸入壞了,併進 3 會被當成跳過藏起來。`latest-version.sh` 不收專案目錄,所以沒有 6。
4 與 5 在各工具間意思不同,是為了保住既有的跳過路由;新增工具請優先用 4 表示指令不存在。
回 1、回 2、回 6 與回「指令不存在」時,技能只回報並停手,不還原工作樹——工具鏈壞了不是套件壞了,還原只會白白刪掉檔案。
## Skills 目錄 ## Skills 目錄
@@ -36,6 +61,8 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
套件批次更新:列套件 → 查最新穩定版 → 逐 ecosystem 以 sub agent 更新 → 建置與測試(指令不明時決策樹詢問)→ 失敗還原全部變更。 套件批次更新:列套件 → 查最新穩定版 → 逐 ecosystem 以 sub agent 更新 → 建置與測試(指令不明時決策樹詢問)→ 失敗還原全部變更。
更新途中要在版本來源檔案或程式碼留註解時,只寫鎖版本或繞道的原因,不寫內部議題編號、工作包編號、人名與 @ 提及、產生來源署名;第三方套件的 issue 連結可以寫,用來說明繞道成因與解除條件。完整清單與白名單見 [`jsc-review`](https://gitea.jsc.idv.tw/plugins/review) 的 `references/comment-scope.md`。
<!-- JSC-SKILLS:END --> <!-- JSC-SKILLS:END -->
## 相關 domain ## 相關 domain
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-pkg", "name": "jsc-pkg",
"version": "0.0.3", "version": "0.0.6",
"description": "套件批次更新(nodejs/python/dotnet),失敗還原", "description": "套件批次更新(nodejs/python/dotnet),失敗還原",
"skills": "./skills/" "skills": "./skills/"
} }
+44 -12
View File
@@ -5,18 +5,50 @@ description: Update every external package of a project to its latest stable ver
# pkg-update — batch-update packages # pkg-update — batch-update packages
## Exit-code routes
Every tool exit code below has exactly one route. Three routes exist:
- **skip** — record the reason, keep going.
- **stop** — report and end the run. Change no file, and never enter step 5.
- **revert** — go to step 5, which reverts the working tree.
Only a real install, build or test failure takes the revert route. A missing input, a bad argument, an unknown ecosystem or a missing command is a broken call or a broken toolchain, so it takes the stop route.
One number carries one meaning across all five tools. Exit 6 is always a missing project directory and always stops the run — never fold it into the exit 3 skip, or a bad path hides as "nothing to do".
| Tool | 0 | 1 (bad argument count) | 2 (unknown ecosystem) | 3 (no source file) | 4 | 5 | 6 (project dir not found) | other |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `list-packages.sh` | continue | stop | — | — | stop (python3 missing) | — | stop | stop |
| `latest-version.sh` | continue | stop | stop | — | skip (not in registry) | stop (curl or python3 missing) | — (takes no project dir) | stop |
| `apply-version.sh` | continue | stop | stop | skip | skip (package absent from the file) | stop (python3 missing) | stop | stop |
| `install-deps.sh` | continue | stop | stop | skip | stop (npm, pip or dotnet missing) | — | stop | **revert** |
| `build-test.sh` | continue | stop | stop | — (uses 5 instead) | stop (npm, python3, pytest or dotnet missing) | ask the user | stop | **revert** |
Exit 4 and exit 5 are the two codes whose meaning depends on the tool, so read them off this table rather than from memory.
## Steps ## Steps
1. Run `tools/list-packages.sh {project dir}` to get every external package (ecosystem, name, current version). 1. Run `tools/list-packages.sh {project dir}` to get every external package (ecosystem, name, current version). Route the exit code per the table above. Step 1 is done only when the tool exited 0 and at least one row came back, with an ecosystem, a name and a current version in every row. Zero rows → stop and report the project directory you scanned plus the supported ecosystems (nodejs / python / dotnet), and run no further step.
2. Confirm the working tree is clean: stop and report when uncommitted changes exist, so the revert cannot destroy them. 2. Prove the project directory is a git repository with a clean tree. Run this before any step changes a file:
1. Run `git -C {project dir} rev-parse --git-dir`. Exit 0 is required to continue, because step 5's revert is impossible outside a git repository. Any other exit code → stop and report the directory, and run no further step.
2. Run `git -C {project dir} status --porcelain`. Continuing requires that it prints **nothing at all**. Any output stops the run and reports that output, **including `??` untracked lines**: step 5 runs `git clean -fd`, which deletes untracked files with no reflog and no way back.
3. Step 2 is done only when `rev-parse --git-dir` exited 0 and `status --porcelain` printed zero bytes. Report both results, then enter step 3.
3. Update ecosystem by ecosystem. This step **MUST run as a sub agent** (one sub agent per ecosystem): 3. Update ecosystem by ecosystem. This step **MUST run as a sub agent** (one sub agent per ecosystem):
1. For every package, run `tools/latest-version.sh {ecosystem} {name}` to get the latest stable version. 1. For every package, run `tools/latest-version.sh {ecosystem} {name}` for the latest stable version, then `tools/apply-version.sh {ecosystem} {project dir} {name} {version}` to rewrite the version source file (package.json / requirements.txt / pyproject.toml / *.csproj). This substep is done when every package of the ecosystem carries either an applied version or a skip reason from substep 2.
2. Run `tools/apply-version.sh {ecosystem} {project dir} {name} {version}` to rewrite the version source file (package.json / requirements.txt / pyproject.toml / *.csproj). 2. Route every exit code per the table above. The skip route covers `latest-version.sh` exit 4 (package not found in the registry), `apply-version.sh` exit 3 (no version source file) and `apply-version.sh` exit 4 (package absent from the file): record the package and the reason, move on to the next package, and never abort the whole ecosystem. The stop route covers exit 1, exit 2, `latest-version.sh` or `apply-version.sh` exit 5 (a required command is missing) and `apply-version.sh` exit 6 (project directory not found): report the code and end the run without entering step 5. This substep is done when every exit code seen has taken exactly one route.
3. Re-resolve and install (`npm install` / `pip install -r` / `dotnet restore`). 3. Run `tools/install-deps.sh {ecosystem} {project dir}` once, after every package of that ecosystem is applied. Exit 0 means the install finished. Exit 3 means this ecosystem has no dependency source file, which is the same documented skip as substep 2: record the ecosystem and the reason, and install nothing. Exit 1, exit 2, exit 4 and exit 6 take the stop route — exit 6 is a missing project directory, so report it instead of skipping it. Only another non-zero code is a real install failure and goes to step 5. This substep is done when the exit code is recorded together with the route it took.
4. Run build and tests: 4. The sub agent returns one row per package from substep 1: name, old version, new version — or `skipped` plus the reason. It also returns the `install-deps.sh` exit code and its route. The ecosystem is done only when every package appears in exactly one row.
- nodejs: `npm run build` (if present) plus `npm test` (if present). 5. **Comments this step writes.** Holding a package at an older version, or coding around an incompatibility, sometimes needs a comment in the version source file or in the code. Write **why** the pin or the workaround exists, never a tracking number. The one this skill trips over most: **a third-party package's issue link is on the allow list** — it is what states the cause of the workaround and the condition for removing it, as in `// works around github.com/foo/bar/issues/88; drop this pin once that ships`. Out of a comment: internal issue ids, work package ids, personal names, `@` mentions and generated-by credits. Full list and allow list: `jsc-review/references/comment-scope.md`. `jsc-hooks/hooks/comment-scope.sh` compares every write against that list right after the file is written and prints a warning on a hit; fix the comment on the spot, then continue this step. Completion condition: every comment line this step added names a reason, carries no internal issue id, work package id, personal name, `@` mention or generated-by credit, and every `comment-scope.sh` warning this step received has been fixed and re-checked with no warning left.
- python: `pytest` (when tests exist). 4. Run `tools/build-test.sh {ecosystem} {project dir}` for every ecosystem and route on the exit code:
- dotnet: `dotnet build` plus `dotnet test`. - 0 → this ecosystem passed.
- When the commands cannot be inferred, ask the user per the `jsc-ask:ask` rules. - 1, 2, 4 or 6 → stop route. Report the code and the missing argument, ecosystem, command or directory, and enter no further step. Exit 4 means the toolchain is broken, not that the packages are broken, so reverting would destroy files for nothing.
5. Build or tests fail → revert every change (`git checkout -- .` and clean untracked lock changes), then report the failing packages with an error summary. - 5 → no build or test command could be inferred. Ask the user for the build command and the test command per the `jsc-ask:ask` rules, run the answers in that order, and take their exit codes as this ecosystem's result: all 0 → passed; any non-zero → step 5.
6. Success → report the update list (package, old version, new version) and hand off to `jsc-git:commit`. - any other code → a real build or test failure. Go to step 5.
Step 4 is done only when every ecosystem reached exit 0, from the tool or from the user's own commands.
5. A real install, build or test failure reached this step → revert:
1. Run `git -C {project dir} checkout -- .` to restore every tracked file to HEAD.
2. Run `git -C {project dir} clean -fd` to remove the untracked files and directories this run created, such as a new lock file. Gitignored paths survive `-fd` on purpose: `node_modules`, `__pycache__`, `bin/` and `obj/` stay behind, so restoring install output is out of scope for this skill. Do not reach for `-fdx` — it deletes far more than this run created.
3. The revert is done only when `git -C {project dir} status --porcelain` prints nothing. Report the failing packages with an error summary after that check passes.
6. Success → report the update list (package, old version, new version), plus every skip and its reason, and hand off to `jsc-git:commit`. Step 6 is done when the hand-off is made and every package from step 1 appears either as an update or as a skip.
+27 -8
View File
@@ -1,17 +1,36 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# apply-version.sh — 改寫版本來源檔案,把套件釘選到指定版本。 # apply-version.sh — 改寫版本來源檔案,把套件釘選到指定版本。
# 用法: apply-version.sh <ecosystem> <project-dir> <name> <version> # 用法:apply-version.sh <ecosystem> <project-dir> <name> <version>
# ecosystem: nodejs | python | dotnet # ecosystem:nodejs | python | dotnet
# 對應檔案(與 list-packages.sh 相同的解析邏輯): # 對應檔案(與 list-packages.sh 相同的解析邏輯):
# nodejs → package.json(dependencies / devDependencies) # nodejs → package.json(dependencies / devDependencies)
# python → requirements.txt(優先)或 pyproject.toml 的 [project] dependencies # python → requirements.txt(優先)或 pyproject.toml 的 [project] dependencies
# dotnet → *.csproj 的 PackageReference # dotnet → *.csproj 的 PackageReference
# 找不到對應檔案 exit 3;檔案中找不到該套件 exit 4 # 結束碼(慣例見 README「工具」章的結束碼總表):
# 0 改寫成功
# 1 參數個數不對
# 2 ecosystem 不認識
# 3 找不到對應的版本來源檔案——呼叫方跳過這個套件
# 4 檔案中找不到該套件——呼叫方跳過這個套件
# 5 需要的指令不存在(python3)
# 6 找不到專案目錄——呼叫方停手,不要當成跳過
set -u set -u
eco="${1:?ecosystem required (nodejs|python|dotnet)}"
DIR="${2:?project dir required}" if [ "$#" -ne 4 ]; then
name="${3:?package name required}" echo "用法:apply-version.sh <ecosystem> <project-dir> <name> <version>" >&2
version="${4:?version required}" 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 case "$eco" in
nodejs) nodejs)
+91
View File
@@ -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
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env sh
# install-deps.sh — 重新解析並安裝專案的相依套件。
# 用法:install-deps.sh <ecosystem> <project-dir>
# ecosystem:nodejs | python | dotnet
# 對應動作:
# nodejs → npm install
# python → pip install -r requirements.txt(優先)或 pip install -e .(pyproject.toml)
# dotnet → dotnet restore
# 輸出:底層指令的原始輸出。
# 檢查順序:先確認相依來源檔案存在,才檢查指令存在。順序顛倒會把「沒有來源檔案」報成「指令不存在」。
# 結束碼(慣例見 README「工具」章的結束碼總表):
# 0 安裝成功
# 1 參數個數不對
# 2 ecosystem 不認識
# 3 該 ecosystem 沒有相依來源檔案——呼叫方跳過這個 ecosystem
# 4 需要的指令不存在(npm、pip、dotnet)
# 6 找不到專案目錄——呼叫方停手,不要當成跳過
# 其他 底層指令的結束碼,代表安裝失敗
set -u
if [ "$#" -ne 2 ]; then
echo "用法:install-deps.sh <ecosystem> <project-dir>" >&2
exit 1
fi
eco="$1"
DIR="$2"
[ -d "$DIR" ] || { echo "project dir not found: $DIR" >&2; exit 6; }
case "$eco" in
nodejs)
[ -f "$DIR/package.json" ] || { echo "package.json not found in $DIR" >&2; exit 3; }
command -v npm >/dev/null 2>&1 || { echo "npm not found" >&2; exit 4; }
( cd "$DIR" && npm install )
exit $?
;;
python)
if [ -f "$DIR/requirements.txt" ]; then
target="-r requirements.txt"
elif [ -f "$DIR/pyproject.toml" ]; then
target="-e ."
else
echo "requirements.txt or pyproject.toml not found in $DIR" >&2
exit 3
fi
pip=""
for c in pip3 pip; do
if command -v "$c" >/dev/null 2>&1; then pip="$c"; break; fi
done
if [ -z "$pip" ]; then
if command -v python3 >/dev/null 2>&1 && python3 -m pip --version >/dev/null 2>&1; then
pip="python3 -m pip"
else
echo "pip not found" >&2
exit 4
fi
fi
( cd "$DIR" && $pip install $target )
exit $?
;;
dotnet)
projs=$(find "$DIR" -maxdepth 3 \( -name '*.csproj' -o -name '*.sln' \) 2>/dev/null)
[ -n "$projs" ] || { echo "*.csproj or *.sln not found in $DIR" >&2; exit 3; }
command -v dotnet >/dev/null 2>&1 || { echo "dotnet not found" >&2; exit 4; }
( cd "$DIR" && dotnet restore )
exit $?
;;
*) echo "unknown ecosystem: $eco" >&2; exit 2 ;;
esac
+23 -5
View File
@@ -1,11 +1,29 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# latest-version.sh — 查詢套件最新且穩定的版本號。 # latest-version.sh — 查詢套件最新且穩定的版本號。
# 用法: latest-version.sh <ecosystem> <name> # 用法:latest-version.sh <ecosystem> <name>
# ecosystem: nodejs | python | dotnet # ecosystem:nodejs | python | dotnet
# 輸出: 版本號一行;查不到 exit 4 # 輸出:版本號一行。
# 結束碼(慣例見 README「工具」章的結束碼總表):
# 0 查到版本號
# 1 參數個數不對
# 2 ecosystem 不認識
# 4 登錄站上查不到這個套件——呼叫方跳過這個套件
# 5 需要的指令不存在(curl、python3)
# 本工具不收專案目錄,所以沒有 6。
set -u set -u
eco="${1:?ecosystem required (nodejs|python|dotnet)}"
name="${2:?package name required}" if [ "$#" -ne 2 ]; then
echo "用法:latest-version.sh <ecosystem> <name>" >&2
exit 1
fi
eco="$1"
name="$2"
# 回應靠 curl 取得、靠 python3 解析。少了任一支會解出空字串,被誤判成查不到套件,所以先擋。
for c in curl python3; do
command -v "$c" >/dev/null 2>&1 || { echo "$c not found" >&2; exit 5; }
done
case "$eco" in case "$eco" in
nodejs) nodejs)
+20 -3
View File
@@ -1,11 +1,28 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# list-packages.sh — 列出專案的所有外部套件與目前版本。 # list-packages.sh — 列出專案的所有外部套件與目前版本。
# 用法: list-packages.sh [專案目錄](預設目前目錄) # 用法:list-packages.sh [專案目錄](預設目前目錄)
# 輸出(TSV): ecosystem<TAB>name<TAB>current # 輸出(TSV):ecosystem<TAB>name<TAB>current
# 支援: nodejs(package.json)、python(requirements.txt / pyproject.toml)、dotnet(*.csproj) # 支援:nodejs(package.json)、python(requirements.txt / pyproject.toml)、dotnet(*.csproj)
# 結束碼(慣例見 README「工具」章的結束碼總表):
# 0 掃描完成(沒有套件時輸出零行)
# 1 參數個數不對
# 4 需要的指令不存在(python3)
# 6 找不到專案目錄——呼叫方停手
set -u set -u
if [ "$#" -gt 1 ]; then
echo "用法:list-packages.sh [專案目錄]" >&2
exit 1
fi
DIR="${1:-.}" DIR="${1:-.}"
# 先擋找不到專案目錄。少了這道,壞路徑會輸出零行,被誤判成專案沒有套件。
[ -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 4; }
# nodejs: package.json 的 dependencies / devDependencies # nodejs: package.json 的 dependencies / devDependencies
if [ -f "$DIR/package.json" ]; then if [ -f "$DIR/package.json" ]; then
python3 - "$DIR/package.json" <<'EOF' python3 - "$DIR/package.json" <<'EOF'