name: Release on: push: branches: - master workflow_dispatch: inputs: source_ref: description: Commit SHA, branch, or tag to publish as stable required: true type: string default: master stable_date: description: Enter a UTC date in YYYY-MM-DD format, for example 2026-03-18. Do not enter a version string. The workflow will resolve that date to a stable version such as 2026.318.0, then 2026.318.1 for the next same-day stable. required: false type: string dry_run: description: Preview the stable release without publishing required: true type: boolean default: false concurrency: group: release-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: false jobs: verify_canary: if: github.event_name == 'push' runs-on: ubuntu-latest timeout-minutes: 30 permissions: contents: read steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9.15.4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Typecheck run: pnpm -r typecheck - name: Run tests run: pnpm test:run - name: Build run: pnpm build publish_canary: if: github.event_name == 'push' needs: verify_canary runs-on: ubuntu-latest timeout-minutes: 45 environment: npm-canary permissions: contents: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9.15.4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Restore tracked install-time changes run: git checkout -- pnpm-lock.yaml - name: Configure git author run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - name: Publish canary env: GITHUB_ACTIONS: "true" run: ./scripts/release.sh canary --skip-verify - name: Push canary tag run: | tag="$(git tag --points-at HEAD | grep '^canary/v' | head -1)" if [ -z "$tag" ]; then echo "Error: no canary tag points at HEAD after release." >&2 exit 1 fi git push origin "refs/tags/${tag}" verify_stable: if: github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest timeout-minutes: 30 permissions: contents: read steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ inputs.source_ref }} - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9.15.4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Typecheck run: pnpm -r typecheck - name: Run tests run: pnpm test:run - name: Build run: pnpm build preview_stable: if: github.event_name == 'workflow_dispatch' && inputs.dry_run needs: verify_stable runs-on: ubuntu-latest timeout-minutes: 45 permissions: contents: read steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ inputs.source_ref }} - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9.15.4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Dry-run stable release env: GITHUB_ACTIONS: "true" run: | args=(stable --skip-verify --dry-run) if [ -n "${{ inputs.stable_date }}" ]; then args+=(--date "${{ inputs.stable_date }}") fi ./scripts/release.sh "${args[@]}" publish_stable: if: github.event_name == 'workflow_dispatch' && !inputs.dry_run needs: verify_stable runs-on: ubuntu-latest timeout-minutes: 45 environment: npm-stable permissions: contents: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ inputs.source_ref }} - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9.15.4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Restore tracked install-time changes run: git checkout -- pnpm-lock.yaml - name: Configure git author run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - name: Publish stable env: GITHUB_ACTIONS: "true" run: | args=(stable --skip-verify) if [ -n "${{ inputs.stable_date }}" ]; then args+=(--date "${{ inputs.stable_date }}") fi ./scripts/release.sh "${args[@]}" - name: Push stable tag run: | tag="$(git tag --points-at HEAD | grep '^v' | head -1)" if [ -z "$tag" ]; then echo "Error: no stable tag points at HEAD after release." >&2 exit 1 fi git push origin "refs/tags/${tag}" - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} PUBLISH_REMOTE: origin run: | version="$(git tag --points-at HEAD | grep '^v' | head -1 | sed 's/^v//')" if [ -z "$version" ]; then echo "Error: no v* tag points at HEAD after stable release." >&2 exit 1 fi ./scripts/create-github-release.sh "$version"