|
1 | | -import type { Finding, Issue } from "./types.d.js"; |
| 1 | +import type { Finding, ResolvedFiling, RepeatedFiling } from "./types.d.js"; |
2 | 2 | import process from "node:process"; |
3 | 3 | import core from "@actions/core"; |
4 | 4 | import { Octokit } from "@octokit/core"; |
5 | 5 | import { throttling } from "@octokit/plugin-throttling"; |
6 | | -import { toFindingsMap } from "./toFindingsMap.js" |
7 | | -import { closeIssueForFinding } from "./closeIssueForFinding.js"; |
8 | | -import { openIssueForFinding } from "./openIssueForFinding.js"; |
| 6 | +import { Issue } from "./Issue.js"; |
| 7 | +import { closeIssue } from "./closeIssue.js"; |
| 8 | +import { isNewFiling } from "./isNewFiling.js"; |
| 9 | +import { isRepeatedFiling } from "./isRepeatedFiling.js"; |
| 10 | +import { isResolvedFiling } from "./isResolvedFiling.js"; |
| 11 | +import { openIssue } from "./openIssue.js"; |
| 12 | +import { reopenIssue } from "./reopenIssue.js"; |
| 13 | +import { updateFilingsWithNewFindings } from "./updateFilingsWithNewFindings.js"; |
9 | 14 | const OctokitWithThrottling = Octokit.plugin(throttling); |
10 | 15 |
|
11 | 16 | export default async function () { |
12 | 17 | core.info("Started 'file' action"); |
13 | | - const findings: Finding[] = JSON.parse(core.getInput('findings', { required: true })); |
14 | | - const repoWithOwner = core.getInput('repository', { required: true }); |
15 | | - const token = core.getInput('token', { required: true }); |
16 | | - const cachedFindings: Finding[] = JSON.parse(core.getInput('cached_findings', { required: false }) || "[]"); |
| 18 | + const findings: Finding[] = JSON.parse( |
| 19 | + core.getInput("findings", { required: true }) |
| 20 | + ); |
| 21 | + const repoWithOwner = core.getInput("repository", { required: true }); |
| 22 | + const token = core.getInput("token", { required: true }); |
| 23 | + const cachedFilings: (ResolvedFiling | RepeatedFiling)[] = JSON.parse( |
| 24 | + core.getInput("cached_results", { required: false }) || "[]" |
| 25 | + ); |
17 | 26 | core.debug(`Input: 'findings: ${JSON.stringify(findings)}'`); |
18 | 27 | core.debug(`Input: 'repository: ${repoWithOwner}'`); |
19 | | - core.debug(`Input: 'cached_findings: ${JSON.stringify(cachedFindings)}'`); |
20 | | - |
21 | | - const findingsMap = toFindingsMap(findings); |
22 | | - const cachedFindingsMap = toFindingsMap(cachedFindings); |
| 28 | + core.debug(`Input: 'cached_filings: ${JSON.stringify(cachedFilings)}'`); |
23 | 29 |
|
24 | 30 | const octokit = new OctokitWithThrottling({ |
25 | 31 | auth: token, |
26 | 32 | throttle: { |
27 | 33 | onRateLimit: (retryAfter, options, octokit, retryCount) => { |
28 | | - octokit.log.warn(`Request quota exhausted for request ${options.method} ${options.url}`); |
| 34 | + octokit.log.warn( |
| 35 | + `Request quota exhausted for request ${options.method} ${options.url}` |
| 36 | + ); |
29 | 37 | if (retryCount < 3) { |
30 | 38 | octokit.log.info(`Retrying after ${retryAfter} seconds!`); |
31 | 39 | return true; |
32 | 40 | } |
33 | 41 | }, |
34 | 42 | onSecondaryRateLimit: (retryAfter, options, octokit, retryCount) => { |
35 | | - octokit.log.warn(`Secondary rate limit hit for request ${options.method} ${options.url}`); |
| 43 | + octokit.log.warn( |
| 44 | + `Secondary rate limit hit for request ${options.method} ${options.url}` |
| 45 | + ); |
36 | 46 | if (retryCount < 3) { |
37 | 47 | octokit.log.info(`Retrying after ${retryAfter} seconds!`); |
38 | 48 | return true; |
39 | 49 | } |
40 | 50 | }, |
41 | | - } |
| 51 | + }, |
42 | 52 | }); |
43 | | - /** @deprecated */ |
44 | | - const closedIssues: Issue[] = []; |
45 | | - /** @deprecated */ |
46 | | - const openedIssues: Issue[] = []; |
47 | | - /** @deprecated */ |
48 | | - const repeatedIssues: Issue[] = []; |
49 | | - |
50 | | - for (const cachedFinding of cachedFindings) { |
51 | | - if (!findingsMap.has(`${cachedFinding.url};${cachedFinding.problemShort};${cachedFinding.html}`)) { |
52 | | - try { |
53 | | - // Finding was not found in the latest run, so close its issue (if necessary) |
54 | | - const response = await closeIssueForFinding(octokit, repoWithOwner, cachedFinding); |
55 | | - closedIssues.push({ |
56 | | - id: response.data.id, |
57 | | - nodeId: response.data.node_id, |
58 | | - url: response.data.html_url, |
59 | | - title: response.data.title, |
60 | | - }); |
61 | | - core.info(`Closed issue: ${response.data.title} (${repoWithOwner}#${response.data.number})`); |
62 | | - } catch (error) { |
63 | | - core.setFailed(`Failed to close issue for finding: ${error}`); |
64 | | - process.exit(1); |
65 | | - } |
66 | | - } |
67 | | - } |
| 53 | + const filings = updateFilingsWithNewFindings(cachedFilings, findings); |
68 | 54 |
|
69 | | - for (const finding of findings) { |
70 | | - const cachedIssueUrl = cachedFindingsMap.get(`${finding.url};${finding.problemShort};${finding.html}`)?.issueUrl |
71 | | - finding.issueUrl = cachedIssueUrl; |
| 55 | + for (const filing of filings) { |
| 56 | + let response; |
72 | 57 | try { |
73 | | - const response = await openIssueForFinding(octokit, repoWithOwner, finding); |
74 | | - finding.issueUrl = response.data.html_url; |
75 | | - if (response.data.html_url === cachedIssueUrl) { |
76 | | - // Finding was found in previous and latest runs, so reopen its issue (if necessary) |
77 | | - repeatedIssues.push({ |
78 | | - id: response.data.id, |
79 | | - nodeId: response.data.node_id, |
80 | | - url: response.data.html_url, |
81 | | - title: response.data.title, |
82 | | - }); |
83 | | - core.info(`Repeated issue: ${response.data.title} (${repoWithOwner}#${response.data.number})`); |
84 | | - } else { |
85 | | - // New finding was found in the latest run, so create its issue |
86 | | - openedIssues.push({ |
87 | | - id: response.data.id, |
88 | | - nodeId: response.data.node_id, |
89 | | - url: response.data.html_url, |
90 | | - title: response.data.title, |
91 | | - }); |
92 | | - core.info(`Created issue: ${response.data.title} (${repoWithOwner}#${response.data.number})`); |
| 58 | + if (isResolvedFiling(filing)) { |
| 59 | + // Close the filing’s issue (if necessary) |
| 60 | + response = await closeIssue(octokit, new Issue(filing.issue)); |
| 61 | + filing.issue.state = "closed"; |
| 62 | + } else if (isNewFiling(filing)) { |
| 63 | + // Open a new issue for the filing |
| 64 | + response = await openIssue(octokit, repoWithOwner, filing.findings[0]); |
| 65 | + (filing as any).issue = { state: "open" } as Issue; |
| 66 | + } else if (isRepeatedFiling(filing)) { |
| 67 | + // Reopen the filing’s issue (if necessary) |
| 68 | + response = await reopenIssue(octokit, new Issue(filing.issue)); |
| 69 | + filing.issue.state = "reopened"; |
| 70 | + } |
| 71 | + if (response?.data && filing.issue) { |
| 72 | + // Update the filing with the latest issue data |
| 73 | + filing.issue.id = response.data.id; |
| 74 | + filing.issue.nodeId = response.data.node_id; |
| 75 | + filing.issue.url = response.data.html_url; |
| 76 | + filing.issue.title = response.data.title; |
| 77 | + core.info( |
| 78 | + `Set issue ${response.data.title} (${repoWithOwner}#${response.data.number}) state to ${filing.issue.state}` |
| 79 | + ); |
93 | 80 | } |
94 | 81 | } catch (error) { |
95 | | - core.setFailed(`Failed to open/reopen issue for finding: ${error}`); |
| 82 | + core.setFailed(`Failed on filing: ${filing}\n${error}`); |
96 | 83 | process.exit(1); |
97 | 84 | } |
98 | 85 | } |
99 | 86 |
|
100 | | - // Deprecated outputs |
101 | | - core.setOutput("closed_issues", JSON.stringify(closedIssues)); |
102 | | - core.setOutput("opened_issues", JSON.stringify(openedIssues)); |
103 | | - core.setOutput("repeated_issues", JSON.stringify(repeatedIssues)); |
104 | | - core.setOutput("findings", JSON.stringify(findings)); |
105 | | - core.debug(`Output: 'closed_issues: ${JSON.stringify(closedIssues)}'`); |
106 | | - core.debug(`Output: 'opened_issues: ${JSON.stringify(openedIssues)}'`); |
107 | | - core.debug(`Output: 'repeated_issues: ${JSON.stringify(repeatedIssues)}'`); |
108 | | - core.debug(`Output: 'findings: ${JSON.stringify(findings)}'`); |
109 | | - core.warning("The 'closed_issues' output is deprecated and will be removed in v2."); |
110 | | - core.warning("The 'opened_issues' output is deprecated and will be removed in v2."); |
111 | | - core.warning("The 'repeated_issues' output is deprecated and will be removed in v2."); |
112 | | - core.warning("The 'findings' output is deprecated and will be removed in v2."); |
113 | | - |
| 87 | + core.setOutput("filings", JSON.stringify(filings)); |
| 88 | + core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`); |
114 | 89 | core.info("Finished 'file' action"); |
115 | 90 | } |
0 commit comments