153 lines
6.6 KiB
YAML
153 lines
6.6 KiB
YAML
name: Release
|
|
|
|
# Two-stage release pipeline.
|
|
#
|
|
# This public repo is responsible for version bumps, tagging, and creating
|
|
# the GitHub release. npm publishing is handled by a private cron job (AO)
|
|
# that polls GitHub releases and publishes when a new tag is ahead of the
|
|
# current npm version.
|
|
#
|
|
# No NPM_TOKEN or publisher dispatch secrets are needed in this repo.
|
|
# The only secret used is GITHUB_TOKEN (automatic).
|
|
#
|
|
# See CONTRIBUTING.md → "Release architecture" for the full picture.
|
|
|
|
on:
|
|
workflow_run:
|
|
# Depends on the workflow named "CI" in .github/workflows/ci.yml — if
|
|
# you rename that file or change its `name:` field, update this string
|
|
# too. GitHub matches by name (not filename) and silently no-ops on
|
|
# mismatch — so a rename here will mean releases never trigger again.
|
|
workflows: [CI]
|
|
types: [completed]
|
|
branches: [main]
|
|
|
|
concurrency:
|
|
group: release
|
|
cancel-in-progress: false
|
|
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
release:
|
|
name: Release
|
|
runs-on: ubuntu-latest
|
|
if: >-
|
|
github.event.workflow_run.conclusion == 'success' &&
|
|
github.event.workflow_run.event == 'push' &&
|
|
github.event.workflow_run.head_branch == 'main'
|
|
steps:
|
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
|
with:
|
|
ref: ${{ github.event.workflow_run.head_sha }}
|
|
fetch-depth: 0
|
|
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
|
|
with:
|
|
node-version: 20
|
|
cache: pnpm
|
|
# No `registry-url`: this workflow does not publish to npm.
|
|
- run: echo "HUSKY=0" >> $GITHUB_ENV
|
|
- run: pnpm install --frozen-lockfile
|
|
- run: pnpm -r build
|
|
# Pre-publish guard: catches the case where a publishable package has a
|
|
# workspace:* runtime dep on a `private: true` package — pnpm would
|
|
# rewrite the dep on publish to a version that doesn't exist on npm,
|
|
# breaking `npm install -g @aoagents/ao`. Still runs here so the
|
|
# public repo blocks a malformed version bump before it reaches npm.
|
|
- run: node scripts/check-publishable-deps.mjs
|
|
|
|
# changesets/action manages the "Version Packages" PR — when there
|
|
# are pending changesets it opens/updates the PR; when there are
|
|
# none (i.e. that PR was just merged) it would normally invoke the
|
|
# `publish:` command. We deliberately omit `publish:` so the action
|
|
# never runs `changeset publish`. npm publishing is handled by a
|
|
# private cron that detects the GitHub release.
|
|
- uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b
|
|
id: changesets
|
|
with:
|
|
version: pnpm changeset version
|
|
title: "chore: version packages"
|
|
commit: "chore: version packages"
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
# Determine release state. Each downstream step (tag push, GH
|
|
# release creation) is gated on its own piece of state so the
|
|
# workflow is idempotent and recovers cleanly on re-run after a
|
|
# partial failure.
|
|
#
|
|
# `is_release_commit` is the crucial signal: it filters out
|
|
# regular commits to main (which also have `hasChangesets ==
|
|
# 'false'` but should NOT trigger a publish). We detect a
|
|
# version-bump commit by comparing the umbrella package's
|
|
# version against its value in the parent commit — a Version
|
|
# Packages merge changes that version, a regular commit does not.
|
|
# The umbrella `@aoagents/ao` is the canonical version source for
|
|
# the `vX.Y.Z` tag scheme and is part of the linked group, so
|
|
# any release that bumps the cohort will bump this file.
|
|
- name: Determine release state
|
|
id: state
|
|
if: steps.changesets.outputs.hasChangesets == 'false'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
version=$(node -p "require('./packages/ao/package.json').version")
|
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
|
|
prev_version=""
|
|
if git rev-parse HEAD^ >/dev/null 2>&1; then
|
|
prev_version=$(git show HEAD^:packages/ao/package.json 2>/dev/null | jq -r .version 2>/dev/null || echo "")
|
|
fi
|
|
if [ -n "$prev_version" ] && [ "$prev_version" != "$version" ]; then
|
|
echo "is_release_commit=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "is_release_commit=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
if git ls-remote --tags --exit-code origin "refs/tags/v$version" >/dev/null 2>&1; then
|
|
echo "tag_on_remote=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "tag_on_remote=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
if gh release view "v$version" --json tagName >/dev/null 2>&1; then
|
|
echo "release_exists=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "release_exists=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
# Push the umbrella `vX.Y.Z` tag only if this is a fresh
|
|
# version-bump commit AND the tag isn't already on the remote.
|
|
# Skipped on re-runs where the tag was pushed on a prior run
|
|
# (idempotent recovery).
|
|
#
|
|
# We deliberately skip `pnpm changeset tag`: it would create one
|
|
# tag per publishable package (~27 here) on every release, which
|
|
# creates partial-recovery conflicts on re-run when `git push --tags`
|
|
# tries to re-push existing per-package tags. The npm publisher
|
|
# only consumes the umbrella tag, so the per-package tags add no
|
|
# value.
|
|
- name: Tag versioned packages
|
|
if: steps.state.outputs.is_release_commit == 'true' && steps.state.outputs.tag_on_remote == 'false'
|
|
run: |
|
|
git tag "v${{ steps.state.outputs.version }}"
|
|
git push origin "v${{ steps.state.outputs.version }}"
|
|
|
|
# Public-facing GitHub release. Stable channel — not a prerelease.
|
|
# No `--target`: the `vX.Y.Z` tag is on the remote at the
|
|
# version-bump commit, and `gh release create` resolves the
|
|
# commitish from the existing tag. Avoids the race where another
|
|
# commit lands on main between the tag push and this step,
|
|
# pulling unrelated commits into the auto-generated release notes.
|
|
# Skipped if a release for this version already exists.
|
|
- name: Create GitHub release
|
|
if: steps.state.outputs.is_release_commit == 'true' && steps.state.outputs.release_exists == 'false'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
gh release create "v${{ steps.state.outputs.version }}" \
|
|
--generate-notes
|