-
-
Notifications
You must be signed in to change notification settings - Fork 10
feat: add CodeRabbit label sync workflow for PR reviews #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| name: CodeRabbit Label Sync | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, reopened, synchronize, edited] | ||
|
|
||
| pull_request_review: | ||
| types: [submitted, edited, dismissed] | ||
|
|
||
| pull_request_review_thread: | ||
| types: [resolved, unresolved] | ||
|
Comment on lines
+10
to
+11
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result:
It is not one of the events that can directly trigger GitHub Actions workflows (it does not appear in the “Events that trigger workflows” list). [2] If you need an Actions workflow to react to PR review activity, you typically use Sources: [1] GitHub Docs – “Webhook events and payloads” (pull_request_review_thread) ; [2] GitHub Docs – “Events that trigger workflows” (GitHub Actions)
While Use one of these alternatives instead:
🧰 Tools🪛 actionlint (1.7.10)[error] 10-10: unknown Webhook event "pull_request_review_thread". see https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#webhook-events for list of all Webhook event names (events) 🤖 Prompt for AI Agents |
||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| issues: write | ||
|
|
||
| jobs: | ||
| sync-coderabbit-label: | ||
| runs-on: ubuntu-latest | ||
| name: Update CodeRabbit Review Label | ||
| steps: | ||
| - name: Check for unresolved CodeRabbit threads | ||
| id: check-threads | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const prNumber = context.issue.number; | ||
|
|
||
| console.log('Checking PR:', prNumber); | ||
|
|
||
| // Query for review threads using GraphQL API | ||
| const query = ` | ||
| query($owner: String!, $repo: String!, $prNumber: Int!) { | ||
| repository(owner: $owner, name: $repo) { | ||
| pullRequest(number: $prNumber) { | ||
| reviewThreads(first: 100) { | ||
| nodes { | ||
| isResolved | ||
| isOutdated | ||
| comments(first: 10) { | ||
| nodes { | ||
| author { | ||
| login | ||
| } | ||
| body | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+38
to
+50
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pagination not handled — PRs with >100 review threads will silently miss unresolved threads. The GraphQL query fetches at most 100 threads and 10 comments per thread. For large PRs with extensive review activity, some threads will be silently skipped, potentially causing the label to be removed prematurely (false negative). At minimum, consider checking 🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| } | ||
| } | ||
| `; | ||
|
|
||
| const variables = { | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| prNumber: parseInt(prNumber) | ||
| }; | ||
|
|
||
| const result = await github.graphql(query, variables); | ||
| const threads = result.repository.pullRequest.reviewThreads.nodes; | ||
|
|
||
| console.log(`Total review threads: ${threads.length}`); | ||
|
|
||
| // Filter for unresolved CodeRabbit threads | ||
| const unresolvedCodeRabbitThreads = threads.filter(thread => { | ||
| // Skip resolved or outdated threads | ||
| if (thread.isResolved || thread.isOutdated) return false; | ||
|
|
||
| // Check if any comment in the thread is from CodeRabbit | ||
| const hasCodeRabbitComment = thread.comments.nodes.some(comment => | ||
| comment.author?.login === 'coderabbitai' || | ||
| comment.author?.login === 'coderabbitai[bot]' | ||
| ); | ||
|
|
||
| return hasCodeRabbitComment; | ||
| }); | ||
|
|
||
| console.log('Unresolved CodeRabbit threads:', unresolvedCodeRabbitThreads.length); | ||
|
|
||
| core.setOutput('has-unresolved', unresolvedCodeRabbitThreads.length > 0); | ||
| core.setOutput('unresolved-count', unresolvedCodeRabbitThreads.length); | ||
| core.setOutput('pr-number', prNumber); | ||
|
Comment on lines
+84
to
+86
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider consolidating into a single step. The outputs from step 1 are only consumed by step 2 within the same job. You could combine both steps into a single 🤖 Prompt for AI Agents |
||
|
|
||
| - name: Update unresolved-code-rabbit-review label | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const prNumber = parseInt('${{ steps.check-threads.outputs.pr-number }}'); | ||
| const hasUnresolved = '${{ steps.check-threads.outputs.has-unresolved }}' === 'true'; | ||
| const unresolvedCount = parseInt('${{ steps.check-threads.outputs.unresolved-count }}'); | ||
|
Comment on lines
+92
to
+95
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Avoid Directly embedding Proposed fix uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
+ env:
+ PR_NUMBER: ${{ steps.check-threads.outputs.pr-number }}
+ HAS_UNRESOLVED: ${{ steps.check-threads.outputs.has-unresolved }}
+ UNRESOLVED_COUNT: ${{ steps.check-threads.outputs.unresolved-count }}
script: |
- const prNumber = parseInt('${{ steps.check-threads.outputs.pr-number }}');
- const hasUnresolved = '${{ steps.check-threads.outputs.has-unresolved }}' === 'true';
- const unresolvedCount = parseInt('${{ steps.check-threads.outputs.unresolved-count }}');
+ const prNumber = parseInt(process.env.PR_NUMBER);
+ const hasUnresolved = process.env.HAS_UNRESOLVED === 'true';
+ const unresolvedCount = parseInt(process.env.UNRESOLVED_COUNT);Note: - name: Update unresolved-code-rabbit-review label
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.check-threads.outputs.pr-number }}
HAS_UNRESOLVED: ${{ steps.check-threads.outputs.has-unresolved }}
UNRESOLVED_COUNT: ${{ steps.check-threads.outputs.unresolved-count }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = parseInt(process.env.PR_NUMBER);
const hasUnresolved = process.env.HAS_UNRESOLVED === 'true';
const unresolvedCount = parseInt(process.env.UNRESOLVED_COUNT);🤖 Prompt for AI Agents |
||
|
|
||
| console.log(`PR #${prNumber}: Has unresolved threads: ${hasUnresolved} (${unresolvedCount})`); | ||
|
|
||
| // Get current labels | ||
| const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber | ||
| }); | ||
|
|
||
| const existingLabel = currentLabels.find( | ||
| label => label.name === 'unresolved-code-rabbit-review' | ||
| ); | ||
|
|
||
| // Apply label if unresolved comments exist | ||
| if (hasUnresolved && !existingLabel) { | ||
| console.log('Applying unresolved-code-rabbit-review label'); | ||
|
|
||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber, | ||
| labels: ['unresolved-code-rabbit-review'] | ||
| }); | ||
| } | ||
|
|
||
| // Remove label if all comments resolved | ||
| if (!hasUnresolved && existingLabel) { | ||
| console.log('Removing unresolved-code-rabbit-review label'); | ||
|
|
||
| await github.rest.issues.removeLabel({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber, | ||
| name: 'unresolved-code-rabbit-review' | ||
| }); | ||
| } | ||
|
Comment on lines
+110
to
+132
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No error handling around label API calls. If Also note that 🤖 Prompt for AI Agents |
||
|
|
||
| if ( | ||
| (!hasUnresolved && !existingLabel) || | ||
| (hasUnresolved && existingLabel) | ||
| ) { | ||
| console.log('Label already in correct state. No changes needed.'); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
pull_request_targetruns the workflow from the base branch with write permissions — ensure this is intentional.Using
pull_request_targetis appropriate here since the workflow only reads PR metadata via GraphQL and manages labels (no checkout of untrusted code). Just be aware that if someone later adds a checkout step, this becomes a significant security risk for fork-based PRs.Consider adding a comment in the workflow to document why
pull_request_targetis used.🤖 Prompt for AI Agents