Skip to content

Merge pull request #97365 from cretadn22/refactor/66419-createDraftTr… #12

Merge pull request #97365 from cretadn22/refactor/66419-createDraftTr…

Merge pull request #97365 from cretadn22/refactor/66419-createDraftTr… #12

name: Publish React Native Artifacts
# Single entry point for building + publishing our prebuilt React Native artifacts.
# Runs the platform-independent phases (verify patches / validate request / resolve refs) ONCE,
# then fans out to the iOS and Android publish workflows in parallel. Always builds both platforms.
on:
workflow_dispatch:
inputs:
build_standalone:
description: 'Build Standalone artifacts'
required: false
type: boolean
build_hybridapp:
description: 'Build HybridApp artifacts'
required: false
type: boolean
app_pull_request_url:
description: 'The Expensify/App pull request URL.'
required: false
default: ''
mobile_expensify_pull_request_url:
description: 'The Expensify/Mobile-Expensify pull request URL to check out the submodule.'
required: false
default: ''
reviewed_code:
description: I reviewed this pull request and verified that it does not contain any malicious code.
type: boolean
required: true
default: false
push:
branches:
- main
paths:
- package.json
- patches/react-native+*.patch
- patches/@react-native+*.patch
- patches/react-native/react-native+*.patch
- patches/react-native/@react-native+*.patch
- Mobile-Expensify
- scripts/compute-patches-hash.sh
jobs:
verifyPatches:
name: Verify React Native Patches
runs-on: blacksmith-4vcpu-ubuntu-2404
env:
BUILD_STANDALONE: ${{ github.event_name == 'workflow_dispatch' && inputs.build_standalone || false }}
BUILD_HYBRIDAPP: ${{ github.event_name == 'workflow_dispatch' && inputs.build_hybridapp || false }}
outputs:
build_targets: ${{ steps.getArtifactBuildTargets.outputs.BUILD_TARGETS }}
steps:
- name: Checkout
# v1
uses: useblacksmith/checkout@1c9394c220d293645707b625ba9d79685f093a8f
with:
submodules: true
ref: ${{ github.event.before || 'main' }}
token: ${{ secrets.OS_BOTIFY_TOKEN }}
- name: Get previous patches hash
if: ${{ github.event.after != '' }}
id: getOldPatchesHash
run: |
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
- name: Get previous react-native version
if: ${{ github.event.after != '' }}
id: getOldVersion
run: echo "VERSION=$(jq -r '.dependencies["react-native"]' package.json)" >> "$GITHUB_OUTPUT"
- name: Checkout new ref
if: ${{ github.event.after != '' }}
run: |
git fetch origin ${{ github.event.after }} --depth=1
git checkout ${{ github.event.after }}
git submodule update
- name: Get new patches hash
id: getNewPatchesHash
run: |
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
- name: Get new react-native version
if: ${{ github.event.after != '' }}
id: getNewVersion
run: echo "VERSION=$(jq -r '.dependencies["react-native"]' package.json)" >> "$GITHUB_OUTPUT"
- name: Check if version changed
if: ${{ github.event.after != '' }}
id: didVersionChange
run: |
readonly DID_VERSION_CHANGE=${{ steps.getOldVersion.outputs.VERSION != steps.getNewVersion.outputs.VERSION && 'true' || 'false' }}
echo "DID_VERSION_CHANGE=$DID_VERSION_CHANGE" >> "$GITHUB_OUTPUT"
if [[ "$DID_VERSION_CHANGE" == 'true' ]]; then
echo "::notice::Detected react-native version bump (${{ steps.getOldVersion.outputs.VERSION }} -> ${{ steps.getNewVersion.outputs.VERSION }})"
fi
- name: Check if patches changed
if: ${{ github.event.after != '' }}
id: didPatchesChange
run: |
readonly DID_HYBRID_APP_PATCHES_CHANGE=${{ steps.getOldPatchesHash.outputs.HYBRID_APP_HASH != steps.getNewPatchesHash.outputs.HYBRID_APP_HASH && 'true' || 'false' }}
readonly DID_STANDALONE_APP_PATCHES_CHANGE=${{ steps.getOldPatchesHash.outputs.STANDALONE_APP_HASH != steps.getNewPatchesHash.outputs.STANDALONE_APP_HASH && 'true' || 'false' }}
echo "DID_HYBRID_APP_PATCHES_CHANGE=$DID_HYBRID_APP_PATCHES_CHANGE" >> "$GITHUB_OUTPUT"
echo "DID_STANDALONE_APP_PATCHES_CHANGE=$DID_STANDALONE_APP_PATCHES_CHANGE" >> "$GITHUB_OUTPUT"
if [[ "$DID_HYBRID_APP_PATCHES_CHANGE" == 'true' ]]; then
echo "::notice::Detected changes in HybridApp patches (${{ steps.getOldPatchesHash.outputs.HYBRID_APP_HASH }} -> ${{ steps.getNewPatchesHash.outputs.HYBRID_APP_HASH }})"
fi
if [[ "$DID_STANDALONE_APP_PATCHES_CHANGE" == 'true' ]]; then
echo "::notice::Detected changes in Standalone NewDot patches (${{ steps.getOldPatchesHash.outputs.STANDALONE_APP_HASH }} -> ${{ steps.getNewPatchesHash.outputs.STANDALONE_APP_HASH }})"
fi
- name: Get artifact build targets
id: getArtifactBuildTargets
run: |
# workflow_dispatch path: no push ref, so build from the explicit toggles.
if [[ '${{ github.event.after }}' == '' ]]; then
BUILD_TARGETS=()
if [[ "$BUILD_STANDALONE" == 'true' ]]; then
BUILD_TARGETS+=(false)
fi
if [[ "$BUILD_HYBRIDAPP" == 'true' ]]; then
BUILD_TARGETS+=(true)
fi
if [[ ${#BUILD_TARGETS[@]} -ne 0 ]]; then
echo "BUILD_TARGETS=$(printf '%s\n' "${BUILD_TARGETS[@]}" | jq -R . | jq -c -s .)" >> "$GITHUB_OUTPUT"
fi
exit 0
fi
# push path: derive targets from what actually changed between github.event.before and github.event.after.
# Version change or standalone patch change forces a full rebuild of both hybrid and standalone.
if [[ '${{ steps.didVersionChange.outputs.DID_VERSION_CHANGE }}' == 'true' || '${{ steps.didPatchesChange.outputs.DID_STANDALONE_APP_PATCHES_CHANGE }}' == 'true' ]]; then
echo "BUILD_TARGETS=[\"true\", \"false\"]" >> "$GITHUB_OUTPUT"
elif [[ '${{ steps.didPatchesChange.outputs.DID_HYBRID_APP_PATCHES_CHANGE }}' == 'true' ]]; then
echo "BUILD_TARGETS=[\"true\"]" >> "$GITHUB_OUTPUT"
fi
# Validates the actor and that they reviewed the PR before any token is used or untrusted App PR code is checked out.
prep:
uses: ./.github/workflows/validateBuildRequest.yml
with:
REVIEWED_CODE: ${{ inputs.reviewed_code || false }}
secrets:
OS_BOTIFY_COMMIT_TOKEN: ${{ secrets.OS_BOTIFY_COMMIT_TOKEN }}
resolveRefs:
name: Resolve build refs
needs: [prep]
uses: ./.github/workflows/resolveBuildRefs.yml
with:
APP_PULL_REQUEST_URL: ${{ inputs.app_pull_request_url }}
MOBILE_EXPENSIFY_PULL_REQUEST_URL: ${{ inputs.mobile_expensify_pull_request_url }}
secrets:
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
# Fail-fast: a manual dispatch that ticks neither variant yields no build targets. Without this the run
# would be a confusing green no-op. On push an empty build_targets is a legitimate "nothing changed".
assertHasTargets:
needs: [verifyPatches]
if: github.event_name == 'workflow_dispatch' && needs.verifyPatches.outputs.build_targets == ''
runs-on: ubuntu-latest
steps:
- name: Fail when nothing was selected to build
run: |
echo "::error::No build targets selected — tick build_standalone and/or build_hybridapp."
exit 1
ios:
name: iOS
needs: [verifyPatches, prep, resolveRefs]
if: needs.verifyPatches.outputs.build_targets != ''
uses: ./.github/workflows/publishReactNativeiOSArtifacts.yml
with:
build_targets: ${{ needs.verifyPatches.outputs.build_targets }}
app_ref: ${{ needs.resolveRefs.outputs.APP_REF }}
mobile_expensify_ref: ${{ needs.resolveRefs.outputs.MOBILE_EXPENSIFY_REF }}
secrets: inherit
android:
name: Android
needs: [verifyPatches, prep, resolveRefs]
if: needs.verifyPatches.outputs.build_targets != ''
uses: ./.github/workflows/publishReactNativeAndroidArtifacts.yml
with:
build_targets: ${{ needs.verifyPatches.outputs.build_targets }}
app_ref: ${{ needs.resolveRefs.outputs.APP_REF }}
mobile_expensify_ref: ${{ needs.resolveRefs.outputs.MOBILE_EXPENSIFY_REF }}
secrets: inherit