Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/pr-review-trigger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Lightweight trigger workflow for fork PR auto-reviews.
# Runs in the fork's context (no secrets) on pull_request, saves the PR number
# as an artifact, then completes so that self-review-pr.yml can fire via
# workflow_run in the base repo context with full secret access.

name: PR Review Trigger

on:
pull_request:
types: [ready_for_review, opened]

permissions:
contents: read

jobs:
save-pr-metadata:
# Only fork PRs — same-repo PRs are handled directly by self-review-pr.yml
if: github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest

steps:
- name: Save PR number
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
mkdir -p pr-metadata
echo "$PR_NUMBER" > pr-metadata/pr-number

- name: Upload PR metadata
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pr-review-trigger-metadata
path: pr-metadata/
retention-days: 1
69 changes: 59 additions & 10 deletions .github/workflows/review-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,30 +108,80 @@ jobs:
# ==========================================================================
# AUTOMATIC REVIEW FOR ORG MEMBERS
# Triggers when a PR is marked ready for review or opened (non-draft)
# Only runs for members of the configured org; same-repo branches only — fork PRs use /review command
# Only runs for same-repo PRs (fork PRs don't have access to secrets with pull_request trigger)
# Fork PRs use the /review command instead
# Supports two trigger paths:
# 1. pull_request event (same-repo branches only — fork PRs lack secret access)
# 2. workflow_run event with inputs.pr-number set (fork PRs via workflow_run pattern)
# Only runs for members of the configured org.
# ==========================================================================
auto-review:
if: |
github.event_name == 'pull_request' &&
!github.event.pull_request.draft &&
github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name
(
github.event_name == 'pull_request' &&
!github.event.pull_request.draft &&
github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name
) || (
github.event_name == 'workflow_run' &&
inputs.pr-number != ''
)
runs-on: ubuntu-latest
env:
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}
outputs:
exit-code: ${{ steps.run-review.outputs.exit-code }}

steps:
- name: Get PR number
id: get-pr
shell: bash
env:
INPUT_PR_NUMBER: ${{ inputs.pr-number }}
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
echo "pr-number=${INPUT_PR_NUMBER:-$EVENT_PR_NUMBER}" >> $GITHUB_OUTPUT
# For workflow_run events, github.event.pull_request is unavailable — fetch PR author
# and draft status via API using github.token (repo read access).
# Skipped for pull_request events where the payload already has this info.
- name: Fetch PR info
id: pr-info
if: github.event_name == 'workflow_run'
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
PR_NUMBER: ${{ steps.get-pr.outputs.pr-number }}
with:
github-token: ${{ github.token }}
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: parseInt(process.env.PR_NUMBER, 10)
});
core.setOutput('author', pr.user.login);
core.setOutput('draft', pr.draft ? 'true' : 'false');
- name: Check if PR author is org member
id: membership
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
PR_NUMBER: ${{ steps.get-pr.outputs.pr-number }}
PR_DRAFT: ${{ steps.pr-info.outputs.draft }}
PR_AUTHOR: ${{ steps.pr-info.outputs.author }}
with:
github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }}
script: |
const org = '${{ inputs.auto-review-org }}';
const username = context.payload.pull_request.user.login;
let username;
if (context.eventName === 'workflow_run') {
if (process.env.PR_DRAFT === 'true') {
core.setOutput('is_member', 'false');
console.log(`⏭️ PR #${process.env.PR_NUMBER} is a draft — skipping auto-review`);
return;
}
username = process.env.PR_AUTHOR;
} else {
username = context.payload.pull_request.user.login;
}
try {
await github.rest.orgs.checkMembershipForUser({
Expand All @@ -157,13 +207,12 @@ jobs:
}
}
# With pull_request, checking out the PR head is standard behavior
- name: Checkout PR head
if: steps.membership.outputs.is_member == 'true'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
ref: refs/pull/${{ github.event.pull_request.number }}/head
ref: refs/pull/${{ steps.get-pr.outputs.pr-number }}/head

# Generate GitHub App token for custom app identity (optional - falls back to github.token)
- name: Generate GitHub App token
Expand All @@ -181,7 +230,7 @@ jobs:
continue-on-error: true # Don't fail the calling workflow if the review errors
uses: docker/cagent-action/review-pr@latest
with:
pr-number: ${{ inputs.pr-number || github.event.pull_request.number }}
pr-number: ${{ steps.get-pr.outputs.pr-number }}
additional-prompt: ${{ inputs.additional-prompt }}
add-prompt-files: ${{ inputs.add-prompt-files }}
model: ${{ inputs.model }}
Expand Down
88 changes: 78 additions & 10 deletions .github/workflows/self-review-pr.yml
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow is only for this cagent-action repo, btw.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but thought it would benefit from reviewing in forks (and make sure it works on it's own repo);

Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,108 @@ on:
types: [created]
pull_request:
types: [ready_for_review, opened]
workflow_run:
workflows: ["PR Review Trigger"]
types: [completed]

permissions:
contents: read
pull-requests: write
issues: write
checks: write
actions: read

jobs:
# ==========================================================================
# AUTOMATIC REVIEW FOR ORG MEMBERS
# Triggers when a PR is marked ready for review or opened (non-draft)
# Only runs for members of the docker org; auto-reviews same-repo PRs from org members
# Only runs for same-repo PRs (fork PRs don't have access to secrets with pull_request trigger)
# Fork PRs use the /review command instead
# Supports two trigger paths:
# 1. pull_request event (same-repo branches only — fork PRs lack secret access)
# 2. workflow_run event (fork PRs via pr-review-trigger.yml → workflow_run pattern)
# Only runs for members of the docker org.
# ==========================================================================
auto-review:
if: |
github.event_name == 'pull_request' &&
!github.event.pull_request.draft &&
github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name
(
github.event_name == 'pull_request' &&
!github.event.pull_request.draft &&
github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name
) || (
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_repository.full_name != github.repository
)
runs-on: ubuntu-latest
env:
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}

steps:
# For workflow_run events (fork PRs), download the artifact saved by pr-review-trigger.yml
# to get the PR number. For pull_request events, read it directly from the event payload.
- name: Get PR number
id: get-pr
shell: bash
env:
GH_TOKEN: ${{ github.token }}
EVENT_NAME: ${{ github.event_name }}
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
REPO: ${{ github.repository }}
run: |
if [ "$EVENT_NAME" = "pull_request" ]; then
echo "pr-number=$EVENT_PR_NUMBER" >> $GITHUB_OUTPUT
exit 0
fi

mkdir -p /tmp/trigger-metadata

if ! gh run download "$WORKFLOW_RUN_ID" -n pr-review-trigger-metadata -D /tmp/trigger-metadata --repo "$REPO" 2>/dev/null; then
echo "⏭️ No trigger metadata artifact found — skipping"
echo "pr-number=" >> $GITHUB_OUTPUT
exit 0
fi

PR_NUMBER=$(cat /tmp/trigger-metadata/pr-number | tr -d '[:space:]')
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]] || [ "$PR_NUMBER" -lt 1 ]; then
echo "::error::Invalid PR number: $PR_NUMBER"
exit 1
fi

echo "pr-number=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "✅ Got PR number from trigger metadata: #$PR_NUMBER"

- name: Check if PR author is org member
id: membership
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }}
script: |
const org = 'docker';
const username = context.payload.pull_request.user.login;

// For workflow_run events, fetch PR author and draft status via API
// since github.event.pull_request is not available in that context
let username;
if (context.eventName === 'workflow_run') {
const prNumber = parseInt('${{ steps.get-pr.outputs.pr-number }}', 10);
if (!prNumber) {
core.setOutput('is_member', 'false');
console.log('⏭️ No PR number — skipping auto-review');
return;
}
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
if (pr.draft) {
core.setOutput('is_member', 'false');
console.log(`⏭️ PR #${prNumber} is a draft — skipping auto-review`);
return;
}
username = pr.user.login;
} else {
username = context.payload.pull_request.user.login;
}

try {
await github.rest.orgs.checkMembershipForUser({
Expand All @@ -70,13 +139,12 @@ jobs:
}
}

# With pull_request, checking out the PR head is standard behavior
- name: Checkout PR head
if: steps.membership.outputs.is_member == 'true'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
ref: refs/pull/${{ github.event.pull_request.number }}/head
ref: refs/pull/${{ steps.get-pr.outputs.pr-number }}/head

# Generate GitHub App token for custom app identity (optional - falls back to github.token)
- name: Generate GitHub App token
Expand All @@ -94,7 +162,7 @@ jobs:
continue-on-error: true # Don't fail the calling workflow if the review errors
uses: ./review-pr
with:
pr-number: ${{ github.event.pull_request.number }}
pr-number: ${{ steps.get-pr.outputs.pr-number }}
github-token: ${{ steps.app-token.outputs.token || github.token }}
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
Expand Down
Loading