@semantic-release/github 7.0.5 β 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -6
- package/index.js +1 -1
- package/lib/definitions/errors.js +10 -4
- package/lib/find-sr-issues.js +1 -1
- package/lib/get-client.js +2 -2
- package/lib/get-fail-comment.js +7 -5
- package/lib/get-release-links.js +22 -0
- package/lib/get-success-comment.js +2 -2
- package/lib/glob-assets.js +3 -3
- package/lib/parse-github-url.js +1 -1
- package/lib/publish.js +4 -4
- package/lib/resolve-config.js +3 -1
- package/lib/success.js +38 -17
- package/lib/verify.js +17 -6
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -59,13 +59,16 @@ When creating the token, the **minimum required scopes** are:
|
|
|
59
59
|
- [`repo`](https://github.com/settings/tokens/new?scopes=repo) for a private repository
|
|
60
60
|
- [`public_repo`](https://github.com/settings/tokens/new?scopes=public_repo) for a public repository
|
|
61
61
|
|
|
62
|
+
_Note on GitHub Actions:_ You can use the default token which is provided in the secret _GITHUB_TOKEN_. However releases done with this token will NOT trigger release events to start other workflows.
|
|
63
|
+
If you have actions that trigger on newly created releases, please use a generated token for that and store it in your repository's secrets (any other name than GITHUB_TOKEN is fine).
|
|
64
|
+
|
|
62
65
|
### Environment variables
|
|
63
66
|
|
|
64
|
-
| Variable
|
|
65
|
-
|
|
|
66
|
-
| `GH_TOKEN` or `GITHUB_TOKEN`
|
|
67
|
-
| `GH_URL` or `GITHUB_URL` | The GitHub Enterprise endpoint. |
|
|
68
|
-
| `GH_PREFIX` or `GITHUB_PREFIX`
|
|
67
|
+
| Variable | Description |
|
|
68
|
+
| -------------------------------------------------- | --------------------------------------------------------- |
|
|
69
|
+
| `GH_TOKEN` or `GITHUB_TOKEN` | **Required.** The token used to authenticate with GitHub. |
|
|
70
|
+
| `GITHUB_API_URL` or `GH_URL` or `GITHUB_URL` | The GitHub Enterprise endpoint. |
|
|
71
|
+
| `GH_PREFIX` or `GITHUB_PREFIX` | The GitHub Enterprise API prefix. |
|
|
69
72
|
|
|
70
73
|
### Options
|
|
71
74
|
|
|
@@ -80,7 +83,8 @@ When creating the token, the **minimum required scopes** are:
|
|
|
80
83
|
| `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 π¨` |
|
|
81
84
|
| `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']` |
|
|
82
85
|
| `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. | - |
|
|
83
|
-
| `releasedLabels` | The [labels](https://help.github.com/articles/about-labels) to add to each issue and pull request resolved by the release. Set to `false` to not add any label. See [releasedLabels](#releasedlabels). | `['released<%= nextRelease.channel ? \` on @\${nextRelease.channel}\` : "" %>']
|
|
86
|
+
| `releasedLabels` | The [labels](https://help.github.com/articles/about-labels) to add to each issue and pull request resolved by the release. Set to `false` to not add any label. See [releasedLabels](#releasedlabels). | `['released<%= nextRelease.channel ? \` on @\${nextRelease.channel}\` : "" %>']- |
|
|
87
|
+
| `addReleases` | Will add release links to the GitHub Release. Can be `false`, `"bottom"` or `"top"`. See [addReleases](#addReleases). | `false` |
|
|
84
88
|
|
|
85
89
|
#### proxy
|
|
86
90
|
|
|
@@ -201,3 +205,13 @@ Each label name is generated with [Lodash template](https://lodash.com/docs#temp
|
|
|
201
205
|
The `releasedLabels` ```['released<%= nextRelease.channel ? ` on @\${nextRelease.channel}` : "" %> from <%= branch.name %>']``` will generate the label:
|
|
202
206
|
|
|
203
207
|
> released on @next from branch next
|
|
208
|
+
|
|
209
|
+
#### addReleases
|
|
210
|
+
|
|
211
|
+
Add links to other releases to the GitHub release body.
|
|
212
|
+
|
|
213
|
+
Valid values for this option are `false`, `"top"` or `"bottom"`.
|
|
214
|
+
|
|
215
|
+
##### addReleases example
|
|
216
|
+
|
|
217
|
+
See [The introducing PR](https://github.com/semantic-release/github/pull/282) for an example on how it will look.
|
package/index.js
CHANGED
|
@@ -14,7 +14,7 @@ async function verifyConditions(pluginConfig, context) {
|
|
|
14
14
|
// If the GitHub publish plugin is used and has `assets`, `successComment`, `failComment`, `failTitle`, `labels` or `assignees` configured, validate it now in order to prevent any release if the configuration is wrong
|
|
15
15
|
if (options.publish) {
|
|
16
16
|
const publishPlugin =
|
|
17
|
-
castArray(options.publish).find(config => config.path && config.path === '@semantic-release/github') || {};
|
|
17
|
+
castArray(options.publish).find((config) => config.path && config.path === '@semantic-release/github') || {};
|
|
18
18
|
|
|
19
19
|
pluginConfig.assets = defaultTo(pluginConfig.assets, publishPlugin.assets);
|
|
20
20
|
pluginConfig.successComment = defaultTo(pluginConfig.successComment, publishPlugin.successComment);
|
|
@@ -3,9 +3,9 @@ const {isString} = require('lodash');
|
|
|
3
3
|
const pkg = require('../../package.json');
|
|
4
4
|
|
|
5
5
|
const [homepage] = pkg.homepage.split('#');
|
|
6
|
-
const stringify = object =>
|
|
6
|
+
const stringify = (object) =>
|
|
7
7
|
isString(object) ? object : inspect(object, {breakLength: Infinity, depth: 2, maxArrayLength: 5});
|
|
8
|
-
const linkify = file => `${homepage}/blob/master/${file}`;
|
|
8
|
+
const linkify = (file) => `${homepage}/blob/master/${file}`;
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
11
|
EINVALIDASSETS: ({assets}) => ({
|
|
@@ -57,6 +57,12 @@ Your configuration for the \`assignees\` option is \`${stringify(assignees)}\`.`
|
|
|
57
57
|
)}) if defined, must be an \`Array\` of non empty \`String\`.
|
|
58
58
|
|
|
59
59
|
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)}\`.`,
|
|
60
66
|
}),
|
|
61
67
|
EINVALIDGITHUBURL: () => ({
|
|
62
68
|
message: 'The git repository URL is not a valid GitHub URL.',
|
|
@@ -73,7 +79,7 @@ By default the \`repositoryUrl\` option is retrieved from the \`repository\` pro
|
|
|
73
79
|
Your configuration for the \`proxy\` option is \`${stringify(proxy)}\`.`,
|
|
74
80
|
}),
|
|
75
81
|
EMISSINGREPO: ({owner, repo}) => ({
|
|
76
|
-
message: `The repository ${owner}/${repo} doesn
|
|
82
|
+
message: `The repository ${owner}/${repo} doesn't exist.`,
|
|
77
83
|
details: `The **semantic-release** \`repositoryUrl\` option must refer to your GitHub repository. The repository must be accessible with the [GitHub API](https://developer.github.com/v3).
|
|
78
84
|
|
|
79
85
|
By default the \`repositoryUrl\` option is retrieved from the \`repository\` property of your \`package.json\` or the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) of the repository cloned by your CI environment.
|
|
@@ -83,7 +89,7 @@ If you are using [GitHub Enterprise](https://enterprise.github.com) please make
|
|
|
83
89
|
)}).`,
|
|
84
90
|
}),
|
|
85
91
|
EGHNOPERMISSION: ({owner, repo}) => ({
|
|
86
|
-
message: `The GitHub token doesn
|
|
92
|
+
message: `The GitHub token doesn't allow to push on the repository ${owner}/${repo}.`,
|
|
87
93
|
details: `The user associated with the [GitHub token](${linkify(
|
|
88
94
|
'README.md#github-authentication'
|
|
89
95
|
)}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must allows to push to the repository ${owner}/${repo}.
|
package/lib/find-sr-issues.js
CHANGED
|
@@ -7,5 +7,5 @@ module.exports = async (github, title, owner, repo) => {
|
|
|
7
7
|
q: `in:title+repo:${owner}/${repo}+type:issue+state:open+${title}`,
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
return issues.filter(issue => issue.body && issue.body.includes(ISSUE_ID));
|
|
10
|
+
return issues.filter((issue) => issue.body && issue.body.includes(ISSUE_ID));
|
|
11
11
|
};
|
package/lib/get-client.js
CHANGED
|
@@ -11,7 +11,7 @@ const {RETRY_CONF, RATE_LIMITS, GLOBAL_RATE_LIMIT} = require('./definitions/rate
|
|
|
11
11
|
/**
|
|
12
12
|
* Http error status for which to not retry.
|
|
13
13
|
*/
|
|
14
|
-
const SKIP_RETRY_CODES = [400, 401, 403];
|
|
14
|
+
const SKIP_RETRY_CODES = new Set([400, 401, 403]);
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Create or retrieve the throttler function for a given rate limit group.
|
|
@@ -50,7 +50,7 @@ module.exports = ({githubToken, githubUrl, githubApiPathPrefix, proxy}) => {
|
|
|
50
50
|
try {
|
|
51
51
|
return await getThrottler(limitKey, globalThrottler).wrap(request)(options);
|
|
52
52
|
} catch (error) {
|
|
53
|
-
if (SKIP_RETRY_CODES.
|
|
53
|
+
if (SKIP_RETRY_CODES.has(error.status)) {
|
|
54
54
|
throw new pRetry.AbortError(error);
|
|
55
55
|
}
|
|
56
56
|
|
package/lib/get-fail-comment.js
CHANGED
|
@@ -4,14 +4,16 @@ const GET_HELP_URL = `${HOME_URL}#get-help`;
|
|
|
4
4
|
const USAGE_DOC_URL = `${HOME_URL}/blob/caribou/docs/usage/README.md`;
|
|
5
5
|
const NEW_ISSUE_URL = `${HOME_URL}/issues/new`;
|
|
6
6
|
|
|
7
|
-
const formatError = error => `### ${error.message}
|
|
7
|
+
const formatError = (error) => `### ${error.message}
|
|
8
8
|
|
|
9
|
-
${
|
|
10
|
-
|
|
9
|
+
${
|
|
10
|
+
error.details ||
|
|
11
|
+
`Unfortunately this error doesn't have any additional information.${
|
|
11
12
|
error.pluginName
|
|
12
13
|
? ` Feel free to kindly ask the author of the \`${error.pluginName}\` plugin to add more helpful information.`
|
|
13
14
|
: ''
|
|
14
|
-
}`
|
|
15
|
+
}`
|
|
16
|
+
}`;
|
|
15
17
|
|
|
16
18
|
module.exports = (branch, errors) => `## :rotating_light: The automated release from the \`${
|
|
17
19
|
branch.name
|
|
@@ -36,7 +38,7 @@ If those donβt help, or if this issue is reporting something you think isnβt
|
|
|
36
38
|
|
|
37
39
|
---
|
|
38
40
|
|
|
39
|
-
${errors.map(formatError).join('\n\n---\n\n')}
|
|
41
|
+
${errors.map((error) => formatError(error)).join('\n\n---\n\n')}
|
|
40
42
|
|
|
41
43
|
---
|
|
42
44
|
|
|
@@ -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
|
+
}`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const HOME_URL = 'https://github.com/semantic-release/semantic-release';
|
|
2
|
-
const linkify = releaseInfo =>
|
|
2
|
+
const linkify = (releaseInfo) =>
|
|
3
3
|
`${releaseInfo.url ? `[${releaseInfo.name}](${releaseInfo.url})` : `\`${releaseInfo.name}\``}`;
|
|
4
4
|
|
|
5
5
|
module.exports = (issue, releaseInfos, nextRelease) =>
|
|
@@ -10,7 +10,7 @@ module.exports = (issue, releaseInfos, nextRelease) =>
|
|
|
10
10
|
? `\n\nThe release is available on${
|
|
11
11
|
releaseInfos.length === 1
|
|
12
12
|
? ` ${linkify(releaseInfos[0])}`
|
|
13
|
-
: `:\n${releaseInfos.map(releaseInfo => `- ${linkify(releaseInfo)}`).join('\n')}`
|
|
13
|
+
: `:\n${releaseInfos.map((releaseInfo) => `- ${linkify(releaseInfo)}`).join('\n')}`
|
|
14
14
|
}`
|
|
15
15
|
: ''
|
|
16
16
|
}
|
package/lib/glob-assets.js
CHANGED
|
@@ -10,7 +10,7 @@ module.exports = async ({cwd}, assets) =>
|
|
|
10
10
|
[]
|
|
11
11
|
.concat(
|
|
12
12
|
...(await Promise.all(
|
|
13
|
-
assets.map(async asset => {
|
|
13
|
+
assets.map(async (asset) => {
|
|
14
14
|
// Wrap single glob definition in Array
|
|
15
15
|
let glob = castArray(isPlainObject(asset) ? asset.path : asset);
|
|
16
16
|
// TODO Temporary workaround for https://github.com/mrmlnc/fast-glob/issues/47
|
|
@@ -40,7 +40,7 @@ module.exports = async ({cwd}, assets) =>
|
|
|
40
40
|
// - `path` of the matched file
|
|
41
41
|
// - `name` based on the actual file name (to avoid assets with duplicate `name`)
|
|
42
42
|
// - other properties of the original asset definition
|
|
43
|
-
return globbed.map(file => ({...asset, path: file, name: basename(file)}));
|
|
43
|
+
return globbed.map((file) => ({...asset, path: file, name: basename(file)}));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// If asset is an Object, output an Object definition with:
|
|
@@ -60,7 +60,7 @@ module.exports = async ({cwd}, assets) =>
|
|
|
60
60
|
// Sort with Object first, to prioritize Object definition over Strings in dedup
|
|
61
61
|
))
|
|
62
62
|
)
|
|
63
|
-
.sort(asset => (isPlainObject(asset) ? -1 : 1)),
|
|
63
|
+
.sort((asset) => (isPlainObject(asset) ? -1 : 1)),
|
|
64
64
|
// Compare `path` property if Object definition, value itself if String
|
|
65
65
|
(a, b) => path.resolve(cwd, isPlainObject(a) ? a.path : a) === path.resolve(cwd, isPlainObject(b) ? b.path : b)
|
|
66
66
|
);
|
package/lib/parse-github-url.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module.exports = repositoryUrl => {
|
|
1
|
+
module.exports = (repositoryUrl) => {
|
|
2
2
|
const [match, auth, host, path] = /^(?!.+:\/\/)(?:(?<auth>.*)@)?(?<host>.*?):(?<path>.*)$/.exec(repositoryUrl) || [];
|
|
3
3
|
try {
|
|
4
4
|
const [, owner, repo] = /^\/(?<owner>[^/]+)?\/?(?<repo>.+?)(?:\.git)?$/.exec(
|
package/lib/publish.js
CHANGED
|
@@ -28,11 +28,11 @@ module.exports = async (pluginConfig, context) => {
|
|
|
28
28
|
// When there are no assets, we publish a release directly
|
|
29
29
|
if (!assets || assets.length === 0) {
|
|
30
30
|
const {
|
|
31
|
-
data: {html_url: url},
|
|
31
|
+
data: {html_url: url, id: releaseId},
|
|
32
32
|
} = await github.repos.createRelease(release);
|
|
33
33
|
|
|
34
34
|
logger.log('Published GitHub release: %s', url);
|
|
35
|
-
return {url, name: RELEASE_NAME};
|
|
35
|
+
return {url, name: RELEASE_NAME, id: releaseId};
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// We'll create a draft release, append the assets to it, and then publish it.
|
|
@@ -48,7 +48,7 @@ module.exports = async (pluginConfig, context) => {
|
|
|
48
48
|
debug('globed assets: %o', globbedAssets);
|
|
49
49
|
|
|
50
50
|
await Promise.all(
|
|
51
|
-
globbedAssets.map(async asset => {
|
|
51
|
+
globbedAssets.map(async (asset) => {
|
|
52
52
|
const filePath = isPlainObject(asset) ? asset.path : asset;
|
|
53
53
|
let file;
|
|
54
54
|
|
|
@@ -94,5 +94,5 @@ module.exports = async (pluginConfig, context) => {
|
|
|
94
94
|
} = await github.repos.updateRelease({owner, repo, release_id: releaseId, draft: false});
|
|
95
95
|
|
|
96
96
|
logger.log('Published GitHub release: %s', url);
|
|
97
|
-
return {url, name: RELEASE_NAME};
|
|
97
|
+
return {url, name: RELEASE_NAME, id: releaseId};
|
|
98
98
|
};
|
package/lib/resolve-config.js
CHANGED
|
@@ -12,11 +12,12 @@ module.exports = (
|
|
|
12
12
|
labels,
|
|
13
13
|
assignees,
|
|
14
14
|
releasedLabels,
|
|
15
|
+
addReleases,
|
|
15
16
|
},
|
|
16
17
|
{env}
|
|
17
18
|
) => ({
|
|
18
19
|
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
|
|
19
|
-
githubUrl: githubUrl || env.GH_URL || env.GITHUB_URL,
|
|
20
|
+
githubUrl: githubUrl || env.GITHUB_API_URL || env.GH_URL || env.GITHUB_URL,
|
|
20
21
|
githubApiPathPrefix: githubApiPathPrefix || env.GH_PREFIX || env.GITHUB_PREFIX || '',
|
|
21
22
|
proxy: proxy || env.HTTP_PROXY,
|
|
22
23
|
assets: assets ? castArray(assets) : assets,
|
|
@@ -30,4 +31,5 @@ module.exports = (
|
|
|
30
31
|
: releasedLabels === false
|
|
31
32
|
? false
|
|
32
33
|
: castArray(releasedLabels),
|
|
34
|
+
addReleases: isNil(addReleases) ? false : addReleases,
|
|
33
35
|
});
|
package/lib/success.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {isNil, uniqBy, template, flatten} = require('lodash');
|
|
1
|
+
const {isNil, uniqBy, template, flatten, isEmpty} = require('lodash');
|
|
2
2
|
const pFilter = require('p-filter');
|
|
3
3
|
const AggregateError = require('aggregate-error');
|
|
4
4
|
const issueParser = require('issue-parser');
|
|
@@ -9,6 +9,8 @@ const getClient = require('./get-client');
|
|
|
9
9
|
const getSearchQueries = require('./get-search-queries');
|
|
10
10
|
const getSuccessComment = require('./get-success-comment');
|
|
11
11
|
const findSRIssues = require('./find-sr-issues');
|
|
12
|
+
const {RELEASE_NAME} = require('./definitions/constants');
|
|
13
|
+
const getReleaseLinks = require('./get-release-links');
|
|
12
14
|
|
|
13
15
|
module.exports = async (pluginConfig, context) => {
|
|
14
16
|
const {
|
|
@@ -27,6 +29,7 @@ module.exports = async (pluginConfig, context) => {
|
|
|
27
29
|
failComment,
|
|
28
30
|
failTitle,
|
|
29
31
|
releasedLabels,
|
|
32
|
+
addReleases,
|
|
30
33
|
} = resolveConfig(pluginConfig, context);
|
|
31
34
|
|
|
32
35
|
const github = getClient({githubToken, githubUrl, githubApiPathPrefix, proxy});
|
|
@@ -39,11 +42,11 @@ module.exports = async (pluginConfig, context) => {
|
|
|
39
42
|
logger.log('Skip commenting on issues and pull requests.');
|
|
40
43
|
} else {
|
|
41
44
|
const parser = issueParser('github', githubUrl ? {hosts: [githubUrl]} : {});
|
|
42
|
-
const releaseInfos = releases.filter(release => Boolean(release.name));
|
|
45
|
+
const releaseInfos = releases.filter((release) => Boolean(release.name));
|
|
43
46
|
const shas = commits.map(({hash}) => hash);
|
|
44
47
|
|
|
45
48
|
const searchQueries = getSearchQueries(`repo:${owner}/${repo}+type:pr+is:merged`, shas).map(
|
|
46
|
-
async q => (await github.search.issuesAndPullRequests({q})).data.items
|
|
49
|
+
async (q) => (await github.search.issuesAndPullRequests({q})).data.items
|
|
47
50
|
);
|
|
48
51
|
|
|
49
52
|
const prs = await pFilter(
|
|
@@ -55,24 +58,27 @@ module.exports = async (pluginConfig, context) => {
|
|
|
55
58
|
|
|
56
59
|
debug(
|
|
57
60
|
'found pull requests: %O',
|
|
58
|
-
prs.map(pr => pr.number)
|
|
61
|
+
prs.map((pr) => pr.number)
|
|
59
62
|
);
|
|
60
63
|
|
|
61
64
|
// Parse the release commits message and PRs body to find resolved issues/PRs via comment keyworkds
|
|
62
|
-
const issues = [...prs.map(pr => pr.body), ...commits.map(commit => commit.message)].reduce(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
const issues = [...prs.map((pr) => pr.body), ...commits.map((commit) => commit.message)].reduce(
|
|
66
|
+
(issues, message) => {
|
|
67
|
+
return message
|
|
68
|
+
? issues.concat(
|
|
69
|
+
parser(message)
|
|
70
|
+
.actions.close.filter((action) => isNil(action.slug) || action.slug === `${owner}/${repo}`)
|
|
71
|
+
.map((action) => ({number: Number.parseInt(action.issue, 10)}))
|
|
72
|
+
)
|
|
73
|
+
: issues;
|
|
74
|
+
},
|
|
75
|
+
[]
|
|
76
|
+
);
|
|
71
77
|
|
|
72
78
|
debug('found issues via comments: %O', issues);
|
|
73
79
|
|
|
74
80
|
await Promise.all(
|
|
75
|
-
uniqBy([...prs, ...issues], 'number').map(async issue => {
|
|
81
|
+
uniqBy([...prs, ...issues], 'number').map(async (issue) => {
|
|
76
82
|
const body = successComment
|
|
77
83
|
? template(successComment)({...context, issue})
|
|
78
84
|
: getSuccessComment(issue, releaseInfos, nextRelease);
|
|
@@ -85,7 +91,7 @@ module.exports = async (pluginConfig, context) => {
|
|
|
85
91
|
logger.log('Added comment to issue #%d: %s', issue.number, url);
|
|
86
92
|
|
|
87
93
|
if (releasedLabels) {
|
|
88
|
-
const labels = releasedLabels.map(label => template(label)(context));
|
|
94
|
+
const labels = releasedLabels.map((label) => template(label)(context));
|
|
89
95
|
// Donβt use .issues.addLabels for GHE < 2.16 support
|
|
90
96
|
// https://github.com/semantic-release/github/issues/138
|
|
91
97
|
await github.request('POST /repos/:owner/:repo/issues/:number/labels', {
|
|
@@ -100,7 +106,7 @@ module.exports = async (pluginConfig, context) => {
|
|
|
100
106
|
if (error.status === 403) {
|
|
101
107
|
logger.error('Not allowed to add a comment to the issue #%d.', issue.number);
|
|
102
108
|
} else if (error.status === 404) {
|
|
103
|
-
logger.error(
|
|
109
|
+
logger.error("Failed to add a comment to the issue #%d as it doesn't exist.", issue.number);
|
|
104
110
|
} else {
|
|
105
111
|
errors.push(error);
|
|
106
112
|
logger.error('Failed to add a comment to the issue #%d.', issue.number);
|
|
@@ -119,7 +125,7 @@ module.exports = async (pluginConfig, context) => {
|
|
|
119
125
|
debug('found semantic-release issues: %O', srIssues);
|
|
120
126
|
|
|
121
127
|
await Promise.all(
|
|
122
|
-
srIssues.map(async issue => {
|
|
128
|
+
srIssues.map(async (issue) => {
|
|
123
129
|
debug('close issue: %O', issue);
|
|
124
130
|
try {
|
|
125
131
|
const updateIssue = {owner, repo, issue_number: issue.number, state: 'closed'};
|
|
@@ -137,6 +143,21 @@ module.exports = async (pluginConfig, context) => {
|
|
|
137
143
|
);
|
|
138
144
|
}
|
|
139
145
|
|
|
146
|
+
if (addReleases !== false && errors.length === 0) {
|
|
147
|
+
const ghRelease = releases.find((release) => release.name && release.name === RELEASE_NAME);
|
|
148
|
+
if (!isNil(ghRelease)) {
|
|
149
|
+
const ghRelaseId = ghRelease.id;
|
|
150
|
+
const additionalReleases = getReleaseLinks(releases);
|
|
151
|
+
if (!isEmpty(additionalReleases) && !isNil(ghRelaseId)) {
|
|
152
|
+
const newBody =
|
|
153
|
+
addReleases === 'top'
|
|
154
|
+
? additionalReleases.concat('\n---\n', nextRelease.notes)
|
|
155
|
+
: nextRelease.notes.concat('\n---\n', additionalReleases);
|
|
156
|
+
await github.repos.updateRelease({owner, repo, release_id: ghRelaseId, body: newBody});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
140
161
|
if (errors.length > 0) {
|
|
141
162
|
throw new AggregateError(errors);
|
|
142
163
|
}
|
package/lib/verify.js
CHANGED
|
@@ -6,16 +6,18 @@ const resolveConfig = require('./resolve-config');
|
|
|
6
6
|
const getClient = require('./get-client');
|
|
7
7
|
const getError = require('./get-error');
|
|
8
8
|
|
|
9
|
-
const isNonEmptyString = value => isString(value) && value.trim();
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
9
|
+
const isNonEmptyString = (value) => isString(value) && value.trim();
|
|
10
|
+
const oneOf = (enumArray) => (value) => enumArray.some((element) => element === value);
|
|
11
|
+
const isStringOrStringArray = (value) =>
|
|
12
|
+
isNonEmptyString(value) || (isArray(value) && value.every((string) => isNonEmptyString(string)));
|
|
13
|
+
const isArrayOf = (validator) => (array) => isArray(array) && array.every((value) => validator(value));
|
|
14
|
+
const canBeDisabled = (validator) => (value) => value === false || validator(value);
|
|
13
15
|
|
|
14
16
|
const VALIDATORS = {
|
|
15
|
-
proxy: proxy =>
|
|
17
|
+
proxy: (proxy) =>
|
|
16
18
|
isNonEmptyString(proxy) || (isPlainObject(proxy) && isNonEmptyString(proxy.host) && isNumber(proxy.port)),
|
|
17
19
|
assets: isArrayOf(
|
|
18
|
-
asset => isStringOrStringArray(asset) || (isPlainObject(asset) && isStringOrStringArray(asset.path))
|
|
20
|
+
(asset) => isStringOrStringArray(asset) || (isPlainObject(asset) && isStringOrStringArray(asset.path))
|
|
19
21
|
),
|
|
20
22
|
successComment: canBeDisabled(isNonEmptyString),
|
|
21
23
|
failTitle: canBeDisabled(isNonEmptyString),
|
|
@@ -23,6 +25,7 @@ const VALIDATORS = {
|
|
|
23
25
|
labels: canBeDisabled(isArrayOf(isNonEmptyString)),
|
|
24
26
|
assignees: isArrayOf(isNonEmptyString),
|
|
25
27
|
releasedLabels: canBeDisabled(isArrayOf(isNonEmptyString)),
|
|
28
|
+
addReleases: canBeDisabled(oneOf(['bottom', 'top'])),
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
module.exports = async (pluginConfig, context) => {
|
|
@@ -68,6 +71,14 @@ module.exports = async (pluginConfig, context) => {
|
|
|
68
71
|
},
|
|
69
72
|
} = await github.repos.get({repo, owner});
|
|
70
73
|
if (!push) {
|
|
74
|
+
// If authenticated as GitHub App installation, `push` will always be false.
|
|
75
|
+
// We send another request to check if current authentication is an installation.
|
|
76
|
+
// Note: we cannot check if the installation has all required permissions, it's
|
|
77
|
+
// up to the user to make sure it has
|
|
78
|
+
if (await github.request('HEAD /installation/repositories', {per_page: 1}).catch(() => false)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
errors.push(getError('EGHNOPERMISSION', {owner, repo}));
|
|
72
83
|
}
|
|
73
84
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semantic-release/github",
|
|
3
3
|
"description": "semantic-release plugin to publish a GitHub release and comment on released Pull Requests/Issues",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.1.1",
|
|
5
5
|
"author": "Pierre Vanduynslager (https://twitter.com/@pvdlg_)",
|
|
6
6
|
"ava": {
|
|
7
7
|
"files": [
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"server-destroy": "^1.0.1",
|
|
46
46
|
"sinon": "^9.0.0",
|
|
47
47
|
"tempy": "^0.5.0",
|
|
48
|
-
"xo": "^0.
|
|
48
|
+
"xo": "^0.30.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=10.18"
|
|
@@ -110,7 +110,8 @@
|
|
|
110
110
|
{
|
|
111
111
|
"properties": "never"
|
|
112
112
|
}
|
|
113
|
-
]
|
|
113
|
+
],
|
|
114
|
+
"unicorn/string-content": "off"
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
}
|