Commit bb4bbd9
[EPAC-2011]: inherit Linear projectId from originating PR's EPAC issue (#586)
## Why
CI-failure issues created by the handler landed unparented in Linear.
When a workflow fails after a PR merge, the failure issue should inherit
the originating PR's EPAC issue's Linear project so it appears in the
same project view as the work that caused it.
## What changed
- **`GitHubPRClient`**: New thin client with `find_pr_for_commit(repo,
sha)` that calls `GET /repos/{owner}/{repo}/commits/{sha}/pulls`,
preferring the PR whose `merge_commit_sha` matches the head SHA and
falling back to the first PR.
- **`PRInfo` / `OriginatingContext`**: Value objects carrying the
originating PR metadata and optional Linear project inheritance.
- **`extract_linear_id(pr_title)`**: Regex `\bEPAC-\d+\b` extracts the
first EPAC identifier from a PR title. Non-EPAC prefixes are ignored.
- **`LinearClient.get_issue_project_id(identifier)`**: GraphQL query
returning the originating issue's `projectId` (or `None` if
unparented/missing).
- **`resolve_originating_context`**: Orchestrates the lookup chain
(GitHub PR → regex → Linear project). Best-effort: any failure is logged
and falls through to unparented creation.
- **`report_ci_workflow_outcome`**: Accepts optional `github_client`; on
the create path, resolves originating context, sets `projectId` on the
new issue, and appends a "Triggered by" footer linking back to the PR
and originating EPAC issue.
- **`LinearIssueRequest.project_id`**: New optional field;
`create_issue` includes `projectId` in the mutation payload when set.
- **Workflow YAML**: Added `pull-requests: read` permission and
`GITHUB_TOKEN` env var.
## Trade-offs not taken
- Separate `scripts/ci/github_pr_client.py` module: kept inline with the
existing single-file pattern since the client is thin (one method) and
the script has no other modules.
- Caching across handler runs: unnecessary since each `workflow_run`
event is a single invocation.
- Cross-team ID parsing (e.g. `AUTO-XXX`): out of scope per the issue.
## Test plan
Unit tests cover all 6 AC scenarios plus `extract_linear_id` edge cases
(22 tests, all passing):
- (a) PR found + Linear ID matches + issue has projectId → inherits
projectId, footer present
- (b) PR found + Linear ID matches + issue unparented → no projectId,
footer present
- (c) PR found + no Linear ID regex match → no projectId, no footer
- (d) No PR for SHA (direct push) → no projectId, no footer
- (e) GitHub API failure → graceful no-op, issue still created
- (f) Linear project lookup failure → graceful no-op, issue still
created with footer
```
$ python3 -m pytest scripts/ci/tests/test_ci_failure_to_linear.py -v
22 passed in 0.05s
```
## Verification evidence
- All 22 unit tests pass
- Existing EPAC-2009/2010 dedup and auto-close behavior unchanged (dedup
path is untouched)
- Workflow actionlint passes (pre-commit hook validated)
Resolves EPAC-2011
Reviewer-Boundary: review-only
Co-authored-by: riddim-developer-bot <developer-bot@riddimsoftware.com>1 parent e5ea10f commit bb4bbd9
3 files changed
Lines changed: 332 additions & 11 deletions
File tree
- .github/workflows
- scripts/ci
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| 40 | + | |
40 | 41 | | |
41 | 42 | | |
42 | 43 | | |
| |||
63 | 64 | | |
64 | 65 | | |
65 | 66 | | |
| 67 | + | |
66 | 68 | | |
67 | 69 | | |
68 | 70 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
99 | 113 | | |
100 | 114 | | |
101 | 115 | | |
| |||
104 | 118 | | |
105 | 119 | | |
106 | 120 | | |
| 121 | + | |
107 | 122 | | |
108 | 123 | | |
109 | 124 | | |
| |||
123 | 138 | | |
124 | 139 | | |
125 | 140 | | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
126 | 188 | | |
127 | 189 | | |
128 | 190 | | |
| |||
148 | 210 | | |
149 | 211 | | |
150 | 212 | | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
151 | 232 | | |
152 | 233 | | |
153 | 234 | | |
| |||
158 | 239 | | |
159 | 240 | | |
160 | 241 | | |
| 242 | + | |
| 243 | + | |
161 | 244 | | |
162 | 245 | | |
163 | 246 | | |
| |||
386 | 469 | | |
387 | 470 | | |
388 | 471 | | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
389 | 500 | | |
390 | 501 | | |
391 | 502 | | |
392 | 503 | | |
393 | 504 | | |
| 505 | + | |
394 | 506 | | |
395 | 507 | | |
396 | 508 | | |
| |||
482 | 594 | | |
483 | 595 | | |
484 | 596 | | |
| 597 | + | |
| 598 | + | |
485 | 599 | | |
486 | 600 | | |
487 | 601 | | |
488 | | - | |
| 602 | + | |
489 | 603 | | |
490 | 604 | | |
491 | 605 | | |
492 | 606 | | |
| 607 | + | |
493 | 608 | | |
494 | 609 | | |
495 | 610 | | |
| |||
498 | 613 | | |
499 | 614 | | |
500 | 615 | | |
501 | | - | |
502 | | - | |
503 | | - | |
504 | | - | |
505 | | - | |
506 | | - | |
507 | | - | |
508 | | - | |
509 | | - | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
510 | 634 | | |
511 | 635 | | |
512 | 636 | | |
| |||
637 | 761 | | |
638 | 762 | | |
639 | 763 | | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
640 | 767 | | |
641 | 768 | | |
642 | 769 | | |
643 | 770 | | |
644 | 771 | | |
| 772 | + | |
645 | 773 | | |
646 | 774 | | |
647 | 775 | | |
| |||
0 commit comments