takt/.github/workflows/cc-resolve.yml

314 lines
13 KiB
YAML
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: CC Resolve
on:
issue_comment:
types: [created]
jobs:
resolve:
# Uncomment to allow organization members or collaborators:
# || github.event.comment.author_association == 'MEMBER'
# || github.event.comment.author_association == 'COLLABORATOR'
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '/resolve') &&
github.event.comment.author_association == 'OWNER'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Acknowledge
run: |
gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
-f content=rocket
gh pr comment ${{ github.event.issue.number }} --repo ${{ github.repository }} \
--body "🚀 cc-resolve started: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check if fork PR
id: pr
run: |
PR_REPO=$(gh pr view ${{ github.event.issue.number }} --repo ${{ github.repository }} \
--json headRepositoryOwner,headRepository \
--jq '"\(.headRepositoryOwner.login)/\(.headRepository.name)"')
BRANCH=$(gh pr view ${{ github.event.issue.number }} --repo ${{ github.repository }} \
--json headRefName -q .headRefName)
echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
if [ "$PR_REPO" != "${{ github.repository }}" ]; then
echo "::error::Fork PR はサポートしていません。contributor 側で解決してください。"
exit 1
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v4
with:
ref: ${{ steps.pr.outputs.branch }}
fetch-depth: 0
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Merge main (detect conflicts)
id: merge
run: |
git fetch origin main
if git merge origin/main --no-edit 2>/dev/null; then
echo "conflicts=false" >> "$GITHUB_OUTPUT"
else
echo "conflicts=true" >> "$GITHUB_OUTPUT"
fi
- name: Collect PR review comments
id: reviews
run: |
PR_NUMBER=${{ github.event.issue.number }}
COMMENTS=$(gh pr view "$PR_NUMBER" --json comments -q '.comments[].body' 2>/dev/null || echo "")
REVIEWS=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/reviews" --jq '.[].body' 2>/dev/null || echo "")
REVIEW_COMMENTS=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/comments" --jq '.[] | "**\(.path):\(.line // .original_line)** \(.body)"' 2>/dev/null || echo "")
{
echo "review_context<<REVIEW_EOF"
if [ -n "$REVIEWS" ]; then
echo "## PR Reviews"
echo "$REVIEWS"
fi
if [ -n "$REVIEW_COMMENTS" ]; then
echo "## PR Review Comments (inline)"
echo "$REVIEW_COMMENTS"
fi
if [ -n "$COMMENTS" ]; then
echo "## PR Comments"
echo "$COMMENTS"
fi
echo "REVIEW_EOF"
} >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Resolve
run: |
claude -p --dangerously-skip-permissions "$(cat <<'PROMPT'
このPRのコンフリクトおよびレビュー指摘を解決してください。
## 状況判定
まず現在の状態を確認してください。
1. `git status` でコンフリクトの有無を確認
2. コンフリクトがあれば「コンフリクト解決」を実行
3. PRのレビューコメントがあれば「レビュー指摘対応」を実行
4. 両方あれば、コンフリクト解決を先に行い、その後レビュー指摘に対応
---
## コンフリクト解決
Git merge/rebase/cherry-pick のコンフリクトを、差分分析に基づいて解決する。
**原則: 差分を読み、疑い、判断根拠を書いてから解決する。妄信的に片方を採用しない。**
### 1. コンフリクト状態を確認する
```bash
git status
```
- `Unmerged paths` がなければ「コンフリクトなし」と報告してスキップ
- merge / rebase / cherry-pick のどれが進行中か特定する
- `.git/MERGE_HEAD` があれば merge
- `.git/rebase-merge/` があれば rebase
- `.git/CHERRY_PICK_HEAD` があれば cherry-pick
### 2. コンテキストを把握する
以下を**並列で**実行:
- `git log --oneline HEAD -5` で HEAD 側(現在のブランチ)の最近の変更を確認
- `git log --oneline MERGE_HEAD -5` で取り込み側の最近の変更を確認merge の場合)
- 両ブランチの関係性(どちらがベースでどちらが新しいか)を理解する
### 3. コンフリクトファイルを列挙する
```bash
git diff --name-only --diff-filter=U
```
ファイル数と種類(ソースコード / 設定ファイル / ロックファイル等)を報告する。
### 4. 各ファイルを分析する
**ここが核心。ファイルごとに以下を必ず実行する。省略しない。**
1. ファイル全体を読む(コンフリクトマーカー付きの状態)
2. 各コンフリクトブロック(`<<<<<<<` 〜 `>>>>>>>`)について:
- HEAD 側の内容を具体的に読む
- theirs 側の内容を具体的に読む
- 差分が何を意味するか分析する(バージョン番号?リファクタ?機能追加?型変更?)
- 判断に迷う場合は `git log --oneline -- {file}` で変更履歴を確認する
3. **判断を書く**(以下の形式で必ず出力すること):
```markdown
### ファイル: path/to/file.ts
#### コンフリクト 1 (L30-45)
- HEAD 側: {具体的な内容を書く}
- theirs 側: {具体的な内容を書く}
- 分析: {差分が何を意味するか}
- 判断: {HEAD / theirs / 両方統合} を採用({理由}
```
**疑うべきポイント:**
- 「〇〇側が新しいから」だけで判断していないか? HEAD 側に独自の意図ある変更はないか?
- theirs を採用すると、HEAD 側でしか行っていない作業が消えないか?
- 両方の変更を統合すべきケースではないか?
- package-lock.json のような機械生成ファイルでも、バージョンの意味を確認したか?
### 5. 解決を実施する
ステップ4の分析結果に基づいて解決する:
- 片方採用が明確な場合: `git checkout --ours {file}` / `git checkout --theirs {file}` を使ってよい(**分析済みファイルのみ**
- 両方の変更を統合する場合: コンフリクトマーカーを除去し、両方の内容を適切に結合する
- 解決したファイルを `git add {file}` でマークする
解決後、`<<<<<<<` を検索し、マーカーの取り残しがないか確認する。
---
## レビュー指摘対応
PRのレビューコメントを分析し、コンフリクト解決と同じ原則で対応する。
**原則: 指摘を読み、コードを確認し、判断根拠を書いてから修正する。盲従しない。**
### 1. レビューコメントを収集する
`gh pr view` や `gh api` でPRのレビューコメントを取得し、全指摘を列挙する。
### 2. 各指摘を分析する
**指摘ごとに以下を必ず実行する。省略しない。**
1. 指摘箇所のコードを実際に読む
2. 指摘の意図を理解する
3. 現状コードが指摘通りに問題があるか分析する
4. **判断を書く**(以下の形式で必ず出力すること):
```markdown
### 指摘: {レビューコメントの要約}
- 指摘箇所: {ファイル:行}
- 現状コード: {具体的な内容}
- 指摘の意図: {何を改善すべきか}
- 判断: {修正 / 部分修正 / 反論}{理由}
```
**疑うべきポイント:**
- 指摘が的外れではないか? コンテキストを見落としていないか?
- 修正すると他の箇所に影響しないか?
- 指摘の通りに修正するのがベストか、別のアプローチの方が良くないか?
### 3. 修正を実施する
判断に基づいて修正する:
- 修正: 指摘が妥当 → コードを修正
- 部分修正: 一部妥当 → 妥当な部分のみ修正
- 反論: 指摘が不適切 → 理由を明記してスキップ
---
## 波及影響確認(共通)
**コンフリクト解決・指摘修正だけでは終わらない。** 対象外ファイルにも影響が出ていないか検証する。
- ビルド確認(`npm run build`、`./gradlew build` 等、プロジェクトに応じて)
- テスト確認(`npm test`、`./gradlew test` 等)
- 対象外ファイルが、変更と矛盾していないか確認する
- 例: 関数シグネチャを変更したのに、テストが旧シグネチャを期待している
- 例: import パスを変更したのに、別ファイルが旧パスを参照している
問題が見つかった場合はここで修正する。
---
## 結果を報告する
全ファイルの解決結果をサマリーテーブルで報告する:
```markdown
## 解決サマリー
### コンフリクト解決
| ファイル | コンフリクト数 | 採用 | 理由 |
|---------|-------------|------|------|
| path/to/file.ts | 2 | theirs | リファクタリング済み |
### レビュー指摘対応
| 指摘 | 判断 | 理由 |
|------|------|------|
| {指摘要約} | 修正/反論 | {理由} |
波及修正: {対象外ファイルの修正内容。なければ「なし」}
ビルド: OK / NG
テスト: OK / NG ({passed}/{total})
```
---
## 絶対原則
- **差分を読まずに解決しない。** ファイルの中身を確認せずに `--ours` / `--theirs` を適用しない
- **盲従しない。** HEAD 側に独自の意図がないか必ず疑う。レビュー指摘も鵜呑みにしない
- **判断根拠を省略しない。** 各コンフリクト・各指摘に「何が・なぜ・どちらを」の3点を書く
- **波及を確認する。** 対象外ファイルもビルド・テストで検証する
## 禁止事項
- 分析なしで `git checkout --ours .` / `git checkout --theirs .` を実行しない
- 「とりあえず片方」で全ファイルを一括解決しない
- コンフリクトマーカー (`<<<<<<<`) が残ったままにしない
- `git merge --abort` を実行しない
PROMPT
)" --verbose
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit and push
run: |
git add -A
if ! git diff --cached --quiet; then
git commit -m "fix: resolve conflicts and review comments"
fi
AHEAD=$(git rev-list --count origin/${{ steps.pr.outputs.branch }}..HEAD 2>/dev/null || echo "0")
if [ "$AHEAD" -gt 0 ]; then
echo "Pushing $AHEAD commit(s)"
git push
else
echo "Nothing to push"
fi
- name: Report result
if: always()
run: |
PR_NUMBER=${{ github.event.issue.number }}
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
if [ "${{ job.status }}" = "success" ]; then
gh pr comment "$PR_NUMBER" --repo ${{ github.repository }} --body "✅ cc-resolve completed. [View logs](${RUN_URL})"
else
gh pr comment "$PR_NUMBER" --repo ${{ github.repository }} --body "❌ cc-resolve failed. [View logs](${RUN_URL})"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}