Skip to content

Commit 5ec97df

Browse files
joaoloureiropCopilotmetamaskbot
authored
chore: enable auto RC builds (#23379)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This PR introduces automation for Release Candidate (RC) builds by adding GitHub Actions workflows that integrate with Bitrise CI/CD. It enables both manual and automatic RC build triggering, streamlines version bumping, and removes redundant build steps from the Bitrise pipeline. ### Key Changes #### New GitHub Actions Workflows 1. **`build-rc-create.yml`** - Manual RC Build Workflow - Triggered via `workflow_dispatch` with semantic version input - Automatically bumps build version before triggering builds - Triggers Bitrise RC pipeline for both iOS and Android 2. **`build-rc-auto.yml`** - Automatic RC Build Workflow - Triggers on pushes to `release/*` branches - Only runs when the associated PR has the `auto-rc-builds` label - Validates branch naming (semantic versioning format) - Automatically bumps version and triggers Bitrise builds #### Enhanced Workflow Reusability - **`update-latest-build-version.yml`** - Now supports `workflow_call` - Can be invoked by other workflows as a reusable action - Exposes outputs: `build-version` and `commit-hash` #### New Build Script - **`.github/scripts/rc-builds.sh`** - Bitrise Build Trigger Script - Triggers Bitrise `pr_rc_rwy_pipeline` via API - Waits for build completion (40-minute timeout) - Retrieves and displays build artifacts and public URLs - Validates required environment variables #### Bitrise Configuration Updates - **`bitrise.yml`** - Removed redundant version bumping step - Removed `bump_version_code` dependency from `pr_rc_rwy_pipeline` - Version bumping now handled by GitHub Actions before triggering Bitrise - Build workflows (`build_ios_rc_and_upload_sourcemaps`, `build_android_rc_and_upload_sourcemaps`) now depend directly on `pr_check_build_cache` ### Usage **Manual RC Build:** 1. Navigate to Actions → "Create RC builds" 2. Click "Run workflow" 3. Enter semantic version (e.g., `7.62.0`) 4. Workflow handles version bumping and Bitrise trigger automatically **Automatic RC Build:** 1. Create/update a release branch (e.g., `release/7.62.0`) 2. Add `auto-rc-builds` label to the associated PR 3. Push commits to the release branch 4. Workflow automatically triggers RC builds ## **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: #23068 ## **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** - [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. ## **Pre-merge reviewer checklist** - [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] > Introduces end-to-end automation for RC builds via GitHub Actions and Bitrise. > > - New workflows `build-rc-auto.yml` (label-gated on `release/*` pushes) and `build-rc-create.yml` (manual) that bump versions then trigger Bitrise `pr_rc_rwy_pipeline` > - Reusable `update-latest-build-version.yml` now supports `workflow_call` and exposes `build-version` and `commit-hash`; commits bumped files and pushes > - New script `.github/scripts/rc-builds.sh` triggers Bitrise, waits for completion, and surfaces artifact info (Android public link) > - Bitrise `bitrise.yml`: remove `bump_version_code` dependency from `pr_rc_rwy_pipeline`; keep `build_ios_rc_and_upload_sourcemaps` and `build_android_rc_and_upload_sourcemaps` dependent on `pr_check_build_cache`; minor whitespace/comment tidy > - Version bumps: Android `versionCode` to `3432`; iOS `CURRENT_PROJECT_VERSION` to `3432`; env vars `VERSION_NUMBER`/`FLASK_VERSION_NUMBER` updated accordingly > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fc29a62. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
1 parent 24b7f45 commit 5ec97df

5 files changed

Lines changed: 380 additions & 49 deletions

File tree

.github/scripts/rc-builds.sh

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
# Validate required environment variables
6+
: "${SEMVER:?SEMVER environment variable must be set}"
7+
: "${BUILD_NUMBER:?BUILD_NUMBER environment variable must be set}"
8+
: "${BITRISE_APP_ID:?BITRISE_APP_ID environment variable must be set}"
9+
: "${BITRISE_BUILD_TRIGGER_TOKEN:?BITRISE_BUILD_TRIGGER_TOKEN environment variable must be set}"
10+
: "${BITRISE_API_TOKEN:?BITRISE_API_TOKEN environment variable must be set}"
11+
: "${COMMIT_HASH:?COMMIT_HASH environment variable must be set}"
12+
: "${GH_REF_NAME:?GH_REF_NAME environment variable must be set}"
13+
14+
# Additional validation for semver format
15+
if ! [[ "${SEMVER:-}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
16+
echo "Error: SEMVER must be numeric X.Y.Z format, got: ${SEMVER:-<empty>}" >&2
17+
exit 1
18+
fi
19+
20+
METAMASK_WORKFLOW="pr_rc_rwy_pipeline"
21+
22+
# Use jq to safely construct JSON payload
23+
JSON_PAYLOAD=$(jq -n \
24+
--arg branch "$GH_REF_NAME" \
25+
--arg pipeline_id "$METAMASK_WORKFLOW" \
26+
--arg commit_message "RC build ${SEMVER}(${BUILD_NUMBER})" \
27+
--arg commit_hash "$COMMIT_HASH" \
28+
--arg build_trigger_token "$BITRISE_BUILD_TRIGGER_TOKEN" \
29+
'{
30+
"build_params": {
31+
"branch": $branch,
32+
"pipeline_id": $pipeline_id,
33+
"commit_message": $commit_message,
34+
"commit_hash": $commit_hash
35+
},
36+
"hook_info": {
37+
"type": "bitrise",
38+
"build_trigger_token": $build_trigger_token
39+
},
40+
"triggered_by": "GitHub Actions RC Build"
41+
}')
42+
43+
BUILD_RESPONSE=$(curl -s -X POST \
44+
"https://app.bitrise.io/app/$BITRISE_APP_ID/build/start.json" \
45+
-H "Content-Type: application/json" \
46+
-d "$JSON_PAYLOAD")
47+
48+
echo "Build response: $BUILD_RESPONSE"
49+
BUILD_SLUG=$(echo "$BUILD_RESPONSE" | jq -r '.build_slug')
50+
echo "Build slug: $BUILD_SLUG"
51+
52+
if [[ -z "$BUILD_SLUG" || "$BUILD_SLUG" == "null" ]]; then
53+
echo "Error: Failed to get build slug"
54+
echo "Full response: $BUILD_RESPONSE"
55+
exit 1
56+
fi
57+
58+
# Wait for the workflow to complete
59+
echo "Waiting for $METAMASK_WORKFLOW to complete..."
60+
TIMEOUT=2400 # 40 minutes
61+
ELAPSED=0
62+
63+
while [ $ELAPSED -lt $TIMEOUT ]; do
64+
BUILD_RESPONSE=$(curl -s -H "Authorization: $BITRISE_API_TOKEN" \
65+
"https://api.bitrise.io/v0.1/apps/$BITRISE_APP_ID/pipelines/$BUILD_SLUG")
66+
67+
BUILD_STATUS=$(echo "$BUILD_RESPONSE" | jq -r '.status')
68+
echo "Build status: $BUILD_STATUS (elapsed: ${ELAPSED}s)"
69+
70+
# Check for successful completion (status 1 or success/succeeded)
71+
if [ "$BUILD_STATUS" = "1" ] || [ "$BUILD_STATUS" = "success" ] || [ "$BUILD_STATUS" = "succeeded" ]; then
72+
echo "Build completed successfully"
73+
break
74+
elif [ "$BUILD_STATUS" = "0" ] || [ "$BUILD_STATUS" = "in_progress" ] || [ "$BUILD_STATUS" = "running" ]; then
75+
echo "Build is in progress..."
76+
elif [ "$BUILD_STATUS" = "2" ] || [ "$BUILD_STATUS" = "failed" ] || [ "$BUILD_STATUS" = "aborted" ]; then
77+
echo "Build failed with status: $BUILD_STATUS"
78+
exit 1
79+
elif [ "$BUILD_STATUS" = "initializing" ]; then
80+
echo "Build has started..."
81+
else
82+
echo "Unknown build status: $BUILD_STATUS"
83+
fi
84+
85+
sleep 30
86+
ELAPSED=$((ELAPSED + 30))
87+
done
88+
89+
if [ "$ELAPSED" -ge "$TIMEOUT" ]; then
90+
echo "Timeout waiting for build to complete"
91+
echo "Final build status: $BUILD_STATUS"
92+
echo "Build slug: $BUILD_SLUG"
93+
exit 1
94+
fi
95+
96+
# Android workflow slug
97+
ANDROID_WORKFLOW_ID=$(echo "$BUILD_RESPONSE" | jq -r '.workflows | .[] | select(.name=="build_android_rc_and_upload_sourcemaps") | .external_id')
98+
IOS_WORKFLOW_ID=$(echo "$BUILD_RESPONSE" | jq -r '.workflows | .[] | select(.name=="build_ios_rc_and_upload_sourcemaps") | .external_id')
99+
100+
if [[ -z "$ANDROID_WORKFLOW_ID" || "$ANDROID_WORKFLOW_ID" == "null" ]]; then
101+
echo "Error: Failed to get Android workflow ID"
102+
exit 1
103+
fi
104+
105+
if [[ -z "$IOS_WORKFLOW_ID" || "$IOS_WORKFLOW_ID" == "null" ]]; then
106+
echo "Error: Failed to get iOS workflow ID"
107+
exit 1
108+
fi
109+
ANDROID_ARTIFACTS=$(curl -s -H "Authorization: $BITRISE_API_TOKEN" \
110+
"https://api.bitrise.io/v0.1/apps/$BITRISE_APP_ID/builds/$ANDROID_WORKFLOW_ID/artifacts")
111+
112+
ANDROID_ARTIFACT_ID=$(echo "$ANDROID_ARTIFACTS" | jq -r '.data | .[] | select(.is_public_page_enabled==true) | .slug')
113+
114+
if [[ -z "$ANDROID_ARTIFACT_ID" || "$ANDROID_ARTIFACT_ID" == "null" ]]; then
115+
echo "Warning: No public Android artifact found"
116+
ANDROID_PUBLIC_URL="N/A"
117+
else
118+
ANDROID_APK=$(curl -s -H "Authorization: $BITRISE_API_TOKEN" \
119+
"https://api.bitrise.io/v0.1/apps/$BITRISE_APP_ID/builds/$ANDROID_WORKFLOW_ID/artifacts/$ANDROID_ARTIFACT_ID")
120+
ANDROID_PUBLIC_URL=$(echo "$ANDROID_APK" | jq -r '.data.public_install_page_url')
121+
fi
122+
echo "Pipeline ID: $BUILD_SLUG"
123+
echo "Android build ID: $ANDROID_WORKFLOW_ID"
124+
echo "iOS Build ID: $IOS_WORKFLOW_ID"
125+
echo "Android public link: $ANDROID_PUBLIC_URL"
126+
echo "Build number: $BUILD_NUMBER"
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
##############################################################################################
2+
#
3+
# This Workflow is responsible for triggering release candidate builds (iOS & Android).
4+
# It runs on every commit pushed to a release branch, but only when the release PR
5+
# has the 'auto-rc-builds' label.
6+
#
7+
##############################################################################################
8+
name: Auto RC builds
9+
10+
on:
11+
push:
12+
branches:
13+
- 'release/*'
14+
15+
16+
jobs:
17+
validate-and-check-label:
18+
name: Validate branch and check PR label
19+
runs-on: ubuntu-latest
20+
outputs:
21+
semver: ${{ steps.extract-version.outputs.semver }}
22+
has-label: ${{ steps.check-label.outputs.has-label }}
23+
branch-name: ${{ steps.extract-version.outputs.branch-name }}
24+
permissions:
25+
pull-requests: read
26+
steps:
27+
- name: Checkout repository
28+
uses: actions/checkout@v3
29+
with:
30+
fetch-depth: 1
31+
32+
- name: Extract semver from branch name
33+
id: extract-version
34+
run: |
35+
BRANCH_NAME="${{ github.ref_name }}"
36+
echo "Checking branch: $BRANCH_NAME"
37+
echo "branch-name=$BRANCH_NAME" >> "$GITHUB_OUTPUT"
38+
39+
# Validate branch matches release/x.y.z format (semantic versioning)
40+
if [[ "$BRANCH_NAME" =~ ^release/[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
41+
VERSION="${BRANCH_NAME#release/}"
42+
echo "Valid release branch detected: $BRANCH_NAME (version: $VERSION)"
43+
echo "semver=$VERSION" >> "$GITHUB_OUTPUT"
44+
else
45+
echo "Branch '$BRANCH_NAME' does not match release/x.y.z pattern. Skipping."
46+
echo "semver=" >> "$GITHUB_OUTPUT"
47+
exit 1
48+
fi
49+
50+
- name: Find PR and check for auto-rc-builds label
51+
id: check-label
52+
run: |
53+
BRANCH_NAME="${{ github.ref_name }}"
54+
echo "Looking for PR with head branch: $BRANCH_NAME"
55+
56+
# Find PRs where the head branch matches our release branch
57+
PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' || echo "")
58+
59+
if [[ -z "$PR_NUMBER" ]]; then
60+
echo "No PR found for branch $BRANCH_NAME. Skipping."
61+
echo "has-label=false" >> "$GITHUB_OUTPUT"
62+
exit 0
63+
fi
64+
65+
echo "Found PR #$PR_NUMBER"
66+
67+
# Check if PR has the auto-rc-builds label
68+
LABELS=$(gh pr view "$PR_NUMBER" --json labels --jq '.labels[].name' || echo "")
69+
if echo "$LABELS" | grep -qx "auto-rc-builds"; then
70+
echo "PR #$PR_NUMBER has 'auto-rc-builds' label. Proceeding with build."
71+
echo "has-label=true" >> "$GITHUB_OUTPUT"
72+
else
73+
echo "PR #$PR_NUMBER does not have 'auto-rc-builds' label. Skipping build."
74+
echo "has-label=false" >> "$GITHUB_OUTPUT"
75+
fi
76+
env:
77+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
78+
79+
bump-version:
80+
uses: ./.github/workflows/update-latest-build-version.yml
81+
needs: validate-and-check-label
82+
if: needs.validate-and-check-label.outputs.has-label == 'true'
83+
with:
84+
base-branch: ${{ github.ref_name }}
85+
secrets:
86+
PR_TOKEN: ${{ secrets.PR_TOKEN }}
87+
permissions:
88+
id-token: write
89+
contents: write
90+
91+
trigger-rc-build:
92+
runs-on: ubuntu-latest
93+
needs:
94+
- validate-and-check-label
95+
- bump-version
96+
if: needs.validate-and-check-label.outputs.has-label == 'true'
97+
steps:
98+
- name: Checkout repository
99+
uses: actions/checkout@v3
100+
with:
101+
fetch-depth: 0
102+
ref: ${{ github.ref }}
103+
- name: Trigger RC Build
104+
env:
105+
SEMVER: ${{ needs.validate-and-check-label.outputs.semver }}
106+
GH_REF_NAME: ${{ github.ref_name }}
107+
COMMIT_HASH: ${{ needs.bump-version.outputs.commit-hash }}
108+
BUILD_NUMBER: ${{ needs.bump-version.outputs.build-version }}
109+
BITRISE_APP_ID: ${{ secrets.BITRISE_APP_ID }}
110+
BITRISE_BUILD_TRIGGER_TOKEN: ${{ secrets.BITRISE_BUILD_TRIGGER_TOKEN }}
111+
BITRISE_API_TOKEN: ${{ secrets.BITRISE_API_TOKEN }}
112+
run: ./.github/scripts/rc-builds.sh
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
##############################################################################################
2+
#
3+
# This Workflow is responsible for triggering release candidate builds (iOS & Android).
4+
# You need to provide the semantic version of the release and the release branch
5+
# must exist on the repository
6+
#
7+
##############################################################################################
8+
name: Create RC builds
9+
10+
on:
11+
workflow_dispatch:
12+
inputs:
13+
semver:
14+
description: 'release version'
15+
required: true
16+
jobs:
17+
validate-input:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Validate semver input
21+
env:
22+
SEMVER: ${{ inputs.semver }}
23+
run: |
24+
set -euo pipefail
25+
26+
echo "Provided semver input: ${SEMVER}"
27+
# Validate semver format (X.Y.Z where X, Y, Z are digits)
28+
if ! [[ "${SEMVER:-}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
29+
echo "Error: semver must be numeric X.Y.Z format, got: ${SEMVER:-<empty>}" >&2
30+
exit 1
31+
fi
32+
33+
BRANCH_NAME="release/${SEMVER}"
34+
if [[ "$BRANCH_NAME" =~ [^a-zA-Z0-9._/-] ]]; then
35+
echo "Error: semver contains invalid characters for branch name" >&2
36+
exit 1
37+
fi
38+
39+
echo "Semver validation passed: ${SEMVER}"
40+
echo "Branch name: ${BRANCH_NAME}"
41+
42+
bump-version:
43+
needs: validate-input
44+
uses: ./.github/workflows/update-latest-build-version.yml
45+
with:
46+
base-branch: release/${{ inputs.semver }}
47+
secrets:
48+
PR_TOKEN: ${{ secrets.PR_TOKEN }}
49+
permissions:
50+
id-token: write
51+
contents: write
52+
53+
trigger-rc-build:
54+
runs-on: ubuntu-latest
55+
needs:
56+
- validate-input
57+
- bump-version
58+
steps:
59+
- name: Checkout repository
60+
uses: actions/checkout@v3
61+
with:
62+
fetch-depth: 0
63+
ref: release/${{ inputs.semver }}
64+
- name: Trigger RC Build
65+
env:
66+
SEMVER: ${{ inputs.semver }}
67+
GH_REF_NAME: release/${{ inputs.semver }}
68+
COMMIT_HASH: ${{ needs.bump-version.outputs.commit-hash }}
69+
BUILD_NUMBER: ${{ needs.bump-version.outputs.build-version }}
70+
BITRISE_APP_ID: ${{ secrets.BITRISE_APP_ID }}
71+
BITRISE_BUILD_TRIGGER_TOKEN: ${{ secrets.BITRISE_BUILD_TRIGGER_TOKEN }}
72+
BITRISE_API_TOKEN: ${{ secrets.BITRISE_API_TOKEN }}
73+
run: ./.github/scripts/rc-builds.sh

.github/workflows/update-latest-build-version.yml

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ on:
1313
base-branch:
1414
description: 'The base branch, tag, or SHA for git operations and the pull request.'
1515
required: true
16+
type: string
17+
workflow_call:
18+
inputs:
19+
base-branch:
20+
description: 'The base branch, tag, or SHA for git operations and the pull request.'
21+
required: true
22+
type: string
23+
secrets:
24+
PR_TOKEN:
25+
description: 'GitHub token for checkout and push operations.'
26+
required: true
27+
outputs:
28+
build-version:
29+
description: 'Generated build version number'
30+
value: ${{ jobs.generate-build-version.outputs.build-version }}
31+
commit-hash:
32+
description: 'Commit hash with build version bumped'
33+
value: ${{ jobs.bump-version.outputs.commit-hash }}
1634
jobs:
1735
generate-build-version:
1836
uses: MetaMask/metamask-mobile-build-version/.github/workflows/metamask-mobile-build-version.yml@v0.3.0
@@ -22,24 +40,29 @@ jobs:
2240
bump-version:
2341
runs-on: ubuntu-latest
2442
needs: generate-build-version
43+
outputs:
44+
commit-hash: ${{ steps.bump-build-version.outputs.commit-hash }}
2545
steps:
2646
- uses: actions/checkout@v3
2747
with:
2848
fetch-depth: 0
2949
ref: ${{ inputs.base-branch }}
30-
token: ${{ secrets.PR_TOKEN }}
31-
32-
- name: Bump script
50+
token: ${{ secrets.PR_TOKEN || github.token }}
51+
- name: Bump build version
52+
id: bump-build-version
53+
shell: bash
3354
env:
55+
BUILD_NUMBER: ${{ needs.generate-build-version.outputs.build-version }}
3456
HEAD_REF: ${{ inputs.base-branch }}
3557
run: |
36-
./scripts/set-build-version.sh ${{ needs.generate-build-version.outputs.build-version }}
58+
./scripts/set-build-version.sh "$BUILD_NUMBER"
3759
git diff
3860
git config user.name metamaskbot
3961
git config user.email metamaskbot@users.noreply.github.com
4062
git add bitrise.yml
4163
git add package.json
4264
git add ios/MetaMask.xcodeproj/project.pbxproj
4365
git add android/app/build.gradle
44-
git commit -m "[skip ci] Bump version number to ${{ needs.generate-build-version.outputs.build-version }}"
66+
git commit -m "[skip ci] Bump version number to ${BUILD_NUMBER}"
4567
git push origin HEAD:"$HEAD_REF" --force-with-lease
68+
echo "commit-hash=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"

0 commit comments

Comments
 (0)