release-it 18.0.0-next.4 → 18.1.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/README.md CHANGED
@@ -44,7 +44,7 @@ npm install -D release-it
44
44
  "release": "release-it"
45
45
  },
46
46
  "devDependencies": {
47
- "release-it": "^16.1.0"
47
+ "release-it": "^18.0.0"
48
48
  }
49
49
  }
50
50
  ```
@@ -99,7 +99,7 @@ Here's a quick example `.release-it.json`:
99
99
 
100
100
  ```json
101
101
  {
102
- "$schema": "https://unpkg.com/release-it@17/schema/release-it.json",
102
+ "$schema": "https://unpkg.com/release-it@18/schema/release-it.json",
103
103
  "git": {
104
104
  "commitMessage": "chore: release v${version}"
105
105
  },
@@ -344,10 +344,18 @@ release-it programmatically][54] for example code.
344
344
  - [Repositories that depend on release-it][76]
345
345
  - GitHub search for [path:\*\*/.release-it.json][77]
346
346
 
347
- ## Legacy Node.js
347
+ ## Node.js version support
348
348
 
349
- The latest major version is v17, supporting Node.js 18 and up (as Node.js v16 is EOL). The previous major version was
350
- v16, supporting Node.js 16. Use release-it v15 for environments running Node.js v14. Also see [CHANGELOG.md][78].
349
+ The latest major version is v18, supporting Node.js 20 and up:
350
+
351
+ | release-it | Node.js |
352
+ | :--------: | :-----: |
353
+ | v18 | v20 |
354
+ | v17 | v18 |
355
+ | v16 | v16 |
356
+ | v15 | v14 |
357
+
358
+ Also see [CHANGELOG.md][78] for dates and details.
351
359
 
352
360
  ## Links
353
361
 
@@ -31,7 +31,8 @@ class GitRelease extends GitBase {
31
31
  async beforeRelease() {
32
32
  const { releaseNotes: script } = this.options;
33
33
  const { changelog } = this.config.getContext();
34
- const releaseNotes = script ? await this.processReleaseNotes(script) : changelog;
34
+ const releaseNotes =
35
+ typeof script === 'function' || typeof script === 'string' ? await this.processReleaseNotes(script) : changelog;
35
36
  this.setContext({ releaseNotes });
36
37
  if (releaseNotes !== changelog) {
37
38
  this.log.preview({ title: 'release notes', text: releaseNotes });
@@ -42,7 +43,9 @@ class GitRelease extends GitBase {
42
43
  if (typeof script === 'function') {
43
44
  const ctx = Object.assign({}, this.config.getContext(), { [this.namespace]: this.getContext() });
44
45
  return script(ctx);
45
- } else {
46
+ }
47
+
48
+ if (typeof script === 'string') {
46
49
  return this.exec(script);
47
50
  }
48
51
  }
@@ -211,7 +211,7 @@ class GitHub extends Release {
211
211
  }
212
212
  }
213
213
 
214
- getOctokitReleaseOptions(options = {}) {
214
+ async getOctokitReleaseOptions(options = {}) {
215
215
  const { owner, project: repo } = this.getContext('repo');
216
216
  const {
217
217
  releaseName,
@@ -225,7 +225,12 @@ class GitHub extends Release {
225
225
  const { version, releaseNotes, isUpdate } = this.getContext();
226
226
  const { isPreRelease } = parseVersion(version);
227
227
  const name = format(releaseName, this.config.getContext());
228
- const body = autoGenerate ? (isUpdate ? null : '') : truncateBody(releaseNotes);
228
+ const releaseNotesObject = this.options.releaseNotes;
229
+ const body = autoGenerate
230
+ ? isUpdate
231
+ ? null
232
+ : ''
233
+ : truncateBody(releaseNotesObject?.commit ? await this.renderReleaseNotes(releaseNotesObject) : releaseNotes);
229
234
 
230
235
  /**
231
236
  * @type {CreateReleaseOptions}
@@ -254,7 +259,7 @@ class GitHub extends Release {
254
259
  }
255
260
 
256
261
  async createRelease() {
257
- const options = this.getOctokitReleaseOptions();
262
+ const options = await this.getOctokitReleaseOptions();
258
263
  const { isDryRun } = this.config;
259
264
 
260
265
  this.log.exec(`octokit repos.createRelease "${options.name}" (${options.tag_name})`, { isDryRun });
@@ -350,11 +355,11 @@ class GitHub extends Release {
350
355
  return `https://${host}/${repository}/releases/tag/${tagName}`;
351
356
  }
352
357
 
353
- generateWebUrl() {
358
+ async generateWebUrl() {
354
359
  const host = this.options.host || this.getContext('repo.host');
355
360
  const isGitHub = host === 'github.com';
356
361
 
357
- const options = this.getOctokitReleaseOptions();
362
+ const options = await this.getOctokitReleaseOptions();
358
363
  const url = newGithubReleaseUrl({
359
364
  user: options.owner,
360
365
  repo: options.repo,
@@ -369,7 +374,7 @@ class GitHub extends Release {
369
374
  async createWebRelease() {
370
375
  const { isCI } = this.config;
371
376
  const { tagName } = this.config.getContext();
372
- const url = this.generateWebUrl();
377
+ const url = await this.generateWebUrl();
373
378
  if (isCI) {
374
379
  this.setContext({ isReleased: true, releaseUrl: url });
375
380
  } else {
@@ -380,10 +385,10 @@ class GitHub extends Release {
380
385
  }
381
386
  }
382
387
 
383
- updateRelease() {
388
+ async updateRelease() {
384
389
  const { isDryRun } = this.config;
385
390
  const release_id = this.getContext('releaseId');
386
- const options = this.getOctokitReleaseOptions({ release_id });
391
+ const options = await this.getOctokitReleaseOptions({ release_id });
387
392
 
388
393
  this.log.exec(`octokit repos.updateRelease (${options.tag_name})`, { isDryRun });
389
394
 
@@ -438,6 +443,30 @@ class GitHub extends Release {
438
443
  }
439
444
  }
440
445
  }
446
+
447
+ async getCommits() {
448
+ const { owner, project: repo } = this.getContext('repo');
449
+ const { latestTag } = this.config.getContext();
450
+ this.debug({ owner, repo, base: latestTag, head: 'HEAD' });
451
+ const { data } = await this.client.repos.compareCommits({ owner, repo, base: latestTag, head: 'HEAD' });
452
+ return data.commits;
453
+ }
454
+
455
+ async renderReleaseNotes(releaseNotes) {
456
+ const { commit: template, excludeMatches = [] } = releaseNotes;
457
+ const commits = await this.getCommits();
458
+
459
+ return commits
460
+ .map(commit => {
461
+ commit.commit.subject = commit.commit.message.split('\n')[0];
462
+ const partial = template.replace(/(?<!\$)\{((?:[^{}]|\${[^}]+})+)\}/g, (_, block) => {
463
+ const rendered = format(block, commit);
464
+ return excludeMatches.some(match => rendered.includes(match)) ? '' : rendered;
465
+ });
466
+ return format(partial, commit);
467
+ })
468
+ .join('\n');
469
+ }
441
470
  }
442
471
 
443
472
  export default GitHub;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-it",
3
- "version": "18.0.0-next.4",
3
+ "version": "18.1.0",
4
4
  "description": "Generic CLI tool to automate versioning and package publishing-related tasks.",
5
5
  "keywords": [
6
6
  "build",
@@ -69,7 +69,7 @@
69
69
  "lint": "eslint lib test",
70
70
  "format": "prettier --write eslint.config.mjs \"{lib,test}/**/*.js\"",
71
71
  "docs": "remark README.md 'docs/**/*.md' '.github/*.md' -o",
72
- "test": "ava --no-worker-threads && installed-check",
72
+ "test": "ava --no-worker-threads && installed-check --ignore ava",
73
73
  "release": "./bin/release-it.js"
74
74
  },
75
75
  "author": {
@@ -108,8 +108,8 @@
108
108
  "@eslint/compat": "1.2.4",
109
109
  "@eslint/eslintrc": "3.2.0",
110
110
  "@eslint/js": "9.17.0",
111
- "@octokit/request-error": "6.1.5",
112
- "@types/node": "20.16.10",
111
+ "@octokit/request-error": "6.1.6",
112
+ "@types/node": "20.17.11",
113
113
  "ava": "6.2.0",
114
114
  "eslint": "9.17.0",
115
115
  "eslint-config-prettier": "9.1.0",
@@ -120,7 +120,7 @@
120
120
  "globals": "15.14.0",
121
121
  "installed-check": "9.3.0",
122
122
  "knip": "5.41.1",
123
- "memfs": "4.15.1",
123
+ "memfs": "4.15.3",
124
124
  "mock-stdio": "1.0.3",
125
125
  "nock": "14.0.0-beta.8",
126
126
  "prettier": "3.4.2",
@@ -135,7 +135,7 @@
135
135
  "socks": "2.8.3"
136
136
  },
137
137
  "engines": {
138
- "node": "^20.9.0 || ^22.0.0"
138
+ "node": "^20.9.0 || >=22.0.0"
139
139
  },
140
140
  "remarkConfig": {
141
141
  "plugins": [
@@ -14,6 +14,24 @@
14
14
  "default": "Release ${version}"
15
15
  },
16
16
  "releaseNotes": {
17
+ "anyOf": [
18
+ { "type": ["string", "null"] },
19
+ {
20
+ "type": "object",
21
+ "properties": {
22
+ "commit": {
23
+ "type": "string"
24
+ },
25
+ "excludeMatches": {
26
+ "type": "array",
27
+ "items": {
28
+ "type": "string"
29
+ },
30
+ "default": []
31
+ }
32
+ }
33
+ }
34
+ ],
17
35
  "default": null
18
36
  },
19
37
  "autoGenerate": {
package/types/config.d.ts CHANGED
@@ -106,7 +106,7 @@ export interface Config {
106
106
  releaseName?: string;
107
107
 
108
108
  /** @default null */
109
- releaseNotes?: any;
109
+ releaseNotes?: string | null | (() => string | Promise<string>) | { commit?: string; excludeMatches?: string[] };
110
110
 
111
111
  /** @default false */
112
112
  autoGenerate?: boolean;