diff --git a/README.md b/README.md index 084652c0..6cd1a564 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # @semantic-release/github -Set of [Semantic-release](https://github.com/semantic-release/semantic-release) plugins for publishing a -[GitHub release](https://help.github.com/articles/about-releases). +[**semantic-release**](https://github.com/semantic-release/semantic-release) plugin to publish a +[GitHub release](https://help.github.com/articles/about-releases) and comment on released Pull Requests/Issues. [![Travis](https://img.shields.io/travis/semantic-release/github.svg)](https://travis-ci.org/semantic-release/github) [![Codecov](https://img.shields.io/codecov/c/github/semantic-release/github.svg)](https://codecov.io/gh/semantic-release/github) @@ -10,29 +10,45 @@ Set of [Semantic-release](https://github.com/semantic-release/semantic-release) [![npm latest version](https://img.shields.io/npm/v/@semantic-release/github/latest.svg)](https://www.npmjs.com/package/@semantic-release/github) [![npm next version](https://img.shields.io/npm/v/@semantic-release/github/next.svg)](https://www.npmjs.com/package/@semantic-release/github) -## verifyConditions +| Step | Description | +|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `verifyConditions` | Verify the presence and the validity of the authentication (set via [environment variables](#environment-variables)) and the [assets](#assets) option configuration. | +| `publish` | Publish a [GitHub release](https://help.github.com/articles/about-releases), optionally uploading file assets. | +| `success` | Add a comment to each [GitHub Issue](https://help.github.com/articles/about-issues) or [Pull Request](https://help.github.com/articles/about-pull-requests) resolved by the release and close issues previously open by the `fail` step. | +| `fail` | Open or update a [GitHub Issue](https://help.github.com/articles/about-issues) with informations about the errors that caused the release to fail. | -Verify the presence and the validity of the authentication (set via [environment variables](#environment-variables)) and -the [assets](#assets) option configuration. +## Install -## publish - -Publish a [GitHub release](https://help.github.com/articles/about-releases), optionally uploading files. +```bash +$ npm install @semantic-release/github -D +``` -## success +## Usage -Add a comment to each GitHub issue or pull request resolved by the release and close issues previously open by the [fail](#fail) step. +The plugin can be configured in the [**semantic-release** configuration file](https://github.com/semantic-release/semantic-release/blob/caribou/docs/usage/configuration.md#configuration): -## fail +```json +{ + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + ["@semantic-release/github", { + "assets": [ + {"path": "dist/asset.min.css", "label": "CSS distribution"}, + {"path": "dist/asset.min.js", "label": "JS distribution"} + ] + }], + ] +} +``` -Open or update a GitHub issue with informations about the errors that caused the release to fail. +With this example [GitHub releases](https://help.github.com/articles/about-releases) will be published with the file `dist/asset.min.css` and `dist/asset.min.js`. ## Configuration ### GitHub authentication -The GitHub authentication configuration is **required** and can be set via -[environment variables](#environment-variables). +The GitHub authentication configuration is **required** and can be set via [environment variables](#environment-variables). Follow the [Creating a personal access token for the command line](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) documentation to obtain an authentication token. The token has to be made available in your CI environment via the `GH_TOKEN` environment variable. The user associated with the token must have push permission to the repository. @@ -46,19 +62,17 @@ Follow the [Creating a personal access token for the command line](https://help. ### Options -| Option | Description | Default | -|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------| -| `githubUrl` | The GitHub Enterprise endpoint. | `GH_URL` or `GITHUB_URL` environment variable. | -| `githubApiPathPrefix` | The GitHub Enterprise API prefix. | `GH_PREFIX` or `GITHUB_PREFIX` environment variable. | -| `proxy` | The proxy to use to access the GitHub API. See [proxy](#proxy). | `HTTP_PROXY` environment variable. | -| `assets` | An array of files to upload to the release. See [assets](#assets). | - | -| `successComment` | The comment added to each issue and pull request resolved by the release. See [successComment](#successcomment). | `:tada: This issue has been resolved in version ${nextRelease.version} :tada:\n\nThe release is available on [GitHub release]()` | -| `failComment` | The content of the issue created when a release fails. See [failComment](#failcomment). | Friendly message with links to **semantic-release** documentation and support, with the list of errors that caused the release to fail. | -| `failTitle` | The title of the issue created when a release fails. | `The automated release is failing 🚨` | -| `labels` | The [labels](https://help.github.com/articles/about-labels) to add to the issue created when a release fails. | `['semantic-release']` | -| `assignees` | The [assignees](https://help.github.com/articles/assigning-issues-and-pull-requests-to-other-github-users) to add to the issue created when a release fails. | - | - -**Note**: If you use a [shareable configuration](https://github.com/semantic-release/semantic-release/blob/caribou/docs/usage/shareable-configurations.md#shareable-configurations) that defines one of these options you can set it to `false` in your [**semantic-release** configuration](https://github.com/semantic-release/semantic-release/blob/caribou/docs/usage/configuration.md#configuration) in order to use the default value. +| Option | Description | Default | +|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------| +| `githubUrl` | The GitHub Enterprise endpoint. | `GH_URL` or `GITHUB_URL` environment variable. | +| `githubApiPathPrefix` | The GitHub Enterprise API prefix. | `GH_PREFIX` or `GITHUB_PREFIX` environment variable. | +| `proxy` | The proxy to use to access the GitHub API. See [proxy](#proxy). | `HTTP_PROXY` environment variable. | +| `assets` | An array of files to upload to the release. See [assets](#assets). | - | +| `successComment` | The comment added to each issue and pull request resolved by the release. Set to `false` to disable commenting on issues and pull requests. See [successComment](#successcomment). | `:tada: This issue has been resolved in version ${nextRelease.version} :tada:\n\nThe release is available on [GitHub release]()` | +| `failComment` | The content of the issue created when a release fails. Set to `false` to disable opening an issue when a release fails. See [failComment](#failcomment). | Friendly message with links to **semantic-release** documentation and support, with the list of errors that caused the release to fail. | +| `failTitle` | The title of the issue created when a release fails. Set to `false` to disable opening an issue when a release fails. | `The automated release is failing 🚨` | +| `labels` | The [labels](https://help.github.com/articles/about-labels) to add to the issue created when a release fails. Set to `false` to not add any label. | `['semantic-release']` | +| `assignees` | The [assignees](https://help.github.com/articles/assigning-issues-and-pull-requests-to-other-github-users) to add to the issue created when a release fails. | - | #### proxy @@ -147,51 +161,3 @@ The `failComment` `This release from branch ${branch} had failed due to the foll > This release from branch master had failed due to the following errors: > - Error message 1 > - Error message 2 - -### Usage - -The plugins are used by default by [Semantic-release](https://github.com/semantic-release/semantic-release) so no -specific configuration is required if `githubUrl` and `githubApiPathPrefix` are set via environment variable. - -Each individual plugin can be disabled, replaced or used with other plugins in the `package.json`: - -```json -{ - "release": { - "verifyConditions": ["@semantic-release/github", "@semantic-release/npm", "verify-other-condition"], - "publish": ["@semantic-release/npm", "@semantic-release/github", "other-publish"], - "success": ["@semantic-release/github", "other-success"], - "fail": ["@semantic-release/github", "other-fail"] - } -} -``` - -Options can be set within the plugin definition in the [**semantic-release** configuration](https://github.com/semantic-release/semantic-release/blob/caribou/docs/usage/configuration.md#configuration): - -```json -{ - "release": { - "verifyConditions": [ - "@semantic-release/npm", - { - "path": "@semantic-release/github", - "githubUrl": "https://my-ghe.com", - "githubApiPathPrefix": "/api-prefix" - }, - "verify-other-condition" - ], - "publish": [ - "@semantic-release/npm", - { - "path": "@semantic-release/github", - "githubUrl": "https://my-ghe.com", - "githubApiPathPrefix": "/api-prefix", - "assets": [ - {"path": "dist/asset.min.css", "label": "CSS distribution"}, - {"path": "dist/asset.min.js", "label": "JS distribution"} - ] - } - ] - } -} -``` diff --git a/lib/fail.js b/lib/fail.js index 482fb85a..b2a0fa9b 100644 --- a/lib/fail.js +++ b/lib/fail.js @@ -17,25 +17,30 @@ module.exports = async (pluginConfig, context) => { pluginConfig, context ); - const {name: repo, owner} = parseGithubUrl(repositoryUrl); - const github = getClient({githubToken, githubUrl, githubApiPathPrefix, proxy}); - const body = failComment ? template(failComment)({branch, errors}) : getFailComment(branch, errors); - const [srIssue] = await findSRIssues(github, failTitle, owner, repo); - if (srIssue) { - logger.log('Found existing semantic-release issue #%d.', srIssue.number); - const comment = {owner, repo, number: srIssue.number, body}; - debug('create comment: %O', comment); - const { - data: {html_url: url}, - } = await github.issues.createComment(comment); - logger.log('Added comment to issue #%d: %s.', srIssue.number, url); + if (failComment === false || failTitle === false) { + logger.log('Skip issue creation.'); } else { - const newIssue = {owner, repo, title: failTitle, body: `${body}\n\n${ISSUE_ID}`, labels, assignees}; - debug('create issue: %O', newIssue); - const { - data: {html_url: url, number}, - } = await github.issues.create(newIssue); - logger.log('Created issue #%d: %s.', number, url); + const {name: repo, owner} = parseGithubUrl(repositoryUrl); + const github = getClient({githubToken, githubUrl, githubApiPathPrefix, proxy}); + const body = failComment ? template(failComment)({branch, errors}) : getFailComment(branch, errors); + const [srIssue] = await findSRIssues(github, failTitle, owner, repo); + + if (srIssue) { + logger.log('Found existing semantic-release issue #%d.', srIssue.number); + const comment = {owner, repo, number: srIssue.number, body}; + debug('create comment: %O', comment); + const { + data: {html_url: url}, + } = await github.issues.createComment(comment); + logger.log('Added comment to issue #%d: %s.', srIssue.number, url); + } else { + const newIssue = {owner, repo, title: failTitle, body: `${body}\n\n${ISSUE_ID}`, labels: labels || [], assignees}; + debug('create issue: %O', newIssue); + const { + data: {html_url: url, number}, + } = await github.issues.create(newIssue); + logger.log('Created issue #%d: %s.', number, url); + } } }; diff --git a/lib/resolve-config.js b/lib/resolve-config.js index 6a23cab7..cf339f63 100644 --- a/lib/resolve-config.js +++ b/lib/resolve-config.js @@ -1,4 +1,4 @@ -const {isUndefined, castArray} = require('lodash'); +const {isNil, castArray} = require('lodash'); module.exports = ( {githubUrl, githubApiPathPrefix, proxy, assets, successComment, failTitle, failComment, labels, assignees}, @@ -10,8 +10,8 @@ module.exports = ( proxy: proxy || env.HTTP_PROXY, assets: assets ? castArray(assets) : assets, successComment, - failTitle: isUndefined(failTitle) || failTitle === false ? 'The automated release is failing 🚨' : failTitle, + failTitle: isNil(failTitle) ? 'The automated release is failing 🚨' : failTitle, failComment, - labels: isUndefined(labels) ? ['semantic-release'] : labels === false ? [] : castArray(labels), + labels: isNil(labels) ? ['semantic-release'] : labels === false ? false : castArray(labels), assignees: assignees ? castArray(assignees) : assignees, }); diff --git a/lib/success.js b/lib/success.js index b55002fb..2354a90c 100644 --- a/lib/success.js +++ b/lib/success.js @@ -1,4 +1,4 @@ -const {isUndefined, uniqBy, template, flatten} = require('lodash'); +const {isNil, uniqBy, template, flatten} = require('lodash'); const parseGithubUrl = require('parse-github-url'); const pFilter = require('p-filter'); const AggregateError = require('aggregate-error'); @@ -19,95 +19,103 @@ module.exports = async (pluginConfig, context) => { releases, logger, } = context; - const {githubToken, githubUrl, githubApiPathPrefix, proxy, successComment, failTitle} = resolveConfig( + const {githubToken, githubUrl, githubApiPathPrefix, proxy, successComment, failComment, failTitle} = resolveConfig( pluginConfig, context ); const {name: repo, owner} = parseGithubUrl(repositoryUrl); const github = getClient({githubToken, githubUrl, githubApiPathPrefix, proxy}); - const parser = issueParser('github', githubUrl ? {hosts: [githubUrl]} : {}); - const releaseInfos = releases.filter(release => Boolean(release.name)); - const shas = commits.map(({hash}) => hash); + const errors = []; - const searchQueries = getSearchQueries(`repo:${owner}/${repo}+type:pr+is:merged`, shas).map( - async q => (await github.search.issues({q})).data.items - ); + if (successComment === false) { + logger.log('Skip commenting on issues and pull requests.'); + } else { + const parser = issueParser('github', githubUrl ? {hosts: [githubUrl]} : {}); + const releaseInfos = releases.filter(release => Boolean(release.name)); + const shas = commits.map(({hash}) => hash); - const prs = await pFilter( - uniqBy(flatten(await Promise.all(searchQueries)), 'number'), - async ({number}) => - (await github.pullRequests.getCommits({owner, repo, number})).data.find(({sha}) => shas.includes(sha)) || - shas.includes((await github.pullRequests.get({owner, repo, number})).data.merge_commit_sha) - ); + const searchQueries = getSearchQueries(`repo:${owner}/${repo}+type:pr+is:merged`, shas).map( + async q => (await github.search.issues({q})).data.items + ); - debug('found pull requests: %O', prs.map(pr => pr.number)); + const prs = await pFilter( + uniqBy(flatten(await Promise.all(searchQueries)), 'number'), + async ({number}) => + (await github.pullRequests.getCommits({owner, repo, number})).data.find(({sha}) => shas.includes(sha)) || + shas.includes((await github.pullRequests.get({owner, repo, number})).data.merge_commit_sha) + ); - // Parse the release commits message and PRs body to find resolved issues/PRs via comment keyworkds - const issues = [...prs.map(pr => pr.body), ...commits.map(commit => commit.message)].reduce((issues, message) => { - return message - ? issues.concat( - parser(message) - .actions.close.filter(action => isUndefined(action.slug) || action.slug === `${owner}/${repo}`) - .map(action => ({number: parseInt(action.issue, 10)})) - ) - : issues; - }, []); + debug('found pull requests: %O', prs.map(pr => pr.number)); - debug('found issues via comments: %O', issues); + // Parse the release commits message and PRs body to find resolved issues/PRs via comment keyworkds + const issues = [...prs.map(pr => pr.body), ...commits.map(commit => commit.message)].reduce((issues, message) => { + return message + ? issues.concat( + parser(message) + .actions.close.filter(action => isNil(action.slug) || action.slug === `${owner}/${repo}`) + .map(action => ({number: parseInt(action.issue, 10)})) + ) + : issues; + }, []); - const errors = []; + debug('found issues via comments: %O', issues); - await Promise.all( - uniqBy([...prs, ...issues], 'number').map(async issue => { - const body = successComment - ? template(successComment)({branch, lastRelease, commits, nextRelease, releases, issue}) - : getSuccessComment(issue, releaseInfos, nextRelease); - try { - const state = issue.state || (await github.issues.get({owner, repo, number: issue.number})).data.state; + await Promise.all( + uniqBy([...prs, ...issues], 'number').map(async issue => { + const body = successComment + ? template(successComment)({branch, lastRelease, commits, nextRelease, releases, issue}) + : getSuccessComment(issue, releaseInfos, nextRelease); + try { + const state = issue.state || (await github.issues.get({owner, repo, number: issue.number})).data.state; - if (state === 'closed') { - const comment = {owner, repo, number: issue.number, body}; - debug('create comment: %O', comment); - const { - data: {html_url: url}, - } = await github.issues.createComment(comment); - logger.log('Added comment to issue #%d: %s', issue.number, url); - } else { - logger.log("Skip comment on issue #%d as it's open: %s", issue.number); - } - } catch (error) { - if (error.code === 404) { - logger.error("Failed to add a comment to the issue #%d as it doesn't exists.", issue.number); - } else { - errors.push(error); - logger.error('Failed to add a comment to the issue #%d.', issue.number); - // Don't throw right away and continue to update other issues + if (state === 'closed') { + const comment = {owner, repo, number: issue.number, body}; + debug('create comment: %O', comment); + const { + data: {html_url: url}, + } = await github.issues.createComment(comment); + logger.log('Added comment to issue #%d: %s', issue.number, url); + } else { + logger.log("Skip comment on issue #%d as it's open: %s", issue.number); + } + } catch (error) { + if (error.code === 404) { + logger.error("Failed to add a comment to the issue #%d as it doesn't exists.", issue.number); + } else { + errors.push(error); + logger.error('Failed to add a comment to the issue #%d.', issue.number); + // Don't throw right away and continue to update other issues + } } - } - }) - ); + }) + ); + } - const srIssues = await findSRIssues(github, failTitle, owner, repo); + if (failComment === false || failTitle === false) { + logger.log('Skip closing issue.'); + } else { + const srIssues = await findSRIssues(github, failTitle, owner, repo); - debug('found semantic-release issues: %O', srIssues); + debug('found semantic-release issues: %O', srIssues); - await Promise.all( - srIssues.map(async issue => { - debug('close issue: %O', issue); - try { - const updateIssue = {owner, repo, number: issue.number, state: 'closed'}; - debug('closing issue: %O', updateIssue); - const { - data: {html_url: url}, - } = await github.issues.edit(updateIssue); - logger.log('Closed issue #%d: %s.', issue.number, url); - } catch (error) { - errors.push(error); - logger.error('Failed to close the issue #%d.', issue.number); - // Don't throw right away and continue to close other issues - } - }) - ); + await Promise.all( + srIssues.map(async issue => { + debug('close issue: %O', issue); + try { + const updateIssue = {owner, repo, number: issue.number, state: 'closed'}; + debug('closing issue: %O', updateIssue); + const { + data: {html_url: url}, + } = await github.issues.edit(updateIssue); + logger.log('Closed issue #%d: %s.', issue.number, url); + } catch (error) { + errors.push(error); + logger.error('Failed to close the issue #%d.', issue.number); + // Don't throw right away and continue to close other issues + } + }) + ); + } if (errors.length > 0) { throw new AggregateError(errors); diff --git a/lib/verify.js b/lib/verify.js index 1981ae28..26cce170 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -1,4 +1,4 @@ -const {isString, isPlainObject, isUndefined, isArray, isNumber} = require('lodash'); +const {isString, isPlainObject, isNil, isArray, isNumber} = require('lodash'); const parseGithubUrl = require('parse-github-url'); const urlJoin = require('url-join'); const AggregateError = require('aggregate-error'); @@ -9,6 +9,7 @@ const getError = require('./get-error'); const isNonEmptyString = value => isString(value) && value.trim(); const isStringOrStringArray = value => isNonEmptyString(value) || (isArray(value) && value.every(isNonEmptyString)); const isArrayOf = validator => array => isArray(array) && array.every(value => validator(value)); +const canBeDisabled = validator => value => value === false || validator(value); const VALIDATORS = { proxy: proxy => @@ -16,11 +17,11 @@ const VALIDATORS = { assets: isArrayOf( asset => isStringOrStringArray(asset) || (isPlainObject(asset) && isStringOrStringArray(asset.path)) ), - successComment: isNonEmptyString, - failTitle: isNonEmptyString, - failComment: isNonEmptyString, - labels: isArrayOf(isStringOrStringArray), - assignees: isArrayOf(isStringOrStringArray), + successComment: canBeDisabled(isNonEmptyString), + failTitle: canBeDisabled(isNonEmptyString), + failComment: canBeDisabled(isNonEmptyString), + labels: canBeDisabled(isArrayOf(isNonEmptyString)), + assignees: isArrayOf(isNonEmptyString), }; module.exports = async (pluginConfig, context) => { @@ -32,7 +33,7 @@ module.exports = async (pluginConfig, context) => { const errors = Object.entries({...options, proxy}).reduce( (errors, [option, value]) => - !isUndefined(value) && value !== false && !VALIDATORS[option](value) + !isNil(value) && !VALIDATORS[option](value) ? [...errors, getError(`EINVALID${option.toUpperCase()}`, {[option]: value})] : errors, [] diff --git a/package.json b/package.json index d329e21a..8c8b18c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@semantic-release/github", - "description": "Set of semantic-release plugins for publishing a GitHub release", + "description": "semantic-release plugin to publish a GitHub release and comment on released Pull Requests/Issues", "version": "0.0.0-development", "author": "Pierre Vanduynslager (https://twitter.com/@pvdlg_)", "bugs": { diff --git a/test/fail.test.js b/test/fail.test.js index d6aa0f59..65642a0b 100644 --- a/test/fail.test.js +++ b/test/fail.test.js @@ -237,3 +237,37 @@ test.serial('Update the first existing issue with the list of errors', async t = t.true(t.context.log.calledWith('Added comment to issue #%d: %s.', 2, 'https://github.com/issues/2')); t.true(github.isDone()); }); + +test.serial('Skip if "failComment" is "false"', async t => { + const owner = 'test_user'; + const repo = 'test_repo'; + const env = {GITHUB_TOKEN: 'github_token'}; + const pluginConfig = {failComment: false}; + const options = {branch: 'master', repositoryUrl: `https://github.com/${owner}/${repo}.git`}; + const errors = [ + new SemanticReleaseError('Error message 1', 'ERR1', 'Error 1 details'), + new SemanticReleaseError('Error message 2', 'ERR2', 'Error 2 details'), + new SemanticReleaseError('Error message 3', 'ERR3', 'Error 3 details'), + ]; + + await fail(pluginConfig, {env, options, errors, logger: t.context.logger}); + + t.true(t.context.log.calledWith('Skip issue creation.')); +}); + +test.serial('Skip if "failTitle" is "false"', async t => { + const owner = 'test_user'; + const repo = 'test_repo'; + const env = {GITHUB_TOKEN: 'github_token'}; + const pluginConfig = {failTitle: false}; + const options = {branch: 'master', repositoryUrl: `https://github.com/${owner}/${repo}.git`}; + const errors = [ + new SemanticReleaseError('Error message 1', 'ERR1', 'Error 1 details'), + new SemanticReleaseError('Error message 2', 'ERR2', 'Error 2 details'), + new SemanticReleaseError('Error message 3', 'ERR3', 'Error 3 details'), + ]; + + await fail(pluginConfig, {env, options, errors, logger: t.context.logger}); + + t.true(t.context.log.calledWith('Skip issue creation.')); +}); diff --git a/test/success.test.js b/test/success.test.js index a2b46989..285d018d 100644 --- a/test/success.test.js +++ b/test/success.test.js @@ -548,7 +548,76 @@ test.serial('Close open issues when a release is successful', async t => { .reply(200, {html_url: 'https://github.com/issues/3'}); await success(pluginConfig, {env, options, commits, nextRelease, releases, logger: t.context.logger}); + t.true(t.context.log.calledWith('Closed issue #%d: %s.', 2, 'https://github.com/issues/2')); t.true(t.context.log.calledWith('Closed issue #%d: %s.', 3, 'https://github.com/issues/3')); t.true(github.isDone()); }); + +test.serial('Skip commention on issues/PR if "successComment" is "false"', async t => { + const owner = 'test_user'; + const repo = 'test_repo'; + const env = {GITHUB_TOKEN: 'github_token'}; + const failTitle = 'The automated release is failing 🚨'; + const pluginConfig = {failTitle, successComment: false}; + const options = {branch: 'master', repositoryUrl: `https://github.com/${owner}/${repo}.git`}; + const commits = [{hash: '123', message: 'Commit 1 message\n\n Fix #1', tree: {long: 'aaa'}}]; + const nextRelease = {version: '1.0.0'}; + const releases = [{name: 'GitHub release', url: 'https://github.com/release'}]; + const github = authenticate(env) + .get( + `/search/issues?q=${escape('in:title')}+${escape(`repo:${owner}/${repo}`)}+${escape('type:issue')}+${escape( + 'state:open' + )}+${escape(failTitle)}` + ) + .reply(200, {items: []}); + + await success(pluginConfig, {env, options, commits, nextRelease, releases, logger: t.context.logger}); + + t.true(t.context.log.calledWith('Skip commenting on issues and pull requests.')); + t.true(github.isDone()); +}); + +test.serial('Skip closing issues if "failComment" is "false"', async t => { + const owner = 'test_user'; + const repo = 'test_repo'; + const env = {GITHUB_TOKEN: 'github_token'}; + const pluginConfig = {failComment: false}; + const options = {branch: 'master', repositoryUrl: `https://github.com/${owner}/${repo}.git`}; + const commits = [{hash: '123', message: 'Commit 1 message'}]; + const nextRelease = {version: '1.0.0'}; + const releases = [{name: 'GitHub release', url: 'https://github.com/release'}]; + const github = authenticate(env) + .get( + `/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits + .map(commit => commit.hash) + .join('+')}` + ) + .reply(200, {items: []}); + + await success(pluginConfig, {env, options, commits, nextRelease, releases, logger: t.context.logger}); + t.true(t.context.log.calledWith('Skip closing issue.')); + t.true(github.isDone()); +}); + +test.serial('Skip closing issues if "failTitle" is "false"', async t => { + const owner = 'test_user'; + const repo = 'test_repo'; + const env = {GITHUB_TOKEN: 'github_token'}; + const pluginConfig = {failTitle: false}; + const options = {branch: 'master', repositoryUrl: `https://github.com/${owner}/${repo}.git`}; + const commits = [{hash: '123', message: 'Commit 1 message'}]; + const nextRelease = {version: '1.0.0'}; + const releases = [{name: 'GitHub release', url: 'https://github.com/release'}]; + const github = authenticate(env) + .get( + `/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits + .map(commit => commit.hash) + .join('+')}` + ) + .reply(200, {items: []}); + + await success(pluginConfig, {env, options, commits, nextRelease, releases, logger: t.context.logger}); + t.true(t.context.log.calledWith('Skip closing issue.')); + t.true(github.isDone()); +}); diff --git a/test/verify.test.js b/test/verify.test.js index d3d6da7c..1eab9b31 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -47,17 +47,17 @@ test.serial('Verify package, token and repository access', async t => { }); test.serial( - 'Verify package, token and repository access with "proxy", "asset", "successComment", "failTitle", "failComment" and "label" set to "false"', + 'Verify package, token and repository access with "proxy", "asset", "successComment", "failTitle", "failComment" and "label" set to "null"', async t => { const owner = 'test_user'; const repo = 'test_repo'; const env = {GH_TOKEN: 'github_token'}; - const proxy = false; - const assets = false; - const successComment = false; - const failTitle = false; - const failComment = false; - const labels = false; + const proxy = null; + const assets = null; + const successComment = null; + const failTitle = null; + const failComment = null; + const labels = null; const github = authenticate(env) .get(`/repos/${owner}/${repo}`) .reply(200, {permissions: {push: true}});