@oorabona/release-it-preset 1.2.0 → 1.4.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
@@ -1,16 +1,49 @@
1
1
  # @oorabona/release-it-preset
2
2
 
3
- Shared [release-it](https://github.com/release-it/release-it) configuration and scripts for automated versioning, changelog generation, and package publishing.
3
+ Shareable [release-it](https://github.com/release-it/release-it) configuration and scripts for automated versioning, changelog generation, and package publishing — for solo and small-team JavaScript maintainers who want Keep a Changelog discipline without the ceremony of changesets or the hands-off philosophy of semantic-release.
4
4
 
5
5
  [![NPM Version](https://img.shields.io/npm/v/@oorabona/release-it-preset.svg)](https://npmjs.org/package/@oorabona/release-it-preset)
6
6
  [![NPM Downloads](https://img.shields.io/npm/dm/@oorabona/release-it-preset.svg)](https://npmjs.org/package/@oorabona/release-it-preset)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
  [![Node](https://img.shields.io/node/v/@oorabona/release-it-preset.svg)](https://nodejs.org/)
9
9
  [![OIDC trusted publishing](https://img.shields.io/badge/npm-OIDC%20trusted%20publishing-green.svg)](https://docs.npmjs.com/trusted-publishers)
10
+ [![SLSA Level 3](https://slsa.dev/images/gh-badge-level3.svg)](docs/VERIFY.md)
10
11
  [![CI](https://github.com/oorabona/release-it-preset/actions/workflows/ci.yml/badge.svg)](https://github.com/oorabona/release-it-preset/actions/workflows/ci.yml)
11
12
  [![Audit](https://github.com/oorabona/release-it-preset/actions/workflows/audit.yml/badge.svg)](https://github.com/oorabona/release-it-preset/actions/workflows/audit.yml)
12
13
  [![codecov](https://codecov.io/github/oorabona/release-it-preset/graph/badge.svg?token=6RMN34Z7TX)](https://codecov.io/github/oorabona/release-it-preset)
13
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
14
+ [![TypeScript](https://img.shields.io/badge/TypeScript-supported-blue.svg)](https://www.typescriptlang.org/)
15
+
16
+ ## Quick Start (30 seconds)
17
+
18
+ ```bash
19
+ pnpm add -D release-it @oorabona/release-it-preset
20
+ pnpm release-it-preset init --with-workflows
21
+ ```
22
+
23
+ That's it. You now have:
24
+ - `.release-it.json` extending the `default` preset (auto-generated changelog from commits)
25
+ - A `CHANGELOG.md` with Keep a Changelog skeleton
26
+ - Release scripts in your `package.json` (`pnpm release:patch`, `release:minor`, `release:major`)
27
+ - A `.github/workflows/release.yml` that publishes via npm OIDC trusted publishing on tag push
28
+
29
+ Run a release:
30
+ ```bash
31
+ pnpm release-it-preset validate # pre-flight checks
32
+ pnpm release:minor # bump + commit + tag + push (CI publishes)
33
+ ```
34
+
35
+ **For monorepos:** `init` auto-detects `pnpm-workspace.yaml` / `package.json#workspaces` and scaffolds per-package `.release-it.json`.
36
+
37
+ **One-off (no install):** `pnpm dlx @oorabona/release-it-preset init --with-workflows`
38
+
39
+ → Full reference: [docs/USAGE.md](docs/USAGE.md) · [Migration v0→v1](docs/MIGRATION.md) · [Public API](docs/PUBLIC_API.md)
40
+
41
+ ## Supply chain verification
42
+
43
+ Releases use npm OIDC provenance and, starting with v1.4.0, attach the npm
44
+ registry tarball, SLSA L3 provenance, and a cosign keyless bundle to the GitHub
45
+ release. See [docs/VERIFY.md](docs/VERIFY.md) for copy-paste verification
46
+ commands.
14
47
 
15
48
  ## Why this preset?
16
49
 
@@ -18,7 +51,7 @@ Most release workflows fall into one of three traps: too much manual work (plain
18
51
 
19
52
  `@oorabona/release-it-preset` occupies the productive middle ground for solo and small-team JavaScript package maintainers who want:
20
53
 
21
- - **Human-readable changelogs.** Keep a Changelog format (Added/Changed/Deprecated/Removed/Fixed/Security) generated automatically from conventional commits — no manual entry writing, no machine-format diffs. `[YANKED]` markers in version headings are preserved transparently; apply them manually post-release per the [Keep a Changelog spec](https://keepachangelog.com/en/1.1.0/).
54
+ - **Human-readable changelogs.** Keep a Changelog format (Added/Changed/Deprecated/Removed/Fixed/Security) generated automatically from conventional commits — no manual entry writing, no machine-format diffs. `[YANKED]` markers in version headings are preserved transparently.
22
55
  - **OIDC publishing without CI plumbing.** Import the reusable `publish.yml` workflow in three lines. OIDC trusted publishing with npm provenance ships on day one, no `NPM_TOKEN` secret required.
23
56
  - **Diagnostic confidence before release.** Run `release-it-preset doctor` to surface every misconfiguration — git auth, npm auth, changelog hygiene, branch requirements — before anything breaks in CI.
24
57
  - **Recovery presets for the real world.** Dedicated `republish` and `retry-publish` configs handle the scenarios other tools pretend don't happen.
@@ -36,1620 +69,52 @@ Most release workflows fall into one of three traps: too much manual work (plain
36
69
  | [changesets](https://github.com/changesets/changesets) | PR-driven versioning, fixed/linked package versions | 5+ maintainer monorepo, every change deserves explicit intent |
37
70
  | [semantic-release](https://github.com/semantic-release/semantic-release) | Fully-automated, zero human intervention | Branch-driven release pipelines, no human review of changelogs |
38
71
  | [release-please](https://github.com/googleapis/release-please) | GitHub Release PR pattern, 20+ language strategies | Polyglot repos, GitHub-native PR-driven workflow |
39
- | [`@release-it-plugins/workspaces`](https://github.com/release-it-plugins/workspaces) | Multi-package iteration + cross-pkg dep sync | Monorepo with bulk publish — composes with this preset (see [Composing with `@release-it-plugins/workspaces`](#composing-with-release-it-pluginsworkspaces)) |
40
-
41
- ## Table of Contents
42
-
43
- - [Why this preset?](#why-this-preset)
44
- - [Ecosystem positioning](#ecosystem-positioning)
45
- - [Features](#features)
46
- - [Installation](#installation)
47
- - [Install patterns](#install-patterns)
48
- - [Quick Start](#quick-start)
49
- - [Available Configurations](#available-configurations)
50
- - [CLI Usage](#cli-usage)
51
- - [Zero-Config Mode (Auto-Detection)](#zero-config-mode-auto-detection)
52
- - [Preset Selection Mode](#preset-selection-mode)
53
- - [Passthrough Mode (Custom Config Override)](#passthrough-mode-custom-config-override)
54
- - [Monorepo Support](#monorepo-support)
55
- - [Composing with `@release-it-plugins/workspaces`](#composing-with-release-it-pluginsworkspaces)
56
- - [Utility Commands](#utility-commands)
57
- - [Scripts](#scripts)
58
- - [Environment Variables](#environment-variables)
59
- - [Configuration Modes](#configuration-modes)
60
- - [Borrowing Scripts & Workflows](#borrowing-scripts--workflows)
61
- - [Release Workflow](#release-workflow)
62
- - [GitHub Actions Workflows](#github-actions-workflows)
63
- - [Reusable Workflows](#reusable-workflows)
64
- - [Workflow Reference](#workflow-reference)
65
- - [Exit codes](#exit-codes)
66
- - [Best Practices](#best-practices)
67
- - [Troubleshooting](#troubleshooting)
68
- - [Public API](#public-api)
69
- - [Contributing](#contributing)
72
+ | [`@release-it-plugins/workspaces`](https://github.com/release-it-plugins/workspaces) | Multi-package iteration + cross-pkg dep sync | Monorepo with bulk publish — composes with this preset |
70
73
 
71
74
  ## Features
72
75
 
73
- - 📦 Multiple release configurations for different scenarios
74
- - 📝 Automatic changelog generation using [Keep a Changelog](https://keepachangelog.com/) format
75
- - 🤖 Conventional commits parsing and categorization
76
- - 🏷️ Git tagging with optional GitHub release automation
77
- - 🚀 npm publishing with provenance (opt-in, ideal for CI)
78
- - 🔄 Republish and retry mechanisms for failed releases
79
- - Hotfix release support
80
- - 🎯 Environment variable configuration
81
- - 🔍 Zero-config auto-detection mode
82
- - 🏢 Monorepo support with parent directory config references
83
- - ⚙️ Passthrough mode for custom config files
84
-
85
- ## Installation
86
-
87
- ```bash
88
- pnpm add -D @oorabona/release-it-preset release-it
89
- ```
90
-
91
- ### Install patterns
92
-
93
- | Use case | Command | Notes |
94
- |---|---|---|
95
- | **Try without installing** | `pnpm dlx @oorabona/release-it-preset doctor` | Fetch + run, no install. Use for evaluating the preset on an existing repo. |
96
- | **One-shot npx** | `npx -y @oorabona/release-it-preset doctor` | Same idea, npm-flavored |
97
- | **Adopt as devDep** (recommended) | `pnpm add -D @oorabona/release-it-preset release-it` | Pins via lockfile, idiomatic for projects |
98
- | **CI usage** | `pnpm install --frozen-lockfile && pnpm exec release-it-preset retry-publish --ci` | Lockfile-deterministic, no prompts |
99
- | **Diagnostic on any repo** | `pnpm dlx @oorabona/release-it-preset doctor` | Works against the cwd's git/package.json/CHANGELOG; great for quick health checks |
100
-
101
- **Global install is not recommended** — pin per-project for reproducibility. The preset is small (<20KB unpacked); CI overhead is negligible.
102
-
103
- The peer requirement is `release-it ^19.0.0 || ^20.0.0`. CI runs against the upper bound (v20.x) on every commit; v19 was smoke-tested manually before the constraint was widened. v20 is recommended for the OIDC trusted publishing handshake (npm ≥ 11.5.1, Node ≥ 24); v19 is supported for composing with [`@release-it-plugins/workspaces`](#composing-with-release-it-pluginsworkspaces) (its peer maxes at v19 today).
104
-
105
- ## Quick Start
106
-
107
- ### Option 1: Using the CLI (Recommended)
108
-
109
- Add scripts to your `package.json`:
110
-
111
- ```json
112
- {
113
- "scripts": {
114
- "release": "release-it-preset default",
115
- "release:hotfix": "release-it-preset hotfix"
116
- }
117
- }
118
- ```
119
-
120
- Then run:
121
-
122
- ```bash
123
- pnpm release
124
- ```
125
-
126
- ### Option 2: Using extends
127
-
128
- Create `.release-it.json` in your project:
129
-
130
- ```json
131
- {
132
- "extends": "@oorabona/release-it-preset/config/default"
133
- }
134
- ```
135
-
136
- Add scripts to your `package.json`:
137
-
138
- ```json
139
- {
140
- "scripts": {
141
- "release": "release-it"
142
- }
143
- }
144
- ```
145
-
146
- ### Initialize CHANGELOG.md
147
-
148
- Create a `CHANGELOG.md` file with Keep a Changelog format:
149
-
150
- ```markdown
151
- # Changelog
152
-
153
- All notable changes to this project will be documented in this file.
154
-
155
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
156
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
157
-
158
- ## [Unreleased]
159
-
160
- ### Added
161
- - Initial release
162
- ```
163
-
164
- ## GitHub Actions
165
-
166
- ### Quick Start: Reusable Workflows
167
-
168
- Import pre-configured workflows into your repository:
169
-
170
- **PR Validation:**
171
- ```yaml
172
- name: PR Checks
173
-
174
- on:
175
- pull_request:
176
- types: [opened, synchronize, reopened]
177
-
178
- permissions:
179
- contents: read
180
- pull-requests: write
181
-
182
- jobs:
183
- validate:
184
- uses: oorabona/release-it-preset/.github/workflows/reusable-verify.yml@main
185
- with:
186
- base-ref: origin/${{ github.base_ref }}
187
- head-ref: ${{ github.sha }}
188
- run-tests: true
189
- secrets: inherit
190
- ```
191
-
192
- **Publish on Tag:**
193
- ```yaml
194
- name: Publish
195
-
196
- on:
197
- push:
198
- tags: ['v*']
199
-
200
- permissions:
201
- contents: write
202
- id-token: write
203
-
204
- jobs:
205
- publish:
206
- uses: oorabona/release-it-preset/.github/workflows/publish.yml@main
207
- secrets:
208
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
209
- ```
210
-
211
- 📖 **[Full Reusable Workflows Documentation](examples/reusable-workflows.md)** | 📚 **[CI/CD Integration Examples](examples/ci-integration.md)**
212
-
213
- ## Available Configurations
214
-
215
- ### `default` - Standard Release
216
-
217
- Full-featured release with changelog, git operations, and optional GitHub/npm publishing.
218
-
219
- **CLI:**
220
- ```bash
221
- pnpm release-it-preset default
222
- ```
223
-
224
- **Extends:**
225
- ```json
226
- {
227
- "extends": "@oorabona/release-it-preset/config/default"
228
- }
229
- ```
230
-
231
- Features:
232
- - ✅ Version bumping (interactive)
233
- - ✅ Automatic changelog population from conventional commits
234
- - ✅ Git commit, tag, and push
235
- - ☑️ GitHub release creation (set `GITHUB_RELEASE=true`)
236
- - ☑️ npm publishing with provenance (set `NPM_PUBLISH=true`)
237
-
238
- ### `hotfix` - Emergency Hotfix
239
-
240
- For urgent patches that need quick changelog generation from git log (GitHub/npm remain opt-in).
241
-
242
- **CLI:**
243
- ```bash
244
- pnpm release-it-preset hotfix
245
- ```
246
-
247
- **Extends:**
248
- ```json
249
- {
250
- "extends": "@oorabona/release-it-preset/config/hotfix"
251
- }
252
- ```
253
-
254
- Features:
255
- - ✅ Forced patch version increment
256
- - ✅ Automatic changelog from recent commits
257
- - ✅ Pre-bump unreleased section population
258
- - ☑️ GitHub release with extracted notes (set `GITHUB_RELEASE=true`)
259
- - ☑️ npm publishing with provenance (set `NPM_PUBLISH=true`)
260
-
261
- ### `changelog-only` - Changelog Preparation
262
-
263
- Updates changelog without performing a release (useful in CI or pre-release).
264
-
265
- **CLI:**
266
- ```bash
267
- pnpm release-it-preset changelog-only --ci
268
- ```
269
-
270
- **Extends:**
271
- ```json
272
- {
273
- "extends": "@oorabona/release-it-preset/config/changelog-only"
274
- }
275
- ```
276
-
277
- Features:
278
- - ✅ Populates [Unreleased] section
279
- - ❌ No version bump
280
- - ❌ No git operations
281
- - ❌ No publishing
282
-
283
- ### `manual-changelog` - Manual Changelog Release
284
-
285
- For releases where you've manually edited the [Unreleased] section in CHANGELOG.md.
286
- Skips automatic changelog generation while keeping GitHub/npm steps opt-in.
287
-
288
- **Workflow:**
289
- ```bash
290
- # 1. Generate initial changelog
291
- pnpm release-it-preset update
292
-
293
- # 2. Manually edit CHANGELOG.md [Unreleased] section
294
-
295
- # 3. Release without regenerating changelog
296
- pnpm release-it-preset manual-changelog
297
- ```
298
-
299
- **Extends:**
300
- ```json
301
- {
302
- "extends": "@oorabona/release-it-preset/config/manual-changelog"
303
- }
304
- ```
305
-
306
- Features:
307
- - ✅ Version bumping (interactive)
308
- - ✅ Preserves manual [Unreleased] edits
309
- - ✅ Moves [Unreleased] to versioned section
310
- - ✅ Git commit, tag, and push
311
- - ☑️ GitHub release creation (set `GITHUB_RELEASE=true`)
312
- - ☑️ npm publishing with provenance (set `NPM_PUBLISH=true`)
313
- - ❌ Skips automatic changelog population
314
-
315
- ### `no-changelog` - Quick Release
316
-
317
- Standard release without changelog updates; GitHub/npm steps remain opt-in.
318
-
319
- **CLI:**
320
- ```bash
321
- pnpm release-it-preset no-changelog
322
- ```
323
-
324
- **Extends:**
325
- ```json
326
- {
327
- "extends": "@oorabona/release-it-preset/config/no-changelog"
328
- }
329
- ```
330
-
331
- Features:
332
- - ✅ Version bumping
333
- - ✅ Git operations
334
- - ☑️ GitHub releases (set `GITHUB_RELEASE=true`)
335
- - ☑️ npm publishing (set `NPM_PUBLISH=true`)
336
- - ❌ No changelog updates
337
-
338
- ### `republish` - Git Tag Move + GitHub Release Update
339
-
340
- ⚠️ **DANGER**: Moves an existing git tag to HEAD and updates the GitHub release notes (breaks semver immutability for that tag).
341
-
342
- Only use when you need to fix a broken release that requires moving the git tag. This preset **does not publish to npm** — npm immutability (since 2016) makes republishing an existing version impossible under any dist-tag. See [ADR 0005](docs/adr/0005-republish-scope-narrowing.md).
343
-
344
- Alternatives:
345
- - **dist-tag change** (e.g. move `latest` to a different version): `npm dist-tag add @oorabona/release-it-preset@<version> latest`
346
- - **Retry a failed npm/GitHub publish**: use the `retry-publish` preset instead
347
-
348
- **CLI:**
349
- ```bash
350
- pnpm release-it-preset republish
351
- ```
352
-
353
- **Extends:**
354
- ```json
355
- {
356
- "extends": "@oorabona/release-it-preset/config/republish"
357
- }
358
- ```
359
-
360
- Features:
361
- - ⚠️ Moves existing git tag
362
- - ✅ Updates changelog for current version
363
- - ☑️ Updates GitHub release (set `GITHUB_RELEASE=true`)
364
- - ❌ Does not publish to npm (npm immutability — use `npm dist-tag add` or `retry-publish`)
365
-
366
- ### `retry-publish` - Retry Failed Publishing
367
-
368
- Retries npm/GitHub publishing for an existing tag without modifying git history; opt in to each surface via `NPM_PUBLISH` and `GITHUB_RELEASE`.
369
-
370
- **CLI:**
371
- ```bash
372
- # Step 1: Run pre-flight checks (optional)
373
- pnpm release-it-preset retry-publish-preflight
374
- # Advanced (direct compiled call)
375
- # node node_modules/@oorabona/release-it-preset/dist/scripts/retry-publish.js
376
-
377
- # Step 2: Retry the publish
378
- pnpm release-it-preset retry-publish
379
- ```
380
-
381
- **Extends:**
382
- ```json
383
- {
384
- "extends": "@oorabona/release-it-preset/config/retry-publish"
385
- }
386
- ```
387
-
388
- Features:
389
- - ☑️ Republishes to npm (set `NPM_PUBLISH=true`)
390
- - ☑️ Updates GitHub release (set `GITHUB_RELEASE=true`)
391
- - ❌ No version increment
392
- - ❌ No git operations
393
-
394
- ## CLI Usage
395
-
396
- The package provides a `release-it-preset` CLI with four operating modes:
397
-
398
- 1. **Zero-Config Mode** (auto-detection) - No arguments needed
399
- 2. **Preset Selection Mode** - Specify which preset to use
400
- 3. **Passthrough Mode** - Direct config file override
401
- 4. **Utility Mode** - Helper commands
76
+ - **One-command init** — `init --with-workflows` scaffolds `.release-it.json`, `CHANGELOG.md`, `package.json` scripts, and a GitHub Actions publish workflow.
77
+ - **Seven release configs** — `default`, `hotfix`, `manual-changelog`, `no-changelog`, `changelog-only`, `republish`, `retry-publish` — each tuned for a specific scenario. → [docs/USAGE.md#configurations](docs/USAGE.md#available-configurations)
78
+ - **Doctor command** pre-release diagnostics: branch state, publish workflow freshness, npm provenance readiness, peer-dep range, CHANGELOG validity, readiness score. → [docs/USAGE.md#doctor](docs/USAGE.md#doctor---release-readiness-diagnostic)
79
+ - **OIDC trusted publishing** zero-config npm provenance via GitHub Actions OIDC; no `NPM_TOKEN` secret needed when using the reusable `publish.yml` workflow.
80
+ - **Monorepo support** `init` auto-detects workspace manifests; `GIT_CHANGELOG_PATH` scopes changelog generation per package.
81
+ - **Recovery flows** `republish` / `retry-publish` for the inevitable "first publish failed at npm step" moment.
82
+ - **Smart dist-tag selection** — pre-releases (`-rc`, `-beta`) auto-publish under non-`latest` tags.
83
+ - **Conventional Commits aware** — auto-generated `[Unreleased]` from commit history, with curatable manual edits preserved.
84
+ - **Reusable GitHub workflows** — `publish.yml`, `hotfix.yml`, `republish.yml` shipped as composable callables.
85
+ - **TypeScript-first** DI pattern in scripts, fully testable (213 unit tests).
402
86
 
403
- ### Zero-Config Mode (Auto-Detection)
87
+ ## Installation & requirements
404
88
 
405
- The CLI can automatically detect which preset to use from your `.release-it.json`:
89
+ - **Node.js** >= 20.19.0
90
+ - **Package manager:** pnpm, npm, or yarn
91
+ - **Peer dependency:** `release-it ^19.0.0 || ^20.0.0` (v20 recommended for OIDC publishing)
92
+ - **TypeScript:** built with TypeScript 6; TypeScript 5+ projects are supported via the compiled ESM distribution
406
93
 
407
94
  ```bash
408
- # Just run release-it-preset with no arguments
409
- pnpm release-it-preset
410
-
411
- # 🔍 Auto-detected preset: default
412
- # ✅ Config validated: preset "default"
413
- # 📝 Using: /path/to/.release-it.json
414
- ```
415
-
416
- **How it works:**
417
- 1. CLI reads your `.release-it.json`
418
- 2. Extracts the preset name from the `extends` field
419
- 3. Runs that preset automatically
420
-
421
- **Requirements:**
422
- - `.release-it.json` must exist
423
- - Must have `extends` field like `"@oorabona/release-it-preset/config/default"`
424
-
425
- **Benefits:**
426
- - ✅ Shortest command possible
427
- - ✅ Config file is source of truth
428
- - ✅ No need to remember preset names
429
- - ✅ Follows industry standards (ESLint, TypeScript, Prettier)
430
-
431
- ### Preset Selection Mode
432
-
433
- Run release-it with specific configurations:
434
-
435
- ```bash
436
- # Show help
437
- pnpm release-it-preset --help
438
-
439
- # Run releases
440
- pnpm release-it-preset default --dry-run
441
- pnpm release-it-preset hotfix --verbose
442
- pnpm release-it-preset changelog-only --ci
443
- pnpm release-it-preset manual-changelog
444
- ```
445
-
446
- All additional arguments are passed through to release-it.
447
-
448
- ### Passthrough Mode (Custom Config Override)
449
-
450
- Use a custom config file and bypass preset validation:
451
-
452
- ```bash
453
- # Use custom config file
454
- pnpm release-it-preset --config .release-it-manual.json
455
-
456
- # 🔀 Passthrough mode: using config .release-it-manual.json
457
- # Bypassing preset validation - direct release-it invocation
458
- ```
459
-
460
- **Use cases:**
461
- - **Switching presets occasionally** - Have multiple config files for different scenarios
462
- - **Monorepo workflows** - Reference shared configs from parent directories
463
- - **Advanced customization** - Full control over release-it configuration
464
-
465
- **Example workflow:**
466
-
467
- ```json
468
- // .release-it.json (default - 95% of time)
469
- {
470
- "extends": "@oorabona/release-it-preset/config/default",
471
- "git": { "requireBranch": "develop" }
472
- }
473
-
474
- // .release-it-manual.json (rare - 5% of time)
475
- {
476
- "extends": "@oorabona/release-it-preset/config/manual-changelog",
477
- "git": { "requireBranch": "develop" }
478
- }
479
- ```
480
-
481
- ```bash
482
- # Normal release
483
- pnpm release-it-preset # Auto-detects default
484
-
485
- # Manual changelog release (rare)
486
- pnpm release-it-preset --config .release-it-manual.json
487
- ```
488
-
489
- **Benefits:**
490
- - ✅ No need to edit `.release-it.json` to switch presets
491
- - ✅ Config files are explicit and version-controlled
492
- - ✅ Works with monorepo parent directory references
493
-
494
- ### Monorepo Support
495
-
496
- Parent directory config references are now supported:
497
-
498
- ```bash
499
- # Monorepo structure
500
- /my-monorepo/
501
- ├── .release-it-base.json # Shared configuration
502
- ├── packages/
503
- │ ├── core/
504
- │ │ └── .release-it.json # extends: ../../.release-it-base.json
505
- │ └── utils/
506
- │ └── .release-it.json # extends: ../../.release-it-base.json
95
+ pnpm add -D release-it @oorabona/release-it-preset
507
96
  ```
508
97
 
509
- ```json
510
- // packages/core/.release-it.json
511
- {
512
- "extends": [
513
- "../../.release-it-base.json", // ✅ Parent reference allowed!
514
- "@oorabona/release-it-preset/config/default"
515
- ]
516
- }
517
- ```
518
-
519
- **Security validation:**
520
- - ✅ Parent directory references (`../`) supported (up to 5 levels)
521
- - ✅ Config file extension whitelist (`.json`, `.js`, `.cjs`, `.mjs`, `.yaml`, `.yml`, `.toml`)
522
- - ✅ File existence validation
523
- - ❌ Absolute paths blocked (use relative paths)
524
- - ❌ Excessive traversal blocked (max `../../../../../../`)
525
-
526
- **Why this is safe:**
527
- - Config files are trusted code (developer controls the repository)
528
- - Industry standard pattern (TypeScript, ESLint, Prettier all allow `../`)
529
- - Multiple validation layers prevent abuse
530
- - No privilege escalation in CLI tool context
531
-
532
- See [examples/monorepo-workflow.md](examples/monorepo-workflow.md) for complete monorepo guide and [examples/monorepo/](examples/monorepo/) for a runnable workspace demo.
533
-
534
- ### Composing with `@release-it-plugins/workspaces`
535
-
536
- This preset focuses on a single package per release-it run. If your monorepo needs **bulk publish** (iterate over every workspace package + sync cross-package dependency versions), compose this preset with [`@release-it-plugins/workspaces`](https://github.com/release-it-plugins/workspaces) — the canonical release-it plugin for that workflow.
537
-
538
- ```bash
539
- # Install both
540
- pnpm add -D @oorabona/release-it-preset @release-it-plugins/workspaces release-it@^19
541
- ```
542
-
543
- ```jsonc
544
- // .release-it.json — extends our preset AND loads the workspaces plugin
545
- {
546
- "extends": "@oorabona/release-it-preset/config/default",
547
- "plugins": {
548
- "@release-it-plugins/workspaces": true
549
- }
550
- }
551
- ```
552
-
553
- **Peer compatibility note:** `@release-it-plugins/workspaces` v5.0.3 declares peer `release-it ^17 || ^18 || ^19`. Our preset declares peer `^19 || ^20`. The intersection is `^19`, so when composing with the workspaces plugin you must pin release-it to v19. v20 standalone (without the workspaces plugin) is fully supported and recommended for new projects.
554
-
555
- `release-it-preset doctor` does **not** check whether the workspaces plugin is loaded — it's an opt-in composition. Run it manually after install if you want to verify the plugin's own preflight checks.
556
-
557
- When this composition is right for you:
558
- - You release multiple packages from one repo with **synchronized versions** (all bumped together).
559
- - You want **cross-package dependency sync** (when `pkg-a` bumps to 2.0, `pkg-b`'s reference auto-updates).
560
-
561
- When our preset alone is enough:
562
- - **Independent versioning** per package (each package releases when ready). Use `GIT_CHANGELOG_PATH=packages/<pkg>` to scope the CHANGELOG. See [examples/monorepo/](examples/monorepo/) for the runnable demo.
563
-
564
- ### Utility Commands
565
-
566
- Helper commands for project setup and maintenance:
567
-
568
- #### `init` - Initialize Project
569
-
570
- Creates CHANGELOG.md, .release-it.json, and optionally adds scripts to package.json:
571
-
572
- ```bash
573
- # Interactive mode (asks for confirmation)
574
- pnpm release-it-preset init
575
-
576
- # Non-interactive mode (skip prompts, use defaults)
577
- pnpm release-it-preset init --yes
578
-
579
- # Also scaffold a GitHub Actions publish workflow
580
- pnpm release-it-preset init --yes --with-workflows
581
-
582
- # Use a custom workflow filename (default: release.yml)
583
- pnpm release-it-preset init --yes --with-workflows --workflow-name=publish.yml
584
- ```
585
-
586
- **What it does:**
587
- - Creates `CHANGELOG.md` with Keep a Changelog template
588
- - Creates `.release-it.json` with extends configuration
589
- - Optionally adds release scripts to `package.json`
590
- - Skips existing files in `--yes` mode
591
-
592
- > One-off usage: `pnpm dlx @oorabona/release-it-preset init` (or `npx @oorabona/release-it-preset init`) runs the CLI without installing it as a dependency.
593
-
594
- #### `update` - Update Changelog
595
-
596
- Updates the [Unreleased] section with commits since last tag:
597
-
98
+ **Try without installing:**
598
99
  ```bash
599
- pnpm release-it-preset update
100
+ pnpm dlx @oorabona/release-it-preset doctor # health check on any repo
101
+ pnpm dlx @oorabona/release-it-preset init # scaffold a new project
600
102
  ```
601
103
 
602
- **What it does:**
603
- - Parses conventional commits since last git tag
604
- - Groups commits by type (Added, Fixed, Changed, etc.)
605
- - Updates [Unreleased] section in CHANGELOG.md
606
- - Generates commit links to repository
607
- - Uses only the conventional commit subject; feel free to edit `CHANGELOG.md` afterwards if you want to add the detailed bullet points that lived in the commit body
104
+ ## CHANGELOG
608
105
 
609
- #### `validate` - Validate Release Readiness
106
+ See [CHANGELOG.md](CHANGELOG.md) for all version history, or browse [GitHub Releases](https://github.com/oorabona/release-it-preset/releases).
610
107
 
611
- Checks if project is ready for release:
612
-
613
- ```bash
614
- # Standard validation
615
- pnpm release-it-preset validate
108
+ ## Contributing & support
616
109
 
617
- # Allow uncommitted changes
618
- pnpm release-it-preset validate --allow-dirty
619
- ```
620
-
621
- **What it checks:**
622
- - ✅ CHANGELOG.md exists and is well-formatted
623
- - ✅ [Unreleased] section has content
624
- - ✅ Working directory is clean (unless --allow-dirty)
625
- - ✅ npm authentication works (npm whoami)
626
- - ✅ Current branch is allowed (if GIT_REQUIRE_BRANCH is set)
627
-
628
- Exit code 0 if all checks pass, 1 if any fail (useful in CI/pre-commit hooks).
629
-
630
- #### `check` - Diagnostic Information
631
-
632
- Displays configuration and project status:
633
-
634
- ```bash
635
- pnpm release-it-preset check
636
- ```
637
-
638
- **What it shows:**
639
- - Environment variables and their values
640
- - Repository information (URL, branch, remote)
641
- - Git tags and latest version
642
- - Commits since last tag
643
- - Configuration files status
644
- - npm authentication status
645
-
646
- Useful for debugging release issues.
647
-
648
- #### `doctor` - Release Readiness Diagnostic
649
-
650
- Runs a structured checklist across four categories and outputs a readiness score:
651
-
652
- ```bash
653
- pnpm release-it-preset doctor
654
- pnpm release-it-preset doctor --json
655
- ```
656
-
657
- **What it checks:**
658
-
659
- | Category | Checks |
660
- |----------|--------|
661
- | Environment | Known env vars, source (env / default / unset), publish-mode consistency |
662
- | Repository | Git repo presence, branch vs `GIT_REQUIRE_BRANCH`, latest tag, commit count, dirty WD, upstream tracking, remote URL |
663
- | Configuration | `CHANGELOG.md` exists + Keep a Changelog format + `[Unreleased]` content, `.release-it.json` parseable + `extends` field, `package.json` valid semver version, `release-it` peer range satisfied, `release-it` major version advisor |
664
- | Readiness Summary | `PASS`/`WARN`/`FAIL` counts, score `N/M checks passing`, status (`READY`/`WARNINGS`/`BLOCKED`), actionable recommendations |
665
-
666
- **Exit codes:**
667
- - `0` — status is `READY` or `WARNINGS`
668
- - `1` — status is `BLOCKED` (at least one `FAIL`)
669
-
670
- **`--json` output shape:**
671
- ```json
672
- {
673
- "environment": { "checks": [...], "vars": [...], "status": "PASS" },
674
- "repository": { "checks": [...], "status": "WARN" },
675
- "configuration": { "checks": [...], "status": "PASS" },
676
- "summary": {
677
- "pass": 10, "warn": 2, "fail": 0, "total": 12,
678
- "score": "10/12 checks passing",
679
- "status": "WARNINGS",
680
- "recommendations": ["Review 2 warning(s) before releasing"]
681
- }
682
- }
683
- ```
684
-
685
- Use `doctor` as a pre-release sanity check, and `check` for the full verbose configuration dump.
686
-
687
- #### `check-pr` - Pull Request Hygiene
688
-
689
- Evaluates PR readiness by analysing commits and changelog changes. Designed for CI usage but safe locally when the required environment variables are set (`PR_BASE_REF`, `PR_HEAD_REF`).
690
-
691
- ```bash
692
- PR_BASE_REF=origin/main PR_HEAD_REF=HEAD pnpm release-it-preset check-pr
693
- ```
694
-
695
- Outputs JSON summaries for workflows (base64 encoded) and prints a human-readable report.
696
-
697
- #### `retry-publish-preflight` - Retry Safety Checks
698
-
699
- Runs the retry publish pre-flight script with the same CLI convenience wrapper as other utilities. Verifies that the latest tag exists, matches `package.json`, and that there are no unexpected workspace changes before attempting a retry.
700
-
701
- ```bash
702
- pnpm release-it-preset retry-publish-preflight
703
- ```
704
-
705
- Use this before calling `pnpm release-it-preset retry-publish` when recovering from a failed publish.
706
-
707
- ### pnpm Script Shortcuts
708
-
709
- The root `package.json` defines helper scripts that wrap the CLI so you can run the most common flows with `pnpm run`:
710
-
711
- - `pnpm release` → run the default release config (`release-it-preset default`)
712
- - `pnpm run release:default:dry-run` → dry-run the default release configuration
713
- - `pnpm run release:no-changelog` → publish without touching the changelog
714
- - `pnpm run release:changelog-only` → update only the changelog
715
- - `pnpm run release:manual-changelog` → release with manually edited changelog (skip auto-generation)
716
- - `pnpm run release:hotfix` → execute the hotfix workflow
717
- - `pnpm run release:republish` → trigger the republish workflow (dangerous flow)
718
- - `pnpm run release:retry-preflight` → run retry publish safety checks
719
- - `pnpm run release:retry-publish` → retry npm/GitHub publishing for an existing tag
720
- - `pnpm run release:update` → populate the `[Unreleased]` section
721
- - `pnpm run release:validate` → run release validation checks
722
- - `pnpm run release:validate:allow-dirty` → validation that tolerates uncommitted changes
723
- - `pnpm run release:check` → show diagnostic information about the current repo
724
-
725
- ## Scripts
726
-
727
- Scripts are authored in TypeScript but distributed as compiled ESM JavaScript in `dist/scripts`. Under normal circumstances you should invoke them via the `release-it-preset` CLI or the pnpm aliases listed above; the CLI automatically prefers the compiled build and falls back to `tsx` only for local development. The direct `node` examples below are provided for automation scenarios where you deliberately want to call the compiled output.
728
-
729
- ### `extract-changelog.ts`
730
-
731
- Extracts the changelog entry for a specific version (used automatically by the release notes generator). If you ever need to call it manually:
732
-
733
- ```bash
734
- node node_modules/@oorabona/release-it-preset/dist/scripts/extract-changelog.js 1.2.3
735
- ```
736
-
737
- ### `populate-unreleased-changelog.ts`
738
-
739
- Populates the [Unreleased] section with commits since the last tag using conventional commits.
740
-
741
- ```bash
742
- # Preferred
743
- pnpm release-it-preset update
744
- # or
745
- pnpm run release:update
746
-
747
- # Advanced (call compiled output directly)
748
- node node_modules/@oorabona/release-it-preset/dist/scripts/populate-unreleased-changelog.js
749
- ```
750
-
751
- Supported commit types:
752
- - `feat`, `feature`, `add` → Added
753
- - `fix`, `bugfix` → Fixed
754
- - `deprecate`, `deprecated`, `deprecation` → Deprecated
755
- - `perf`, `refactor`, `style`, `docs`, `test`, `chore`, `build` → Changed
756
- - `remove`, `removed`, `delete`, `deleted` → Removed
757
- - `security` → Security
758
- - `ci`, `release`, `hotfix` → Ignored
759
-
760
- Add `[skip-changelog]` to commit message to exclude it.
761
-
762
- ### `republish-changelog.ts`
763
-
764
- Moves [Unreleased] content to the current version entry (for republishing).
765
-
766
- ```bash
767
- # Preferred
768
- pnpm run release:republish
769
- # or
770
- pnpm release-it-preset republish
771
-
772
- # Advanced
773
- node node_modules/@oorabona/release-it-preset/dist/scripts/republish-changelog.js
774
- ```
775
-
776
- ### `retry-publish.ts`
777
-
778
- Performs pre-flight checks before retrying a failed publish.
779
-
780
- ```bash
781
- # Preferred (CLI)
782
- pnpm release-it-preset retry-publish-preflight
783
-
784
- # Advanced (call compiled output directly)
785
- node node_modules/@oorabona/release-it-preset/dist/scripts/retry-publish.js
786
- ```
110
+ - [CONTRIBUTING.md](CONTRIBUTING.md) Conventional Commits, branch prefixes, pre-PR checklist, testing conventions
111
+ - [SUPPORT.md](SUPPORT.md) — where to ask questions, file bugs, and report security issues
112
+ - [Discussions](https://github.com/oorabona/release-it-preset/discussions) — Q&A, usage tips, ideas
113
+ - [Issues](https://github.com/oorabona/release-it-preset/issues) — bugs + feature requests (use templates)
114
+ - [SECURITY.md](SECURITY.md) — vulnerability reporting (do NOT use public issues)
787
115
 
788
- ## Environment Variables
789
-
790
- Customize behavior with environment variables:
791
-
792
- ### Changelog
793
- - `CHANGELOG_FILE` - Changelog file path (default: `CHANGELOG.md`)
794
- - `GIT_CHANGELOG_PATH` - Optional. When set to a repository-relative path (e.g. `packages/tar-xz`), restrict changelog generation to commits touching that path. Useful for monorepo per-package CHANGELOG files. Empty / unset = repository-wide (default).
795
- - `GIT_CHANGELOG_SINCE` - Optional. Override the `since` baseline for changelog generation (any git ref: SHA, tag, branch). When set, bypasses both the per-package release-commit detection and the `git describe --tags` fallback. Useful for monorepo workspaces with non-standard release commit patterns. Empty / unset = use auto-detection.
796
- - `CHANGELOG_TYPE_MAP` - Optional. JSON string mapping commit types to CHANGELOG section headings. Merged on top of `.changelog-types.json` (if present) and the built-in defaults. Use `false` as a value to suppress a type entirely. Example: `CHANGELOG_TYPE_MAP='{"ops":"### Operations","deps":"### Dependencies"}'`.
797
-
798
- ### Custom type map (`.changelog-types.json`)
799
-
800
- Create a `.changelog-types.json` file in your project root to override or extend the built-in commit-type → section mapping at the project level. The file is merged on top of the built-in defaults; individual keys can be overridden without touching the rest.
801
-
802
- **Resolution order** (highest priority wins):
803
- 1. `CHANGELOG_TYPE_MAP` env var (runtime override, e.g. in CI)
804
- 2. `.changelog-types.json` project file
805
- 3. Built-in defaults
806
-
807
- **Example `.changelog-types.json`:**
808
- ```json
809
- {
810
- "deps": "### Dependencies",
811
- "ops": "### Operations",
812
- "ci": false
813
- }
814
- ```
815
- - String values must be a valid `### Section Heading`.
816
- - `false` suppresses the type (no CHANGELOG entry emitted).
817
- - Malformed JSON or invalid values → warning logged, layer ignored, lower-priority map used.
818
-
819
- **BREAKING CHANGE: footer parsing** (Conventional Commits 1.0.0 §6): `BREAKING CHANGE:` is recognised as a footer only when it appears after a blank-line separator from the preceding paragraph. Mid-body occurrences without the blank line do not promote the commit to breaking. Multiple `BREAKING CHANGE:` lines in the same footer paragraph each emit a separate entry under `### ⚠️ BREAKING CHANGES`.
820
-
821
- ### Git
822
- - `GIT_COMMIT_MESSAGE` - Commit message template. Defaults vary per preset: `chore(release): v${version}` (`default`), `chore(hotfix): v${version}` (`hotfix`), `chore: republish v${version}` (`republish`). Set this env var to override across all presets.
823
- - `GIT_TAG_NAME` - Tag name template (default: `v${version}`)
824
- - `GIT_REQUIRE_BRANCH` - Required branch (default: `main`)
825
- - `GIT_REQUIRE_UPSTREAM` - Require upstream tracking (default: `false`)
826
- - `GIT_REQUIRE_CLEAN` - Require clean working directory (default: `false`)
827
- - `GIT_REMOTE` - Git remote name (default: `origin`)
828
- - `GIT_CHANGELOG_COMMAND` - Override the git log command used for previews (default filters out release/hotfix/ci commits)
829
- - `GIT_CHANGELOG_DESCRIBE_COMMAND` - Override the latest-tag detection command (default: `git describe --tags --abbrev=0`)
830
-
831
- ### GitHub
832
- - `GITHUB_RELEASE` - Enable GitHub releases (default: `false`)
833
- - `GITHUB_REPOSITORY` - Repository in `owner/repo` format (auto-detected from git remote)
834
-
835
- ### npm
836
- - `NPM_PUBLISH` - Enable npm publishing (default: `false`)
837
- - `NPM_SKIP_CHECKS` - Skip npm checks (default: `false`)
838
- - `NPM_ACCESS` - npm access level (default: `public`)
839
- - `NPM_TAG` - Optional. When set, the npm publish step appends `--tag <value>` (e.g. `legacy-v0.10.0`). Used to assign version-named dist-tags when republishing older versions so `latest` is not overwritten. Empty / unset = npm uses `latest`.
840
-
841
- ### Hotfix
842
- - `HOTFIX_INCREMENT` - Increment kind passed to release-it for the `hotfix` preset (default: `patch`). Accepts any release-it increment value (`patch`, `minor`, `major`, or an explicit version).
843
-
844
- > ℹ️ By default, the presets skip GitHub releases and npm publishing. Set `GITHUB_RELEASE=true` and/or `NPM_PUBLISH=true` in the environment (typically in CI) when you are ready to perform those steps.
845
-
846
- ### Example
847
-
848
- ```bash
849
- CHANGELOG_FILE="HISTORY.md" \
850
- GIT_REQUIRE_BRANCH="develop" \
851
- GIT_REQUIRE_CLEAN="true" \
852
- pnpm release
853
- ```
854
-
855
- ## Configuration Modes
856
-
857
- The preset supports two configuration modes:
858
-
859
- ### Mode 1: Direct Preset Usage (No Config File)
860
-
861
- **When to use:** Simple projects, trust preset defaults, or customize only via environment variables
862
-
863
- Don't create `.release-it.json`. Just run the CLI:
864
-
865
- ```bash
866
- pnpm release-it-preset default
867
- ```
868
-
869
- All configuration comes from the preset and environment variables.
870
-
871
- **Pros:**
872
- - ✅ Zero config files
873
- - ✅ Consistent behavior across projects
874
- - ✅ Easy to understand
875
- - ✅ Perfect for getting started
876
-
877
- ---
878
-
879
- ### Mode 2: Preset + User Overrides (Recommended)
880
-
881
- **When to use:** Customize specific options while keeping preset defaults
882
-
883
- Create `.release-it.json` **WITH the `extends` field**:
884
-
885
- ```json
886
- {
887
- "extends": "@oorabona/release-it-preset/config/default",
888
- "git": {
889
- "requireBranch": "master",
890
- "commitMessage": "chore: release v${version}"
891
- }
892
- }
893
- ```
894
-
895
- Run with CLI preset:
896
-
897
- ```bash
898
- pnpm release-it-preset default
899
- ```
900
-
901
- **How it works:**
902
- - The `extends` field loads the preset
903
- - release-it merges your overrides on top via c12
904
- - **Your values take precedence** over preset defaults
905
- - CLI validates that `extends` is present; mismatched preset name warns and uses the invoked preset's config for that run
906
-
907
- **Pros:**
908
- - ✅ **Recommended for customization**
909
- - ✅ Declarative config with explicit preset
910
- - ✅ Industry standard pattern (like ESLint, TypeScript)
911
- - ✅ Guaranteed config merging via release-it's c12
912
-
913
- **Example:** Using `hotfix` preset but release from `master` instead of `main`:
914
-
915
- ```json
916
- {
917
- "extends": "@oorabona/release-it-preset/config/hotfix",
918
- "git": {
919
- "requireBranch": "master"
920
- }
921
- }
922
- ```
923
-
924
- ```bash
925
- pnpm release-it-preset hotfix
926
- ```
927
-
928
- ---
929
-
930
- ### Configuration Validation
931
-
932
- The CLI validates your `.release-it.json` to prevent misconfigurations:
933
-
934
- #### Error 1: Missing `extends` field
935
-
936
- ```bash
937
- # .release-it.json without extends:
938
- {
939
- "git": { "requireBranch": "master" }
940
- }
941
-
942
- # Running:
943
- pnpm release-it-preset default
944
-
945
- # ❌ Configuration error!
946
- # .release-it.json is missing the required "extends" field.
947
- #
948
- # Without "extends", your config won't merge with the preset.
949
- # This means you'll get release-it defaults instead of preset defaults.
950
- #
951
- # Fix by adding this to .release-it.json:
952
- # {
953
- # "extends": "@oorabona/release-it-preset/config/default",
954
- # ...your overrides
955
- # }
956
- ```
957
-
958
- **Why `extends` is required:** Without it, release-it only loads your config file and uses release-it's own defaults. The preset is never loaded, so you lose important defaults like `npm.publish: false`.
959
-
960
- #### Note: Preset mismatch (warning, not error)
961
-
962
- ```bash
963
- # .release-it.json extends "default":
964
- {
965
- "extends": "@oorabona/release-it-preset/config/default"
966
- }
967
-
968
- # But you run:
969
- pnpm release-it-preset hotfix
970
-
971
- # ⚠️ Note: your .release-it.json extends "default"
972
- # but you invoked the "hotfix" preset.
973
- # Using "hotfix" config directly; .release-it.json customizations are ignored for this run.
974
- # To use your customizations, run: release-it-preset default
975
- ```
976
-
977
- > **Note**: invoking a preset different from your `.release-it.json` extends value now warns and uses the invoked preset's config (was: hard error). Use the matching name to keep your customizations.
978
-
979
- ---
980
-
981
- ### Which Mode Should I Use?
982
-
983
- | Scenario | Recommended Mode |
984
- |----------|------------------|
985
- | Quick start, minimal config | **Mode 1** (No config file) |
986
- | Customize branch/commit/hooks | **Mode 2** (Config with extends) |
987
- | Environment-only customization | **Mode 1** (Use env vars) |
988
- | Monorepo with per-package config | **Mode 2** (Each package has own config) |
989
-
990
- **Use Mode 1 to get started, switch to Mode 2 when you need customization.**
991
-
992
- ## Borrowing Scripts & Workflows
993
-
994
- - The root `package.json` of this repository shows how to expose convenient `pnpm run release:*` shortcuts. Feel free to copy that block into your own project (adjust the commands if you only need a subset).
995
- - The GitHub Actions workflows under `.github/workflows/*.yml` illustrate how to wire the CLI into CI. They are safe to reuse, provided you review the permissions/secrets section and adapt branch names or triggers to your process.
996
-
997
- ## Release Workflow
998
-
999
- ### Recommended Workflow
1000
-
1001
- **Local (Developer):**
1002
- 1. Make changes and commit with conventional commits
1003
- 2. Run `pnpm run release:update` to populate the `[Unreleased]` section from commits
1004
- 3. Review `CHANGELOG.md` - you have two options here:
1005
-
1006
- **Option A: Quick release with auto-generated changelog**
1007
- - Stage `CHANGELOG.md` as-is
1008
- - Run `pnpm run release:validate` to verify readiness
1009
- - Dry-run with `pnpm run release:default:dry-run`
1010
- - Execute `pnpm release` to perform the real release
1011
-
1012
- **Option B: Manual changelog editing (recommended for detailed release notes)**
1013
- - Manually edit `CHANGELOG.md` [Unreleased] section (add narrative, reorganize, etc.)
1014
- - No need to stage or commit
1015
- - Run `pnpm run release:validate` (or `pnpm run release:validate:allow-dirty`)
1016
- - Dry-run with `pnpm run release:manual-changelog --dry-run`
1017
- - Execute `pnpm run release:manual-changelog` to release
1018
- - This skips changelog regeneration, preserving your edits
1019
- - Bumps version, moves [Unreleased] to versioned section
1020
- - Creates release commit + tag and pushes to origin (GitHub release happens later if `GITHUB_RELEASE=true` in CI)
1021
-
1022
- **If you change your mind mid-release:** If you started with Option A but want to add manual edits when prompted `Commit (chore(release): vX.Y.Z)?`, answer **No**, then press Ctrl+C to abort. Edit your `CHANGELOG.md`, then run `pnpm run release:manual-changelog` instead. Alternatively, re-run `pnpm release` and select the same version again (the preset's `--allow-same-version` makes this safe).
1023
-
1024
- 4. **Note:** GitHub releases and npm publish are skipped locally by default. Enable them with environment variables or let the `publish.yml` workflow handle both steps after the tag push.
1025
-
1026
- ```mermaid
1027
- flowchart TD
1028
- A[Conventional commits] --> B[pnpm run release:update]
1029
- B --> C{Want to edit<br/>changelog manually?}
1030
-
1031
- C -->|No - Auto changelog| D[Stage CHANGELOG.md]
1032
- D --> E[pnpm run release:validate]
1033
- E --> F[pnpm run release:default:dry-run]
1034
- F --> G[pnpm release]
1035
-
1036
- C -->|Yes - Manual editing| H[Edit CHANGELOG.md manually]
1037
- H --> I[pnpm run release:validate --allow-dirty]
1038
- I --> J[pnpm run release:manual-changelog --dry-run]
1039
- J --> K[pnpm run release:manual-changelog]
1040
-
1041
- G --> L[Push commit \u0026 tag]
1042
- K --> L
1043
- L --> M[Publish workflow runs in CI]
1044
- ```
1045
-
1046
- **CI (GitHub Actions):**
1047
- - When tag is pushed, CI publishes to npm with provenance
1048
-
1049
- ### Why This Workflow?
1050
-
1051
- - **Single CI entry point** - Tag pushes run the `retry-publish` preset, which updates the GitHub release and publishes to npm with provenance in one command.
1052
- - **Local runs stay safe** - Without `GITHUB_RELEASE=true` or `NPM_PUBLISH=true`, the presets only handle changelog updates, commits, and tags.
1053
- - **Better security** - Publishing requires CI credentials (GITHUB_TOKEN + NPM_TOKEN), keeping local environments token-free by default.
1054
- - **Predictable outputs** - Release notes are regenerated from the committed changelog, avoiding drift between local runs and CI.
1055
-
1056
- ### GitHub Actions Setup
1057
-
1058
- Create `.github/workflows/publish.yml`:
1059
-
1060
- ```yaml
1061
- name: Publish Package
1062
-
1063
- on:
1064
- push:
1065
- tags:
1066
- - 'v*'
1067
-
1068
- permissions:
1069
- contents: write
1070
- id-token: write # For npm provenance
1071
-
1072
- jobs:
1073
- publish:
1074
- runs-on: ubuntu-latest
1075
- steps:
1076
- - uses: actions/checkout@v4
1077
-
1078
- - uses: pnpm/action-setup@v4
1079
-
1080
- - uses: actions/setup-node@v4
1081
- with:
1082
- node-version: 20
1083
- registry-url: 'https://registry.npmjs.org'
1084
- cache: 'pnpm'
1085
-
1086
- - run: pnpm install --frozen-lockfile
1087
-
1088
- - run: pnpm build
1089
-
1090
- - name: Update GitHub release and publish to npm
1091
- run: pnpm release-it-preset retry-publish --ci
1092
- env:
1093
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
1094
- NPM_PUBLISH: 'true'
1095
- GITHUB_RELEASE: 'true'
1096
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1097
- ```
1098
-
1099
- **Required Secrets:**
1100
- - `NPM_TOKEN` - Automation token from npmjs.com (Settings → Access Tokens → Generate New Token → Automation)
1101
- - `GITHUB_TOKEN` is provided automatically by GitHub Actions (no manual secret needed)
1102
-
1103
- **Required Permissions (locally):**
1104
- - Set `GITHUB_RELEASE=true` and/or `NPM_PUBLISH=true` only when you explicitly want to perform those actions from your machine. Provide `GITHUB_TOKEN`/`NPM_TOKEN` as needed.
1105
-
1106
- ### Alternative: Full CI Release
1107
-
1108
- If you prefer to run the entire release in CI:
1109
-
1110
- ```yaml
1111
- on:
1112
- workflow_dispatch: # Manual trigger
1113
- inputs:
1114
- version:
1115
- description: 'Version bump type'
1116
- required: true
1117
- type: choice
1118
- options: [patch, minor, major]
1119
-
1120
- permissions:
1121
- contents: write # For git operations and GitHub releases
1122
- id-token: write # For npm provenance
1123
-
1124
- jobs:
1125
- release:
1126
- runs-on: ubuntu-latest
1127
- steps:
1128
- # ... setup steps ...
1129
-
1130
- - run: pnpm release-it-preset default --ci --increment ${{ inputs.version }}
1131
- env:
1132
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1133
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
1134
- GITHUB_RELEASE: 'true'
1135
- NPM_PUBLISH: 'true'
1136
- ```
1137
-
1138
- ## GitHub Actions Workflows
1139
-
1140
- This repository includes several GitHub Actions workflows for automated CI/CD and release management.
1141
-
1142
- ### Reusable Workflows
1143
-
1144
- Two workflows are designed for reuse in your own projects:
1145
-
1146
- #### 🔄 `reusable-verify.yml` - PR Validation & Hygiene Checks
1147
-
1148
- Validates TypeScript compilation, runs tests, checks release readiness, and evaluates PR hygiene (changelog updates, conventional commits).
1149
-
1150
- **When to use:** Import this workflow in your PR validation to ensure code quality and release readiness.
1151
-
1152
- **Inputs:**
1153
-
1154
- | Input | Type | Default | Description |
1155
- |-------|------|---------|-------------|
1156
- | `node-version` | string | `'20'` | Node.js version to use |
1157
- | `run-tests` | boolean | `false` | Run `pnpm test` after compilation |
1158
- | `base-ref` | string | `''` | Base ref for diff comparisons (e.g., `origin/main`) |
1159
- | `head-ref` | string | `'HEAD'` | Head ref for comparisons |
1160
- | `install-args` | string | `'--frozen-lockfile'` | Additional pnpm install arguments |
1161
- | `fetch-depth` | number | `0` | Git fetch depth for checkout |
1162
-
1163
- **Outputs:**
1164
-
1165
- | Output | Description |
1166
- |--------|-------------|
1167
- | `release_validation` | `'true'` when release validation passes |
1168
- | `changelog_status` | Changelog status: `updated`, `skipped`, or `missing` |
1169
- | `skip_changelog` | `'true'` when `[skip-changelog]` detected in commits |
1170
- | `conventional_commits` | `'true'` when conventional commits detected |
1171
- | `commit_messages` | Base64 encoded JSON array of analyzed commit messages |
1172
- | `changed_files` | Base64 encoded JSON array of changed files |
1173
-
1174
- **Example usage in your project:**
1175
-
1176
- ```yaml
1177
- # .github/workflows/validate-pr.yml
1178
- name: PR Validation
1179
-
1180
- on:
1181
- pull_request:
1182
- types: [opened, synchronize, reopened]
1183
-
1184
- jobs:
1185
- validate:
1186
- uses: oorabona/release-it-preset/.github/workflows/reusable-verify.yml@main
1187
- with:
1188
- node-version: '20'
1189
- base-ref: origin/${{ github.base_ref }}
1190
- head-ref: ${{ github.sha }}
1191
- run-tests: true
1192
- secrets: inherit
1193
-
1194
- comment:
1195
- needs: validate
1196
- runs-on: ubuntu-latest
1197
- if: always()
1198
- permissions:
1199
- pull-requests: write
1200
- steps:
1201
- - uses: actions/github-script@v7
1202
- with:
1203
- script: |
1204
- const summary = `## 📋 PR Validation
1205
-
1206
- ${needs.validate.outputs.release_validation === 'true' ? '✅' : '⚠️'} Release validation
1207
- ${needs.validate.outputs.changelog_status === 'updated' ? '✅' : 'ℹ️'} Changelog: ${needs.validate.outputs.changelog_status}
1208
- ${needs.validate.outputs.conventional_commits === 'true' ? '✅' : 'ℹ️'} Conventional commits
1209
- `;
1210
-
1211
- github.rest.issues.createComment({
1212
- owner: context.repo.owner,
1213
- repo: context.repo.repo,
1214
- issue_number: context.issue.number,
1215
- body: summary
1216
- });
1217
- ```
1218
-
1219
- #### 🔄 `build-dist.yml` - Build Compiled Distribution
1220
-
1221
- Builds TypeScript sources to `dist/` and uploads as artifact for reuse in other jobs.
1222
-
1223
- **When to use:** When you need compiled outputs across multiple jobs without rebuilding.
1224
-
1225
- **Inputs:**
1226
-
1227
- | Input | Type | Default | Description |
1228
- |-------|------|---------|-------------|
1229
- | `artifact_name` | string | `'dist-build'` | Name for the uploaded dist artifact |
1230
- | `ref` | string | (current) | Optional git ref to checkout before building |
1231
-
1232
- **Outputs:**
1233
-
1234
- | Output | Description |
1235
- |--------|-------------|
1236
- | `artifact_name` | Name of the uploaded dist artifact |
1237
-
1238
- **Example usage in your project:**
1239
-
1240
- ```yaml
1241
- # .github/workflows/ci.yml
1242
- jobs:
1243
- build:
1244
- uses: oorabona/release-it-preset/.github/workflows/build-dist.yml@main
1245
- with:
1246
- artifact_name: my-dist
1247
- ref: ${{ github.sha }}
1248
-
1249
- test:
1250
- needs: build
1251
- runs-on: ubuntu-latest
1252
- steps:
1253
- - uses: actions/checkout@v4
1254
- - uses: actions/download-artifact@v4
1255
- with:
1256
- name: ${{ needs.build.outputs.artifact_name }}
1257
- path: dist
1258
- - run: pnpm test
1259
- ```
1260
-
1261
- ### Workflow Reference
1262
-
1263
- #### Overview Table
1264
-
1265
- | Workflow | Type | Trigger | Purpose |
1266
- |----------|------|---------|---------|
1267
- | 🔄 [reusable-verify.yml](#-reusable-verifyyml---pr-validation--hygiene-checks) | Reusable | `workflow_call` | PR validation & hygiene checks |
1268
- | 🔄 [build-dist.yml](#-build-distyml---build-compiled-distribution) | Reusable | `workflow_call` | Build TypeScript distribution |
1269
- | ⚙️ [ci.yml](#1-️-ci-github-workflowsciyml) | Standalone | Push, PR, Manual | Continuous Integration |
1270
- | ✅ [validate-pr.yml](#2--validate-pr-github-workflowsvalidate-pryml) | Standalone | PR | Pull request validation |
1271
- | 🚨 [hotfix.yml](#3--hotfix-release-github-workflowshotfixyml) | Manual | `workflow_dispatch` | Emergency hotfix releases |
1272
- | 🔄 [retry-publish.yml](#4--retry-publish-github-workflowsretry-publishyml) | Manual | `workflow_dispatch` | Retry failed publishing |
1273
- | ⚠️ [republish.yml](#5-️-republish-exceptional-github-workflowsrepublishyml) | Manual | `workflow_dispatch` | Republish existing version |
1274
- | 📦 [publish.yml](#6--publish-github-workflowspublishyml) | Reusable | Tag push, `workflow_call` | Automated publishing |
1275
-
1276
- You can copy these workflows into your own repository (adjusting names, branches, and secrets to match your context). They work with the release-it-preset CLI defaults.
1277
-
1278
- #### 1. ⚙️ **CI** (`.github/workflows/ci.yml`)
1279
-
1280
- **Triggers:**
1281
- - Push to `main`
1282
- - Pull Requests to `main`
1283
- - Manual (`workflow_dispatch`)
1284
-
1285
- **Jobs:**
1286
- - `build-dist` - Builds compiled distribution using reusable workflow
1287
- - `tests` - Runs unit tests with coverage
1288
- - `test-cli` - Tests all CLI commands (help, check, validate, init)
1289
- - `release` - Manual release creation (workflow_dispatch only)
1290
-
1291
- **Manual Release:**
1292
- ```bash
1293
- # Go to Actions → CI → Run workflow
1294
- # Select increment type: patch, minor, or major
1295
- ```
1296
-
1297
- **Secrets required:**
1298
- - `NPM_TOKEN` - npm automation token (for release job)
1299
- - `CODECOV_TOKEN` - Codecov upload token (optional)
1300
-
1301
- #### 2. ✅ **Validate PR** (`.github/workflows/validate-pr.yml`)
1302
-
1303
- **Triggers:**
1304
- - Pull Request `opened`, `synchronize`, `reopened`
1305
- - Can be called as reusable workflow (`workflow_call`)
1306
-
1307
- **Jobs:**
1308
- - `validate` - Uses `reusable-verify.yml` for hygiene checks
1309
- - `summarize` - Posts validation summary comment on PR
1310
-
1311
- **What it checks:**
1312
- - ✅ TypeScript compilation
1313
- - ✅ Release validation (with `--allow-dirty`)
1314
- - ✅ CHANGELOG.md updates (or `[skip-changelog]` marker)
1315
- - ✅ Conventional commits format
1316
- - ✅ Commit messages analysis
1317
-
1318
- **Permissions required:**
1319
- ```yaml
1320
- permissions:
1321
- contents: read
1322
- pull-requests: write # For posting comments
1323
- ```
1324
-
1325
- **No secrets required** (uses `GITHUB_TOKEN` automatically)
1326
-
1327
- #### 3. 🚨 **Hotfix Release** (`.github/workflows/hotfix.yml`)
1328
-
1329
- **Trigger:** Manual (`workflow_dispatch`)
1330
-
1331
- **Inputs:**
1332
-
1333
- | Input | Type | Required | Default | Description |
1334
- |-------|------|----------|---------|-------------|
1335
- | `increment` | choice | ✅ | `patch` | Version bump: `patch` or `minor` |
1336
- | `commit` | string | ❌ | latest | Specific commit SHA to release |
1337
- | `dry_run` | boolean | ❌ | `false` | Test without actual publishing |
1338
-
1339
- **Jobs:**
1340
- - `validate` - Validates TypeScript compilation and builds
1341
- - `hotfix` - Creates emergency hotfix release and publishes
1342
-
1343
- **What it does:**
1344
- 1. Validates code at specified commit
1345
- 2. Auto-generates changelog from recent commits
1346
- 3. Creates hotfix release (patch/minor bump)
1347
- 4. Pushes git tag
1348
- 5. **Publishes to npm with provenance**
1349
- 6. **Creates GitHub Release**
1350
-
1351
- **When to use:** Critical bugs needing immediate patch release
1352
-
1353
- **Permissions required:**
1354
- ```yaml
1355
- permissions:
1356
- contents: write # For git operations
1357
- id-token: write # For npm provenance
1358
- ```
1359
-
1360
- **Secrets required:**
1361
- - `NPM_TOKEN` - npm automation token
1362
- - `GITHUB_TOKEN` - Provided automatically
1363
-
1364
- #### 4. 🔄 **Retry Publish** (`.github/workflows/retry-publish.yml`)
1365
-
1366
- **Trigger:** Manual (`workflow_dispatch`)
1367
-
1368
- **Inputs:**
1369
-
1370
- | Input | Type | Required | Default | Description |
1371
- |-------|------|----------|---------|-------------|
1372
- | `tag_name` | string | ❌ | latest tag | Git tag to republish |
1373
- | `npm_only` | boolean | ❌ | `false` | Publish to npm only (skip GitHub Release) |
1374
- | `github_only` | boolean | ❌ | `false` | Create GitHub Release only (skip npm) |
1375
-
1376
- **Jobs:**
1377
- - `determine-tag` - Validates and determines which tag to publish
1378
- - `build-dist` - Builds distribution using reusable workflow
1379
- - `retry-publish` - Republishes to npm and/or GitHub
1380
-
1381
- **What it does:**
1382
- 1. Verifies git tag exists
1383
- 2. Runs pre-flight checks (`retry-publish.js` script)
1384
- 3. Republishes to selected destination(s)
1385
- 4. Uses existing changelog for release notes
1386
-
1387
- **When to use:** Previous publish failed (network issue, auth problem, etc.)
1388
-
1389
- **Permissions required:**
1390
- ```yaml
1391
- permissions:
1392
- contents: write # For GitHub releases
1393
- id-token: write # For npm provenance
1394
- ```
1395
-
1396
- **Secrets required:**
1397
- - `NPM_TOKEN` - npm automation token (if npm publish enabled)
1398
- - `GITHUB_TOKEN` - Provided automatically
1399
-
1400
- #### 5. ⚠️ **Republish (EXCEPTIONAL)** (`.github/workflows/republish.yml`)
1401
-
1402
- **Trigger:** Manual (`workflow_dispatch`)
1403
-
1404
- **⚠️ DANGER:** Moves existing git tag (breaks semver immutability)
1405
-
1406
- **Inputs:**
1407
-
1408
- | Input | Type | Required | Description |
1409
- |-------|------|----------|-------------|
1410
- | `version` | string | ✅ | Version to republish (e.g., `1.2.3`) |
1411
- | `confirmation` | string | ✅ | Must type exactly `"I understand the risks"` |
1412
-
1413
- **Jobs:**
1414
- - `pre-flight-checks` - Validates confirmation, version format, and tag existence
1415
- - `build-dist` - Builds distribution using reusable workflow
1416
- - `validate` - Validates TypeScript compilation
1417
- - `republish` - Moves git tag and updates GitHub release
1418
-
1419
- **What it does:**
1420
- 1. **Pre-flight safety checks:**
1421
- - Validates confirmation phrase
1422
- - Checks version format
1423
- - Verifies tag exists
1424
- - Displays warning message
1425
- - **10-second safety delay** ⏰
1426
- 2. Validates code compilation
1427
- 3. **Moves git tag to current commit** (⚠️ breaks immutability)
1428
- 4. Updates changelog for current version
1429
- 5. Updates GitHub Release
1430
-
1431
- > **Note:** npm is not republished — npm immutability (since 2016) prevents republishing an existing version. To redirect a dist-tag, use `npm dist-tag add`. To retry a failed publish, use the `retry-publish` preset.
1432
-
1433
- **When to use:** ONLY for exceptional emergencies where a published version must be moved to a different commit (e.g. a broken tag pointing to the wrong SHA)
1434
-
1435
- **Permissions required:**
1436
- ```yaml
1437
- permissions:
1438
- contents: write # For git tag operations
1439
- ```
1440
-
1441
- **Secrets required:**
1442
- - `GITHUB_TOKEN` - Provided automatically
1443
-
1444
- **Concurrency:** Prevents parallel republish operations for same version
1445
-
1446
- #### 6. 📦 **Publish** (`.github/workflows/publish.yml`)
1447
-
1448
- **Triggers:**
1449
- - Tag push matching `v*` pattern
1450
- - Can be called as reusable workflow (`workflow_call`)
1451
-
1452
- **Inputs (for `workflow_call`):**
1453
-
1454
- | Input | Type | Required | Description |
1455
- |-------|------|----------|-------------|
1456
- | `tag` | string | ❌ | Override tag (auto-detected from `github.ref_name`) |
1457
-
1458
- **Jobs:**
1459
- - `build-dist` - Builds distribution using reusable workflow
1460
- - `publish` - Updates GitHub release and publishes to npm
1461
-
1462
- **What it does:**
1463
- 1. Builds compiled distribution
1464
- 2. Runs `release-it-preset retry-publish --ci`
1465
- 3. Creates/updates GitHub Release with changelog
1466
- 4. Publishes to npm with provenance attestation
1467
-
1468
- **When it runs:** Automatically triggered when a tag is pushed (e.g., by `default` or `hotfix` workflows)
1469
-
1470
- **Permissions required:**
1471
- ```yaml
1472
- permissions:
1473
- contents: write # For GitHub releases
1474
- id-token: write # For npm provenance attestation
1475
- ```
1476
-
1477
- **Secrets required (for `workflow_call`):**
1478
- - `NPM_TOKEN` - npm automation token (must be passed explicitly)
1479
-
1480
- **Secrets required (for tag push):**
1481
- - `NPM_TOKEN` - npm automation token (repository secret)
1482
- - `GITHUB_TOKEN` - Provided automatically
1483
-
1484
- **Environment variables set:**
1485
- - `GITHUB_RELEASE=true` - Enables GitHub release creation
1486
- - `NPM_PUBLISH=true` - Enables npm publishing
1487
-
1488
- ---
1489
-
1490
- ### Workflows Summary Diagram
1491
-
1492
- ```mermaid
1493
- graph TB
1494
- subgraph "Reusable Workflows"
1495
- RV[🔄 reusable-verify.yml<br/>PR validation & hygiene]
1496
- BD[🔄 build-dist.yml<br/>Build TypeScript dist]
1497
- end
1498
-
1499
- subgraph "Development Flow"
1500
- PR[Pull Request] --> VPR[✅ validate-pr.yml]
1501
- VPR --> RV
1502
- VPR --> Comment[Post PR comment]
1503
- end
1504
-
1505
- subgraph "Release Flow"
1506
- Manual[Manual Trigger] --> CI[⚙️ ci.yml]
1507
- CI --> BD
1508
- CI --> Tag[Create Tag]
1509
- Tag --> PUB[📦 publish.yml]
1510
- PUB --> BD
1511
- PUB --> NPM[npm publish]
1512
- PUB --> GH[GitHub Release]
1513
- end
1514
-
1515
- subgraph "Emergency Flow"
1516
- Critical[Critical Bug] --> HF[🚨 hotfix.yml]
1517
- HF --> BD
1518
- HF --> Tag
1519
- end
1520
-
1521
- subgraph "Recovery Flow"
1522
- Failed[Failed Publish] --> RP[🔄 retry-publish.yml]
1523
- RP --> BD
1524
- RP --> Decision{Retry What?}
1525
- Decision -->|npm only| NPM
1526
- Decision -->|GitHub only| GH
1527
- Decision -->|Both| Both[npm + GitHub]
1528
- end
1529
-
1530
- style RV fill:#e1f5fe
1531
- style BD fill:#e1f5fe
1532
- style VPR fill:#c8e6c9
1533
- style CI fill:#fff9c4
1534
- style HF fill:#ffccbc
1535
- style RP fill:#b2ebf2
1536
- style PUB fill:#d1c4e9
1537
- ```
1538
-
1539
- ## Best Practices
1540
-
1541
- 1. **Use conventional commits** - Enables automatic changelog generation
1542
- 2. **Keep [Unreleased] updated** - Run `pnpm release-it-preset update` regularly or before releases
1543
- 3. **Validate before releasing** - Run `pnpm release-it-preset validate` to catch issues early
1544
- 4. **Test releases** - Use `--dry-run` flag to test without publishing
1545
- 5. **Protect main branch** - Require PR reviews before merging
1546
- 6. **Use CI for publishing** - Let GitHub Actions handle GitHub releases and npm publishing with provenance
1547
- 7. **Local runs are for prep** - Keep local runs focused on changelog, versioning, and tagging unless you explicitly opt in to publish
1548
-
1549
- ## Security
1550
-
1551
- This preset implements OWASP security best practices:
1552
-
1553
- ### Input Validation
1554
-
1555
- All CLI inputs are validated before execution:
1556
- - **Whitelist validation**: Config names and commands are validated against allowed lists
1557
- - **Argument sanitization**: All arguments are checked for dangerous characters (`;`, `&`, `|`, `` ` ``, `$()`, etc.)
1558
- - **Path traversal protection**: File paths are validated to prevent directory traversal attacks
1559
-
1560
- ### Command Injection Prevention
1561
-
1562
- - All `spawn()` calls use `shell: false` to prevent command injection
1563
- - Arguments are passed as arrays, not concatenated strings
1564
- - No user input is ever executed in a shell context
1565
-
1566
- ### Architecture
1567
-
1568
- The preset follows SOLID principles:
1569
- - **Single Responsibility**: Each module has one clear purpose
1570
- - **DRY**: Shared configuration builders eliminate code duplication
1571
- - **Dependency Inversion**: User configs have priority over preset defaults
1572
-
1573
- All 213 unit tests verify functionality and security boundaries.
1574
-
1575
- ## Troubleshooting
1576
-
1577
- ### Changelog not updating
1578
-
1579
- Run the update command:
1580
- ```bash
1581
- pnpm release-it-preset update
1582
- ```
1583
-
1584
- ### GitHub releases failing
1585
-
1586
- Ensure you have a `GITHUB_TOKEN` with `repo` scope and opt in to GitHub releases:
1587
- ```bash
1588
- GITHUB_RELEASE=true GITHUB_TOKEN=your_token pnpm release-it-preset default
1589
- ```
1590
-
1591
- Or use GitHub CLI authentication:
1592
- ```bash
1593
- gh auth login
1594
- pnpm release-it-preset default
1595
- ```
1596
-
1597
- ### npm publish failing in CI
1598
-
1599
- Check that:
1600
- 1. `NPM_TOKEN` secret is set in repository settings
1601
- 2. Token is an **automation token** (not a publish token)
1602
- 3. Token has permission to publish the package
1603
- 4. Package name is available (not already taken)
1604
-
1605
- Remember to export `NPM_PUBLISH=true` (and `GITHUB_RELEASE=true` if you expect a GitHub release) in the workflow or shell where you invoke release-it.
1606
-
1607
- Test locally:
1608
- ```bash
1609
- pnpm release-it-preset check # Check npm auth status
1610
- pnpm npm whoami # Verify authentication
1611
- ```
1612
-
1613
- ### Validation failing
1614
-
1615
- Run check command to see detailed status:
1616
- ```bash
1617
- pnpm release-it-preset check
1618
- ```
1619
-
1620
- Common issues:
1621
- - Working directory not clean → commit or stash changes, or use `--allow-dirty`
1622
- - [Unreleased] section empty → run `pnpm release-it-preset update`
1623
- - Not on required branch → checkout correct branch or update `GIT_REQUIRE_BRANCH`
1624
-
1625
- ### `npm error Version not changed`
1626
-
1627
- This can appear if you interrupt a release, tweak `CHANGELOG.md`, then retry with the same version. The preset automatically passes `--allow-same-version` to `npm version`, so simply re-run `pnpm release` (or `pnpm release-it-preset default --retry`) and select the same version—`npm` will no longer abort.
1628
-
1629
- ## Exit codes
1630
-
1631
- The CLI follows this convention (stable from v1.0.0 onward):
1632
-
1633
- | Code | Meaning | Examples |
1634
- |---|---|---|
1635
- | `0` | Success | Command completed; for `doctor`, `READY` or `WARNINGS` status |
1636
- | `1` | General failure | Unhandled error, validation failure, `doctor` `BLOCKED` status |
1637
- | `2` | Precondition failure (CI-friendly) | `validate` reports CHANGELOG missing or `[Unreleased]` empty |
1638
- | `3..9` | **Reserved** | Not currently emitted; reserved for future contract additions |
1639
-
1640
- In CI scripts, distinguish `exit 1` (try-again-friendly) from `exit 2` (precondition not met — require operator action) when chaining commands.
1641
-
1642
- ## Public API
1643
-
1644
- The full **stable surface** (CLI commands, environment variables, config exports, GHA workflow inputs, exit codes) is documented in [`docs/PUBLIC_API.md`](docs/PUBLIC_API.md). Items not listed there are internal and may change in any version.
116
+ By participating you agree to abide by the [Code of Conduct](CODE_OF_CONDUCT.md) (Contributor Covenant 2.1).
1645
117
 
1646
118
  ## License
1647
119
 
1648
- MIT — see [`LICENSE`](LICENSE).
1649
-
1650
- ## Contributing
1651
-
1652
- PRs and issues welcome. Please read [`CONTRIBUTING.md`](CONTRIBUTING.md) before opening a pull request — it covers the Conventional Commits requirement, branch prefixes, the pre-PR checklist, and the testing conventions. By participating you agree to abide by the [Code of Conduct](CODE_OF_CONDUCT.md) (Contributor Covenant 2.1).
1653
-
1654
- For security concerns, please email `olivier.orabona@gmail.com` directly rather than opening a public issue. See [`SECURITY.md`](SECURITY.md) for the disclosure policy.
1655
-
120
+ MIT — see [LICENSE](LICENSE).