Skip to content

fix: id-only events updates last event id #100

fix: id-only events updates last event id

fix: id-only events updates last event id #100

Workflow file for this run

name: Release
on:
push:
# `v[0-9]+` are the maintenance branches (`v4` today) that supported older majors
# are patched from. The archived `v1.x`/`v2.x` branches predate the convention and
# deliberately do not match.
branches: [main, 'v[0-9]+']
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
release:
name: 'Release: Version PR or publish to npm'
# `workflow_dispatch` can be triggered on any ref, and npm's trusted publisher
# config pins the workflow file but not the branch. Without this, dispatching
# from a feature branch could version and publish from an unreviewed ref. The
# `Resolve release channel` step tightens this to the exact branch names, since
# expressions here cannot match a pattern.
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/v')
runs-on: ubuntu-latest
permissions:
contents: write # to push the version commit and tag, and create the GitHub release
pull-requests: write # to open and update the "Version Packages" pull request
id-token: write # to authenticate with npm through OIDC (trusted publishing)
steps:
# Runs before checkout so an unexpected ref never gets as far as building.
- name: Resolve release channel
id: channel
run: |
if [ "$GITHUB_REF_NAME" = 'main' ]; then
echo 'npm-tag=latest' >> "$GITHUB_OUTPUT"
elif [[ "$GITHUB_REF_NAME" =~ ^v[0-9]+$ ]]; then
echo "npm-tag=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
else
echo "::error::Refusing to release from '$GITHUB_REF_NAME'. Releases run from 'main' or a 'vN' maintenance branch."
exit 1
fi
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: lts/*
cache: npm
# Trusted publishing needs npm >= 11.5.1. Older versions silently skip OIDC
# rather than erroring, so don't rely on whatever npm the runner ships with.
# Pinned to the major so a new npm release can't land here unattended.
- run: npm install --global npm@12
- run: npm ci
- name: Create version pull request or publish to npm
id: changesets
uses: changesets/action@22ccf9aa43179fe9e27dc62e575971d28cce197c # v2.0.0
with:
version-script: npm run version:packages
# `--tag` keeps backports off the `latest` dist-tag: `main` publishes to
# `latest`, `v4` publishes to `v4`, and so on.
#
# The action discovers what was published by reading the file named in the
# `CHANGESETS_OUTPUT` environment variable, which it expects the script to
# pass through to the changesets CLI. `npm run` forwards the environment, so
# this works as-is - but don't wrap it in anything that drops env vars.
publish-script: npm run release -- --tag ${{ steps.channel.outputs.npm-tag }}
commit-message: 'chore(release): version packages'
pr-title: 'chore(release): version packages'
# `changesets/action` calls the create-release API without `make_latest`, and that
# parameter defaults to true - so a backport would silently take the "Latest" badge
# off the current major. Clear it on everything we just published, then assert the
# repository's latest release is not one of them.
#
# This corrects the flag rather than never setting it: there are a few seconds
# between the action creating the release and this step running. Closing that
# window would mean turning off `create-github-releases` and rebuilding the
# changelog-derived release notes by hand, which risks the worse failure of
# publishing to npm with no GitHub release at all. The assertion below is what
# makes the end state guaranteed - if the demotion does not stick, the job fails
# loudly instead of leaving the badge on the wrong major.
#
# `make_latest` is a string enum ("true" / "false" / "legacy"), so it goes through
# `gh api -f` rather than `gh release edit --latest=false`, which would depend on
# how the runner's gh build handles negated boolean flags.
- name: Keep backport releases off "Latest"
if: steps.channel.outputs.npm-tag != 'latest' && steps.changesets.outputs.published == 'true'
env:
GH_TOKEN: ${{ github.token }}
PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.published-packages }}
run: |
# Single-package repo, so changesets tags releases `v<version>`.
mapfile -t tags < <(jq -r '.[] | "v\(.version)"' <<< "$PUBLISHED_PACKAGES")
for tag in "${tags[@]}"; do
id=$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$tag" --jq '.id')
echo "Clearing latest flag on $tag (release $id)"
gh api --method PATCH "repos/$GITHUB_REPOSITORY/releases/$id" -f make_latest=false >/dev/null
done
latest=$(gh api "repos/$GITHUB_REPOSITORY/releases/latest" --jq '.tag_name' 2>/dev/null || echo '<none>')
echo "Latest release is now $latest"
for tag in "${tags[@]}"; do
if [ "$latest" = "$tag" ]; then
echo "::error::$tag is still flagged as the latest release."
exit 1
fi
done