Skip to content

Commit c3194db

Browse files
committed
Switch Devin review to API workflow
1 parent 6a09065 commit c3194db

1 file changed

Lines changed: 128 additions & 16 deletions

File tree

.github/workflows/devin-review.yml

Lines changed: 128 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,145 @@
11
name: Devin Review
22

33
on:
4-
pull_request:
4+
pull_request_target:
55
types: [opened, synchronize, reopened, ready_for_review]
6+
workflow_dispatch:
7+
inputs:
8+
pr_number:
9+
description: Pull request number to review
10+
required: true
11+
type: string
612

713
jobs:
814
devin-review:
15+
if: ${{ github.event_name == 'workflow_dispatch' || !github.event.pull_request.draft }}
916
runs-on: ubuntu-latest
10-
timeout-minutes: 30
17+
timeout-minutes: 10
18+
env:
19+
DEVIN_API_KEY: ${{ secrets.DEVIN_API_KEY }}
1120
permissions:
1221
contents: read
13-
pull-requests: write
22+
pull-requests: read
1423

1524
steps:
16-
- name: Checkout repository
17-
uses: actions/checkout@v4
25+
- name: Resolve pull request context
26+
id: pr
27+
uses: actions/github-script@v8
1828
with:
19-
fetch-depth: 0
29+
script: |
30+
const prNumber = context.eventName === 'workflow_dispatch'
31+
? Number(core.getInput('pr_number'))
32+
: context.payload.pull_request.number;
2033
21-
- name: Setup Node.js
22-
uses: actions/setup-node@v4
23-
with:
24-
node-version: '20'
34+
if (!Number.isInteger(prNumber) || prNumber <= 0) {
35+
core.setFailed(`Invalid pull request number: ${prNumber}`);
36+
return;
37+
}
38+
39+
const { owner, repo } = context.repo;
40+
const { data: pr } = await github.rest.pulls.get({
41+
owner,
42+
repo,
43+
pull_number: prNumber,
44+
});
45+
const files = await github.paginate(github.rest.pulls.listFiles, {
46+
owner,
47+
repo,
48+
pull_number: prNumber,
49+
per_page: 100,
50+
});
51+
52+
core.setOutput('number', String(prNumber));
53+
core.setOutput('url', pr.html_url);
54+
core.setOutput('title', pr.title);
55+
core.setOutput('author', pr.user.login);
56+
core.setOutput('head_sha', pr.head.sha);
57+
core.setOutput('head_repo', pr.head.repo.full_name);
58+
core.setOutput('base_repo', pr.base.repo.full_name);
59+
core.setOutput('files_json', JSON.stringify(files.map((file) => file.filename)));
60+
61+
- name: Validate Devin API configuration
62+
if: ${{ env.DEVIN_API_KEY == '' }}
63+
run: |
64+
echo "DEVIN_API_KEY is not configured for this repository or organization." >&2
65+
echo "Configure DEVIN_API_KEY before using the API-based Devin review workflow." >&2
66+
exit 1
2567
26-
- name: Run Devin Review
27-
# Use script to emulate a TTY as devin-review requires terminal features
28-
# The -q flag suppresses script output, -e exits with command exit code,
29-
# and -c runs the command. /dev/null discards script's own output.
68+
- name: Start Devin review session
69+
id: devin
3070
env:
31-
CI: true # Ensures the tool runs in non-interactive CI mode
71+
PR_NUMBER: ${{ steps.pr.outputs.number }}
72+
PR_URL: ${{ steps.pr.outputs.url }}
73+
PR_TITLE: ${{ steps.pr.outputs.title }}
74+
PR_AUTHOR: ${{ steps.pr.outputs.author }}
75+
PR_HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
76+
PR_HEAD_REPO: ${{ steps.pr.outputs.head_repo }}
77+
PR_BASE_REPO: ${{ steps.pr.outputs.base_repo }}
78+
PR_FILES_JSON: ${{ steps.pr.outputs.files_json }}
79+
REPOSITORY: ${{ github.repository }}
3280
run: |
33-
script -q -e -c "printf 'y\n' | npx devin-review '${{ github.event.pull_request.html_url }}'" /dev/null
81+
PROMPT=$(cat <<EOF
82+
You are reviewing pull request #${PR_NUMBER} in ${REPOSITORY}.
83+
84+
Repository:
85+
- Base repository: ${PR_BASE_REPO}
86+
- Head repository: ${PR_HEAD_REPO}
87+
88+
Pull request:
89+
- Title: ${PR_TITLE}
90+
- Author: ${PR_AUTHOR}
91+
- URL: ${PR_URL}
92+
- Head SHA: ${PR_HEAD_SHA}
93+
94+
Changed files JSON:
95+
${PR_FILES_JSON}
96+
97+
Tasks:
98+
1. Review the current pull request diff and related repository context for PR #${PR_NUMBER}.
99+
2. Never commit, push, or open a new pull request.
100+
3. Never ask the user for confirmation and never wait for user messages.
101+
4. Leave at most 3 total review comments.
102+
5. Use inline review comments with precise line references when possible.
103+
6. Before commenting, check whether the same issue was already raised or already fixed in the current PR discussion.
104+
7. If no issues are found, leave a short summary comment saying everything looks good.
105+
8. Follow repository instruction files such as AGENTS.md, CLAUDE.md, CONTRIBUTING.md, and REVIEW.md if present.
106+
107+
Focus on bugs, regressions, missing tests, and clear correctness issues. Avoid speculative nits.
108+
EOF
109+
)
110+
111+
PAYLOAD=$(jq -n \
112+
--arg prompt "$PROMPT" \
113+
--arg title "PR Review #${PR_NUMBER} (${REPOSITORY})" \
114+
'{
115+
prompt: $prompt,
116+
idempotent: true,
117+
title: $title,
118+
tags: ["github-actions", "devin-review", "pull-request"]
119+
}')
120+
121+
RESPONSE=$(curl --fail --silent --show-error \
122+
--request POST \
123+
--url https://api.devin.ai/v1/sessions \
124+
--header "Authorization: Bearer ${DEVIN_API_KEY}" \
125+
--header "Content-Type: application/json" \
126+
--data "$PAYLOAD")
127+
128+
SESSION_ID=$(echo "$RESPONSE" | jq -r '.session_id')
129+
SESSION_URL=$(echo "$RESPONSE" | jq -r '.url')
130+
131+
if [[ -z "$SESSION_ID" || "$SESSION_ID" == "null" || -z "$SESSION_URL" || "$SESSION_URL" == "null" ]]; then
132+
echo "Unexpected Devin API response: $RESPONSE" >&2
133+
exit 1
134+
fi
135+
136+
echo "session_id=$SESSION_ID" >> "$GITHUB_OUTPUT"
137+
echo "session_url=$SESSION_URL" >> "$GITHUB_OUTPUT"
138+
139+
{
140+
echo "Started Devin review session."
141+
echo
142+
echo "- PR: #${PR_NUMBER}"
143+
echo "- Session ID: ${SESSION_ID}"
144+
echo "- Session URL: ${SESSION_URL}"
145+
} >> "$GITHUB_STEP_SUMMARY"

0 commit comments

Comments
 (0)