# Release Process This document describes the complete release and delivery pipeline for node-liblzma. ## Overview ```mermaid graph LR subgraph "Standard Release" R[release.yml
bump, tag, changelog] --> BA[build-artifacts.yml
Linux, macOS, Windows] BA --> P[publish.yml
3 npm packages + OIDC] end subgraph "Emergency" MR[manual-release.yml
existing tag] --> BA2[build-artifacts.yml] BA2 --> P2[publish.yml] end subgraph "Standalone" PR[pre-release.yml
alpha / beta / rc] end style R fill:#4CAF50,color:#fff style MR fill:#FF9800,color:#fff style PR fill:#2196F3,color:#fff ``` ## Standard Release **Workflow:** `release.yml` (manual trigger via GitHub Actions UI) This is the primary release path. It handles everything end-to-end. > **First-time bootstrap (only once per new package).** OIDC trusted publishing requires the package to already exist on npm before `publish.yml` can publish it via the workflow. For a brand-new package (e.g. when introducing `@oorabona/nxz`), the maintainer must run a one-time manual publish locally that mirrors `publish.yml`'s pack-then-publish flow: > > ```bash > # From the repo root > pnpm install --frozen-lockfile > pnpm build && pnpm -r --filter './packages/*' run build # root + all workspace pkgs (a workspace pkg's build depends on root lib/) > TARBALL=$(cd packages/ && pnpm pack --pack-destination /tmp | tail -1) > npm publish "$TARBALL" --access public # may prompt for OTP > ``` > > The `pnpm pack` step is essential: it rewrites `workspace:` protocol dependencies to concrete versions in the tarball. A bare `npm publish` from the package directory would publish broken metadata. After the publish succeeds, configure the trusted publisher on npmjs.com (`Repository: oorabona/node-liblzma`, `Workflow: publish.yml`). Subsequent releases of that package then flow through `release.yml` → OIDC normally. ```mermaid sequenceDiagram participant M as Maintainer participant R as release.yml participant BA as build-artifacts.yml participant P as publish.yml participant NPM as npm registry M->>R: workflow_dispatch (patch/minor/major) R->>R: release-it: bump version + CHANGELOG R->>R: GPG-sign commit + tag R->>R: Push to master R->>R: Create GitHub Release R->>BA: Build prebuilds (3 platforms) BA-->>R: Upload to GitHub Release assets R->>P: gh workflow run publish.yml P->>NPM: Publish node-liblzma (OIDC) P->>NPM: Publish tar-xz (OIDC) P->>NPM: Publish @oorabona/nxz (OIDC) ``` ### Inputs | Input | Type | Description | |-------|------|-------------| | `increment` | choice: patch / minor / major | Semver bump type | | `skip_npm` | boolean | Skip npm publish (dry run) | ### Steps 1. **Bump version** — `release-it-preset` updates `package.json` and `CHANGELOG.md` from conventional commits 2. **GPG-sign commit** — Version bump committed with GPG signature (key: `B98806DCD4E29D4D`) 3. **Create tag** — GPG-signed tag `vX.Y.Z` 4. **Push** — Commit and tag pushed to `master` 5. **GitHub Release** — Created automatically with generated release notes 6. **Build prebuilds** — Cross-platform native binaries via `build-artifacts.yml` 7. **Publish to npm** — All 3 packages via `publish.yml` (OIDC provenance) ### How to run 1. Go to **Actions** → **Release** → **Run workflow** 2. Select the semver increment (patch / minor / major) 3. Optionally check "Skip npm publish" for a dry run 4. Click **Run workflow** ## Emergency Release **Workflow:** `manual-release.yml` (manual trigger) Use this when a tag already exists but the release pipeline failed partway through (e.g., GitHub Release wasn't created, prebuilds weren't built, or npm publish failed). ### When to use - `release.yml` partially failed after creating the tag - You created a tag manually and need to complete the release - You need to re-run build + publish for an existing tag ### Inputs | Input | Type | Description | |-------|------|-------------| | `tag` | string | Existing git tag (e.g., `v3.2.0`) | | `skip_npm` | boolean | Skip npm publish | ### Steps 1. Checks out the given tag 2. Creates GitHub Release 3. Builds prebuilds for all platforms 4. Triggers `publish.yml` ## Pre-release **Workflow:** `pre-release.yml` (manual trigger) For publishing alpha, beta, or release candidate versions. ### Inputs | Input | Type | Description | |-------|------|-------------| | `prerelease-type` | choice: alpha / beta / rc | npm dist-tag | | `version` | string | Full version (e.g., `3.3.0-alpha.1`) | ### Steps 1. Runs tests and type-check 2. Builds N-API prebuilt binaries (Node-version-independent) for linux-x64, macOS-arm64, win32-x64 3. Publishes to npm with the appropriate dist-tag (`--tag alpha`) 4. Creates GitHub pre-release ### Installing a pre-release ```bash npm install node-liblzma@alpha # or @beta, @rc ``` ## Recovery If npm publish fails partway through, simply re-run `publish.yml` manually via **Actions → Publish → Run workflow** with the same tag. The workflow is idempotent — already-published packages are skipped. ## npm Packages Three packages are published in dependency order: | # | Package | npm name | Description | |---|---------|----------|-------------| | 1 | root | `node-liblzma` | Core XZ/LZMA2 bindings (native + WASM) | | 2 | packages/tar-xz | `tar-xz` | tar.xz streaming library | | 3 | packages/nxz | `@oorabona/nxz` | CLI tool for XZ compression | ### Publishing details - **Authentication:** OIDC trusted publishing (no npm token needed) - **Node.js:** v24+ required in `publish.yml` (npm >= 11.5.1 for OIDC) - **Provenance:** All packages published with `--provenance` attestation - **Idempotent:** Already-published versions are skipped (safe re-runs) - **Workspace protocol:** `pnpm pack` resolves `workspace:` dependencies before `npm publish` ## Supporting Workflows | Workflow | Trigger | Purpose | |----------|---------|---------| | `ci.yml` | Push, PR, nightly | Tests, lint, coverage. Smart smoke/full matrix selection | | `build-artifacts.yml` | Called by release/manual-release | Cross-platform prebuilds (Linux, macOS, Windows × x64) | | `check-xz-updates.yml` | Weekly (Monday 3 AM UTC) | Monitors upstream XZ Utils, auto-PRs compatible updates | | `docs.yml` | Release published, doc changes | Builds and deploys docs to GitHub Pages | | `build-wasm.yml` | WASM file changes | Isolated WASM build with size gate (< 100KB gzipped) | ### check-xz-updates.yml Runs weekly to detect new XZ Utils releases: 1. Queries GitHub API for latest XZ release 2. Compares with `xz-version.json` 3. If new version: runs full test suite against it 4. If tests pass: creates PR with auto-merge enabled 5. If tests fail: creates issue for manual review ## Secrets & Prerequisites | Secret | Required | Used in | Purpose | |--------|----------|---------|---------| | `GPG_PRIVATE_KEY` | Yes | release, check-xz-updates | GPG-sign commits and tags | | `GITHUB_TOKEN` | Auto | All workflows | GitHub API access | | `CODECOV_TOKEN` | Yes | ci (coverage) | Upload coverage reports | ### OIDC Trusted Publishing Normal releases use npm OIDC trusted publishing — no npm token is stored as a secret. This requires: - `id-token: write` permission in the workflow - `registry-url: 'https://registry.npmjs.org'` in setup-node - Node.js 24+ (npm >= 11.5.1) - Each package must be configured for trusted publishing on npmjs.com ### GPG Signing All release commits and tags are signed with GPG key `B98806DCD4E29D4D`. The `crazy-max/ghaction-import-gpg` action configures git to use the key automatically. Committer identity: `Olivier ORABONA `. ## Troubleshooting ### OIDC publish fails - Verify `id-token: write` permission is set - Ensure Node.js version is 24+ (npm OIDC requires >= 11.5.1) - Publish workflow must be triggered via `workflow_dispatch` (not `workflow_call`) — the OIDC token includes the workflow filename, and `workflow_call` makes the *caller* appear in the token instead ### Prebuilds missing from npm package - Verify `prebuilds/` is listed in `package.json` `"files"` array - Check that `build-artifacts.yml` completed successfully and uploaded assets to the GitHub Release - Run `npm pack --dry-run | grep prebuilds` to verify tarball contents ### GITHUB_TOKEN doesn't trigger other workflows Actions performed by `GITHUB_TOKEN` don't trigger other GitHub workflows. This is why: - `release.yml` uses `gh workflow run` (creates a new workflow_dispatch event) instead of relying on release events - `manual-release.yml` exists as a fallback for when automated chains break