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 1/3] 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 From a13b4762c0b05ad84bd6f7f03d849825cf83c6df Mon Sep 17 00:00:00 2001 From: "pydevices-release-automation[bot]" Date: Tue, 20 Oct 2026 02:56:12 +0000 Subject: [PATCH 2/3] Release 0.0.1.dev0 --- CHANGELOG.md | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fb8158..8df1ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.0.1.dev0 (2026-10-20) + +- Prepare release: the release PR carries every version declaration + ## v0.1.2rc4 (2026-10-20) - put -r from WSL: the Windows sidecar opens /mnt/ paths diff --git a/VERSION b/VERSION index c8e4caf..b732403 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.2rc4 +0.0.1.dev0 From b50b92c09f8b34a020b1789bd6f934942b1eac46 Mon Sep 17 00:00:00 2001 From: "pydevices-release-automation[bot]" Date: Tue, 20 Oct 2026 02:56:25 +0000 Subject: [PATCH 3/3] Release 0.0.1.dev0: every declaration carries the version --- .claude-plugin/marketplace.json | 2 +- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- integrations/claude-code-plugin/.claude-plugin/plugin.json | 2 +- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 9d23843..ffe3a87 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ "name": "mpftp", "source": "./integrations/claude-code-plugin", "description": "A skill that teaches the mpftp CLI for MicroPython/CircuitPython boards: file transfer, REPL, driving a running app, and firmware.", - "version": "0.1.2-rc.4" + "version": "0.0.1-dev.0" } ] } diff --git a/extension/package-lock.json b/extension/package-lock.json index 30a0c2c..e1b558e 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "mpftp", - "version": "0.1.2-rc.4", + "version": "0.0.1-dev.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mpftp", - "version": "0.1.2-rc.4", + "version": "0.0.1-dev.0", "license": "MIT", "dependencies": { "@vscode/codicons": "^0.0.45" diff --git a/extension/package.json b/extension/package.json index d913bb1..48e70c5 100644 --- a/extension/package.json +++ b/extension/package.json @@ -2,7 +2,7 @@ "name": "mpftp", "displayName": "mpftp — MicroPython / CircuitPython Board Tools", "description": "Connect to MicroPython and CircuitPython boards over USB serial or Wi-Fi (WebREPL): dual-pane file transfer, ANSI REPL, mip/circup packages, and guided MicroPython firmware download/build/flash. Works on Linux, Windows, and WSL (COM ports via Windows Python).", - "version": "0.1.2-rc.4", + "version": "0.0.1-dev.0", "publisher": "pydevices", "license": "MIT", "engines": { diff --git a/integrations/claude-code-plugin/.claude-plugin/plugin.json b/integrations/claude-code-plugin/.claude-plugin/plugin.json index b094d99..d2c71a7 100644 --- a/integrations/claude-code-plugin/.claude-plugin/plugin.json +++ b/integrations/claude-code-plugin/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "mpftp", "description": "A skill that teaches the mpftp CLI for MicroPython/CircuitPython boards: file transfer, REPL, driving a running app, and firmware.", - "version": "0.1.2-rc.4", + "version": "0.0.1-dev.0", "author": { "name": "Brad Barnett" }, diff --git a/ui/package-lock.json b/ui/package-lock.json index ef1e02b..64bda21 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "mpftp-ui", - "version": "0.1.2-rc.4", + "version": "0.0.1-dev.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mpftp-ui", - "version": "0.1.2-rc.4", + "version": "0.0.1-dev.0", "dependencies": { "@codemirror/lang-python": "^6.2.1", "@xterm/addon-fit": "^0.11.0", diff --git a/ui/package.json b/ui/package.json index 932a5c1..523fa74 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "mpftp-ui", - "version": "0.1.2-rc.4", + "version": "0.0.1-dev.0", "private": true, "description": "mpftp local PWA: file transfer + REPL for a MicroPython/CircuitPython board.", "scripts": {