Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .github/workflows/cut-release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: Cut Release

# CI replacement for running ./release.sh on a laptop. Kick it off from the
# Actions tab ("Cut Release" → Run workflow) with the version to release.
# Actions tab ("Cut Release" → Run workflow). Leave the version empty to cut
# the next patch release; give an explicit version to pin it.
#
# This runs release.sh itself — one source of truth: bump package.json →
# typecheck (against the live prod OpenAPI spec) + lint + test + build →
Expand All @@ -14,12 +15,16 @@ name: Cut Release
# pushed with GITHUB_TOKEN do not trigger other workflows, so release.yml
# would never fire.

run-name: >-
Cut Release — ${{ inputs.version || 'next patch' }}${{ inputs.dry_run && ' (dry run)' || '' }}

on:
workflow_dispatch:
inputs:
version:
description: 'Version to release (no v prefix, e.g. 0.3.0)'
required: true
description: 'Version to release (leave empty for the next patch; no v prefix, e.g. 0.3.0)'
required: false
default: ''
type: string
dry_run:
description: 'Dry run: bump + run all checks, but do not commit/tag/push'
Expand Down Expand Up @@ -86,7 +91,8 @@ jobs:

# release.sh runs the full gate before touching git: typecheck (codegen
# against the live prod spec — hard gate, the polylane.com installer
# serves the latest release), lint, test, build.
# serves the latest release), lint, test, build. An empty VERSION makes
# release.sh bump the next patch version; the log shows the result.
- name: Run release.sh
env:
VERSION: ${{ inputs.version }}
Expand Down
30 changes: 20 additions & 10 deletions release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
# Cut a new release of the polylane CLI.
#
# ./release.sh 0.1.0
# ./release.sh # prompts for version (interactive only)
# ./release.sh # prompts for version (interactive only);
# # empty answer = next patch version
#
# Steps: bump package.json → typecheck + lint + test + build → commit → tag →
# push. `release.yml` takes over once the v* tag reaches origin.
#
# CI mode (CI env var set, as in GitHub Actions): no prompts — the version
# argument is required and the branch must be main. Run via the "Cut Release"
# workflow (.github/workflows/cut-release.yml) instead of a laptop.
# CI mode (CI env var set, as in GitHub Actions): no prompts — no version
# argument means "bump the next patch version" and the branch must be main.
# Run via the "Cut Release" workflow (.github/workflows/cut-release.yml)
# instead of a laptop.
#
# RELEASE_DRY_RUN=1 runs the version bump and all checks, then reverts the
# bump and exits before committing, tagging, or pushing.
Expand All @@ -29,16 +31,24 @@ if [ -n "$(git status --porcelain)" ]; then
die "working tree is dirty — commit or stash first"
fi

# Version: arg or prompt (never prompt in CI).
# Version: arg or prompt (never prompt in CI). Empty means "next patch".
VERSION="${1:-}"
if [ -z "$VERSION" ]; then
if [ -n "${CI:-}" ]; then
die "version argument required in CI: ./release.sh <version>"
fi
read -rp "Release version (no v prefix, e.g. 0.1.0): " VERSION
if [ -z "$VERSION" ] && [ -z "${CI:-}" ]; then
read -rp "Release version (no v prefix, e.g. 0.1.0; empty = next patch): " VERSION
fi
VERSION="${VERSION#v}"

# No version given: compute the next patch from package.json, matching what
# `npm version patch` would produce (a prerelease is promoted to its release).
if [ -z "$VERSION" ]; then
CURRENT="$(node -p 'require("./package.json").version')"
VERSION="$(node -p '
const m = process.argv[1].match(/^(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]*)?/);
m[4] ? `${m[1]}.${m[2]}.${m[3]}` : `${m[1]}.${m[2]}.${Number(m[3]) + 1}`
' "$CURRENT")" || die "could not compute next patch version from '$CURRENT'"
info "no version given — next patch: $CURRENT → $VERSION"
fi

# Reject anything that isn't semver x.y.z[-prerelease][+build].
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
die "invalid semver: '$VERSION' (expected x.y.z)"
Expand Down
Loading