Skip to content

Commit db2e9c8

Browse files
ChumperNils Plaschke
and
Nils Plaschke
authoredSep 7, 2020
feat: add additional release links to the release (#282)
A new option `addReleases` has been added. Setting this option will add links to other releases to the Github release body. The option can be one of `false|"top"|"bottom"`. The default is `false` to be backward compatible. Closes #281 Co-authored-by: Nils Plaschke <plaschke@adobe.com>
1 parent 32654fb commit db2e9c8

10 files changed

+573
-4
lines changed
 

‎README.md

+10
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,13 @@ Each label name is generated with [Lodash template](https://lodash.com/docs#temp
204204
The `releasedLabels` ```['released<%= nextRelease.channel ? ` on @\${nextRelease.channel}` : "" %> from <%= branch.name %>']``` will generate the label:
205205

206206
> released on @next from branch next
207+
208+
#### addReleases
209+
210+
Add links to other releases to the GitHub release body.
211+
212+
Valid values for this option are `false`, `"top"` or `"bottom"`.
213+
214+
##### addReleases example
215+
216+
See [The introducing PR](https://github.com/semantic-release/github/pull/282) for an example on how it will look.

‎lib/definitions/errors.js

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ Your configuration for the \`assignees\` option is \`${stringify(assignees)}\`.`
5757
)}) if defined, must be an \`Array\` of non empty \`String\`.
5858
5959
Your configuration for the \`releasedLabels\` option is \`${stringify(releasedLabels)}\`.`,
60+
}),
61+
EINVALIDADDRELEASES: ({addReleases}) => ({
62+
message: 'Invalid `addReleases` option.',
63+
details: `The [addReleases option](${linkify('README.md#options')}) if defined, must be one of \`false|top|bottom\`.
64+
65+
Your configuration for the \`addReleases\` option is \`${stringify(addReleases)}\`.`,
6066
}),
6167
EINVALIDGITHUBURL: () => ({
6268
message: 'The git repository URL is not a valid GitHub URL.',

‎lib/get-release-links.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const {RELEASE_NAME} = require('./definitions/constants');
2+
3+
const linkify = (releaseInfo) =>
4+
`${
5+
releaseInfo.url
6+
? releaseInfo.url.startsWith('http')
7+
? `[${releaseInfo.name}](${releaseInfo.url})`
8+
: `${releaseInfo.name}: \`${releaseInfo.url}\``
9+
: `\`${releaseInfo.name}\``
10+
}`;
11+
12+
const filterReleases = (releaseInfos) =>
13+
releaseInfos.filter((releaseInfo) => releaseInfo.name && releaseInfo.name !== RELEASE_NAME);
14+
15+
module.exports = (releaseInfos) =>
16+
`${
17+
filterReleases(releaseInfos).length > 0
18+
? `This release is also available on:\n${filterReleases(releaseInfos)
19+
.map((releaseInfo) => `- ${linkify(releaseInfo)}`)
20+
.join('\n')}`
21+
: ''
22+
}`;

‎lib/publish.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ module.exports = async (pluginConfig, context) => {
2828
// When there are no assets, we publish a release directly
2929
if (!assets || assets.length === 0) {
3030
const {
31-
data: {html_url: url},
31+
data: {html_url: url, id: releaseId},
3232
} = await github.repos.createRelease(release);
3333

3434
logger.log('Published GitHub release: %s', url);
35-
return {url, name: RELEASE_NAME};
35+
return {url, name: RELEASE_NAME, id: releaseId};
3636
}
3737

3838
// We'll create a draft release, append the assets to it, and then publish it.
@@ -94,5 +94,5 @@ module.exports = async (pluginConfig, context) => {
9494
} = await github.repos.updateRelease({owner, repo, release_id: releaseId, draft: false});
9595

9696
logger.log('Published GitHub release: %s', url);
97-
return {url, name: RELEASE_NAME};
97+
return {url, name: RELEASE_NAME, id: releaseId};
9898
};

‎lib/resolve-config.js

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module.exports = (
1212
labels,
1313
assignees,
1414
releasedLabels,
15+
addReleases,
1516
},
1617
{env}
1718
) => ({
@@ -30,4 +31,5 @@ module.exports = (
3031
: releasedLabels === false
3132
? false
3233
: castArray(releasedLabels),
34+
addReleases: isNil(addReleases) ? false : addReleases,
3335
});

‎lib/success.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const {isNil, uniqBy, template, flatten} = require('lodash');
1+
const {isNil, uniqBy, template, flatten, isEmpty} = require('lodash');
22
const pFilter = require('p-filter');
33
const AggregateError = require('aggregate-error');
44
const issueParser = require('issue-parser');
@@ -9,6 +9,8 @@ const getClient = require('./get-client');
99
const getSearchQueries = require('./get-search-queries');
1010
const getSuccessComment = require('./get-success-comment');
1111
const findSRIssues = require('./find-sr-issues');
12+
const {RELEASE_NAME} = require('./definitions/constants');
13+
const getReleaseLinks = require('./get-release-links');
1214

1315
module.exports = async (pluginConfig, context) => {
1416
const {
@@ -17,6 +19,7 @@ module.exports = async (pluginConfig, context) => {
1719
nextRelease,
1820
releases,
1921
logger,
22+
notes,
2023
} = context;
2124
const {
2225
githubToken,
@@ -27,6 +30,7 @@ module.exports = async (pluginConfig, context) => {
2730
failComment,
2831
failTitle,
2932
releasedLabels,
33+
addReleases,
3034
} = resolveConfig(pluginConfig, context);
3135

3236
const github = getClient({githubToken, githubUrl, githubApiPathPrefix, proxy});
@@ -140,6 +144,21 @@ module.exports = async (pluginConfig, context) => {
140144
);
141145
}
142146

147+
if (addReleases !== false && errors.length === 0) {
148+
const ghRelease = releases.find((release) => release.name && release.name === RELEASE_NAME);
149+
if (!isNil(ghRelease)) {
150+
const ghRelaseId = ghRelease.id;
151+
const additionalReleases = getReleaseLinks(releases);
152+
if (!isEmpty(additionalReleases) && !isNil(ghRelaseId)) {
153+
const newBody =
154+
addReleases === 'top'
155+
? additionalReleases.concat('\n---\n', notes)
156+
: notes.concat('\n---\n', additionalReleases);
157+
await github.repos.updateRelease({owner, repo, release_id: ghRelaseId, body: newBody});
158+
}
159+
}
160+
}
161+
143162
if (errors.length > 0) {
144163
throw new AggregateError(errors);
145164
}

‎lib/verify.js

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const getClient = require('./get-client');
77
const getError = require('./get-error');
88

99
const isNonEmptyString = (value) => isString(value) && value.trim();
10+
const oneOf = (enumArray) => (value) => enumArray.some((element) => element === value);
1011
const isStringOrStringArray = (value) =>
1112
isNonEmptyString(value) || (isArray(value) && value.every((string) => isNonEmptyString(string)));
1213
const isArrayOf = (validator) => (array) => isArray(array) && array.every((value) => validator(value));
@@ -24,6 +25,7 @@ const VALIDATORS = {
2425
labels: canBeDisabled(isArrayOf(isNonEmptyString)),
2526
assignees: isArrayOf(isNonEmptyString),
2627
releasedLabels: canBeDisabled(isArrayOf(isNonEmptyString)),
28+
addReleases: canBeDisabled(oneOf(['bottom', 'top'])),
2729
};
2830

2931
module.exports = async (pluginConfig, context) => {

‎test/get-release-links.test.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const test = require('ava');
2+
const getReleaseLinks = require('../lib/get-release-links');
3+
const {RELEASE_NAME} = require('../lib/definitions/constants');
4+
5+
test('Comment for release with multiple releases', (t) => {
6+
const releaseInfos = [
7+
{name: RELEASE_NAME, url: 'https://github.com/release'},
8+
{name: 'Http release', url: 'https://release.com/release'},
9+
{name: 'npm release', url: 'https://npm.com/release'},
10+
];
11+
const comment = getReleaseLinks(releaseInfos);
12+
13+
t.is(
14+
comment,
15+
`This release is also available on:
16+
- [Http release](https://release.com/release)
17+
- [npm release](https://npm.com/release)`
18+
);
19+
});
20+
21+
test('Release with missing release URL', (t) => {
22+
const releaseInfos = [
23+
{name: RELEASE_NAME, url: 'https://github.com/release'},
24+
{name: 'Http release', url: 'https://release.com/release'},
25+
{name: 'npm release'},
26+
];
27+
const comment = getReleaseLinks(releaseInfos);
28+
29+
t.is(
30+
comment,
31+
`This release is also available on:
32+
- [Http release](https://release.com/release)
33+
- \`npm release\``
34+
);
35+
});
36+
37+
test('Release with one release', (t) => {
38+
const releaseInfos = [
39+
{name: RELEASE_NAME, url: 'https://github.com/release'},
40+
{name: 'Http release', url: 'https://release.com/release'},
41+
];
42+
const comment = getReleaseLinks(releaseInfos);
43+
44+
t.is(
45+
comment,
46+
`This release is also available on:
47+
- [Http release](https://release.com/release)`
48+
);
49+
});
50+
51+
test('Release with non http releases', (t) => {
52+
const releaseInfos = [{name: 'S3', url: 's3://my-bucket/release-asset'}];
53+
const comment = getReleaseLinks(releaseInfos);
54+
55+
t.is(
56+
comment,
57+
`This release is also available on:
58+
- S3: \`s3://my-bucket/release-asset\``
59+
);
60+
});
61+
62+
test('Release with only github release', (t) => {
63+
const releaseInfos = [{name: RELEASE_NAME, url: 'https://github.com/release'}];
64+
const comment = getReleaseLinks(releaseInfos);
65+
66+
t.is(comment, '');
67+
});
68+
69+
test('Comment with no release object', (t) => {
70+
const releaseInfos = [];
71+
const comment = getReleaseLinks(releaseInfos);
72+
73+
t.is(comment, '');
74+
});

‎test/success.test.js

+311
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const proxyquire = require('proxyquire');
77
const {ISSUE_ID} = require('../lib/definitions/constants');
88
const {authenticate} = require('./helpers/mock-github');
99
const rateLimit = require('./helpers/rate-limit');
10+
const getReleaseLinks = require('../lib/get-release-links');
1011

1112
/* eslint camelcase: ["error", {properties: "never"}] */
1213

@@ -624,6 +625,316 @@ test.serial('Comment on issue/PR without ading a label', async (t) => {
624625
t.true(github.isDone());
625626
});
626627

628+
test.serial('Editing the release to include all release links at the bottom', async (t) => {
629+
const owner = 'test_user';
630+
const repo = 'test_repo';
631+
const env = {GITHUB_TOKEN: 'github_token'};
632+
const failTitle = 'The automated release is failing 🚨';
633+
const pluginConfig = {releasedLabels: false, addReleases: 'bottom'};
634+
const prs = [{number: 1, pull_request: {}, state: 'closed'}];
635+
const options = {repositoryUrl: `https://github.com/${owner}/${repo}.git`};
636+
const nextRelease = {version: '2.0.0', gitTag: 'v1.0.0', name: 'v1.0.0', notes: 'Test release note body'};
637+
const lastRelease = {version: '1.0.0'};
638+
const commits = [{hash: '123', message: 'Commit 1 message'}];
639+
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
640+
const releaseId = 1;
641+
const releases = [
642+
{name: 'GitHub release', url: 'https://github.com/release', id: releaseId},
643+
{name: 'S3', url: 's3://my-bucket/release-asset'},
644+
{name: 'Docker: docker.io/python:slim'},
645+
];
646+
const github = authenticate(env)
647+
.get(`/repos/${owner}/${repo}`)
648+
.reply(200, {full_name: `${owner}/${repo}`})
649+
.get(
650+
`/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits
651+
.map((commit) => commit.hash)
652+
.join('+')}`
653+
)
654+
.reply(200, {items: prs})
655+
.get(`/repos/${owner}/${repo}/pulls/1/commits`)
656+
.reply(200, [{sha: commits[0].hash}])
657+
.post(`/repos/${owner}/${repo}/issues/1/comments`, {body: /This PR is included/})
658+
.reply(200, {html_url: 'https://github.com/successcomment-1'})
659+
.get(
660+
`/search/issues?q=${escape('in:title')}+${escape(`repo:${owner}/${repo}`)}+${escape('type:issue')}+${escape(
661+
'state:open'
662+
)}+${escape(failTitle)}`
663+
)
664+
.reply(200, {items: []})
665+
.patch(`/repos/${owner}/${repo}/releases/${releaseId}`, {
666+
body: nextRelease.notes.concat('\n---\n', getReleaseLinks(releases)),
667+
})
668+
.reply(200, {html_url: releaseUrl});
669+
670+
await success(pluginConfig, {
671+
env,
672+
options,
673+
branch: {name: 'master'},
674+
lastRelease,
675+
commits,
676+
nextRelease,
677+
releases,
678+
notes: nextRelease.notes,
679+
logger: t.context.logger,
680+
});
681+
682+
t.true(t.context.log.calledWith('Added comment to issue #%d: %s', 1, 'https://github.com/successcomment-1'));
683+
t.true(github.isDone());
684+
});
685+
686+
test.serial('Editing the release to include all release links at the top', async (t) => {
687+
const owner = 'test_user';
688+
const repo = 'test_repo';
689+
const env = {GITHUB_TOKEN: 'github_token'};
690+
const failTitle = 'The automated release is failing 🚨';
691+
const pluginConfig = {releasedLabels: false, addReleases: 'top'};
692+
const prs = [{number: 1, pull_request: {}, state: 'closed'}];
693+
const options = {repositoryUrl: `https://github.com/${owner}/${repo}.git`};
694+
const nextRelease = {version: '2.0.0', gitTag: 'v1.0.0', name: 'v1.0.0', notes: 'Test release note body'};
695+
const lastRelease = {version: '1.0.0'};
696+
const commits = [{hash: '123', message: 'Commit 1 message'}];
697+
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
698+
const releaseId = 1;
699+
const releases = [
700+
{name: 'GitHub release', url: 'https://github.com/release', id: releaseId},
701+
{name: 'S3', url: 's3://my-bucket/release-asset'},
702+
{name: 'Docker: docker.io/python:slim'},
703+
];
704+
const github = authenticate(env)
705+
.get(`/repos/${owner}/${repo}`)
706+
.reply(200, {full_name: `${owner}/${repo}`})
707+
.get(
708+
`/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits
709+
.map((commit) => commit.hash)
710+
.join('+')}`
711+
)
712+
.reply(200, {items: prs})
713+
.get(`/repos/${owner}/${repo}/pulls/1/commits`)
714+
.reply(200, [{sha: commits[0].hash}])
715+
.post(`/repos/${owner}/${repo}/issues/1/comments`, {body: /This PR is included/})
716+
.reply(200, {html_url: 'https://github.com/successcomment-1'})
717+
.get(
718+
`/search/issues?q=${escape('in:title')}+${escape(`repo:${owner}/${repo}`)}+${escape('type:issue')}+${escape(
719+
'state:open'
720+
)}+${escape(failTitle)}`
721+
)
722+
.reply(200, {items: []})
723+
.patch(`/repos/${owner}/${repo}/releases/${releaseId}`, {
724+
body: getReleaseLinks(releases).concat('\n---\n', nextRelease.notes),
725+
})
726+
.reply(200, {html_url: releaseUrl});
727+
728+
await success(pluginConfig, {
729+
env,
730+
options,
731+
branch: {name: 'master'},
732+
lastRelease,
733+
commits,
734+
nextRelease,
735+
releases,
736+
notes: nextRelease.notes,
737+
logger: t.context.logger,
738+
});
739+
740+
t.true(t.context.log.calledWith('Added comment to issue #%d: %s', 1, 'https://github.com/successcomment-1'));
741+
t.true(github.isDone());
742+
});
743+
744+
test.serial('Editing the release to include all release links with no additional releases (top)', async (t) => {
745+
const owner = 'test_user';
746+
const repo = 'test_repo';
747+
const env = {GITHUB_TOKEN: 'github_token'};
748+
const failTitle = 'The automated release is failing 🚨';
749+
const pluginConfig = {releasedLabels: false, addReleases: 'top'};
750+
const prs = [{number: 1, pull_request: {}, state: 'closed'}];
751+
const options = {repositoryUrl: `https://github.com/${owner}/${repo}.git`};
752+
const nextRelease = {version: '2.0.0', gitTag: 'v1.0.0', name: 'v1.0.0', notes: 'Test release note body'};
753+
const lastRelease = {version: '1.0.0'};
754+
const commits = [{hash: '123', message: 'Commit 1 message'}];
755+
const releaseId = 1;
756+
const releases = [{name: 'GitHub release', url: 'https://github.com/release', id: releaseId}];
757+
const github = authenticate(env)
758+
.get(`/repos/${owner}/${repo}`)
759+
.reply(200, {full_name: `${owner}/${repo}`})
760+
.get(
761+
`/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits
762+
.map((commit) => commit.hash)
763+
.join('+')}`
764+
)
765+
.reply(200, {items: prs})
766+
.get(`/repos/${owner}/${repo}/pulls/1/commits`)
767+
.reply(200, [{sha: commits[0].hash}])
768+
.post(`/repos/${owner}/${repo}/issues/1/comments`, {body: /This PR is included/})
769+
.reply(200, {html_url: 'https://github.com/successcomment-1'})
770+
.get(
771+
`/search/issues?q=${escape('in:title')}+${escape(`repo:${owner}/${repo}`)}+${escape('type:issue')}+${escape(
772+
'state:open'
773+
)}+${escape(failTitle)}`
774+
)
775+
.reply(200, {items: []});
776+
777+
await success(pluginConfig, {
778+
env,
779+
options,
780+
branch: {name: 'master'},
781+
lastRelease,
782+
commits,
783+
nextRelease,
784+
releases,
785+
logger: t.context.logger,
786+
});
787+
788+
t.true(t.context.log.calledWith('Added comment to issue #%d: %s', 1, 'https://github.com/successcomment-1'));
789+
t.true(github.isDone());
790+
});
791+
792+
test.serial('Editing the release to include all release links with no additional releases (bottom)', async (t) => {
793+
const owner = 'test_user';
794+
const repo = 'test_repo';
795+
const env = {GITHUB_TOKEN: 'github_token'};
796+
const failTitle = 'The automated release is failing 🚨';
797+
const pluginConfig = {releasedLabels: false, addReleases: 'bottom'};
798+
const prs = [{number: 1, pull_request: {}, state: 'closed'}];
799+
const options = {repositoryUrl: `https://github.com/${owner}/${repo}.git`};
800+
const nextRelease = {version: '2.0.0', gitTag: 'v1.0.0', name: 'v1.0.0', notes: 'Test release note body'};
801+
const lastRelease = {version: '1.0.0'};
802+
const commits = [{hash: '123', message: 'Commit 1 message'}];
803+
const releaseId = 1;
804+
const releases = [{name: 'GitHub release', url: 'https://github.com/release', id: releaseId}];
805+
const github = authenticate(env)
806+
.get(`/repos/${owner}/${repo}`)
807+
.reply(200, {full_name: `${owner}/${repo}`})
808+
.get(
809+
`/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits
810+
.map((commit) => commit.hash)
811+
.join('+')}`
812+
)
813+
.reply(200, {items: prs})
814+
.get(`/repos/${owner}/${repo}/pulls/1/commits`)
815+
.reply(200, [{sha: commits[0].hash}])
816+
.post(`/repos/${owner}/${repo}/issues/1/comments`, {body: /This PR is included/})
817+
.reply(200, {html_url: 'https://github.com/successcomment-1'})
818+
.get(
819+
`/search/issues?q=${escape('in:title')}+${escape(`repo:${owner}/${repo}`)}+${escape('type:issue')}+${escape(
820+
'state:open'
821+
)}+${escape(failTitle)}`
822+
)
823+
.reply(200, {items: []});
824+
825+
await success(pluginConfig, {
826+
env,
827+
options,
828+
branch: {name: 'master'},
829+
lastRelease,
830+
commits,
831+
nextRelease,
832+
releases,
833+
logger: t.context.logger,
834+
});
835+
836+
t.true(t.context.log.calledWith('Added comment to issue #%d: %s', 1, 'https://github.com/successcomment-1'));
837+
t.true(github.isDone());
838+
});
839+
840+
test.serial('Editing the release to include all release links with no releases', async (t) => {
841+
const owner = 'test_user';
842+
const repo = 'test_repo';
843+
const env = {GITHUB_TOKEN: 'github_token'};
844+
const failTitle = 'The automated release is failing 🚨';
845+
const pluginConfig = {releasedLabels: false, addReleases: 'bottom'};
846+
const prs = [{number: 1, pull_request: {}, state: 'closed'}];
847+
const options = {repositoryUrl: `https://github.com/${owner}/${repo}.git`};
848+
const nextRelease = {version: '2.0.0', gitTag: 'v1.0.0', name: 'v1.0.0', notes: 'Test release note body'};
849+
const lastRelease = {version: '1.0.0'};
850+
const commits = [{hash: '123', message: 'Commit 1 message'}];
851+
const releases = [];
852+
const github = authenticate(env)
853+
.get(`/repos/${owner}/${repo}`)
854+
.reply(200, {full_name: `${owner}/${repo}`})
855+
.get(
856+
`/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits
857+
.map((commit) => commit.hash)
858+
.join('+')}`
859+
)
860+
.reply(200, {items: prs})
861+
.get(`/repos/${owner}/${repo}/pulls/1/commits`)
862+
.reply(200, [{sha: commits[0].hash}])
863+
.post(`/repos/${owner}/${repo}/issues/1/comments`, {body: /This PR is included/})
864+
.reply(200, {html_url: 'https://github.com/successcomment-1'})
865+
.get(
866+
`/search/issues?q=${escape('in:title')}+${escape(`repo:${owner}/${repo}`)}+${escape('type:issue')}+${escape(
867+
'state:open'
868+
)}+${escape(failTitle)}`
869+
)
870+
.reply(200, {items: []});
871+
872+
await success(pluginConfig, {
873+
env,
874+
options,
875+
branch: {name: 'master'},
876+
lastRelease,
877+
commits,
878+
nextRelease,
879+
releases,
880+
logger: t.context.logger,
881+
});
882+
883+
t.true(t.context.log.calledWith('Added comment to issue #%d: %s', 1, 'https://github.com/successcomment-1'));
884+
t.true(github.isDone());
885+
});
886+
887+
test.serial('Editing the release with no ID in the release', async (t) => {
888+
const owner = 'test_user';
889+
const repo = 'test_repo';
890+
const env = {GITHUB_TOKEN: 'github_token'};
891+
const failTitle = 'The automated release is failing 🚨';
892+
const pluginConfig = {releasedLabels: false, addReleases: 'bottom'};
893+
const prs = [{number: 1, pull_request: {}, state: 'closed'}];
894+
const options = {repositoryUrl: `https://github.com/${owner}/${repo}.git`};
895+
const nextRelease = {version: '2.0.0', gitTag: 'v1.0.0', name: 'v1.0.0', notes: 'Test release note body'};
896+
const lastRelease = {version: '1.0.0'};
897+
const commits = [{hash: '123', message: 'Commit 1 message'}];
898+
const releases = [
899+
{name: 'GitHub release', url: 'https://github.com/release'},
900+
{name: 'S3', url: 's3://my-bucket/release-asset'},
901+
{name: 'Docker: docker.io/python:slim'},
902+
];
903+
const github = authenticate(env)
904+
.get(`/repos/${owner}/${repo}`)
905+
.reply(200, {full_name: `${owner}/${repo}`})
906+
.get(
907+
`/search/issues?q=${escape(`repo:${owner}/${repo}`)}+${escape('type:pr')}+${escape('is:merged')}+${commits
908+
.map((commit) => commit.hash)
909+
.join('+')}`
910+
)
911+
.reply(200, {items: prs})
912+
.get(`/repos/${owner}/${repo}/pulls/1/commits`)
913+
.reply(200, [{sha: commits[0].hash}])
914+
.post(`/repos/${owner}/${repo}/issues/1/comments`, {body: /This PR is included/})
915+
.reply(200, {html_url: 'https://github.com/successcomment-1'})
916+
.get(
917+
`/search/issues?q=${escape('in:title')}+${escape(`repo:${owner}/${repo}`)}+${escape('type:issue')}+${escape(
918+
'state:open'
919+
)}+${escape(failTitle)}`
920+
)
921+
.reply(200, {items: []});
922+
923+
await success(pluginConfig, {
924+
env,
925+
options,
926+
branch: {name: 'master'},
927+
lastRelease,
928+
commits,
929+
nextRelease,
930+
releases,
931+
logger: t.context.logger,
932+
});
933+
934+
t.true(t.context.log.calledWith('Added comment to issue #%d: %s', 1, 'https://github.com/successcomment-1'));
935+
t.true(github.isDone());
936+
});
937+
627938
test.serial('Ignore errors when adding comments and closing issues', async (t) => {
628939
const owner = 'test_user';
629940
const repo = 'test_repo';

‎test/verify.test.js

+123
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,63 @@ test.serial('Verify "assignees" is a String', async (t) => {
340340
t.true(github.isDone());
341341
});
342342

343+
test.serial('Verify "addReleases" is a valid string (top)', async (t) => {
344+
const owner = 'test_user';
345+
const repo = 'test_repo';
346+
const env = {GH_TOKEN: 'github_token'};
347+
const addReleases = 'top';
348+
const github = authenticate(env)
349+
.get(`/repos/${owner}/${repo}`)
350+
.reply(200, {permissions: {push: true}});
351+
352+
await t.notThrowsAsync(
353+
verify(
354+
{addReleases},
355+
{env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger}
356+
)
357+
);
358+
359+
t.true(github.isDone());
360+
});
361+
362+
test.serial('Verify "addReleases" is a valid string (bottom)', async (t) => {
363+
const owner = 'test_user';
364+
const repo = 'test_repo';
365+
const env = {GH_TOKEN: 'github_token'};
366+
const addReleases = 'bottom';
367+
const github = authenticate(env)
368+
.get(`/repos/${owner}/${repo}`)
369+
.reply(200, {permissions: {push: true}});
370+
371+
await t.notThrowsAsync(
372+
verify(
373+
{addReleases},
374+
{env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger}
375+
)
376+
);
377+
378+
t.true(github.isDone());
379+
});
380+
381+
test.serial('Verify "addReleases" is valid (false)', async (t) => {
382+
const owner = 'test_user';
383+
const repo = 'test_repo';
384+
const env = {GH_TOKEN: 'github_token'};
385+
const addReleases = false;
386+
const github = authenticate(env)
387+
.get(`/repos/${owner}/${repo}`)
388+
.reply(200, {permissions: {push: true}});
389+
390+
await t.notThrowsAsync(
391+
verify(
392+
{addReleases},
393+
{env, options: {repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`}, logger: t.context.logger}
394+
)
395+
);
396+
397+
t.true(github.isDone());
398+
});
399+
343400
// https://github.com/semantic-release/github/issues/182
344401
test.serial('Verify if run in GitHub Action', async (t) => {
345402
const owner = 'test_user';
@@ -997,3 +1054,69 @@ test.serial('Throw SemanticReleaseError if "releasedLabels" option is a whitespa
9971054
t.is(error.code, 'EINVALIDRELEASEDLABELS');
9981055
t.true(github.isDone());
9991056
});
1057+
1058+
test.serial('Throw SemanticReleaseError if "addReleases" option is not a valid string (botom)', async (t) => {
1059+
const owner = 'test_user';
1060+
const repo = 'test_repo';
1061+
const env = {GH_TOKEN: 'github_token'};
1062+
const addReleases = 'botom';
1063+
const github = authenticate(env)
1064+
.get(`/repos/${owner}/${repo}`)
1065+
.reply(200, {permissions: {push: true}});
1066+
1067+
const [error, ...errors] = await t.throwsAsync(
1068+
verify(
1069+
{addReleases},
1070+
{env, options: {repositoryUrl: `https://github.com/${owner}/${repo}.git`}, logger: t.context.logger}
1071+
)
1072+
);
1073+
1074+
t.is(errors.length, 0);
1075+
t.is(error.name, 'SemanticReleaseError');
1076+
t.is(error.code, 'EINVALIDADDRELEASES');
1077+
t.true(github.isDone());
1078+
});
1079+
1080+
test.serial('Throw SemanticReleaseError if "addReleases" option is not a valid string (true)', async (t) => {
1081+
const owner = 'test_user';
1082+
const repo = 'test_repo';
1083+
const env = {GH_TOKEN: 'github_token'};
1084+
const addReleases = true;
1085+
const github = authenticate(env)
1086+
.get(`/repos/${owner}/${repo}`)
1087+
.reply(200, {permissions: {push: true}});
1088+
1089+
const [error, ...errors] = await t.throwsAsync(
1090+
verify(
1091+
{addReleases},
1092+
{env, options: {repositoryUrl: `https://github.com/${owner}/${repo}.git`}, logger: t.context.logger}
1093+
)
1094+
);
1095+
1096+
t.is(errors.length, 0);
1097+
t.is(error.name, 'SemanticReleaseError');
1098+
t.is(error.code, 'EINVALIDADDRELEASES');
1099+
t.true(github.isDone());
1100+
});
1101+
1102+
test.serial('Throw SemanticReleaseError if "addReleases" option is not a valid string (number)', async (t) => {
1103+
const owner = 'test_user';
1104+
const repo = 'test_repo';
1105+
const env = {GH_TOKEN: 'github_token'};
1106+
const addReleases = 42;
1107+
const github = authenticate(env)
1108+
.get(`/repos/${owner}/${repo}`)
1109+
.reply(200, {permissions: {push: true}});
1110+
1111+
const [error, ...errors] = await t.throwsAsync(
1112+
verify(
1113+
{addReleases},
1114+
{env, options: {repositoryUrl: `https://github.com/${owner}/${repo}.git`}, logger: t.context.logger}
1115+
)
1116+
);
1117+
1118+
t.is(errors.length, 0);
1119+
t.is(error.name, 'SemanticReleaseError');
1120+
t.is(error.code, 'EINVALIDADDRELEASES');
1121+
t.true(github.isDone());
1122+
});

0 commit comments

Comments
 (0)
Please sign in to comment.