Skip to content

release

release #228

Workflow file for this run

name: release
on:
workflow_dispatch:
inputs:
ref:
description: 'Git ref (branch, tag or commit) to build & publish from. Defaults to master for a normal release.'
required: false
default: master
publish_only:
description: 'Skip the version phase and only publish (from-package). Enable when back-publishing an already-versioned ref.'
type: boolean
required: false
default: false
jobs:
publish:
strategy:
matrix:
os: [ubuntu-22.04]
runs-on: ${{ matrix.os }}
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
# Fetch all history for all tags and branches
fetch-depth: 0
ref: ${{ inputs.ref || 'master' }}
token: ${{ secrets.BOT_GH_TOKEN }}
- name: 🧰 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org'
- name: Import bot's GPG key for signing commits
id: import-gpg
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.BOT_GPG_KEY }}
git_config_global: true
git_user_signingkey: true
git_commit_gpgsign: true
- name: 💽 Install dependencies
uses: ./.github/actions/install
with:
ignore-scripts: ${{ vars.DISABLE_NPM_SCRIPTS || 'false' }}
env:
YARN_ENABLE_IMMUTABLE_INSTALLS: false
- name: 🔨 Build
run: |
yarn build
# Phase 1 — decide versions, commit, tag, push to master, and create GitHub Releases.
# No-ops when there are no new conventional commits (e.g. re-running after a publish
# failure), so it never double-bumps an already-versioned release. Skipped entirely when
# publishing from a nominated ref or in publish_only mode: those refs are already versioned,
# and `lerna version --allow-branch master` would reject a non-master / detached checkout.
- name: 🏷️ Version
if: ${{ !inputs.publish_only && (inputs.ref == '' || inputs.ref == 'master') }}
run: |
if [ "$RELEASE_MODE" = "stable" ]; then yarn version:stable; else yarn version:rc; fi
env:
# Used for making a GitHub Release
GH_TOKEN: ${{ secrets.BOT_GH_TOKEN }}
RELEASE_MODE: ${{ vars.RELEASE_MODE }}
# Guard — refuse to publish a tree that isn't a genuine release state. `from-package`
# publishes whatever version sits in each package.json with no check that the source has
# stayed put since that version was tagged, so a mis-nominated `ref` could ship drifted
# source under an already-versioned number. Assert every publishable package's current
# version has a matching `<name>@<version>` tag AND its src+manifest at HEAD is identical
# to that tag. Passes trivially for a normal release (Phase 1 just created the tags at HEAD).
- name: 🔎 Verify tree aligns with release tags
run: |
node -e '
const fs=require("fs"),cp=require("child_process");
const bad=[];
for(const d of fs.readdirSync("packages")){
let p; try{p=JSON.parse(fs.readFileSync("packages/"+d+"/package.json","utf8"))}catch{continue}
if(p.private) continue;
const tag=p.name+"@"+p.version;
if(cp.spawnSync("git",["rev-parse","-q","--verify","refs/tags/"+tag]).status!==0){bad.push("no tag: "+tag);continue}
if(cp.spawnSync("git",["diff","--quiet",tag,"HEAD","--","packages/"+d+"/src","packages/"+d+"/package.json"]).status!==0)
bad.push("drift vs tag: "+tag);
}
if(bad.length){console.error("Refusing to publish — tree does not align with release tags:\n "+bad.join("\n "));process.exit(1)}
console.log("All publishable packages align with their release tags.");
'
# Phase 2 — publish to npm via `lerna publish from-package`, which queries the registry
# and publishes ONLY the versions in the checked-out tree that are not yet there. This makes
# the job idempotent and recoverable: re-running (optionally with publish_only=true) ships
# the missing packages without touching git history. To back-publish an older release, set
# `ref` to that release's tag/commit AND publish_only=true — BUT note the tree's own
# `@lerna-lite` must be a version that can actually publish (>=4 for the tar-7 line); older
# refs that predate that bump will crash here exactly as they did originally.
- name: 📦 Publish to npm
run: |
if [ "$RELEASE_MODE" = "stable" ]; then yarn publish:stable; else yarn publish:rc; fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}
RELEASE_MODE: ${{ vars.RELEASE_MODE }}