Skip to content

Commit 06979d8

Browse files
committed
feat: add details to error messages
1 parent 0e5b372 commit 06979d8

File tree

7 files changed

+86
-27
lines changed

7 files changed

+86
-27
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Add a comment to each GitHub issue or pull request resolved by the release.
3030
The GitHub authentication configuration is **required** and can be set via
3131
[environment variables](#environment-variables).
3232

33-
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.
33+
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.
3434

3535
### Environment variables
3636

lib/definitions/errors.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const url = require('url');
2+
const {inspect} = require('util');
3+
const {isString} = require('lodash');
4+
const pkg = require('../../package.json');
5+
6+
const homepage = url.format({...url.parse(pkg.homepage), ...{hash: null}});
7+
const stringify = obj => (isString(obj) ? obj : inspect(obj, {breakLength: Infinity, depth: 2, maxArrayLength: 5}));
8+
const linkify = file => `${homepage}/blob/master/${file}`;
9+
10+
module.exports = {
11+
EINVALIDASSETS: ({assets}) => ({
12+
message: 'Invalid `assets` option.',
13+
details: `The [assets option](${linkify(
14+
'README.md#assets'
15+
)}) option must be an \`Array\` of \`Strings\` or \`Objects\` with a \`path\` property.
16+
17+
Your configuration for the \`assets\` option is \`${stringify(assets)}\`.`,
18+
}),
19+
EINVALIDSUCCESSCOMMENT: ({successComment}) => ({
20+
message: 'Invalid `successComment` option.',
21+
details: `The [successComment option](${linkify(
22+
'README.md#successcomment'
23+
)}) option, if defined, must be a non empty \`String\`.
24+
25+
Your configuration for the \`successComment\` option is \`${stringify(successComment)}\`.`,
26+
}),
27+
EINVALIDGITHUBURL: () => ({
28+
message: 'The git repository URL is not a valid GitHub URL.',
29+
details: `The **semantic-release** \`repositoryUrl\` option must a valid GitHub URL with the format \`<GitHub_or_GHE_URL>/<owner>/<repo>.git\`.
30+
31+
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.`,
32+
}),
33+
EMISSINGREPO: ({owner, repo}) => ({
34+
message: `The repository ${owner}/${repo} doesn't exist.`,
35+
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).
36+
37+
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.
38+
39+
If you are using [GitHub Enterprise](https://enterprise.github.com) please make sure to configure the \`githubUrl\` and \`githubApiPathPrefix\` [options](${linkify(
40+
'README.md#options'
41+
)}).`,
42+
}),
43+
EGHNOPERMISSION: ({owner, repo}) => ({
44+
message: `The GitHub token doesn't allow to push on the repository ${owner}/${repo}.`,
45+
details: `The user associated with the [GitHub token](${linkify(
46+
'README.md#github-authentication'
47+
)}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must allows to push to the repository ${owner}/${repo}.
48+
49+
Please make sure the GitHub user associated with the token is an [owner](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#owner-access-on-a-repository-owned-by-a-user-account) or a [collaborator](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#collaborator-access-on-a-repository-owned-by-a-user-account) if the reposotory belong to a user account or has [write permissions](https://help.github.com/articles/managing-team-access-to-an-organization-repository) if the repository [belongs to an organization](https://help.github.com/articles/repository-permission-levels-for-an-organization).`,
50+
}),
51+
EINVALIDGHTOKEN: ({owner, repo}) => ({
52+
message: 'Invalid GitHub token.',
53+
details: `The [GitHub token](${linkify(
54+
'README.md#github-authentication'
55+
)}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must be a valid [personnal token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) allowing to push to the repository ${owner}/${repo}.
56+
57+
Please make sure to set the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable in your CI with the exact value of the GitHub personnal token.`,
58+
}),
59+
ENOGHTOKEN: ({owner, repo}) => ({
60+
message: 'No GitHub token specified.',
61+
details: `A [GitHub personnal token](${linkify(
62+
'README.md#github-authentication'
63+
)}) must be created and set in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable on your CI environment.
64+
65+
Please make sure to create a [GitHub personnal token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) and to set it in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable on your CI environment. The token must allow to push to the repository ${owner}/${repo}.`,
66+
}),
67+
};

lib/get-error.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const SemanticReleaseError = require('@semantic-release/error');
2+
const ERROR_DEFINITIONS = require('./definitions/errors');
3+
4+
module.exports = (code, ctx = {}) => {
5+
const {message, details} = ERROR_DEFINITIONS[code](ctx);
6+
return new SemanticReleaseError(message, code, details);
7+
};

lib/verify.js

+8-23
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ const {isString, isPlainObject, isUndefined, isArray} = require('lodash');
22
const parseGithubUrl = require('parse-github-url');
33
const urlJoin = require('url-join');
44
const AggregateError = require('aggregate-error');
5-
const SemanticReleaseError = require('@semantic-release/error');
65
const resolveConfig = require('./resolve-config');
76
const getClient = require('./get-client');
7+
const getError = require('./get-error');
88

99
const isNonEmptyString = value => isString(value) && value.trim();
1010
const isStringOrStringArray = value => isNonEmptyString(value) || (isArray(value) && value.every(isNonEmptyString));
@@ -21,21 +21,11 @@ module.exports = async (pluginConfig, {options: {repositoryUrl}, logger}) => {
2121
assets.every(asset => isStringOrStringArray(asset) || (isPlainObject(asset) && isStringOrStringArray(asset.path)))
2222
)
2323
) {
24-
errors.push(
25-
new SemanticReleaseError(
26-
'The "assets" options must be an Array of Strings or Objects with a path property.',
27-
'EINVALIDASSETS'
28-
)
29-
);
24+
errors.push(getError('EINVALIDASSETS', {assets}));
3025
}
3126

3227
if (!isUndefined(successComment) && successComment !== false && !isNonEmptyString(successComment)) {
33-
errors.push(
34-
new SemanticReleaseError(
35-
'The "successComment" options, if defined, must be a non empty String.',
36-
'EINVALIDSUCCESSCOMMENT'
37-
)
38-
);
28+
errors.push(getError('EINVALIDSUCCESSCOMMENT', {successComment}));
3929
}
4030

4131
if (githubUrl) {
@@ -46,7 +36,7 @@ module.exports = async (pluginConfig, {options: {repositoryUrl}, logger}) => {
4636

4737
const {name: repo, owner} = parseGithubUrl(repositoryUrl);
4838
if (!owner || !repo) {
49-
errors.push(new SemanticReleaseError('The git repository URL is not a valid GitHub URL.', 'EINVALIDGITURL'));
39+
errors.push(getError('EINVALIDGITHUBURL'));
5040
}
5141

5242
if (githubToken) {
@@ -55,24 +45,19 @@ module.exports = async (pluginConfig, {options: {repositoryUrl}, logger}) => {
5545
try {
5646
const {data: {permissions: {push}}} = await github.repos.get({repo, owner});
5747
if (!push) {
58-
errors.push(
59-
new SemanticReleaseError(
60-
`The github token doesn't allow to push on the repository ${owner}/${repo}.`,
61-
'EGHNOPERMISSION'
62-
)
63-
);
48+
errors.push(getError('EGHNOPERMISSION', {owner, repo}));
6449
}
6550
} catch (err) {
6651
if (err.code === 401) {
67-
errors.push(new SemanticReleaseError('Invalid GitHub token.', 'EINVALIDGHTOKEN'));
52+
errors.push(getError('EINVALIDGHTOKEN', {owner, repo}));
6853
} else if (err.code === 404) {
69-
errors.push(new SemanticReleaseError(`The repository ${owner}/${repo} doesn't exist.`, 'EMISSINGREPO'));
54+
errors.push(getError('EMISSINGREPO', {owner, repo}));
7055
} else {
7156
throw err;
7257
}
7358
}
7459
} else {
75-
errors.push(new SemanticReleaseError('No github token specified.', 'ENOGHTOKEN'));
60+
errors.push(getError('ENOGHTOKEN', {owner, repo}));
7661
}
7762
if (errors.length > 0) {
7863
throw new AggregateError(errors);

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
],
1818
"dependencies": {
1919
"@octokit/rest": "^14.0.9",
20-
"@semantic-release/error": "^2.1.0",
20+
"@semantic-release/error": "^2.2.0",
2121
"aggregate-error": "^1.0.0",
2222
"debug": "^3.1.0",
2323
"fs-extra": "^5.0.0",

test/integration.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ test.serial('Throw SemanticReleaseError if invalid config', async t => {
105105
t.is(errors[1].name, 'SemanticReleaseError');
106106
t.is(errors[1].code, 'EINVALIDSUCCESSCOMMENT');
107107
t.is(errors[2].name, 'SemanticReleaseError');
108-
t.is(errors[2].code, 'EINVALIDGITURL');
108+
t.is(errors[2].code, 'EINVALIDGITHUBURL');
109109
t.is(errors[3].name, 'SemanticReleaseError');
110110
t.is(errors[3].code, 'ENOGHTOKEN');
111111
});

test/verify.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ test.serial('Throw SemanticReleaseError for invalid repositoryUrl', async t => {
317317
const [error] = await t.throws(verify({}, {options: {repositoryUrl: 'invalid_url'}, logger: t.context.logger}));
318318

319319
t.is(error.name, 'SemanticReleaseError');
320-
t.is(error.code, 'EINVALIDGITURL');
320+
t.is(error.code, 'EINVALIDGITHUBURL');
321321
});
322322

323323
test.serial("Throw SemanticReleaseError if token doesn't have the push permission on the repository", async t => {

0 commit comments

Comments
 (0)