diff --git a/README.md b/README.md index 0cad246..eac6130 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,12 @@ steps: assignees: JasonEtco, octocat milestone: 1 update_existing: true + search_existing: all ``` -The `assignees` and `milestone` speak for themselves, the `update_existing` param can be passed and set to `true` when you want to update an open issue with the **exact same title** when it exists and `false` if you don't want to create a new issue, but skip updating an existing one. +* The `assignees` and `milestone` speak for themselves. +* The `update_existing` param can be passed and set to `true` when you want to update an open issue with the **exact same title** when it exists and `false` if you don't want to create a new issue, but skip updating an existing one. +* The `search_existing` param lets you specify whether to search `open`, `closed`, or `all` existing issues for duplicates (default is `open`). ### Outputs diff --git a/action.yml b/action.yml index 8fc3fe1..0588fa5 100644 --- a/action.yml +++ b/action.yml @@ -20,6 +20,10 @@ inputs: update_existing: description: Update an open existing issue with the same title if it exists required: false + search_existing: + description: Existing types of issues to search for (comma-separated) + required: false + default: open outputs: number: description: Number of the issue that was created diff --git a/package-lock.json b/package-lock.json index ea81c62..9c0125a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2496,7 +2496,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true + "dev": true, + "optional": true }, "har-schema": { "version": "2.0.0", @@ -2778,8 +2779,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "optional": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -2797,7 +2797,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "optional": true, "requires": { "is-extglob": "^2.1.1" } @@ -2840,6 +2839,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "optional": true, "requires": { "is-docker": "^2.0.0" } @@ -4365,6 +4365,7 @@ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", "dev": true, + "optional": true, "requires": { "growly": "^1.3.0", "is-wsl": "^2.2.0", @@ -4379,6 +4380,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, + "optional": true, "requires": { "lru-cache": "^6.0.0" } @@ -4388,6 +4390,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "optional": true, "requires": { "isexe": "^2.0.0" } @@ -5219,7 +5222,8 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true + "dev": true, + "optional": true }, "signal-exit": { "version": "3.0.3", @@ -5882,7 +5886,8 @@ "version": "8.3.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "dev": true + "dev": true, + "optional": true }, "v8-to-istanbul": { "version": "7.0.0", diff --git a/src/action.ts b/src/action.ts index 2eb5048..45ebce0 100644 --- a/src/action.ts +++ b/src/action.ts @@ -9,6 +9,8 @@ import { FrontMatterAttributes, listToArray, setOutputs } from './helpers' export async function createAnIssue (tools: Toolkit) { const template = tools.inputs.filename || '.github/ISSUE_TEMPLATE.md' const assignees = tools.inputs.assignees + const searchExistingType = tools.inputs.search_existing || 'open' + let updateExisting: Boolean | null = null if (tools.inputs.update_existing) { if (tools.inputs.update_existing === 'true') { @@ -19,6 +21,7 @@ export async function createAnIssue (tools: Toolkit) { tools.exit.failure(`Invalid value update_existing=${tools.inputs.update_existing}, must be one of true or false`) } } + const env = nunjucks.configure({ autoescape: false }) env.addFilter('date', dateFilter) @@ -48,7 +51,7 @@ export async function createAnIssue (tools: Toolkit) { tools.log.info(`Fetching issues with title "${templated.title}"`) try { const existingIssues = await tools.github.search.issuesAndPullRequests({ - q: `is:open is:issue repo:${process.env.GITHUB_REPOSITORY} in:title ${templated.title}` + q: `is:${searchExistingType} is:issue repo:${process.env.GITHUB_REPOSITORY} in:title ${templated.title}` }) existingIssue = existingIssues.data.items.find(issue => issue.title === templated.title) } catch (err) { @@ -66,7 +69,7 @@ export async function createAnIssue (tools: Toolkit) { body: templated.body }) setOutputs(tools, issue) - tools.exit.success(`Updated issue ${existingIssue.title}#${issue.data.number}: ${issue.data.html_url}`) + tools.exit.success(`Updated issue ${existingIssue.title}#${existingIssue.number}: ${existingIssue.html_url}`) } catch (err) { tools.exit.failure(err) } diff --git a/tests/__snapshots__/index.test.ts.snap b/tests/__snapshots__/index.test.ts.snap index afc91ea..a45c21a 100644 --- a/tests/__snapshots__/index.test.ts.snap +++ b/tests/__snapshots__/index.test.ts.snap @@ -239,7 +239,7 @@ Array [ ] `; -exports[`create-an-issue updates an existing issue with the same title 1`] = ` +exports[`create-an-issue updates an existing open issue with the same title 1`] = ` Object { "assignees": Array [ "octocat", diff --git a/tests/index.test.ts b/tests/index.test.ts index 3f18922..de913da 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -151,6 +151,32 @@ describe('create-an-issue', () => { expect(tools.log.success).toHaveBeenCalled() }) + it('updates an existing open issue with the same title', async () => { + nock.cleanAll() + nock('https://api.github.com') + .get(/\/search\/issues.*/) + .query(parsedQuery => { + const q = parsedQuery['q'] + if (typeof(q) === 'string') { + const args = q.split(' ') + return (args.includes('is:open') || args.includes('is:closed')) + && args.includes('is:issue') + } else { + return false + } + }) + .reply(200, { + items: [{ number: 1, title: 'Hello!' }] + }) + .patch(/\/repos\/.*\/.*\/issues\/.*/).reply(200, {}) + + process.env.INPUT_UPDATE_EXISTING = 'true' + + await createAnIssue(tools) + expect(params).toMatchSnapshot() + expect(tools.exit.success).toHaveBeenCalled() + }) + it('checks the value of update_existing', async () => { process.env.INPUT_UPDATE_EXISTING = 'invalid' @@ -159,23 +185,28 @@ describe('create-an-issue', () => { expect(tools.exit.failure).toHaveBeenCalledWith('Invalid value update_existing=invalid, must be one of true or false') }) - it('updates an existing issue with the same title', async () => { + it('updates an existing closed issue with the same title', async () => { nock.cleanAll() nock('https://api.github.com') - .get(/\/search\/issues.*/).reply(200, { - items: [{ number: 1, title: 'Hello!', html_url: '/issues/1' }] - }) - .patch(/\/repos\/.*\/.*\/issues/).reply(200, (_, body: any) => { - return { - title: body.title, - number: 1, - html_url: '/issues/1' + .get(/\/search\/issues.*/) + .query(parsedQuery => { + const q = parsedQuery['q'] + if (typeof(q) === 'string') { + const args = q.split(' ') + return args.includes('is:all') && args.includes('is:issue') + } else { + return false } }) + .reply(200, { + items: [{ number: 1, title: 'Hello!', html_url: '/issues/1' }] + }) + .patch(/\/repos\/.*\/.*\/issues\/.*/).reply(200, {}) + process.env.INPUT_UPDATE_EXISTING = 'true' + process.env.INPUT_SEARCH_EXISTING = 'all' await createAnIssue(tools) - expect(params).toMatchSnapshot() expect(tools.exit.success).toHaveBeenCalledWith('Updated issue Hello!#1: /issues/1') })