feat/commit-split-and-pr/main
master
/sdlc-feat 的第三段:工作包做完之後,變更被整理成讀得懂的 git 歷史,PR 開出來,碼錶停下。
/sdlc-feat
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
#13 — 以 sdlc-feat 分批提交、開立 PR 並停錶
新增 scripts/commit-split.js、scripts/pr-create.js,prompts/sdlc-feat.md 加入第三段, scripts/lib.js 增加 openGitRepo 並修正 parseFlags。15 顆 commit:
scripts/commit-split.js
scripts/pr-create.js
prompts/sdlc-feat.md
scripts/lib.js
openGitRepo
parseFlags
feat(commit-split)
test(分批提交)
feat(pr-create)
test(pr-create)
feat(sdlc-feat)
test(sdlc-feat-assets)
fix(commit-split)
test(commit-split)
fix(pr-create)
refactor(lib)
fix(lib)
test(script-contract)
--key=value
--
docs(sdlc-feat)
這 15 顆 commit 全部由本 PR 的 commit-split 自己產生。
commit-split
scripts/
--type
--files
pr-create
Code review 抓出四個缺陷,都已修掉並各自補上回歸測試:
1. 停錶停到別人的議題上。 claim 在工作包議題所在的 repo 起錶,而 PR 開在目標 專案上——議題在需求的 repo,程式碼在 repos 列的那幾個,兩者常常不同。原本用同一個 --repo 同時指 PR 與停錶,會去停一顆不相干的議題(或 404,而且是在 PR 已經建立之後 才拋錯,重跑又會撞上重複的 PR),而自己的錶一直跑下去。新增 --issue-repo。
claim
repos
--repo
--issue-repo
2. 改名時舊檔的刪除被漏掉。 git diff --name-only 預設偵測改名,只印目的地那一個 路徑。實測:git mv a b 之後,a 的刪除留在 index 沒被提交,而腳本回報 ok: true, 要下一次跑才會發現工作區不乾淨。加 --no-renames。
git diff --name-only
git mv a b
a
ok: true
--no-renames
3. 類型對照表只認 test/。 目標專案用 tests/、spec/、__tests__/,或把 user.test.js 放在被測檔案旁邊,測試就會被併進 feat 那一批。
test/
tests/
spec/
__tests__/
user.test.js
feat
4. 中途失敗不說做到哪裡。 某一批提交失敗時,前面已經建立的 commit 不會被回捲(那會 動到使用者的歷史,而那幾顆本身是好的),但錯誤原本沒說已經做了什麼,重跑前得自己去翻 git log。
git log
另外修掉一個 lib 的既有瑕疵:parseFlags 對 --key=value 與 --key value 套用同一條 「值不得以 -- 開頭」檢查。等號寫法沒有這個歧義,而 commit 訊息與 PR 描述裡出現 --flag 是常態。這是拿 commit-split 提交它自己時真的撞到的——--body 的內容第一行就是 「--repo 與 --issue-repo 的差別」,整顆 commit 因此做不出來。
--key value
--flag
--body
scripts/branch-prep.js
lib.js
test/helpers/temp-repo.js
makeTempRepo
git
已知的上游落差:議題 #1 的 story 38 說「PR 七段描述」,但列出的是八個名稱。本 PR 依 列表實作八段(SECTIONS),正本也寫「固定八個段落」。#1 的措辭仍待修正,不在本工作包範圍。
SECTIONS
在最新 master(1c6fb8aa)之上實際執行 npm test:
1c6fb8aa
npm test
ℹ tests 597 ℹ suites 0 ℹ pass 597 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
master 既有 505,本分支新增 92。
commit-split 的類型分類是表格驅動(15 種路徑各一例),分批界線、scope 規則、改名、 中途失敗、--files、--body 各有覆蓋;git 的部分在臨時 repo 上跑真的 git。 pr-create 的八段各有「缺這一段就擋」的案例,空話清單逐項驗過,停錶的順序、跨 repo、 冪等與「錶本來就沒在跑」也都釘住。
實機驗證:改名後工作區確實乾淨且 A+D 都在同一顆 commit 裡;測試檔放在程式碼旁邊 認得出來;中途失敗的訊息確實列出已建立的 commit。最強的一次驗證是本 PR 的 15 顆 commit 全部由 commit-split 自己產生,而這份描述在送出前先通過了 pr-create 自己的八段檢查。
A
D
🤖 Generated with Claude Code
一個 commit 只裝一種類型:程式碼、測試、文件、雜項各自成批,reviewer 一次只看一件事, 日後 git log 也讀得懂。全部混成一顆「完成工作包」的巨大 commit,等於沒有歷史。 類型多半看得出來——測試檔就是 test、README 就是 docs——但 scripts/ 底下的改動是新功能 還是修 bug,只有做的人知道,所以那一批由 --type 指定。這張對照表是純字串規則,表格驅動。 scope 單檔用檔名(claim.test.js 的 scope 是 claim,不是 claim.test),多檔用 --scope 的 功能名。描述要有中文:日後回顧時看得懂的是中文,而夾雜英文的專有名詞本來就該保留原文。 --files 讓一次變更橫跨兩個功能時能分兩次跑;--body 讓工具產出的歷史與本 repo 既有的 commit 一樣說明得出「為什麼」。 列變更檔案刻意不用 git status --porcelain:它的前兩欄是狀態碼,而 runGit 會 trim 掉 輸出的前導空白,未 staged 的修改會少掉檔名的第一個字元。
標題等同分支名:reviewer 在列表上看到的就是分支,兩者對不上會找錯 PR。 描述的段落固定且順序固定,缺一段或順序不對就擋下,不自動補——補出來的段落是編的, 而 reviewer 會把它當成真的。 「測試結果」另外驗一次它不是空話。那一段是 reviewer 唯一能判斷「這東西真的跑過嗎」的 依據,寫「已測試通過」等於沒寫。判斷刻意很窄,只擋「整段只有一行,而那一行是已知的 偷懶寫法」——這一關要擋的是明顯沒跑過就交差,不是去評價別人的測試寫得夠不夠好。 沒有自動化測試時,寫得出可重現的手動驗證步驟就放行。 停錶排在 PR 開出去之後,而且只在 PR 真的建立了才停:工時要記在真的有做事的那段時間上。 錶本來就沒在跑不算失敗(Gitea 對此回 500)——PR 已經開出去了,把整件事報成失敗只會讓人 以為 PR 沒開成而重跑一次。
PR 描述的八個段落與順序寫在正本裡,由 pr-create 擋;正本負責的是腳本擋不住的事: 測試結果要貼實際輸出而不是改寫成一句話、被擋下來時補真的內容而不是為了通過而拼湊、 以及跨兩個功能時用 --files 分兩次跑。 先開 PR 再停錶的理由也寫進去了:工時要記在真的有做事的那段時間上。
git diff --name-only 預設偵測改名,只印出目的地那一個路徑。來源的刪除因此被漏掉—— 留在 index 裡沒被提交,而腳本還回報成功,要等下一次跑才會發現工作區不乾淨。加 --no-renames。 某一批提交失敗時,錯誤現在會列出前面已經建立的那幾顆 commit。不回捲它們:那會動到使用者的 歷史,而那幾顆本身是好的;但一定要說出做到哪裡,否則重跑前得自己去翻 git log。 類型對照表補上目標專案常見的測試擺法:tests/、spec/、__tests__/,以及放在被測檔案旁邊的 user.test.js。先前只認 test/,目標專案的測試會被併進 feat 那一批。
claim 在工作包議題上起錶,而 PR 開在目標專案上——議題在需求的 repo,程式碼在 repos 列的 那幾個,兩者常常不是同一個。先前用同一個 --repo 同時指 PR 與停錶,停到的會是別人的議題 (或 404 而在 PR 已建立之後才拋錯),而自己的錶還在跑。新增 --issue-repo,預設與 --repo 相同。 --index 與 --base 改為必填:停錶是這一步的一部分,忘了給會讓工時算不準;而目標專案的開發 分支可能叫 master、main 或 develop,猜錯會開到不存在的 base。 重跑先查同一個 head 有沒有開著的 PR,有就回傳它並把 created 設為 false,然後照樣停錶—— 那一步可能正是上次中斷的地方。先前重跑會撞上 Gitea 的 422,而那個錯誤看不出 PR 其實已經開好。 停錶的 500 改為只在訊息確實提到 stopwatch 時才視為「本來就沒在跑」,免得把真的伺服器錯誤 吞掉;未經證實的 409 那一支拿掉。測試結果的空話檢查改成整段每一行都是空話才擋,段落也改用 行首標題切,描述裡引用到「## 測試結果」這幾個字不會再讓檢查看錯地方。
「路徑不是 repo 就報 NOT_A_GIT_REPO」加上「把 cwd 綁進 runGit」原本在 branch-prep 與 commit-split 各寫一份。錯誤碼要一致,而這件事寫第三遍就該收起來了。
commit 訊息與 PR 描述裡出現 --flag 是常態,而原本的檢查對兩種寫法一視同仁:值只要以 -- 開頭就報「需要一個值」。空格分隔的寫法確實分不出「值」與「打錯的 flag」,但等號寫法 沒有這個歧義,不該一起擋掉。 這是實際撞到的:拿 commit-split 提交它自己時,--body 的內容第一行就是「--repo 與 --issue-repo 的差別」,整個 commit 因此做不出來。空格寫法的錯誤訊息現在會指路到等號寫法。
說明 --repo 與 --issue-repo 的差別、--base 要明講不讓腳本猜、重跑不會開出第二顆 PR, 以及提交中途失敗時不要自己回捲歷史。
No dependencies set.
The note is not visible to the blocked user.
摘要
/sdlc-feat的第三段:工作包做完之後,變更被整理成讀得懂的 git 歷史,PR 開出來,碼錶停下。需求議題
#1 — tea-sdlc:以 tea 驅動 SDLC 全流程的跨平台指令組
工作包議題
#13 — 以 sdlc-feat 分批提交、開立 PR 並停錶
變更內容
新增
scripts/commit-split.js、scripts/pr-create.js,prompts/sdlc-feat.md加入第三段,scripts/lib.js增加openGitRepo並修正parseFlags。15 顆 commit:feat(commit-split)/test(分批提交)feat(pr-create)/test(pr-create)feat(sdlc-feat)/test(sdlc-feat-assets)fix(commit-split)/test(commit-split)fix(pr-create)/test(pr-create)refactor(lib)fix(lib)/test(script-contract)--key=value的值可以本身以--開頭test(sdlc-feat-assets)/docs(sdlc-feat)這 15 顆 commit 全部由本 PR 的
commit-split自己產生。設計重點
一件事。全部混成一顆「完成工作包」的巨大 commit,等於沒有歷史。
scripts/底下的改動是新功能還是修 bug 只有做的人知道,那一批吃
--type。這張對照表是純字串規則,表格驅動測試。
--files讓一次變更橫跨兩個功能時分兩次跑。腳本認得出類型,認不出「這兩個檔案算不算同一件事」。
pr-create只驗描述的形狀,不評價內容。 八段齊全、順序正確、「測試結果」不是整段空話——就這三件。這一關擋的是明顯沒跑過就交差,不是去評斷別人的測試寫得好不好。
解決的問題
Code review 抓出四個缺陷,都已修掉並各自補上回歸測試:
1. 停錶停到別人的議題上。
claim在工作包議題所在的 repo 起錶,而 PR 開在目標專案上——議題在需求的 repo,程式碼在
repos列的那幾個,兩者常常不同。原本用同一個--repo同時指 PR 與停錶,會去停一顆不相干的議題(或 404,而且是在 PR 已經建立之後才拋錯,重跑又會撞上重複的 PR),而自己的錶一直跑下去。新增
--issue-repo。2. 改名時舊檔的刪除被漏掉。
git diff --name-only預設偵測改名,只印目的地那一個路徑。實測:
git mv a b之後,a的刪除留在 index 沒被提交,而腳本回報ok: true,要下一次跑才會發現工作區不乾淨。加
--no-renames。3. 類型對照表只認
test/。 目標專案用tests/、spec/、__tests__/,或把user.test.js放在被測檔案旁邊,測試就會被併進feat那一批。4. 中途失敗不說做到哪裡。 某一批提交失敗時,前面已經建立的 commit 不會被回捲(那會
動到使用者的歷史,而那幾顆本身是好的),但錯誤原本沒說已經做了什麼,重跑前得自己去翻
git log。另外修掉一個 lib 的既有瑕疵:
parseFlags對--key=value與--key value套用同一條「值不得以
--開頭」檢查。等號寫法沒有這個歧義,而 commit 訊息與 PR 描述裡出現--flag是常態。這是拿
commit-split提交它自己時真的撞到的——--body的內容第一行就是「
--repo與--issue-repo的差別」,整顆 commit 因此做不出來。影響的功能
scripts/branch-prep.js改用lib.js的openGitRepo,行為不變(既有 28 個測試全過)。parseFlags的行為改變只放寬等號寫法;空格寫法仍然擋,錯誤訊息現在會指路到等號寫法。test/helpers/temp-repo.js的makeTempRepo補上git執行器,與帶遠端的版本對稱。/sdlc-feat三段到此完整:領取與開工準備、逐項實作、提交與開立 PR。已知的上游落差:議題 #1 的 story 38 說「PR 七段描述」,但列出的是八個名稱。本 PR 依
列表實作八段(
SECTIONS),正本也寫「固定八個段落」。#1 的措辭仍待修正,不在本工作包範圍。測試結果
在最新 master(
1c6fb8aa)之上實際執行npm test:master 既有 505,本分支新增 92。
commit-split的類型分類是表格驅動(15 種路徑各一例),分批界線、scope 規則、改名、中途失敗、
--files、--body各有覆蓋;git 的部分在臨時 repo 上跑真的 git。pr-create的八段各有「缺這一段就擋」的案例,空話清單逐項驗過,停錶的順序、跨 repo、冪等與「錶本來就沒在跑」也都釘住。
實機驗證:改名後工作區確實乾淨且
A+D都在同一顆 commit 裡;測試檔放在程式碼旁邊認得出來;中途失敗的訊息確實列出已建立的 commit。最強的一次驗證是本 PR 的 15 顆 commit
全部由
commit-split自己產生,而這份描述在送出前先通過了pr-create自己的八段檢查。🤖 Generated with Claude Code