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<> "$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 "$(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 }} - name: Commit and push run: | git add -A if ! git diff --cached --quiet; then git commit -m "fix: resolve conflicts and review comments" git push else echo "No changes to commit" 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 }}