release-it 14.1.0-next.0 → 14.2.2
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 +2 -2
- package/lib/plugin/GitBase.js +2 -1
- package/lib/plugin/Plugin.js +1 -0
- package/lib/plugin/version/Version.js +10 -5
- package/lib/tasks.js +2 -0
- package/package.json +18 -18
- package/test/git.init.js +8 -7
- package/test/github.js +7 -9
- package/test/gitlab.js +8 -8
- package/test/npm.js +3 -3
- package/test/plugins.js +70 -1
- package/test/stub/shell.js +4 -2
- package/test/tasks.js +5 -16
- package/test/util/index.js +25 -5
- package/test/version.js +57 -2
package/README.md
CHANGED
|
@@ -241,8 +241,8 @@ The "Releases" tab on GitHub projects links to a page to store the changelog cq.
|
|
|
241
241
|
[GitHub releases](https://help.github.com/articles/creating-releases) in your release-it flow:
|
|
242
242
|
|
|
243
243
|
- Configure `github.release: true`
|
|
244
|
-
- Obtain a [personal access token](https://github.com/settings/tokens
|
|
245
|
-
or other scopes).
|
|
244
|
+
- Obtain a [personal access token](https://github.com/settings/tokens/new?scopes=repo&description=release-it)
|
|
245
|
+
(release-it only needs "repo" access; no "admin" or other scopes).
|
|
246
246
|
- Make sure the token is [available as an environment variable](./docs/environment-variables.md).
|
|
247
247
|
|
|
248
248
|
→ See [GitHub Releases](./docs/github-releases.md) for more details.
|
package/lib/plugin/GitBase.js
CHANGED
|
@@ -49,7 +49,8 @@ class GitBase extends Plugin {
|
|
|
49
49
|
|
|
50
50
|
bump(version) {
|
|
51
51
|
const { tagTemplate } = this.getContext();
|
|
52
|
-
const
|
|
52
|
+
const context = Object.assign(this.config.getContext(), { version });
|
|
53
|
+
const tagName = format(tagTemplate, context) || version;
|
|
53
54
|
this.setContext({ version, tagName });
|
|
54
55
|
this.config.setContext({ tagName });
|
|
55
56
|
}
|
package/lib/plugin/Plugin.js
CHANGED
|
@@ -57,9 +57,11 @@ class Version extends Plugin {
|
|
|
57
57
|
return '0.0.0';
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
getIncrement(options) {
|
|
61
|
+
return options.increment;
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
getIncrementedVersionCI(options) {
|
|
61
|
-
const { isCI } = this.config;
|
|
62
|
-
options.increment = options.increment == null && isCI ? 'patch' : options.increment;
|
|
63
65
|
return this.incrementVersion(options);
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -103,12 +105,15 @@ class Version extends Plugin {
|
|
|
103
105
|
return increment;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
if (_isPreRelease && latestIsPreRelease) {
|
|
108
|
+
if (isPreRelease && !increment && latestIsPreRelease) {
|
|
108
109
|
return semver.inc(latestVersion, 'prerelease', preReleaseId);
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
|
|
112
|
+
if (this.config.isCI && !increment) {
|
|
113
|
+
return semver.inc(latestVersion, 'patch');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const normalizedType = RELEASE_TYPES.includes(increment) && isPreRelease ? `pre${increment}` : increment;
|
|
112
117
|
if (ALL_RELEASE_TYPES.includes(normalizedType)) {
|
|
113
118
|
return semver.inc(latestVersion, normalizedType, preReleaseId);
|
|
114
119
|
}
|
package/lib/tasks.js
CHANGED
|
@@ -68,6 +68,8 @@ const runTasks = async (opts, di) => {
|
|
|
68
68
|
const changelog = await reduceUntil(plugins, plugin => plugin.getChangelog(latestVersion));
|
|
69
69
|
|
|
70
70
|
const incrementBase = { latestVersion, increment, isPreRelease, preReleaseId };
|
|
71
|
+
incrementBase.increment = await reduceUntil(plugins, plugin => plugin.getIncrement(incrementBase));
|
|
72
|
+
|
|
71
73
|
let version = await reduceUntil(plugins, plugin => plugin.getIncrementedVersionCI(incrementBase));
|
|
72
74
|
|
|
73
75
|
config.setContext({ name, latestVersion, version, changelog });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-it",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.2",
|
|
4
4
|
"description": "Generic CLI tool to automate versioning and package publishing related tasks.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"build",
|
|
@@ -56,18 +56,18 @@
|
|
|
56
56
|
"license": "MIT",
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@iarna/toml": "2.2.5",
|
|
59
|
-
"@octokit/rest": "18.0.
|
|
59
|
+
"@octokit/rest": "18.0.9",
|
|
60
60
|
"async-retry": "1.3.1",
|
|
61
61
|
"chalk": "4.1.0",
|
|
62
62
|
"cosmiconfig": "7.0.0",
|
|
63
|
-
"debug": "4.
|
|
63
|
+
"debug": "4.3.1",
|
|
64
64
|
"deprecated-obj": "2.0.0",
|
|
65
|
-
"execa": "4.0
|
|
65
|
+
"execa": "4.1.0",
|
|
66
66
|
"find-up": "5.0.0",
|
|
67
67
|
"form-data": "3.0.0",
|
|
68
|
-
"git-url-parse": "11.
|
|
68
|
+
"git-url-parse": "11.4.0",
|
|
69
69
|
"globby": "11.0.1",
|
|
70
|
-
"got": "11.
|
|
70
|
+
"got": "11.8.0",
|
|
71
71
|
"import-cwd": "3.0.0",
|
|
72
72
|
"inquirer": "7.3.3",
|
|
73
73
|
"is-ci": "2.0.0",
|
|
@@ -78,29 +78,29 @@
|
|
|
78
78
|
"parse-json": "5.1.0",
|
|
79
79
|
"semver": "7.3.2",
|
|
80
80
|
"shelljs": "0.8.4",
|
|
81
|
-
"update-notifier": "
|
|
81
|
+
"update-notifier": "5.0.1",
|
|
82
82
|
"url-join": "4.0.1",
|
|
83
|
-
"uuid": "8.3.
|
|
83
|
+
"uuid": "8.3.1",
|
|
84
84
|
"yaml": "1.10.0",
|
|
85
|
-
"yargs-parser": "20.
|
|
85
|
+
"yargs-parser": "20.2.4"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
|
-
"@octokit/request-error": "2.0.
|
|
89
|
-
"ava": "3.
|
|
90
|
-
"codecov": "3.
|
|
91
|
-
"eslint": "7.
|
|
92
|
-
"eslint-config-prettier": "6.
|
|
88
|
+
"@octokit/request-error": "2.0.3",
|
|
89
|
+
"ava": "3.13.0",
|
|
90
|
+
"codecov": "3.8.1",
|
|
91
|
+
"eslint": "7.14.0",
|
|
92
|
+
"eslint-config-prettier": "6.15.0",
|
|
93
93
|
"eslint-plugin-ava": "11.0.0",
|
|
94
|
-
"eslint-plugin-import": "2.22.
|
|
94
|
+
"eslint-plugin-import": "2.22.1",
|
|
95
95
|
"eslint-plugin-prettier": "3.1.4",
|
|
96
96
|
"markdown-toc": "1.2.0",
|
|
97
97
|
"mock-fs": "4.13.0",
|
|
98
98
|
"mock-stdio": "1.0.3",
|
|
99
|
-
"nock": "13.0.
|
|
99
|
+
"nock": "13.0.5",
|
|
100
100
|
"nyc": "15.1.0",
|
|
101
|
-
"prettier": "2.
|
|
101
|
+
"prettier": "2.2.0",
|
|
102
102
|
"proxyquire": "2.1.3",
|
|
103
|
-
"sinon": "9.
|
|
103
|
+
"sinon": "9.2.1",
|
|
104
104
|
"strip-ansi": "6.0.0"
|
|
105
105
|
},
|
|
106
106
|
"engines": {
|
package/test/git.init.js
CHANGED
|
@@ -21,32 +21,32 @@ test.serial('should throw if on wrong branch', async t => {
|
|
|
21
21
|
const options = { git: { requireBranch: 'dev' } };
|
|
22
22
|
const gitClient = factory(Git, { options });
|
|
23
23
|
sh.exec('git remote remove origin');
|
|
24
|
-
await t.throwsAsync(gitClient.init(),
|
|
24
|
+
await t.throwsAsync(gitClient.init(), { message: /^Must be on branch dev/ });
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
test.serial('should throw if there is no remote Git url', async t => {
|
|
28
28
|
const gitClient = factory(Git, { options: { git } });
|
|
29
29
|
sh.exec('git remote remove origin');
|
|
30
|
-
await t.throwsAsync(gitClient.init(),
|
|
30
|
+
await t.throwsAsync(gitClient.init(), { message: /^Could not get remote Git url/ });
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
test.serial('should throw if working dir is not clean', async t => {
|
|
34
34
|
const gitClient = factory(Git, { options: { git } });
|
|
35
35
|
sh.exec('rm file');
|
|
36
|
-
await t.throwsAsync(gitClient.init(), { message:
|
|
36
|
+
await t.throwsAsync(gitClient.init(), { message: /^Working dir must be clean/ });
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
test.serial('should throw if no upstream is configured', async t => {
|
|
40
40
|
const gitClient = factory(Git, { options: { git } });
|
|
41
41
|
sh.exec('git checkout -b foo');
|
|
42
|
-
await t.throwsAsync(gitClient.init(),
|
|
42
|
+
await t.throwsAsync(gitClient.init(), { message: /^No upstream configured for current branch/ });
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
test.serial('should throw if there are no commits', async t => {
|
|
46
46
|
const options = { git: { requireCommits: true } };
|
|
47
47
|
const gitClient = factory(Git, { options });
|
|
48
48
|
sh.exec('git tag 1.0.0');
|
|
49
|
-
await t.throwsAsync(gitClient.init(),
|
|
49
|
+
await t.throwsAsync(gitClient.init(), { message: /^There are no commits since the latest tag/ });
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
test.serial('should not throw if there are commits', async t => {
|
|
@@ -95,11 +95,12 @@ test.serial('should detect and exclude version prefix (configured)', async t =>
|
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
test.serial('should honor custom tagName configuration', async t => {
|
|
98
|
-
const gitClient = factory(Git, { options: { git: { tagName: 'TAGNAME-v${version}' } } });
|
|
98
|
+
const gitClient = factory(Git, { options: { git: { tagName: 'TAGNAME-${repo.project}-v${version}' } } });
|
|
99
99
|
sh.exec('git tag 1.0.0');
|
|
100
100
|
await gitClient.init();
|
|
101
101
|
await gitClient.bump('1.0.1');
|
|
102
|
-
|
|
102
|
+
const { project } = gitClient.getContext('repo');
|
|
103
|
+
t.is(gitClient.getContext('tagName'), `TAGNAME-${project}-v1.0.1`);
|
|
103
104
|
});
|
|
104
105
|
|
|
105
106
|
test.serial('should get the latest tag after fetch', async t => {
|
package/test/github.js
CHANGED
|
@@ -24,7 +24,7 @@ test.serial('should validate token', async t => {
|
|
|
24
24
|
delete process.env[tokenRef];
|
|
25
25
|
|
|
26
26
|
await t.throwsAsync(github.init(), {
|
|
27
|
-
message:
|
|
27
|
+
message: /^Environment variable "MY_GITHUB_TOKEN" is required for GitHub releases/
|
|
28
28
|
});
|
|
29
29
|
process.env[tokenRef] = '123'; // eslint-disable-line require-atomic-updates
|
|
30
30
|
|
|
@@ -193,11 +193,9 @@ test('should throw for unauthenticated user', async t => {
|
|
|
193
193
|
const stub = sinon.stub(github.client.users, 'getAuthenticated');
|
|
194
194
|
stub.throws(new RequestError('Bad credentials', 401, { request: { url: '', headers: {} } }));
|
|
195
195
|
|
|
196
|
-
await t.throwsAsync(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
'Could not authenticate with GitHub using environment variable "GITHUB_TOKEN". Generate a new token at https://github.com/settings/tokens'
|
|
200
|
-
);
|
|
196
|
+
await t.throwsAsync(runTasks(github), {
|
|
197
|
+
message: /^Could not authenticate with GitHub using environment variable "GITHUB_TOKEN"/
|
|
198
|
+
});
|
|
201
199
|
|
|
202
200
|
t.is(stub.callCount, 1);
|
|
203
201
|
stub.restore();
|
|
@@ -210,7 +208,7 @@ test('should throw for non-collaborator', async t => {
|
|
|
210
208
|
const stub = sinon.stub(github.client.repos, 'checkCollaborator');
|
|
211
209
|
stub.throws(new RequestError('HttpError', 401, { request: { url: '', headers: {} } }));
|
|
212
210
|
|
|
213
|
-
await t.throwsAsync(runTasks(github),
|
|
211
|
+
await t.throwsAsync(runTasks(github), { message: /^User john is not a collaborator for user\/repo/ });
|
|
214
212
|
|
|
215
213
|
stub.restore();
|
|
216
214
|
});
|
|
@@ -243,7 +241,7 @@ test('should handle octokit client error (without retries)', async t => {
|
|
|
243
241
|
interceptAuthentication();
|
|
244
242
|
interceptCollaborator();
|
|
245
243
|
|
|
246
|
-
await t.throwsAsync(runTasks(github),
|
|
244
|
+
await t.throwsAsync(runTasks(github), { message: /^404 \(Not found\)/ });
|
|
247
245
|
|
|
248
246
|
t.is(stub.callCount, 1);
|
|
249
247
|
stub.restore();
|
|
@@ -257,7 +255,7 @@ test('should handle octokit client error (with retries)', async t => {
|
|
|
257
255
|
interceptAuthentication();
|
|
258
256
|
interceptCollaborator();
|
|
259
257
|
|
|
260
|
-
await t.throwsAsync(runTasks(github),
|
|
258
|
+
await t.throwsAsync(runTasks(github), { message: /^500 \(Request failed\)/ });
|
|
261
259
|
|
|
262
260
|
t.is(stub.callCount, 3);
|
|
263
261
|
stub.restore();
|
package/test/gitlab.js
CHANGED
|
@@ -20,7 +20,9 @@ test.serial('should validate token', async t => {
|
|
|
20
20
|
const gitlab = factory(GitLab, { options });
|
|
21
21
|
delete process.env[tokenRef];
|
|
22
22
|
|
|
23
|
-
await t.throwsAsync(gitlab.init(),
|
|
23
|
+
await t.throwsAsync(gitlab.init(), {
|
|
24
|
+
message: /^Environment variable "MY_GITLAB_TOKEN" is required for GitLab releases/
|
|
25
|
+
});
|
|
24
26
|
process.env[tokenRef] = '123'; // eslint-disable-line require-atomic-updates
|
|
25
27
|
|
|
26
28
|
interceptUser();
|
|
@@ -115,11 +117,9 @@ test.serial('should throw for unauthenticated user', async t => {
|
|
|
115
117
|
const scope = nock(host);
|
|
116
118
|
scope.get(`/api/v4/user`).reply(401);
|
|
117
119
|
|
|
118
|
-
await t.throwsAsync(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
'Could not authenticate with GitLab using environment variable "GITLAB_TOKEN".'
|
|
122
|
-
);
|
|
120
|
+
await t.throwsAsync(runTasks(gitlab), {
|
|
121
|
+
message: /^Could not authenticate with GitLab using environment variable "GITLAB_TOKEN"/
|
|
122
|
+
});
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
test.serial('should throw for non-collaborator', async t => {
|
|
@@ -131,7 +131,7 @@ test.serial('should throw for non-collaborator', async t => {
|
|
|
131
131
|
scope.get(`/api/v4/projects/john%2Frepo/members/all/1`).reply(200, { username: 'emma' });
|
|
132
132
|
interceptUser({ owner: 'john' });
|
|
133
133
|
|
|
134
|
-
await t.throwsAsync(runTasks(gitlab),
|
|
134
|
+
await t.throwsAsync(runTasks(gitlab), { message: /^User john is not a collaborator for john\/repo/ });
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
test.serial('should throw for insufficient access level', async t => {
|
|
@@ -143,7 +143,7 @@ test.serial('should throw for insufficient access level', async t => {
|
|
|
143
143
|
scope.get(`/api/v4/projects/john%2Frepo/members/all/1`).reply(200, { username: 'john', access_level: 10 });
|
|
144
144
|
interceptUser({ owner: 'john' });
|
|
145
145
|
|
|
146
|
-
await t.throwsAsync(runTasks(gitlab),
|
|
146
|
+
await t.throwsAsync(runTasks(gitlab), { message: /^User john is not a collaborator for john\/repo/ });
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
test.serial('should fallback for gitlab < v12.4', async t => {
|
package/test/npm.js
CHANGED
|
@@ -129,7 +129,7 @@ test('should throw if npm is down', async t => {
|
|
|
129
129
|
const npmClient = factory(npm);
|
|
130
130
|
const exec = sinon.stub(npmClient.shell, 'exec').resolves();
|
|
131
131
|
exec.withArgs('npm ping').rejects();
|
|
132
|
-
await t.throwsAsync(runTasks(npmClient), { message:
|
|
132
|
+
await t.throwsAsync(runTasks(npmClient), { message: /^Unable to reach npm registry/ });
|
|
133
133
|
exec.restore();
|
|
134
134
|
});
|
|
135
135
|
|
|
@@ -177,7 +177,7 @@ test('should throw if user is not authenticated', async t => {
|
|
|
177
177
|
const npmClient = factory(npm);
|
|
178
178
|
const exec = sinon.stub(npmClient.shell, 'exec').resolves();
|
|
179
179
|
exec.withArgs('npm whoami').rejects();
|
|
180
|
-
await t.throwsAsync(runTasks(npmClient), { message:
|
|
180
|
+
await t.throwsAsync(runTasks(npmClient), { message: /^Not authenticated with npm/ });
|
|
181
181
|
exec.restore();
|
|
182
182
|
});
|
|
183
183
|
|
|
@@ -186,7 +186,7 @@ test('should throw if user is not a collaborator', async t => {
|
|
|
186
186
|
const exec = sinon.stub(npmClient.shell, 'exec').resolves();
|
|
187
187
|
exec.withArgs('npm whoami').resolves('ada');
|
|
188
188
|
exec.withArgs('npm access ls-collaborators release-it').resolves(JSON.stringify({ john: ['write'] }));
|
|
189
|
-
await t.throwsAsync(runTasks(npmClient), { message:
|
|
189
|
+
await t.throwsAsync(runTasks(npmClient), { message: /^User ada is not a collaborator for release-it/ });
|
|
190
190
|
exec.restore();
|
|
191
191
|
});
|
|
192
192
|
|
package/test/plugins.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const path = require('path');
|
|
1
2
|
const test = require('ava');
|
|
2
3
|
const sh = require('shelljs');
|
|
3
4
|
const proxyquire = require('proxyquire');
|
|
@@ -94,6 +95,7 @@ test.serial('should instantiate plugins and execute all release-cycle methods',
|
|
|
94
95
|
'init',
|
|
95
96
|
'getName',
|
|
96
97
|
'getLatestVersion',
|
|
98
|
+
'getIncrement',
|
|
97
99
|
'getIncrementedVersionCI',
|
|
98
100
|
'beforeBump',
|
|
99
101
|
'bump',
|
|
@@ -105,7 +107,8 @@ test.serial('should instantiate plugins and execute all release-cycle methods',
|
|
|
105
107
|
t.is(myLocalPlugin[method].callCount, 1);
|
|
106
108
|
});
|
|
107
109
|
|
|
108
|
-
const incrementBase = { latestVersion: '0.0.0', increment:
|
|
110
|
+
const incrementBase = { latestVersion: '0.0.0', increment: undefined, isPreRelease: false, preReleaseId: undefined };
|
|
111
|
+
t.deepEqual(myPlugin.getIncrement.firstCall.args[0], incrementBase);
|
|
109
112
|
t.deepEqual(myPlugin.getIncrementedVersionCI.firstCall.args[0], incrementBase);
|
|
110
113
|
t.deepEqual(myLocalPlugin.getIncrementedVersionCI.firstCall.args[0], incrementBase);
|
|
111
114
|
t.is(myPlugin.bump.firstCall.args[0], '0.0.1');
|
|
@@ -129,3 +132,69 @@ test.serial('should disable core plugins', async t => {
|
|
|
129
132
|
version: undefined
|
|
130
133
|
});
|
|
131
134
|
});
|
|
135
|
+
|
|
136
|
+
test.serial('should expose context to execute commands', async t => {
|
|
137
|
+
const { bare } = t.context;
|
|
138
|
+
const latestVersion = '1.0.0';
|
|
139
|
+
const project = path.basename(bare);
|
|
140
|
+
const pkgName = 'plugin-context';
|
|
141
|
+
const owner = path.basename(path.dirname(bare));
|
|
142
|
+
gitAdd(`{"name":"${pkgName}","version":"${latestVersion}"}`, 'package.json', 'Add package.json');
|
|
143
|
+
|
|
144
|
+
class MyPlugin extends Plugin {
|
|
145
|
+
init() {
|
|
146
|
+
this.exec('echo ${version.isPreRelease}');
|
|
147
|
+
}
|
|
148
|
+
beforeBump() {
|
|
149
|
+
const context = this.config.getContext();
|
|
150
|
+
t.is(context.name, pkgName);
|
|
151
|
+
this.exec('echo ${name} ${repo.owner} ${repo.project} ${latestVersion} ${version}');
|
|
152
|
+
}
|
|
153
|
+
bump() {
|
|
154
|
+
const repo = this.config.getContext('repo');
|
|
155
|
+
t.is(repo.owner, owner);
|
|
156
|
+
t.is(repo.project, project);
|
|
157
|
+
t.is(repo.repository, `${owner}/${project}`);
|
|
158
|
+
this.exec('echo ${name} ${repo.owner} ${repo.project} ${latestVersion} ${version}');
|
|
159
|
+
}
|
|
160
|
+
beforeRelease() {
|
|
161
|
+
const context = this.config.getContext();
|
|
162
|
+
t.is(context.name, pkgName);
|
|
163
|
+
this.exec('echo ${name} ${repo.owner} ${repo.project} ${latestVersion} ${version} ${tagName}');
|
|
164
|
+
}
|
|
165
|
+
release() {
|
|
166
|
+
const context = this.config.getContext();
|
|
167
|
+
t.is(context.latestVersion, latestVersion);
|
|
168
|
+
t.is(context.version, '1.0.1');
|
|
169
|
+
this.exec('echo ${name} ${repo.owner} ${repo.project} ${latestVersion} ${version} ${tagName}');
|
|
170
|
+
}
|
|
171
|
+
afterRelease() {
|
|
172
|
+
const context = this.config.getContext();
|
|
173
|
+
t.is(context.tagName, '1.0.1');
|
|
174
|
+
this.exec('echo ${name} ${repo.owner} ${repo.project} ${latestVersion} ${version} ${tagName}');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const statics = { isEnabled: () => true, disablePlugin: () => null };
|
|
178
|
+
const options = { '@global': true, '@noCallThru': true };
|
|
179
|
+
const runTasks = proxyquire('../lib/tasks', {
|
|
180
|
+
'my-plugin': Object.assign(MyPlugin, statics, options)
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const container = getContainer({ plugins: { 'my-plugin': {} } });
|
|
184
|
+
const exec = sinon.spy(container.shell, 'execFormattedCommand');
|
|
185
|
+
|
|
186
|
+
await runTasks({}, container);
|
|
187
|
+
|
|
188
|
+
const pluginExecArgs = exec.args
|
|
189
|
+
.map(args => args[0])
|
|
190
|
+
.filter(arg => typeof arg === 'string' && arg.startsWith('echo'));
|
|
191
|
+
|
|
192
|
+
t.deepEqual(pluginExecArgs, [
|
|
193
|
+
'echo false',
|
|
194
|
+
`echo ${pkgName} ${owner} ${project} ${latestVersion} 1.0.1`,
|
|
195
|
+
`echo ${pkgName} ${owner} ${project} ${latestVersion} 1.0.1`,
|
|
196
|
+
`echo ${pkgName} ${owner} ${project} ${latestVersion} 1.0.1 1.0.1`,
|
|
197
|
+
`echo ${pkgName} ${owner} ${project} ${latestVersion} 1.0.1 1.0.1`,
|
|
198
|
+
`echo ${pkgName} ${owner} ${project} ${latestVersion} 1.0.1 1.0.1`
|
|
199
|
+
]);
|
|
200
|
+
});
|
package/test/stub/shell.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const debug = require('debug')('release-it:shell-stub');
|
|
2
2
|
const Shell = require('../../lib/shell');
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
class ShellStub extends Shell {
|
|
5
5
|
exec(command) {
|
|
6
6
|
if (/^(npm (ping|publish|show)|git fetch)/.test(command)) {
|
|
7
7
|
debug(command);
|
|
@@ -17,4 +17,6 @@ module.exports = class ShellStub extends Shell {
|
|
|
17
17
|
}
|
|
18
18
|
return super.exec(...arguments);
|
|
19
19
|
}
|
|
20
|
-
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = ShellStub;
|
package/test/tasks.js
CHANGED
|
@@ -398,22 +398,11 @@ test.serial('should propagate errors', async t => {
|
|
|
398
398
|
});
|
|
399
399
|
|
|
400
400
|
{
|
|
401
|
-
|
|
402
|
-
myPlugin.namespace = 'my-plugin';
|
|
403
|
-
const MyPlugin = sandbox.stub().callsFake(() => myPlugin);
|
|
404
|
-
const myLocalPlugin = sandbox.createStubInstance(Plugin);
|
|
405
|
-
const MyLocalPlugin = sandbox.stub().callsFake(() => myLocalPlugin);
|
|
406
|
-
const replacePlugin = sandbox.createStubInstance(Plugin);
|
|
407
|
-
const ReplacePlugin = sandbox.stub().callsFake(() => replacePlugin);
|
|
408
|
-
|
|
401
|
+
class MyPlugin extends Plugin {}
|
|
409
402
|
const statics = { isEnabled: () => true, disablePlugin: () => null };
|
|
410
403
|
const options = { '@global': true, '@noCallThru': true };
|
|
411
404
|
const runTasks = proxyquire('../lib/tasks', {
|
|
412
|
-
'my-plugin': Object.assign(MyPlugin, statics, options)
|
|
413
|
-
'/my/plugin': Object.assign(MyLocalPlugin, statics, options),
|
|
414
|
-
'replace-plugin': Object.assign(ReplacePlugin, statics, options, {
|
|
415
|
-
disablePlugin: () => ['version', 'git']
|
|
416
|
-
})
|
|
405
|
+
'my-plugin': Object.assign(MyPlugin, statics, options)
|
|
417
406
|
});
|
|
418
407
|
|
|
419
408
|
test.serial('should run all hooks', async t => {
|
|
@@ -421,9 +410,9 @@ test.serial('should propagate errors', async t => {
|
|
|
421
410
|
const hooks = {};
|
|
422
411
|
['before', 'after'].forEach(prefix => {
|
|
423
412
|
['version', 'git', 'npm', 'my-plugin'].forEach(ns => {
|
|
424
|
-
['init', 'beforeBump', 'bump', 'beforeRelease', 'release', 'afterRelease'].forEach(
|
|
425
|
-
hooks[`${prefix}:${
|
|
426
|
-
hooks[`${prefix}:${ns}:${
|
|
413
|
+
['init', 'beforeBump', 'bump', 'beforeRelease', 'release', 'afterRelease'].forEach(cycle => {
|
|
414
|
+
hooks[`${prefix}:${cycle}`] = `echo ${prefix}:${cycle}`;
|
|
415
|
+
hooks[`${prefix}:${ns}:${cycle}`] = `echo ${prefix}:${ns}:${cycle}`;
|
|
427
416
|
});
|
|
428
417
|
});
|
|
429
418
|
});
|
package/test/util/index.js
CHANGED
|
@@ -30,19 +30,39 @@ module.exports.factory = (Definition, { namespace, options = {}, container = {}
|
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
const getIncrement = (plugin, { latestVersion }) => {
|
|
34
|
+
return (
|
|
35
|
+
plugin.getIncrement({
|
|
36
|
+
latestVersion,
|
|
37
|
+
increment: plugin.options.increment,
|
|
38
|
+
isPreRelease: false,
|
|
39
|
+
preReleaseId: null
|
|
40
|
+
}) ||
|
|
41
|
+
plugin.getContext('increment') ||
|
|
42
|
+
plugin.config.getContext('increment')
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getVersion = async (plugin, { latestVersion, increment }) => {
|
|
47
|
+
return (
|
|
48
|
+
(await plugin.getIncrementedVersionCI({ latestVersion, increment })) ||
|
|
49
|
+
(await plugin.getIncrementedVersion({ latestVersion, increment })) ||
|
|
50
|
+
(increment !== false ? semver.inc(latestVersion, increment || 'patch') : latestVersion)
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
33
54
|
module.exports.runTasks = async plugin => {
|
|
34
55
|
await plugin.init();
|
|
35
56
|
|
|
36
57
|
const name = (await plugin.getName()) || '__test__';
|
|
37
58
|
const latestVersion = (await plugin.getLatestVersion()) || '1.0.0';
|
|
38
59
|
const changelog = (await plugin.getChangelog(latestVersion)) || null;
|
|
39
|
-
const increment = plugin
|
|
60
|
+
const increment = getIncrement(plugin, { latestVersion });
|
|
61
|
+
|
|
40
62
|
plugin.config.setContext({ name, latestVersion, latestTag: latestVersion, changelog });
|
|
41
63
|
|
|
42
|
-
const version =
|
|
43
|
-
|
|
44
|
-
(await plugin.getIncrementedVersion({ latestVersion, increment })) ||
|
|
45
|
-
(increment !== false ? semver.inc(latestVersion, increment || 'patch') : latestVersion);
|
|
64
|
+
const version = await getVersion(plugin, { latestVersion, increment });
|
|
65
|
+
|
|
46
66
|
plugin.config.setContext(parseVersion(version));
|
|
47
67
|
|
|
48
68
|
await plugin.beforeBump();
|
package/test/version.js
CHANGED
|
@@ -15,11 +15,19 @@ test('isPreRelease', t => {
|
|
|
15
15
|
t.is(v.isPreRelease('1.0.0'), false);
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
test('should return the same version in both interactive and ci mode', async t => {
|
|
19
|
+
const v = factory(Version);
|
|
20
|
+
const options = { latestVersion: '2.0.0-beta.1', increment: null, preReleaseId: 'rc', isPreRelease: true };
|
|
21
|
+
const resultInteractiveMode = await v.getIncrementedVersion(options);
|
|
22
|
+
t.is(resultInteractiveMode, '2.0.0-rc.0');
|
|
23
|
+
const resultCiMode = v.getIncrementedVersionCI(options);
|
|
24
|
+
t.is(resultInteractiveMode, resultCiMode);
|
|
25
|
+
});
|
|
26
|
+
|
|
18
27
|
test('should increment latest version', t => {
|
|
19
28
|
const v = factory(Version);
|
|
20
29
|
const latestVersion = '1.0.0';
|
|
21
30
|
t.is(v.incrementVersion({ latestVersion, increment: false }), '1.0.0');
|
|
22
|
-
t.is(v.incrementVersion({ latestVersion, increment: null }), undefined);
|
|
23
31
|
t.is(v.incrementVersion({ latestVersion, increment: 'foo' }), undefined);
|
|
24
32
|
t.is(v.incrementVersion({ latestVersion, increment: 'patsj' }), undefined);
|
|
25
33
|
t.is(v.incrementVersion({ latestVersion, increment: 'a.b.c' }), undefined);
|
|
@@ -29,6 +37,22 @@ test('should increment latest version', t => {
|
|
|
29
37
|
t.is(v.incrementVersion({ latestVersion, increment: '2.0.0-beta.1' }), '2.0.0-beta.1');
|
|
30
38
|
});
|
|
31
39
|
|
|
40
|
+
test('should not increment latest version in interactive mode', t => {
|
|
41
|
+
const v = factory(Version, { options: { ci: false } });
|
|
42
|
+
const latestVersion = '1.0.0';
|
|
43
|
+
t.is(v.incrementVersion({ latestVersion, increment: null }), undefined);
|
|
44
|
+
t.is(v.incrementVersion({ latestVersion, increment: false }), '1.0.0');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should always set increment version in CI mode', t => {
|
|
48
|
+
const v = factory(Version, { options: { ci: true } });
|
|
49
|
+
const latestVersion = '1.0.0';
|
|
50
|
+
t.is(v.getIncrementedVersionCI({ latestVersion, increment: false }), '1.0.0');
|
|
51
|
+
t.is(v.getIncrementedVersionCI({ latestVersion, increment: null }), '1.0.1');
|
|
52
|
+
t.is(v.getIncrementedVersionCI({ latestVersion, increment: '1.1.0' }), '1.1.0');
|
|
53
|
+
t.is(v.getIncrementedVersionCI({ latestVersion, increment: 'major' }), '2.0.0');
|
|
54
|
+
});
|
|
55
|
+
|
|
32
56
|
test('should increment latest version (coerce)', t => {
|
|
33
57
|
const v = factory(Version);
|
|
34
58
|
t.is(v.incrementVersion({ increment: '1.2' }), '1.2.0');
|
|
@@ -38,7 +62,7 @@ test('should increment latest version (coerce)', t => {
|
|
|
38
62
|
|
|
39
63
|
test('should increment version (pre-release continuation)', t => {
|
|
40
64
|
const v = factory(Version);
|
|
41
|
-
t.is(v.incrementVersion({ latestVersion: '1.2.3-alpha.0', increment: 'prepatch' }), '1.2.
|
|
65
|
+
t.is(v.incrementVersion({ latestVersion: '1.2.3-alpha.0', increment: 'prepatch' }), '1.2.4-0');
|
|
42
66
|
});
|
|
43
67
|
|
|
44
68
|
test('should increment version (prepatch)', t => {
|
|
@@ -54,6 +78,27 @@ test('should increment version (normalized)', t => {
|
|
|
54
78
|
);
|
|
55
79
|
});
|
|
56
80
|
|
|
81
|
+
test('should increment version (prepatch on prerelease version)', t => {
|
|
82
|
+
const v = factory(Version);
|
|
83
|
+
t.is(
|
|
84
|
+
v.incrementVersion({ latestVersion: '1.2.3-alpha.5', increment: 'prepatch', preReleaseId: 'next' }),
|
|
85
|
+
'1.2.4-next.0'
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should increment version (normalized on prerelease version)', t => {
|
|
90
|
+
const v = factory(Version);
|
|
91
|
+
t.is(
|
|
92
|
+
v.incrementVersion({
|
|
93
|
+
latestVersion: '1.2.3-alpha.5',
|
|
94
|
+
increment: 'patch',
|
|
95
|
+
preReleaseId: 'next',
|
|
96
|
+
isPreRelease: true
|
|
97
|
+
}),
|
|
98
|
+
'1.2.4-next.0'
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
57
102
|
test('should increment version (prerelease)', t => {
|
|
58
103
|
const v = factory(Version);
|
|
59
104
|
t.is(v.incrementVersion({ latestVersion: '1.2.3', increment: 'prerelease', preReleaseId: 'alpha' }), '1.2.4-alpha.0');
|
|
@@ -96,9 +141,19 @@ test('should increment version (patch release after pre-release)', t => {
|
|
|
96
141
|
test('should run tasks without errors', async t => {
|
|
97
142
|
const options = { version: { increment: 'minor' } };
|
|
98
143
|
const v = factory(Version, { options });
|
|
144
|
+
const getIncrement = sinon.spy(v, 'getIncrement');
|
|
99
145
|
const getIncrementedVersionCI = sinon.spy(v, 'getIncrementedVersionCI');
|
|
100
146
|
const incrementVersion = sinon.spy(v, 'incrementVersion');
|
|
147
|
+
|
|
101
148
|
await runTasks(v);
|
|
149
|
+
|
|
150
|
+
t.is(getIncrement.callCount, 1);
|
|
151
|
+
t.deepEqual(getIncrement.firstCall.args[0], {
|
|
152
|
+
latestVersion: '0.0.0',
|
|
153
|
+
increment: 'minor',
|
|
154
|
+
isPreRelease: false,
|
|
155
|
+
preReleaseId: null
|
|
156
|
+
});
|
|
102
157
|
t.is(getIncrementedVersionCI.callCount, 1);
|
|
103
158
|
t.deepEqual(getIncrementedVersionCI.firstCall.args[0], { latestVersion: '0.0.0', increment: 'minor' });
|
|
104
159
|
t.is(await incrementVersion.firstCall.returnValue, '0.1.0');
|