diff --git a/.github/workflows/claude-code-followup.yml b/.github/workflows/claude-code-followup.yml new file mode 100644 index 0000000000..e0eeab9f51 --- /dev/null +++ b/.github/workflows/claude-code-followup.yml @@ -0,0 +1,90 @@ +name: Code Review Followup + +on: + issue_comment: + types: [created] + +jobs: + code-followup: + if: >- + github.event.issue.pull_request && + contains(github.event.comment.body, '@claude') && + github.event.comment.user.type != 'Bot' && + contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) + concurrency: + group: code-followup-${{ github.event.issue.number }} + cancel-in-progress: false + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + issues: write + steps: + - name: Get PR info + id: pr-info + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER="${{ github.event.issue.number }}" + PR_DATA=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json headRefName,baseRefName,isCrossRepository,headRefOid) + BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') + echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" + echo "branch=$(echo "$PR_DATA" | jq -r '.headRefName')" >> "$GITHUB_OUTPUT" + echo "sha=$(echo "$PR_DATA" | jq -r '.headRefOid')" >> "$GITHUB_OUTPUT" + echo "is_fork=$(echo "$PR_DATA" | jq -r '.isCrossRepository')" >> "$GITHUB_OUTPUT" + if [ "$BASE_BRANCH" = "dev" ]; then + echo "targets_dev=true" >> "$GITHUB_OUTPUT" + else + echo "targets_dev=false" >> "$GITHUB_OUTPUT" + fi + + - name: Post fork notice + if: steps.pr-info.outputs.is_fork == 'true' && steps.pr-info.outputs.targets_dev == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr comment ${{ steps.pr-info.outputs.number }} --repo ${{ github.repository }} \ + --body "This PR is from a fork. I can suggest changes but cannot push fixes directly." + + - name: React with eyes + if: steps.pr-info.outputs.is_fork == 'false' && steps.pr-info.outputs.targets_dev == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \ + --method POST -f content="eyes" + + - name: Checkout base repository + if: steps.pr-info.outputs.is_fork == 'false' && steps.pr-info.outputs.targets_dev == 'true' + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + token: ${{ secrets.VALE_TOKEN }} + fetch-depth: 0 + + - name: Switch to PR branch + if: steps.pr-info.outputs.is_fork == 'false' && steps.pr-info.outputs.targets_dev == 'true' + env: + BRANCH: ${{ steps.pr-info.outputs.branch }} + SHA: ${{ steps.pr-info.outputs.sha }} + run: | + git fetch origin "$BRANCH" + git checkout -B "$BRANCH" "$SHA" + + - name: Handle @claude request + if: steps.pr-info.outputs.is_fork == 'false' && steps.pr-info.outputs.targets_dev == 'true' + uses: anthropics/claude-code-action@24492741e0ccfdef4c1d19da8e11e0f373d07494 # v1 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + github_token: ${{ secrets.GITHUB_TOKEN }} + show_full_output: true + prompt: | + A contributor has tagged @claude on PR #${{ steps.pr-info.outputs.number }} in ${{ github.repository }}. + + Their request: ${{ github.event.comment.body }} + + Read the PR diff, understand the change, and fulfill the request. You can read and edit + files, run git commands, and push commits to the branch. If asked to fix something, + apply the fix and commit it. If asked a question, answer it as a PR comment. + claude_args: '--max-turns 50 --allowedTools "Bash(gh:*),Bash(git:*),Read,Write,Edit,Glob,Grep"' diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 0000000000..e4407975d6 --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,63 @@ +name: Code Review + +on: + pull_request: + types: [opened, synchronize] + branches: + - dev + paths-ignore: + - 'docs/**/*.md' + - 'docs/kb/**' + - 'static/**' + +jobs: + code-review: + if: github.event.pull_request.head.repo.fork == false + concurrency: + group: code-review-${{ github.event.pull_request.number }} + cancel-in-progress: true + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: write + steps: + - name: Checkout repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 1 + + - name: Delete previous bot review comments + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=${{ github.event.pull_request.number }} + COMMENT_IDS=$(gh api repos/${{ github.repository }}/issues/${PR_NUMBER}/comments --paginate \ + --jq '[.[] | select(.user.login == "github-actions[bot]" and (.body | startswith("## Code Review"))) | .id] | .[]' 2>/dev/null || true) + for ID in $COMMENT_IDS; do + gh api repos/${{ github.repository }}/issues/comments/${ID} -X DELETE 2>/dev/null || true + done + + - name: Run code review + uses: anthropics/claude-code-action@24492741e0ccfdef4c1d19da8e11e0f373d07494 # v1 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + github_token: ${{ secrets.GITHUB_TOKEN }} + show_full_output: true + prompt: | + Review this PR for correctness issues. Focus on: + - Bugs, broken logic, or unintended side effects + - Security issues (injection, exposed secrets, unsafe eval, etc.) + - Docusaurus config changes that could break the build or routing (products.js, docusaurus.config.js, sidebars) + - Script changes that could break the KB copy pipeline or build process + - GitHub Actions workflow changes — correct triggers, permissions, and secret usage + + Do NOT review documentation content or style — a separate workflow handles that. + + Use `gh pr diff ${{ github.event.pull_request.number }}` to read the diff. + Post your findings as a single PR comment starting with "## Code Review". + If there are no issues, say so briefly. + claude_args: '--allowedTools "Bash(gh:*),Read,Glob,Grep"'