diff --git a/.github/workflows/cubic-devin-review-trigger.yml b/.github/workflows/cubic-devin-review-trigger.yml new file mode 100644 index 0000000000..94b989510b --- /dev/null +++ b/.github/workflows/cubic-devin-review-trigger.yml @@ -0,0 +1,32 @@ +name: Cubic AI Review Trigger + +on: + pull_request_review: + types: [submitted] + +# This workflow triggers on pull_request_review events (including from forks) +# and saves the review context as an artifact. The main cubic-devin-review.yml +# workflow then runs via workflow_run with full permissions and secrets access. + +jobs: + save-review-context: + name: Save Review Context + if: github.event.review.user.login == 'cubic-dev-ai[bot]' + runs-on: ubuntu-latest + steps: + - name: Save review context to artifact + run: | + cat > review-context.json << 'EOF' + { + "pr_number": ${{ github.event.pull_request.number }}, + "review_body": ${{ toJSON(github.event.review.body) }}, + "repository": "${{ github.repository }}" + } + EOF + + - name: Upload review context + uses: actions/upload-artifact@v4 + with: + name: cubic-review-context + path: review-context.json + retention-days: 1 diff --git a/.github/workflows/cubic-devin-review.yml b/.github/workflows/cubic-devin-review.yml index 2360869423..929f0e0fce 100644 --- a/.github/workflows/cubic-devin-review.yml +++ b/.github/workflows/cubic-devin-review.yml @@ -1,33 +1,66 @@ -name: Cubic AI to Devin Review +name: Cubic feedback addressed by Devin on: - pull_request_review: - types: [submitted] + workflow_run: + workflows: ["Cubic AI Review Trigger"] + types: + - completed permissions: contents: read pull-requests: write + actions: read jobs: trigger-devin: name: Trigger Devin to Address Cubic AI Review - # Only run if the review is from cubic-dev-ai bot and contains the AI prompt - if: github.event.review.user.login == 'cubic-dev-ai[bot]' + if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: blacksmith-2vcpu-ubuntu-2404 steps: + - name: Download review context artifact + uses: actions/github-script@v7 + with: + script: | + const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + + const matchArtifact = artifacts.data.artifacts.find( + artifact => artifact.name === 'cubic-review-context' + ); + + if (!matchArtifact) { + core.setFailed('No cubic-review-context artifact found'); + return; + } + + const download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + + const fs = require('fs'); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/context.zip`, Buffer.from(download.data)); + + - name: Unzip artifact + run: unzip context.zip + - name: Extract AI prompt from Cubic review id: extract-prompt uses: actions/github-script@v7 with: script: | - const reviewBody = context.payload.review.body || ''; + const fs = require('fs'); + const contextData = JSON.parse(fs.readFileSync('review-context.json', 'utf8')); + const reviewBody = contextData.review_body || ''; + const prNumber = contextData.pr_number; + + core.setOutput('pr-number', prNumber); - // Look for the AI prompt section in Cubic's review - // Format:
Prompt for AI agents (all issues) - // ```text - // ... prompt content ... - // ``` - //
const promptMatch = reviewBody.match(/
\s*Prompt for AI agents[^<]*<\/summary>\s*```(?:text)?\s*([\s\S]*?)```\s*<\/details>/i); if (!promptMatch || !promptMatch[1]) { @@ -40,8 +73,6 @@ jobs: const prompt = promptMatch[1].trim(); console.log('Extracted prompt:', prompt); - // Save prompt to file to avoid shell escaping issues - const fs = require('fs'); fs.writeFileSync('/tmp/cubic-prompt.txt', prompt); core.setOutput('has-prompt', 'true'); @@ -57,7 +88,7 @@ jobs: with: devin-api-key: ${{ secrets.DEVIN_API_KEY }} github-token: ${{ secrets.GITHUB_TOKEN }} - pr-number: ${{ github.event.pull_request.number }} + pr-number: ${{ steps.extract-prompt.outputs.pr-number }} - name: Set session environment variables if: steps.extract-prompt.outputs.has-prompt == 'true' && steps.check-session.outputs.has-existing-session == 'true' @@ -72,7 +103,7 @@ jobs: run: | CUBIC_PROMPT=$(cat /tmp/cubic-prompt.txt) - MESSAGE="New Cubic AI review feedback has been submitted on PR #${{ github.event.pull_request.number }}. + MESSAGE="New Cubic AI review feedback has been submitted on PR #${{ steps.extract-prompt.outputs.pr-number }}. IMPORTANT: Before fixing any issue, check the individual Cubic comment on the PR for that issue's confidence score. The confidence score appears as 'Fix confidence (alpha): X/10' in each comment. Note that the (alpha) may or not be there. Don't be picky about that text. But only fix issues where the confidence score is 9/10 or higher. If you cannot find a confidence score for an issue, skip it. @@ -102,7 +133,7 @@ jobs: run: | CUBIC_PROMPT=$(cat /tmp/cubic-prompt.txt) - FULL_PROMPT="You are addressing code review feedback from Cubic AI on PR #${{ github.event.pull_request.number }} in repository ${{ github.repository }}. + FULL_PROMPT="You are addressing code review feedback from Cubic AI on PR #${{ steps.extract-prompt.outputs.pr-number }} in repository ${{ github.repository }}. Your tasks: 1. Clone the repository ${{ github.repository }} locally. @@ -127,11 +158,11 @@ jobs: -H "Content-Type: application/json" \ -d "$(jq -n \ --arg prompt "$FULL_PROMPT" \ - --arg title "Cubic AI Review: PR #${{ github.event.pull_request.number }}" \ + --arg title "Cubic AI Review: PR #${{ steps.extract-prompt.outputs.pr-number }}" \ '{ prompt: $prompt, title: $title, - tags: ["cubic-ai-review", "pr-${{ github.event.pull_request.number }}"] + tags: ["cubic-ai-review", "pr-${{ steps.extract-prompt.outputs.pr-number }}"] }')") if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then @@ -161,10 +192,14 @@ jobs: ? `### Devin AI is addressing Cubic AI's review feedback\n\nA Devin session has been created to address the issues identified by Cubic AI.\n\n[View Devin Session](${sessionUrl})` : `### Devin AI is addressing Cubic AI's review feedback\n\nNew feedback has been sent to the existing Devin session.\n\n[View Devin Session](${sessionUrl})`; + const fs = require('fs'); + const contextData = JSON.parse(fs.readFileSync('review-context.json', 'utf8')); + const prNumber = contextData.pr_number; + const { data: comment } = await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: context.payload.pull_request.number, + issue_number: prNumber, body: message }); @@ -189,7 +224,7 @@ jobs: MESSAGE="IMPORTANT: When you have finished addressing Cubic AI's feedback (whether you pushed changes or not), you MUST update the GitHub comment to show completion status. - Use the GitHub API to update comment ID ${COMMENT_ID} on PR #${{ github.event.pull_request.number }} in repository ${{ github.repository }}. + Use the GitHub API to update comment ID ${COMMENT_ID} on PR #${{ steps.extract-prompt.outputs.pr-number }} in repository ${{ github.repository }}. Add a completion status section at the bottom of the comment: - If you pushed changes: Add '\n\n---\n:white_check_mark: Pushed commit [\`{SHORT_HASH}\`](https://github.com/${{ github.repository }}/commit/{FULL_HASH})' where {SHORT_HASH} is the first 7 characters of the commit hash and {FULL_HASH} is the full commit hash.