Skip to content

Commit d75e16e

Browse files
committed
Merge branch 'main' into abdul/test-plugins
2 parents 0359d54 + 9e2af13 commit d75e16e

17 files changed

Lines changed: 189 additions & 122 deletions

.github/actions/auth/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/auth/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"playwright": "^1.58.2"
1818
},
1919
"devDependencies": {
20-
"@types/node": "^25.3.3",
20+
"@types/node": "^25.4.0",
2121
"typescript": "^5.9.3"
2222
}
2323
}

.github/actions/file/action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ inputs:
1717
screenshot_repository:
1818
description: "Repository (with owner) where screenshots are stored on the gh-cache branch. Defaults to the 'repository' input if not set. Required if issues are open in a different repo to construct proper screenshot URLs."
1919
required: false
20+
open_grouped_issues:
21+
description: "In the 'file' step, also open grouped issues which link to all issues with the same root cause"
22+
required: false
23+
default: "false"
2024

2125
outputs:
2226
filings:

.github/actions/file/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/file/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"@octokit/plugin-throttling": "^11.0.3"
1919
},
2020
"devDependencies": {
21-
"@types/node": "^25.3.3",
21+
"@types/node": "^25.4.0",
2222
"typescript": "^5.9.3"
2323
}
2424
}

.github/actions/file/src/index.ts

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {Finding, ResolvedFiling, RepeatedFiling} from './types.d.js'
1+
import type {Finding, ResolvedFiling, RepeatedFiling, FindingGroupIssue, Filing, IssueResponse} from './types.d.js'
22
import process from 'node:process'
33
import * as core from '@actions/core'
44
import {Octokit} from '@octokit/core'
@@ -11,6 +11,7 @@ import {isResolvedFiling} from './isResolvedFiling.js'
1111
import {openIssue} from './openIssue.js'
1212
import {reopenIssue} from './reopenIssue.js'
1313
import {updateFilingsWithNewFindings} from './updateFilingsWithNewFindings.js'
14+
import {OctokitResponse} from '@octokit/types'
1415
const OctokitWithThrottling = Octokit.plugin(throttling)
1516

1617
export default async function () {
@@ -22,10 +23,12 @@ export default async function () {
2223
const cachedFilings: (ResolvedFiling | RepeatedFiling)[] = JSON.parse(
2324
core.getInput('cached_filings', {required: false}) || '[]',
2425
)
26+
const shouldOpenGroupedIssues = core.getBooleanInput('open_grouped_issues')
2527
core.debug(`Input: 'findings: ${JSON.stringify(findings)}'`)
2628
core.debug(`Input: 'repository: ${repoWithOwner}'`)
2729
core.debug(`Input: 'screenshot_repository: ${screenshotRepo}'`)
2830
core.debug(`Input: 'cached_filings: ${JSON.stringify(cachedFilings)}'`)
31+
core.debug(`Input: 'open_grouped_issues: ${shouldOpenGroupedIssues}'`)
2932

3033
const octokit = new OctokitWithThrottling({
3134
auth: token,
@@ -48,8 +51,12 @@ export default async function () {
4851
})
4952
const filings = updateFilingsWithNewFindings(cachedFilings, findings)
5053

54+
// Track new issues for grouping
55+
const newIssuesByProblemShort: Record<string, FindingGroupIssue[]> = {}
56+
const trackingIssueUrls: Record<string, string> = {}
57+
5158
for (const filing of filings) {
52-
let response
59+
let response: OctokitResponse<IssueResponse> | undefined
5360
try {
5461
if (isResolvedFiling(filing)) {
5562
// Close the filing’s issue (if necessary)
@@ -58,8 +65,19 @@ export default async function () {
5865
} else if (isNewFiling(filing)) {
5966
// Open a new issue for the filing
6067
response = await openIssue(octokit, repoWithOwner, filing.findings[0], screenshotRepo)
61-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
62-
;(filing as any).issue = {state: 'open'} as Issue
68+
;(filing as Filing).issue = {state: 'open'} as Issue
69+
70+
// Track for grouping
71+
if (shouldOpenGroupedIssues) {
72+
const problemShort: string = filing.findings[0].problemShort
73+
if (!newIssuesByProblemShort[problemShort]) {
74+
newIssuesByProblemShort[problemShort] = []
75+
}
76+
newIssuesByProblemShort[problemShort].push({
77+
url: response.data.html_url,
78+
id: response.data.number,
79+
})
80+
}
6381
} else if (isRepeatedFiling(filing)) {
6482
// Reopen the filing's issue (if necessary) and update the body with the latest finding
6583
response = await reopenIssue(
@@ -87,6 +105,32 @@ export default async function () {
87105
}
88106
}
89107

108+
// Open tracking issues for groups with >1 new issue and link back from each
109+
// new issue
110+
if (shouldOpenGroupedIssues) {
111+
for (const [problemShort, issues] of Object.entries(newIssuesByProblemShort)) {
112+
if (issues.length > 1) {
113+
const capitalizedProblemShort = problemShort[0].toUpperCase() + problemShort.slice(1)
114+
const title: string = `${capitalizedProblemShort} issues`
115+
const body: string =
116+
`# ${capitalizedProblemShort} issues\n\n` + issues.map(issue => `- [ ] ${issue.url}`).join('\n')
117+
try {
118+
const trackingResponse = await octokit.request(`POST /repos/${repoWithOwner}/issues`, {
119+
owner: repoWithOwner.split('/')[0],
120+
repo: repoWithOwner.split('/')[1],
121+
title,
122+
body,
123+
})
124+
const trackingUrl: string = trackingResponse.data.html_url
125+
trackingIssueUrls[problemShort] = trackingUrl
126+
core.info(`Opened tracking issue for '${capitalizedProblemShort}' with ${issues.length} issues.`)
127+
} catch (error) {
128+
core.warning(`Failed to open tracking issue for '${capitalizedProblemShort}': ${error}`)
129+
}
130+
}
131+
}
132+
}
133+
90134
core.setOutput('filings', JSON.stringify(filings))
91135
core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`)
92136
core.info("Finished 'file' action")

.github/actions/file/src/types.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ export type Issue = {
1818
state?: 'open' | 'reopened' | 'closed'
1919
}
2020

21+
export type IssueResponse = {
22+
id: number
23+
node_id: string
24+
number: number
25+
html_url: string
26+
title: string
27+
}
28+
2129
export type ResolvedFiling = {
2230
findings: never[]
2331
issue: Issue
@@ -34,3 +42,8 @@ export type RepeatedFiling = {
3442
}
3543

3644
export type Filing = ResolvedFiling | NewFiling | RepeatedFiling
45+
46+
export type FindingGroupIssue = {
47+
url: string
48+
id: number
49+
}

.github/actions/find/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/find/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"playwright": "^1.58.2"
1919
},
2020
"devDependencies": {
21-
"@types/node": "^25.3.3",
21+
"@types/node": "^25.4.0",
2222
"typescript": "^5.9.3"
2323
}
2424
}

.github/actions/fix/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)