Skip to content

Commit 5185f5c

Browse files
runway-github[bot]metamaskbotCal-Lwachuneiabretonc7s
authored
chore(runway): cherry-pick ci: add separate Runway OTA and native build workflows (phase 1) cp-7.75.0 (#29352)
- ci: add separate Runway OTA and native build workflows (phase 1) cp-7.75.0 (#29294) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Splits the Runway release flow so that OTA updates and native binary builds are triggered by dedicated entry points rather than being auto-detected inside a shared core workflow. This PR is **phase 1 (additive-only)** — it introduces the new workflows alongside the existing ones without removing or renaming anything. ### Why Today the 4 per-platform Runway entry workflows (`runway-{ios,android}-{production,rc}-workflow.yml`) all go through `runway-ota-build-core.yml`, which compares `OTA_VERSION` in `app/constants/ota.ts` against the release tag to decide whether to dispatch `push-eas-update.yml` (OTA) or `build.yml` (native binary). We want release engineers to make that choice explicitly in Runway, and to combine iOS + Android into a single dispatch so the build-version bump only happens once per release. ### Why two phases Runway dispatches a workflow from the currently-selected release branch (no `source_branch` input is passed). That means the workflow file must exist on whichever branch Runway points at. Runway is a single configuration across all branches. Because this PR can only be cherry-picked to `release/7.75.0` and not to older active branches (`release/7.73.x`, `release/7.74.x`), the cleanup (deleting the 4 old per-platform workflows and renaming the core) has to wait until those older branches are retired — otherwise flipping Runway to the new names would break dispatches against them. To keep this PR safe and reviewable without committing the organisation to the cleanup yet, the work is split into two phases: - **Phase 1 (this PR)** — add the 5 new workflow files only; do not touch or remove anything existing. - **Phase 2 (follow-up PR, later)** — delete the 4 old per-platform workflows, rename `runway-ota-build-core.yml` → `auto-rc-ota-build-core.yml`, and update `build-rc-auto.yml`. This will be opened only after `release/7.73.x` and `release/7.74.x` are retired and Runway has been flipped to the new workflow names. ### What this PR adds - **`runway-ota-resolve-context.yml`** — reusable workflow that resolves `pr_number`, `base_ref`, `ota_version`, and `ota_bump` from a given ref. Consumed by the new OTA workflows and designed to be consumed by the renamed core in phase 2. - **`runway-production-builds.yml`** — bumps the build version once, then runs `build.yml` with `platform: both` for `main-prod`, and uploads the iOS IPA to TestFlight. No OTA, no Slack (matches today's production behaviour). - **`runway-rc-builds.yml`** — same shape as above for `main-rc`, plus the existing Slack RC notification (matches today's RC behaviour). - **`runway-ota-production.yml`** — pushes OTA to the `production` channel for both platforms via `push-eas-update.yml` (`platform: all`), then creates the `v<OTA_VERSION>` release tag via the existing `runway-create-ota-production-tag.yml`. - **`runway-ota-rc.yml`** — pushes OTA to the `rc` channel for both platforms, plus the existing Slack RC notification. ### What this PR does NOT change - `runway-ios-production-workflow.yml`, `runway-android-production-workflow.yml`, `runway-ios-rc-workflow.yml`, `runway-android-rc-workflow.yml` — untouched; Runway can keep dispatching these as today. - `runway-ota-build-core.yml` — untouched. - `build-rc-auto.yml` — untouched; keeps calling `runway-ota-build-core.yml` as today. ### Rollout notes - Merge this PR to `main`, then cherry-pick to `release/7.75.0` so the new workflow files exist on the first release branch that will use them. - Runway config is **not** flipped yet. It keeps pointing at the 4 old per-platform workflow names until `release/7.73.x` and `release/7.74.x` are retired. - The phase 2 cleanup PR will flip Runway and delete the now-unused old workflows. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry:null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### 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](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adds new Runway-triggered workflows that publish OTA updates, bump build versions, and create production tags; misconfiguration could impact release automation and tagging but changes are additive and don’t alter existing workflows. > > **Overview** > Introduces new **Runway entrypoint** GitHub Actions workflows to explicitly choose between OTA releases and native binary builds (additive-only). > > Adds `runway-ota-rc.yml` and `runway-ota-production.yml` to publish EAS OTA updates for *both platforms* via `push-eas-update.yml`, with PR-number validation and production tag creation (`v<OTA_VERSION>`). > > Adds `runway-rc-builds.yml` and `runway-production-builds.yml` to bump the build version once via `update-latest-build-version.yml`, build iOS+Android together (`platform: both`), upload iOS to TestFlight, and (for RC) post the existing Slack notification. > > Adds reusable `runway-ota-resolve-context.yml` to resolve `pr_number`, `base_ref` (from `package.json`), `ota_version` (from `app/constants/ota.ts`), and an `ota_bump` flag for future consumers. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4a78c24. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [764a031](764a031) --------- Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com> Co-authored-by: Cal Leung <cal.leung@consensys.net> Co-authored-by: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com> Co-authored-by: Pedro Pablo Aste Kompen <wachunei@gmail.com> Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com> Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com> Co-authored-by: Satyajeet Kolhapure <77279246+satyajeetkolhapure@users.noreply.github.com> Co-authored-by: Jean-Baptiste Blanc <jb.blanc@consensys.net> Co-authored-by: Brian August Nguyen <brianacnguyen@gmail.com> Co-authored-by: George Weiler <georgejweiler@gmail.com> Co-authored-by: Caainã Jeronimo <caainaje@gmail.com> Co-authored-by: Luis Taniça <matallui@gmail.com> Co-authored-by: VGR <VanGulckRik@gmail.com> Co-authored-by: George Marshall <george.marshall@consensys.net> Co-authored-by: AxelGes <34173844+AxelGes@users.noreply.github.com> Co-authored-by: Patryk Łucka <patryk.lucka@gmail.com> Co-authored-by: Gustavo Antunes <17601467+gantunesr@users.noreply.github.com> Co-authored-by: Juanmi <95381763+juanmigdr@users.noreply.github.com> Co-authored-by: infiniteflower <139582705+infiniteflower@users.noreply.github.com> Co-authored-by: Davide Brocchetto <davide.brocchetto@consensys.net> Co-authored-by: Curtis David <Curtis.David7@gmail.com> Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com> Co-authored-by: Monte Lai <monte.lai@consensys.net> Co-authored-by: Jyoti Puri <jyotipuri@gmail.com> Co-authored-by: Bruno Nascimento <brunonascimentodev@gmail.com> Co-authored-by: Maarten Zuidhoorn <maarten@zuidhoorn.com> Co-authored-by: cmd-ob <ola.bale@consensys.net> Co-authored-by: João <castrofjoao@gmail.com> Co-authored-by: sophieqgu <sophieqgu@gmail.com> Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com> Co-authored-by: Mathieu Artu <mathieu.artu@consensys.net> Co-authored-by: sophieqgu <37032128+sophieqgu@users.noreply.github.com> Co-authored-by: Charly Chevalier <charlyy.chevalier@gmail.com> Co-authored-by: Bryan Fullam <bryan.fullam@consensys.net> Co-authored-by: Bryan Fullam <8902170+bfullam@users.noreply.github.com> Co-authored-by: SteP-n-s <stylianos.panagakos@consensys.net> Co-authored-by: António Regadas <antonio.regadas@consensys.net> Co-authored-by: Edouard Bougon <15703023+EdouardBougon@users.noreply.github.com> Co-authored-by: Alex Donesky <adonesky@gmail.com> Co-authored-by: Baptiste Marchand <75846779+baptiste-marchand@users.noreply.github.com> Co-authored-by: Fabio Bozzo <fabio.bozzo@gmail.com> Co-authored-by: Owen Craston <owen.craston@consensys.net> Co-authored-by: Pavel Dvorkin <pavel.dvorkin@consensys.net> Co-authored-by: Kevin Bluer <kevin@bluer.com> Co-authored-by: Vince Howard <vincenguyenhoward@gmail.com> Co-authored-by: Nicholas Gambino <nicholas.gambino@consensys.net> Co-authored-by: Nicholas Smith <nick.smith@consensys.net> Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com> Co-authored-by: Nodonisko <suchydan@gmail.com> Co-authored-by: Tamas <soostamas.hu@gmail.com> Co-authored-by: ffmcgee <51971598+ffmcgee725@users.noreply.github.com> Co-authored-by: Alexandre Chappaz <alex@achappaz.fr> Co-authored-by: Harika <153644847+hjetpoluru@users.noreply.github.com> Co-authored-by: Erik Nilsson <eriks@mail.se> Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com> Co-authored-by: Wei Sun <wei.sun@consensys.net> Co-authored-by: Patryk Łucka <5708018+PatrykLucka@users.noreply.github.com> Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com> Co-authored-by: OGPoyraz <omergoktugpoyraz@gmail.com> Co-authored-by: Bernardo Garces Chapero <bernardo.chapero@consensys.net> Co-authored-by: Christian Montoya <christian.montoya@consensys.net> Co-authored-by: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com> Co-authored-by: sethkfman <Seth.Kaufman@consensys.net> Co-authored-by: Gauthier Petetin <gauthierpetetin@hotmail.com> Co-authored-by: Ganesh Suresh Patra <ganesh.patra@consensys.net> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com> Co-authored-by: ieow <4881057+ieow@users.noreply.github.com> Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com> Co-authored-by: Xiaoming Wang <7315988+dawnseeker8@users.noreply.github.com> Co-authored-by: himanshuchawla009 <himanshuchawla2014@gmail.com> Co-authored-by: Gaurav Goel <grvgoel19@gmail.com> Co-authored-by: Elliot Winkler <elliot.winkler@gmail.com> Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com> Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net> Co-authored-by: Charly Chevalier <charly.chevalier@consensys.net> Co-authored-by: Micaela <100321200+micaelae@users.noreply.github.com> Co-authored-by: salimtb <salim.toubal@consensys.net> Co-authored-by: Micaela Estabillo <micaela.estabillo@consensys.net> Co-authored-by: jake-perkins <128608287+jake-perkins@users.noreply.github.com> Co-authored-by: Laurel <153323700+i18nlaurel@users.noreply.github.com> Co-authored-by: Kylan Hurt <6249205+smilingkylan@users.noreply.github.com> Co-authored-by: sethkfman <setk.kaufman@consensys.net> Co-authored-by: Prithpal Sooriya <prithpal.sooriya@consensys.net> Co-authored-by: Aslau Mario-Daniel <marioaslau@gmail.com> Co-authored-by: sahar-fehri <sahar.fehri@consensys.net> Co-authored-by: Alexey Kureev <a.g.kureev@gmail.com> Co-authored-by: Matt D. <85914066+geositta@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: saustrie-consensys <shane.austrie@consensys.net> Co-authored-by: Matthew Grainger <matthew.grainger@consensys.net> Co-authored-by: Darius Costolas <dariuscostolas@yahoo.com> Co-authored-by: Darius Costolas <10818970+meltingice1337@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: wachunei <1024246+wachunei@users.noreply.github.com> Co-authored-by: Tyler Chong <tyler.chong@consensys.net> Co-authored-by: chloeYue <chloe.gao@consensys.net> Co-authored-by: geositta <matthew.denton@consensys.net> Co-authored-by: Michal Szorad <michal.szorad@consensys.net> Co-authored-by: Javier Garcia Vera <javier.vera@consensys.net> Co-authored-by: Samir Mehta <12882259+samir-acle@users.noreply.github.com> Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com> Co-authored-by: sleepytanya <104780023+sleepytanya@users.noreply.github.com> Co-authored-by: Remi ARQUEVAUX <r.arquevaux@gmail.com> Co-authored-by: metamaskbotv2[bot] <214045046+metamaskbotv2[bot]@users.noreply.github.com>
1 parent 5ae50a8 commit 5185f5c

5 files changed

Lines changed: 408 additions & 0 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
##############################################################################################
2+
#
3+
# Runway OTA Production
4+
#
5+
# Triggered from Runway to push an OTA update to the production channel (iOS + Android) and
6+
# create the corresponding `v<OTA_VERSION>` release tag.
7+
#
8+
# This workflow does not build binaries and does not bump the build version — the release PR is
9+
# expected to bump OTA_VERSION (app/constants/ota.ts) before dispatch.
10+
#
11+
##############################################################################################
12+
name: Runway OTA Production
13+
14+
on:
15+
workflow_dispatch:
16+
inputs:
17+
source_branch:
18+
description: >-
19+
Optional branch, tag, or SHA for OTA publish + tag creation.
20+
Empty uses the branch selected in the "Use workflow from" UI.
21+
required: false
22+
type: string
23+
24+
permissions:
25+
contents: write # required to push the v<OTA_VERSION> tag
26+
pull-requests: read
27+
id-token: write # required by push-eas-update.yml
28+
29+
jobs:
30+
resolve-context:
31+
name: Resolve OTA context
32+
uses: ./.github/workflows/runway-ota-resolve-context.yml
33+
with:
34+
source_branch: ${{ inputs.source_branch }}
35+
secrets: inherit
36+
37+
validate-ota-pr:
38+
name: Validate PR for OTA
39+
needs: resolve-context
40+
runs-on: ubuntu-latest
41+
steps:
42+
- name: Validate PR number
43+
run: |
44+
if [[ -z "${{ needs.resolve-context.outputs.pr_number }}" ]]; then
45+
echo "::error::No PR found for this branch. OTA update requires a PR number."
46+
echo "::error::If you ran the workflow manually (workflow_dispatch), select your release branch in the 'Use workflow from' dropdown (e.g. release/7.71.0), not main."
47+
exit 1
48+
fi
49+
echo "Using PR #${{ needs.resolve-context.outputs.pr_number }}"
50+
51+
push-ota:
52+
name: Push OTA update (production)
53+
needs: [resolve-context, validate-ota-pr]
54+
uses: ./.github/workflows/push-eas-update.yml
55+
with:
56+
pr_number: ${{ needs.resolve-context.outputs.pr_number }}
57+
base_branch: ${{ needs.resolve-context.outputs.base_ref }}
58+
message: ${{ needs.resolve-context.outputs.ota_version }}
59+
channel: production
60+
platform: all
61+
secrets: inherit
62+
63+
create-ota-production-tag:
64+
name: Create OTA production release tag
65+
needs: [resolve-context, push-ota]
66+
uses: ./.github/workflows/runway-create-ota-production-tag.yml
67+
with:
68+
tag_name: ${{ needs.resolve-context.outputs.ota_version }}
69+
checkout_ref: ${{ inputs.source_branch || github.ref_name }}
70+
secrets: inherit
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
##############################################################################################
2+
#
3+
# Runway OTA RC
4+
#
5+
# Triggered from Runway to push an OTA update to the RC channel (iOS + Android) and post a Slack
6+
# notification (matching the prior Runway RC behaviour on the OTA path).
7+
#
8+
# This workflow does not build binaries and does not bump the build version — the release PR is
9+
# expected to bump OTA_VERSION (app/constants/ota.ts) before dispatch.
10+
#
11+
##############################################################################################
12+
name: Runway OTA RC
13+
14+
on:
15+
workflow_dispatch:
16+
inputs:
17+
source_branch:
18+
description: >-
19+
Optional branch, tag, or SHA for OTA publish.
20+
Empty uses the branch selected in the "Use workflow from" UI.
21+
required: false
22+
type: string
23+
24+
permissions:
25+
contents: read
26+
pull-requests: read
27+
id-token: write # required by push-eas-update.yml
28+
29+
jobs:
30+
resolve-context:
31+
name: Resolve OTA context
32+
uses: ./.github/workflows/runway-ota-resolve-context.yml
33+
with:
34+
source_branch: ${{ inputs.source_branch }}
35+
secrets: inherit
36+
37+
validate-ota-pr:
38+
name: Validate PR for OTA
39+
needs: resolve-context
40+
runs-on: ubuntu-latest
41+
steps:
42+
- name: Validate PR number
43+
run: |
44+
if [[ -z "${{ needs.resolve-context.outputs.pr_number }}" ]]; then
45+
echo "::error::No PR found for this branch. OTA update requires a PR number."
46+
echo "::error::If you ran the workflow manually (workflow_dispatch), select your release branch in the 'Use workflow from' dropdown (e.g. release/7.71.0), not main."
47+
exit 1
48+
fi
49+
echo "Using PR #${{ needs.resolve-context.outputs.pr_number }}"
50+
51+
push-ota:
52+
name: Push OTA update (rc)
53+
needs: [resolve-context, validate-ota-pr]
54+
uses: ./.github/workflows/push-eas-update.yml
55+
with:
56+
pr_number: ${{ needs.resolve-context.outputs.pr_number }}
57+
base_branch: ${{ needs.resolve-context.outputs.base_ref }}
58+
message: ${{ needs.resolve-context.outputs.ota_version }}
59+
channel: rc
60+
platform: all
61+
secrets: inherit
62+
63+
slack-notification:
64+
name: Slack RC Notification
65+
needs: push-ota
66+
if: success()
67+
uses: ./.github/workflows/slack-rc-notification.yml
68+
with:
69+
source_branch: ${{ inputs.source_branch || github.ref_name }}
70+
secrets: inherit
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
##############################################################################################
2+
#
3+
# Runway OTA Resolve Context (reusable)
4+
#
5+
# Resolves OTA-related context for Runway OTA / auto-RC flows:
6+
# - pr_number: open PR number for the resolved branch (empty if none)
7+
# - base_ref: semver release tag derived from package.json version (e.g. v7.71.0)
8+
# - ota_version: OTA_VERSION string exported from app/constants/ota.ts at the resolved ref
9+
# - ota_bump: "true" if OTA_VERSION differs from base_ref (or origin/main when tag missing)
10+
#
11+
# Callers:
12+
# - auto-rc-ota-build-core.yml (uses all outputs incl. ota_bump to decide OTA vs build)
13+
# - runway-ota-rc.yml / runway-ota-production.yml (OTA-only entry points; ignore ota_bump)
14+
#
15+
##############################################################################################
16+
name: Runway OTA Resolve Context
17+
18+
on:
19+
workflow_call:
20+
inputs:
21+
source_branch:
22+
description: >-
23+
Optional branch, tag, or SHA to resolve context from.
24+
Empty uses the calling workflow's triggering ref.
25+
required: false
26+
type: string
27+
default: ''
28+
outputs:
29+
pr_number:
30+
description: 'Open PR number for the resolved branch (empty if none)'
31+
value: ${{ jobs.resolve.outputs.pr_number }}
32+
base_ref:
33+
description: 'Semver release tag derived from package.json (e.g. v7.71.0)'
34+
value: ${{ jobs.resolve.outputs.base_ref }}
35+
ota_version:
36+
description: 'OTA_VERSION exported from app/constants/ota.ts at the resolved ref'
37+
value: ${{ jobs.resolve.outputs.ota_version }}
38+
ota_bump:
39+
description: 'true when OTA_VERSION differs from base_ref (or origin/main when tag missing)'
40+
value: ${{ jobs.resolve.outputs.ota_bump }}
41+
42+
permissions:
43+
contents: read
44+
pull-requests: read
45+
46+
jobs:
47+
resolve:
48+
name: Resolve OTA context
49+
runs-on: ubuntu-latest
50+
outputs:
51+
pr_number: ${{ steps.resolve-pr.outputs.pr_number }}
52+
base_ref: ${{ steps.decide.outputs.base_ref }}
53+
ota_version: ${{ steps.decide.outputs.ota_version }}
54+
ota_bump: ${{ steps.decide.outputs.ota_bump }}
55+
steps:
56+
- name: Checkout repository
57+
uses: actions/checkout@v4
58+
with:
59+
fetch-depth: 0
60+
ref: ${{ inputs.source_branch || github.ref }}
61+
62+
- name: Setup Node.js
63+
uses: actions/setup-node@v4
64+
with:
65+
node-version-file: '.nvmrc'
66+
67+
- name: Resolve PR number for current branch
68+
id: resolve-pr
69+
run: |
70+
BRANCH="${{ inputs.source_branch || github.ref_name }}"
71+
# Strip refs/heads/ if present
72+
BRANCH="${BRANCH#refs/heads/}"
73+
echo "Resolving PR for branch: $BRANCH (repo: $GITHUB_REPOSITORY)"
74+
75+
# Try same-repo head first, then owner:branch (required by API when listing pulls)
76+
# jq '.[0].number' on an empty array outputs the literal string "null", so normalise to empty
77+
PR_NUMBER=$(gh pr list --repo "$GITHUB_REPOSITORY" --head "$BRANCH" --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
78+
if [[ -z "$PR_NUMBER" ]]; then
79+
PR_NUMBER=$(gh pr list --repo "$GITHUB_REPOSITORY" --head "$GITHUB_REPOSITORY_OWNER:$BRANCH" --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
80+
fi
81+
82+
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
83+
echo "Branch: $BRANCH, PR number: ${PR_NUMBER:-none}"
84+
env:
85+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
86+
87+
- name: Decide OTA context
88+
id: decide
89+
run: |
90+
set -e
91+
# Version from package.json (e.g. 7.70.0) → base ref for OTA workflow is always v{VERSION}
92+
VERSION=$(node -p "require('./package.json').version")
93+
RELEASE_TAG="v${VERSION}"
94+
echo "base_ref=${RELEASE_TAG}" >> "$GITHUB_OUTPUT"
95+
96+
# Parse OTA_VERSION from the export line (do not use a fixed line number — comment block length changes).
97+
extract_ota() { grep -E '^export const OTA_VERSION' "$1" | sed -n "s/^export const OTA_VERSION: string = '\\([^']*\\)'.*/\\1/p"; }
98+
extract_ota_from_git_show() { grep -E '^export const OTA_VERSION' | sed -n "s/^export const OTA_VERSION: string = '\\([^']*\\)'.*/\\1/p"; }
99+
100+
# OTA_VERSION from current ref
101+
CURRENT_OTA=$(extract_ota app/constants/ota.ts)
102+
echo "ota_version=${CURRENT_OTA}" >> "$GITHUB_OUTPUT"
103+
104+
# Ref to compare against for detecting bump: use release tag if it exists, else main
105+
if git rev-parse "$RELEASE_TAG" >/dev/null 2>&1; then
106+
COMPARE_REF="$RELEASE_TAG"
107+
BASE_OTA=$(git show "${COMPARE_REF}:app/constants/ota.ts" 2>/dev/null | extract_ota_from_git_show || echo "")
108+
else
109+
COMPARE_REF="main"
110+
BASE_OTA=$(git show "origin/main:app/constants/ota.ts" 2>/dev/null | extract_ota_from_git_show || echo "")
111+
echo "Release tag ${RELEASE_TAG} not found; comparing OTA_VERSION to ${COMPARE_REF} to detect bump"
112+
fi
113+
114+
if [[ -n "$BASE_OTA" && "$CURRENT_OTA" != "$BASE_OTA" ]]; then
115+
echo "ota_bump=true" >> "$GITHUB_OUTPUT"
116+
echo "OTA_VERSION changed: $BASE_OTA -> $CURRENT_OTA"
117+
else
118+
echo "ota_bump=false" >> "$GITHUB_OUTPUT"
119+
echo "No OTA version bump (base: $BASE_OTA, current: $CURRENT_OTA)"
120+
fi
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
##############################################################################################
2+
#
3+
# Runway Production Builds
4+
#
5+
# Triggered from Runway to build the production iOS + Android binaries in one run.
6+
# Bumps the build version once, then dispatches build.yml with platform: both so iOS and Android
7+
# build in parallel against the same bumped commit. Finishes by uploading the iOS IPA to
8+
# TestFlight.
9+
#
10+
# This workflow only produces fresh native binaries — OTA updates are handled by the separate
11+
# runway-ota-production.yml workflow.
12+
#
13+
##############################################################################################
14+
name: Runway Production Builds
15+
16+
on:
17+
workflow_dispatch:
18+
inputs:
19+
source_branch:
20+
description: >-
21+
Optional branch, tag, or SHA (Build workflow source_branch).
22+
Empty uses the branch selected in the "Use workflow from" UI.
23+
required: false
24+
type: string
25+
26+
permissions:
27+
contents: write # required by build.yml (update-build-version job)
28+
pull-requests: read
29+
actions: write
30+
id-token: write # required by build.yml
31+
32+
jobs:
33+
update-build-version:
34+
name: Bump build version
35+
uses: ./.github/workflows/update-latest-build-version.yml
36+
permissions:
37+
contents: write
38+
id-token: write
39+
with:
40+
base-branch: ${{ inputs.source_branch || github.ref_name }}
41+
secrets:
42+
PR_TOKEN: ${{ secrets.PR_TOKEN }}
43+
44+
build:
45+
name: Build iOS + Android (main-prod)
46+
needs: update-build-version
47+
uses: ./.github/workflows/build.yml
48+
with:
49+
build_name: main-prod
50+
platform: both
51+
skip_version_bump: true
52+
source_branch: ${{ needs.update-build-version.outputs.commit-hash }}
53+
upload_to_sentry: true
54+
secrets: inherit
55+
56+
upload-ios-testflight:
57+
name: Upload iOS to TestFlight
58+
needs: build
59+
uses: ./.github/workflows/upload-to-testflight.yml
60+
with:
61+
environment: prod
62+
source_branch: ${{ inputs.source_branch || github.ref_name }}
63+
build_branch: ${{ inputs.source_branch || github.ref_name }}
64+
build_name: main-prod
65+
build_commit_sha: ${{ needs.build.outputs.built_commit_sha }}
66+
build_version: ${{ needs.build.outputs.semantic_version }}
67+
build_number: ${{ needs.build.outputs.ios_version_code }}
68+
secrets: inherit

0 commit comments

Comments
 (0)