This repository has been archived on 2026-07-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
code-review/skills/code-review-action-docker/SKILL.md
T
JefferyandClaude Opus 4.8 5a4d70dca9 docs(code-review-action-docker): 將 .js 集中資料夾慣例由 app 改為 src
把 code-review-action-docker skill 收集 .js 的資料夾慣例從 app/ 改為 src/,
同步更新 SKILL.md(各階段說明、entrypoint.sh/Dockerfile 範例路徑)與 README.md 對應段落。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 17:53:44 +08:00

242 lines
19 KiB
Markdown
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.
---
name: code-review-action-docker
description: 將 GiteaGitHub「Docker 容器 action」專案標準化為 Node 主程式+容器化,並串接文件化流程:(1) 檢查 action 主程式是否為 Node,否則保守改寫為 Node,且所有 `.js` 檔一律集中到 `src/` 資料夾;(2) 產生 `entrypoint.sh`,啟動前先輸出 action 名稱/用途/更新時間,再執行 node 主程式;(3) 產生使用最新 node 版本的 `Dockerfile`(4) 最後完整執行 `/jsc:doc-funcs` 處理流程(function 文件、指令檔逐行註解、重建 README)。當使用者說把 action 改成 dockernode、容器化 action、action 主程式 node 化、把 js 收進 src、產 entrypoint.shDockerfile 給 action,或提到 code-review-action-docker 時觸發。不適用於:非 action 專案、純前端打包、或不需容器化的一般 repo。
argument-hint: "[--action-dir <action 根目錄>] [--node-version <node tag>] [--main <主程式檔>] [--yes]"
---
# code-review-action-docker — action 容器化(Node 主程式)+文件化
五階段 skill:先做**前置設定與偵測**(找出 action 專案、讀取名稱/用途、判斷主程式語言),再把**主程式 Node 化並將所有 `.js` 收進 `src/`**,接著產生**啟動前先輸出 action 名稱/用途/更新時間的 `entrypoint.sh`**,然後產生**使用最新 node 版本的 `Dockerfile`**(並對齊 `action.yml` 的 docker 設定),最後**完整執行 `/jsc:doc-funcs` 處理流程**替整個專案補文件並重建 README。
| 階段 | 動作 |
| --- | --- |
| A. 前置設定與偵測 | 決定 action 根目錄 → 讀 `action.yml``action.yaml``name``description` → 判斷目前主程式與語言 |
| B. 主程式 Node 化 | 主程式非 Node 則**保守改寫**為 Node(高風險,先確認)→ 所有 `.js` 集中到 `src/`,更新所有引用、`package.json``action.yml` |
| C. entrypoint.sh | 產生 `entrypoint.sh`:先輸出 action **名稱/用途/更新時間**,再 `exec` node 主程式 |
| D. Dockerfile | 依六步流程(參數處理 → 安裝套件 → 複製檔案 → 執行程序 → 縮小映像檔 → 設定入口)產生使用**最新 node 版本**的 `Dockerfile`,多階段建置縮小映像、`ENTRYPOINT` 指向 `entrypoint.sh` |
| E. 串接 doc-funcs | 對整個 action 專案完整執行 `/jsc:doc-funcs` 流程(function 文件、指令檔逐行註解、重建 README) |
---
## 輸出規範(務必遵守)
- **語言**:所有面向使用者的輸出(計畫、進度、總結、反問)一律使用**繁體中文(台灣用語)**;僅識別字、檔名、git/docker 指令、API 路徑、程式碼等技術標識保留原文,**不可**使用簡體字。
- **編碼無亂碼**:凡輸出含繁體中文、全形標點、emoji,一律 **UTF-8(不含 BOM**,不得出現問號方框或錯碼。產生/覆寫的 `entrypoint.sh``Dockerfile``action.yml``README.md` 同樣需 UTF-8(不含 BOM)。
- **自動執行原則**:除非使用者明確要求先確認,或遇到不可忽略的必要決策,否則各階段只需輸出簡短計畫/進度後直接執行到完成。**一定會中斷詢問的點**:階段 B 主程式「非 Node 需改寫」時(破壞性,須先確認),以及階段 E 由 `/jsc:doc-funcs` 自身的「如何實作」詢問。
- **不破壞既有工作**:移動 `.js`、改寫主程式、覆寫 `entrypoint.sh``Dockerfile``action.yml` 前,若工作區有未提交變更,先提醒使用者建議先 commit/備份;**絕不** `reset --hard``checkout -f``clean`,也不刪除使用者既有原始碼。移動檔案優先用 `git mv` 以保留歷史。
- **保留行為**:Node 化只「翻譯」既有邏輯,不得擅自改變對外行為、輸入輸出契約或副作用;任何無法可靠等價推論的改動一律不做,並以註解或回報標註「需人工確認」。
- **不擴及無關檔案**:本 skill 只動 action 專案根目錄內的:主程式、`.js`(搬移到 `src/`)、`package.json``action.yml``action.yaml``entrypoint.sh``Dockerfile`,以及階段 E 由 doc-funcs 流程處理的目標;排除 `node_modules``.git``.docs``bin``obj`/第三方依賴。
---
## 參數
格式:`[--action-dir <action 根目錄>] [--node-version <node tag>] [--main <主程式檔>] [--yes]`
- `--action-dir <action 根目錄>`:action 專案根目錄。**省略時預設目前工作目錄**(須含 `action.yml``action.yaml`,否則依 A1 詢問)。
- `--node-version <node tag>``Dockerfile` 的 node base image tag(如 `22``22-alpine``lts`)。**省略時預設使用最新 node 版本**(`node:latest`,見階段 D)。
- `--main <主程式檔>`:指定主程式入口檔(相對 action 根目錄)。省略時依 A3 自動判斷。
- `--yes`:盡量不中斷。即使帶此參數,「主程式非 Node 需改寫」與 doc-funcs 的「如何實作」仍會詢問。
---
## 階段 A:前置設定與偵測
### A1. 決定 action 根目錄
-`--action-dir` → 採用(展開 `~`)。
- 省略 → 用目前工作目錄。
- 根目錄須存在 `action.yml``action.yaml`action manifest)。**找不到** action manifest → 回報「此目錄不是 action 專案(缺 action.ymlaction.yaml)」並詢問正確路徑,**不臆測**、不在非 action 專案上動工。
### A2. 讀取 action 名稱與用途
從 action manifest 讀取:
- `name`action 名稱(供 `entrypoint.sh` 輸出與 README 使用)。
- `description`action 用途。
- `runs`:目前的執行設定(`using``main``image``entrypoint` 等)。
`name``description` 缺漏,回報並請使用者補;無法取得時於後續輸出以「(未提供)」保守標示,**不編造**。
### A3. 判斷目前主程式與語言
依序判斷主程式入口(取第一個成立者):
1.`--main <主程式檔>` → 直接採用。
2. `action.yml` 為 JS action`runs.using: node*`)→ 取 `runs.main`
3. `action.yml` 為 docker action`runs.using: docker`)→ 看 `runs.entrypoint``Dockerfile``ENTRYPOINT``CMD` 推主程式。
4. 以上皆無 → 依專案檔與副檔名分布推斷(`package.json``main``bin``index.js``*.sh``*.py` 等)。
判定**主程式是否為 Node**:入口為 `.js``.mjs``.cjs` 且由 `node` 執行即視為 Node;入口為 shellpython/其他則視為非 Node。輸出偵測結果(action 名稱、用途、主程式檔、判定語言、是否為 Node),再進入階段 B。
---
## 階段 B:主程式 Node 化,並將所有 `.js` 收進 `src/`
### B1. 主程式 Node 化
- **已是 Node** → 確認入口檔,不改寫邏輯,直接進 B2。
- **非 Nodeshellpython/其他)** → 這是**破壞性高風險決策**:先以 `AskUserQuestion` 向使用者確認是否改寫為 Node,選項至少含「改寫為 Node」「維持原樣只做容器化(略過改寫)」「其他」。經確認後才改寫:
- 逐段把原主程式邏輯**保守翻譯**為 Node(建議 `index.js`);保留對外行為、輸入(環境變數/`INPUT_*`args)與輸出(stdoutexit code/檔案副作用)契約。
- 外部指令呼叫以 `child_process``execFileSync``spawnSync`)對應;檔案操作以 `fs`;環境變數以 `process.env`
- 任何無法可靠等價翻譯處,**不臆測**:以 `// 需人工確認:...` 標註並回報。
- 改寫完成後,原非 Node 主程式於 B2 一併處理(移除或保留由使用者裁示;預設保留並在 README/回報標註已由 Node 取代)。
### B2. 所有 `.js` 集中到 `src/`
- 在 action 根目錄建立 `src/`(若不存在)。
- 將專案內所有 `.js``.mjs``.cjs`(排除 `node_modules``.git``.docs``bin``obj`/第三方依賴)**移入 `src/`**,優先 `git mv` 保留歷史。主程式入口統一為 `src/index.js`(或 `src/<main>.js`)。
- **移動後必須更新所有引用**,確保不破壞:
- 模組間的 `require``import` 相對路徑。
- `package.json``main``bin``scripts``exports`(指向 `src/...`)。
- `action.yml``Dockerfile``entrypoint.sh` 內對主程式路徑的引用。
-`src/` 下無 `package.json` 而專案需要相依,於 `src/` 建立或移入 `package.json``main` 指向入口檔;不擅自新增與功能無關的相依。
### B3. action.yml 對齊 docker
將 manifest 的 `runs` 對齊為 docker 容器 action(保留既有 `inputs``outputs``name``description`):
```yaml
runs:
using: docker
image: Dockerfile
entrypoint: entrypoint.sh
```
若原本是 JS action`using: node*`),改為上述 docker 設定;若已是 docker action,確認 `image` 指向 `Dockerfile``entrypoint` 指向 `entrypoint.sh`
---
## 階段 C:產生 entrypoint.sh(先輸出名稱/用途/更新時間,再啟動 node 主程式)
在 action 根目錄產生(或覆寫)`entrypoint.sh`:**啟動 node 主程式前,先輸出 action 名稱、用途、更新時間**。
- **更新時間**為產生此檔當下的時間戳,使用台灣時區(Asia/Taipei)並固定為 `yyyy/MM/dd HH:mm:ss`(可用 `TZ='Asia/Taipei' date +'%Y/%m/%d %H:%M:%S'` 取得),**寫成檔內固定字串**(非執行期動態時間)。
- 名稱/用途取自階段 A2 的 `action.yml`
- 最後以 `exec node <主程式>`(如 `exec node /action/src/index.js "$@"`)啟動,讓 node 取代 shell 行程,正確傳遞訊號與 exit code;路徑須與階段 D 的 `Dockerfile` 落點一致。
範例(實際路徑依階段 B 入口而定):
```sh
#!/bin/sh
set -e
# action 啟動橫幅:輸出名稱/用途/更新時間(此檔由 code-review-action-docker 產生)
echo "================================================"
echo "Action : <action name>"
echo "用途 : <action description>"
echo "更新時間: 2026/06/30 18:30:05"
echo "================================================"
# 啟動 node 主程式(以 exec 取代 shell,正確處理訊號與 exit code
exec node /action/src/index.js "$@"
```
- 賦予可執行權限:`chmod +x entrypoint.sh`(並於 git 標記為可執行)。
- 此檔開頭的「用途/更新時間」與每行註解,最終會在階段 E 由 `/jsc:doc-funcs` 的指令檔流程統一補齊/覆寫為標準格式(用途與更新日期同一註解區塊、逐行註解);本階段先確保**執行期輸出**正確即可。
---
## 階段 D:產生 Dockerfile(使用最新 node 版本,六步流程依主程式實作量身產生)
在 action 根目錄產生(或覆寫)`Dockerfile`**base image 使用最新 node 版本**,採**多階段建置**以縮小最終映像檔。六步流程是**骨架**,但**每一步的實際內容必須依階段 B 的主程式(`src/`)實作決定**——不要套用與主程式無關的固定樣板,也不要硬塞主程式用不到的安裝或建置指令。
### D0. 先盤點主程式實作需求
產生 Dockerfile 前,先檢視 `src/` 主程式與 `package.json`,判斷各步該放什麼:
- **相依套件**`src/package.json``dependencies``devDependencies`、是否有 lockfile`package-lock.json``npm-shrinkwrap.json`)。決定第 2 步用 `npm ci` 還是 `npm install`、是否需要 dev 相依來 build。
- **是否需要 buildtranspile**:有無 `scripts.build`、是否為 TypeScript/打包(產物落在 `dist/``build/` 等)。決定第 4 步是否要跑建置、第 5 步 runtime 該帶入哪個產物目錄。
- **OS 層相依**:主程式是否以 `child_process` 呼叫外部執行檔(如 `git``bash``openssl``python3``ffmpeg``imagemagick`),或使用需編譯的原生模組(node-gypnative addon)。決定第 2 步是否要 `apt-get install` 對應套件,以及第 5 步 runtime 基底是否需保留這些執行檔。
- **執行期需求**:主程式讀取的環境變數、需存取的檔案路徑、是否寫入暫存目錄。決定 `WORKDIR`、需 `COPY` 的檔案範圍與必要的 `ENV`
- **入口檔**:階段 B 決定的主程式入口(如 `src/index.js`),決定第 6 步與 `entrypoint.sh``node` 路徑。
### D1~D6:依盤點結果填入六步
1. **參數處理**:以 `ARG` 注入 node 版本(預設最新)與主程式需要的 build-time 參數;可調參數集中在檔案開頭。
2. **安裝套件**:依 D0 的相依結果安裝——有 lockfile 用 `npm ci`、否則 `npm install`;不需 build 時加 `--omit=dev`,需 build 時先裝完整相依(含 dev)供第 4 步使用。**只在主程式真的會用到時**才 `apt-get install` OS 套件,並於同一 `RUN` 清掉 apt 快取。先 `COPY` 相依描述(`package*.json`)再安裝,以利 layer 快取。
3. **複製檔案**`COPY` 主程式實際需要的檔案(`src/``entrypoint.sh`,及主程式會讀取的資源);不需要的檔案不必帶入。
4. **執行程序**:賦予 `entrypoint.sh` 執行權限;**僅當 D0 判定需要 buildtranspile 時**才執行(如 `npm run build`),否則此步只做權限設定,不要硬加建置指令。
5. **縮小映像檔**:多階段建置,runtime 改用 slim 基底,只 `COPY --from=build` 帶入主程式執行**真正需要**的產物——有 build 產物時帶入 `dist/` 與 production `node_modules``npm prune --omit=dev` 或重裝 production 相依),純 JS 無 build 時帶入 `src/` 與 production `node_modules`;若 D0 判定 runtime 需要某些 OS 執行檔,於 runtime 階段一併安裝(slim 基底可能不含)。不要把 build 階段的 dev 相依與快取帶進最終映像。
6. **設定入口**`ENTRYPOINT` 指向 `entrypoint.sh`,其內 `node` 路徑為 D0 的入口檔。
base image 版本:預設 build 基底 `node:latest`、runtime 基底 `node:slim`(皆為最新版,slim 用於縮小);帶 `--node-version <tag>`(如 `22``lts`)時改用 `node:<tag>``node:<tag>-slim`。若需確認當前最新穩定版號,可查詢 Docker Hub(`https://hub.docker.com/_/node`)後於 `FROM` 註記實際版本,但**預設行為是使用最新版**。
下列為**最簡基準骨架**(純 JS、無 build、無 OS 相依的情況);實際內容須依 D0 盤點調整,第 4 步建置、第 2/5 步 OS 套件等視主程式需要增刪:
```Dockerfile
# syntax=docker/dockerfile:1
# 1. 參數處理:node 版本以 ARG 注入(預設最新版;--node-version 可覆寫)
ARG NODE_VERSION=latest
ARG NODE_RUNTIME=slim
# ---- build 階段:安裝相依、準備產物 ----
FROM node:${NODE_VERSION} AS build
WORKDIR /action
# 2. 安裝套件:先帶相依描述以利 layer 快取,再裝 src/ 相依
# (需 build 時改裝完整相依;需 OS 套件時於此 apt-get install 並清快取)
COPY src/package*.json /action/src/
RUN if [ -f /action/src/package.json ]; then \
cd /action/src && (npm ci --omit=dev || npm install --omit=dev); \
fi
# 3. 複製檔案:複製主程式實際需要的檔案
COPY . /action
# 4. 執行程序:賦予 entrypoint 執行權限(D0 判定需要 build 時於此 npm run build
RUN chmod +x /action/entrypoint.sh
# 5. 縮小映像檔:多階段建置,runtime 改用 slim 基底、只帶必要產物
# (有 build 產物時改帶 dist/ 與 production node_modulesruntime 需要的 OS 執行檔於此安裝)
FROM node:${NODE_RUNTIME} AS runtime
WORKDIR /action
COPY --from=build /action /action
# 6. 設定入口:以 entrypoint.sh 啟動(其內 node 指向 D0 的入口檔)
ENTRYPOINT ["/action/entrypoint.sh"]
```
- **依主程式實作**:上面只是基準骨架。若主程式是 TypeScript/需打包,第 4 步要加 `npm run build`、第 5 步只帶 `dist/` 與 production 相依;若主程式會 spawn 外部執行檔或用原生模組,第 2/5 步要補對應 OS 套件;用不到的步驟內容不要硬塞。
- **版號對齊**runtime 的 slim 基底版號需與 build 基底一致。預設 `node:latest``node:slim`;帶 `--node-version 22` 時設 `NODE_VERSION=22``NODE_RUNTIME=22-slim`。注意**沒有 `node:latest-slim` 這個 tag**,最新版 slim 一律用 `node:slim`,故以獨立的 `NODE_RUNTIME` 參數帶入、不要用 `${NODE_VERSION}-slim` 組裝。
- **自我檢查**`entrypoint.sh``node <主程式>` 路徑(如 `/action/src/index.js`)需與 `Dockerfile``WORKDIR``COPY` 落點一致,避免容器啟動時找不到主程式。
- 此檔的用途/更新日期註解與逐行註解,同樣於階段 E 由 doc-funcs 指令檔流程統一補齊。
---
## 階段 E:完整執行 /jsc:doc-funcs 處理流程
容器化與 Node 化完成後,對**整個 action 專案**完整執行 `/jsc:doc-funcs` 流程,替程式碼與指令檔補文件並重建 README:
- 以階段 A1 的 action 根目錄為目標,執行 `doc-funcs` skill 的完整流程(判斷語言 → 掃描 function 與指令檔 → 建立 `.docs/` 草稿 → 草稿品質檢查 → 詢問使用者如何實作 → 依選擇寫回 → 保守優化 → 重建 README → 錨點檢查 → 清理草稿 → 建置/語法驗證)。
- doc-funcs 會涵蓋本次新增/變更的指令檔:`entrypoint.sh`(補齊「用途+更新日期同一註解區塊」與逐行註解)、`Dockerfile`(逐行註解);以及 `src/` 內 Node 主程式與各 function 的文件註解。
- doc-funcs 的「如何實作」詢問(全部一起/逐個/其他)由使用者於該流程內裁示,本 skill 不代為決定。
- 完成後依 doc-funcs 規範重建根目錄 `README.md`(含台灣時區更新時間、專案列表、功能列表、使用範例)。
> 銜接方式:在本 skill 環境中以 `/jsc:doc-funcs`(或 Skill 工具)啟動 doc-funcs 流程;若該流程需參數,沿用本 skill 的 action 根目錄為目標專案。
---
## 總結
各階段執行後輸出:
- **階段 A**action 根目錄、action 名稱/用途、原主程式檔與語言、是否為 Node。
- **階段 B**:是否改寫主程式(及改寫摘要與「需人工確認」清單)、搬入 `src/``.js` 清單、已更新的引用(`package.json``action.yml`/路徑)。
- **階段 CD**`entrypoint.sh` 的輸出內容(名稱/用途/更新時間)與啟動的 node 主程式、`Dockerfile` 採用的 node 版本與 `ENTRYPOINT`
- **階段 E**doc-funcs 流程的處理結果(文件化的 function 與指令檔、重建的 README)。
- 列出本次新增/變更的檔案與其相對路徑,並提醒使用者於提交前確認 `entrypoint.sh` 有可執行權限、容器能正確啟動。
---
## 呼叫方式
格式:`[--action-dir <action 根目錄>] [--node-version <node tag>] [--main <主程式檔>] [--yes]` — 全部可省略(根目錄預設目前工作目錄;node 版本預設最新;主程式自動判斷)。
| 助理 | 呼叫 |
| --- | --- |
| Claude Code / Antigravity | `/jsc:code-review-action-docker`,或 `/jsc:code-review-action-docker --action-dir ~/work/my-action --node-version 22` |
| Codex | `$code-review-action-docker`,或 `$code-review-action-docker --action-dir ~/work/my-action`,或用 `/skills` 選單 |
| OpenCode | 描述需求(如「把這個 action 主程式改成 node、所有 js 收進 src/,產生會先輸出 action 名稱/用途/更新時間再啟動 node 的 entrypoint.sh、用最新 node 版本的 Dockerfile,最後跑 doc-funcs 補文件並重建 README」)自動觸發 |