chore: stable-sync 7.75.0 into release/7.75.1 (#29688) #804
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ############################################################################################## | |
| # | |
| # This Workflow is responsible for triggering release candidate builds (iOS & Android). | |
| # It runs automatically on every commit pushed to a release branch that has an open PR. | |
| # | |
| # Rolling builds: when a new run starts for the same release branch, any queued or | |
| # in-progress run of this workflow for that branch is cancelled (same behavior as | |
| # Bitrise "Rolling builds" / "Abort running builds" for one branch + one workflow). | |
| # | |
| # Version bump runs once (update-latest-build-version.yml), then iOS and Android | |
| # builds are triggered in parallel via runway-ota-build-core.yml (skip_version_bump). | |
| # | |
| # The RC build comment includes an AI-generated test plan (inline with collapsible sections). | |
| # | |
| ############################################################################################## | |
| name: Auto RC builds | |
| on: | |
| push: | |
| branches: | |
| - 'release/*' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| actions: write | |
| id-token: write | |
| jobs: | |
| validate-and-find-pr: | |
| name: Validate branch and find PR | |
| runs-on: ubuntu-latest | |
| outputs: | |
| semver: ${{ steps.extract-version.outputs.semver }} | |
| has-pr: ${{ steps.find-pr.outputs.has-pr }} | |
| branch-name: ${{ steps.extract-version.outputs.branch-name }} | |
| pr-number: ${{ steps.find-pr.outputs.pr-number }} | |
| permissions: | |
| pull-requests: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v3 | |
| with: | |
| fetch-depth: 1 | |
| - name: Extract semver from branch name | |
| id: extract-version | |
| run: | | |
| BRANCH_NAME="${{ github.ref_name }}" | |
| echo "Checking branch: $BRANCH_NAME" | |
| echo "branch-name=$BRANCH_NAME" >> "$GITHUB_OUTPUT" | |
| # Validate branch matches release/x.y.z or release/x.y.z-ota (OTA hotfix) format | |
| if [[ "$BRANCH_NAME" =~ ^release/[0-9]+\.[0-9]+\.[0-9]+(-ota)?$ ]]; then | |
| VERSION="${BRANCH_NAME#release/}" | |
| # Strip `-ota` suffix: it is a branch-name convention only. Downstream consumers | |
| # (build-announce display "RC X.Y.Z", test-plan artifact name) expect strict X.Y.Z. | |
| VERSION="${VERSION%-ota}" | |
| echo "Valid release branch detected: $BRANCH_NAME (version: $VERSION)" | |
| echo "semver=$VERSION" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Branch '$BRANCH_NAME' does not match release/x.y.z or release/x.y.z-ota pattern. Skipping." | |
| echo "semver=" >> "$GITHUB_OUTPUT" | |
| exit 1 | |
| fi | |
| - name: Find associated PR | |
| id: find-pr | |
| run: | | |
| BRANCH_NAME="${{ github.ref_name }}" | |
| echo "Looking for PR with head branch: $BRANCH_NAME" | |
| # Find PRs where the head branch matches our release branch | |
| PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' || echo "") | |
| if [[ -z "$PR_NUMBER" ]]; then | |
| echo "No PR found for branch $BRANCH_NAME. Skipping." | |
| echo "has-pr=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "Found PR #$PR_NUMBER - proceeding with RC build" | |
| echo "pr-number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | |
| echo "has-pr=true" >> "$GITHUB_OUTPUT" | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| update_rc_build_version: | |
| name: Update RC build version | |
| uses: ./.github/workflows/update-latest-build-version.yml | |
| needs: validate-and-find-pr | |
| if: needs.validate-and-find-pr.outputs.has-pr == 'true' | |
| permissions: | |
| contents: write | |
| id-token: write | |
| with: | |
| base-branch: ${{ needs.validate-and-find-pr.outputs.branch-name }} | |
| secrets: | |
| PR_TOKEN: ${{ secrets.PR_TOKEN }} | |
| trigger-ios-rc-build: | |
| name: Trigger iOS RC Build | |
| uses: ./.github/workflows/runway-ota-build-core.yml | |
| needs: | |
| - validate-and-find-pr | |
| - update_rc_build_version | |
| if: needs.validate-and-find-pr.outputs.has-pr == 'true' | |
| with: | |
| platform: ios | |
| source_branch: ${{ needs.update_rc_build_version.outputs.commit-hash }} | |
| skip_version_bump: true | |
| secrets: inherit | |
| trigger-android-rc-build: | |
| name: Trigger Android RC Build | |
| uses: ./.github/workflows/runway-ota-build-core.yml | |
| needs: | |
| - validate-and-find-pr | |
| - update_rc_build_version | |
| if: needs.validate-and-find-pr.outputs.has-pr == 'true' | |
| with: | |
| platform: android | |
| source_branch: ${{ needs.update_rc_build_version.outputs.commit-hash }} | |
| skip_version_bump: true | |
| secrets: inherit | |
| post-rc-build-comment: | |
| name: Post RC Build Comment with Test Plan | |
| runs-on: ubuntu-latest | |
| needs: | |
| - validate-and-find-pr | |
| - trigger-ios-rc-build | |
| - trigger-android-rc-build | |
| if: always() && needs.trigger-ios-rc-build.result == 'success' && needs.trigger-android-rc-build.result == 'success' && needs.validate-and-find-pr.outputs.pr-number != '' | |
| environment: release-ci | |
| permissions: | |
| pull-requests: write | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.validate-and-find-pr.outputs.branch-name }} | |
| fetch-depth: 50 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: yarn | |
| - name: Install dependencies | |
| run: yarn install --immutable | |
| - name: Post RC Build Comment with Test Plan | |
| run: node -r esbuild-register scripts/build-announce/index.ts | |
| timeout-minutes: 8 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ needs.validate-and-find-pr.outputs.pr-number }} | |
| SEMVER: ${{ needs.validate-and-find-pr.outputs.semver }} | |
| IOS_BUILD_NUMBER: ${{ needs.trigger-ios-rc-build.outputs.ios_version_code }} | |
| ANDROID_BUILD_NUMBER: ${{ needs.trigger-android-rc-build.outputs.android_version_code }} | |
| BUILD_PIPELINE_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| # AI Provider keys for test plan generation | |
| E2E_CLAUDE_API_KEY: ${{ secrets.E2E_CLAUDE_API_KEY }} | |
| E2E_OPENAI_API_KEY: ${{ secrets.E2E_OPENAI_API_KEY }} | |
| E2E_GEMINI_API_KEY: ${{ secrets.E2E_GEMINI_API_KEY }} | |
| - name: Upload test plan JSON artifact | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-plan-${{ needs.validate-and-find-pr.outputs.semver }} | |
| path: release-test-plan.json | |
| compression-level: 0 | |
| if-no-files-found: ignore | |
| retention-days: 90 | |
| slack-notification: | |
| name: Slack RC Notification | |
| needs: | |
| - validate-and-find-pr | |
| - trigger-ios-rc-build | |
| - trigger-android-rc-build | |
| if: always() && needs.trigger-ios-rc-build.result == 'success' && needs.trigger-android-rc-build.result == 'success' | |
| uses: ./.github/workflows/slack-rc-notification.yml | |
| with: | |
| source_branch: ${{ needs.validate-and-find-pr.outputs.branch-name }} | |
| semver: ${{ needs.trigger-ios-rc-build.outputs.semantic_version }} | |
| ios_build_number: ${{ needs.trigger-ios-rc-build.outputs.ios_version_code }} | |
| android_build_number: ${{ needs.trigger-android-rc-build.outputs.android_version_code }} | |
| secrets: inherit |