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
package/test/github.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import test from '
|
|
2
|
-
import
|
|
1
|
+
import test, { describe, before, after, afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
3
|
import { RequestError } from '@octokit/request-error';
|
|
4
4
|
import GitHub from '../lib/plugin/github/GitHub.js';
|
|
5
5
|
import { getSearchQueries } from '../lib/plugin/github/util.js';
|
|
@@ -12,536 +12,619 @@ import {
|
|
|
12
12
|
interceptUpdate,
|
|
13
13
|
interceptAsset
|
|
14
14
|
} from './stub/github.js';
|
|
15
|
+
import { mockFetch } from './util/mock.js';
|
|
16
|
+
|
|
17
|
+
describe('github', () => {
|
|
18
|
+
const tokenRef = 'GITHUB_TOKEN';
|
|
19
|
+
const pushRepo = 'git://github.com/user/repo';
|
|
20
|
+
const host = 'github.com';
|
|
21
|
+
const git = { changelog: '' };
|
|
22
|
+
const requestErrorOptions = { request: { url: '', headers: {} }, response: { headers: {} } };
|
|
23
|
+
|
|
24
|
+
const [mocker, api, assets, example, custom] = mockFetch([
|
|
25
|
+
'https://api.github.com',
|
|
26
|
+
'https://uploads.github.com',
|
|
27
|
+
'https://github.example.org/api/v3',
|
|
28
|
+
'https://custom.example.org/api/v3'
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
before(() => {
|
|
32
|
+
mocker.mockGlobal();
|
|
33
|
+
});
|
|
15
34
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const git = { changelog: '' };
|
|
20
|
-
const requestErrorOptions = { request: { url: '', headers: {} }, response: { headers: {} } };
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
mocker.clearAll();
|
|
37
|
+
});
|
|
21
38
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const github = factory(GitHub, { options });
|
|
39
|
+
after(() => {
|
|
40
|
+
mocker.unmockGlobal();
|
|
41
|
+
});
|
|
26
42
|
|
|
27
|
-
|
|
43
|
+
test('should check token and perform checks', async () => {
|
|
44
|
+
const tokenRef = 'MY_GITHUB_TOKEN';
|
|
45
|
+
const options = { github: { release: true, tokenRef, pushRepo } };
|
|
46
|
+
const github = factory(GitHub, { options });
|
|
28
47
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
48
|
+
interceptAuthentication(api);
|
|
49
|
+
interceptCollaborator(api);
|
|
50
|
+
await assert.doesNotReject(github.init());
|
|
51
|
+
});
|
|
33
52
|
|
|
34
|
-
test
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
53
|
+
test('should check token and warn', async () => {
|
|
54
|
+
const tokenRef = 'MY_GITHUB_TOKEN';
|
|
55
|
+
const options = { github: { release: true, tokenRef, pushRepo } };
|
|
56
|
+
const github = factory(GitHub, { options });
|
|
57
|
+
delete process.env[tokenRef];
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
await assert.doesNotReject(github.init());
|
|
41
60
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
assert.equal(
|
|
62
|
+
github.log.warn.mock.calls[0].arguments[0],
|
|
63
|
+
'Environment variable "MY_GITHUB_TOKEN" is required for automated GitHub Releases.'
|
|
64
|
+
);
|
|
65
|
+
assert.equal(github.log.warn.mock.calls[1].arguments[0], 'Falling back to web-based GitHub Release.');
|
|
66
|
+
});
|
|
45
67
|
|
|
46
|
-
test('should release and upload assets', async t => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
});
|
|
68
|
+
test('should release and upload assets', async t => {
|
|
69
|
+
const options = {
|
|
70
|
+
git,
|
|
71
|
+
github: {
|
|
72
|
+
pushRepo,
|
|
73
|
+
tokenRef,
|
|
74
|
+
release: true,
|
|
75
|
+
releaseName: 'Release ${tagName}',
|
|
76
|
+
releaseNotes: 'echo Custom notes',
|
|
77
|
+
assets: 'test/resources/file-v${version}.txt'
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const github = factory(GitHub, { options });
|
|
81
|
+
|
|
82
|
+
const original = github.shell.exec.bind(github.shell);
|
|
83
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
84
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
85
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
86
|
+
return original(...args);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
interceptAuthentication(api);
|
|
90
|
+
interceptCollaborator(api);
|
|
91
|
+
interceptCreate(api, { body: { tag_name: '2.0.2', name: 'Release 2.0.2', body: 'Custom notes' } });
|
|
92
|
+
interceptAsset(assets, { body: '*' });
|
|
93
|
+
|
|
94
|
+
await runTasks(github);
|
|
95
|
+
|
|
96
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
97
|
+
assert(isReleased);
|
|
98
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
99
|
+
});
|
|
75
100
|
|
|
76
|
-
test('should create a pre-release and draft release notes', async t => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const exec = sinon.stub(github.shell, 'exec').callThrough();
|
|
90
|
-
exec.withArgs('git log --pretty=format:"* %s (%h)" ${from}...${to}').resolves('');
|
|
91
|
-
exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('2.0.1');
|
|
92
|
-
|
|
93
|
-
interceptAuthentication();
|
|
94
|
-
interceptCollaborator();
|
|
95
|
-
interceptCreate({ body: { tag_name: '2.0.2', name: 'Release 2.0.2', prerelease: true, draft: true } });
|
|
96
|
-
|
|
97
|
-
await runTasks(github);
|
|
98
|
-
|
|
99
|
-
const { isReleased, releaseUrl } = github.getContext();
|
|
100
|
-
t.true(isReleased);
|
|
101
|
-
t.is(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
102
|
-
exec.restore();
|
|
103
|
-
});
|
|
101
|
+
test('should create a pre-release and draft release notes', async t => {
|
|
102
|
+
const options = {
|
|
103
|
+
git,
|
|
104
|
+
github: {
|
|
105
|
+
pushRepo,
|
|
106
|
+
tokenRef,
|
|
107
|
+
release: true,
|
|
108
|
+
releaseName: 'Release ${tagName}',
|
|
109
|
+
preRelease: true,
|
|
110
|
+
draft: true
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const github = factory(GitHub, { options });
|
|
104
114
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
release: true,
|
|
112
|
-
releaseName: 'Release ${tagName}',
|
|
113
|
-
autoGenerate: true
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
const github = factory(GitHub, { options });
|
|
117
|
-
const exec = sinon.stub(github.shell, 'exec').callThrough();
|
|
118
|
-
exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('2.0.1');
|
|
115
|
+
const original = github.shell.exec.bind(github.shell);
|
|
116
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
117
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
118
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
119
|
+
return original(...args);
|
|
120
|
+
});
|
|
119
121
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
interceptAuthentication(api);
|
|
123
|
+
interceptCollaborator(api);
|
|
124
|
+
interceptCreate(api, { body: { tag_name: '2.0.2', name: 'Release 2.0.2', prerelease: true, draft: true } });
|
|
123
125
|
|
|
124
|
-
|
|
126
|
+
await runTasks(github);
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
128
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
129
|
+
assert(isReleased);
|
|
130
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
131
|
+
});
|
|
131
132
|
|
|
132
|
-
test('should
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
t.true(isReleased);
|
|
164
|
-
t.is(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.1');
|
|
165
|
-
exec.restore();
|
|
166
|
-
});
|
|
133
|
+
test('should create auto-generated release notes', async t => {
|
|
134
|
+
const options = {
|
|
135
|
+
git,
|
|
136
|
+
github: {
|
|
137
|
+
pushRepo,
|
|
138
|
+
tokenRef,
|
|
139
|
+
release: true,
|
|
140
|
+
releaseName: 'Release ${tagName}',
|
|
141
|
+
autoGenerate: true
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const github = factory(GitHub, { options });
|
|
145
|
+
|
|
146
|
+
const original = github.shell.exec.bind(github.shell);
|
|
147
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
148
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
149
|
+
return original(...args);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
interceptAuthentication(api);
|
|
153
|
+
interceptCollaborator(api);
|
|
154
|
+
interceptCreate(api, {
|
|
155
|
+
body: { tag_name: '2.0.2', name: 'Release 2.0.2', generate_release_notes: true, body: '' }
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await runTasks(github);
|
|
159
|
+
|
|
160
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
161
|
+
assert(isReleased);
|
|
162
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
163
|
+
});
|
|
167
164
|
|
|
168
|
-
test('should
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
165
|
+
test('should update release and upload assets', async t => {
|
|
166
|
+
const asset = 'file1';
|
|
167
|
+
const options = {
|
|
168
|
+
increment: false,
|
|
169
|
+
git,
|
|
170
|
+
github: {
|
|
171
|
+
update: true,
|
|
172
|
+
pushRepo,
|
|
173
|
+
tokenRef,
|
|
174
|
+
release: true,
|
|
175
|
+
releaseName: 'Release ${tagName}',
|
|
176
|
+
releaseNotes: 'echo Custom notes',
|
|
177
|
+
assets: `test/resources/${asset}`
|
|
178
178
|
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
};
|
|
180
|
+
const github = factory(GitHub, { options });
|
|
181
|
+
|
|
182
|
+
const original = github.shell.exec.bind(github.shell);
|
|
183
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
184
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
185
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
186
|
+
if (args[0] === 'git rev-list 2.0.1 --tags --max-count=1') return Promise.resolve('a123456');
|
|
187
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
188
|
+
return original(...args);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
interceptAuthentication(api);
|
|
192
|
+
interceptCollaborator(api);
|
|
193
|
+
interceptListReleases(api, { tag_name: '2.0.1' });
|
|
194
|
+
interceptUpdate(api, { body: { tag_name: '2.0.1', name: 'Release 2.0.1', body: 'Custom notes' } });
|
|
195
|
+
interceptAsset(assets, { body: asset });
|
|
196
|
+
|
|
197
|
+
await runTasks(github);
|
|
198
|
+
|
|
199
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
200
|
+
assert(isReleased);
|
|
201
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.1');
|
|
202
|
+
});
|
|
184
203
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
204
|
+
test('should create custom release notes using releaseNotes function', async t => {
|
|
205
|
+
const options = {
|
|
206
|
+
git,
|
|
207
|
+
github: {
|
|
208
|
+
pushRepo,
|
|
209
|
+
tokenRef,
|
|
210
|
+
release: true,
|
|
211
|
+
releaseName: 'Release ${tagName}',
|
|
212
|
+
releaseNotes(context) {
|
|
213
|
+
return `Custom notes for tag ${context.tagName}`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
const github = factory(GitHub, { options });
|
|
218
|
+
|
|
219
|
+
const original = github.shell.exec.bind(github.shell);
|
|
220
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
221
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
222
|
+
return original(...args);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
interceptAuthentication(api);
|
|
226
|
+
interceptCollaborator(api);
|
|
227
|
+
interceptCreate(api, {
|
|
228
|
+
body: { tag_name: '2.0.2', name: 'Release 2.0.2', body: 'Custom notes for tag 2.0.2' }
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
await runTasks(github);
|
|
232
|
+
|
|
233
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
234
|
+
assert(isReleased);
|
|
235
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
236
|
+
});
|
|
188
237
|
|
|
189
|
-
|
|
238
|
+
test('should create new release for unreleased tag', async t => {
|
|
239
|
+
const options = {
|
|
240
|
+
increment: false,
|
|
241
|
+
git,
|
|
242
|
+
github: {
|
|
243
|
+
update: true,
|
|
244
|
+
pushRepo,
|
|
245
|
+
tokenRef,
|
|
246
|
+
release: true,
|
|
247
|
+
releaseName: 'Release ${tagName}',
|
|
248
|
+
releaseNotes: 'echo Custom notes'
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const github = factory(GitHub, { options });
|
|
252
|
+
|
|
253
|
+
const original = github.shell.exec.bind(github.shell);
|
|
254
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
255
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
256
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
257
|
+
if (args[0] === 'git rev-list 2.0.1 --tags --max-count=1') return Promise.resolve('b123456');
|
|
258
|
+
if (args[0] === 'git describe --tags --abbrev=0 "b123456^"') return Promise.resolve('2.0.1');
|
|
259
|
+
return original(...args);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
interceptAuthentication(api);
|
|
263
|
+
interceptCollaborator(api);
|
|
264
|
+
interceptListReleases(api, { tag_name: '2.0.0' });
|
|
265
|
+
interceptCreate(api, { body: { tag_name: '2.0.1', name: 'Release 2.0.1', body: 'Custom notes' } });
|
|
266
|
+
|
|
267
|
+
await runTasks(github);
|
|
268
|
+
|
|
269
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
270
|
+
assert(isReleased);
|
|
271
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.1');
|
|
272
|
+
});
|
|
190
273
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
274
|
+
test('should release to enterprise host', async t => {
|
|
275
|
+
const options = { git, github: { tokenRef, pushRepo: 'git://github.example.org/user/repo' } };
|
|
276
|
+
const github = factory(GitHub, { options });
|
|
277
|
+
|
|
278
|
+
const original = github.shell.exec.bind(github.shell);
|
|
279
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
280
|
+
if (args[0] === 'git remote get-url origin') return Promise.resolve(`https://github.example.org/user/repo`);
|
|
281
|
+
if (args[0] === 'git config --get remote.origin.url')
|
|
282
|
+
return Promise.resolve('https://github.example.org/user/repo');
|
|
283
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('1.0.0');
|
|
284
|
+
return original(...args);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
interceptAuthentication(example);
|
|
288
|
+
interceptCollaborator(example);
|
|
289
|
+
interceptCreate(example, {
|
|
290
|
+
api: 'https://github.example.org/api/v3',
|
|
291
|
+
host: 'github.example.org',
|
|
292
|
+
body: { tag_name: '1.0.1' }
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
await runTasks(github);
|
|
296
|
+
|
|
297
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
298
|
+
assert(isReleased);
|
|
299
|
+
assert.equal(releaseUrl, 'https://github.example.org/user/repo/releases/tag/1.0.1');
|
|
300
|
+
});
|
|
196
301
|
|
|
197
|
-
test('should
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const { isReleased, releaseUrl } = github.getContext();
|
|
225
|
-
t.true(isReleased);
|
|
226
|
-
t.is(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.1');
|
|
227
|
-
exec.restore();
|
|
228
|
-
});
|
|
302
|
+
test('should release to alternative host and proxy', async t => {
|
|
303
|
+
const options = {
|
|
304
|
+
git,
|
|
305
|
+
github: {
|
|
306
|
+
tokenRef,
|
|
307
|
+
pushRepo: `git://custom.example.org/user/repo`,
|
|
308
|
+
host: 'custom.example.org',
|
|
309
|
+
proxy: 'http://proxy:8080'
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
const github = factory(GitHub, { options });
|
|
313
|
+
|
|
314
|
+
const original = github.shell.exec.bind(github.shell);
|
|
315
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
316
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
317
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('1.0.0');
|
|
318
|
+
return original(...args);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
interceptAuthentication(custom);
|
|
322
|
+
interceptCollaborator(custom);
|
|
323
|
+
interceptCreate(custom, {
|
|
324
|
+
api: 'https://custom.example.org/api/v3',
|
|
325
|
+
host: 'custom.example.org',
|
|
326
|
+
body: { tag_name: '1.0.1' }
|
|
327
|
+
});
|
|
229
328
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
interceptCreate(Object.assign({ body: { tag_name: '1.0.1' } }, remote));
|
|
242
|
-
|
|
243
|
-
await runTasks(github);
|
|
244
|
-
|
|
245
|
-
const { isReleased, releaseUrl } = github.getContext();
|
|
246
|
-
t.true(isReleased);
|
|
247
|
-
t.is(releaseUrl, `https://github.example.org/user/repo/releases/tag/1.0.1`);
|
|
248
|
-
exec.restore();
|
|
249
|
-
});
|
|
329
|
+
await runTasks(github);
|
|
330
|
+
|
|
331
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
332
|
+
assert(isReleased);
|
|
333
|
+
assert.equal(releaseUrl, 'https://custom.example.org/user/repo/releases/tag/1.0.1');
|
|
334
|
+
assert.equal(github.options.proxy, 'http://proxy:8080');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test('should release to git.pushRepo', async t => {
|
|
338
|
+
const options = { git: { pushRepo: 'upstream', changelog: '' }, github: { tokenRef, skipChecks: true } };
|
|
339
|
+
const github = factory(GitHub, { options });
|
|
250
340
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
341
|
+
const original = github.shell.exec.bind(github.shell);
|
|
342
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
343
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
344
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('1.0.0');
|
|
345
|
+
if (args[0] === 'git remote get-url upstream') return Promise.resolve('https://custom.example.org/user/repo');
|
|
346
|
+
return original(...args);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
interceptCreate(custom, {
|
|
350
|
+
api: 'https://custom.example.org/api/v3',
|
|
261
351
|
host: 'custom.example.org',
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
const github = factory(GitHub, { options });
|
|
266
|
-
const exec = sinon.stub(github.shell, 'exec').callThrough();
|
|
267
|
-
exec.withArgs('git log --pretty=format:"* %s (%h)" ${from}...${to}').resolves('');
|
|
268
|
-
exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('1.0.0');
|
|
269
|
-
|
|
270
|
-
await runTasks(github);
|
|
271
|
-
|
|
272
|
-
const { isReleased, releaseUrl } = github.getContext();
|
|
273
|
-
t.true(isReleased);
|
|
274
|
-
t.is(releaseUrl, `https://custom.example.org/user/repo/releases/tag/1.0.1`);
|
|
275
|
-
t.is(github.options.proxy, 'http://proxy:8080');
|
|
276
|
-
exec.restore();
|
|
277
|
-
});
|
|
352
|
+
body: { tag_name: '1.0.1' }
|
|
353
|
+
});
|
|
278
354
|
|
|
279
|
-
|
|
280
|
-
const remote = { api: 'https://custom.example.org/api/v3', host: 'custom.example.org' };
|
|
281
|
-
interceptCreate(Object.assign({ body: { tag_name: '1.0.1' } }, remote));
|
|
282
|
-
const options = { git: { pushRepo: 'upstream', changelog: '' }, github: { tokenRef, skipChecks: true } };
|
|
283
|
-
const github = factory(GitHub, { options });
|
|
284
|
-
const exec = sinon.stub(github.shell, 'exec').callThrough();
|
|
285
|
-
exec.withArgs('git log --pretty=format:"* %s (%h)" ${from}...${to}').resolves('');
|
|
286
|
-
exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('1.0.0');
|
|
287
|
-
exec.withArgs('git remote get-url upstream').resolves('https://custom.example.org/user/repo');
|
|
288
|
-
|
|
289
|
-
await runTasks(github);
|
|
290
|
-
|
|
291
|
-
const { isReleased, releaseUrl } = github.getContext();
|
|
292
|
-
t.true(isReleased);
|
|
293
|
-
t.is(releaseUrl, 'https://custom.example.org/user/repo/releases/tag/1.0.1');
|
|
294
|
-
exec.restore();
|
|
295
|
-
});
|
|
355
|
+
await runTasks(github);
|
|
296
356
|
|
|
297
|
-
const
|
|
357
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
358
|
+
assert(isReleased);
|
|
359
|
+
assert.equal(releaseUrl, 'https://custom.example.org/user/repo/releases/tag/1.0.1');
|
|
360
|
+
});
|
|
298
361
|
|
|
299
|
-
testSkipOnActions
|
|
300
|
-
const options = { github: { tokenRef, pushRepo, host } };
|
|
301
|
-
const github = factory(GitHub, { options });
|
|
302
|
-
const stub = sinon.stub(github.client.users, 'getAuthenticated');
|
|
303
|
-
stub.throws(new RequestError('Bad credentials', 401, requestErrorOptions));
|
|
362
|
+
const testSkipOnActions = process.env.GITHUB_ACTIONS ? test.skip : test;
|
|
304
363
|
|
|
305
|
-
|
|
306
|
-
|
|
364
|
+
testSkipOnActions('should throw for unauthenticated user', async t => {
|
|
365
|
+
const options = { github: { tokenRef, pushRepo, host } };
|
|
366
|
+
const github = factory(GitHub, { options });
|
|
367
|
+
|
|
368
|
+
const getAuthenticated = t.mock.method(github.client.users, 'getAuthenticated', () => {
|
|
369
|
+
throw new RequestError('Bad credentials', 401, requestErrorOptions);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
await assert.rejects(runTasks(github), {
|
|
373
|
+
message: /Could not authenticate with GitHub using environment variable "GITHUB_TOKEN"/
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
assert.equal(getAuthenticated.mock.callCount(), 1);
|
|
307
377
|
});
|
|
308
378
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
});
|
|
379
|
+
testSkipOnActions('should throw for non-collaborator', async t => {
|
|
380
|
+
const options = { github: { tokenRef, pushRepo, host } };
|
|
381
|
+
const github = factory(GitHub, { options });
|
|
312
382
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const github = factory(GitHub, { options });
|
|
317
|
-
const stub = sinon.stub(github.client.repos, 'checkCollaborator');
|
|
318
|
-
stub.throws(new RequestError('HttpError', 401, requestErrorOptions));
|
|
383
|
+
t.mock.method(github.client.repos, 'checkCollaborator', () => {
|
|
384
|
+
throw new RequestError('HttpError', 401, requestErrorOptions);
|
|
385
|
+
});
|
|
319
386
|
|
|
320
|
-
|
|
387
|
+
interceptAuthentication(api, { username: 'john' });
|
|
321
388
|
|
|
322
|
-
|
|
323
|
-
});
|
|
389
|
+
await assert.rejects(runTasks(github), /User john is not a collaborator for user\/repo/);
|
|
390
|
+
});
|
|
324
391
|
|
|
325
|
-
test
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
392
|
+
test('should skip authentication and collaborator checks when running on GitHub Actions', async t => {
|
|
393
|
+
const { GITHUB_ACTIONS, GITHUB_ACTOR } = process.env;
|
|
394
|
+
if (!GITHUB_ACTIONS) {
|
|
395
|
+
process.env.GITHUB_ACTIONS = 1;
|
|
396
|
+
process.env.GITHUB_ACTOR = 'webpro';
|
|
397
|
+
}
|
|
331
398
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
399
|
+
const options = { github: { tokenRef } };
|
|
400
|
+
const github = factory(GitHub, { options });
|
|
401
|
+
const authStub = t.mock.method(github, 'isAuthenticated');
|
|
402
|
+
const collaboratorStub = t.mock.method(github, 'isCollaborator');
|
|
336
403
|
|
|
337
|
-
|
|
404
|
+
await assert.doesNotReject(github.init());
|
|
338
405
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
406
|
+
assert.equal(authStub.mock.callCount(), 0);
|
|
407
|
+
assert.equal(collaboratorStub.mock.callCount(), 0);
|
|
408
|
+
assert.equal(github.getContext('username'), process.env.GITHUB_ACTOR);
|
|
342
409
|
|
|
343
|
-
|
|
344
|
-
|
|
410
|
+
if (!GITHUB_ACTIONS) {
|
|
411
|
+
process.env.GITHUB_ACTIONS = GITHUB_ACTIONS || '';
|
|
412
|
+
process.env.GITHUB_ACTOR = GITHUB_ACTOR || '';
|
|
413
|
+
}
|
|
414
|
+
});
|
|
345
415
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
});
|
|
416
|
+
test('should handle octokit client error (without retries)', async t => {
|
|
417
|
+
const github = factory(GitHub, { options: { github: { tokenRef, pushRepo, host } } });
|
|
418
|
+
const createRelease = t.mock.method(github.client.repos, 'createRelease', () => {
|
|
419
|
+
throw new RequestError('Not found', 404, requestErrorOptions);
|
|
420
|
+
});
|
|
351
421
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const stub = sinon.stub(github.client.repos, 'createRelease');
|
|
355
|
-
stub.throws(new RequestError('Not found', 404, requestErrorOptions));
|
|
356
|
-
interceptAuthentication();
|
|
357
|
-
interceptCollaborator();
|
|
422
|
+
interceptAuthentication(api);
|
|
423
|
+
interceptCollaborator(api);
|
|
358
424
|
|
|
359
|
-
|
|
425
|
+
await assert.rejects(runTasks(github), /404 \(Not found\)/);
|
|
360
426
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
});
|
|
427
|
+
assert.equal(createRelease.mock.callCount(), 1);
|
|
428
|
+
});
|
|
364
429
|
|
|
365
|
-
test('should handle octokit client error (with retries)', async t => {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const stub = sinon.stub(github.client.repos, 'createRelease');
|
|
369
|
-
stub.throws(new RequestError('Request failed', 500, requestErrorOptions));
|
|
370
|
-
interceptAuthentication();
|
|
371
|
-
interceptCollaborator();
|
|
430
|
+
test('should handle octokit client error (with retries)', async t => {
|
|
431
|
+
const options = { github: { tokenRef, pushRepo, host, retryMinTimeout: 0 } };
|
|
432
|
+
const github = factory(GitHub, { options });
|
|
372
433
|
|
|
373
|
-
|
|
434
|
+
const createRelease = t.mock.method(github.client.repos, 'createRelease', () => {
|
|
435
|
+
throw new RequestError('Request failed', 500, requestErrorOptions);
|
|
436
|
+
});
|
|
374
437
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
});
|
|
438
|
+
interceptAuthentication(api);
|
|
439
|
+
interceptCollaborator(api);
|
|
378
440
|
|
|
379
|
-
|
|
380
|
-
const options = { 'dry-run': true, git, github: { tokenRef, pushRepo, releaseName: 'R ${version}', assets: ['*'] } };
|
|
381
|
-
const github = factory(GitHub, { options });
|
|
382
|
-
const spy = sinon.spy(github, 'client', ['get']);
|
|
383
|
-
const exec = sinon.stub(github.shell, 'exec').callThrough();
|
|
384
|
-
exec.withArgs('git log --pretty=format:"* %s (%h)" ${from}...${to}').resolves('');
|
|
385
|
-
exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('v1.0.0');
|
|
386
|
-
|
|
387
|
-
await runTasks(github);
|
|
388
|
-
|
|
389
|
-
t.is(spy.get.callCount, 0);
|
|
390
|
-
t.is(github.log.exec.args[1][0], 'octokit repos.createRelease "R 1.0.1" (v1.0.1)');
|
|
391
|
-
t.is(github.log.exec.lastCall.args[0], 'octokit repos.uploadReleaseAssets');
|
|
392
|
-
const { isReleased, releaseUrl } = github.getContext();
|
|
393
|
-
t.true(isReleased);
|
|
394
|
-
t.is(releaseUrl, 'https://github.com/user/repo/releases/tag/v1.0.1');
|
|
395
|
-
spy.get.restore();
|
|
396
|
-
exec.restore();
|
|
397
|
-
});
|
|
441
|
+
await assert.rejects(runTasks(github), /500 \(Request failed\)/);
|
|
398
442
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const github = factory(GitHub, { options });
|
|
402
|
-
await t.notThrowsAsync(github.init());
|
|
403
|
-
});
|
|
443
|
+
assert.equal(createRelease.mock.callCount(), 3);
|
|
444
|
+
});
|
|
404
445
|
|
|
405
|
-
test('should
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
});
|
|
446
|
+
test('should not call octokit client in dry run', async t => {
|
|
447
|
+
const options = {
|
|
448
|
+
'dry-run': true,
|
|
449
|
+
git,
|
|
450
|
+
github: { tokenRef, pushRepo, releaseName: 'R ${version}', assets: ['*'] }
|
|
451
|
+
};
|
|
452
|
+
const github = factory(GitHub, { options });
|
|
453
|
+
|
|
454
|
+
const get = t.mock.getter(github, 'client');
|
|
455
|
+
const original = github.shell.exec.bind(github.shell);
|
|
456
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
457
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
458
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('v1.0.0');
|
|
459
|
+
return original(...args);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
await runTasks(github);
|
|
463
|
+
|
|
464
|
+
assert.equal(get.mock.callCount(), 0);
|
|
465
|
+
assert.equal(github.log.exec.mock.calls[1].arguments[0], 'octokit repos.createRelease "R 1.0.1" (v1.0.1)');
|
|
466
|
+
assert.equal(github.log.exec.mock.calls.at(-1).arguments[0], 'octokit repos.uploadReleaseAssets');
|
|
467
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
468
|
+
assert(isReleased);
|
|
469
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/v1.0.1');
|
|
470
|
+
});
|
|
430
471
|
|
|
431
|
-
test('should generate GitHub web release url
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
472
|
+
test('should generate GitHub web release url', async t => {
|
|
473
|
+
const options = {
|
|
474
|
+
github: {
|
|
475
|
+
pushRepo,
|
|
476
|
+
release: true,
|
|
477
|
+
web: true,
|
|
478
|
+
releaseName: 'Release ${tagName}',
|
|
479
|
+
releaseNotes: 'echo Custom notes'
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
const github = factory(GitHub, { options });
|
|
483
|
+
|
|
484
|
+
const original = github.shell.exec.bind(github.shell);
|
|
485
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
486
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
487
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
488
|
+
return original(...args);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
await runTasks(github);
|
|
492
|
+
|
|
493
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
494
|
+
assert(isReleased);
|
|
495
|
+
assert.equal(
|
|
496
|
+
releaseUrl,
|
|
497
|
+
'https://github.com/user/repo/releases/new?tag=2.0.2&title=Release+2.0.2&body=Custom+notes&prerelease=false'
|
|
498
|
+
);
|
|
499
|
+
});
|
|
458
500
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
});
|
|
501
|
+
test('should generate GitHub web release url for enterprise host', async t => {
|
|
502
|
+
const options = {
|
|
503
|
+
git,
|
|
504
|
+
github: {
|
|
505
|
+
pushRepo: 'git@custom.example.org:user/repo',
|
|
506
|
+
release: true,
|
|
507
|
+
web: true,
|
|
508
|
+
host: 'custom.example.org',
|
|
509
|
+
releaseName: 'The Launch',
|
|
510
|
+
releaseNotes: 'echo It happened'
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
const github = factory(GitHub, { options });
|
|
514
|
+
|
|
515
|
+
const original = github.shell.exec.bind(github.shell);
|
|
516
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
517
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
518
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
519
|
+
return original(...args);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
await runTasks(github);
|
|
523
|
+
|
|
524
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
525
|
+
assert(isReleased);
|
|
526
|
+
assert.equal(
|
|
527
|
+
releaseUrl,
|
|
528
|
+
'https://custom.example.org/user/repo/releases/new?tag=2.0.2&title=The+Launch&body=It+happened&prerelease=false'
|
|
529
|
+
);
|
|
530
|
+
});
|
|
489
531
|
|
|
490
|
-
test('should
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
const longResult = getSearchQueries(base, manyCommits, separator);
|
|
505
|
-
t.true(longResult.length > 1, 'Many commits should be split into multiple queries');
|
|
506
|
-
t.true(
|
|
507
|
-
longResult.every(query => encodeURIComponent(query).length <= 256),
|
|
508
|
-
'Each query should not exceed 256 characters after encoding'
|
|
509
|
-
);
|
|
510
|
-
});
|
|
532
|
+
test.skip('should truncate long body', async t => {
|
|
533
|
+
const releaseNotes = 'a'.repeat(125001);
|
|
534
|
+
const body = 'a'.repeat(124000) + '...';
|
|
535
|
+
const options = {
|
|
536
|
+
git,
|
|
537
|
+
github: {
|
|
538
|
+
pushRepo,
|
|
539
|
+
tokenRef,
|
|
540
|
+
release: true,
|
|
541
|
+
releaseName: 'Release ${tagName}',
|
|
542
|
+
releaseNotes: 'echo ' + releaseNotes
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
const github = factory(GitHub, { options });
|
|
511
546
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
547
|
+
const original = github.shell.exec.bind(github.shell);
|
|
548
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
549
|
+
if (args[0] === 'git log --pretty=format:"* %s (%h)" ${from}...${to}') return Promise.resolve('');
|
|
550
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
551
|
+
return original(...args);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
interceptAuthentication(api);
|
|
555
|
+
interceptCollaborator(api);
|
|
556
|
+
interceptCreate(api, { body: { tag_name: '2.0.2', name: 'Release 2.0.2', body } });
|
|
557
|
+
|
|
558
|
+
await runTasks(github);
|
|
559
|
+
|
|
560
|
+
const { isReleased, releaseUrl } = github.getContext();
|
|
561
|
+
assert(isReleased);
|
|
562
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test('should generate search queries correctly', () => {
|
|
566
|
+
const generateCommit = () => Math.random().toString(36).substring(2, 9);
|
|
567
|
+
const base = 'repo:owner/repo+type:pr+is:merged';
|
|
568
|
+
const commits = Array.from({ length: 5 }, generateCommit);
|
|
569
|
+
const separator = '+';
|
|
570
|
+
|
|
571
|
+
const result = getSearchQueries(base, commits, separator);
|
|
572
|
+
|
|
573
|
+
// Test case 1: Check if all commits are included in the search queries
|
|
574
|
+
const allCommitsIncluded = commits.every(commit => result.some(query => query.includes(commit)));
|
|
575
|
+
assert(allCommitsIncluded, 'All commits should be included in the search queries');
|
|
576
|
+
|
|
577
|
+
assert.equal(
|
|
578
|
+
commits.every(commit => result.some(query => query.includes(commit))),
|
|
579
|
+
true
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
// Test case 2: Check if the function respects the 256 character limit
|
|
583
|
+
const manyCommits = Array.from({ length: 100 }, generateCommit);
|
|
584
|
+
const longResult = getSearchQueries(base, manyCommits, separator);
|
|
585
|
+
assert(longResult.length > 1, 'Many commits should be split into multiple queries');
|
|
586
|
+
assert(
|
|
587
|
+
longResult.every(query => encodeURIComponent(query).length <= 256),
|
|
588
|
+
'Each query should not exceed 256 characters after encoding'
|
|
589
|
+
);
|
|
538
590
|
});
|
|
539
591
|
|
|
540
|
-
|
|
592
|
+
test('should create auto-generated discussion', async t => {
|
|
593
|
+
const options = {
|
|
594
|
+
git,
|
|
595
|
+
github: {
|
|
596
|
+
pushRepo,
|
|
597
|
+
tokenRef,
|
|
598
|
+
release: true,
|
|
599
|
+
releaseName: 'Release ${tagName}',
|
|
600
|
+
autoGenerate: false,
|
|
601
|
+
discussionCategoryName: 'Announcement'
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
const github = factory(GitHub, { options });
|
|
605
|
+
const original = github.shell.exec.bind(github.shell);
|
|
606
|
+
t.mock.method(github.shell, 'exec', (...args) => {
|
|
607
|
+
if (args[0] === 'git describe --tags --match=* --abbrev=0') return Promise.resolve('2.0.1');
|
|
608
|
+
return original(...args);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
interceptAuthentication(api);
|
|
612
|
+
interceptCollaborator(api);
|
|
613
|
+
interceptCreate(api, {
|
|
614
|
+
body: {
|
|
615
|
+
tag_name: '2.0.2',
|
|
616
|
+
name: 'Release 2.0.2',
|
|
617
|
+
generate_release_notes: false,
|
|
618
|
+
body: null,
|
|
619
|
+
discussion_category_name: 'Announcement'
|
|
620
|
+
}
|
|
621
|
+
});
|
|
541
622
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
623
|
+
await runTasks(github);
|
|
624
|
+
|
|
625
|
+
const { isReleased, releaseUrl, discussionUrl } = github.getContext();
|
|
626
|
+
assert(isReleased);
|
|
627
|
+
assert.equal(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
628
|
+
assert.equal(discussionUrl, 'https://github.com/user/repo/discussions/1');
|
|
629
|
+
});
|
|
547
630
|
});
|