Skip to content

fix(capgo): give every OTA upload a unique bundle version - #2708

Open
innolope-dev wants to merge 2 commits into
devfrom
fix/capgo-ota-bundle-version
Open

fix(capgo): give every OTA upload a unique bundle version#2708
innolope-dev wants to merge 2 commits into
devfrom
fix/capgo-ota-bundle-version

Conversation

@innolope-dev

Copy link
Copy Markdown
Collaborator

Closes #2638

Problem

package.json's version only moves on a native release, so every OTA upload after the first reused bundle version 1.0.8. Capgo failed those uploads loudly until #2636 added --version-exists-ok, which turned them into silent no-ops: green check, nothing shipped.

One correction to the issue's suggestion

1.0.8-<short-sha> would have made it worse. Capgo's update endpoint rejects any bundle that semver-sorts below the device's native version (disable_auto_update_under_native, on by default — update.ts), and a prerelease sorts under plain 1.0.8. Uploads would succeed, the dashboard would show new bundles, and every device on the 1.0.8 binary would refuse them. The commit-count variant the issue also proposes is what this PR uses.

Changes

  • scripts/capgo-bundle-version.mjs — prints <major>.<minor> from package.json + the git commit count (today: 1.0.9798). Anchoring major/minor to package.json keeps the version above the native floor when a native release bumps it; the commit count makes it unique per commit. It refuses a shallow clone (would emit 1.0.1), a prerelease override, and any CAPGO_BUNDLE_VERSION override below the native version.
  • Both Capgo workflows — fetch-depth: 0, a "Resolve bundle version" step, --bundle <version> on the upload, and a post-upload assertion that channel currentBundle actually serves the version the run just built. --version-exists-ok stays, but now only covers a re-run of the same commit; any other no-op leaves the channel stale and turns the job red. That check is the issue's "verify when fixed" criterion, enforced in CI.
  • capgo:upload:dev|staging package scripts get the same derived version — they had the identical collision.

Verification

  • 6 new jest tests (scripts/__tests__/capgo-bundle-version.test.js), including a real shallow-clone repo.
  • The verification step was simulated under bash -e for match / stale-channel / CLI-error; it is green only on a real match.
  • eslint and prettier --check clean on the touched files; both workflows parse.

Before the first release

Check on the Capgo dashboard that the channels' update policy is not patch — that setting blocks any patch-differing bundle, i.e. all OTA, regardless of the version scheme. Also note a native release that overrides versionName without bumping package.json would strand OTA bundles under the shipped binary.

package.json's version only moves on a native release, so every OTA upload
after the first reused bundle version 1.0.8. Capgo failed those uploads until
--version-exists-ok turned them into silent no-ops: green check, nothing
shipped.

Derive the version per commit instead — <major>.<minor> from package.json plus
the git commit count — so each upload is real. The patch cannot be a prerelease
(1.0.8-<sha>): Capgo's disable_auto_update_under_native rule makes devices on
the 1.0.8 binary reject anything that sorts below it.

--version-exists-ok now only covers a re-run of the same commit, and a new step
asserts the channel actually serves the version the run built, so a no-op that
ships nothing is red again.

Closes #2638
@innolope-dev innolope-dev self-assigned this Aug 17, 2026
@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview Aug 17, 2026 7:37pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f7ca960b-0595-4aac-a433-2371507c6cb6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@github-actions

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 7159.84 → 7159.84 (0)
Findings: 0 net (+0 new, -0 resolved)

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 3068 ran, 0 failed, 0 skipped, 50.9s

📊 Coverage (unit)

metric %
statements 66.9%
branches 52.0%
functions 57.2%
lines 67.7%
⏱ 10 slowest test cases
time test
3.7s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
0.9s src/utils/__tests__/demo-api.test.ts › isDemoMode() is false when not running under Capacitor
0.4s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › every sticker stays within canvas at any count
0.4s src/utils/__tests__/sentry.utils.test.ts › defaults to the client budget under a browser global
0.3s src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx › Bank withdrawal keeps the $1 minimum for sub-$1 amounts
0.3s src/utils/__tests__/sentry.utils.test.ts › still lets a per-call timeoutMs win over the default
0.3s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in validateInviteCode
0.3s src/utils/__tests__/auth-token.test.ts › authReady does not park — hydrates the plain token without an unlock
0.3s src/utils/__tests__/auth-token.test.ts › is none — never guarded — when only the guarded marker is present
0.3s src/utils/__tests__/auth-token.test.ts › returns the token hydrated from Preferences after authReady
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

The unit job checks the repo out shallow, so asserting the derived version
against the checkout's history failed in CI. Only the CAPGO_BUNDLE_VERSION
cases still use the checkout — that path never reads git.
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.

1 participant