release-it 15.0.0-esm.2 → 15.0.0-esm.5
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 +22 -16
- package/config/release-it.json +5 -1
- package/lib/config.js +7 -15
- package/lib/index.js +13 -21
- package/lib/log.js +1 -1
- package/lib/plugin/GitBase.js +2 -2
- package/lib/plugin/GitRelease.js +1 -1
- package/lib/plugin/Plugin.js +1 -1
- package/lib/plugin/factory.js +5 -5
- package/lib/plugin/git/Git.js +11 -4
- package/lib/plugin/github/GitHub.js +59 -15
- package/lib/plugin/gitlab/GitLab.js +69 -15
- package/lib/plugin/npm/npm.js +3 -2
- package/lib/plugin/version/Version.js +5 -5
- package/lib/shell.js +3 -3
- package/lib/spinner.js +3 -3
- package/lib/util.js +2 -2
- package/package.json +36 -42
- package/test/config.js +21 -28
- package/test/git.init.js +32 -7
- package/test/git.js +5 -2
- package/test/github.js +116 -19
- package/test/gitlab.js +69 -18
- package/test/log.js +1 -1
- package/test/npm.js +12 -3
- package/test/plugins.js +34 -22
- package/test/spinner.js +8 -11
- package/test/stub/config/default/.release-it.json +5 -0
- package/test/stub/config/invalid-config-rc +1 -0
- package/test/stub/config/invalid-config-txt +2 -0
- package/test/stub/config/merge/.release-it.json +5 -0
- package/test/stub/config/merge/package.json +7 -0
- package/test/stub/config/toml/.release-it.toml +2 -0
- package/test/stub/config/yaml/.release-it.yaml +2 -0
- package/test/stub/config/yml/.release-it.yml +2 -0
- package/test/stub/github.js +26 -10
- package/test/stub/gitlab.js +15 -7
- package/test/stub/shell.js +2 -2
- package/test/tasks.interactive.js +2 -3
- package/test/tasks.js +44 -4
- package/test/util/helpers.js +6 -6
- package/test/util/index.js +13 -18
- package/test/utils.js +1 -1
- package/test/version.js +14 -9
- package/config/.codecov.yml +0 -5
- package/config/deprecated.json +0 -1
- package/lib/deprecated.js +0 -22
- package/lib/metrics.js +0 -76
- package/test/deprecated.js +0 -11
- package/test/metrics.js +0 -17
package/test/gitlab.js
CHANGED
|
@@ -6,9 +6,9 @@ import { factory, runTasks } from './util/index.js';
|
|
|
6
6
|
import {
|
|
7
7
|
interceptUser,
|
|
8
8
|
interceptCollaborator,
|
|
9
|
-
interceptCollaboratorFallback,
|
|
10
9
|
interceptPublish,
|
|
11
|
-
interceptAsset
|
|
10
|
+
interceptAsset,
|
|
11
|
+
interceptMilestones
|
|
12
12
|
} from './stub/gitlab.js';
|
|
13
13
|
|
|
14
14
|
const tokenHeader = 'Private-Token';
|
|
@@ -55,7 +55,8 @@ test.serial('should upload assets and release', async t => {
|
|
|
55
55
|
release: true,
|
|
56
56
|
releaseName: 'Release ${version}',
|
|
57
57
|
releaseNotes: 'echo Custom notes',
|
|
58
|
-
assets: 'test/resources/file-v${version}.txt'
|
|
58
|
+
assets: 'test/resources/file-v${version}.txt',
|
|
59
|
+
milestones: ['${version}', '${latestVersion} UAT']
|
|
59
60
|
}
|
|
60
61
|
};
|
|
61
62
|
const gitlab = factory(GitLab, { options });
|
|
@@ -63,6 +64,26 @@ test.serial('should upload assets and release', async t => {
|
|
|
63
64
|
|
|
64
65
|
interceptUser();
|
|
65
66
|
interceptCollaborator();
|
|
67
|
+
interceptMilestones({
|
|
68
|
+
query: { title: '2.0.1' },
|
|
69
|
+
milestones: [
|
|
70
|
+
{
|
|
71
|
+
id: 17,
|
|
72
|
+
iid: 3,
|
|
73
|
+
title: '2.0.1'
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
interceptMilestones({
|
|
78
|
+
query: { title: '2.0.0 UAT' },
|
|
79
|
+
milestones: [
|
|
80
|
+
{
|
|
81
|
+
id: 42,
|
|
82
|
+
iid: 4,
|
|
83
|
+
title: '2.0.0 UAT'
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
});
|
|
66
87
|
interceptAsset();
|
|
67
88
|
interceptPublish({
|
|
68
89
|
body: {
|
|
@@ -76,7 +97,8 @@ test.serial('should upload assets and release', async t => {
|
|
|
76
97
|
url: `${pushRepo}/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/file-v2.0.1.txt`
|
|
77
98
|
}
|
|
78
99
|
]
|
|
79
|
-
}
|
|
100
|
+
},
|
|
101
|
+
milestones: ['2.0.1', '2.0.0 UAT']
|
|
80
102
|
}
|
|
81
103
|
});
|
|
82
104
|
|
|
@@ -88,6 +110,41 @@ test.serial('should upload assets and release', async t => {
|
|
|
88
110
|
t.is(releaseUrl, `${pushRepo}/-/releases`);
|
|
89
111
|
});
|
|
90
112
|
|
|
113
|
+
test.serial('should throw when release milestone is missing', async t => {
|
|
114
|
+
const pushRepo = 'https://gitlab.com/user/repo';
|
|
115
|
+
const options = {
|
|
116
|
+
git: { pushRepo },
|
|
117
|
+
gitlab: {
|
|
118
|
+
tokenRef,
|
|
119
|
+
release: true,
|
|
120
|
+
milestones: ['${version}', '${latestVersion} UAT']
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const gitlab = factory(GitLab, { options });
|
|
124
|
+
sinon.stub(gitlab, 'getLatestVersion').resolves('2.0.0');
|
|
125
|
+
|
|
126
|
+
interceptUser();
|
|
127
|
+
interceptCollaborator();
|
|
128
|
+
interceptMilestones({
|
|
129
|
+
query: { title: '2.0.1' },
|
|
130
|
+
milestones: [
|
|
131
|
+
{
|
|
132
|
+
id: 17,
|
|
133
|
+
iid: 3,
|
|
134
|
+
title: '2.0.1'
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
});
|
|
138
|
+
interceptMilestones({
|
|
139
|
+
query: { title: '2.0.0 UAT' },
|
|
140
|
+
milestones: []
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await t.throwsAsync(runTasks(gitlab), {
|
|
144
|
+
message: /^Missing one or more milestones in GitLab. Creating a GitLab release will fail./
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
91
148
|
test.serial('should release to self-managed host', async t => {
|
|
92
149
|
const host = 'https://gitlab.example.org';
|
|
93
150
|
const scope = nock(host);
|
|
@@ -162,19 +219,6 @@ test.serial('should throw for insufficient access level', async t => {
|
|
|
162
219
|
await t.throwsAsync(runTasks(gitlab), { message: /^User john is not a collaborator for john\/repo/ });
|
|
163
220
|
});
|
|
164
221
|
|
|
165
|
-
test.serial('should fallback for gitlab < v12.4', async t => {
|
|
166
|
-
const host = 'https://gitlab.com';
|
|
167
|
-
const pushRepo = `${host}/user/repo`;
|
|
168
|
-
const options = { gitlab: { tokenRef, pushRepo, host } };
|
|
169
|
-
const gitlab = factory(GitLab, { options });
|
|
170
|
-
const scope = nock(host);
|
|
171
|
-
scope.get(`/api/v4/projects/user%2Frepo/members/all/1`).reply(404);
|
|
172
|
-
interceptUser();
|
|
173
|
-
interceptCollaboratorFallback();
|
|
174
|
-
|
|
175
|
-
await t.notThrowsAsync(gitlab.init());
|
|
176
|
-
});
|
|
177
|
-
|
|
178
222
|
test('should not make requests in dry run', async t => {
|
|
179
223
|
const [host, owner, repo] = ['https://gitlab.example.org', 'user', 'repo'];
|
|
180
224
|
const pushRepo = `${host}/${owner}/${repo}`;
|
|
@@ -195,7 +239,14 @@ test('should not make requests in dry run', async t => {
|
|
|
195
239
|
});
|
|
196
240
|
|
|
197
241
|
test('should skip checks', async t => {
|
|
198
|
-
const options = { gitlab: { tokenRef, skipChecks: true } };
|
|
242
|
+
const options = { gitlab: { tokenRef, skipChecks: true, release: true, milestones: ['v1.0.0'] } };
|
|
199
243
|
const gitlab = factory(GitLab, { options });
|
|
244
|
+
const spy = sinon.spy(gitlab, 'client', ['get']);
|
|
245
|
+
|
|
200
246
|
await t.notThrowsAsync(gitlab.init());
|
|
247
|
+
await t.notThrowsAsync(gitlab.beforeRelease());
|
|
248
|
+
|
|
249
|
+
t.is(spy.get.callCount, 0);
|
|
250
|
+
|
|
251
|
+
t.is(gitlab.log.exec.args.filter(entry => /checkReleaseMilestones/.test(entry[0])).length, 0);
|
|
201
252
|
});
|
package/test/log.js
CHANGED
package/test/npm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path from 'path';
|
|
1
|
+
import path from 'node:path';
|
|
2
2
|
import test from 'ava';
|
|
3
3
|
import sinon from 'sinon';
|
|
4
4
|
import mock from 'mock-fs';
|
|
@@ -13,9 +13,9 @@ test('should return npm package url', t => {
|
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
test('should return npm package url (custom registry)', t => {
|
|
16
|
-
const options = { npm: { name: 'my-cool-package', publishConfig: { registry: 'https://
|
|
16
|
+
const options = { npm: { name: 'my-cool-package', publishConfig: { registry: 'https://registry.example.org/' } } };
|
|
17
17
|
const npmClient = factory(npm, { options });
|
|
18
|
-
t.is(npmClient.getPackageUrl(), 'https://
|
|
18
|
+
t.is(npmClient.getPackageUrl(), 'https://registry.example.org/package/my-cool-package');
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
test('should return default tag', async t => {
|
|
@@ -347,3 +347,12 @@ test('should not publish when `npm version` fails', async t => {
|
|
|
347
347
|
|
|
348
348
|
exec.restore();
|
|
349
349
|
});
|
|
350
|
+
|
|
351
|
+
test('should add allow-same-version argument', async t => {
|
|
352
|
+
const options = { npm: { skipChecks: true, allowSameVersion: true } };
|
|
353
|
+
const npmClient = factory(npm, { options });
|
|
354
|
+
const exec = sinon.stub(npmClient.shell, 'exec').resolves();
|
|
355
|
+
await runTasks(npmClient);
|
|
356
|
+
const version = exec.args.filter(arg => arg[0].startsWith('npm version'));
|
|
357
|
+
t.regex(version[0][0], / --allow-same-version/);
|
|
358
|
+
});
|
package/test/plugins.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
1
2
|
import test from 'ava';
|
|
2
3
|
import sh from 'shelljs';
|
|
3
4
|
import sinon from 'sinon';
|
|
@@ -12,16 +13,13 @@ import ContextPlugin from './stub/plugin-context.js';
|
|
|
12
13
|
import { mkTmpDir } from './util/helpers.js';
|
|
13
14
|
import ShellStub from './stub/shell.js';
|
|
14
15
|
|
|
15
|
-
const rootDir = new URL('..', import.meta.url);
|
|
16
|
-
|
|
17
16
|
const noop = Promise.resolve();
|
|
18
17
|
|
|
19
18
|
const sandbox = sinon.createSandbox();
|
|
20
19
|
|
|
21
20
|
const testConfig = {
|
|
22
21
|
ci: true,
|
|
23
|
-
config: false
|
|
24
|
-
'disable-metrics': true
|
|
22
|
+
config: false
|
|
25
23
|
};
|
|
26
24
|
|
|
27
25
|
const log = sandbox.createStubInstance(Log);
|
|
@@ -39,6 +37,11 @@ const getContainer = options => {
|
|
|
39
37
|
};
|
|
40
38
|
};
|
|
41
39
|
|
|
40
|
+
test.serial.before(t => {
|
|
41
|
+
t.timeout(60 * 1000);
|
|
42
|
+
sh.exec('npm link');
|
|
43
|
+
});
|
|
44
|
+
|
|
42
45
|
test.serial.beforeEach(t => {
|
|
43
46
|
const dir = mkTmpDir();
|
|
44
47
|
sh.pushd('-q', dir);
|
|
@@ -50,23 +53,28 @@ test.serial.afterEach(() => {
|
|
|
50
53
|
});
|
|
51
54
|
|
|
52
55
|
test.serial('should instantiate plugins and execute all release-cycle methods', async t => {
|
|
53
|
-
|
|
54
|
-
sh.exec(`npm install ${rootDir}`);
|
|
56
|
+
const { dir } = t.context;
|
|
55
57
|
|
|
56
58
|
const pluginDir = mkTmpDir();
|
|
57
59
|
sh.pushd('-q', pluginDir);
|
|
58
|
-
sh.ShellString(JSON.stringify({ name: 'my-plugin', version: '1.0.0', type: 'module' })).toEnd(
|
|
59
|
-
|
|
60
|
+
sh.ShellString(JSON.stringify({ name: 'my-plugin', version: '1.0.0', type: 'module' })).toEnd(
|
|
61
|
+
join(pluginDir, 'package.json')
|
|
62
|
+
);
|
|
63
|
+
sh.exec(`npm link release-it`);
|
|
60
64
|
const content = "import { Plugin } from 'release-it'; " + MyPlugin.toString() + '; export default MyPlugin;';
|
|
61
|
-
sh.ShellString(content).toEnd('index.js');
|
|
62
|
-
sh.popd();
|
|
65
|
+
sh.ShellString(content).toEnd(join(pluginDir, 'index.js'));
|
|
63
66
|
|
|
67
|
+
sh.pushd('-q', dir);
|
|
64
68
|
sh.mkdir('-p', 'my/plugin');
|
|
65
69
|
sh.pushd('-q', 'my/plugin');
|
|
66
|
-
sh.ShellString(content).toEnd('index.js');
|
|
67
|
-
sh.popd();
|
|
70
|
+
sh.ShellString(content).toEnd(join(dir, 'my', 'plugin', 'index.js'));
|
|
68
71
|
|
|
72
|
+
sh.pushd('-q', dir);
|
|
73
|
+
sh.ShellString(JSON.stringify({ name: 'project', version: '1.0.0', type: 'module' })).toEnd(
|
|
74
|
+
join(dir, 'package.json')
|
|
75
|
+
);
|
|
69
76
|
sh.exec(`npm install ${pluginDir}`);
|
|
77
|
+
sh.exec(`npm link release-it`);
|
|
70
78
|
|
|
71
79
|
const config = {
|
|
72
80
|
plugins: {
|
|
@@ -114,14 +122,16 @@ test.serial('should instantiate plugins and execute all release-cycle methods',
|
|
|
114
122
|
});
|
|
115
123
|
|
|
116
124
|
test.serial('should disable core plugins', async t => {
|
|
117
|
-
|
|
118
|
-
sh.
|
|
119
|
-
const content =
|
|
120
|
-
|
|
125
|
+
const { dir } = t.context;
|
|
126
|
+
sh.ShellString(JSON.stringify({ name: 'project', version: '1.0.0' })).toEnd(join(dir, 'package.json'));
|
|
127
|
+
const content =
|
|
128
|
+
"import { Plugin } from 'release-it'; " + ReplacePlugin.toString() + '; export default ReplacePlugin;';
|
|
129
|
+
sh.ShellString(content).toEnd(join(dir, 'replace-plugin.mjs'));
|
|
130
|
+
sh.exec(`npm link release-it`);
|
|
121
131
|
|
|
122
132
|
const config = {
|
|
123
133
|
plugins: {
|
|
124
|
-
'./replace-plugin.
|
|
134
|
+
'./replace-plugin.mjs': {}
|
|
125
135
|
}
|
|
126
136
|
};
|
|
127
137
|
const container = getContainer(config);
|
|
@@ -131,18 +141,20 @@ test.serial('should disable core plugins', async t => {
|
|
|
131
141
|
t.deepEqual(result, {
|
|
132
142
|
changelog: undefined,
|
|
133
143
|
name: undefined,
|
|
134
|
-
latestVersion:
|
|
144
|
+
latestVersion: '0.0.0',
|
|
135
145
|
version: undefined
|
|
136
146
|
});
|
|
137
147
|
});
|
|
138
148
|
|
|
139
149
|
test.serial('should expose context to execute commands', async t => {
|
|
140
|
-
|
|
141
|
-
sh.
|
|
142
|
-
|
|
150
|
+
const { dir } = t.context;
|
|
151
|
+
sh.ShellString(JSON.stringify({ name: 'pkg-name', version: '1.0.0', type: 'module' })).toEnd(
|
|
152
|
+
join(dir, 'package.json')
|
|
153
|
+
);
|
|
143
154
|
const content =
|
|
144
155
|
"import { Plugin } from 'release-it'; " + ContextPlugin.toString() + '; export default ContextPlugin;';
|
|
145
|
-
sh.ShellString(content).toEnd('context-plugin.js');
|
|
156
|
+
sh.ShellString(content).toEnd(join(dir, 'context-plugin.js'));
|
|
157
|
+
sh.exec(`npm link release-it`);
|
|
146
158
|
|
|
147
159
|
const repo = parseGitUrl('https://github.com/user/pkg');
|
|
148
160
|
|
package/test/spinner.js
CHANGED
|
@@ -4,16 +4,13 @@ import Spinner from '../lib/spinner.js';
|
|
|
4
4
|
import Config from '../lib/config.js';
|
|
5
5
|
|
|
6
6
|
test.beforeEach(t => {
|
|
7
|
-
t.context.ora =
|
|
8
|
-
promise: sinon.spy()
|
|
9
|
-
};
|
|
7
|
+
t.context.ora = sinon.spy();
|
|
10
8
|
});
|
|
11
9
|
|
|
12
10
|
const getConfig = options => {
|
|
13
11
|
const testConfig = {
|
|
14
12
|
ci: false,
|
|
15
|
-
config: false
|
|
16
|
-
'disable-metrics': true
|
|
13
|
+
config: false
|
|
17
14
|
};
|
|
18
15
|
return new Config(Object.assign({}, testConfig, options));
|
|
19
16
|
};
|
|
@@ -24,7 +21,7 @@ test('should not show spinner and not execute task if disabled', async t => {
|
|
|
24
21
|
const spinner = new Spinner({ container: { ora } });
|
|
25
22
|
await spinner.show({ enabled: false, task });
|
|
26
23
|
t.is(task.callCount, 0);
|
|
27
|
-
t.is(ora.
|
|
24
|
+
t.is(ora.callCount, 0);
|
|
28
25
|
});
|
|
29
26
|
|
|
30
27
|
test('should show spinner and run task by default', async t => {
|
|
@@ -35,9 +32,9 @@ test('should show spinner and run task by default', async t => {
|
|
|
35
32
|
const spinner = new Spinner({ container: { ora, config } });
|
|
36
33
|
await spinner.show({ task, label });
|
|
37
34
|
t.is(task.callCount, 1);
|
|
38
|
-
t.is(ora.
|
|
39
|
-
t.is(ora.
|
|
40
|
-
t.is(ora.
|
|
35
|
+
t.is(ora.callCount, 1);
|
|
36
|
+
t.is(ora.firstCall.args[0], task.firstCall.returnValue);
|
|
37
|
+
t.is(ora.firstCall.args[1], label);
|
|
41
38
|
});
|
|
42
39
|
|
|
43
40
|
test('should run task, but not show spinner if interactive', async t => {
|
|
@@ -47,7 +44,7 @@ test('should run task, but not show spinner if interactive', async t => {
|
|
|
47
44
|
const spinner = new Spinner({ container: { ora, config } });
|
|
48
45
|
await spinner.show({ task });
|
|
49
46
|
t.is(task.callCount, 1);
|
|
50
|
-
t.is(ora.
|
|
47
|
+
t.is(ora.callCount, 0);
|
|
51
48
|
});
|
|
52
49
|
|
|
53
50
|
test('should run task and show spinner if interactive, but external', async t => {
|
|
@@ -57,5 +54,5 @@ test('should run task and show spinner if interactive, but external', async t =>
|
|
|
57
54
|
const spinner = new Spinner({ container: { ora, config } });
|
|
58
55
|
await spinner.show({ task, external: true });
|
|
59
56
|
t.is(task.callCount, 1);
|
|
60
|
-
t.is(ora.
|
|
57
|
+
t.is(ora.callCount, 1);
|
|
61
58
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
foo=bar
|
package/test/stub/github.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import nock from 'nock';
|
|
2
2
|
|
|
3
|
-
const interceptAuthentication = ({ api = 'https://api.github.com', username = 'john' } = {}) =>
|
|
3
|
+
const interceptAuthentication = ({ api = 'https://api.github.com', username = 'john' } = {}) => {
|
|
4
4
|
nock(api).get('/user').reply(200, {
|
|
5
5
|
login: username
|
|
6
6
|
});
|
|
7
|
+
};
|
|
7
8
|
|
|
8
9
|
const interceptCollaborator = ({
|
|
9
10
|
api = 'https://api.github.com',
|
|
10
11
|
owner = 'user',
|
|
11
12
|
project = 'repo',
|
|
12
13
|
username = 'john'
|
|
13
|
-
} = {}) =>
|
|
14
|
+
} = {}) => {
|
|
15
|
+
nock(api).get(`/repos/${owner}/${project}/collaborators/${username}`).reply(204);
|
|
16
|
+
};
|
|
14
17
|
|
|
15
18
|
const interceptListReleases = ({
|
|
16
19
|
host = 'github.com',
|
|
@@ -18,7 +21,7 @@ const interceptListReleases = ({
|
|
|
18
21
|
owner = 'user',
|
|
19
22
|
project = 'repo',
|
|
20
23
|
tag_name
|
|
21
|
-
} = {}) =>
|
|
24
|
+
} = {}) => {
|
|
22
25
|
nock(api)
|
|
23
26
|
.get(`/repos/${owner}/${project}/releases?per_page=1&page=1`)
|
|
24
27
|
.reply(200, [
|
|
@@ -34,16 +37,24 @@ const interceptListReleases = ({
|
|
|
34
37
|
prerelease: false
|
|
35
38
|
}
|
|
36
39
|
]);
|
|
40
|
+
};
|
|
37
41
|
|
|
38
42
|
const interceptCreate = ({
|
|
39
43
|
api = 'https://api.github.com',
|
|
40
44
|
host = 'github.com',
|
|
41
45
|
owner = 'user',
|
|
42
46
|
project = 'repo',
|
|
43
|
-
body: { tag_name, name = '', body = null, prerelease = false, draft = false }
|
|
44
|
-
} = {}) =>
|
|
47
|
+
body: { tag_name, name = '', generate_release_notes = false, body = null, prerelease = false, draft = false }
|
|
48
|
+
} = {}) => {
|
|
45
49
|
nock(api)
|
|
46
|
-
.post(`/repos/${owner}/${project}/releases`, {
|
|
50
|
+
.post(`/repos/${owner}/${project}/releases`, {
|
|
51
|
+
tag_name,
|
|
52
|
+
name,
|
|
53
|
+
body,
|
|
54
|
+
prerelease,
|
|
55
|
+
draft,
|
|
56
|
+
generate_release_notes
|
|
57
|
+
})
|
|
47
58
|
.reply(() => {
|
|
48
59
|
const id = 1;
|
|
49
60
|
const responseBody = {
|
|
@@ -53,21 +64,23 @@ const interceptCreate = ({
|
|
|
53
64
|
body,
|
|
54
65
|
prerelease,
|
|
55
66
|
draft,
|
|
67
|
+
generate_release_notes,
|
|
56
68
|
upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/${id}/assets{?name,label}`,
|
|
57
69
|
html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`
|
|
58
70
|
};
|
|
59
71
|
return [200, responseBody, { location: `${api}/repos/${owner}/${project}/releases/${id}` }];
|
|
60
72
|
});
|
|
73
|
+
};
|
|
61
74
|
|
|
62
75
|
const interceptUpdate = ({
|
|
63
76
|
host = 'github.com',
|
|
64
77
|
api = 'https://api.github.com',
|
|
65
78
|
owner = 'user',
|
|
66
79
|
project = 'repo',
|
|
67
|
-
body: { tag_name, name = '', body = null, prerelease = false, draft = false }
|
|
68
|
-
} = {}) =>
|
|
80
|
+
body: { tag_name, name = '', body = null, prerelease = false, draft = false, generate_release_notes = false }
|
|
81
|
+
} = {}) => {
|
|
69
82
|
nock(api)
|
|
70
|
-
.patch(`/repos/${owner}/${project}/releases/1`, { tag_name, name, body, draft, prerelease })
|
|
83
|
+
.patch(`/repos/${owner}/${project}/releases/1`, { tag_name, name, body, draft, prerelease, generate_release_notes })
|
|
71
84
|
.reply(200, {
|
|
72
85
|
id: 1,
|
|
73
86
|
tag_name,
|
|
@@ -75,9 +88,11 @@ const interceptUpdate = ({
|
|
|
75
88
|
body,
|
|
76
89
|
prerelease,
|
|
77
90
|
draft,
|
|
91
|
+
generate_release_notes,
|
|
78
92
|
upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/1/assets{?name,label}`,
|
|
79
93
|
html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`
|
|
80
94
|
});
|
|
95
|
+
};
|
|
81
96
|
|
|
82
97
|
const interceptAsset = ({
|
|
83
98
|
api = 'https://api.github.com',
|
|
@@ -86,7 +101,7 @@ const interceptAsset = ({
|
|
|
86
101
|
project = 'repo',
|
|
87
102
|
tagName,
|
|
88
103
|
body = {}
|
|
89
|
-
} = {}) =>
|
|
104
|
+
} = {}) => {
|
|
90
105
|
nock(`https://uploads.${host}`)
|
|
91
106
|
.post(`/repos/${owner}/${project}/releases/1/assets`, body)
|
|
92
107
|
.query(true)
|
|
@@ -103,6 +118,7 @@ const interceptAsset = ({
|
|
|
103
118
|
browser_download_url: `https://${host}/${owner}/${project}/releases/download/${tagName}/${name}`
|
|
104
119
|
};
|
|
105
120
|
});
|
|
121
|
+
};
|
|
106
122
|
|
|
107
123
|
export {
|
|
108
124
|
interceptAuthentication,
|
package/test/stub/gitlab.js
CHANGED
|
@@ -11,16 +11,24 @@ export let interceptCollaborator = (
|
|
|
11
11
|
.get(`/api/v4/projects/${group ? `${group}%2F` : ''}${owner}%2F${project}/members/all/${userId}`)
|
|
12
12
|
.reply(200, { id: userId, username: owner, access_level: 30 });
|
|
13
13
|
|
|
14
|
-
export let
|
|
15
|
-
|
|
14
|
+
export let interceptPublish = ({ host = 'https://gitlab.com', owner = 'user', project = 'repo', body } = {}, options) =>
|
|
15
|
+
nock(host, options).post(`/api/v4/projects/${owner}%2F${project}/releases`, body).reply(200, {});
|
|
16
|
+
|
|
17
|
+
export let interceptMilestones = (
|
|
18
|
+
{ host = 'https://gitlab.com', owner = 'user', project = 'repo', query = {}, milestones = [] } = {},
|
|
16
19
|
options
|
|
17
20
|
) =>
|
|
18
21
|
nock(host, options)
|
|
19
|
-
.get(`/api/v4/projects/${
|
|
20
|
-
.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
.get(`/api/v4/projects/${owner}%2F${project}/milestones`)
|
|
23
|
+
.query(
|
|
24
|
+
Object.assign(
|
|
25
|
+
{
|
|
26
|
+
include_parent_milestones: true
|
|
27
|
+
},
|
|
28
|
+
query
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
.reply(200, JSON.stringify(milestones));
|
|
24
32
|
|
|
25
33
|
export let interceptAsset = ({ host = 'https://gitlab.com', owner = 'user', project = 'repo' } = {}) =>
|
|
26
34
|
nock(host)
|
package/test/stub/shell.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path from 'path';
|
|
1
|
+
import path from 'node:path';
|
|
2
2
|
import test from 'ava';
|
|
3
3
|
import sh from 'shelljs';
|
|
4
4
|
import _ from 'lodash';
|
|
@@ -19,8 +19,7 @@ const sandbox = sinon.createSandbox();
|
|
|
19
19
|
|
|
20
20
|
const testConfig = {
|
|
21
21
|
ci: false,
|
|
22
|
-
config: false
|
|
23
|
-
'disable-metrics': true
|
|
22
|
+
config: false
|
|
24
23
|
};
|
|
25
24
|
|
|
26
25
|
const log = sandbox.createStubInstance(Log);
|
package/test/tasks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path from 'path';
|
|
1
|
+
import path from 'node:path';
|
|
2
2
|
import test from 'ava';
|
|
3
3
|
import sh from 'shelljs';
|
|
4
4
|
import _ from 'lodash';
|
|
@@ -30,8 +30,7 @@ const sandbox = sinon.createSandbox();
|
|
|
30
30
|
|
|
31
31
|
const testConfig = {
|
|
32
32
|
ci: true,
|
|
33
|
-
config: false
|
|
34
|
-
'disable-metrics': true
|
|
33
|
+
config: false
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
const log = sandbox.createStubInstance(Log);
|
|
@@ -358,7 +357,7 @@ test.serial('should initially publish non-private scoped npm package privately',
|
|
|
358
357
|
test.serial('should use pkg.publishConfig.registry', async t => {
|
|
359
358
|
const { target } = t.context;
|
|
360
359
|
const pkgName = path.basename(target);
|
|
361
|
-
const registry = 'https://my-registry.
|
|
360
|
+
const registry = 'https://my-registry.example.org';
|
|
362
361
|
|
|
363
362
|
gitAdd(
|
|
364
363
|
JSON.stringify({
|
|
@@ -397,6 +396,47 @@ test.serial('should propagate errors', async t => {
|
|
|
397
396
|
t.is(log.error.callCount, 1);
|
|
398
397
|
});
|
|
399
398
|
|
|
399
|
+
test.serial('should use custom changelog command with context', async t => {
|
|
400
|
+
const { bare } = t.context;
|
|
401
|
+
const project = path.basename(bare);
|
|
402
|
+
const owner = path.basename(path.dirname(bare));
|
|
403
|
+
sh.exec('git tag v1.0.0');
|
|
404
|
+
gitAdd('line', 'file', 'More file');
|
|
405
|
+
|
|
406
|
+
interceptGitHubAuthentication();
|
|
407
|
+
interceptGitHubCollaborator({ owner, project });
|
|
408
|
+
interceptGitHubCreate({
|
|
409
|
+
owner,
|
|
410
|
+
project,
|
|
411
|
+
body: {
|
|
412
|
+
tag_name: 'v1.1.0',
|
|
413
|
+
name: 'Release 1.1.0',
|
|
414
|
+
body: 'custom-changelog-generator --from=v1.0.0 --to=v1.1.0',
|
|
415
|
+
draft: false,
|
|
416
|
+
prerelease: false
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const container = getContainer({
|
|
421
|
+
increment: 'minor',
|
|
422
|
+
github: {
|
|
423
|
+
release: true,
|
|
424
|
+
releaseNotes: 'echo custom-changelog-generator --from=${latestTag} --to=${tagName}',
|
|
425
|
+
pushRepo: `https://github.com/${owner}/${project}`
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
const exec = sinon.spy(container.shell, 'execStringCommand');
|
|
430
|
+
|
|
431
|
+
await runTasks({}, container);
|
|
432
|
+
|
|
433
|
+
const command = exec.args.find(([command]) => command.includes('custom-changelog-generator'));
|
|
434
|
+
|
|
435
|
+
t.is(command[0], 'echo custom-changelog-generator --from=v1.0.0 --to=v1.1.0');
|
|
436
|
+
|
|
437
|
+
exec.restore();
|
|
438
|
+
});
|
|
439
|
+
|
|
400
440
|
{
|
|
401
441
|
test.serial('should run all hooks', async t => {
|
|
402
442
|
gitAdd(`{"name":"hooked","version":"1.0.0","type":"module"}`, 'package.json', 'Add package.json');
|
package/test/util/helpers.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
3
4
|
import sh from 'shelljs';
|
|
4
|
-
import tmp from 'tmp';
|
|
5
5
|
|
|
6
6
|
const mkTmpDir = () => {
|
|
7
|
-
const dir =
|
|
8
|
-
return dir
|
|
7
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'release-it-'));
|
|
8
|
+
return dir;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
const readFile = file => fs.readFile(path.resolve(file), 'utf8');
|
|
11
|
+
const readFile = file => fs.promises.readFile(path.resolve(file), 'utf8');
|
|
12
12
|
|
|
13
13
|
const gitAdd = (content, file, message) => {
|
|
14
14
|
sh.ShellString(content).toEnd(file);
|