Skip to content

Upload the bundle to a Google Play track from Build APK - #257

Merged
bubulux merged 1 commit into
mainfrom
feat/play-upload
Oct 23, 2026
Merged

bubulux merged 1 commit into
mainfrom
feat/play-upload

Conversation

@bubulux

@bubulux bubulux commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

Part of OpenClapper-dev/deploy#11 (epic deploy#8). Stacked on #256. Closed by hand on merge.

What changed

  • scripts/play-upload.mjs reads the service account's JSON key from PLAY_SERVICE_ACCOUNT_JSON, from the environment only. It signs an RS256 assertion with node:crypto and exchanges it at Google's token endpoint. It then runs androidpublisher v3: create an edit, upload the bundle (media upload), set the track release with notes, commit. No dependency, no third-party action, no Expo account.
    • A version code Play already has is a notice and exits 0, so a release built again stays green.
    • An app that was never published only takes draft releases. The script retries as a draft and says to roll it out in the Console.
    • On any error the edit is deleted, so nothing half-done stays behind.
  • Build APK takes track: none by default, or internal. With a track, the settings step requires the secret and refuses the dev variant. The upload step runs after the Play checks and reads the package from the built APK.
  • Docs: self-hosting.md covers the service account, the Play permission, the secret and the track input. infrastructure.md adds the secret and how to rotate it.

Checked

  • make check, including 3 new tests:
    • the assertion's header and claims, URL-safe encoding, and a signature that verifies with the public key;
    • the hint for a JSON key that is not a service account;
    • Play's two special answers.
  • The workflow parses.

Not checked

  • Nothing has talked to Google yet. That needs the developer account, the apps and the service account (deploy#9). The first real upload goes to the staging app's internal track.

🤖 Generated with Claude Code

…dev/deploy#11)

scripts/play-upload.mjs: the service account's JSON key (PLAY_SERVICE_ACCOUNT_JSON, environment only)
signs an RS256 assertion with node:crypto for Google's token endpoint; then androidpublisher v3: edit,
bundle upload, track release, commit. No dependency, no third-party action, no Expo account. A version
code Play already has is a notice and exit 0; a never-published app gets a draft release with a hint.
Build APK takes `track` (none by default, internal) and runs it after the Play checks for release and
staging, with the package read from the built APK. Tests cover the assertion (claims, base64url, a
verifying signature) and Play's two special answers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bubulux
bubulux changed the base branch from feat/play-bundle to main October 23, 2026 09:46
@bubulux
bubulux merged commit afa418c into main Oct 23, 2026
5 checks passed
@bubulux
bubulux deleted the feat/play-upload branch October 23, 2026 09:48
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