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.
@@ -65,6 +65,7 @@
65
65
  "certificateAuthorityFile": null,
66
66
  "secure": null,
67
67
  "assets": null,
68
+ "useIdsForUrls": false,
68
69
  "origin": null,
69
70
  "skipChecks": false
70
71
  }
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 'is-ci';
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');
@@ -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 { releaseName, draft = false, preRelease = false, autoGenerate = false } = this.options;
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
- return Object.assign(options, {
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({ isReleased: true, releaseId: id, releaseUrl: html_url, upload_url });
255
- this.config.setContext({ isReleased: true, releaseId: id, releaseUrl: html_url, upload_url });
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 - separator.length) {
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 response = await this.client[method](endpoint, options);
183
- const body = typeof response.body === 'string' ? JSON.parse(response.body) : response.body || {};
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
- body.set('file', fileFromSync(filePath));
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.6.0",
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.1",
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.1",
96
+ "ora": "8.1.0",
99
97
  "os-name": "5.1.0",
100
98
  "proxy-agent": "6.4.0",
101
- "semver": "7.6.2",
99
+ "semver": "7.6.3",
102
100
  "shelljs": "0.8.5",
103
- "update-notifier": "7.1.0",
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.1.1",
107
+ "@eslint/compat": "1.2.0",
110
108
  "@eslint/eslintrc": "3.1.0",
111
- "@eslint/js": "9.7.0",
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.7.0",
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.0.1",
119
- "eslint-plugin-prettier": "5.1.3",
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.8.0",
119
+ "globals": "15.10.0",
122
120
  "installed-check": "9.3.0",
123
- "knip": "5.26.0",
124
- "memfs": "4.9.3",
121
+ "knip": "5.31.0",
122
+ "memfs": "4.12.0",
125
123
  "mock-stdio": "1.0.3",
126
- "nock": "13.5.4",
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.0",
130
- "sinon": "18.0.0",
127
+ "remark-preset-webpro": "1.1.1",
128
+ "sinon": "19.0.2",
131
129
  "strip-ansi": "7.1.0",
132
- "typescript": "5.5.3"
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
- "type": "boolean",
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": {
@@ -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"
@@ -28,7 +28,7 @@
28
28
  "type": "boolean",
29
29
  "default": false
30
30
  },
31
- "milesstones": {
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
@@ -1,5 +1,5 @@
1
1
  import test from 'ava';
2
- import isCI from 'is-ci';
2
+ import { isCI } from 'ci-info';
3
3
  import Config from '../lib/config.js';
4
4
  import { readJSON } from '../lib/util.js';
5
5
 
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
- t.is(spy.get.callCount, 0);
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
 
@@ -44,7 +44,16 @@ const interceptCreate = ({
44
44
  host = 'github.com',
45
45
  owner = 'user',
46
46
  project = 'repo',
47
- body: { tag_name, name = '', generate_release_notes = false, body = null, prerelease = false, draft = false }
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: { tag_name, name = '', body = null, prerelease = false, draft = false, generate_release_notes = false }
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`, { tag_name, name, body, draft, prerelease, generate_release_notes })
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,
@@ -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