release-it 19.0.0-next.1 → 19.0.0-next.3
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 +1 -1
- package/lib/cli.js +2 -5
- package/lib/config.js +34 -2
- package/lib/index.js +26 -9
- package/lib/log.js +7 -7
- package/lib/plugin/github/GitHub.js +2 -6
- package/lib/plugin/github/util.js +1 -1
- package/lib/plugin/gitlab/GitLab.js +11 -4
- package/lib/plugin/npm/npm.js +4 -0
- package/lib/plugin/version/Version.js +6 -4
- package/package.json +14 -23
- package/schema/gitlab.json +4 -0
- package/schema/release-it.json +4 -0
- package/test/cli.js +6 -5
- package/test/config.js +228 -122
- package/test/git.init.js +220 -218
- package/test/git.js +359 -364
- package/test/github.js +563 -480
- package/test/gitlab.js +374 -336
- package/test/log.js +141 -138
- package/test/npm.js +315 -373
- package/test/plugin-name.js +7 -6
- package/test/plugins.js +200 -211
- package/test/prompt.js +26 -32
- package/test/shell.js +63 -60
- package/test/spinner.js +20 -24
- package/test/stub/github.js +113 -123
- package/test/stub/gitlab.js +75 -51
- package/test/tasks.interactive.js +215 -164
- package/test/tasks.js +392 -412
- package/test/util/helpers.js +4 -3
- package/test/util/index.js +34 -7
- package/test/util/mock.js +11 -0
- package/test/utils.js +33 -32
- package/test/version.js +192 -176
- package/test/util/setup.js +0 -3
|
@@ -1,216 +1,267 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { renameSync } from 'node:fs';
|
|
3
3
|
import childProcess from 'node:child_process';
|
|
4
|
-
import test from '
|
|
5
|
-
import
|
|
6
|
-
import Log from '../lib/log.js';
|
|
7
|
-
import Spinner from '../lib/spinner.js';
|
|
4
|
+
import test, { afterEach, after, before, beforeEach, describe, mock } from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
8
6
|
import Prompt from '../lib/prompt.js';
|
|
9
7
|
import Config from '../lib/config.js';
|
|
10
8
|
import runTasks from '../lib/index.js';
|
|
11
9
|
import Git from '../lib/plugin/git/Git.js';
|
|
12
10
|
import { execOpts } from '../lib/util.js';
|
|
13
|
-
import { mkTmpDir, gitAdd } from './util/helpers.js';
|
|
11
|
+
import { mkTmpDir, gitAdd, getArgs } from './util/helpers.js';
|
|
14
12
|
import ShellStub from './stub/shell.js';
|
|
15
13
|
import { interceptPublish as interceptGitLabPublish } from './stub/gitlab.js';
|
|
16
14
|
import { interceptCreate as interceptGitHubCreate } from './stub/github.js';
|
|
17
|
-
import { factory } from './util/index.js';
|
|
15
|
+
import { factory, LogStub, SpinnerStub } from './util/index.js';
|
|
16
|
+
import { mockFetch } from './util/mock.js';
|
|
17
|
+
|
|
18
|
+
describe('tasks.interactive', () => {
|
|
19
|
+
const [mocker, github, gitlab, githubusercontent] = mockFetch([
|
|
20
|
+
'https://api.github.com',
|
|
21
|
+
'https://gitlab.com/api/v4',
|
|
22
|
+
'https://raw.githubusercontent.com'
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
before(() => {
|
|
26
|
+
mocker.mockGlobal();
|
|
27
|
+
});
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
mocker.clearAll();
|
|
31
|
+
prompt.mock.resetCalls();
|
|
32
|
+
log.resetCalls();
|
|
33
|
+
});
|
|
20
34
|
|
|
21
|
-
|
|
35
|
+
after(() => {
|
|
36
|
+
mocker.unmockGlobal();
|
|
37
|
+
});
|
|
22
38
|
|
|
23
|
-
const testConfig = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
39
|
+
const testConfig = {
|
|
40
|
+
ci: false,
|
|
41
|
+
config: false
|
|
42
|
+
};
|
|
27
43
|
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
44
|
+
const getHooks = plugins => {
|
|
45
|
+
const hooks = {};
|
|
46
|
+
['before', 'after'].forEach(prefix => {
|
|
47
|
+
plugins.forEach(ns => {
|
|
48
|
+
['init', 'beforeBump', 'bump', 'beforeRelease', 'release', 'afterRelease'].forEach(lifecycle => {
|
|
49
|
+
hooks[`${prefix}:${lifecycle}`] = `echo ${prefix}:${lifecycle}`;
|
|
50
|
+
hooks[`${prefix}:${ns}:${lifecycle}`] = `echo ${prefix}:${ns}:${lifecycle}`;
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return hooks;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const log = new LogStub();
|
|
58
|
+
const spinner = new SpinnerStub();
|
|
31
59
|
|
|
32
|
-
const
|
|
33
|
-
prompt: sandbox.stub().callsFake(([options]) => {
|
|
60
|
+
const prompt = mock.fn(([options]) => {
|
|
34
61
|
const answer = options.type === 'list' ? options.choices[0].value : options.name === 'version' ? '0.0.1' : true;
|
|
35
62
|
return { [options.name]: answer };
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
log,
|
|
45
|
-
spinner,
|
|
46
|
-
config,
|
|
47
|
-
shell,
|
|
48
|
-
prompt
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const defaultInquirer = { prompt };
|
|
66
|
+
|
|
67
|
+
const getContainer = (options, inquirer = defaultInquirer) => {
|
|
68
|
+
const config = new Config(Object.assign({}, testConfig, options));
|
|
69
|
+
const shell = new ShellStub({ container: { log, config } });
|
|
70
|
+
const prompt = new Prompt({ container: { inquirer } });
|
|
71
|
+
return { log, spinner, config, shell, prompt };
|
|
49
72
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
|
|
74
|
+
let bare;
|
|
75
|
+
let target;
|
|
76
|
+
beforeEach(async () => {
|
|
77
|
+
bare = mkTmpDir();
|
|
78
|
+
target = mkTmpDir();
|
|
79
|
+
process.chdir(bare);
|
|
80
|
+
childProcess.execSync(`git init --bare .`, execOpts);
|
|
81
|
+
childProcess.execSync(`git clone ${bare} ${target}`, execOpts);
|
|
82
|
+
process.chdir(target);
|
|
83
|
+
gitAdd('line', 'file', 'Add file');
|
|
61
84
|
});
|
|
62
|
-
return hooks;
|
|
63
|
-
};
|
|
64
85
|
|
|
65
|
-
test
|
|
66
|
-
|
|
67
|
-
});
|
|
86
|
+
test('should run tasks without throwing errors', async () => {
|
|
87
|
+
renameSync('.git', 'foo');
|
|
88
|
+
const { name, latestVersion, version } = await runTasks({}, getContainer());
|
|
89
|
+
assert.equal(version, '0.0.1');
|
|
90
|
+
assert(log.obtrusive.mock.calls[0].arguments[0].includes(`release ${name} (currently at ${latestVersion})`));
|
|
91
|
+
assert.match(log.log.mock.calls.at(-1).arguments[0], /Done \(in [0-9]+s\.\)/);
|
|
92
|
+
});
|
|
68
93
|
|
|
69
|
-
test
|
|
70
|
-
|
|
71
|
-
const target = mkTmpDir();
|
|
72
|
-
process.chdir(bare);
|
|
73
|
-
childProcess.execSync(`git init --bare .`, execOpts);
|
|
74
|
-
childProcess.execSync(`git clone ${bare} ${target}`, execOpts);
|
|
75
|
-
process.chdir(target);
|
|
76
|
-
gitAdd('line', 'file', 'Add file');
|
|
77
|
-
t.context = { bare, target };
|
|
78
|
-
});
|
|
94
|
+
test('should run tasks using extended configuration', async t => {
|
|
95
|
+
renameSync('.git', 'foo');
|
|
79
96
|
|
|
80
|
-
|
|
81
|
-
sandbox.resetHistory();
|
|
82
|
-
});
|
|
97
|
+
const validationExtendedConfiguration = "echo 'extended_configuration'";
|
|
83
98
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
99
|
+
githubusercontent.get('/release-it/release-it-configuration/HEAD/.release-it.json', {
|
|
100
|
+
status: 200,
|
|
101
|
+
body: {
|
|
102
|
+
hooks: {
|
|
103
|
+
'before:init': validationExtendedConfiguration
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
91
107
|
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
const config = {
|
|
109
|
+
$schema: 'https://unpkg.com/release-it@18/schema/release-it.json',
|
|
110
|
+
extends: 'github:release-it/release-it-configuration'
|
|
111
|
+
};
|
|
94
112
|
|
|
95
|
-
|
|
96
|
-
hooks,
|
|
97
|
-
git: { push: false },
|
|
98
|
-
github: { release: false },
|
|
99
|
-
gitlab: { release: false },
|
|
100
|
-
npm: { publish: false }
|
|
101
|
-
});
|
|
113
|
+
const container = getContainer(config);
|
|
102
114
|
|
|
103
|
-
|
|
115
|
+
const exec = t.mock.method(container.shell, 'execFormattedCommand');
|
|
104
116
|
|
|
105
|
-
|
|
117
|
+
const { name, latestVersion, version } = await runTasks({}, container);
|
|
106
118
|
|
|
107
|
-
|
|
119
|
+
const commands = getArgs(exec, 'echo');
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
t.true(commands.includes('echo after:afterRelease'));
|
|
121
|
+
assert(commands.includes(validationExtendedConfiguration));
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
});
|
|
123
|
+
assert.equal(version, '0.0.1');
|
|
124
|
+
assert(log.obtrusive.mock.calls[0].arguments[0].includes(`release ${name} (currently at ${latestVersion})`));
|
|
125
|
+
assert.match(log.log.mock.calls.at(-1).arguments[0], /Done \(in [0-9]+s\.\)/);
|
|
126
|
+
});
|
|
117
127
|
|
|
118
|
-
test
|
|
119
|
-
|
|
120
|
-
const pkgName = path.basename(target);
|
|
121
|
-
gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
|
|
122
|
-
childProcess.execSync('git tag 1.0.0', execOpts);
|
|
128
|
+
test('should run tasks not using extended configuration as it is not a string', async () => {
|
|
129
|
+
renameSync('.git', 'foo');
|
|
123
130
|
|
|
124
|
-
|
|
125
|
-
|
|
131
|
+
const config = {
|
|
132
|
+
$schema: 'https://unpkg.com/release-it@18/schema/release-it.json',
|
|
133
|
+
extends: false
|
|
134
|
+
};
|
|
126
135
|
|
|
127
|
-
|
|
128
|
-
{
|
|
129
|
-
increment: 'minor',
|
|
130
|
-
hooks,
|
|
131
|
-
github: { release: true, skipChecks: true },
|
|
132
|
-
gitlab: { release: true, skipChecks: true },
|
|
133
|
-
npm: { publish: true, skipChecks: true }
|
|
134
|
-
},
|
|
135
|
-
inquirer
|
|
136
|
-
);
|
|
136
|
+
const container = getContainer(config);
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
const { name, latestVersion, version } = await runTasks({}, container);
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
assert.equal(version, '0.0.1');
|
|
141
|
+
assert(log.obtrusive.mock.calls[0].arguments[0].includes(`release ${name} (currently at ${latestVersion})`));
|
|
142
|
+
assert.match(log.log.mock.calls.at(-1).arguments[0], /Done \(in [0-9]+s\.\)/);
|
|
143
|
+
});
|
|
141
144
|
|
|
142
|
-
|
|
145
|
+
test('should not run hooks for disabled release-cycle methods', async t => {
|
|
146
|
+
const hooks = getHooks(['version', 'git', 'github', 'gitlab', 'npm']);
|
|
143
147
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
const container = getContainer({
|
|
149
|
+
hooks,
|
|
150
|
+
git: { push: false },
|
|
151
|
+
github: { release: false },
|
|
152
|
+
gitlab: { release: false },
|
|
153
|
+
npm: { publish: false }
|
|
154
|
+
});
|
|
148
155
|
|
|
149
|
-
|
|
150
|
-
t.false(commands.includes('echo after:github:release'));
|
|
151
|
-
t.false(commands.includes('echo after:gitlab:release'));
|
|
152
|
-
t.false(commands.includes('echo after:npm:release'));
|
|
156
|
+
const exec = t.mock.method(container.shell, 'execFormattedCommand');
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
await runTasks({}, container);
|
|
159
|
+
|
|
160
|
+
const commands = getArgs(exec, 'echo');
|
|
156
161
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const sha = gitAdd('line', 'file', 'More file');
|
|
165
|
-
|
|
166
|
-
const git = factory(Git);
|
|
167
|
-
const ref = (await git.getBranchName()) ?? 'HEAD';
|
|
168
|
-
|
|
169
|
-
interceptGitHubCreate({
|
|
170
|
-
owner,
|
|
171
|
-
project,
|
|
172
|
-
body: { tag_name: '1.1.0', name: 'Release 1.1.0', body: `* More file (${sha})` }
|
|
162
|
+
assert(commands.includes('echo before:init'));
|
|
163
|
+
assert(commands.includes('echo after:afterRelease'));
|
|
164
|
+
|
|
165
|
+
assert(!commands.includes('echo after:git:release'));
|
|
166
|
+
assert(!commands.includes('echo after:github:release'));
|
|
167
|
+
assert(!commands.includes('echo after:gitlab:release'));
|
|
168
|
+
assert(!commands.includes('echo after:npm:release'));
|
|
173
169
|
});
|
|
174
170
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
171
|
+
test('should not run hooks for cancelled release-cycle methods', async t => {
|
|
172
|
+
const pkgName = path.basename(target);
|
|
173
|
+
gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
|
|
174
|
+
childProcess.execSync('git tag 1.0.0', execOpts);
|
|
175
|
+
|
|
176
|
+
const hooks = getHooks(['version', 'git', 'github', 'gitlab', 'npm']);
|
|
177
|
+
const prompt = mock.fn(([options]) => ({ [options.name]: false }));
|
|
178
|
+
const inquirer = { prompt };
|
|
179
|
+
|
|
180
|
+
const container = getContainer(
|
|
181
|
+
{
|
|
182
|
+
increment: 'minor',
|
|
183
|
+
hooks,
|
|
184
|
+
github: { release: true, skipChecks: true },
|
|
185
|
+
gitlab: { release: true, skipChecks: true },
|
|
186
|
+
npm: { publish: true, skipChecks: true }
|
|
187
|
+
},
|
|
188
|
+
inquirer
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const exec = t.mock.method(container.shell, 'execFormattedCommand');
|
|
192
|
+
|
|
193
|
+
await runTasks({}, container);
|
|
194
|
+
|
|
195
|
+
const commands = getArgs(exec, 'echo');
|
|
196
|
+
|
|
197
|
+
assert(commands.includes('echo before:init'));
|
|
198
|
+
assert(commands.includes('echo after:afterRelease'));
|
|
199
|
+
assert(commands.includes('echo after:git:bump'));
|
|
200
|
+
assert(commands.includes('echo after:npm:bump'));
|
|
201
|
+
|
|
202
|
+
assert(!commands.includes('echo after:git:release'));
|
|
203
|
+
assert(!commands.includes('echo after:github:release'));
|
|
204
|
+
assert(!commands.includes('echo after:gitlab:release'));
|
|
205
|
+
assert(!commands.includes('echo after:npm:release'));
|
|
185
206
|
});
|
|
186
207
|
|
|
187
|
-
|
|
208
|
+
test('should run "after:*:release" plugin hooks', async t => {
|
|
209
|
+
const project = path.basename(bare);
|
|
210
|
+
const pkgName = path.basename(target);
|
|
211
|
+
const owner = path.basename(path.dirname(bare));
|
|
212
|
+
gitAdd(`{"name":"${pkgName}","version":"1.0.0"}`, 'package.json', 'Add package.json');
|
|
213
|
+
childProcess.execSync('git tag 1.0.0', execOpts);
|
|
214
|
+
const sha = gitAdd('line', 'file', 'More file');
|
|
215
|
+
|
|
216
|
+
const git = factory(Git);
|
|
217
|
+
const ref = (await git.getBranchName()) ?? 'HEAD';
|
|
218
|
+
|
|
219
|
+
interceptGitHubCreate(github, {
|
|
220
|
+
owner,
|
|
221
|
+
project,
|
|
222
|
+
body: { tag_name: '1.1.0', name: 'Release 1.1.0', body: `* More file (${sha})` }
|
|
223
|
+
});
|
|
188
224
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
225
|
+
interceptGitLabPublish(gitlab, {
|
|
226
|
+
owner,
|
|
227
|
+
project,
|
|
228
|
+
body: {
|
|
229
|
+
name: 'Release 1.1.0',
|
|
230
|
+
ref,
|
|
231
|
+
tag_name: '1.1.0',
|
|
232
|
+
tag_message: 'Release 1.1.0',
|
|
233
|
+
description: `* More file (${sha})`
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const hooks = getHooks(['version', 'git', 'github', 'gitlab', 'npm']);
|
|
238
|
+
|
|
239
|
+
const container = getContainer({
|
|
240
|
+
increment: 'minor',
|
|
241
|
+
hooks,
|
|
242
|
+
github: { release: true, pushRepo: `https://github.com/${owner}/${project}`, skipChecks: true },
|
|
243
|
+
gitlab: { release: true, pushRepo: `https://gitlab.com/${owner}/${project}`, skipChecks: true },
|
|
244
|
+
npm: { name: pkgName, skipChecks: true }
|
|
245
|
+
});
|
|
196
246
|
|
|
197
|
-
|
|
247
|
+
const exec = t.mock.method(container.shell, 'execFormattedCommand');
|
|
198
248
|
|
|
199
|
-
|
|
249
|
+
await runTasks({}, container);
|
|
200
250
|
|
|
201
|
-
|
|
251
|
+
const commands = getArgs(exec, 'echo');
|
|
202
252
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
});
|
|
253
|
+
assert(commands.includes('echo after:git:bump'));
|
|
254
|
+
assert(commands.includes('echo after:npm:bump'));
|
|
255
|
+
assert(commands.includes('echo after:git:release'));
|
|
256
|
+
assert(commands.includes('echo after:github:release'));
|
|
257
|
+
assert(commands.includes('echo after:gitlab:release'));
|
|
258
|
+
assert(commands.includes('echo after:npm:release'));
|
|
259
|
+
});
|
|
210
260
|
|
|
211
|
-
test
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
261
|
+
test('should show only version prompt', async () => {
|
|
262
|
+
const config = { ci: false, 'only-version': true };
|
|
263
|
+
await runTasks({}, getContainer(config));
|
|
264
|
+
assert.equal(prompt.mock.callCount(), 1);
|
|
265
|
+
assert.equal(prompt.mock.calls[0].arguments[0][0].name, 'incrementList');
|
|
266
|
+
});
|
|
216
267
|
});
|