14 KiB
name: sdlc-feat description: 僅由 /sdlc-feat 指令叫用。領取一顆工作包、起錶、備妥分支,逐項實作並勾選待辦,最後分批提交並開立 PR。
sdlc-feat
拿一顆工作包,從領取到開出 PR。
第一段領取與開工準備:把工作包安全地認領下來,開始計時,備妥開工的分支。 這一段不改任何一行程式碼——它只負責讓後面的實作有個乾淨的起點。
第二段逐項實作:一項一項把待辦做完並即時勾選,讓議題頁的進度條隨時反映真實狀態。
第三段提交與開立 PR:把變更整理成讀得懂的歷史,開出 PR,停錶。
這份檔案是流程正本。各平台的轉接檔只是指回這裡,不要把規則抄過去。
輸入
一個工作包議題編號。
第一段:領取與開工準備
1. 讀工作包
node scripts/wp-extract.js --repo <owner/name> --index <編號>
拿到的是結構化欄位:待辦與它自己的驗收、範圍邊界、介面契約、相依、repo 列表。 不必再讀整份議題全文。
先看 未處理留言數。 只要不是 0,就代表議題描述可能是過期的——留言裡有決策還沒被
整併回描述。這時先停下來告訴使用者有幾則未整併的留言,建議先執行 /sdlc-sync
把它們整併回描述,再回來實作。使用者堅持要繼續就繼續,但要記下這件事,
並在最後的 PR 描述裡註明「實作基於未整併留言前的描述」。
再看 相依.depends。 裡面還有沒關閉的議題,代表這顆的前置還沒做完。照樣先說出來,
讓使用者決定要不要現在做。
2. 領取工作包
先試跑,看清楚會做什麼:
node scripts/claim.js --repo <owner/name> --index <編號> --dry-run
確認無誤後拿掉旗標再跑一次。放行時它會設 assignee、貼「進行中」標籤、起錶——三件事 一起構成領取鎖,錶則是工時的來源。
領取鎖有四種狀態,三種擋、一種放行。被擋下來時不要繞過去,照著錯誤碼告訴使用者 發生什麼事、下一步是什麼:
| 狀態 | 錯誤碼 | 下一步 |
|---|---|---|
| 別人已經認領這顆 | CLAIMED_BY_OTHER |
改領別顆,或先跟對方確認 |
| 你的錶已經跑在這顆上 | STOPWATCH_ON_THIS_ISSUE |
這顆你正在做;要重新計時請先手動停錶 |
| 你的錶跑在別的議題上 | STOPWATCH_ON_OTHER_ISSUE |
多半是忘了停上一顆;先去停掉再回來 |
| 沒有鎖 | —— | 放行。自己已認領但沒起錶也算沒有鎖,那正是中斷後重跑的情形 |
碼錶一律由使用者自己停。哪一段時間該記在哪顆議題上只有他知道,代勞會把工時記錯地方。
鎖以外還有一個前置條件:repo 上要有「進行中」標籤。缺了會得到 LABEL_NOT_FOUND,
請使用者自己去建立——不要自己建,標籤體系不該在多個 repo 之間長出雜草。
3. 問來源分支
一次問一題。 新分支要從哪裡長出來,只有使用者知道,不要替他決定。 給兩個選項,並附上你判斷的理由:
- 建議 — 你的答案。多數情況是開發分支(
master/main/develop); 但若這顆工作包明顯是某個既有功能分支的一部分,就建議那一支,並說明為什麼。 - 手動輸入 — 讓使用者自己填分支名。
4. 把議題標題翻成英文
分支名的中段要用英文,中文會讓 CI 與 URL 出問題。把工作包議題的標題翻成
小寫英文 kebab、40 字元以內,例如「建立工作包的抽取契約」→ wp-extract-contract。
翻譯要保留原意而不是逐字直譯,寧可用一個更短的說法,也不要把長句截斷成看不懂的字串。
5. 備妥分支
分支開在工作包的 repos 列出的那些 repo 上,不是開在本 plugin 的目錄裡。
repos 只有一顆就用那一顆;有多顆時逐一確認要在哪幾個開分支,
再對每一個各跑一次 branch-prep,分支名在每個 repo 都相同。
node scripts/branch-prep.js --path <目標專案路徑> --source <來源分支> \
--slug <英文-kebab> [--type feat] --dry-run
--type 只在來源是開發分支時要給(feat/fix/chore…);從功能分支長出時,
類型與需求描述沿用來源,不必也不能再指定。
試跑會印出將執行的 git 指令與算出來的分支名。確認無誤後拿掉旗標再跑一次。
它保證三件事,都是為了不弄丟別人的東西:工作區不乾淨時先擋下來,免得把不相干的 改動帶進這顆工作包的分支;來源分支在遠端已存在時是 pull 而不是重建;目標分支已經 存在時是接上去而不是蓋掉。
工作區不乾淨(DIRTY_WORKTREE)時,把 git 回報的檔案念給使用者聽,讓他決定要提交、
git stash 還是丟掉——不要自己選。
6. 回報
印出一份開工前的現況,不寫回議題:
- 工作包標題與網址、這一顆有幾項待辦
- 認領結果(是否本來就是自己的)、碼錶已起
- 來源分支、新分支名、分支是新建還是接上既有
- 未處理留言數與未關閉的先決議題(若有)
第二段:逐項實作
7. 認出語言,讀規則正本
改任何一個檔案之前,先依專案檔認出這是什麼語言,再讀兩份規則正本:
references/coding-standards.md— 分層判定與各層要寫什麼註解references/comment-styles.md— 該語言的註解格式
規則以那兩份為準,這裡不複述——抄過來就會有兩份各自演化的規則。只強調兩件最常被跳過的: 認不出語言就停下來問、不要猜,以及規則只存在於本 plugin 裡, 不寫進目標專案的任何檔案。
屬性的資料範例優先從 MCP 取得;取不到就以邏輯推理,並照 comment-styles.md 的寫法
在註解裡註明「由邏輯推理、未經驗證」。這句註明不能省,否則後面的人會照著沒對過的格式寫解析。
8. 一項一項做
依 wp-extract 給的 待辦 順序做。每一項的做法:
- 讀它底下的
驗收——那是「這一項做到什麼程度算完成」的定義。 - 實作,照
coding-standards.md的分層與註解規範。 - 這一項的驗收都成立了,才算完成。
過程不打斷。 不要每做完一項就問一次「可以繼續嗎」——二十項待辦不該按二十次同意。
只印進度,例如 [3/12] 已完成:解析九個段落。
真正需要停下來問的只有三種:語言認不出來、待辦的意思有歧義、做下去會超出工作包的
範圍邊界。除此之外一路做完。
9. 做完一項就勾一項
node scripts/issue-update.js --repo <owner/name> --index <編號> \
--tick '<wp-extract 給的那一行 raw>' --section 待辦
--tick 收的是抽取契約交出的那一整行 raw,逐字包含縮排;它只把那一行的方框換成
已勾,議題其餘部分一字不動。待辦與它底下的驗收各自是一行,各勾各的。
--section 是那一項所在的段落:勾 待辦 裡的項目就給 待辦,勾 整體驗收 就給
整體驗收。一定要給——兩個段落常有一模一樣的一句話,不給就分不出要勾哪一個。
不要自己拼那一行,一律用 wp-extract 給的 raw。四種擋下來的情況都照實說,不要繞過去:
| 錯誤碼 | 意思 | 下一步 |
|---|---|---|
RAW_NOT_FOUND |
議題上找不到這一行 | 手上的抽取結果過期了(議題被改過);重跑 wp-extract 再試 |
RAW_AMBIGUOUS |
這一行在同一個段落裡出現不只一次 | 分不出要勾哪個;請使用者把重複的那幾項改寫成看得出差別的說法 |
NOT_A_CHECKBOX |
議題上那一項沒有方框 | 請使用者把它補成 - [ ] …;不要自己改寫議題 |
SECTION_NOT_FOUND |
--section 的段落不存在 |
對照 wp-extract 的輸出確認段落名稱 |
不要為了勾選在議題上留留言。 勾選改的是 body,進度條自己會動;逐項留言會把議題洗版, reviewer 得從一堆「已完成第 N 項」裡找真正的討論。
10. 中斷後重跑
進度完全由 Gitea 上的勾選狀態推導,不看任何本機檔案。重跑這一段時:
- 重新
wp-extract,看待辦裡哪些done已經是true。 - 從第一個還沒勾的接下去做。
- 已經勾過的項目再
--tick一次是安靜的 no-op(回傳已經勾過: true,不發 PATCH), 所以不確定某一項有沒有勾到時,直接再勾一次即可,不必先查。
11. 回報
全部待辦完成後印一份小結,不寫回議題:
- 幾項待辦、幾項驗收,全部勾選完成
- 改了哪些檔案,各屬於哪一層
- 有沒有待辦因為
範圍邊界而被刻意不做 - 語言與註解格式用的是哪一份對照
- 哪些資料範例是推理來的(MCP 取不到的那些),讓 reviewer 知道哪幾個格式還沒人對過
第三段:提交與開立 PR
12. 分批提交
全部待辦都勾完之後才進這一段。變更依類型分批:
node scripts/commit-split.js --path <目標專案路徑> --type feat \
--subject '<繁中描述>' [--scope <功能名>] --dry-run
--type 是這次程式碼變更的類型(feat/fix/refactor…);測試、文件與設定檔
由腳本自己認出來,各自成批,不必也不能指定。--body 寫「為什麼這樣做」,那一段會接在
每一顆 commit 的首行之後——本 repo 的歷史靠它讀得懂。
某一批提交失敗時,錯誤會列出前面已經建立的那幾顆 commit。修掉原因之後重跑即可, 已建立的不會重複;不要自己去回捲歷史。
--scope 只在某一批有多個檔案時才需要:單檔那批的 scope 就是檔名。試跑會印出將建立的
每一顆 commit 與它各自的檔案,確認無誤後拿掉旗標再跑一次。
描述用繁體中文。 日後回顧時看得懂的是中文;夾雜英文的專有名詞(函式名、旗標名) 保留原文即可。
一次變更橫跨兩個不相干的功能時,用 --files 分兩次跑:
node scripts/commit-split.js ... --files scripts/claim.js,test/claim.test.js
一顆 commit 的描述只說得清楚一件事,硬湊在一起就失去了分批的意義。
13. 寫 PR 描述
固定八個段落,順序不能換——reviewer 每次都在同一個位置找到要找的資訊:
- 摘要 — 這個 PR 做完之後,什麼事變得可能。
- 需求議題 —
#<編號>。 - 工作包議題 —
#<編號>。 - 變更內容 — 改了什麼。commit 一覽加上新增/修改的檔案。
- 設計重點 — 為什麼這樣做。取捨與理由,不是實作步驟的複述。
- 解決的問題 — 這次修掉了什麼。有具體觸發條件的就寫出來。
- 影響的功能 — 誰會被影響、既有行為有沒有改變。
- 測試結果 — 見下。
「測試結果」放實際跑過的輸出,原樣貼上,不要改寫成「已測試通過」——那句話看不出 跑過什麼,reviewer 沒辦法據以判斷。沒有自動化測試時,寫出 reviewer 自己能重現的手動 驗證步驟(跑什麼指令、看到什麼算對)。
pr-create 會擋下缺段落、順序不對、以及測試結果只有空話的描述。被擋下來時補真的內容,
不要為了通過而拼湊。
14. 開 PR 並停錶
node scripts/pr-create.js --repo <目標專案 owner/name> --head <分支名> \
--base <來源分支> --body-file <描述檔> \
--issue-repo <工作包議題的 owner/name> --index <工作包編號> --dry-run
--repo 是程式碼所在的 repo(PR 開在那裡),--issue-repo 是工作包議題所在的
repo(錶停在那裡)。兩者常常不是同一個——議題在需求的 repo,程式碼在 repos 列的
那幾個。同一個 repo 時 --issue-repo 可以省略。
--base 就是第一段問到的那支來源分支,要明講——腳本不替你猜 master 還是 main。
標題由腳本設為分支名,不必也不能另外指定。
順序是先開 PR 再停錶,而且 PR 沒開成就不停錶——工時要記在真的有做事的那段時間上。
錶本來就沒在跑不算失敗(碼錶已停 會是 false 並附一句說明),PR 仍然開出去了。
重跑不會開出第二顆 PR:同一個 head 已經有開著的 PR 就回傳它(created 為 false),
然後照樣停錶——那一步可能正是上次中斷的地方。
15. 回報
- PR 的網址與編號、標題(等同分支名),以及它是這次新開的還是接上既有的
- 建立了哪幾顆 commit
- 碼錶是否已停;沒停的話把腳本回的那句說明一起帶出來
- 議題上還有沒有沒勾完的待辦(理論上應該沒有;有的話要說出來)
邊界
- 第一段不改任何一行程式碼、不勾待辦、不提交、不開 PR——那些是後面幾段的事。
- 第二段只實作與勾選。不提交、不開 PR、不停錶——那是第三段的事。
- 第三段不改任何一行程式碼。到這裡實作已經結束,要改就回第二段改完再來。
- 不把「已測試通過」這種空話寫進 PR 描述,也不為了通過檢查而拼湊內容。
- 不代替使用者決定 commit 的類型與描述;
--type與--subject都要是這次真的做了什麼。 - 不把實作規範或註解格式寫進目標專案的任何檔案。
- 不改與待辦無關的程式碼;順手想修的東西記下來說出來,不要摸進這次的變更裡。
- 不為了勾選在議題上留留言。
- 不自行建立標籤。缺「進行中」標籤時中止並請使用者建立。
- 不代替使用者停錶,也不在被鎖擋下時繞過去。
- 不替使用者決定來源分支。
- 不寫任何本機狀態檔。 進度完全由 Gitea 上的 assignee、標籤、碼錶與 git 本身推導, 換一台機器或換一個 agent 都要能直接接手。