Commit 30f7d96
authored
[CRCR] Fix the way of searching PR (#8386)
## Summary
Fix `crcrOncallBot`'s "commit SHA → PR number" resolution for cross-fork
pull requests on `pytorch/pytorch`, where the bot was silently failing
to comment on downstream CI failures for the majority of contributions.
## Problem
`crcrOncallBot` reacts to `check_run.completed` webhook events and posts
oncall-ping comments on the associated PR when downstream CI fails. To
find which PR a check run belongs to, it uses a two-step strategy:
1. **`checkRun.pull_requests`** — the `check_run` payload's
`pull_requests` array
2. **Fallback: `listPullRequestsAssociatedWithCommit`** (GitHub Commits
API) — when `pull_requests` is empty, which happens for **cross-fork
PRs** (the code comment itself admits this)
The problem: **both paths are dead ends for cross-fork PRs on large
repos like `pytorch/pytorch`.**
| API | Behavior for fork PR |
|-----|---------------------|
| `checkRun.pull_requests` | Empty `[]` — GitHub does not populate this
for cross-fork check runs |
| `GET /repos/{owner}/{repo}/commits/{sha}/pulls` | Returns `[]` — the
commits-pulls endpoint does not return PRs from forked repositories on
repos of `pytorch/pytorch`'s scale |
The commits-pulls API returns HTTP 200 with `[]` (not an error), so the
`try/catch` on the fallback doesn't fire — execution falls through to an
empty-array check that silently returns without posting a comment. The
bot was effectively **completely broken for cross-fork PRs**, which is
the dominant contribution pattern for `pytorch/pytorch`.
### Evidence
Tested with two real open fork PRs on `pytorch/pytorch`:
```bash
# PR #191304 (head: RohitRathore1/pytorch)
$ gh api repos/pytorch/pytorch/commits/29249453f.../pulls --jq 'length'
0 # ← commits API returns nothing
$ gh api 'search/issues?q=29249453f...+type:pr+repo:pytorch/pytorch' \
--jq '[.items[].number]'
[191304] # ← Search API returns the correct PR
# PR #191301 (head: vishals-3/pytorch)
$ gh api repos/pytorch/pytorch/commits/159d04cd9.../pulls --jq 'length'
0
$ gh api 'search/issues?q=159d04cd9...+type:pr+repo:pytorch/pytorch' \
--jq '[.items[].number]'
[191301]
```
Fork-branch PR (not functional):
pytorch/pytorch#189246
Intra-branch PR (functional):
pytorch/pytorch#191313
## Fix
### Core approach: embed PR number at the source
Instead of a server-side API lookup, the PR number is now embedded in
the check run's `external_id` field at creation time — alongside the
downstream `run_id` that was already stored there. The bot reads it back
directly with no external API call.
**Producer side** (Python — `callback_handler.py`, `cleanup_handler.py`,
`event_handler.py`):
```python
# Before: external_id stored only the run_id
external_id=str(run_id)
# After: external_id encodes both run_id and pr_number
external_id=f"{run_id}:{pr_number}" if pr_number else str(run_id)
```
**Consumer side** (`crcrOncallBot.ts`):
```ts
// Before: fallback tried the Commits API (broken for forks)
// After: parse external_id to extract the PR number
} else if (checkRun.external_id) {
const parts = checkRun.external_id.split(":");
if (parts.length === 2 && parts[1]) {
prNumbers = [parseInt(parts[1], 10)];
}
}
```
**Read sites** (`event_handler.py` — check run rerequest handlers) parse
out the run_id portion:
```python
# Before: run_id = check_run.get("external_id") or ""
# After: split on ":" to extract just the run_id
run_id = (check_run.get("external_id") or "").split(":")[0]
```
### Why `external_id` instead of `output.summary`
`output.summary` is user-facing display text rendered in the check run
detail panel. Binding a machine contract to it means any future copy
change silently breaks the bot, with no shared constant or cross-repo
test between the Python (AWS Lambda) and TypeScript (Probot) deploy
units. `external_id` is purpose-built for machine-readable data and was
already used to store `run_id` for rerequest handling.
### Also fixed: `str(None)` bug
`str(pr_field.get("number", ""))` produces the literal string `"None"`
when the `number` key exists but is `null` — Python's `dict.get()` only
returns the default when the key is missing, not when it's `None`.
Changed to `str(pr_field.get("number") or "")` in all three call sites.1 parent 6bb3c0f commit 30f7d96
7 files changed
Lines changed: 52 additions & 29 deletions
File tree
- aws/lambda/cross_repo_ci_relay
- callback
- tests
- webhook
- torchci
- lib/bot
- test
Lines changed: 4 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
203 | 203 | | |
204 | 204 | | |
205 | 205 | | |
| 206 | + | |
206 | 207 | | |
207 | 208 | | |
208 | 209 | | |
| |||
233 | 234 | | |
234 | 235 | | |
235 | 236 | | |
236 | | - | |
| 237 | + | |
237 | 238 | | |
238 | 239 | | |
239 | 240 | | |
| |||
369 | 370 | | |
370 | 371 | | |
371 | 372 | | |
| 373 | + | |
372 | 374 | | |
373 | 375 | | |
374 | 376 | | |
| |||
408 | 410 | | |
409 | 411 | | |
410 | 412 | | |
| 413 | + | |
411 | 414 | | |
412 | 415 | | |
413 | 416 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| 86 | + | |
86 | 87 | | |
87 | 88 | | |
88 | 89 | | |
| |||
117 | 118 | | |
118 | 119 | | |
119 | 120 | | |
120 | | - | |
| 121 | + | |
121 | 122 | | |
122 | 123 | | |
123 | 124 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
365 | 365 | | |
366 | 366 | | |
367 | 367 | | |
368 | | - | |
| 368 | + | |
369 | 369 | | |
370 | 370 | | |
371 | 371 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
194 | | - | |
| 194 | + | |
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| |||
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
218 | | - | |
| 218 | + | |
219 | 219 | | |
220 | 220 | | |
221 | 221 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
155 | | - | |
| 155 | + | |
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
| |||
205 | 205 | | |
206 | 206 | | |
207 | 207 | | |
208 | | - | |
| 208 | + | |
209 | 209 | | |
210 | | - | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
211 | 214 | | |
212 | 215 | | |
213 | 216 | | |
| |||
263 | 266 | | |
264 | 267 | | |
265 | 268 | | |
266 | | - | |
| 269 | + | |
267 | 270 | | |
268 | 271 | | |
269 | 272 | | |
| |||
346 | 349 | | |
347 | 350 | | |
348 | 351 | | |
349 | | - | |
| 352 | + | |
350 | 353 | | |
351 | 354 | | |
352 | 355 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | 83 | | |
87 | 84 | | |
88 | 85 | | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
104 | 90 | | |
105 | 91 | | |
106 | 92 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
176 | 176 | | |
177 | 177 | | |
178 | 178 | | |
179 | | - | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
180 | 182 | | |
181 | 183 | | |
182 | 184 | | |
183 | 185 | | |
| 186 | + | |
184 | 187 | | |
185 | 188 | | |
186 | 189 | | |
187 | 190 | | |
188 | 191 | | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
189 | 219 | | |
190 | 220 | | |
191 | 221 | | |
| |||
0 commit comments