Skip to content

ci(v3): keep @wailsio/runtime in lockstep with the CLI version - #5820

Merged
leaanthony merged 2 commits into
masterfrom
ci/runtime-version-lockstep
Jul 26, 2026
Merged

leaanthony merged 2 commits into
masterfrom
ci/runtime-version-lockstep

Conversation

@taliesin-ai

@taliesin-ai taliesin-ai commented Jul 26, 2026 •

Copy link
Copy Markdown
Collaborator

The problem

publish-npm.yml bumped the package with:

npm --no-git-tag-version --force version prerelease

That increments the trailing numeric identifier and knows nothing about the release channel. It is exactly why the two version series drifted apart: the CLI moved alpha → alpha2 → beta while npm carried on counting alpha.N.

Today the CLI reports v3.0.0-alpha2.117 and npm's latest is 3.0.0-alpha.97. At beta that becomes user-visible: a v3.0.0-beta.0 CLI sitting next to an @wailsio/runtime that still says alpha, and every upgrading user has to be told the mismatch is fine.

The change

The runtime version now comes from v3/internal/version/version.txt — the same file go:embed puts into the CLI — so the two always agree.

Two consequences handled:

  • Republish. The version now only moves when version.txt moves, so a run triggered by a runtime source change between releases would try to republish an existing version and fail. Those runs now skip the publish step while still committing regenerated assets, with a notice explaining why.
  • Trigger. version.txt is added to both the trigger paths and the detect job's file list, so a release that moves it does publish.

Merging this publishes nothing

A workflow-file-only change does not match the detect job's file lists, so the publish job will not run on merge. I deliberately did not bump package.json in this PR for that reason.

The next publish happens when version.txt next moves, and it will be 3.0.0-alpha2.117 rather than 3.0.0-alpha.98. That sorts higher under semver, so latest resolution and every downstream pin behave correctly. It is a visible jump in the npm series, which is the one-off cost of ending the drift.

Verification

  • actionlint clean.
  • Version derivation exercised against the real version.txt (v3.0.0-alpha2.117 → 3.0.0-alpha2.117) and against the beta branch value (v3.0.0-beta.0 → 3.0.0-beta.0).
  • The already-published guard exercised against the live registry: correctly reports 3.0.0-alpha.97 as present (would skip) and 3.0.0-beta.0 as absent (would publish).

Once this is in, the alpha-to-beta upgrade page on the beta branch loses its "the runtime version will not match your CLI" caveat, which is a better outcome than documenting the confusion.

Summary by CodeRabbit

  • New Features
    • Runtime releases now use the exact version specified for the release.
    • Publishing automatically skips versions already available on npm while continuing related release updates.
    • Release publishing now applies the appropriate npm latest tag behavior.
  • Bug Fixes
    • Changes to the release version now reliably trigger the publishing workflow.

The npm package version was produced by `npm version prerelease`, which
increments the trailing numeric identifier and knows nothing about the release
channel. That is how the two series drifted: the CLI went alpha -> alpha2 ->
beta while npm kept counting alpha.N. Today the CLI is v3.0.0-alpha2.117 and
npm is 3.0.0-alpha.97, and at beta a v3.0.0-beta.0 CLI would have shipped
alongside an "alpha" runtime, with every upgrading user needing to be told the
mismatch was expected.

The runtime version now comes from v3/internal/version/version.txt, the same
file go:embed puts into the CLI, so the two always agree.

Because the version now only moves when version.txt moves, a run triggered by a
runtime source change between releases would try to republish an existing
version. Such runs now skip the publish step while still committing regenerated
assets, and version.txt is added to the trigger and detection paths so a release
that moves it does publish.

Merging this publishes nothing: a workflow-file-only change does not match the
detect job's file lists, so the publish job does not run. The next publish
happens when version.txt next moves, and it will be 3.0.0-alpha2.117 rather
than 3.0.0-alpha.98. That sorts higher, so nothing downstream breaks.

Verified: actionlint clean; version derivation exercised for both the current
master value and the beta value; the already-published guard correctly detects
3.0.0-alpha.97 as present and 3.0.0-beta.0 as absent.

Claude-Session: https://claude.ai/code/session_01FigQqUQbNu9ngE4a2CSNm8

@leaanthony leaanthony left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deriving from version.txt is the right anchor: it is already the single source the CLI embeds, so lockstep falls out rather than needing to be maintained.

The republish guard is the part I would have missed. Without it, the first runtime source change after a release fails the workflow at npm publish, which is precisely the failure mode that left npm frozen at alpha.79 for months last time.

Agreed on not bumping package.json here so the merge stays inert.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The npm publishing workflow now triggers on runtime version changes, derives the package version from version.txt, skips versions already published to npm, and publishes missing versions with the latest tag.

Changes

npm publish workflow

Layer / File(s) Summary
Version change trigger and detection
.github/workflows/publish-npm.yml
Runtime version changes now trigger the workflow and count as committed source changes.
Version resolution and publish gating
.github/workflows/publish-npm.yml
The workflow validates and applies the version from version.txt, checks npm for an existing version, and conditionally publishes with the latest tag.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant version.txt
  participant publish-npm.yml
  participant npm_registry
  version.txt->>publish-npm.yml: Provide the package version
  publish-npm.yml->>publish-npm.yml: Validate and set the package version
  publish-npm.yml->>npm_registry: Check whether the version exists
  npm_registry-->>publish-npm.yml: Return published status
  publish-npm.yml->>npm_registry: Publish missing versions with latest tag
Loading

Possibly related PRs

Suggested labels: reviewed ✅

Suggested reviewers: leaanthony

Poem

I’m a rabbit with versions tucked tight,
Reading the file by moonlight.
If npm has the carrot in store,
I skip the climb and publish no more.
Fresh tags hop to latest with cheer—
And runtime sprouts for the new year!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: keeping @wailsio/runtime aligned with the CLI version.
Description check ✅ Passed The description covers the motivation, change details, and verification, but it omits an explicit Fixes #issue reference and dependency notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/runtime-version-lockstep

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

taliesin-ai pushed a commit that referenced this pull request Jul 26, 2026
Follows the lockstep change in #5820: from the beta onwards @wailsio/runtime
takes its version from the same file the CLI embeds, so the upgrade page no
longer has to explain away a mismatch. It now says the two agree, and why an
alpha project's runtime version looks unrelated.

Claude-Session: https://claude.ai/code/session_01FigQqUQbNu9ngE4a2CSNm8

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/publish-npm.yml:
- Around line 167-181: Update the already-published check in the “Skip publish
if this version is already on npm” step to distinguish a missing package version
from npm lookup failures: treat only an E404 response as unpublished, while
propagating or failing the workflow for network, registry, authentication, or
other errors. Preserve the existing published=true output and notice for
versions confirmed to exist.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1fafeeff-b523-47a2-af77-d8a26c34c5b2

📥 Commits

Reviewing files that changed from the base of the PR and between d7168e8 and 6d887b8.

📒 Files selected for processing (1)
  • .github/workflows/publish-npm.yml

Comment on lines +167 to +181
- name: Skip publish if this version is already on npm
id: already-published
# Lockstep means the version only moves when version.txt moves, so a run
# triggered by a runtime source change between releases would otherwise
# try to republish an existing version and fail. Regenerated assets are
# still committed below; only the publish is skipped.
run: |
echo "version=$(npm --no-git-tag-version --force version prerelease)" >> "$GITHUB_OUTPUT"
set -euo pipefail
VERSION="${{ steps.bump-version.outputs.version }}"
if npm view "@wailsio/runtime@${VERSION}" version >/dev/null 2>&1; then
echo "published=true" >> "$GITHUB_OUTPUT"
echo "::notice::@wailsio/runtime@${VERSION} is already on npm; skipping publish. It will publish when version.txt next moves."
else
echo "published=false" >> "$GITHUB_OUTPUT"
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set +e
npm view '`@wailsio/runtime`@0.0.0-coderabbit-absent' version >/dev/null 2>npm-view.err
status=$?
echo "exit status: $status"
cat npm-view.err
rm -f npm-view.err

Repository: wailsapp/wails

Length of output: 795


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow relevant lines =="
sed -n '140,210p' .github/workflows/publish-npm.yml

echo
echo "== npm view E404 behavior for a non-existent `@wailsio/runtime` version =="
set +e
tmp="$(mktemp)"
npm view '`@wailsio/runtime`@0.0.0-coderabbit-absent-mock' version >/dev/null 2>"$tmp"
status=$?
echo "exit status: $status"
grep -n 'npm error code E404' "$tmp" || true
rm -f "$tmp"

echo
echo "== npm view E404 behavior for the existing wailsio runtime version =="
set +e
tmp="$(mktemp)"
npm view '`@wailsio/runtime`@1.0.0' version >/dev/null 2>"$tmp"
status=$?
echo "exit status: $status"
if [ "$status" -eq 0 ]; then
  echo "already published"
fi
rm -f "$tmp"

Repository: wailsapp/wails

Length of output: 4061


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== npm view stdout with existing version =="
set +e
tmp="$(mktemp)"
npm view '`@wailsio/runtime`@1.0.0' version >/dev/null 2>"$tmp"
status=$?
echo "exit status: $status"
printf ':=%s=:' "$(head -n 5 "$tmp" | tr '\n' ' ')"
rm -f "$tmp"

echo
echo "== npm view with non-existent version =="
tmp="$(mktemp)"
npm view '`@wailsio/runtime`@0.0.0-coderabbit-absent-mock' version >/dev/null 2>"$tmp"
status=$?
echo "exit status: $status"
cat "$tmp"
rm -f "$tmp"

Repository: wailsapp/wails

Length of output: 1266


🌐 Web query:

npm CLI registry https://registry.npmjs.org wailsio/runtime package latest npm view

💡 Result:

The npm package for the Wails framework's frontend runtime in Wails v3 is @wailsio/runtime [1][2]. As of July 26, 2026, the latest version of @wailsio/runtime available on the npm registry is 3.0.0-alpha.97 [1][3]. The Wails team manages this package as part of the Wails v3 ecosystem [1][4], and it is intended to be installed as a dependency in Wails projects to provide frontend access to the Wails runtime [2][5]. For historical context, older versions of the Wails framework used different packages, such as @wails/runtime and @wailsapp/runtime (associated with Wails v2) [6][7][8]. Users should ensure they are using @wailsio/runtime for Wails v3 projects [2].

Citations:


Fail closed when the npm lookup errors.

A failed npm view covers registry/network failures too, not just missing versions. This marks the version unpublished and commits generated assets, so the subsequent publish can fail without retrying that release. Treat only E404 as not yet published.

Proposed fix
         run: |
           set -euo pipefail
           VERSION="${{ steps.bump-version.outputs.version }}"
-          if npm view "`@wailsio/runtime`@${VERSION}" version >/dev/null 2>&1; then
+          error_file="$(mktemp)"
+          trap 'rm -f "$error_file"' EXIT
+          if npm view "`@wailsio/runtime`@${VERSION}" version >/dev/null 2>"$error_file"; then
             echo "published=true" >> "$GITHUB_OUTPUT"
             echo "::notice::`@wailsio/runtime`@${VERSION} is already on npm; skipping publish. It will publish when version.txt next moves."
           else
-            echo "published=false" >> "$GITHUB_OUTPUT"
+            status=$?
+            if grep -q '^npm error code E404$' "$error_file"; then
+              echo "published=false" >> "$GITHUB_OUTPUT"
+            else
+              cat "$error_file" >&2
+              exit "$status"
+            fi
           fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Skip publish if this version is already on npm
id: already-published
# Lockstep means the version only moves when version.txt moves, so a run
# triggered by a runtime source change between releases would otherwise
# try to republish an existing version and fail. Regenerated assets are
# still committed below; only the publish is skipped.
run: |
echo "version=$(npm --no-git-tag-version --force version prerelease)" >> "$GITHUB_OUTPUT"
set -euo pipefail
VERSION="${{ steps.bump-version.outputs.version }}"
if npm view "@wailsio/runtime@${VERSION}" version >/dev/null 2>&1; then
echo "published=true" >> "$GITHUB_OUTPUT"
echo "::notice::@wailsio/runtime@${VERSION} is already on npm; skipping publish. It will publish when version.txt next moves."
else
echo "published=false" >> "$GITHUB_OUTPUT"
fi
- name: Skip publish if this version is already on npm
id: already-published
# Lockstep means the version only moves when version.txt moves, so a run
# triggered by a runtime source change between releases would otherwise
# try to republish an existing version and fail. Regenerated assets are
# still committed below; only the publish is skipped.
run: |
set -euo pipefail
VERSION="${{ steps.bump-version.outputs.version }}"
error_file="$(mktemp)"
trap 'rm -f "$error_file"' EXIT
if npm view "`@wailsio/runtime`@${VERSION}" version >/dev/null 2>"$error_file"; then
echo "published=true" >> "$GITHUB_OUTPUT"
echo "::notice::`@wailsio/runtime`@${VERSION} is already on npm; skipping publish. It will publish when version.txt next moves."
else
status=$?
if grep -q '^npm error code E404$' "$error_file"; then
echo "published=false" >> "$GITHUB_OUTPUT"
else
cat "$error_file" >&2
exit "$status"
fi
fi
🧰 Tools
🪛 zizmor (1.26.1)

[info] 175-175: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-npm.yml around lines 167 - 181, Update the
already-published check in the “Skip publish if this version is already on npm”
step to distinguish a missing package version from npm lookup failures: treat
only an E404 response as unpublished, while propagating or failing the workflow
for network, registry, authentication, or other errors. Preserve the existing
published=true output and notice for versions confirmed to exist.

@leaanthony
leaanthony merged commit ab3963c into master Jul 26, 2026
33 checks passed
@leaanthony
leaanthony deleted the ci/runtime-version-lockstep branch July 26, 2026 09:54
angaz pushed a commit to beam-transfer/wails that referenced this pull request Aug 2, 2026
Picks up the contribution terms (wailsapp#5816), the release workflow hardening
(wailsapp#5815), the runtime/CLI version lockstep (wailsapp#5820) and the crash fixes merged
since the first sync. Clean merge, no conflicts.

The branch was six commits behind again within hours of the first sync, which
is why this is now an audit blocker rather than something to remember: a
release branch that quietly ages is how a release ships without fixes everyone
believes are in it.

Claude-Session: https://claude.ai/code/session_01FigQqUQbNu9ngE4a2CSNm8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants