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