From fde50cdba782b5d63aa8ffb825addfbf41b35eb3 Mon Sep 17 00:00:00 2001 From: Simone Busoli Date: Thu, 27 May 2021 11:19:41 +0200 Subject: [PATCH] fix: octokit issue api also includes: - prettier - formatting - contributors - husky configuration fix --- .eslintrc | 2 +- .husky/pre-commit | 2 +- .prettierrc | 4 + dist/index.js | 478 ++++++++++--------- dist/issue.template.hbs | 11 +- jest.config.js | 4 +- package-lock.json | 36 ++ package.json | 15 +- src/index.js | 20 +- src/issue.js | 244 +++++----- src/issue.template.hbs | 11 +- src/log.js | 14 +- src/release-notify-action.js | 42 +- src/release.js | 50 +- test/issue.spec.js | 286 +++++++----- test/release-notify-action.spec.js | 134 +++--- test/release.spec.js | 78 ++-- test/testData.js | 707 +++++++++++++++-------------- 18 files changed, 1161 insertions(+), 977 deletions(-) create mode 100644 .prettierrc diff --git a/.eslintrc b/.eslintrc index 0b262519..d4871bd6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,5 +1,5 @@ { - "extends": "eslint:recommended", + "extends": ["eslint:recommended", "plugin:prettier/recommended"], "env": { "node": true, "es6": true, diff --git a/.husky/pre-commit b/.husky/pre-commit index 449fcdee..6d6ecc24 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -npm test +npm run build && git add dist diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..b2095be8 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "semi": false, + "singleQuote": true +} diff --git a/dist/index.js b/dist/index.js index cbb627ec..ae517c19 100644 --- a/dist/index.js +++ b/dist/index.js @@ -14348,125 +14348,131 @@ function wrappy (fn, cb) { /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; - -const github = __nccwpck_require__(5438); -const { logInfo } = __nccwpck_require__(653); - -const fs = __nccwpck_require__(5747); -const path = __nccwpck_require__(5622); -const { promisify } = __nccwpck_require__(1669); -const readFile = promisify(fs.readFile); -const handlebars = __nccwpck_require__(7492); - -const ISSUE_LABEL = 'notify-release'; -const ISSUE_TITLE = 'Release pending!'; -const STATE_OPEN = 'open'; -const STATE_CLOSED = 'closed'; - -function registerHandlebarHelpers(config) { - const { - commitMessageLines - } = config; - handlebars.registerHelper('commitMessage', function(content) { - if (!commitMessageLines || commitMessageLines < 0) { - return content; - } - return content - .split('\n') - .slice(0, commitMessageLines) - .join('\n') - .trim(); - }); - handlebars.registerHelper('substring', function(content, characters) { - return (content || "").substring(0, characters); - }); -} - -async function renderIssueBody(data) { - const templateFilePath = __nccwpck_require__.ab + "issue.template.hbs"; - const templateStringBuffer = await readFile(__nccwpck_require__.ab + "issue.template.hbs"); - const template = handlebars.compile(templateStringBuffer.toString()); - return template(data); -} - -async function createIssue(token, issueBody) { - const octokit = github.getOctokit(token); - - return octokit.issues.create({ - ...github.context.repo, - title: ISSUE_TITLE, - body: issueBody, - labels: [ISSUE_LABEL], - }); -} - -async function getLastOpenPendingIssue(token) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const pendingIssues = await octokit.request(`GET /repos/{owner}/{repo}/issues`, { - owner, - repo, - creator: 'app/github-actions', - state: STATE_OPEN, - sort: 'created', - direction: 'desc', - labels: ISSUE_LABEL - }); - - return pendingIssues.data.length ? pendingIssues.data[0] : null; -} - -async function updateLastOpenPendingIssue(token, issueBody, issueNo) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const updatedIssue = await octokit.request(`PATCH /repos/{owner}/{repo}/issues/${issueNo}`, { - owner, - repo, - title: ISSUE_TITLE, - body: issueBody - }); - - return updatedIssue.data.length ? updatedIssue.data[0] : null; -} - -async function createOrUpdateIssue(token, unreleasedCommits, pendingIssue, latestRelease, commitMessageLines) { - registerHandlebarHelpers({ - commitMessageLines - }); - const issueBody = await renderIssueBody({ - commits: unreleasedCommits, - latestRelease, - }) - if (pendingIssue) { - await updateLastOpenPendingIssue(token, issueBody, pendingIssue.number); - logInfo(`Issue ${pendingIssue.number} has been updated`); - } else { - const issueNo = await createIssue(token, issueBody); - logInfo(`New issue has been created. Issue No. - ${issueNo}`); - } -} - -async function closeIssue(token, issueNo) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - await octokit.request(`PATCH /repos/{owner}/{repo}/issues/${issueNo}`, { - owner, - repo, - state: STATE_CLOSED - }); - logInfo(`Closed issue no. - ${issueNo}`); -} - -module.exports = { - createIssue, - getLastOpenPendingIssue, - updateLastOpenPendingIssue, - createOrUpdateIssue, - closeIssue -}; + +const github = __nccwpck_require__(5438) +const { logInfo } = __nccwpck_require__(653) + +const fs = __nccwpck_require__(5747) +const path = __nccwpck_require__(5622) +const { promisify } = __nccwpck_require__(1669) +const readFile = promisify(fs.readFile) +const handlebars = __nccwpck_require__(7492) + +const ISSUE_LABEL = 'notify-release' +const ISSUE_TITLE = 'Release pending!' +const STATE_OPEN = 'open' +const STATE_CLOSED = 'closed' + +function registerHandlebarHelpers(config) { + const { commitMessageLines } = config + handlebars.registerHelper('commitMessage', function (content) { + if (!commitMessageLines || commitMessageLines < 0) { + return content + } + return content.split('\n').slice(0, commitMessageLines).join('\n').trim() + }) + handlebars.registerHelper('substring', function (content, characters) { + return (content || '').substring(0, characters) + }) +} + +async function renderIssueBody(data) { + const templateFilePath = __nccwpck_require__.ab + "issue.template.hbs" + const templateStringBuffer = await readFile(__nccwpck_require__.ab + "issue.template.hbs") + const template = handlebars.compile(templateStringBuffer.toString()) + return template(data) +} + +async function createIssue(token, issueBody) { + const octokit = github.getOctokit(token) + + return octokit.rest.issues.create({ + ...github.context.repo, + title: ISSUE_TITLE, + body: issueBody, + labels: [ISSUE_LABEL], + }) +} + +async function getLastOpenPendingIssue(token) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const pendingIssues = await octokit.request( + `GET /repos/{owner}/{repo}/issues`, + { + owner, + repo, + creator: 'app/github-actions', + state: STATE_OPEN, + sort: 'created', + direction: 'desc', + labels: ISSUE_LABEL, + } + ) + + return pendingIssues.data.length ? pendingIssues.data[0] : null +} + +async function updateLastOpenPendingIssue(token, issueBody, issueNo) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const updatedIssue = await octokit.request( + `PATCH /repos/{owner}/{repo}/issues/${issueNo}`, + { + owner, + repo, + title: ISSUE_TITLE, + body: issueBody, + } + ) + + return updatedIssue.data.length ? updatedIssue.data[0] : null +} + +async function createOrUpdateIssue( + token, + unreleasedCommits, + pendingIssue, + latestRelease, + commitMessageLines +) { + registerHandlebarHelpers({ + commitMessageLines, + }) + const issueBody = await renderIssueBody({ + commits: unreleasedCommits, + latestRelease, + }) + if (pendingIssue) { + await updateLastOpenPendingIssue(token, issueBody, pendingIssue.number) + logInfo(`Issue ${pendingIssue.number} has been updated`) + } else { + const issueNo = await createIssue(token, issueBody) + logInfo(`New issue has been created. Issue No. - ${issueNo}`) + } +} + +async function closeIssue(token, issueNo) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + await octokit.request(`PATCH /repos/{owner}/{repo}/issues/${issueNo}`, { + owner, + repo, + state: STATE_CLOSED, + }) + logInfo(`Closed issue no. - ${issueNo}`) +} + +module.exports = { + createIssue, + getLastOpenPendingIssue, + updateLastOpenPendingIssue, + createOrUpdateIssue, + closeIssue, +} /***/ }), @@ -14475,17 +14481,15 @@ module.exports = { /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; - -const { - debug, error, info, warning, -} = __nccwpck_require__(2186); - -const log = (logger) => (message) => logger(JSON.stringify(message)); - -exports.logDebug = log(debug); -exports.logError = log(error); -exports.logInfo = log(info); -exports.logWarning = log(warning); + +const { debug, error, info, warning } = __nccwpck_require__(2186) + +const log = (logger) => (message) => logger(JSON.stringify(message)) + +exports.logDebug = log(debug) +exports.logError = log(error) +exports.logInfo = log(info) +exports.logWarning = log(warning) /***/ }), @@ -14494,42 +14498,56 @@ exports.logWarning = log(warning); /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; - - -const { logInfo } = __nccwpck_require__(653); -const { getLatestRelease, getUnreleasedCommits } = __nccwpck_require__(2026); -const { createOrUpdateIssue, getLastOpenPendingIssue, closeIssue } = __nccwpck_require__(5465); - -async function runAction(token, staleDays, commitMessageLines) { - const latestRelease = await getLatestRelease(token); - - if (!latestRelease) { - return logInfo('Could not find latest release'); - } - - logInfo(`Latest release - name:${latestRelease.name}, published:${latestRelease.published_at}, -Tag:${latestRelease.tag_name}, author:${latestRelease.author.login}`); - - let pendingIssue = await getLastOpenPendingIssue(token); - const unreleasedCommits = await getUnreleasedCommits( - token, - latestRelease.published_at, - staleDays, - ); - - if (unreleasedCommits.length) { - await createOrUpdateIssue(token, unreleasedCommits, pendingIssue, latestRelease, commitMessageLines); - } else { - logInfo('No pending commits found'); - if (pendingIssue && Date.parse(latestRelease.published_at) > Date.parse(pendingIssue.updated_at)) { - await closeIssue(token, pendingIssue.number); - } - } -} - -module.exports = { - runAction, -}; + + +const { logInfo } = __nccwpck_require__(653) +const { getLatestRelease, getUnreleasedCommits } = __nccwpck_require__(2026) +const { + createOrUpdateIssue, + getLastOpenPendingIssue, + closeIssue, +} = __nccwpck_require__(5465) + +async function runAction(token, staleDays, commitMessageLines) { + const latestRelease = await getLatestRelease(token) + + if (!latestRelease) { + return logInfo('Could not find latest release') + } + + logInfo(`Latest release - name:${latestRelease.name}, published:${latestRelease.published_at}, +Tag:${latestRelease.tag_name}, author:${latestRelease.author.login}`) + + let pendingIssue = await getLastOpenPendingIssue(token) + const unreleasedCommits = await getUnreleasedCommits( + token, + latestRelease.published_at, + staleDays + ) + + if (unreleasedCommits.length) { + await createOrUpdateIssue( + token, + unreleasedCommits, + pendingIssue, + latestRelease, + commitMessageLines + ) + } else { + logInfo('No pending commits found') + if ( + pendingIssue && + Date.parse(latestRelease.published_at) > + Date.parse(pendingIssue.updated_at) + ) { + await closeIssue(token, pendingIssue.number) + } + } +} + +module.exports = { + runAction, +} /***/ }), @@ -14538,47 +14556,53 @@ module.exports = { /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; - -const github = __nccwpck_require__(5438); - -async function getLatestRelease(token) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const latestReleaseResponse = await octokit.request(`GET /repos/{owner}/{repo}/releases/latest`, { - owner, - repo, - }); - - return latestReleaseResponse.data; -} - -async function getUnreleasedCommits(token, latestReleaseDate, staleDays) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const allCommitsResp = await octokit.request(`GET /repos/{owner}/{repo}/commits`, { - owner, - repo, - since: latestReleaseDate, - }); - - const staleDate = new Date().getTime() - (staleDays * 24 * 60 * 60 * 1000); - - for (const commit of allCommitsResp.data) { - const commitDate = new Date(commit.commit.committer.date).getTime(); - if (commitDate < staleDate) { - return allCommitsResp.data; - } - } - - return []; -} - -module.exports = { - getLatestRelease, - getUnreleasedCommits, -}; + +const github = __nccwpck_require__(5438) + +async function getLatestRelease(token) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const latestReleaseResponse = await octokit.request( + `GET /repos/{owner}/{repo}/releases/latest`, + { + owner, + repo, + } + ) + + return latestReleaseResponse.data +} + +async function getUnreleasedCommits(token, latestReleaseDate, staleDays) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const allCommitsResp = await octokit.request( + `GET /repos/{owner}/{repo}/commits`, + { + owner, + repo, + since: latestReleaseDate, + } + ) + + const staleDate = new Date().getTime() - staleDays * 24 * 60 * 60 * 1000 + + for (const commit of allCommitsResp.data) { + const commitDate = new Date(commit.commit.committer.date).getTime() + if (commitDate < staleDate) { + return allCommitsResp.data + } + } + + return [] +} + +module.exports = { + getLatestRelease, + getUnreleasedCommits, +} /***/ }), @@ -14735,26 +14759,26 @@ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be in strict mode. (() => { "use strict"; - -const core = __nccwpck_require__(2186); -const { logInfo } = __nccwpck_require__(653); - -const { runAction } = __nccwpck_require__(1254); - -async function run() { - try { - const token = core.getInput('github-token', { required: true }); - const staleDays = Number(core.getInput('stale-days')); - const commitMessageLines = Number(core.getInput('commit-messages-lines')); - - return await runAction(token, staleDays, commitMessageLines); - } catch (error) { - logInfo(error.message); - core.setFailed(error.message); - } -} - -run(); + +const core = __nccwpck_require__(2186) +const { logInfo } = __nccwpck_require__(653) + +const { runAction } = __nccwpck_require__(1254) + +async function run() { + try { + const token = core.getInput('github-token', { required: true }) + const staleDays = Number(core.getInput('stale-days')) + const commitMessageLines = Number(core.getInput('commit-messages-lines')) + + return await runAction(token, staleDays, commitMessageLines) + } catch (error) { + logInfo(error.message) + core.setFailed(error.message) + } +} + +run() })(); diff --git a/dist/issue.template.hbs b/dist/issue.template.hbs index 5605d485..3cc3d94d 100644 --- a/dist/issue.template.hbs +++ b/dist/issue.template.hbs @@ -1,10 +1,11 @@ ### Pending commits since release [{{this.latestRelease.tag_name}}]({{this.latestRelease.html_url}}) - -Unreleased commits have been found which are pending release, please publish the changes. +Unreleased commits have been found which are pending release, please publish the +changes. {{#each commits}} -* [{{substring this.sha 7}}]({{this.html_url}}) {{commitMessage this.commit.message}} + * [{{substring this.sha 7}}]({{this.html_url}}) + {{commitMessage this.commit.message}} {{/each}} - -Issue generated by [github-actions-notify-release](https://github.com/nearform/github-action-notify-release). \ No newline at end of file +Issue generated by +[github-actions-notify-release](https://github.com/nearform/github-action-notify-release). diff --git a/jest.config.js b/jest.config.js index 06e08373..64230011 100644 --- a/jest.config.js +++ b/jest.config.js @@ -8,7 +8,7 @@ module.exports = { branches: 100, functions: 100, lines: 100, - } + }, }, - coveragePathIgnorePatterns: ['/node_modules/', '/dist/', '/husky/'] + coveragePathIgnorePatterns: ['/node_modules/', '/dist/', '/husky/'], } diff --git a/package-lock.json b/package-lock.json index c0cad300..084d8d82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1663,6 +1663,21 @@ } } }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -1818,6 +1833,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3199,6 +3220,21 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-format": { "version": "27.0.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.1.tgz", diff --git a/package.json b/package.json index fd4e6df0..98249bbd 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,10 @@ "type": "git", "url": "git+https://github.com/nearform/github-action-notify-release.git" }, - "author": "Esther Saimpou", + "author": "Esther Saimpou ", "contributors": [ - "Sameer Srivastava " + "Sameer Srivastava ", + "Simone Busoli " ], "license": "ISC", "bugs": { @@ -31,12 +32,10 @@ "devDependencies": { "@vercel/ncc": "^0.28.6", "eslint": "^7.27.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^3.4.0", "husky": "^6.0.0", - "jest": "^27.0.1" - }, - "husky": { - "hooks": { - "pre-commit": "npm run build && git add dist" - } + "jest": "^27.0.1", + "prettier": "^2.3.0" } } diff --git a/src/index.js b/src/index.js index 30401b20..602ada9f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,20 +1,20 @@ 'use strict' -const core = require('@actions/core'); -const { logInfo } = require('./log'); +const core = require('@actions/core') +const { logInfo } = require('./log') -const { runAction } = require('./release-notify-action'); +const { runAction } = require('./release-notify-action') async function run() { try { - const token = core.getInput('github-token', { required: true }); - const staleDays = Number(core.getInput('stale-days')); - const commitMessageLines = Number(core.getInput('commit-messages-lines')); + const token = core.getInput('github-token', { required: true }) + const staleDays = Number(core.getInput('stale-days')) + const commitMessageLines = Number(core.getInput('commit-messages-lines')) - return await runAction(token, staleDays, commitMessageLines); + return await runAction(token, staleDays, commitMessageLines) } catch (error) { - logInfo(error.message); - core.setFailed(error.message); + logInfo(error.message) + core.setFailed(error.message) } } -run(); +run() diff --git a/src/issue.js b/src/issue.js index 5377a8f3..eeae91e5 100644 --- a/src/issue.js +++ b/src/issue.js @@ -1,119 +1,125 @@ -'use strict' -const github = require('@actions/github'); -const { logInfo } = require('./log'); - -const fs = require('fs'); -const path = require('path'); -const { promisify } = require('util'); -const readFile = promisify(fs.readFile); -const handlebars = require('handlebars'); - -const ISSUE_LABEL = 'notify-release'; -const ISSUE_TITLE = 'Release pending!'; -const STATE_OPEN = 'open'; -const STATE_CLOSED = 'closed'; - -function registerHandlebarHelpers(config) { - const { - commitMessageLines - } = config; - handlebars.registerHelper('commitMessage', function(content) { - if (!commitMessageLines || commitMessageLines < 0) { - return content; - } - return content - .split('\n') - .slice(0, commitMessageLines) - .join('\n') - .trim(); - }); - handlebars.registerHelper('substring', function(content, characters) { - return (content || "").substring(0, characters); - }); -} - -async function renderIssueBody(data) { - const templateFilePath = path.resolve(__dirname, 'issue.template.hbs'); - const templateStringBuffer = await readFile(templateFilePath); - const template = handlebars.compile(templateStringBuffer.toString()); - return template(data); -} - -async function createIssue(token, issueBody) { - const octokit = github.getOctokit(token); - - return octokit.issues.create({ - ...github.context.repo, - title: ISSUE_TITLE, - body: issueBody, - labels: [ISSUE_LABEL], - }); -} - -async function getLastOpenPendingIssue(token) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const pendingIssues = await octokit.request(`GET /repos/{owner}/{repo}/issues`, { - owner, - repo, - creator: 'app/github-actions', - state: STATE_OPEN, - sort: 'created', - direction: 'desc', - labels: ISSUE_LABEL - }); - - return pendingIssues.data.length ? pendingIssues.data[0] : null; -} - -async function updateLastOpenPendingIssue(token, issueBody, issueNo) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const updatedIssue = await octokit.request(`PATCH /repos/{owner}/{repo}/issues/${issueNo}`, { - owner, - repo, - title: ISSUE_TITLE, - body: issueBody - }); - - return updatedIssue.data.length ? updatedIssue.data[0] : null; -} - -async function createOrUpdateIssue(token, unreleasedCommits, pendingIssue, latestRelease, commitMessageLines) { - registerHandlebarHelpers({ - commitMessageLines - }); - const issueBody = await renderIssueBody({ - commits: unreleasedCommits, - latestRelease, - }) - if (pendingIssue) { - await updateLastOpenPendingIssue(token, issueBody, pendingIssue.number); - logInfo(`Issue ${pendingIssue.number} has been updated`); - } else { - const issueNo = await createIssue(token, issueBody); - logInfo(`New issue has been created. Issue No. - ${issueNo}`); - } -} - -async function closeIssue(token, issueNo) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - await octokit.request(`PATCH /repos/{owner}/{repo}/issues/${issueNo}`, { - owner, - repo, - state: STATE_CLOSED - }); - logInfo(`Closed issue no. - ${issueNo}`); -} - -module.exports = { - createIssue, - getLastOpenPendingIssue, - updateLastOpenPendingIssue, - createOrUpdateIssue, - closeIssue -}; +'use strict' +const github = require('@actions/github') +const { logInfo } = require('./log') + +const fs = require('fs') +const path = require('path') +const { promisify } = require('util') +const readFile = promisify(fs.readFile) +const handlebars = require('handlebars') + +const ISSUE_LABEL = 'notify-release' +const ISSUE_TITLE = 'Release pending!' +const STATE_OPEN = 'open' +const STATE_CLOSED = 'closed' + +function registerHandlebarHelpers(config) { + const { commitMessageLines } = config + handlebars.registerHelper('commitMessage', function (content) { + if (!commitMessageLines || commitMessageLines < 0) { + return content + } + return content.split('\n').slice(0, commitMessageLines).join('\n').trim() + }) + handlebars.registerHelper('substring', function (content, characters) { + return (content || '').substring(0, characters) + }) +} + +async function renderIssueBody(data) { + const templateFilePath = path.resolve(__dirname, 'issue.template.hbs') + const templateStringBuffer = await readFile(templateFilePath) + const template = handlebars.compile(templateStringBuffer.toString()) + return template(data) +} + +async function createIssue(token, issueBody) { + const octokit = github.getOctokit(token) + + return octokit.rest.issues.create({ + ...github.context.repo, + title: ISSUE_TITLE, + body: issueBody, + labels: [ISSUE_LABEL], + }) +} + +async function getLastOpenPendingIssue(token) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const pendingIssues = await octokit.request( + `GET /repos/{owner}/{repo}/issues`, + { + owner, + repo, + creator: 'app/github-actions', + state: STATE_OPEN, + sort: 'created', + direction: 'desc', + labels: ISSUE_LABEL, + } + ) + + return pendingIssues.data.length ? pendingIssues.data[0] : null +} + +async function updateLastOpenPendingIssue(token, issueBody, issueNo) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const updatedIssue = await octokit.request( + `PATCH /repos/{owner}/{repo}/issues/${issueNo}`, + { + owner, + repo, + title: ISSUE_TITLE, + body: issueBody, + } + ) + + return updatedIssue.data.length ? updatedIssue.data[0] : null +} + +async function createOrUpdateIssue( + token, + unreleasedCommits, + pendingIssue, + latestRelease, + commitMessageLines +) { + registerHandlebarHelpers({ + commitMessageLines, + }) + const issueBody = await renderIssueBody({ + commits: unreleasedCommits, + latestRelease, + }) + if (pendingIssue) { + await updateLastOpenPendingIssue(token, issueBody, pendingIssue.number) + logInfo(`Issue ${pendingIssue.number} has been updated`) + } else { + const issueNo = await createIssue(token, issueBody) + logInfo(`New issue has been created. Issue No. - ${issueNo}`) + } +} + +async function closeIssue(token, issueNo) { + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + await octokit.request(`PATCH /repos/{owner}/{repo}/issues/${issueNo}`, { + owner, + repo, + state: STATE_CLOSED, + }) + logInfo(`Closed issue no. - ${issueNo}`) +} + +module.exports = { + createIssue, + getLastOpenPendingIssue, + updateLastOpenPendingIssue, + createOrUpdateIssue, + closeIssue, +} diff --git a/src/issue.template.hbs b/src/issue.template.hbs index 5605d485..3cc3d94d 100644 --- a/src/issue.template.hbs +++ b/src/issue.template.hbs @@ -1,10 +1,11 @@ ### Pending commits since release [{{this.latestRelease.tag_name}}]({{this.latestRelease.html_url}}) - -Unreleased commits have been found which are pending release, please publish the changes. +Unreleased commits have been found which are pending release, please publish the +changes. {{#each commits}} -* [{{substring this.sha 7}}]({{this.html_url}}) {{commitMessage this.commit.message}} + * [{{substring this.sha 7}}]({{this.html_url}}) + {{commitMessage this.commit.message}} {{/each}} - -Issue generated by [github-actions-notify-release](https://github.com/nearform/github-action-notify-release). \ No newline at end of file +Issue generated by +[github-actions-notify-release](https://github.com/nearform/github-action-notify-release). diff --git a/src/log.js b/src/log.js index a499a5dd..6675116d 100644 --- a/src/log.js +++ b/src/log.js @@ -1,11 +1,9 @@ 'use strict' -const { - debug, error, info, warning, -} = require('@actions/core'); +const { debug, error, info, warning } = require('@actions/core') -const log = (logger) => (message) => logger(JSON.stringify(message)); +const log = (logger) => (message) => logger(JSON.stringify(message)) -exports.logDebug = log(debug); -exports.logError = log(error); -exports.logInfo = log(info); -exports.logWarning = log(warning); +exports.logDebug = log(debug) +exports.logError = log(error) +exports.logInfo = log(info) +exports.logWarning = log(warning) diff --git a/src/release-notify-action.js b/src/release-notify-action.js index 7e3f7d75..5309ffd9 100644 --- a/src/release-notify-action.js +++ b/src/release-notify-action.js @@ -1,36 +1,50 @@ 'use strict' -const { logInfo } = require('./log'); -const { getLatestRelease, getUnreleasedCommits } = require('./release'); -const { createOrUpdateIssue, getLastOpenPendingIssue, closeIssue } = require('./issue'); +const { logInfo } = require('./log') +const { getLatestRelease, getUnreleasedCommits } = require('./release') +const { + createOrUpdateIssue, + getLastOpenPendingIssue, + closeIssue, +} = require('./issue') async function runAction(token, staleDays, commitMessageLines) { - const latestRelease = await getLatestRelease(token); + const latestRelease = await getLatestRelease(token) if (!latestRelease) { - return logInfo('Could not find latest release'); + return logInfo('Could not find latest release') } logInfo(`Latest release - name:${latestRelease.name}, published:${latestRelease.published_at}, -Tag:${latestRelease.tag_name}, author:${latestRelease.author.login}`); +Tag:${latestRelease.tag_name}, author:${latestRelease.author.login}`) - let pendingIssue = await getLastOpenPendingIssue(token); + let pendingIssue = await getLastOpenPendingIssue(token) const unreleasedCommits = await getUnreleasedCommits( token, latestRelease.published_at, - staleDays, - ); + staleDays + ) if (unreleasedCommits.length) { - await createOrUpdateIssue(token, unreleasedCommits, pendingIssue, latestRelease, commitMessageLines); + await createOrUpdateIssue( + token, + unreleasedCommits, + pendingIssue, + latestRelease, + commitMessageLines + ) } else { - logInfo('No pending commits found'); - if (pendingIssue && Date.parse(latestRelease.published_at) > Date.parse(pendingIssue.updated_at)) { - await closeIssue(token, pendingIssue.number); + logInfo('No pending commits found') + if ( + pendingIssue && + Date.parse(latestRelease.published_at) > + Date.parse(pendingIssue.updated_at) + ) { + await closeIssue(token, pendingIssue.number) } } } module.exports = { runAction, -}; +} diff --git a/src/release.js b/src/release.js index d2c4a6b6..d01fb07f 100644 --- a/src/release.js +++ b/src/release.js @@ -1,41 +1,47 @@ 'use strict' -const github = require('@actions/github'); +const github = require('@actions/github') async function getLatestRelease(token) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const latestReleaseResponse = await octokit.request(`GET /repos/{owner}/{repo}/releases/latest`, { - owner, - repo, - }); + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const latestReleaseResponse = await octokit.request( + `GET /repos/{owner}/{repo}/releases/latest`, + { + owner, + repo, + } + ) - return latestReleaseResponse.data; + return latestReleaseResponse.data } async function getUnreleasedCommits(token, latestReleaseDate, staleDays) { - const octokit = github.getOctokit(token); - const { owner, repo } = github.context.repo; - - const allCommitsResp = await octokit.request(`GET /repos/{owner}/{repo}/commits`, { - owner, - repo, - since: latestReleaseDate, - }); + const octokit = github.getOctokit(token) + const { owner, repo } = github.context.repo + + const allCommitsResp = await octokit.request( + `GET /repos/{owner}/{repo}/commits`, + { + owner, + repo, + since: latestReleaseDate, + } + ) - const staleDate = new Date().getTime() - (staleDays * 24 * 60 * 60 * 1000); + const staleDate = new Date().getTime() - staleDays * 24 * 60 * 60 * 1000 for (const commit of allCommitsResp.data) { - const commitDate = new Date(commit.commit.committer.date).getTime(); + const commitDate = new Date(commit.commit.committer.date).getTime() if (commitDate < staleDate) { - return allCommitsResp.data; + return allCommitsResp.data } } - return []; + return [] } module.exports = { getLatestRelease, getUnreleasedCommits, -}; +} diff --git a/test/issue.spec.js b/test/issue.spec.js index 61dc86ba..45e8ed46 100644 --- a/test/issue.spec.js +++ b/test/issue.spec.js @@ -1,123 +1,163 @@ -'use strict'; - -const { getOctokit } = require('@actions/github'); - -const issue = require('../src/issue'); - -const { - unreleasedCommitsData1, -} = require('./testData'); - -const token = 'dummytoken'; -const owner = 'sameer'; -const repo = 'testrepo'; - -jest.mock('../src/log', () => ({ - logInfo: jest.fn(), -})); - -jest.mock('@actions/github', () => ({ - getOctokit: jest.fn(), - context: { repo: { owner, repo} }, -})); - -test('Creates an issue', async () => { - getOctokit.mockReturnValue( - { issues: { create: async () => ({ data: { number: 9 } }) } }); - const issueTitle = 'Release pending!'; - const issueBody = 'issue has been created with pending commits'; - - const issueResponse = await issue.createIssue(token, issueTitle, issueBody); - expect(issueResponse.data.number).toStrictEqual(9); -}); - -test('Throws if something went wrong in creating an issue', async () => { - getOctokit.mockImplementation(() => null); - const issueTitle = 'Release pending!'; - const issueBody = 'issue has been created with pending commits'; - - await expect(issue.createIssue(token, issueTitle, issueBody)).rejects.toThrow(); -}); - -test('Updates an issue', async () => { - getOctokit.mockReturnValue({ request: async () => ({ data: [{ number: 9 }] }) }); - const issueTitle = 'Release pending!'; - const issueNo = 9; - const issueBody = 'issue has been updated with pending commits'; - - const updatedIssue = await issue.updateLastOpenPendingIssue(token, issueTitle, issueBody, issueNo); - expect(updatedIssue.number).toStrictEqual(9); -}); - -test('Updates an issue', async () => { - getOctokit.mockReturnValue({ request: async () => ({ data: [] }) }); - const issueTitle = 'Release pending!'; - const issueNo = 9; - const issueBody = 'issue has been updated with pending commits'; - - const updatedIssue = await issue.updateLastOpenPendingIssue(token, issueTitle, issueBody, issueNo); - expect(updatedIssue).toStrictEqual(null); -}); - - -test('Gets last open pending issue', async () => { - const latestReleaseDate = 'test date'; - getOctokit.mockReturnValue({ request: async () => ({ data: [{ number: 9 }] }) }); - - const pendingIssue = await issue.getLastOpenPendingIssue(token, latestReleaseDate); - expect(pendingIssue.number).toStrictEqual(9); -}); - -test('Get last open pending issue returns invalid result', async () => { - const latestReleaseDate = 'test date'; - getOctokit.mockReturnValue({ request: async () => ({ data: [] }) }); - - const pendingIssue = await issue.getLastOpenPendingIssue(token, latestReleaseDate); - expect(pendingIssue).toStrictEqual(null); -}); - -test('Close an issue', async () => { - const request = jest.fn() - getOctokit.mockReturnValue({request}); - - await issue.closeIssue(token, '1'); - expect(request).toHaveBeenCalledWith('PATCH /repos/{owner}/{repo}/issues/1', { - owner, - repo, - state: 'closed', - }); -}); - -test('Create an issue when no existing issue exists', async () => { - const create = jest.fn() - getOctokit.mockReturnValue({issues: {create}}); - - await issue.createOrUpdateIssue(token, unreleasedCommitsData1, null, 'test-date'); - expect(create).toHaveBeenCalled(); -}); - -test('Update an issue when exists', async () => { - const request = jest.fn() - getOctokit.mockReturnValue({request}); - request.mockResolvedValue({ - data: {} - }) - - await issue.createOrUpdateIssue(token, unreleasedCommitsData1, {number: '1'}, 'test-date', 1); - expect(request).toHaveBeenCalledWith('PATCH /repos/{owner}/{repo}/issues/1', { - owner, - repo, - title: expect.any(String), - body: expect.any(String), - }); -}); - -test('Create issue body that contains commits shortened SHA identifiers', async () => { - const create = jest.fn() - getOctokit.mockReturnValue({issues: {create}}); - - await issue.createOrUpdateIssue(token, unreleasedCommitsData1, null, 'test-date'); - expect(create).toHaveBeenCalledWith(expect.objectContaining({ - body: expect.stringContaining(unreleasedCommitsData1[0].sha.substring(0, 7)) - })); -}); \ No newline at end of file +'use strict' + +const { getOctokit } = require('@actions/github') + +const issue = require('../src/issue') + +const { unreleasedCommitsData1 } = require('./testData') + +const token = 'dummytoken' +const owner = 'sameer' +const repo = 'testrepo' + +jest.mock('../src/log', () => ({ + logInfo: jest.fn(), +})) + +jest.mock('@actions/github', () => ({ + getOctokit: jest.fn(), + context: { repo: { owner, repo } }, +})) + +test('Creates an issue', async () => { + getOctokit.mockReturnValue({ + rest: { issues: { create: async () => ({ data: { number: 9 } }) } }, + }) + const issueTitle = 'Release pending!' + const issueBody = 'issue has been created with pending commits' + + const issueResponse = await issue.createIssue(token, issueTitle, issueBody) + expect(issueResponse.data.number).toStrictEqual(9) +}) + +test('Throws if something went wrong in creating an issue', async () => { + getOctokit.mockImplementation(() => null) + const issueTitle = 'Release pending!' + const issueBody = 'issue has been created with pending commits' + + await expect( + issue.createIssue(token, issueTitle, issueBody) + ).rejects.toThrow() +}) + +test('Updates an issue', async () => { + getOctokit.mockReturnValue({ + request: async () => ({ data: [{ number: 9 }] }), + }) + const issueTitle = 'Release pending!' + const issueNo = 9 + const issueBody = 'issue has been updated with pending commits' + + const updatedIssue = await issue.updateLastOpenPendingIssue( + token, + issueTitle, + issueBody, + issueNo + ) + expect(updatedIssue.number).toStrictEqual(9) +}) + +test('Updates an issue', async () => { + getOctokit.mockReturnValue({ request: async () => ({ data: [] }) }) + const issueTitle = 'Release pending!' + const issueNo = 9 + const issueBody = 'issue has been updated with pending commits' + + const updatedIssue = await issue.updateLastOpenPendingIssue( + token, + issueTitle, + issueBody, + issueNo + ) + expect(updatedIssue).toStrictEqual(null) +}) + +test('Gets last open pending issue', async () => { + const latestReleaseDate = 'test date' + getOctokit.mockReturnValue({ + request: async () => ({ data: [{ number: 9 }] }), + }) + + const pendingIssue = await issue.getLastOpenPendingIssue( + token, + latestReleaseDate + ) + expect(pendingIssue.number).toStrictEqual(9) +}) + +test('Get last open pending issue returns invalid result', async () => { + const latestReleaseDate = 'test date' + getOctokit.mockReturnValue({ request: async () => ({ data: [] }) }) + + const pendingIssue = await issue.getLastOpenPendingIssue( + token, + latestReleaseDate + ) + expect(pendingIssue).toStrictEqual(null) +}) + +test('Close an issue', async () => { + const request = jest.fn() + getOctokit.mockReturnValue({ request }) + + await issue.closeIssue(token, '1') + expect(request).toHaveBeenCalledWith('PATCH /repos/{owner}/{repo}/issues/1', { + owner, + repo, + state: 'closed', + }) +}) + +test('Create an issue when no existing issue exists', async () => { + const create = jest.fn() + getOctokit.mockReturnValue({ rest: { issues: { create } } }) + + await issue.createOrUpdateIssue( + token, + unreleasedCommitsData1, + null, + 'test-date' + ) + expect(create).toHaveBeenCalled() +}) + +test('Update an issue when exists', async () => { + const request = jest.fn() + getOctokit.mockReturnValue({ request }) + request.mockResolvedValue({ + data: {}, + }) + + await issue.createOrUpdateIssue( + token, + unreleasedCommitsData1, + { number: '1' }, + 'test-date', + 1 + ) + expect(request).toHaveBeenCalledWith('PATCH /repos/{owner}/{repo}/issues/1', { + owner, + repo, + title: expect.any(String), + body: expect.any(String), + }) +}) + +test('Create issue body that contains commits shortened SHA identifiers', async () => { + const create = jest.fn() + getOctokit.mockReturnValue({ rest: { issues: { create } } }) + + await issue.createOrUpdateIssue( + token, + unreleasedCommitsData1, + null, + 'test-date' + ) + expect(create).toHaveBeenCalledWith( + expect.objectContaining({ + body: expect.stringContaining( + unreleasedCommitsData1[0].sha.substring(0, 7) + ), + }) + ) +}) diff --git a/test/release-notify-action.spec.js b/test/release-notify-action.spec.js index 1c8ff864..adb94df9 100644 --- a/test/release-notify-action.spec.js +++ b/test/release-notify-action.spec.js @@ -1,99 +1,111 @@ 'use strict' -const { runAction } = require('../src/release-notify-action'); -const release = require('../src/release'); -const issue = require('../src/issue'); +const { runAction } = require('../src/release-notify-action') +const release = require('../src/release') +const issue = require('../src/issue') const { allReleasesData: allReleases, unreleasedCommitsData1, pendingIssues, -} = require('./testData'); +} = require('./testData') jest.mock('../src/log', () => ({ logInfo: jest.fn(), -})); +})) jest.mock('../src/release', () => ({ getLatestRelease: jest.fn(), getUnreleasedCommits: jest.fn(), -})); +})) jest.mock('../src/issue', () => ({ createOrUpdateIssue: jest.fn(), getLastOpenPendingIssue: jest.fn(), closeIssue: jest.fn(), -})); +})) beforeEach(() => { - release.getLatestRelease.mockReset(); - release.getUnreleasedCommits.mockReset(); - issue.createOrUpdateIssue.mockReset(); - issue.getLastOpenPendingIssue.mockReset(); - issue.closeIssue.mockReset(); -}); + release.getLatestRelease.mockReset() + release.getUnreleasedCommits.mockReset() + issue.createOrUpdateIssue.mockReset() + issue.getLastOpenPendingIssue.mockReset() + issue.closeIssue.mockReset() +}) -const token = 'dummyToken'; +const token = 'dummyToken' test('Create issue for unreleased commits (no existing issues)', async () => { - release.getLatestRelease.mockResolvedValue(allReleases.data[0]); - issue.getLastOpenPendingIssue.mockResolvedValue(null); - release.getUnreleasedCommits.mockResolvedValue(unreleasedCommitsData1); - - await runAction(token, 1, 1); - - expect(release.getLatestRelease).toBeCalledWith(token); - expect(issue.getLastOpenPendingIssue).toBeCalledWith(token); - expect(issue.createOrUpdateIssue).toBeCalledWith(token, unreleasedCommitsData1, null, allReleases.data[0], 1); - expect(issue.closeIssue).not.toHaveBeenCalled(); -}); + release.getLatestRelease.mockResolvedValue(allReleases.data[0]) + issue.getLastOpenPendingIssue.mockResolvedValue(null) + release.getUnreleasedCommits.mockResolvedValue(unreleasedCommitsData1) + + await runAction(token, 1, 1) + + expect(release.getLatestRelease).toBeCalledWith(token) + expect(issue.getLastOpenPendingIssue).toBeCalledWith(token) + expect(issue.createOrUpdateIssue).toBeCalledWith( + token, + unreleasedCommitsData1, + null, + allReleases.data[0], + 1 + ) + expect(issue.closeIssue).not.toHaveBeenCalled() +}) test('Update issue for unreleased commits (issue already exists)', async () => { - release.getLatestRelease.mockResolvedValue(allReleases.data[0]); - issue.getLastOpenPendingIssue.mockResolvedValue(pendingIssues[0]); - release.getUnreleasedCommits.mockResolvedValue(unreleasedCommitsData1); - - await runAction(token, 1, 1); - - expect(release.getLatestRelease).toBeCalledWith(token); - expect(issue.getLastOpenPendingIssue).toBeCalledWith(token); - expect(issue.createOrUpdateIssue).toBeCalledWith(token, unreleasedCommitsData1, pendingIssues[0], allReleases.data[0], 1); - expect(issue.closeIssue).not.toHaveBeenCalled(); -}); + release.getLatestRelease.mockResolvedValue(allReleases.data[0]) + issue.getLastOpenPendingIssue.mockResolvedValue(pendingIssues[0]) + release.getUnreleasedCommits.mockResolvedValue(unreleasedCommitsData1) + + await runAction(token, 1, 1) + + expect(release.getLatestRelease).toBeCalledWith(token) + expect(issue.getLastOpenPendingIssue).toBeCalledWith(token) + expect(issue.createOrUpdateIssue).toBeCalledWith( + token, + unreleasedCommitsData1, + pendingIssues[0], + allReleases.data[0], + 1 + ) + expect(issue.closeIssue).not.toHaveBeenCalled() +}) test('Close issue when there is one pending and no unreleased commits', async () => { - release.getLatestRelease.mockResolvedValue(allReleases.data[0]); - issue.getLastOpenPendingIssue.mockResolvedValue(pendingIssues[0]); - release.getUnreleasedCommits.mockResolvedValue([]); + release.getLatestRelease.mockResolvedValue(allReleases.data[0]) + issue.getLastOpenPendingIssue.mockResolvedValue(pendingIssues[0]) + release.getUnreleasedCommits.mockResolvedValue([]) - await runAction(token, 1, 1); + await runAction(token, 1, 1) - expect(release.getLatestRelease).toBeCalledWith(token); - expect(issue.getLastOpenPendingIssue).toBeCalledWith(token); - expect(issue.createOrUpdateIssue).not.toHaveBeenCalled(); - expect(issue.closeIssue).toHaveBeenCalledWith(token, pendingIssues[0].number); -}); + expect(release.getLatestRelease).toBeCalledWith(token) + expect(issue.getLastOpenPendingIssue).toBeCalledWith(token) + expect(issue.createOrUpdateIssue).not.toHaveBeenCalled() + expect(issue.closeIssue).toHaveBeenCalledWith(token, pendingIssues[0].number) +}) test('Do nothing when there is one issue pending and no new releases', async () => { - release.getLatestRelease.mockResolvedValue(allReleases.data[1]); - issue.getLastOpenPendingIssue.mockResolvedValue(pendingIssues[0]); - release.getUnreleasedCommits.mockResolvedValue([]); + release.getLatestRelease.mockResolvedValue(allReleases.data[1]) + issue.getLastOpenPendingIssue.mockResolvedValue(pendingIssues[0]) + release.getUnreleasedCommits.mockResolvedValue([]) - await runAction(token, 1, 1); + await runAction(token, 1, 1) - expect(release.getLatestRelease).toBeCalledWith(token); - expect(issue.getLastOpenPendingIssue).toBeCalledWith(token); - expect(issue.createOrUpdateIssue).not.toHaveBeenCalled(); - expect(issue.closeIssue).not.toHaveBeenCalled(); -}); + expect(release.getLatestRelease).toBeCalledWith(token) + expect(issue.getLastOpenPendingIssue).toBeCalledWith(token) + expect(issue.createOrUpdateIssue).not.toHaveBeenCalled() + expect(issue.closeIssue).not.toHaveBeenCalled() +}) test('Do nothing when no releases found', async () => { - release.getLatestRelease.mockResolvedValue(null); + release.getLatestRelease.mockResolvedValue(null) - await runAction(token, 1, 1); + await runAction(token, 1, 1) - expect(release.getLatestRelease).toBeCalledWith(token); - expect(issue.getLastOpenPendingIssue).not.toHaveBeenCalled(); - expect(issue.createOrUpdateIssue).not.toHaveBeenCalled(); - expect(issue.closeIssue).not.toHaveBeenCalled(); -}); \ No newline at end of file + expect(release.getLatestRelease).toBeCalledWith(token) + expect(issue.getLastOpenPendingIssue).not.toHaveBeenCalled() + expect(issue.createOrUpdateIssue).not.toHaveBeenCalled() + expect(issue.closeIssue).not.toHaveBeenCalled() +}) diff --git a/test/release.spec.js b/test/release.spec.js index c5bad1b1..7998d71c 100644 --- a/test/release.spec.js +++ b/test/release.spec.js @@ -1,6 +1,6 @@ 'use strict' -const { getOctokit } = require('@actions/github'); -const { getLatestRelease, getUnreleasedCommits } = require('../src/release'); +const { getOctokit } = require('@actions/github') +const { getLatestRelease, getUnreleasedCommits } = require('../src/release') const { allCommitsData: allCommits, @@ -8,47 +8,63 @@ const { unreleasedCommitsData0, unreleasedCommitsData1, allReleasesNoData, -} = require('./testData'); +} = require('./testData') -const token = 'dummytoken'; +const token = 'dummytoken' jest.mock('@actions/github', () => ({ getOctokit: jest.fn(), context: { repo: { owner: 'sameer', repo: 'testrepo' } }, -})); +})) test('Gets the latest release of the repository', async () => { - getOctokit.mockReturnValue({ request: async () => ({ data: allReleases.data[0] })}); - const latestReleaseResponse = await getLatestRelease(token); - expect(latestReleaseResponse).toStrictEqual(allReleases.data[0]); -}); + getOctokit.mockReturnValue({ + request: async () => ({ data: allReleases.data[0] }), + }) + const latestReleaseResponse = await getLatestRelease(token) + expect(latestReleaseResponse).toStrictEqual(allReleases.data[0]) +}) test('Retuns null if no releases found', async () => { - getOctokit.mockReturnValue({ request: async () => ({ data: allReleasesNoData.data[0] })}); - const latestReleaseResponse = await getLatestRelease(token); - expect(latestReleaseResponse).toBeUndefined(); -}); + getOctokit.mockReturnValue({ + request: async () => ({ data: allReleasesNoData.data[0] }), + }) + const latestReleaseResponse = await getLatestRelease(token) + expect(latestReleaseResponse).toBeUndefined() +}) test('Gets the unreleased commits with stale-days as 0', async () => { - getOctokit.mockReturnValue({ request: async () => allCommits }); - const daysToIgnore = 0; - const latestReleaseDate = allReleases.data[0].created_at; - const allCommitsResponse = await getUnreleasedCommits(token, latestReleaseDate, daysToIgnore); - expect(allCommitsResponse).toStrictEqual(unreleasedCommitsData1); -}); + getOctokit.mockReturnValue({ request: async () => allCommits }) + const daysToIgnore = 0 + const latestReleaseDate = allReleases.data[0].created_at + const allCommitsResponse = await getUnreleasedCommits( + token, + latestReleaseDate, + daysToIgnore + ) + expect(allCommitsResponse).toStrictEqual(unreleasedCommitsData1) +}) test('Gets the unreleased commits with stale-days as non zero', async () => { - getOctokit.mockReturnValue({ request: async () => allCommits }); - const daysToIgnore = 3; - const latestReleaseDate = allReleases.data[0].created_at; - const allCommitsResponse = await getUnreleasedCommits(token, latestReleaseDate, daysToIgnore); - expect(allCommitsResponse).toStrictEqual(unreleasedCommitsData1); -}); + getOctokit.mockReturnValue({ request: async () => allCommits }) + const daysToIgnore = 3 + const latestReleaseDate = allReleases.data[0].created_at + const allCommitsResponse = await getUnreleasedCommits( + token, + latestReleaseDate, + daysToIgnore + ) + expect(allCommitsResponse).toStrictEqual(unreleasedCommitsData1) +}) test('Gets the unreleased commits and uses default value of stale-days', async () => { - getOctokit.mockReturnValue({ request: async () => allCommits }); - const daysToIgnore = undefined; - const latestReleaseDate = allReleases.data[0].created_at; - const allCommitsResponse = await getUnreleasedCommits(token, latestReleaseDate, daysToIgnore); - expect(allCommitsResponse).toStrictEqual(unreleasedCommitsData0); -}); + getOctokit.mockReturnValue({ request: async () => allCommits }) + const daysToIgnore = undefined + const latestReleaseDate = allReleases.data[0].created_at + const allCommitsResponse = await getUnreleasedCommits( + token, + latestReleaseDate, + daysToIgnore + ) + expect(allCommitsResponse).toStrictEqual(unreleasedCommitsData0) +}) diff --git a/test/testData.js b/test/testData.js index d34bb67e..2d798acb 100644 --- a/test/testData.js +++ b/test/testData.js @@ -1,340 +1,367 @@ -'use strict' -const allCommitsData = { - data: [{ - "sha": "000001abcd", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-28T09:27:24Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-28T09:27:24Z" - }, - "message": `variable changed - - -this message has multiple lines - -` - }, - }, { - "sha": "000002a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T12:49:23Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T12:49:23Z" - }, - "message": "stale days changd", - }, - }, { - "sha": "000003a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:50:36Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:50:36Z" - }, - "message": "another fix", - }, - }, { - "sha": "000004a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:42:44Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:42:44Z" - }, - "message": "minor fix", - }, - }, { - "sha": "000005a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:41:20Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:41:20Z" - }, - "message": "changed url", - }, - }, { - "sha": "000006a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:08:23Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:08:23Z" - }, - "message": "action repo url changed", - }, - }, { - "sha": "000007a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:02:56Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:02:56Z" - }, - "message": "added test function", - }, - }, { - "sha": "000008a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T07:37:09Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T07:37:09Z" - }, - "message": "dummy function added", - }, - }, { - "sha": "000009a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:14:09Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:14:09Z" - }, - "message": "repo name corrected", - }, - }, { - "sha": "000010a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:11:47Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:11:47Z" - }, - "message": "workflow updated", - }, - }, { - "commit": { - "author": {"name": "Sameer Srivastava", "date": "2021-04-26T13:25:08Z"}, - "committer": {"name": "GitHub", "date": "2021-04-26T13:25:08Z"}, - "message": "workflow created", - }, - }, { - "commit": { - "author": {"name": "Sameer Srivastava", "date": "2021-04-26T13:15:48Z"}, - "committer": {"name": "GitHub", "date": "2021-04-26T13:15:48Z"}, - "message": "Initial commit", - }, - }] -} - -const allReleasesData = { - data: [ - { - name: 'Release 2.0', - created_at: '2021-03-27T07:37:09Z', - published_at: '2021-04-27T07:37:09Z', - Tag: '2.0', - author: 'sameer' - }, - { - name: 'Release 1.0', - created_at: '2021-03-20T07:37:09Z', - published_at: '2021-04-20T07:37:09Z', - Tag: '1.0', - author: 'gilach' - }, - ] -} - -const unreleasedCommitsData0 = [] - - -const unreleasedCommitsData1 = [{ - "sha": "000001abcd", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-28T09:27:24Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-28T09:27:24Z" - }, - "message": `variable changed - - -this message has multiple lines - -`, - }, -}, { - "sha": "000002a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T12:49:23Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T12:49:23Z" - }, - "message": "stale days changd", - }, -}, { - "sha": "000003a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:50:36Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:50:36Z" - }, - "message": "another fix", - }, -}, { - "sha": "000004a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:42:44Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:42:44Z" - }, - "message": "minor fix", - }, -}, { - "sha": "000005a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:41:20Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:41:20Z" - }, - "message": "changed url", - }, -}, { - "sha": "000006a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:08:23Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:08:23Z" - }, - "message": "action repo url changed", - }, -}, { - "sha": "000007a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:02:56Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T08:02:56Z" - }, - "message": "added test function", - }, -}, { - "sha": "000008a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T07:37:09Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T07:37:09Z" - }, - "message": "dummy function added", - }, -}, { - "sha": "000009a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:14:09Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:14:09Z" - }, - "message": "repo name corrected", - }, -}, { - "sha": "000010a", - "commit": { - "author": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:11:47Z" - }, - "committer": { - "name": "Sameer Srivastava", - "date": "2021-04-27T06:11:47Z" - }, - "message": "workflow updated", - }, -}, { - "commit": { - "author": {"name": "Sameer Srivastava", "date": "2021-04-26T13:25:08Z"}, - "committer": {"name": "GitHub", "date": "2021-04-26T13:25:08Z"}, - "message": "workflow created", - }, -}, { - "commit": { - "author": {"name": "Sameer Srivastava", "date": "2021-04-26T13:15:48Z"}, - "committer": {"name": "GitHub", "date": "2021-04-26T13:15:48Z"}, - "message": "Initial commit", - }, -}] - -const allReleasesNoData = { - data: [] -} - -const pendingIssues = [{ - number: '1', - updated_at: '2021-04-26T07:37:09Z' -}] - -module.exports = { - allCommitsData, - allReleasesData, - unreleasedCommitsData0, - unreleasedCommitsData1, - allReleasesNoData, - pendingIssues -} +'use strict' +const allCommitsData = { + data: [ + { + sha: '000001abcd', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-28T09:27:24Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-28T09:27:24Z', + }, + message: `variable changed + + +this message has multiple lines + +`, + }, + }, + { + sha: '000002a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T12:49:23Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T12:49:23Z', + }, + message: 'stale days changd', + }, + }, + { + sha: '000003a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:50:36Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:50:36Z', + }, + message: 'another fix', + }, + }, + { + sha: '000004a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:42:44Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:42:44Z', + }, + message: 'minor fix', + }, + }, + { + sha: '000005a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:41:20Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:41:20Z', + }, + message: 'changed url', + }, + }, + { + sha: '000006a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:08:23Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:08:23Z', + }, + message: 'action repo url changed', + }, + }, + { + sha: '000007a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:02:56Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:02:56Z', + }, + message: 'added test function', + }, + }, + { + sha: '000008a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T07:37:09Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T07:37:09Z', + }, + message: 'dummy function added', + }, + }, + { + sha: '000009a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:14:09Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:14:09Z', + }, + message: 'repo name corrected', + }, + }, + { + sha: '000010a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:11:47Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:11:47Z', + }, + message: 'workflow updated', + }, + }, + { + commit: { + author: { name: 'Sameer Srivastava', date: '2021-04-26T13:25:08Z' }, + committer: { name: 'GitHub', date: '2021-04-26T13:25:08Z' }, + message: 'workflow created', + }, + }, + { + commit: { + author: { name: 'Sameer Srivastava', date: '2021-04-26T13:15:48Z' }, + committer: { name: 'GitHub', date: '2021-04-26T13:15:48Z' }, + message: 'Initial commit', + }, + }, + ], +} + +const allReleasesData = { + data: [ + { + name: 'Release 2.0', + created_at: '2021-03-27T07:37:09Z', + published_at: '2021-04-27T07:37:09Z', + Tag: '2.0', + author: 'sameer', + }, + { + name: 'Release 1.0', + created_at: '2021-03-20T07:37:09Z', + published_at: '2021-04-20T07:37:09Z', + Tag: '1.0', + author: 'gilach', + }, + ], +} + +const unreleasedCommitsData0 = [] + +const unreleasedCommitsData1 = [ + { + sha: '000001abcd', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-28T09:27:24Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-28T09:27:24Z', + }, + message: `variable changed + + +this message has multiple lines + +`, + }, + }, + { + sha: '000002a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T12:49:23Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T12:49:23Z', + }, + message: 'stale days changd', + }, + }, + { + sha: '000003a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:50:36Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:50:36Z', + }, + message: 'another fix', + }, + }, + { + sha: '000004a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:42:44Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:42:44Z', + }, + message: 'minor fix', + }, + }, + { + sha: '000005a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:41:20Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:41:20Z', + }, + message: 'changed url', + }, + }, + { + sha: '000006a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:08:23Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:08:23Z', + }, + message: 'action repo url changed', + }, + }, + { + sha: '000007a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:02:56Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T08:02:56Z', + }, + message: 'added test function', + }, + }, + { + sha: '000008a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T07:37:09Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T07:37:09Z', + }, + message: 'dummy function added', + }, + }, + { + sha: '000009a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:14:09Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:14:09Z', + }, + message: 'repo name corrected', + }, + }, + { + sha: '000010a', + commit: { + author: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:11:47Z', + }, + committer: { + name: 'Sameer Srivastava', + date: '2021-04-27T06:11:47Z', + }, + message: 'workflow updated', + }, + }, + { + commit: { + author: { name: 'Sameer Srivastava', date: '2021-04-26T13:25:08Z' }, + committer: { name: 'GitHub', date: '2021-04-26T13:25:08Z' }, + message: 'workflow created', + }, + }, + { + commit: { + author: { name: 'Sameer Srivastava', date: '2021-04-26T13:15:48Z' }, + committer: { name: 'GitHub', date: '2021-04-26T13:15:48Z' }, + message: 'Initial commit', + }, + }, +] + +const allReleasesNoData = { + data: [], +} + +const pendingIssues = [ + { + number: '1', + updated_at: '2021-04-26T07:37:09Z', + }, +] + +module.exports = { + allCommitsData, + allReleasesData, + unreleasedCommitsData0, + unreleasedCommitsData1, + allReleasesNoData, + pendingIssues, +}