Skip to content

Create Release PR

Create Release PR #1

Workflow file for this run

name: Create Release PR
# Manually triggered from the Actions tab. Pick how to bump; the target version
# is computed from the CURRENT version at run time (nothing is hard-coded). This
# sets every package in lockstep (lerna fixed mode) and opens a "Release X.Y.Z"
# PR that only touches lerna.json + package.json files. Merging that PR and
# publishing a GitHub Release is what actually ships to npm.
on:
workflow_dispatch:
inputs:
bump:
description: 'How to bump (examples are illustrative; the actual resulting version is shown in the run summary):'
required: true
default: "prerelease (e.g. 1.2.3-beta.4 -> 1.2.3-beta.5)"
type: choice
options:
- "prerelease (e.g. 1.2.3-beta.4 -> 1.2.3-beta.5)"
- "patch (e.g. 1.2.3-beta.4 -> 1.2.3, or 1.2.3 -> 1.2.4)"
- "minor (e.g. 1.2.3 -> 1.3.0)"
- "major (e.g. 1.2.3 -> 2.0.0)"
- "preminor (e.g. 1.2.3 -> 1.3.0-beta.0)"
- "premajor (e.g. 1.2.3 -> 2.0.0-beta.0)"
permissions:
contents: write
pull-requests: write
checks: write
jobs:
release-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 24
- run: yarn install --frozen-lockfile
- name: Configure git
run: |
git config user.name "percy-release-bot"
git config user.email "percy-release-bot@users.noreply.github.com"
- name: Bump version
id: bump
env:
BUMP: ${{ inputs.bump }}
run: |
set -euo pipefail
# The dropdown value is "<keyword> (e.g. ...)"; take the first word.
KEYWORD="${BUMP%% *}"
CURRENT=$(node -p "require('./lerna.json').version")
# Compute the target version dynamically from the current version.
# 'beta' is the prerelease identifier for any pre* bump.
TARGET=$(KEYWORD="$KEYWORD" node -e "const s=require('semver'); const t=s.inc('$CURRENT', process.env.KEYWORD, 'beta'); if(!t){process.exit(1)} process.stdout.write(t)")
if [[ -z "$TARGET" ]]; then
echo "::error::Could not compute a target version for bump '$KEYWORD' from '$CURRENT'."
exit 1
fi
yarn lerna version "$TARGET" \
--exact --no-git-tag-version --no-push --force-publish --yes
VERSION=$(node -p "require('./lerna.json').version")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
# A prerelease version (contains a hyphen) ships under the `beta`
# npm dist-tag; a clean semver ships under `latest`.
if [[ "$VERSION" == *-* ]]; then
DIST_TAG=beta
else
DIST_TAG=latest
fi
echo "dist_tag=$DIST_TAG" >> "$GITHUB_OUTPUT"
# Keep each package's publishConfig.tag (the npm dist-tag used by
# `lerna publish from-package`) in step with the version.
DIST_TAG="$DIST_TAG" node -e 'const fs=require("fs");const t=process.env.DIST_TAG;for(const d of fs.readdirSync("packages")){const f="packages/"+d+"/package.json";if(!fs.existsSync(f))continue;const p=JSON.parse(fs.readFileSync(f));if(p.publishConfig&&p.publishConfig.tag!==t){p.publishConfig.tag=t;fs.writeFileSync(f,JSON.stringify(p,null,2)+"\n")}}'
{
echo "### Version bump"
echo ""
echo "Bump: \`$BUMP\`"
echo ""
echo "\`$CURRENT\` → **\`$VERSION\`** (npm dist-tag: \`$DIST_TAG\`)"
} >> "$GITHUB_STEP_SUMMARY"
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ secrets.GITHUB_TOKEN }}
base: master
branch: release/${{ steps.bump.outputs.version }}
# Only commit version files — never workflow files (GITHUB_TOKEN may
# not push to .github/workflows, and a release PR shouldn't anyway).
add-paths: |
lerna.json
packages/**/package.json
commit-message: "Release ${{ steps.bump.outputs.version }}"
title: "Release ${{ steps.bump.outputs.version }}"
labels: "🧹 maintenance"
body: |
Automated version bump to **`${{ steps.bump.outputs.version }}`**.
- Triggered by @${{ github.actor }} via `workflow_dispatch` (bump: `${{ inputs.bump }}`).
- On publishing a GitHub Release, this will go to npm under dist-tag **`${{ steps.bump.outputs.dist_tag }}`**.
**Next steps:** review & merge, then cut the GitHub Release.
# A GITHUB_TOKEN-created PR does not trigger the on:pull_request checks
# (GitHub's recursion guard), so the branch-protection required checks
# would hang as "Expected" forever. A release PR only bumps version
# files, so post a passing check run for each required context. Created
# via GITHUB_TOKEN => owned by the GitHub Actions app (id 15368), which
# matches the app-pinned required contexts on master.
# NOTE: for percy/cli, SHA-pin this action (PER-8608). Tag used on the fork.
- name: Satisfy required checks for the release PR (skips CI; version-only PR)
if: steps.cpr.outputs.pull-request-operation == 'created'
uses: actions/github-script@v7
with:
script: |
const head_sha = '${{ steps.cpr.outputs.pull-request-head-sha }}';
// Source of truth: branch protection on master -> required status checks.
const contexts = [
"Lint", "Typecheck", "Build",
"Test @percy/cli", "Test @percy/cli-build", "Test @percy/cli-command",
"Test @percy/cli-config", "Test @percy/cli-exec", "Test @percy/cli-snapshot",
"Test @percy/cli-upload", "Test @percy/client", "Test @percy/config",
"Test @percy/core", "Test @percy/dom", "Test @percy/env",
"Test @percy/logger", "Test @percy/sdk-utils", "Test @percy/webdriver-utils",
"semgrep/ci", "Claude Code Review",
];
core.info(`Posting ${contexts.length} check runs to ${head_sha}`);
for (const name of contexts) {
await github.rest.checks.create({
owner: context.repo.owner, repo: context.repo.repo,
name, head_sha, status: 'completed', conclusion: 'success',
output: {
title: 'Skipped for release PR',
summary: 'Release PRs only bump version files; full CI gates master before publish.',
},
});
}