Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/actions/file/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ inputs:
screenshot_repository:
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."
required: false
open_grouped_issues:
description: "In the 'file' step, also open grouped issues which link to all issues with the same root cause"
required: false
default: "false"

outputs:
filings:
Expand Down
50 changes: 46 additions & 4 deletions .github/actions/file/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {Finding, ResolvedFiling, RepeatedFiling} from './types.d.js'
import type {Finding, ResolvedFiling, RepeatedFiling, FindingGroupIssue, Filing, IssueResponse} from './types.d.js'
import process from 'node:process'
import core from '@actions/core'
import {Octokit} from '@octokit/core'
Expand All @@ -11,6 +11,7 @@ import {isResolvedFiling} from './isResolvedFiling.js'
import {openIssue} from './openIssue.js'
import {reopenIssue} from './reopenIssue.js'
import {updateFilingsWithNewFindings} from './updateFilingsWithNewFindings.js'
import {OctokitResponse} from '@octokit/types'
const OctokitWithThrottling = Octokit.plugin(throttling)

export default async function () {
Expand All @@ -22,10 +23,12 @@ export default async function () {
const cachedFilings: (ResolvedFiling | RepeatedFiling)[] = JSON.parse(
core.getInput('cached_filings', {required: false}) || '[]',
)
const shouldOpenGroupedIssues = core.getBooleanInput('open_grouped_issues')
core.debug(`Input: 'findings: ${JSON.stringify(findings)}'`)
core.debug(`Input: 'repository: ${repoWithOwner}'`)
core.debug(`Input: 'screenshot_repository: ${screenshotRepo}'`)
core.debug(`Input: 'cached_filings: ${JSON.stringify(cachedFilings)}'`)
core.debug(`Input: 'open_grouped_issues: ${shouldOpenGroupedIssues}'`)

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

// Track new issues for grouping
const newIssuesByProblemShort: Record<string, FindingGroupIssue[]> = {}
const trackingIssueUrls: Record<string, string> = {}

for (const filing of filings) {
let response
let response: OctokitResponse<IssueResponse> | undefined
try {
if (isResolvedFiling(filing)) {
// Close the filing’s issue (if necessary)
Expand All @@ -58,8 +65,19 @@ export default async function () {
} else if (isNewFiling(filing)) {
// Open a new issue for the filing
response = await openIssue(octokit, repoWithOwner, filing.findings[0], screenshotRepo)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(filing as any).issue = {state: 'open'} as Issue
;(filing as Filing).issue = {state: 'open'} as Issue

// Track for grouping
if (shouldOpenGroupedIssues) {
const problemShort: string = filing.findings[0].problemShort
if (!newIssuesByProblemShort[problemShort]) {
newIssuesByProblemShort[problemShort] = []
}
newIssuesByProblemShort[problemShort].push({
url: response.data.html_url,
id: response.data.number,
})
}
} else if (isRepeatedFiling(filing)) {
// Reopen the filing's issue (if necessary) and update the body with the latest finding
response = await reopenIssue(
Expand Down Expand Up @@ -87,6 +105,30 @@ export default async function () {
}
}

// Open tracking issues for groups with >1 new issue and link back from each
// new issue
if (shouldOpenGroupedIssues) {
for (const [problemShort, issues] of Object.entries(newIssuesByProblemShort)) {
if (issues.length > 1) {
const title: string = `${problemShort} issues`
const body: string = `# ${problemShort} issues\n\n` + issues.map(issue => `- [ ] ${issue.url}`).join('\n')
try {
const trackingResponse = await octokit.request(`POST /repos/${repoWithOwner}/issues`, {
owner: repoWithOwner.split('/')[0],
repo: repoWithOwner.split('/')[1],
title,
body,
})
const trackingUrl: string = trackingResponse.data.html_url
trackingIssueUrls[problemShort] = trackingUrl
core.info(`Opened tracking issue for '${problemShort}' with ${issues.length} issues.`)
} catch (error) {
core.warning(`Failed to open tracking issue for '${problemShort}': ${error}`)
}
}
}
}

core.setOutput('filings', JSON.stringify(filings))
core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`)
core.info("Finished 'file' action")
Expand Down
13 changes: 13 additions & 0 deletions .github/actions/file/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export type Issue = {
state?: 'open' | 'reopened' | 'closed'
}

export type IssueResponse = {
id: number
node_id: string
number: number
html_url: string
title: string
}

export type ResolvedFiling = {
findings: never[]
issue: Issue
Expand All @@ -34,3 +42,8 @@ export type RepeatedFiling = {
}

export type Filing = ResolvedFiling | NewFiling | RepeatedFiling

export type FindingGroupIssue = {
url: string
id: number
}
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ inputs:
default: "false"
include_screenshots:
description: "Whether to capture screenshots and include links to them in the issue"
open_grouped_issues:
description: "In the 'file' step, also open grouped issues which link to all issues with the same problem"
required: false
default: "false"

Expand Down Expand Up @@ -94,6 +96,7 @@ runs:
token: ${{ inputs.token }}
cached_filings: ${{ steps.normalize_cache.outputs.value }}
screenshot_repository: ${{ github.repository }}
open_grouped_issues: ${{ inputs.open_grouped_issues }}
- if: ${{ steps.file.outputs.filings }}
name: Get issues from filings
id: get_issues_from_filings
Expand Down