feat: livekit cast improvements #3865
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Claude Review | |
| on: | |
| workflow_dispatch: | |
| issue_comment: | |
| types: [created] | |
| pull_request_review_comment: | |
| types: [created] | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review] | |
| jobs: | |
| auto-review: | |
| if: | | |
| github.event_name == 'pull_request' && | |
| github.event.pull_request.draft == false && | |
| !contains(github.event.pull_request.labels.*.name, 'no review') && | |
| !contains(github.event.pull_request.labels.*.name, 'auto-pr') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| statuses: write | |
| steps: | |
| - name: Check PR type | |
| id: check-type | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const title = context.payload.pull_request.title || ''; | |
| const isAutoReview = /^(fix|chore)(\(.*?\))?!?:/i.test(title); | |
| core.setOutput('is-auto-review', isAutoReview.toString()); | |
| - name: Set status to pending | |
| if: steps.check-type.outputs.is-auto-review == 'true' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.payload.pull_request.head.sha, | |
| state: 'pending', | |
| context: 'Claude Review', | |
| description: 'Claude auto-review in progress...' | |
| }); | |
| - name: Checkout repository | |
| if: steps.check-type.outputs.is-auto-review == 'true' | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| fetch-depth: 1 | |
| - name: Load review instructions | |
| if: steps.check-type.outputs.is-auto-review == 'true' | |
| id: prompt | |
| run: echo "instructions<<PROMPT_EOF" >> "$GITHUB_OUTPUT" && cat .github/prompts/review-instructions.md >> "$GITHUB_OUTPUT" && echo "PROMPT_EOF" >> "$GITHUB_OUTPUT" | |
| - name: Claude Review | |
| if: steps.check-type.outputs.is-auto-review == 'true' | |
| id: claude | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| track_progress: true | |
| prompt: | | |
| REPO: ${{ github.repository }} | |
| PR NUMBER: ${{ github.event.pull_request.number }} | |
| This is an automatic review for a fix / chore PR. Review the full PR diff. | |
| ${{ steps.prompt.outputs.instructions }} | |
| claude_args: | | |
| --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr review:*)" | |
| --max-turns 40 | |
| - name: Upload Claude execution output | |
| if: steps.check-type.outputs.is-auto-review == 'true' && always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: claude-execution-output-${{ github.event.pull_request.number }}-${{ github.run_attempt }} | |
| path: /home/runner/work/_temp/claude-execution-output.json | |
| if-no-files-found: warn | |
| retention-days: 30 | |
| - name: Set status and approve if eligible | |
| if: steps.check-type.outputs.is-auto-review == 'true' && always() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const prNumber = ${{ github.event.pull_request.number }}; | |
| const comments = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| per_page: 100 | |
| }); | |
| const claudeComment = comments.data | |
| .reverse() | |
| .find(c => c.user?.login === 'claude[bot]'); | |
| const output = claudeComment?.body ?? ''; | |
| console.log('Claude comment preview:', output.slice(0, 300)); | |
| const failed = output.includes('REVIEW_RESULT: FAIL'); | |
| const errored = '${{ steps.claude.outcome }}' === 'failure'; | |
| const isSimple = output.includes('COMPLEXITY: SIMPLE'); | |
| const qaRequired = !output.includes('QA_REQUIRED: NO'); | |
| const hasReviewResult = output.includes('REVIEW_RESULT:'); | |
| const passed = !failed && !errored; | |
| if (passed && isSimple) { | |
| const approvalBody = qaRequired | |
| ? 'Auto-approved by Claude — simple fix/chore with no blocking issues. QA approval is still required.' | |
| : 'Auto-approved by Claude — simple fix/chore with no blocking issues. No QA needed (non-runtime changes only).'; | |
| await github.rest.pulls.createReview({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: prNumber, | |
| event: 'APPROVE', | |
| body: approvalBody | |
| }); | |
| const labels = ['claude-approved']; | |
| if (!qaRequired) { | |
| labels.push('no QA needed'); | |
| } | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| labels | |
| }); | |
| } else if (passed && !isSimple) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: '🔍 Claude reviewed this PR and found no blocking issues, but assessed it as **complex** — human DEV review is still required before merging.' | |
| }); | |
| } | |
| let description; | |
| if (errored && !output) { | |
| description = 'Claude review failed — credit balance too low or API error'; | |
| } else if (errored && output && !hasReviewResult) { | |
| description = 'Claude review failed — reached maximum number of turns'; | |
| } else if (errored) { | |
| description = 'Claude review encountered an error'; | |
| } else if (failed) { | |
| description = 'Claude found issues that must be resolved'; | |
| } else if (isSimple) { | |
| description = 'No blocking issues found — PR auto-approved'; | |
| } else { | |
| description = 'No blocking issues — complex change, DEV review required'; | |
| } | |
| const state = (failed || errored) ? 'failure' : 'success'; | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: '${{ github.event.pull_request.head.sha }}', | |
| state, | |
| context: 'Claude Review', | |
| description | |
| }); | |
| - name: Re-run failed enforce-approvals check | |
| if: steps.check-type.outputs.is-auto-review == 'true' && always() | |
| env: | |
| GH_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} | |
| run: | | |
| SHA="${{ github.event.pull_request.head.sha }}" | |
| echo "Searching for failed enforce-approvals run for SHA $SHA..." | |
| WORKFLOW_RUN_ID=$(gh run list \ | |
| --workflow="Enforce QA and DEV Approvals" \ | |
| --limit 100 \ | |
| --repo "${{ github.repository }}" \ | |
| --json databaseId,event,headSha,conclusion \ | |
| | jq -r --arg SHA "$SHA" ' | |
| .[] | | |
| select(.event == "pull_request") | | |
| select(.headSha == $SHA) | | |
| select(.conclusion == "failure") | | |
| .databaseId | |
| ' | head -n 1) | |
| if [ -z "$WORKFLOW_RUN_ID" ]; then | |
| echo "No failed enforce-approvals run found for this commit." | |
| exit 0 | |
| fi | |
| echo "Re-running failed enforce-approvals workflow: $WORKFLOW_RUN_ID" | |
| gh run rerun "$WORKFLOW_RUN_ID" --repo "${{ github.repository }}" | |
| echo "Re-run triggered successfully." | |
| review: | |
| if: | | |
| github.event.issue.pull_request != null && | |
| ( | |
| contains(github.event.comment.body, '@claude review') || | |
| contains(github.event.comment.body, '@claude re-review') || | |
| contains(github.event.comment.body, '@claude approve') | |
| ) && | |
| !contains(github.event.issue.labels.*.name, 'no review') && | |
| !contains(github.event.issue.labels.*.name, 'auto-pr') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| statuses: write | |
| steps: | |
| - name: Get PR head SHA | |
| id: pr | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const pr = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number | |
| }); | |
| core.setOutput('sha', pr.data.head.sha); | |
| core.setOutput('is_draft', pr.data.draft); | |
| - name: Set status to pending | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: '${{ steps.pr.outputs.sha }}', | |
| state: 'pending', | |
| context: 'Claude Review', | |
| description: 'Claude review in progress...' | |
| }); | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.pr.outputs.sha }} | |
| fetch-depth: 1 | |
| - name: Load review instructions | |
| id: prompt | |
| run: echo "instructions<<PROMPT_EOF" >> "$GITHUB_OUTPUT" && cat .github/prompts/review-instructions.md >> "$GITHUB_OUTPUT" && echo "PROMPT_EOF" >> "$GITHUB_OUTPUT" | |
| - name: Claude Review | |
| id: claude | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| track_progress: true | |
| prompt: | | |
| REPO: ${{ github.repository }} | |
| PR NUMBER: ${{ github.event.issue.number }} | |
| TRIGGER: ${{ github.event.comment.body }} | |
| ${{ contains(github.event.comment.body, '@claude re-review') && | |
| 'A re-review has been requested. Focus on whether previously raised issues have been addressed. Check prior review comments on this PR before assessing the diff.' || | |
| 'A review has been requested. Review the full PR diff.' }} | |
| ${{ steps.prompt.outputs.instructions }} | |
| claude_args: | | |
| --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr review:*)" | |
| --max-turns 40 | |
| - name: Upload Claude execution output | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: claude-execution-output-${{ github.event.issue.number }}-${{ github.run_attempt }} | |
| path: /home/runner/work/_temp/claude-execution-output.json | |
| if-no-files-found: warn | |
| retention-days: 30 | |
| - name: Set final commit status | |
| if: always() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const comments = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: ${{ github.event.issue.number }}, | |
| per_page: 100 | |
| }); | |
| const claudeComment = comments.data | |
| .reverse() | |
| .find(c => c.user?.login === 'claude[bot]'); | |
| const output = claudeComment?.body ?? ''; | |
| console.log('Claude comment preview:', output.slice(0, 200)); | |
| const failed = output.includes('REVIEW_RESULT: FAIL'); | |
| const errored = '${{ steps.claude.outcome }}' === 'failure'; | |
| const hasReviewResult = output.includes('REVIEW_RESULT:'); | |
| let description; | |
| if (errored && !output) { | |
| description = 'Claude review failed — credit balance too low or API error'; | |
| } else if (errored && output && !hasReviewResult) { | |
| description = 'Claude review failed — reached maximum number of turns'; | |
| } else if (errored) { | |
| description = 'Claude review encountered an error'; | |
| } else if (failed) { | |
| description = 'Claude found issues that must be resolved'; | |
| } else { | |
| description = 'No blocking issues found'; | |
| } | |
| const state = (failed || errored) ? 'failure' : 'success'; | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: '${{ steps.pr.outputs.sha }}', | |
| state, | |
| context: 'Claude Review', | |
| description | |
| }); |