release-it 0.0.0-pl.0
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/LICENSE +21 -0
- package/README.md +421 -0
- package/bin/release-it.js +42 -0
- package/config/release-it.json +70 -0
- package/lib/cli.js +44 -0
- package/lib/config.js +139 -0
- package/lib/index.js +152 -0
- package/lib/log.js +69 -0
- package/lib/plugin/GitBase.js +125 -0
- package/lib/plugin/GitRelease.js +58 -0
- package/lib/plugin/Plugin.js +73 -0
- package/lib/plugin/factory.js +89 -0
- package/lib/plugin/git/Git.js +220 -0
- package/lib/plugin/git/prompts.js +19 -0
- package/lib/plugin/github/GitHub.js +403 -0
- package/lib/plugin/github/prompts.js +16 -0
- package/lib/plugin/github/util.js +39 -0
- package/lib/plugin/gitlab/GitLab.js +277 -0
- package/lib/plugin/gitlab/prompts.js +9 -0
- package/lib/plugin/npm/npm.js +281 -0
- package/lib/plugin/npm/prompts.js +12 -0
- package/lib/plugin/version/Version.js +129 -0
- package/lib/prompt.js +33 -0
- package/lib/shell.js +91 -0
- package/lib/spinner.js +29 -0
- package/lib/util.js +109 -0
- package/package.json +122 -0
- package/test/cli.js +20 -0
- package/test/config.js +144 -0
- package/test/git.init.js +250 -0
- package/test/git.js +358 -0
- package/test/github.js +487 -0
- package/test/gitlab.js +252 -0
- package/test/log.js +143 -0
- package/test/npm.js +417 -0
- package/test/plugin-name.js +9 -0
- package/test/plugins.js +238 -0
- package/test/prompt.js +97 -0
- package/test/resources/file-v2.0.1.txt +1 -0
- package/test/resources/file-v2.0.2.txt +1 -0
- package/test/resources/file1 +1 -0
- package/test/shell.js +74 -0
- package/test/spinner.js +58 -0
- 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 +130 -0
- package/test/stub/gitlab.js +44 -0
- package/test/stub/plugin-context.js +36 -0
- package/test/stub/plugin-replace.js +9 -0
- package/test/stub/plugin.js +39 -0
- package/test/stub/shell.js +24 -0
- package/test/tasks.interactive.js +208 -0
- package/test/tasks.js +585 -0
- package/test/util/helpers.js +32 -0
- package/test/util/index.js +78 -0
- package/test/util/setup.js +5 -0
- package/test/utils.js +97 -0
- package/test/version.js +173 -0
package/test/gitlab.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import nock from 'nock';
|
|
4
|
+
import GitLab from '../lib/plugin/gitlab/GitLab.js';
|
|
5
|
+
import { factory, runTasks } from './util/index.js';
|
|
6
|
+
import {
|
|
7
|
+
interceptUser,
|
|
8
|
+
interceptCollaborator,
|
|
9
|
+
interceptPublish,
|
|
10
|
+
interceptAsset,
|
|
11
|
+
interceptMilestones
|
|
12
|
+
} from './stub/gitlab.js';
|
|
13
|
+
|
|
14
|
+
const tokenHeader = 'Private-Token';
|
|
15
|
+
const tokenRef = 'GITLAB_TOKEN';
|
|
16
|
+
|
|
17
|
+
test.serial('should validate token', async t => {
|
|
18
|
+
const tokenRef = 'MY_GITLAB_TOKEN';
|
|
19
|
+
const pushRepo = 'https://gitlab.com/user/repo';
|
|
20
|
+
const options = { gitlab: { release: true, tokenRef, tokenHeader, pushRepo } };
|
|
21
|
+
const gitlab = factory(GitLab, { options });
|
|
22
|
+
delete process.env[tokenRef];
|
|
23
|
+
|
|
24
|
+
await t.throwsAsync(gitlab.init(), {
|
|
25
|
+
message: /^Environment variable "MY_GITLAB_TOKEN" is required for GitLab releases/
|
|
26
|
+
});
|
|
27
|
+
process.env[tokenRef] = '123'; // eslint-disable-line require-atomic-updates
|
|
28
|
+
|
|
29
|
+
interceptUser(undefined, { reqheaders: { 'private-token': '123' } });
|
|
30
|
+
interceptCollaborator(undefined, { reqheaders: { 'private-token': '123' } });
|
|
31
|
+
await t.notThrowsAsync(gitlab.init());
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test.serial('should support CI Job token header', async t => {
|
|
35
|
+
const tokenRef = 'CI_JOB_TOKEN';
|
|
36
|
+
const tokenHeader = 'Job-Token';
|
|
37
|
+
process.env[tokenRef] = 'j0b-t0k3n';
|
|
38
|
+
const pushRepo = 'https://gitlab.com/user/repo';
|
|
39
|
+
const options = { git: { pushRepo }, gitlab: { release: true, tokenRef, tokenHeader } };
|
|
40
|
+
const gitlab = factory(GitLab, { options });
|
|
41
|
+
|
|
42
|
+
interceptPublish(undefined, { reqheaders: { 'job-token': '1' } });
|
|
43
|
+
|
|
44
|
+
await t.notThrowsAsync(gitlab.init());
|
|
45
|
+
|
|
46
|
+
delete process.env[tokenRef];
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test.serial('should upload assets and release', async t => {
|
|
50
|
+
const pushRepo = 'https://gitlab.com/user/repo';
|
|
51
|
+
const options = {
|
|
52
|
+
git: { pushRepo },
|
|
53
|
+
gitlab: {
|
|
54
|
+
tokenRef,
|
|
55
|
+
release: true,
|
|
56
|
+
releaseName: 'Release ${version}',
|
|
57
|
+
releaseNotes: 'echo Custom notes',
|
|
58
|
+
assets: 'test/resources/file-v${version}.txt',
|
|
59
|
+
milestones: ['${version}', '${latestVersion} UAT']
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const gitlab = factory(GitLab, { options });
|
|
63
|
+
sinon.stub(gitlab, 'getLatestVersion').resolves('2.0.0');
|
|
64
|
+
|
|
65
|
+
interceptUser();
|
|
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
|
+
});
|
|
87
|
+
interceptAsset();
|
|
88
|
+
interceptPublish({
|
|
89
|
+
body: {
|
|
90
|
+
name: 'Release 2.0.1',
|
|
91
|
+
tag_name: '2.0.1',
|
|
92
|
+
description: 'Custom notes',
|
|
93
|
+
assets: {
|
|
94
|
+
links: [
|
|
95
|
+
{
|
|
96
|
+
name: 'file-v2.0.1.txt',
|
|
97
|
+
url: `${pushRepo}/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/file-v2.0.1.txt`
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
milestones: ['2.0.1', '2.0.0 UAT']
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await runTasks(gitlab);
|
|
106
|
+
|
|
107
|
+
t.is(gitlab.assets[0].url, `${pushRepo}/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/file-v2.0.1.txt`);
|
|
108
|
+
const { isReleased, releaseUrl } = gitlab.getContext();
|
|
109
|
+
t.true(isReleased);
|
|
110
|
+
t.is(releaseUrl, `${pushRepo}/-/releases`);
|
|
111
|
+
});
|
|
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
|
+
|
|
148
|
+
test.serial('should release to self-managed host', async t => {
|
|
149
|
+
const host = 'https://gitlab.example.org';
|
|
150
|
+
const scope = nock(host);
|
|
151
|
+
scope.post('/api/v4/projects/user%2Frepo/releases').reply(200, {});
|
|
152
|
+
const options = {
|
|
153
|
+
git: { pushRepo: `${host}/user/repo` },
|
|
154
|
+
gitlab: { releaseName: 'Release ${version}', releaseNotes: 'echo readme', tokenRef }
|
|
155
|
+
};
|
|
156
|
+
const gitlab = factory(GitLab, { options });
|
|
157
|
+
sinon.stub(gitlab, 'getLatestVersion').resolves('1.0.0');
|
|
158
|
+
|
|
159
|
+
interceptUser({ host });
|
|
160
|
+
interceptCollaborator({ host });
|
|
161
|
+
|
|
162
|
+
await runTasks(gitlab);
|
|
163
|
+
|
|
164
|
+
const { origin, baseUrl } = gitlab.getContext();
|
|
165
|
+
t.is(origin, host);
|
|
166
|
+
t.is(baseUrl, `${host}/api/v4`);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test.serial('should release to sub-grouped repo', async t => {
|
|
170
|
+
const scope = nock('https://gitlab.com');
|
|
171
|
+
scope.post('/api/v4/projects/group%2Fsub-group%2Frepo/releases').reply(200, {});
|
|
172
|
+
const options = { gitlab: { tokenRef }, git: { pushRepo: 'git@gitlab.com:group/sub-group/repo.git' } };
|
|
173
|
+
const gitlab = factory(GitLab, { options });
|
|
174
|
+
|
|
175
|
+
interceptUser({ owner: 'sub-group' });
|
|
176
|
+
interceptCollaborator({ owner: 'sub-group', group: 'group' });
|
|
177
|
+
|
|
178
|
+
await runTasks(gitlab);
|
|
179
|
+
|
|
180
|
+
const { isReleased, releaseUrl } = gitlab.getContext();
|
|
181
|
+
t.true(isReleased);
|
|
182
|
+
t.is(releaseUrl, 'https://gitlab.com/group/sub-group/repo/-/releases');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test.serial('should throw for unauthenticated user', async t => {
|
|
186
|
+
const host = 'https://gitlab.com';
|
|
187
|
+
const pushRepo = `${host}/user/repo`;
|
|
188
|
+
const options = { gitlab: { tokenRef, pushRepo, host } };
|
|
189
|
+
const gitlab = factory(GitLab, { options });
|
|
190
|
+
const scope = nock(host);
|
|
191
|
+
scope.get(`/api/v4/user`).reply(401);
|
|
192
|
+
|
|
193
|
+
await t.throwsAsync(runTasks(gitlab), {
|
|
194
|
+
message: /^Could not authenticate with GitLab using environment variable "GITLAB_TOKEN"/
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test.serial('should throw for non-collaborator', async t => {
|
|
199
|
+
const host = 'https://gitlab.com';
|
|
200
|
+
const pushRepo = `${host}/john/repo`;
|
|
201
|
+
const options = { gitlab: { tokenRef, pushRepo, host } };
|
|
202
|
+
const gitlab = factory(GitLab, { options });
|
|
203
|
+
const scope = nock(host);
|
|
204
|
+
scope.get(`/api/v4/projects/john%2Frepo/members/all/1`).reply(200, { username: 'emma' });
|
|
205
|
+
interceptUser({ owner: 'john' });
|
|
206
|
+
|
|
207
|
+
await t.throwsAsync(runTasks(gitlab), { message: /^User john is not a collaborator for john\/repo/ });
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test.serial('should throw for insufficient access level', async t => {
|
|
211
|
+
const host = 'https://gitlab.com';
|
|
212
|
+
const pushRepo = `${host}/john/repo`;
|
|
213
|
+
const options = { gitlab: { tokenRef, pushRepo, host } };
|
|
214
|
+
const gitlab = factory(GitLab, { options });
|
|
215
|
+
const scope = nock(host);
|
|
216
|
+
scope.get(`/api/v4/projects/john%2Frepo/members/all/1`).reply(200, { username: 'john', access_level: 10 });
|
|
217
|
+
interceptUser({ owner: 'john' });
|
|
218
|
+
|
|
219
|
+
await t.throwsAsync(runTasks(gitlab), { message: /^User john is not a collaborator for john\/repo/ });
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test('should not make requests in dry run', async t => {
|
|
223
|
+
const [host, owner, repo] = ['https://gitlab.example.org', 'user', 'repo'];
|
|
224
|
+
const pushRepo = `${host}/${owner}/${repo}`;
|
|
225
|
+
const options = { 'dry-run': true, git: { pushRepo }, gitlab: { releaseName: 'R', tokenRef } };
|
|
226
|
+
const gitlab = factory(GitLab, { options });
|
|
227
|
+
sinon.stub(gitlab, 'getLatestVersion').resolves('1.0.0');
|
|
228
|
+
const spy = sinon.spy(gitlab, 'client', ['get']);
|
|
229
|
+
|
|
230
|
+
await runTasks(gitlab);
|
|
231
|
+
|
|
232
|
+
const { isReleased, releaseUrl } = gitlab.getContext();
|
|
233
|
+
t.is(spy.get.callCount, 0);
|
|
234
|
+
t.is(gitlab.log.exec.args[2][0], 'gitlab releases#uploadAssets');
|
|
235
|
+
t.is(gitlab.log.exec.args[3][0], 'gitlab releases#createRelease "R" (1.0.1)');
|
|
236
|
+
t.true(isReleased);
|
|
237
|
+
t.is(releaseUrl, `${pushRepo}/-/releases`);
|
|
238
|
+
spy.get.restore();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('should skip checks', async t => {
|
|
242
|
+
const options = { gitlab: { tokenRef, skipChecks: true, release: true, milestones: ['v1.0.0'] } };
|
|
243
|
+
const gitlab = factory(GitLab, { options });
|
|
244
|
+
const spy = sinon.spy(gitlab, 'client', ['get']);
|
|
245
|
+
|
|
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);
|
|
252
|
+
});
|
package/test/log.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { EOL } from 'node:os';
|
|
2
|
+
import test from 'ava';
|
|
3
|
+
import mockStdIo from 'mock-stdio';
|
|
4
|
+
import stripAnsi from 'strip-ansi';
|
|
5
|
+
import Log from '../lib/log.js';
|
|
6
|
+
|
|
7
|
+
test('should write to stdout', t => {
|
|
8
|
+
const log = new Log();
|
|
9
|
+
mockStdIo.start();
|
|
10
|
+
log.log('foo');
|
|
11
|
+
const { stdout, stderr } = mockStdIo.end();
|
|
12
|
+
t.is(stdout, 'foo\n');
|
|
13
|
+
t.is(stderr, '');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should write to stderr', t => {
|
|
17
|
+
const log = new Log();
|
|
18
|
+
mockStdIo.start();
|
|
19
|
+
log.error('foo');
|
|
20
|
+
const { stdout, stderr } = mockStdIo.end();
|
|
21
|
+
t.is(stdout, '');
|
|
22
|
+
t.is(stripAnsi(stderr), 'ERROR foo\n');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should print a warning', t => {
|
|
26
|
+
const log = new Log();
|
|
27
|
+
mockStdIo.start();
|
|
28
|
+
log.warn('foo');
|
|
29
|
+
const { stdout } = mockStdIo.end();
|
|
30
|
+
t.is(stripAnsi(stdout), 'WARNING foo\n');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should print verbose', t => {
|
|
34
|
+
const log = new Log({ isVerbose: true, verbosityLevel: 2 });
|
|
35
|
+
mockStdIo.start();
|
|
36
|
+
log.verbose('foo');
|
|
37
|
+
const { stdout } = mockStdIo.end();
|
|
38
|
+
t.is(stdout, 'foo\n');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should print external scripts verbose', t => {
|
|
42
|
+
const log = new Log({ isVerbose: true });
|
|
43
|
+
mockStdIo.start();
|
|
44
|
+
log.verbose('foo', { isExternal: true });
|
|
45
|
+
const { stdout } = mockStdIo.end();
|
|
46
|
+
t.is(stdout, 'foo\n');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should always print external scripts verbose', t => {
|
|
50
|
+
const log = new Log({ isVerbose: true, verbosityLevel: 2 });
|
|
51
|
+
mockStdIo.start();
|
|
52
|
+
log.verbose('foo', { isExternal: true });
|
|
53
|
+
const { stdout } = mockStdIo.end();
|
|
54
|
+
t.is(stdout, 'foo\n');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('should not print verbose by default', t => {
|
|
58
|
+
const log = new Log();
|
|
59
|
+
mockStdIo.start();
|
|
60
|
+
log.verbose('foo');
|
|
61
|
+
const { stdout } = mockStdIo.end();
|
|
62
|
+
t.is(stdout, '');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should not print command execution by default', t => {
|
|
66
|
+
const log = new Log();
|
|
67
|
+
mockStdIo.start();
|
|
68
|
+
log.exec('foo');
|
|
69
|
+
const { stdout } = mockStdIo.end();
|
|
70
|
+
t.is(stdout.trim(), '');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should print command execution (verbose)', t => {
|
|
74
|
+
const log = new Log({ isVerbose: true, verbosityLevel: 2 });
|
|
75
|
+
mockStdIo.start();
|
|
76
|
+
log.exec('foo');
|
|
77
|
+
const { stdout } = mockStdIo.end();
|
|
78
|
+
t.is(stdout.trim(), '$ foo');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('should print command execution (verbose/dry run)', t => {
|
|
82
|
+
const log = new Log({ isVerbose: true });
|
|
83
|
+
mockStdIo.start();
|
|
84
|
+
log.exec('foo', { isDryRun: true, isExternal: true });
|
|
85
|
+
const { stdout } = mockStdIo.end();
|
|
86
|
+
t.is(stdout.trim(), '! foo');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should print command execution (verbose/external)', t => {
|
|
90
|
+
const log = new Log({ isVerbose: true });
|
|
91
|
+
mockStdIo.start();
|
|
92
|
+
log.exec('foo', { isExternal: true });
|
|
93
|
+
const { stdout } = mockStdIo.end();
|
|
94
|
+
t.is(stdout.trim(), '$ foo');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should print command execution (dry run)', t => {
|
|
98
|
+
const log = new Log({ isDryRun: true });
|
|
99
|
+
mockStdIo.start();
|
|
100
|
+
log.exec('foo');
|
|
101
|
+
const { stdout } = mockStdIo.end();
|
|
102
|
+
t.is(stdout, '$ foo\n');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('should print command execution (read-only)', t => {
|
|
106
|
+
const log = new Log({ isDryRun: true });
|
|
107
|
+
mockStdIo.start();
|
|
108
|
+
log.exec('foo', 'bar', false);
|
|
109
|
+
const { stdout } = mockStdIo.end();
|
|
110
|
+
t.is(stdout, '$ foo bar\n');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('should print command execution (write)', t => {
|
|
114
|
+
const log = new Log({ isDryRun: true });
|
|
115
|
+
mockStdIo.start();
|
|
116
|
+
log.exec('foo', '--arg n', { isDryRun: true });
|
|
117
|
+
const { stdout } = mockStdIo.end();
|
|
118
|
+
t.is(stdout, '! foo --arg n\n');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('should print obtrusive', t => {
|
|
122
|
+
const log = new Log({ isCI: false });
|
|
123
|
+
mockStdIo.start();
|
|
124
|
+
log.obtrusive('spacious');
|
|
125
|
+
const { stdout } = mockStdIo.end();
|
|
126
|
+
t.is(stdout, '\nspacious\n\n');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should not print obtrusive in CI mode', t => {
|
|
130
|
+
const log = new Log({ isCI: true });
|
|
131
|
+
mockStdIo.start();
|
|
132
|
+
log.obtrusive('normal');
|
|
133
|
+
const { stdout } = mockStdIo.end();
|
|
134
|
+
t.is(stdout, 'normal\n');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('should print preview', t => {
|
|
138
|
+
const log = new Log();
|
|
139
|
+
mockStdIo.start();
|
|
140
|
+
log.preview({ title: 'title', text: 'changelog' });
|
|
141
|
+
const { stdout } = mockStdIo.end();
|
|
142
|
+
t.is(stripAnsi(stdout), `Title:${EOL}changelog\n`);
|
|
143
|
+
});
|