Skip to content

Commit 17257b2

Browse files
JoyceZhulindseywild
andcommitted
Initial attempt at grouping related issues
Actually respect `open_tracking_issues` Feedback from code review Apply suggestions from Lindsey Co-authored-by: Lindsey Wild <35239154+lindseywild@users.noreply.github.com>
1 parent cc07ea1 commit 17257b2

4 files changed

Lines changed: 72 additions & 7 deletions

File tree

.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/src/index.ts

Lines changed: 60 additions & 7 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} from './types.d.js'
22
import process from 'node:process'
33
import 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<any> | 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,7 +105,42 @@ export default async function () {
87105
}
88106
}
89107

90-
core.setOutput('filings', JSON.stringify(filings))
91-
core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`)
92-
core.info("Finished 'file' action")
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(
112+
newIssuesByProblemShort,
113+
)) {
114+
if (issues.length > 1) {
115+
const title: string = `${problemShort} issues`;
116+
const body: string =
117+
`# ${problemShort} issues\n\n` +
118+
issues.map((issue) => `- [ ] ${issue.url}`).join("\n");
119+
try {
120+
const trackingResponse = await octokit.request(
121+
`POST /repos/${repoWithOwner}/issues`,
122+
{
123+
owner: repoWithOwner.split("/")[0],
124+
repo: repoWithOwner.split("/")[1],
125+
title,
126+
body,
127+
},
128+
);
129+
const trackingUrl: string = trackingResponse.data.html_url;
130+
trackingIssueUrls[problemShort] = trackingUrl;
131+
core.info(
132+
`Opened tracking issue for '${problemShort}' with ${issues.length} issues.`,
133+
);
134+
} catch (error) {
135+
core.warning(
136+
`Failed to open tracking issue for '${problemShort}': ${error}`,
137+
);
138+
}
139+
}
140+
}
141+
}
142+
143+
core.setOutput("filings", JSON.stringify(filings));
144+
core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`);
145+
core.info("Finished 'file' action");
93146
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,8 @@ export type RepeatedFiling = {
3434
}
3535

3636
export type Filing = ResolvedFiling | NewFiling | RepeatedFiling
37+
38+
export type FindingGroupIssue = {
39+
url: string
40+
id: number
41+
};

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ inputs:
3333
default: "false"
3434
include_screenshots:
3535
description: "Whether to capture screenshots and include links to them in the issue"
36+
open_grouped_issues:
37+
description: "In the 'file' step, also open grouped issues which link to all issues with the same problem"
3638
required: false
3739
default: "false"
3840

@@ -94,6 +96,7 @@ runs:
9496
token: ${{ inputs.token }}
9597
cached_filings: ${{ steps.normalize_cache.outputs.value }}
9698
screenshot_repository: ${{ github.repository }}
99+
open_grouped_issues: ${{ inputs.open_grouped_issues }}
97100
- if: ${{ steps.file.outputs.filings }}
98101
name: Get issues from filings
99102
id: get_issues_from_filings

0 commit comments

Comments
 (0)