From 6f6837d070c1bc82ea584ee1c3626e553b5ea8de Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 19 May 2026 03:33:58 -0300 Subject: [PATCH] fix(triage): replace timelineItems with separate gh pr open search Remove the unsupported `timelineItems` field from `ghIssueView`, add `ghPrSearchOpen` wrapper, and synthesize `issue.timelineItems` in the main loop so `classifyIssue` stays unchanged. --- scripts/features/feature-triage.mjs | 12 +++++++++++ scripts/features/lib/github.mjs | 20 ++++++++++++++++++- .../unit/feature-triage/integration.test.mjs | 10 ++++------ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/scripts/features/feature-triage.mjs b/scripts/features/feature-triage.mjs index 4b91ebd894..e33257b26c 100755 --- a/scripts/features/feature-triage.mjs +++ b/scripts/features/feature-triage.mjs @@ -144,6 +144,18 @@ async function main(argv, env, deps = defaultDeps) { continue; } + // Synthesize timelineItems from open PR search (gh issue view doesn't expose timelineItems) + let openPrs = []; + try { + openPrs = deps.ghPrSearchOpen(args.owner, args.repo, num); + } catch (e) { + warnings.push({ level: "warn", issue: num, message: `open PR search failed: ${e.message}` }); + } + issue.timelineItems = openPrs.map((pr) => ({ + __typename: "CrossReferencedEvent", + source: { __typename: "PullRequest", state: "OPEN", number: pr.number }, + })); + const mergedPrs = deps.ghPrSearchMerged(args.owner, args.repo, num); const gitCommits = deps.gitLogGrep(`#${num}`).filter((c) => deps.gitIsAncestor(c.hash, "main")); const del = detectDelivered(num, { mergedPrs, changelog: changelogText, gitCommits }); diff --git a/scripts/features/lib/github.mjs b/scripts/features/lib/github.mjs index 800708db42..69252912eb 100644 --- a/scripts/features/lib/github.mjs +++ b/scripts/features/lib/github.mjs @@ -61,7 +61,24 @@ export function ghIssueView(owner, repo, number) { "--repo", `${owner}/${repo}`, "--json", - "number,title,url,body,state,stateReason,labels,author,assignees,createdAt,closedAt,comments,reactionGroups,timelineItems", + "number,title,url,body,state,stateReason,labels,author,assignees,createdAt,closedAt,comments,reactionGroups", + ]); +} + +export function ghPrSearchOpen(owner, repo, issueNumber) { + return runJson("gh", [ + "pr", + "list", + "--repo", + `${owner}/${repo}`, + "--state", + "open", + "--search", + `#${issueNumber}`, + "--json", + "number,title,body", + "--limit", + "10", ]); } @@ -141,6 +158,7 @@ export const defaultDeps = { ghIssueListFeatureTitled, ghIssueView, ghPrSearchMerged, + ghPrSearchOpen, gitTagsByDate, gitLogGrep, gitIsAncestor, diff --git a/tests/unit/feature-triage/integration.test.mjs b/tests/unit/feature-triage/integration.test.mjs index d72256396c..b56b2c564e 100644 --- a/tests/unit/feature-triage/integration.test.mjs +++ b/tests/unit/feature-triage/integration.test.mjs @@ -11,6 +11,7 @@ function makeDeps(state) { ghIssueListFeatureTitled: () => [], ghIssueView: (_o, _r, n) => state.issuesById[n], ghPrSearchMerged: (_o, _r, n) => state.prsByIssue[n] ?? [], + ghPrSearchOpen: (_o, _r, n) => state.openPrsByIssue?.[n] ?? [], gitTagsByDate: () => state.tags ?? [], gitLogGrep: (pattern) => state.commitsByPattern?.[pattern] ?? [], gitIsAncestor: () => true, @@ -109,14 +110,11 @@ describe("feature-triage integration", () => { assignees: [], comments: [], reactionGroups: [], - timelineItems: [ - { - __typename: "CrossReferencedEvent", - source: { __typename: "PullRequest", state: "OPEN", number: 999 }, - }, - ], }, }, + openPrsByIssue: { + 500: [{ number: 999, title: "WIP fix", body: "addresses #500" }], + }, prsByIssue: { 300: [ {