Skip to content

Commit 65cb22a

Browse files
allspainclaudencreated
authored
Add shadow reviewer workflow (#4430)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Maciek Grzybowski <maciek.grzybowski@datadoghq.com>
1 parent abcbafe commit 65cb22a

1 file changed

Lines changed: 122 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# shadow-review.yml — Shadow Reviewer workflow
2+
# Source: https://github.com/DataDog/rum-ai-toolkit
3+
name: Shadow Review
4+
5+
on:
6+
pull_request:
7+
types: [opened, synchronize, ready_for_review]
8+
9+
jobs:
10+
# Mirror PR to shadow fork (review + post-close disabled for now)
11+
# Fork sync not needed — each shadow PR targets its own base ref
12+
shadow-mirror:
13+
if: >-
14+
github.event_name == 'pull_request'
15+
&& github.event.pull_request.draft != true
16+
&& github.event.pull_request.user.type != 'Bot'
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Mirror PR to shadow fork
20+
env:
21+
GITHUB_TOKEN: ${{ github.token }}
22+
SHADOW_FORK_TOKEN: ${{ secrets.SHADOW_FORK_TOKEN }}
23+
SOURCE_REPO: ${{ github.repository }}
24+
SHADOW_FORK: ${{ vars.SHADOW_FORK }}
25+
PR_NUMBER: ${{ github.event.pull_request.number }}
26+
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
27+
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
28+
PR_TITLE: ${{ github.event.pull_request.title }}
29+
PR_BODY: ${{ github.event.pull_request.body }}
30+
run: |
31+
set -euo pipefail
32+
# Mask tokens in trace output
33+
echo "::add-mask::${SHADOW_FORK_TOKEN}"
34+
echo "::add-mask::${GITHUB_TOKEN}"
35+
set -x
36+
37+
WORK_DIR=$(mktemp -d)
38+
trap 'rm -rf "${WORK_DIR}"' EXIT
39+
40+
echo "=== Pre-flight checks ==="
41+
echo "SOURCE_REPO: ${SOURCE_REPO}"
42+
echo "SHADOW_FORK: ${SHADOW_FORK}"
43+
echo "PR_NUMBER: ${PR_NUMBER}"
44+
echo "PR_HEAD_SHA: ${PR_HEAD_SHA}"
45+
echo "PR_BASE_REF: ${PR_BASE_REF}"
46+
47+
# Verify shadow fork access (using shadow fork token)
48+
echo "Verifying access to shadow fork..."
49+
if ! GITHUB_TOKEN="${SHADOW_FORK_TOKEN}" gh repo view "${SHADOW_FORK}" > /dev/null 2>&1; then
50+
echo "ERROR: Cannot access shadow fork ${SHADOW_FORK}"
51+
echo "Ensure SHADOW_FORK_TOKEN has repo access and SHADOW_FORK variable is set correctly"
52+
exit 1
53+
fi
54+
echo "Shadow fork accessible"
55+
56+
# Verify source repo access (using default token)
57+
echo "Verifying access to source repo..."
58+
if ! gh repo view "${SOURCE_REPO}" > /dev/null 2>&1; then
59+
echo "ERROR: Cannot access source repo ${SOURCE_REPO}"
60+
exit 1
61+
fi
62+
echo "Source repo accessible"
63+
64+
echo "=== Mirroring PR #${PR_NUMBER} (${PR_HEAD_SHA}) to ${SHADOW_FORK} ==="
65+
66+
# Determine version number by counting existing shadow branches (exclude -base)
67+
VERSION=$(git ls-remote --heads "https://x-access-token:${SHADOW_FORK_TOKEN}@github.com/${SHADOW_FORK}.git" "shadow/${PR_NUMBER}/v*" 2>/dev/null \
68+
| { grep -v '\-base$' || true; } | wc -l | tr -d ' ')
69+
VERSION=$((VERSION + 1))
70+
echo "Version: v${VERSION}"
71+
72+
SHADOW_BRANCH="shadow/${PR_NUMBER}/v${VERSION}"
73+
BASE_BRANCH="shadow/${PR_NUMBER}/v${VERSION}-base"
74+
75+
# Clone source repo and fetch PR ref
76+
echo "Cloning source repo..."
77+
git clone --depth=1 --no-checkout "https://x-access-token:${GITHUB_TOKEN}@github.com/${SOURCE_REPO}.git" "${WORK_DIR}/repo"
78+
cd "${WORK_DIR}/repo"
79+
echo "Fetching PR head..."
80+
git fetch origin "pull/${PR_NUMBER}/head:pr-head" --depth=50
81+
echo "Fetching base ref..."
82+
git fetch origin "${PR_BASE_REF}:base-ref" --depth=50
83+
84+
# Compute merge base
85+
MERGE_BASE=$(git merge-base pr-head base-ref)
86+
echo "Merge base: ${MERGE_BASE}"
87+
88+
# Push base and head branches to shadow fork
89+
git remote add shadow "https://x-access-token:${SHADOW_FORK_TOKEN}@github.com/${SHADOW_FORK}.git"
90+
91+
echo "Pushing base branch..."
92+
git push shadow "${MERGE_BASE}:refs/heads/${BASE_BRANCH}" 2>&1 || {
93+
echo "Push failed — retrying with incremented version..."
94+
VERSION=$((VERSION + 1))
95+
SHADOW_BRANCH="shadow/${PR_NUMBER}/v${VERSION}"
96+
BASE_BRANCH="shadow/${PR_NUMBER}/v${VERSION}-base"
97+
git push shadow "${MERGE_BASE}:refs/heads/${BASE_BRANCH}" 2>&1
98+
}
99+
100+
echo "Pushing head branch..."
101+
git push shadow "${PR_HEAD_SHA}:refs/heads/${SHADOW_BRANCH}" 2>&1
102+
103+
# Create shadow PR
104+
echo "Creating shadow PR..."
105+
SHADOW_PR_URL=$(GITHUB_TOKEN="${SHADOW_FORK_TOKEN}" gh pr create \
106+
--repo "${SHADOW_FORK}" \
107+
--base "${BASE_BRANCH}" \
108+
--head "${SHADOW_BRANCH}" \
109+
--title "Shadow: ${PR_TITLE} (v${VERSION})" \
110+
--body "## Shadow Review — PR #${PR_NUMBER} v${VERSION}
111+
112+
**Source:** https://github.com/${SOURCE_REPO}/pull/${PR_NUMBER}
113+
**Commit:** \`${PR_HEAD_SHA}\`
114+
**Timestamp:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
115+
116+
---
117+
118+
## Original PR Description
119+
120+
${PR_BODY}")
121+
122+
echo "Shadow PR created: ${SHADOW_PR_URL}"

0 commit comments

Comments
 (0)