Issue Analyze
分析 GitLab Issue 的影響範圍。跨 30+ 子專案搜尋相關程式碼與 MR,產生結構化影響評估報告。Phase 1 為「觀察者模式」,只產生報告不建 MR。
使用方式
/issue-analyze #123 /issue-analyze --project=backend #45 /issue-analyze https://gitlab.example.com/BizForm/Home/-/issues/123 /issue-analyze #123 --scope=bizform-web,backend,elsa-server /issue-analyze #123 --depth=shallow /issue-analyze #123 --write-back
參數說明
| 參數 | 必要 | 說明 |
|---|---|---|
#IID 或 URL | 是 | 目標 Issue |
--project | 否 | 專案 key(預設 defaultProjectPath) |
--scope | 否 | 限定搜尋的子專案(逗號分隔 key),預設使用智慧選取 |
--depth | 否 | shallow(僅搜尋 repo tree)/ deep(含檔案內容,預設) |
--write-back | 否 | 將報告寫回 Issue 描述底部 |
前置條件
需要 .issue-config.json 存在。按以下優先順序搜尋:
- •專案目錄:
./.issue-config.json - •使用者目錄:
~/.claude/.issue-config.json
若均不存在,提示:「找不到 .issue-config.json,請先執行 /issue-init 建立設定。」
工作流程
Step 1: 前置檢查與設定讀取
從搜尋到的 .issue-config.json 讀取(專案層級優先於使用者層級):
- •
gitlab.projects— 所有可搜尋的子專案清單 - •
gitlab.defaultProjectPath/defaultProjectId - •
analyze設定區塊(搜尋深度、安全策略、專案領域映射等)
檢查邏輯:
- •
.issue-config.json不存在 → 提示執行/issue-init - •解析
--project參數 → 映射到projects[key]取得 projectId / projectPath - •若有
analyze.securityPolicy,初始化安全過濾器
Step 2: 取得 Issue 完整資訊
三個呼叫可並行:
- •
mcp__GitLab_communication_server__get_issue— 取得 Issue 詳細內容 - •
mcp__GitLab_communication_server__list_issue_discussions— 取得所有討論串 - •
mcp__GitLab_communication_server__list_issue_links— 取得關聯 Issue
AI 語義萃取: 從 title、description、discussions、labels 中萃取:
- •技術關鍵字 — API 名稱、元件名稱、資料庫表名、函式名
- •模組關鍵字 — 前端/後端/workflow/表單/通知等模組標示
- •檔案線索 — 描述中直接提及的檔案路徑或類名
- •領域關鍵字 — 業務術語(如「計算欄位」「子表單」「簽核」)
顯示進度:
📋 Issue #123: [Bug] 計算欄位在子表單中顯示 NaN Labels: bug, frontend 討論數: 3 萃取關鍵字: 計算欄位, SubForm, NaN, CalculationEngine
Step 3: 智慧範圍選取 — 三層漏斗策略
Layer 1: 領域分類器(0 API 呼叫,純推理)
使用 config 中 analyze.projectDomains 的靜態映射表,將關鍵字比對到專案領域標籤。
映射邏輯範例:
| 關鍵字類型 | 關鍵字範例 | 映射到專案 |
|---|---|---|
| 前端 UI | 表單元件、CSS、Vue、React | bizform-web, formeditor |
| 後端 API | Controller、API、Swagger | backend |
| Workflow | 簽核、Elsa、流程 | elsa-server, elsa-client |
若使用者用 --scope 明確指定,跳過 Layer 1。
→ 選出 5-8 個候選專案
Layer 2: Repo Tree 快速掃描(5-8 次 API 呼叫,可並行)
對候選專案使用 mcp__GitLab_communication_server__get_repository_tree(recursive 必須為 boolean 值 true)。
AI 根據檔案結構判斷:
- •是否有相關的目錄/檔案路徑
- •過濾掉不相關的專案
安全過濾: 所有路徑必須通過安全檢查:
- •路徑是否匹配
securityPolicy.blockedPaths→ 跳過 - •副檔名是否在
securityPolicy.allowedExtensions→ 否則跳過 - •專案是否在
securityPolicy.blockedProjects→ 跳過整個專案
→ 確認 3-5 個相關專案 + 各專案可能相關的檔案路徑
Layer 3: 檔案內容深度搜尋(僅 depth=deep 時)
使用 mcp__GitLab_communication_server__get_file_contents 讀取相關檔案。
限制:
- •每個專案最多讀取
analyze.maxFilesPerRepo(預設 10)個檔案 - •優先讀取控制器、服務層、元件入口等關鍵檔案
- •跳過測試檔案(除非 Issue 明確涉及測試)
Step 4: 搜尋相關 MR
對每個相關專案(可並行):
- •
mcp__GitLab_communication_server__list_merge_requests— search 已合併 MR(state="merged") - •
mcp__GitLab_communication_server__list_merge_requests— search 開放中 MR(state="opened")
搜尋關鍵字策略:
- •Issue title 核心詞(去除 [Bug]/[Feature] prefix)
- •Issue IID(搜尋 MR 描述中提到 #123 的)
- •技術關鍵字擴展(若結果不足)
每專案最多取 analyze.maxMRsPerRepo(預設 10)個 MR。
對最相關的 MR(最多 analyze.maxDiffMRs,預設 5 個),取得 diff:
- •
mcp__GitLab_communication_server__get_merge_request_diffs
從 diff 萃取:修改檔案、新增/刪除行數、修改的函式/類名。
Step 5: 影響分析與信心度計算
5a. 影響檔案相關性分數
| 分數來源 | 權重 |
|---|---|
| Issue 描述中直接提及的檔案 | +40 |
| MR diff 中修改過的檔案 | +30 |
| Repo Tree 中目錄名稱匹配 | +15 |
| 檔案內容中包含關鍵字 | +10 |
| 關聯 Issue 提及的檔案 | +5 |
5b. 信心度分級系統
| 等級 | 分數 | 含義 |
|---|---|---|
| HIGH | 80-100 | 影響範圍明確,建議可直接採用 |
| MEDIUM | 50-79 | 影響範圍大致正確,建議人工複查 |
| LOW | 20-49 | 資訊不足,僅供參考 |
| INSUFFICIENT | 0-19 | 無法有效分析,建議補充 Issue 描述 |
信心度因子加權:
- •Issue 描述品質 (30%)
- •程式碼匹配度 (25%)
- •MR 佐證 (25%)
- •跨專案一致性 (10%)
- •討論串資訊 (10%)
5c. 複雜度預估
- •
S— 1-2 檔案,單專案 - •
M— 3-5 檔案或跨 2 專案 - •
L— 6-10 檔案或跨 3+ 專案 - •
XL— 10+ 檔案或核心模組變更
Step 6: 產生分析報告
報告以 Markdown 格式輸出到終端機,包含:
- •摘要表格(Issue、類型、信心度、複雜度)
- •影響檔案清單(按專案分組,含相關性分數與說明)
- •相關 MR 清單(MR ID、專案、狀態、相關性)
- •建議修改方向(主要修改點、連帶修改、驗證點)
- •風險與注意事項
- •安全過濾記錄(被排除的檔案/專案)
- •分析方法說明(搜尋的專案、關鍵字、API 呼叫統計)
完整報告格式範例
---
## 🔍 Issue 影響分析報告
> 由 Claude Code `/issue-analyze` 自動產生 | {timestamp}
> [信心度: {LEVEL} ({score}/100)] | [複雜度: {S/M/L/XL}]
### 摘要
| 項目 | 值 |
|------|-----|
| Issue | #{iid} - {title} |
| 類型 | {Bug/Feature} |
| 影響專案 | {project1}, {project2} |
| 影響檔案 | {N} 個 |
| 相關 MR | {N} 個 ({merged} merged, {opened} open) |
| 預估複雜度 | {S/M/L/XL} |
### 影響檔案
#### {project-name} ({N} 檔案)
| 檔案 | 相關性 | 說明 |
|------|--------|------|
| `{path}` | {score}/100 | {description} |
### 相關 MR
| MR | 專案 | 狀態 | 相關性 |
|----|------|------|--------|
| !{iid} - {title} | {project} | {merged/open} | {description} |
### 建議修改方向
1. **主要修改點**: {description}
2. **連帶修改**: {description}
3. **驗證點**: {description}
### 風險與注意事項
- {risk items}
### 安全過濾記錄
{filtered items or "無被過濾的項目"}
### 分析方法
- 搜尋專案: {list}
- 搜尋關鍵字: {keywords}
- Layer 1 排除: {N} 個不相關專案
- Repo Tree 掃描: {N} 個專案
- 檔案內容讀取: {N} 個檔案
- MR 搜尋: {N} 個專案, 找到 {N} 個相關 MR
精簡版(用於 write-back 的摘要選項)
---
## 🔍 Issue 影響分析摘要
> [信心度: {LEVEL}] | [複雜度: {S/M/L/XL}] | {date} by Claude Code
**影響檔案 ({N})**:
- `{project}`: {file1}, {file2}
**相關 MR**: !{iid} ({state}), ...
**建議方向**: {summary}
---
Step 7: (可選) 寫回 Issue
分析報告完成後,使用 AskUserQuestion 詢問:
- •問題:「是否將分析報告寫回 Issue #{iid} 的討論串?」
- •選項:
- •確認,寫回完整報告(含折疊區塊)
- •只寫摘要(精簡版)
- •取消
寫回方式 — 使用 GraphQL createNote mutation:
mutation CreateNote($noteableId: NoteableID!, $body: String!) {
createNote(input: {
noteableId: $noteableId
body: $body
}) {
note { id body url createdAt }
errors
}
}
變數:
- •
noteableId:gid://gitlab/Issue/{issue_id}(注意:使用get_issue回傳的id欄位,非iid) - •
body: 報告內容,使用<details>HTML 標籤包裝為可折疊區塊
報告格式(折疊版):
<details>
<summary>
## 🔍 Issue 影響分析報告
> 信心度: **{LEVEL} ({score}/100)** | 複雜度: **{S/M/L/XL}** | {date} by Claude Code `/issue-analyze`
</summary>
{完整報告內容...}
</details>
---
*由 Claude Code `/issue-analyze` 自動產生 — [Phase 1 觀察者模式]*
注意:
- •不使用
create_issue_note(有 404 "Discussion Not Found" bug) - •不使用
update_issue修改描述(會污染原始描述) - •GraphQL
createNote建立獨立 comment,不影響原始 Issue 內容
Step 8: 完成訊息
✓ Issue #{iid} 影響分析完成
信心度: {LEVEL} ({score}/100)
複雜度: {S/M/L/XL} ({N} 檔案, {N} 專案)
影響範圍:
- {project}: {N} 檔案 ({file list})
相關 MR: {N} 個 ({merged} merged, {open} open)
建議修改方向: {summary}
報告已寫回 Issue: {是/否}
GitLab MCP 工具使用
| Step | 工具 | 用途 | 可並行 |
|---|---|---|---|
| 2 | get_issue | 取得 Issue 詳細內容 | 是 (2a-2c) |
| 2 | list_issue_discussions | 取得討論串 | 是 |
| 2 | list_issue_links | 取得關聯 Issue | 是 |
| 3 | get_repository_tree | 掃描 repo 檔案結構 | 是 (5-8 並行) |
| 3 | get_file_contents | 讀取檔案內容 | 批次 (最多 30) |
| 4 | list_merge_requests | 搜尋相關 MR | 是 (每專案並行) |
| 4 | get_merge_request_diffs | 取得 MR diff | 是 (最多 5 並行) |
| 7 | get_issue | 取得 Issue 全域 ID(寫回用) | - |
| 7 | execute_graphql | GraphQL createNote 建立 comment | - |
安全機制
Phase 1 觀察者模式硬性限制
| 允許 | 禁止 |
|---|---|
| 讀取 Issue / 討論 / 關聯 | 建立/刪除 Issue |
| 讀取 repo 檔案結構和內容 | 任何 git push / MR 建立 |
| 搜尋 MR 和 diff | 任何 MR 操作(approve, merge) |
| 寫回分析報告到 Issue 討論串(comment) | 修改 Issue 的 labels/assignee/state |
路徑安全過濾
- •
blockedPaths: 禁止讀取的路徑 glob(.env、secrets、CI/CD 等) - •
blockedProjects: 禁止搜尋的專案(infra、deploy 等) - •
allowedExtensions: 只允許的副檔名白名單(.cs、.ts、.tsx、.js 等)
效能預估
| 模式 | API 呼叫數 | 預估耗時 |
|---|---|---|
| shallow | 15-25 | 10-15 秒 |
| deep(預設) | 25-58 | 20-40 秒 |
注意事項
- •
get_repository_tree的recursive參數必須傳 boolean true,不能傳字串 "true" - •
create_issue_note有 404 bug("Discussion Not Found"),寫回改用 GraphQLcreateNotemutation - •寫回 Issue 時,使用
<details>折疊區塊包裝報告,避免佔據版面 - •GraphQL
noteableId使用gid://gitlab/Issue/{id}格式,id來自get_issue回傳的id欄位(非iid) - •大量 API 呼叫時注意 GitLab rate limit(300 req/min)
- •報告末尾加入來源標註「由 Claude Code /issue-analyze 自動產生」