release-it 17.6.0 → 17.8.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/config/release-it.json +1 -0
- package/lib/config.js +1 -1
- package/lib/plugin/GitRelease.js +4 -1
- package/lib/plugin/github/GitHub.js +37 -10
- package/lib/plugin/github/util.js +4 -2
- package/lib/plugin/gitlab/GitLab.js +26 -22
- package/package.json +18 -20
- package/schema/git.json +5 -1
- package/schema/github.json +8 -0
- package/schema/gitlab.json +5 -1
- package/test/config.js +1 -1
- package/test/github.js +60 -0
- package/test/gitlab.js +26 -6
- package/test/stub/github.js +35 -5
- package/test/stub/gitlab.js +1 -0
- package/types/config.d.ts +14 -1
package/config/release-it.json
CHANGED
package/lib/config.js
CHANGED
|
@@ -2,7 +2,7 @@ import util from 'node:util';
|
|
|
2
2
|
import { cosmiconfigSync } from 'cosmiconfig';
|
|
3
3
|
import parseToml from '@iarna/toml/parse-string.js';
|
|
4
4
|
import _ from 'lodash';
|
|
5
|
-
import isCI from '
|
|
5
|
+
import { isCI } from 'ci-info';
|
|
6
6
|
import { readJSON, getSystemInfo } from './util.js';
|
|
7
7
|
|
|
8
8
|
const debug = util.debug('release-it:config');
|
package/lib/plugin/GitRelease.js
CHANGED
|
@@ -48,10 +48,13 @@ class GitRelease extends GitBase {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
afterRelease() {
|
|
51
|
-
const { isReleased, releaseUrl } = this.getContext();
|
|
51
|
+
const { isReleased, releaseUrl, discussionUrl } = this.getContext();
|
|
52
52
|
if (isReleased) {
|
|
53
53
|
this.log.log(`🔗 ${releaseUrl}`);
|
|
54
54
|
}
|
|
55
|
+
if (discussionUrl) {
|
|
56
|
+
this.log.log(`🔗 ${discussionUrl}`);
|
|
57
|
+
}
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
|
|
@@ -2,7 +2,6 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import open from 'open';
|
|
4
4
|
import { Octokit } from '@octokit/rest';
|
|
5
|
-
import fetch from 'node-fetch';
|
|
6
5
|
import { globby } from 'globby';
|
|
7
6
|
import mime from 'mime-types';
|
|
8
7
|
import _ from 'lodash';
|
|
@@ -14,6 +13,10 @@ import Release from '../GitRelease.js';
|
|
|
14
13
|
import prompts from './prompts.js';
|
|
15
14
|
import { getCommitsFromChangelog, getResolvedIssuesFromChangelog, searchQueries } from './util.js';
|
|
16
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {import('@octokit/rest').RestEndpointMethodTypes['repos']['createRelease']['parameters']} CreateReleaseOptions
|
|
18
|
+
*/
|
|
19
|
+
|
|
17
20
|
const pkg = readJSON(new URL('../../../package.json', import.meta.url));
|
|
18
21
|
|
|
19
22
|
const docs = 'https://git.io/release-it-github';
|
|
@@ -177,8 +180,7 @@ class GitHub extends Release {
|
|
|
177
180
|
userAgent: `release-it/${pkg.version}`,
|
|
178
181
|
log: this.config.isDebug ? console : null,
|
|
179
182
|
request: {
|
|
180
|
-
timeout
|
|
181
|
-
fetch
|
|
183
|
+
timeout
|
|
182
184
|
}
|
|
183
185
|
};
|
|
184
186
|
|
|
@@ -207,23 +209,36 @@ class GitHub extends Release {
|
|
|
207
209
|
|
|
208
210
|
getOctokitReleaseOptions(options = {}) {
|
|
209
211
|
const { owner, project: repo } = this.getContext('repo');
|
|
210
|
-
const {
|
|
212
|
+
const {
|
|
213
|
+
releaseName,
|
|
214
|
+
draft = false,
|
|
215
|
+
preRelease = false,
|
|
216
|
+
autoGenerate = false,
|
|
217
|
+
makeLatest = true,
|
|
218
|
+
discussionCategoryName = false
|
|
219
|
+
} = this.options;
|
|
211
220
|
const { tagName } = this.config.getContext();
|
|
212
221
|
const { version, releaseNotes, isUpdate } = this.getContext();
|
|
213
222
|
const { isPreRelease } = parseVersion(version);
|
|
214
223
|
const name = format(releaseName, this.config.getContext());
|
|
215
224
|
const body = autoGenerate ? (isUpdate ? null : '') : truncateBody(releaseNotes);
|
|
216
225
|
|
|
217
|
-
|
|
226
|
+
/**
|
|
227
|
+
* @type {CreateReleaseOptions}
|
|
228
|
+
*/
|
|
229
|
+
const contextOptions = {
|
|
218
230
|
owner,
|
|
231
|
+
make_latest: makeLatest.toString(),
|
|
219
232
|
repo,
|
|
220
233
|
tag_name: tagName,
|
|
221
234
|
name,
|
|
222
235
|
body,
|
|
223
236
|
draft,
|
|
224
237
|
prerelease: isPreRelease || preRelease,
|
|
225
|
-
generate_release_notes: autoGenerate
|
|
226
|
-
|
|
238
|
+
generate_release_notes: autoGenerate,
|
|
239
|
+
discussion_category_name: discussionCategoryName
|
|
240
|
+
};
|
|
241
|
+
return Object.assign(options, contextOptions);
|
|
227
242
|
}
|
|
228
243
|
|
|
229
244
|
retry(fn) {
|
|
@@ -250,9 +265,21 @@ class GitHub extends Release {
|
|
|
250
265
|
this.debug(options);
|
|
251
266
|
const response = await this.client.repos.createRelease(options);
|
|
252
267
|
this.debug(response.data);
|
|
253
|
-
const { html_url, upload_url, id } = response.data;
|
|
254
|
-
this.setContext({
|
|
255
|
-
|
|
268
|
+
const { html_url, upload_url, id, discussion_url } = response.data;
|
|
269
|
+
this.setContext({
|
|
270
|
+
isReleased: true,
|
|
271
|
+
releaseId: id,
|
|
272
|
+
releaseUrl: html_url,
|
|
273
|
+
upload_url,
|
|
274
|
+
discussionUrl: discussion_url
|
|
275
|
+
});
|
|
276
|
+
this.config.setContext({
|
|
277
|
+
isReleased: true,
|
|
278
|
+
releaseId: id,
|
|
279
|
+
releaseUrl: html_url,
|
|
280
|
+
upload_url,
|
|
281
|
+
discussionUrl: discussion_url
|
|
282
|
+
});
|
|
256
283
|
this.log.verbose(`octokit repos.createRelease: done (${response.headers.location})`);
|
|
257
284
|
return response.data;
|
|
258
285
|
} catch (err) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// Totally much borrowed from https://github.com/semantic-release/github/blob/master/lib/success.js
|
|
2
2
|
import issueParser from 'issue-parser';
|
|
3
3
|
|
|
4
|
-
const getSearchQueries = (base, commits, separator = '+') => {
|
|
4
|
+
export const getSearchQueries = (base, commits, separator = '+') => {
|
|
5
|
+
const encodedSeparator = encodeURIComponent(separator);
|
|
6
|
+
|
|
5
7
|
return commits.reduce((searches, commit) => {
|
|
6
8
|
const lastSearch = searches[searches.length - 1];
|
|
7
|
-
if (lastSearch && lastSearch.length + commit.length <= 256 -
|
|
9
|
+
if (lastSearch && encodeURIComponent(lastSearch).length + commit.length <= 256 - encodedSeparator.length) {
|
|
8
10
|
searches[searches.length - 1] = `${lastSearch}${separator}${commit}`;
|
|
9
11
|
} else {
|
|
10
12
|
searches.push(`${base}${separator}${commit}`);
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import got from 'got';
|
|
4
3
|
import { globby } from 'globby';
|
|
5
|
-
import { FormData, fileFromSync } from 'node-fetch';
|
|
6
4
|
import _ from 'lodash';
|
|
7
5
|
import Release from '../GitRelease.js';
|
|
8
6
|
import { format, e } from '../../util.js';
|
|
@@ -30,22 +28,6 @@ class GitLab extends Release {
|
|
|
30
28
|
this.certificateAuthorityOption = _.isEmpty(https) ? {} : { https };
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
get client() {
|
|
34
|
-
if (this._client) return this._client;
|
|
35
|
-
const { tokenHeader } = this.options;
|
|
36
|
-
const { baseUrl } = this.getContext();
|
|
37
|
-
this._client = got.extend({
|
|
38
|
-
prefixUrl: baseUrl,
|
|
39
|
-
method: 'POST',
|
|
40
|
-
headers: {
|
|
41
|
-
'user-agent': 'webpro/release-it',
|
|
42
|
-
[tokenHeader]: this.token
|
|
43
|
-
},
|
|
44
|
-
...this.certificateAuthorityOption
|
|
45
|
-
});
|
|
46
|
-
return this._client;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
31
|
async init() {
|
|
50
32
|
await super.init();
|
|
51
33
|
|
|
@@ -179,8 +161,28 @@ class GitLab extends Release {
|
|
|
179
161
|
const { baseUrl } = this.getContext();
|
|
180
162
|
this.debug(Object.assign({ url: `${baseUrl}/${endpoint}` }, options));
|
|
181
163
|
const method = (options.method || 'POST').toLowerCase();
|
|
182
|
-
const
|
|
183
|
-
const
|
|
164
|
+
const { tokenHeader } = this.options;
|
|
165
|
+
const url = `${baseUrl}/${endpoint}${options.searchParams ? `?${new URLSearchParams(options.searchParams)}` : ''}`;
|
|
166
|
+
const headers = {
|
|
167
|
+
'user-agent': 'webpro/release-it',
|
|
168
|
+
[tokenHeader]: this.token
|
|
169
|
+
};
|
|
170
|
+
const requestOptions = {
|
|
171
|
+
method,
|
|
172
|
+
headers,
|
|
173
|
+
...this.certificateAuthorityOption
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const response = await fetch(
|
|
177
|
+
url,
|
|
178
|
+
options.json || options.body
|
|
179
|
+
? {
|
|
180
|
+
...requestOptions,
|
|
181
|
+
body: options.json ? JSON.stringify(options.json) : options.body
|
|
182
|
+
}
|
|
183
|
+
: requestOptions
|
|
184
|
+
);
|
|
185
|
+
const body = await response.json();
|
|
184
186
|
this.debug(body);
|
|
185
187
|
return body;
|
|
186
188
|
}
|
|
@@ -235,11 +237,13 @@ class GitLab extends Release {
|
|
|
235
237
|
|
|
236
238
|
async uploadAsset(filePath) {
|
|
237
239
|
const name = path.basename(filePath);
|
|
240
|
+
const { useIdsForUrls } = this.options;
|
|
238
241
|
const { id, origin, repo } = this.getContext();
|
|
239
242
|
const endpoint = `projects/${id}/uploads`;
|
|
240
243
|
|
|
241
244
|
const body = new FormData();
|
|
242
|
-
|
|
245
|
+
const rawData = await fs.promises.readFile(filePath);
|
|
246
|
+
body.set('file', new Blob([rawData]), name);
|
|
243
247
|
const options = { body };
|
|
244
248
|
|
|
245
249
|
try {
|
|
@@ -247,7 +251,7 @@ class GitLab extends Release {
|
|
|
247
251
|
this.log.verbose(`gitlab releases#uploadAsset: done (${body.url})`);
|
|
248
252
|
this.assets.push({
|
|
249
253
|
name,
|
|
250
|
-
url: `${origin}/${repo.repository}${body.url}`
|
|
254
|
+
url: useIdsForUrls ? `${origin}${body.full_path}` : `${origin}/${repo.repository}${body.url}`
|
|
251
255
|
});
|
|
252
256
|
} catch (err) {
|
|
253
257
|
this.debug(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-it",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.8.0",
|
|
4
4
|
"description": "Generic CLI tool to automate versioning and package publishing-related tasks.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"build",
|
|
@@ -82,54 +82,52 @@
|
|
|
82
82
|
"@octokit/rest": "20.1.1",
|
|
83
83
|
"async-retry": "1.3.3",
|
|
84
84
|
"chalk": "5.3.0",
|
|
85
|
+
"ci-info": "^4.0.0",
|
|
85
86
|
"cosmiconfig": "9.0.0",
|
|
86
|
-
"execa": "8.0.
|
|
87
|
+
"execa": "8.0.0",
|
|
87
88
|
"git-url-parse": "14.0.0",
|
|
88
89
|
"globby": "14.0.2",
|
|
89
|
-
"got": "13.0.0",
|
|
90
90
|
"inquirer": "9.3.2",
|
|
91
|
-
"is-ci": "3.0.1",
|
|
92
91
|
"issue-parser": "7.0.1",
|
|
93
92
|
"lodash": "4.17.21",
|
|
94
93
|
"mime-types": "2.1.35",
|
|
95
94
|
"new-github-release-url": "2.0.0",
|
|
96
|
-
"node-fetch": "3.3.2",
|
|
97
95
|
"open": "10.1.0",
|
|
98
|
-
"ora": "8.0
|
|
96
|
+
"ora": "8.1.0",
|
|
99
97
|
"os-name": "5.1.0",
|
|
100
98
|
"proxy-agent": "6.4.0",
|
|
101
|
-
"semver": "7.6.
|
|
99
|
+
"semver": "7.6.3",
|
|
102
100
|
"shelljs": "0.8.5",
|
|
103
|
-
"update-notifier": "7.1
|
|
101
|
+
"update-notifier": "7.3.1",
|
|
104
102
|
"url-join": "5.0.0",
|
|
105
103
|
"wildcard-match": "5.1.3",
|
|
106
104
|
"yargs-parser": "21.1.1"
|
|
107
105
|
},
|
|
108
106
|
"devDependencies": {
|
|
109
|
-
"@eslint/compat": "1.
|
|
107
|
+
"@eslint/compat": "1.2.0",
|
|
110
108
|
"@eslint/eslintrc": "3.1.0",
|
|
111
|
-
"@eslint/js": "9.
|
|
109
|
+
"@eslint/js": "9.12.0",
|
|
112
110
|
"@octokit/request-error": "5.1.0",
|
|
113
111
|
"@types/node": "20.14.10",
|
|
114
112
|
"ava": "6.1.3",
|
|
115
|
-
"eslint": "9.
|
|
113
|
+
"eslint": "9.12.0",
|
|
116
114
|
"eslint-config-prettier": "9.1.0",
|
|
117
115
|
"eslint-plugin-ava": "15.0.1",
|
|
118
|
-
"eslint-plugin-import-x": "3.
|
|
119
|
-
"eslint-plugin-prettier": "5.1
|
|
116
|
+
"eslint-plugin-import-x": "4.3.1",
|
|
117
|
+
"eslint-plugin-prettier": "5.2.1",
|
|
120
118
|
"fs-monkey": "1.0.6",
|
|
121
|
-
"globals": "15.
|
|
119
|
+
"globals": "15.10.0",
|
|
122
120
|
"installed-check": "9.3.0",
|
|
123
|
-
"knip": "5.
|
|
124
|
-
"memfs": "4.
|
|
121
|
+
"knip": "5.31.0",
|
|
122
|
+
"memfs": "4.12.0",
|
|
125
123
|
"mock-stdio": "1.0.3",
|
|
126
|
-
"nock": "
|
|
124
|
+
"nock": "14.0.0-beta.8",
|
|
127
125
|
"prettier": "3.3.3",
|
|
128
126
|
"remark-cli": "12.0.1",
|
|
129
|
-
"remark-preset-webpro": "1.1.
|
|
130
|
-
"sinon": "
|
|
127
|
+
"remark-preset-webpro": "1.1.1",
|
|
128
|
+
"sinon": "19.0.2",
|
|
131
129
|
"strip-ansi": "7.1.0",
|
|
132
|
-
"typescript": "5.
|
|
130
|
+
"typescript": "5.6.2"
|
|
133
131
|
},
|
|
134
132
|
"overrides": {
|
|
135
133
|
"pac-resolver": "7.0.1",
|
package/schema/git.json
CHANGED
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
"default": true
|
|
15
15
|
},
|
|
16
16
|
"requireBranch": {
|
|
17
|
-
"
|
|
17
|
+
"oneOf": [
|
|
18
|
+
{ "type": "boolean", "enum": [false] },
|
|
19
|
+
{ "type": "string" },
|
|
20
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
21
|
+
],
|
|
18
22
|
"default": false
|
|
19
23
|
},
|
|
20
24
|
"requireUpstream": {
|
package/schema/github.json
CHANGED
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"type": "boolean",
|
|
21
21
|
"default": false
|
|
22
22
|
},
|
|
23
|
+
"makeLatest": {
|
|
24
|
+
"anyOf": [{ "type": "boolean" }, { "const": "legacy" }],
|
|
25
|
+
"default": true
|
|
26
|
+
},
|
|
23
27
|
"preRelease": {
|
|
24
28
|
"type": "boolean",
|
|
25
29
|
"default": false
|
|
@@ -28,6 +32,10 @@
|
|
|
28
32
|
"type": "boolean",
|
|
29
33
|
"default": false
|
|
30
34
|
},
|
|
35
|
+
"discussionCategoryName": {
|
|
36
|
+
"$comment": "Add discussion to the GitHub discussion for the Release",
|
|
37
|
+
"type": "string"
|
|
38
|
+
},
|
|
31
39
|
"tokenRef": {
|
|
32
40
|
"type": "string",
|
|
33
41
|
"default": "GITHUB_TOKEN"
|
package/schema/gitlab.json
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"type": "boolean",
|
|
29
29
|
"default": false
|
|
30
30
|
},
|
|
31
|
-
"
|
|
31
|
+
"milestones": {
|
|
32
32
|
"type": "array",
|
|
33
33
|
"items": {
|
|
34
34
|
"type": "string"
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
"assets": {
|
|
53
53
|
"default": null
|
|
54
54
|
},
|
|
55
|
+
"useIdsForUrls": {
|
|
56
|
+
"type": "boolean",
|
|
57
|
+
"default": false
|
|
58
|
+
},
|
|
55
59
|
"origin": {
|
|
56
60
|
"type": "string",
|
|
57
61
|
"default": null
|
package/test/config.js
CHANGED
package/test/github.js
CHANGED
|
@@ -2,6 +2,7 @@ import test from 'ava';
|
|
|
2
2
|
import sinon from 'sinon';
|
|
3
3
|
import { RequestError } from '@octokit/request-error';
|
|
4
4
|
import GitHub from '../lib/plugin/github/GitHub.js';
|
|
5
|
+
import { getSearchQueries } from '../lib/plugin/github/util.js';
|
|
5
6
|
import { factory, runTasks } from './util/index.js';
|
|
6
7
|
import {
|
|
7
8
|
interceptAuthentication,
|
|
@@ -485,3 +486,62 @@ test.skip('should truncate long body', async t => {
|
|
|
485
486
|
t.is(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
486
487
|
exec.restore();
|
|
487
488
|
});
|
|
489
|
+
|
|
490
|
+
test('should generate search queries correctly', t => {
|
|
491
|
+
const generateCommit = () => Math.random().toString(36).substring(2, 9);
|
|
492
|
+
const base = 'repo:owner/repo+type:pr+is:merged';
|
|
493
|
+
const commits = Array.from({ length: 5 }, generateCommit);
|
|
494
|
+
const separator = '+';
|
|
495
|
+
|
|
496
|
+
const result = getSearchQueries(base, commits, separator);
|
|
497
|
+
|
|
498
|
+
// Test case 1: Check if all commits are included in the search queries
|
|
499
|
+
const allCommitsIncluded = commits.every(commit => result.some(query => query.includes(commit)));
|
|
500
|
+
t.true(allCommitsIncluded, 'All commits should be included in the search queries');
|
|
501
|
+
|
|
502
|
+
// Test case 2: Check if the function respects the 256 character limit
|
|
503
|
+
const manyCommits = Array.from({ length: 100 }, generateCommit);
|
|
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
|
+
});
|
|
511
|
+
|
|
512
|
+
test('should create auto-generated discussion', async t => {
|
|
513
|
+
const options = {
|
|
514
|
+
git,
|
|
515
|
+
github: {
|
|
516
|
+
pushRepo,
|
|
517
|
+
tokenRef,
|
|
518
|
+
release: true,
|
|
519
|
+
releaseName: 'Release ${tagName}',
|
|
520
|
+
autoGenerate: false,
|
|
521
|
+
discussionCategoryName: 'Announcement'
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
const github = factory(GitHub, { options });
|
|
525
|
+
const exec = sinon.stub(github.shell, 'exec').callThrough();
|
|
526
|
+
exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('2.0.1');
|
|
527
|
+
|
|
528
|
+
interceptAuthentication();
|
|
529
|
+
interceptCollaborator();
|
|
530
|
+
interceptCreate({
|
|
531
|
+
body: {
|
|
532
|
+
tag_name: '2.0.2',
|
|
533
|
+
name: 'Release 2.0.2',
|
|
534
|
+
generate_release_notes: false,
|
|
535
|
+
body: null,
|
|
536
|
+
discussion_category_name: 'Announcement'
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
await runTasks(github);
|
|
541
|
+
|
|
542
|
+
const { isReleased, releaseUrl, discussionUrl } = github.getContext();
|
|
543
|
+
t.true(isReleased);
|
|
544
|
+
t.is(releaseUrl, 'https://github.com/user/repo/releases/tag/2.0.2');
|
|
545
|
+
t.is(discussionUrl, 'https://github.com/user/repo/discussions/1');
|
|
546
|
+
exec.restore();
|
|
547
|
+
});
|
package/test/gitlab.js
CHANGED
|
@@ -111,6 +111,31 @@ test.serial('should upload assets and release', async t => {
|
|
|
111
111
|
t.is(releaseUrl, `${pushRepo}/-/releases`);
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
+
test.serial('should upload assets with ID-based URLs too', async t => {
|
|
115
|
+
const host = 'https://gitlab.com';
|
|
116
|
+
const pushRepo = `${host}/user/repo`;
|
|
117
|
+
const options = {
|
|
118
|
+
git: { pushRepo },
|
|
119
|
+
gitlab: {
|
|
120
|
+
tokenRef,
|
|
121
|
+
release: true,
|
|
122
|
+
assets: 'test/resources/file-v${version}.txt',
|
|
123
|
+
useIdsForUrls: true
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const gitlab = factory(GitLab, { options });
|
|
127
|
+
sinon.stub(gitlab, 'getLatestVersion').resolves('2.0.0');
|
|
128
|
+
|
|
129
|
+
interceptUser();
|
|
130
|
+
interceptCollaborator();
|
|
131
|
+
interceptAsset();
|
|
132
|
+
interceptPublish();
|
|
133
|
+
|
|
134
|
+
await runTasks(gitlab);
|
|
135
|
+
|
|
136
|
+
t.is(gitlab.assets[0].url, `${host}/-/project/1234/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/file-v2.0.1.txt`);
|
|
137
|
+
});
|
|
138
|
+
|
|
114
139
|
test.serial('should throw when release milestone is missing', async t => {
|
|
115
140
|
const pushRepo = 'https://gitlab.com/user/repo';
|
|
116
141
|
const options = {
|
|
@@ -226,29 +251,24 @@ test('should not make requests in dry run', async t => {
|
|
|
226
251
|
const options = { 'dry-run': true, git: { pushRepo }, gitlab: { releaseName: 'R', tokenRef } };
|
|
227
252
|
const gitlab = factory(GitLab, { options });
|
|
228
253
|
sinon.stub(gitlab, 'getLatestVersion').resolves('1.0.0');
|
|
229
|
-
const spy = sinon.spy(gitlab, 'client', ['get']);
|
|
230
254
|
|
|
231
255
|
await runTasks(gitlab);
|
|
232
256
|
|
|
233
257
|
const { isReleased, releaseUrl } = gitlab.getContext();
|
|
234
|
-
|
|
258
|
+
|
|
235
259
|
t.is(gitlab.log.exec.args[2][0], 'gitlab releases#uploadAssets');
|
|
236
260
|
t.is(gitlab.log.exec.args[3][0], 'gitlab releases#createRelease "R" (1.0.1)');
|
|
237
261
|
t.true(isReleased);
|
|
238
262
|
t.is(releaseUrl, `${pushRepo}/-/releases`);
|
|
239
|
-
spy.get.restore();
|
|
240
263
|
});
|
|
241
264
|
|
|
242
265
|
test('should skip checks', async t => {
|
|
243
266
|
const options = { gitlab: { tokenRef, skipChecks: true, release: true, milestones: ['v1.0.0'] } };
|
|
244
267
|
const gitlab = factory(GitLab, { options });
|
|
245
|
-
const spy = sinon.spy(gitlab, 'client', ['get']);
|
|
246
268
|
|
|
247
269
|
await t.notThrowsAsync(gitlab.init());
|
|
248
270
|
await t.notThrowsAsync(gitlab.beforeRelease());
|
|
249
271
|
|
|
250
|
-
t.is(spy.get.callCount, 0);
|
|
251
|
-
|
|
252
272
|
t.is(gitlab.log.exec.args.filter(entry => /checkReleaseMilestones/.test(entry[0])).length, 0);
|
|
253
273
|
});
|
|
254
274
|
|
package/test/stub/github.js
CHANGED
|
@@ -44,7 +44,16 @@ const interceptCreate = ({
|
|
|
44
44
|
host = 'github.com',
|
|
45
45
|
owner = 'user',
|
|
46
46
|
project = 'repo',
|
|
47
|
-
body: {
|
|
47
|
+
body: {
|
|
48
|
+
tag_name,
|
|
49
|
+
name = '',
|
|
50
|
+
body = null,
|
|
51
|
+
prerelease = false,
|
|
52
|
+
draft = false,
|
|
53
|
+
generate_release_notes = false,
|
|
54
|
+
make_latest = 'true',
|
|
55
|
+
discussion_category_name = false
|
|
56
|
+
}
|
|
48
57
|
} = {}) => {
|
|
49
58
|
nock(api)
|
|
50
59
|
.post(`/repos/${owner}/${project}/releases`, {
|
|
@@ -53,7 +62,9 @@ const interceptCreate = ({
|
|
|
53
62
|
body,
|
|
54
63
|
prerelease,
|
|
55
64
|
draft,
|
|
56
|
-
generate_release_notes
|
|
65
|
+
generate_release_notes,
|
|
66
|
+
make_latest,
|
|
67
|
+
discussion_category_name
|
|
57
68
|
})
|
|
58
69
|
.reply(() => {
|
|
59
70
|
const id = 1;
|
|
@@ -66,7 +77,8 @@ const interceptCreate = ({
|
|
|
66
77
|
draft,
|
|
67
78
|
generate_release_notes,
|
|
68
79
|
upload_url: `https://uploads.${host}/repos/${owner}/${project}/releases/${id}/assets{?name,label}`,
|
|
69
|
-
html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}
|
|
80
|
+
html_url: `https://${host}/${owner}/${project}/releases/tag/${tag_name}`,
|
|
81
|
+
discussion_url: discussion_category_name ? `https://${host}/${owner}/${project}/discussions/${id}` : undefined
|
|
70
82
|
};
|
|
71
83
|
return [200, responseBody, { location: `${api}/repos/${owner}/${project}/releases/${id}` }];
|
|
72
84
|
});
|
|
@@ -77,10 +89,28 @@ const interceptUpdate = ({
|
|
|
77
89
|
api = 'https://api.github.com',
|
|
78
90
|
owner = 'user',
|
|
79
91
|
project = 'repo',
|
|
80
|
-
body: {
|
|
92
|
+
body: {
|
|
93
|
+
tag_name,
|
|
94
|
+
name = '',
|
|
95
|
+
body = null,
|
|
96
|
+
prerelease = false,
|
|
97
|
+
draft = false,
|
|
98
|
+
generate_release_notes = false,
|
|
99
|
+
make_latest = 'true',
|
|
100
|
+
discussion_category_name = false
|
|
101
|
+
}
|
|
81
102
|
} = {}) => {
|
|
82
103
|
nock(api)
|
|
83
|
-
.patch(`/repos/${owner}/${project}/releases/1`, {
|
|
104
|
+
.patch(`/repos/${owner}/${project}/releases/1`, {
|
|
105
|
+
tag_name,
|
|
106
|
+
name,
|
|
107
|
+
body,
|
|
108
|
+
draft,
|
|
109
|
+
prerelease,
|
|
110
|
+
generate_release_notes,
|
|
111
|
+
make_latest,
|
|
112
|
+
discussion_category_name
|
|
113
|
+
})
|
|
84
114
|
.reply(200, {
|
|
85
115
|
id: 1,
|
|
86
116
|
tag_name,
|
package/test/stub/gitlab.js
CHANGED
|
@@ -39,6 +39,7 @@ export let interceptAsset = ({ host = 'https://gitlab.com', owner = 'user', proj
|
|
|
39
39
|
return {
|
|
40
40
|
alt: name,
|
|
41
41
|
url: `/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name}`,
|
|
42
|
+
full_path: `/-/project/1234/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name}`,
|
|
42
43
|
markdown: `[${name}](/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${name})`
|
|
43
44
|
};
|
|
44
45
|
});
|
package/types/config.d.ts
CHANGED
|
@@ -132,6 +132,16 @@ export interface Config {
|
|
|
132
132
|
/** @default null */
|
|
133
133
|
proxy?: any;
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* @default true
|
|
137
|
+
* 'legacy' - Github determines the latest release based on the release creation date and higher semantic version.
|
|
138
|
+
* See https://docs.github.com/en/rest/releases/releases?apiVersion=latest#create-a-release
|
|
139
|
+
*/
|
|
140
|
+
makeLatest?: boolean | 'legacy';
|
|
141
|
+
|
|
142
|
+
/** @default false */
|
|
143
|
+
discussionCategoryName?: boolean | string;
|
|
144
|
+
|
|
135
145
|
/** @default false */
|
|
136
146
|
skipChecks?: boolean;
|
|
137
147
|
|
|
@@ -170,13 +180,16 @@ export interface Config {
|
|
|
170
180
|
|
|
171
181
|
/** @default null */
|
|
172
182
|
certificateAuthorityFile?: any;
|
|
173
|
-
|
|
183
|
+
|
|
174
184
|
/** @default null */
|
|
175
185
|
secure?: boolean;
|
|
176
186
|
|
|
177
187
|
/** @default null */
|
|
178
188
|
assets?: any;
|
|
179
189
|
|
|
190
|
+
/** @default false */
|
|
191
|
+
useIdsForUrls?: boolean;
|
|
192
|
+
|
|
180
193
|
/** @default null */
|
|
181
194
|
origin?: any;
|
|
182
195
|
|