Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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