From 006d079c2cbaadd66b87f28c663e1509b354e655 Mon Sep 17 00:00:00 2001 From: Brad Barnett <127794626+bdbarnett@users.noreply.github.com> Date: Mon, 19 Oct 2026 21:55:46 -0500 Subject: [PATCH] Prepare release: the release PR carries every version declaration --- .github/workflows/prepare-release.yml | 64 ++++++++++++++++++++++++++- docs/publishing.md | 30 +++++++------ 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 36126aa..3a0ff9c 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -1,5 +1,7 @@ -# Open a release PR (VERSION + CHANGELOG). The version in the PR is the -# human's to edit before merging; merging tags and publishes. +# Open a release PR: VERSION and CHANGELOG from the shared workflow, then one +# more commit that sets every other version declaration from VERSION, so the +# PR's Tests pass without anyone touching the branch. The version in the PR is +# the human's to edit before merging; merging tags and publishes. name: Prepare release on: @@ -19,3 +21,61 @@ jobs: with: version: ${{ inputs.version }} secrets: inherit + + # The shared workflow moves only VERSION and CHANGELOG.md and has no hook for + # more, so this job follows it: it checks out the release branch it opened and + # runs check_versions.py --write, which sets the npm manifests, both + # lockfiles and the plugin manifests. It pushes with the App token, not the + # default one, because a push made with GITHUB_TOKEN does not start the PR's + # Tests again. + sync-versions: + needs: release-pr + runs-on: ubuntu-latest + steps: + - name: Mint App token + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ secrets.PYDEVICES_APP_ID }} + private-key: ${{ secrets.PYDEVICES_APP_PRIVATE_KEY }} + + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + token: ${{ steps.app-token.outputs.token }} + + - name: Find the release branch + id: branch + env: + REQUESTED: ${{ inputs.version }} + run: | + git fetch -q origin '+refs/heads/release/*:refs/remotes/origin/release/*' + if [[ -n "$REQUESTED" ]]; then + BRANCH="release/v$REQUESTED" + else + # No version was given, so the shared workflow picked one: the + # branch it just pushed is the newest release branch. + BRANCH=$(git for-each-ref --sort=-committerdate --count=1 \ + --format='%(refname:strip=3)' 'refs/remotes/origin/release/*') + fi + git rev-parse -q --verify "refs/remotes/origin/$BRANCH" >/dev/null \ + || { echo "No branch $BRANCH" >&2; exit 1; } + echo "name=$BRANCH" >> "$GITHUB_OUTPUT" + + - name: Set every version declaration from VERSION + env: + BRANCH: ${{ steps.branch.outputs.name }} + run: | + git checkout -q -B "$BRANCH" "origin/$BRANCH" + V=$(tr -d '[:space:]' < VERSION) + [[ "$BRANCH" == "release/v$V" ]] \ + || { echo "$BRANCH carries VERSION $V" >&2; exit 1; } + python3 scripts/check_versions.py --write + if git diff --quiet; then + echo "Every declaration already carries $V." + exit 0 + fi + git config user.name "pydevices-release-automation[bot]" + git config user.email "pydevices-release-automation[bot]@users.noreply.github.com" + git commit -qam "Release $V: every declaration carries the version" + git push origin "$BRANCH" diff --git a/docs/publishing.md b/docs/publishing.md index a05d555..60b5b62 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -66,20 +66,22 @@ gh workflow run prepare-release.yml -f version=X.Y.Z # or e.g. 0.1.0rc1 gh pr list --state open # the bot's "Release X.Y.Z" PR ``` -The bot's PR only moves `VERSION` and prepends a commit list to -`CHANGELOG.md`. Before merging, on its `release/vX.Y.Z` branch: - -1. Run `python scripts/check_versions.py --write`. It sets every other - version site from `VERSION`, in the form each one takes, and checks - them: `extension/package.json`, `ui/package.json`, the root entry of - both `package-lock.json` files (two lines each), - `.claude-plugin/marketplace.json` and - `integrations/claude-code-plugin/.claude-plugin/plugin.json`. -2. In `CHANGELOG.md`, turn the curated `## Unreleased` notes into the - `## vX.Y.Z (date)` section and drop the bot's commit list, so there is one - heading per release. - -Push, wait for Tests to pass on the PR, and merge it. Then watch: +The bot opens the PR in two steps. It sets `VERSION` and prepends a commit +list to `CHANGELOG.md`, then a second commit runs +`python scripts/check_versions.py --write`, which sets every other version site +from `VERSION` in the form each one takes: `extension/package.json`, +`ui/package.json`, the root entry of both `package-lock.json` files, +`.claude-plugin/marketplace.json` and +`integrations/claude-code-plugin/.claude-plugin/plugin.json`. The PR's Tests +then pass without anyone touching the branch. If the second commit is missing +(the workflow's `sync-versions` job failed), run that command on the +`release/vX.Y.Z` branch and push. + +Before merging, on the `release/vX.Y.Z` branch, in `CHANGELOG.md`, turn the +curated `## Unreleased` notes into the `## vX.Y.Z (date)` section and drop the +bot's commit list, so there is one heading per release. + +Push any edit, wait for Tests to pass on the PR, and merge it. Then watch: ```bash gh run list --workflow tag-release.yml --limit 1