--- name: spec-pull-request description: JSC plugins 共用「PR 建立流程」:目標分支不得臆測(明確得知或詢問使用者)、解析 origin 座標決定 owner/repo(host 依 spec-gitea 主機決定順序)、full 與 simple 兩種 PR 描述模式、`POST /pulls` 的 body 以 UTF-8 檔案帶入(不可字面 `\n`)、已有相同 head→base 的 open PR 時沿用不重開、API 失敗遮蔽 token、完成後提醒清除對話內文。當其他 skill 內文引用 spec-pull-request 或 /jsc-shared:spec-pull-request、或需要透過 Gitea API 建立 PR 時載入此 skill。單獨被使用者呼叫時,直接說明本規範內容。 --- # spec-pull-request — 共用 PR 建立流程 所有 JSC skills 需要透過 Gitea API 開 Pull Request(例如 `review-resolve` 依議題/findings 修復後發 PR、`target` 每日待辦完成後對預設分支發 PR)時,一律遵守以下規範。本 spec 只講 PR 流程本身;token 機密保護與遮蔽規則一律引用 `/jsc-shared:spec-gitea`,不在此重複。 ## 目標分支不得臆測 - 目標分支必須是**明確得知**(呼叫端參數帶入、或流程中已確認的遠端預設分支)或**詢問使用者**取得,**嚴禁猜測或預設**(不可自行假設 `develop`/`main`/`master`)。 - 若呼叫端有「遠端預設分支」這類已判定好的來源(如 `git symbolic-ref refs/remotes/origin/HEAD`),可直接採用視為「明確得知」,不需再問;沒有把握時一律停下詢問,可用 `git branch -r` 列出分支輔助使用者選擇。 - 目標分支一旦確定,後續建立 PR、查詢既有 PR 都以同一個值為準,不可中途換掉。 ## 解析 origin 座標(host/owner/repo) PR 相關的 API 呼叫都建立在 `/` 這個座標上,一律從 `git remote get-url origin` 解析: ```bash git remote get-url origin # 例:https://gitea.jsc.idv.tw/plugins/code-review.git # → host=gitea.jsc.idv.tw、owner=plugins、repo=code-review ``` - host 的決定順序(`--host` 參數/`$GITEA_HOST`/origin 所在主機/詢問使用者)是唯一權威流程,一律引用 `/jsc-shared:spec-gitea` 的「gitea 主機決定順序」,不在此另行複述或改動順序。 - 解析失敗(origin 不是 Gitea 網址、或無法拆出 owner/repo)→ 回報並停止,不猜測替代座標。 ## 已有相同 head→base 的 open PR 時沿用不重開 **每次開 PR 前必須先查**,不可直接送出建立請求造成重複 PR: ```bash curl -sS -H "Authorization: token ${GITEA_TOKEN}" \ "https:///api/v1/repos///pulls?state=open&base=<目標分支>" ``` - API 只能用 `base` 篩選,**head 需要在回應中自行比對**:分頁完整讀取(依 `/jsc-shared:spec-gitea` 的分頁慣例),逐筆檢查 `head.ref`(或對等欄位)是否等於本次 PR 的來源分支。 - 找到 `head=<來源分支>` → `base=<目標分支>` 的 open PR → **沿用它**,不重複建立: - 回報既有 PR 的連結/編號給使用者。 - 本次新推的 commit 會自動出現在該 PR 上;視情境需要可在該 PR 補一則本次進度留言,但**不再呼叫 `POST /pulls`**。 - 沒找到才進入下一節建立新 PR。 ## PR 描述模式(`full` / `simple`) 呼叫端依需求二選一,未指定時預設 `full`,**不要為描述形式中斷詢問**: | 模式 | 內容 | 產生方式 | | --- | --- | --- | | `full`(完整版) | 結構化繁體中文說明——變更摘要、影響範圍、重點檔案/模組、風險或注意事項 | **重新分析並總結** `git diff <目標分支>...`(比對來源分支自分岔點以來的變更),不是貼原始 diff,而是「人讀得懂的總結」 | | `simple`(簡單版) | 逐條列出本分支領先目標分支的 commit 訊息 | `git log --oneline "<目標分支>.."`,以條列呈現每行 commit 訊息 | - 呼叫端也可直接提供自訂描述文字取代以上兩種模式;此時原樣採用,不再套用 `full`/`simple` 的產生方式。 - **標題**預設取一句總結(可用首個 `feat`/`fix` commit 訊息或分支用途);呼叫端若有更貼合情境的固定命名規則(例如含日期的前綴),可自行覆寫此預設。 ## 建立 PR:body 一律用 UTF-8 檔案帶入 `POST /pulls` 的 body **必須**以 UTF-8 檔案帶入,換行用**實際換行**,不可送出字面 `\n`(例如讓 PR 顯示成 `## Commit\n\n- ...` 這種未展開的跳脫字串): ```bash # body.json 先以 UTF-8 檔案(heredoc/printf/程式寫檔)準備好,換行是實際換行 curl -sS -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ "https:///api/v1/repos///pulls" \ --data @body.json ``` - 不可用 shell 字面 `"標題\n內容"` 這種寫法組 body;若用 `jq` 組 JSON,改用 `jq --rawfile` 或等效方式帶入多行內容。 - **成功**:取回應中的 PR 連結/編號回報使用者。 - **失敗**:顯示 API 回應的錯誤訊息供排查,**先依 `/jsc-shared:spec-gitea` 的機密遮蔽規則遮蔽 token** 才能輸出。常見錯誤: - 目標分支不存在。 - 已有相同 head→base 的 open PR(回到上一節查詢並沿用,不當作失敗處理)。 - token 權限不足(401/403)。 ## 完成後提醒清除對話內文 push/API 呼叫過程可能讓 token 殘留在對話內文,PR 建立完成後: 1. 通知使用者:PR 連結/編號、目標分支、採用的描述形式(`full`/`simple`/自訂)。 2. 提醒清除對話內文以防 token 外洩(互動情境用 Claude Code `/clear` 或當前助理對等指令;排程情境只寫 log、不輸出 token)。 3. 清除前再次確認輸出與 log 中沒有明文 token——細節與遮蔽規則一律依 `/jsc-shared:spec-gitea`,本 spec 不重複。