Skip to content

ci(release): apply build numbers at build time - #33307

Merged
joaoloureirop merged 8 commits into
mainfrom
fix/ci-build-number
Aug 11, 2026
Merged

ci(release): apply build numbers at build time#33307
joaoloureirop merged 8 commits into
mainfrom
fix/ci-build-number

Conversation

@joaoloureirop

@joaoloureirop joaoloureirop commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Description

Release-branch RC and production builds currently commit build number changes back to the branch before building, producing noisy [skip ci] Bump version number to xxxx commits that clutter release history and are unrelated to product changes.

This PR removes that pattern by applying build numbers locally at build time instead of committing them:

  • Removed commit-build-version.yml — the reusable workflow that committed and pushed build number bumps.
  • Updated runway-rc-builds.yml, runway-production-builds.yml, and build-rc-auto.yml to pass the generated build number into build.yml via the existing build_number input (applied by set-build-version.sh on each runner, no git commit).
  • Updated auto-rc-ota-build-core.yml to forward build_number to build.yml.
  • Updated create-release-pr.yml to read the current build number from version files instead of generating a new one via OIDC at release cut (github-tools still requires the input for mobile, but only bumps semver on the release branch).
  • Updated scripts/create-release-pr.sh to stop calling set-build-version.sh for local/manual release cut flows.

Build numbers continue to be allocated by the centralized metamask-mobile-build-version service at build time and remain unique/monotonically increasing. iOS and Android builds in the same workflow run still share the same generated number.

Changelog

CHANGELOG entry: null

Related issues

Fixes: MCWP-527

Manual testing steps

N/A — CI workflow changes only. Verification is via workflow runs on a release branch:

  1. Trigger Auto RC builds (build-rc-auto.yml) by pushing to a release/* branch with an open PR — confirm the run completes, iOS and Android artifacts are produced, and no [skip ci] Bump version number to commit appears on the branch.
  2. Trigger Runway RC Builds or Runway Production Builds via workflow_dispatch — confirm builds succeed, TestFlight upload completes (RC), and no build-number bump commit is pushed.
  3. Trigger Create Release Pull Request for a test semver — confirm the release PR is created with semver-only version changes and no new build number is allocated or committed.

Screenshots/Recordings

N/A — CI-only change with no UI impact.

Before

N/A

After

N/A

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

…them

Stop pushing [skip ci] Bump version number commits to release branches by
removing commit-build-version.yml and passing generated build numbers into
build.yml for RC, production, and auto RC workflows. Release cut no longer
allocates a new build number via create-release-pr; it reads the current
value for github-tools validation only.

Fixes MCWP-527
@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@tommasini

Copy link
Copy Markdown
Contributor

Reviving this — I arrived here from the opposite direction and ended up concluding this PR is the right fix, so sharing the evidence in case it helps get it over the line.

Why this matters more than "noisy commits"

I was asked to just drop the [skip ci] prefix from commit-build-version.yml, on the theory that we do want CI to run on these commits. That turns out to be unsafe, and the reason is a good argument for this PR.

The push in commit-build-version.yml is authenticated with a GitHub App installation token from the Token Exchange Service (MetaMask/github-tools/.github/actions/get-token), not secrets.GITHUB_TOKEN. GitHub's built-in recursion guard — "events triggered by the GITHUB_TOKEN will not create a new workflow run" — applies only to GITHUB_TOKEN. App tokens deliberately do trigger workflows. So [skip ci] is the only thing preventing recursion today.

There's a clean natural experiment in release/8.4.1-ota confirming this. Two commits by the same bot identity (metamaskbot <metamaskbot@users.noreply.github.com>, exactly what commit-build-version.yml configures), one with the skip marker and one without:

Commit Message Push-event workflow runs
4bca65fd2 chore: set OTA_VERSION to v8.4.1... (no [skip ci]) 4 — incl. Auto RC builds
606ca44d3ca [skip ci] Bump version number to 6257 0

The four runs on 4bca65fd2 were Auto RC builds, Check Attributions, Update Release Changelog PR, and Performance E2E Tests for Release Builds, all with triggering_actor = metamask-ci[bot].

And the loop would be worse than an extra build. Because build-rc-auto.yml sets concurrency: cancel-in-progress: true on ${{ github.workflow }}-${{ github.ref }}, and the bump is pushed by update_rc_build_version before the iOS/Android build jobs, each run would push a commit that starts a successor which immediately cancels its own parent mid-build. Net result: RC builds never complete, while still burning a build number from the central allocator every iteration.

Deleting the commit entirely, as this PR does, removes the hazard rather than working around it. That's the durable fix.

Still applies cleanly to main

Checked against current main (624 commits past the branch point, mergeable: MERGEABLE) — every contract this PR depends on is intact:

  • build.yml still has the build_number input and applies it per-runner via set-build-version.sh (lines 232–241, 712–715).
  • scripts/get-build-metadata.sh --ci exists and emits ios_version_code, as the new resolve-build-version job expects.
  • The region of create-release-pr.yml this rewrites is untouched on main.
  • build-rc-auto.yml, both runway-*-builds.yml, and auto-rc-ota-build-core.yml are unchanged on main since the branch point.
  • No dangling references to commit-build-version / update_rc_build_version, and all five changed workflows parse as valid YAML.

One thing I'd change before merge: keep the commit pinned

Right now build-rc-auto.yml passes needs.update_rc_build_version.outputs.commit-hash — a concrete SHA — as source_branch into two separate auto-rc-ota-build-core.yml invocations (iOS and Android). That's what guarantees both platforms build the identical commit. This PR replaces it with needs.validate-and-find-pr.outputs.branch-name, and source_branch flows unmodified into build.yml's actions/checkout ref:.

So two independent runs would each check out a moving branch. If a cherry-pick lands between them, the iOS and Android RC builds ship from different commits under one build number. On a branch as busy as release/8.5.0 (10 build-number bumps in the recent window, cherry-picks minutes apart) that seems reachable.

Suggest using github.sha instead, in both the iOS and Android jobs:

  trigger-ios-rc-build:
    with:
      platform: ios
      source_branch: ${{ github.sha }}
      build_number: ${{ needs.generate_rc_build_version.outputs.build-version }}
      distribute_external: true

That's the push that triggered the run — with the bump commit gone, exactly the commit we want built — and it restores today's pinning guarantee.

Safe downstream, too: runway-ota-resolve-context.yml resolves a PR number with gh pr list --head, which can't match a SHA, but that's already true in production since build-rc-auto currently feeds it the bump SHA. build-rc-auto gets its own PR number from validate-and-find-pr regardless.

The same pinning argument applies to the two runway-*-builds.yml workflows, though the risk is much lower there since they're manually dispatched and unlikely to race with a push.


Happy to push the github.sha change or open a follow-up if that's easier. Main blocker looks procedural: still a draft with no reviewers, and the full CI suite hasn't run (5 lightweight checks passed, 2 policy-bot pending).

joaoloureirop and others added 2 commits July 31, 2026 11:34
Keep iOS and Android on the same commit after removing bump commits,
so cherry-picks mid-run cannot diverge platforms under one build number.

Co-authored-by: Cursor <cursoragent@cursor.com>
@joaoloureirop joaoloureirop added the team-mobile-platform Mobile Platform team label Jul 31, 2026
@joaoloureirop
joaoloureirop marked this pull request as ready for review August 10, 2026 16:23
@joaoloureirop
joaoloureirop requested a review from a team as a code owner August 10, 2026 16:23
@github-actions github-actions Bot added the risk:medium AI analysis: medium risk label Aug 10, 2026
@joaoloureirop

joaoloureirop commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Testing summary (MCWP-527)

Validation that RC/prod (and related) builds apply build numbers at build time and do not push [skip ci] Bump version number… commits.

Fork (MetaMask/metamask-mobile-joaoloureirop)

Took the change as far as a fork can go (OIDC / Environments / Token Exchange are scoped to the real repo).

  • Auto RC path: with a fork-only fake build number, iOS and Android both ran “Apply build number locally” successfully (no bump commit), then stopped on missing Environment secrets — expected.
  • Create Release PR: on 0.1.0, resolve-bases / resolve-previous-ref / “Resolve current build number” (read-from-files) passed; failed at Token Exchange 403 (policy denies the fork). Confirms the new resolve path; full cut still needs the real repo.

Runway was not pushed further on the fork (same secrets/OIDC walls).

Real repo (MetaMask/metamask-mobile)

Throwaway branch release/0.0.0-test + open PR #34515 (so Auto RC can run without touching a live release). Temporary Auto RC branch-name allowance for -test was used for this smoke only.

Workflow Run Result
Auto RC https://github.com/MetaMask/metamask-mobile/actions/runs/31226430507 Success (validate → allocate → iOS + Android → TestFlight → RC PR comment → Slack)
Runway RC https://github.com/MetaMask/metamask-mobile/actions/runs/31227489758 Success (allocate → iOS + Android → TestFlight → Slack)

Confirmed:

  • iOS and Android both received the expected build number
  • No bump commit on release/0.0.0-test

Not re-run on main for this round: Create Release PR full cut (avoids burning allocator numbers / stray release branches; fork already covered the resolve/read path). Runway Production optional after RC passed — not required for this signal. Nightly already uses generate + local build_number; no change needed for this PR.

Follow-ups (under MCWP-527)

  • MCWP-768 — durable build number ↔ commit SHA mapping (ops/tooling)
  • MCWP-767 — surface commit SHA in-app wherever we show/attach the build number

Cleanup

Close/delete throwaway PR #34515 / release/0.0.0-test when finished; drop any temporary Auto RC -test regex if it isn’t meant to ship with this PR.

weitingsun
weitingsun previously approved these changes Aug 10, 2026
@weitingsun

Copy link
Copy Markdown
Contributor

This is great 🥇

Comment thread .github/workflows/create-release-pr.yml Outdated
Comment thread .github/workflows/create-release-pr.yml Outdated

@HowardBraham HowardBraham 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.

I think I'm not understanding where the actual step is that changes the build number when we build the packages.

@joaoloureirop

joaoloureirop commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

I think I'm not understanding where the actual step is that changes the build number when we build the packages.

The apply step is in build.yml (Apply build number locally)
This PR did not change that

Avoid a separate runner for get-build-metadata.sh by reading the current
build number inside create-release-pr (non-OTA only).
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: None (no tests recommended)
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: low
  • AI Confidence: 97%
click to see 🤖 AI reasoning details

E2E Test Selection:
All 9 changed files are purely CI/build pipeline infrastructure changes with zero impact on app source code, test flows, or user-facing functionality:

  1. commit-build-version.yml — Deleted entirely. This workflow committed build version bumps to the repo; its removal is part of a refactor to apply build numbers locally at build time instead.

  2. build-rc-auto.yml, auto-rc-ota-build-core.yml, runway-production-builds.yml, runway-rc-builds.yml — All remove the commit-build-version job dependency, change contents: write to contents: read (reduced permissions), pin source_branch to github.sha for determinism, and pass build_number as a direct input to build jobs.

  3. build.yml — Cosmetic comment update only (no functional change).

  4. create-release-pr.yml — Inlines build number reading into the create-release-pr job instead of using a separate generate-build-version job; reads the current build number from version files rather than generating a new one.

  5. CODEOWNERS — Removes the deleted commit-build-version.yml entry.

  6. scripts/create-release-pr.sh — Removes the NEW_VERSION_NUMBER parameter and set-build-version.sh call; build numbers are now applied at build time.

None of these changes touch app source code, test infrastructure, page objects, selectors, flows, or any user-facing functionality. No E2E test tags are warranted.

Performance Test Selection:
All changes are CI/build pipeline infrastructure only. No app source code, performance-sensitive flows, or performance test specs were modified. No performance tests are warranted.

View GitHub Actions results

@sonarqubecloud

Copy link
Copy Markdown

@joaoloureirop
joaoloureirop added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 02c6372 Aug 11, 2026
118 of 120 checks passed
@joaoloureirop
joaoloureirop deleted the fix/ci-build-number branch August 11, 2026 16:36
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 11, 2026
@metamask-ci metamask-ci Bot added the release-8.8.0 Issue or pull request that will be included in release 8.8.0 label Aug 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-8.8.0 Issue or pull request that will be included in release 8.8.0 risk:medium AI analysis: medium risk size-M team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants