From 47dbb726b6b82d28a2b797eb3bf060b0ec027a18 Mon Sep 17 00:00:00 2001 From: Naoki Oketani Date: Sun, 3 Oct 2021 09:26:16 +0900 Subject: [PATCH] feature: support create_issues, create_pr_comments flag (#93) * doc: support new parameter create_issues, create_pr_comments * feature: support create_pr_comments flag * feature: support create_issues flag --- README.md | 2 ++ __tests__/main.test.ts | 75 +++++++++++++++++++++++++++++++++++++++++- action.yml | 8 +++++ dist/index.js | 16 ++++++++- src/main.ts | 31 +++++++++++++---- 5 files changed, 123 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6c24ede..3e82eb2 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ If vulnerabilities are found by `npm audit`, Action triggered by push, schedule |github_token|true|N/A|GitHub Access Token.
${{ secrets.GITHUB_TOKEN }} is recommended.| |working_directory|false|N/A|The directory which contains package.json (since v1.4.0)| |dedupe_issues|false|false|If 'true', action will not create a new issue when one is already open (since v1.5.0)| +|create_issues|false|true|If 'false', action will not create a new issue even if vulnerabilities are found (since v1.8.0)| +|create_pr_comments|false|true|If 'false', action will not create a pr comment even if vulnerabilities are found (since v1.8.0)| ### Outputs diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 4a799f0..2315be1 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -1,14 +1,17 @@ import * as fs from 'fs' import * as path from 'path' +import {Octokit} from '@octokit/rest' import {mocked} from 'ts-jest/utils' import {Audit} from '../src/audit' import {run} from '../src/main' +import * as issue from '../src/issue' import * as pr from '../src/pr' jest.mock('../src/audit') +jest.mock('../src/issue') jest.mock('../src/pr') -describe('run', () => { +describe('run: pr', () => { beforeEach(() => { // initialize mock mocked(Audit).mockClear() @@ -21,6 +24,7 @@ describe('run', () => { '{ "event_name": "pull_request", "event": { "number": 100} }' process.env.INPUT_GITHUB_TOKEN = '***' process.env.GITHUB_REPOSITORY = 'alice/example' + process.env.INPUT_CREATE_PR_COMMENTS = 'true' }) test('does not call pr.createComment if vulnerabilities are not found', () => { @@ -88,4 +92,73 @@ describe('run', () => { expect(run).not.toThrowError() expect(pr.createComment).toHaveBeenCalled() }) + + test('does not call pr.createComment if create_pr_comments is set to false', () => { + process.env.INPUT_CREATE_PR_COMMENTS = 'false' + + mocked(Audit).mockImplementation((): any => { + return { + stdout: fs.readFileSync( + path.join(__dirname, 'testdata/audit/error.txt') + ), + status: 1, + run: (auditLevel: string): Promise => { + return Promise.resolve(void 0) + }, + foundVulnerability: (): boolean => { + return true + }, + strippedStdout: (): string => { + return path.join(__dirname, 'testdata/audit/error.txt') + } + } + }) + + expect(run).not.toThrowError() + expect(pr.createComment).not.toHaveBeenCalled() + }) +}) + +describe('run: issue', () => { + beforeEach(() => { + // initialize mock + mocked(Audit).mockClear() + mocked(issue).getExistingIssueNumber.mockClear() + + process.env.INPUT_AUDIT_LEVEL = 'low' + process.env.INPUT_PRODUCTION_FLAG = 'false' + process.env.INPUT_JSON_FLAG = 'false' + process.env.INPUT_GITHUB_CONTEXT = '{ "event_name": "push" }' + process.env.INPUT_GITHUB_TOKEN = '***' + process.env.GITHUB_REPOSITORY = 'alice/example' + process.env.INPUT_CREATE_ISSUES = 'true' + process.env.INPUT_DEDUPE_ISSUES = 'true' + }) + + test('does not call octokit.issues.create if create_issues is set to false', () => { + process.env.INPUT_CREATE_ISSUES = 'false' + + mocked(Audit).mockImplementation((): any => { + return { + stdout: fs.readFileSync( + path.join(__dirname, 'testdata/audit/error.txt') + ), + status: 1, + run: (auditLevel: string): Promise => { + return Promise.resolve(void 0) + }, + foundVulnerability: (): boolean => { + return true + }, + strippedStdout: (): string => { + return path.join(__dirname, 'testdata/audit/error.txt') + } + } + }) + + mocked(issue).getExistingIssueNumber.mockResolvedValue(null) + + expect(run).not.toThrowError() + expect(issue.getExistingIssueNumber).not.toHaveBeenCalled() + }) }) diff --git a/action.yml b/action.yml index 7942606..21122e0 100644 --- a/action.yml +++ b/action.yml @@ -38,6 +38,14 @@ inputs: description: 'Flag to de-dupe against open issues' default: 'false' required: false + create_issues: + description: 'Flag to create issues when vulnerabilities are found' + default: 'true' + required: false + create_pr_comments: + description: 'Flag to create pr comments when vulnerabilities are found' + default: 'true' + required: false outputs: npm_audit: description: 'The output of the npm audit report in a text format' diff --git a/dist/index.js b/dist/index.js index 8396df6..2299c3a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -209,12 +209,26 @@ function run() { auth: token }); if (ctx.event_name === 'pull_request') { - yield pr.createComment(token, github.context.repo.owner, github.context.repo.repo, ctx.event.number, audit.strippedStdout()); + const createPRComments = core.getInput('create_pr_comments'); + if (!['true', 'false'].includes(createPRComments)) { + throw new Error('Invalid input: create_pr_comments'); + } + if (createPRComments === 'true') { + yield pr.createComment(token, github.context.repo.owner, github.context.repo.repo, ctx.event.number, audit.strippedStdout()); + } core.setFailed('This repo has some vulnerabilities'); return; } else { core.debug('open an issue'); + const createIssues = core.getInput('create_issues'); + if (!['true', 'false'].includes(createIssues)) { + throw new Error('Invalid input: create_issues'); + } + if (createIssues === 'false') { + core.setFailed('This repo has some vulnerabilities'); + return; + } // remove control characters and create a code block const issueBody = audit.strippedStdout(); const option = issue.getIssueOption(issueBody); diff --git a/src/main.ts b/src/main.ts index 11e38a9..bf4a110 100644 --- a/src/main.ts +++ b/src/main.ts @@ -52,17 +52,34 @@ export async function run(): Promise { }) if (ctx.event_name === 'pull_request') { - await pr.createComment( - token, - github.context.repo.owner, - github.context.repo.repo, - ctx.event.number, - audit.strippedStdout() - ) + const createPRComments = core.getInput('create_pr_comments') + if (!['true', 'false'].includes(createPRComments)) { + throw new Error('Invalid input: create_pr_comments') + } + + if (createPRComments === 'true') { + await pr.createComment( + token, + github.context.repo.owner, + github.context.repo.repo, + ctx.event.number, + audit.strippedStdout() + ) + } core.setFailed('This repo has some vulnerabilities') return } else { core.debug('open an issue') + const createIssues = core.getInput('create_issues') + if (!['true', 'false'].includes(createIssues)) { + throw new Error('Invalid input: create_issues') + } + + if (createIssues === 'false') { + core.setFailed('This repo has some vulnerabilities') + return + } + // remove control characters and create a code block const issueBody = audit.strippedStdout() const option: IssueOption = issue.getIssueOption(issueBody)