Skip to content

Commit add2082

Browse files
committed
Merge remote-tracking branch 'upstream/main' into wildan/92418-skia-web-webgl-precheck
# Conflicts: # src/languages/de.ts # src/languages/fr.ts # src/languages/it.ts # src/languages/ja.ts # src/languages/nl.ts # src/languages/pl.ts # src/languages/pt-BR.ts # src/languages/zh-hans.ts
2 parents 7f016d6 + e279578 commit add2082

222 files changed

Lines changed: 7927 additions & 2634 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/publishReactNativeAndroidArtifacts.yml

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ on:
1111
description: 'Build HybridApp artifacts'
1212
required: false
1313
type: boolean
14+
app_pull_request_url:
15+
description: 'The Expensify/App pull request URL.'
16+
required: false
17+
default: ''
18+
mobile_expensify_pull_request_url:
19+
description: 'The Expensify/Mobile-Expensify pull request URL to check out the submodule.'
20+
required: false
21+
default: ''
1422
push:
1523
branches:
1624
- main
@@ -28,8 +36,6 @@ jobs:
2836
runs-on: 'blacksmith-4vcpu-ubuntu-2404'
2937
outputs:
3038
build_targets: ${{ steps.getArtifactBuildTargets.outputs.BUILD_TARGETS }}
31-
hybrid_app_patches_hash: ${{ steps.getNewPatchesHash.outputs.HYBRID_APP_HASH }}
32-
standalone_patches_hash: ${{ steps.getNewPatchesHash.outputs.STANDALONE_APP_HASH }}
3339
steps:
3440
- name: Checkout
3541
uses: useblacksmith/checkout@c9796daa2a4bdebdab5bd16be2c09a70cd4e1121 # v1
@@ -42,8 +48,8 @@ jobs:
4248
if: ${{ github.event_name != 'workflow_dispatch' }}
4349
id: getOldPatchesHash
4450
run: |
45-
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
46-
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
51+
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
52+
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
4753
4854
- name: Get previous react-native version
4955
if: ${{ github.event_name != 'workflow_dispatch' }}
@@ -60,8 +66,8 @@ jobs:
6066
- name: Get new patches hash
6167
id: getNewPatchesHash
6268
run: |
63-
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
64-
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
69+
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
70+
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
6571
6672
- name: Get new react-native version
6773
if: ${{ github.event_name != 'workflow_dispatch' }}
@@ -122,10 +128,19 @@ jobs:
122128
echo "BUILD_TARGETS=[\"true\"]" >> "$GITHUB_OUTPUT"
123129
fi
124130
131+
getMobileExpensifyRef:
132+
name: Resolve Mobile-Expensify ref
133+
uses: ./.github/workflows/resolveMobileExpensifyRef.yml
134+
with:
135+
APP_PULL_REQUEST_URL: ${{ inputs.app_pull_request_url }}
136+
MOBILE_EXPENSIFY_PULL_REQUEST_URL: ${{ inputs.mobile_expensify_pull_request_url }}
137+
secrets:
138+
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
139+
125140
buildAndPublishReactNativeArtifacts:
126141
name: Build and Publish React Native Artifacts
127142
runs-on: ${{ github.repository_owner == 'Expensify' && 'blacksmith-16vcpu-ubuntu-2404' || 'blacksmith-2vcpu-ubuntu-2404' }}
128-
needs: verifyPatches
143+
needs: [verifyPatches, getMobileExpensifyRef]
129144
if: needs.verifyPatches.outputs.build_targets != ''
130145
strategy:
131146
# Disable fail-fast to prevent cancelling both jobs when only one needs to be stopped due to concurrency limits
@@ -143,6 +158,24 @@ jobs:
143158
submodules: ${{ matrix.is_hybrid }}
144159
token: ${{ secrets.OS_BOTIFY_TOKEN }}
145160

161+
- name: Checkout Mobile-Expensify to specified branch or commit
162+
if: ${{ matrix.is_hybrid == 'true' && needs.getMobileExpensifyRef.outputs.MOBILE_EXPENSIFY_REF != '' }}
163+
run: |
164+
cd Mobile-Expensify
165+
git fetch origin ${{ needs.getMobileExpensifyRef.outputs.MOBILE_EXPENSIFY_REF }}
166+
git checkout ${{ needs.getMobileExpensifyRef.outputs.MOBILE_EXPENSIFY_REF }}
167+
168+
# Recompute the patches hash from the actually checked-out tree (which may include a custom Mobile-Expensify
169+
# ref) so the published artifact is tagged with a hash that consumers will match against.
170+
- name: Compute patches hash
171+
id: computePatchesHash
172+
run: |
173+
if [[ '${{ matrix.is_hybrid }}' == 'true' ]]; then
174+
echo "PATCHES_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
175+
else
176+
echo "PATCHES_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
177+
fi
178+
146179
- name: Setup Node
147180
uses: ./.github/actions/composite/setupNode
148181
with:
@@ -194,7 +227,7 @@ jobs:
194227
GH_PUBLISH_TOKEN: ${{ github.token }}
195228
IS_HYBRID_BUILD: ${{ matrix.is_hybrid }}
196229
PATCHED_VERSION: ${{ steps.getNewPatchedVersion.outputs.NEW_PATCHED_VERSION }}
197-
PATCHES_HASH: ${{ matrix.is_hybrid == 'true' && needs.verifyPatches.outputs.hybrid_app_patches_hash || needs.verifyPatches.outputs.standalone_patches_hash }}
230+
PATCHES_HASH: ${{ steps.computePatchesHash.outputs.PATCHES_HASH }}
198231
CMAKE_VERSION: 3.31.6
199232

200233
- name: Announce failed workflow in Slack
@@ -203,3 +236,4 @@ jobs:
203236
with:
204237
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
205238
CHANNEL: '#expensify-open-source'
239+
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: Resolve Mobile-Expensify ref
2+
3+
# Reusable workflow that resolves which Expensify/Mobile-Expensify commit a build should check out.
4+
# Resolution order:
5+
# 1. An explicit Mobile-Expensify PR URL (MOBILE_EXPENSIFY_PULL_REQUEST_URL), if provided.
6+
# 2. Otherwise, a `MOBILE-EXPENSIFY: <pr-url>` entry in the body of the App PR (APP_PULL_REQUEST_URL).
7+
# 3. Otherwise, empty — callers fall back to the pinned submodule commit.
8+
on:
9+
workflow_call:
10+
inputs:
11+
APP_PULL_REQUEST_URL:
12+
description: The Expensify/App pull request URL. Its description is scanned for a MOBILE-EXPENSIFY entry. Ignored if a Mobile-Expensify PR URL is provided.
13+
required: false
14+
type: string
15+
default: ''
16+
MOBILE_EXPENSIFY_PULL_REQUEST_URL:
17+
description: The Expensify/Mobile-Expensify pull request URL. Overrides MOBILE-EXPENSIFY set in the App PR description.
18+
required: false
19+
type: string
20+
default: ''
21+
outputs:
22+
APP_PR_NUMBER:
23+
description: PR number extracted from the App PR URL (empty if none).
24+
value: ${{ jobs.resolve.outputs.APP_PR_NUMBER }}
25+
MOBILE_EXPENSIFY_PR:
26+
description: Resolved Mobile-Expensify PR number (empty if none).
27+
value: ${{ jobs.resolve.outputs.MOBILE_EXPENSIFY_PR }}
28+
MOBILE_EXPENSIFY_REF:
29+
description: Resolved Mobile-Expensify head SHA (empty to use the pinned submodule commit).
30+
value: ${{ jobs.resolve.outputs.MOBILE_EXPENSIFY_REF }}
31+
secrets:
32+
OS_BOTIFY_TOKEN:
33+
description: Token with read access to Expensify/Mobile-Expensify, used to resolve the PR head ref.
34+
required: true
35+
36+
jobs:
37+
resolve:
38+
name: Resolve Mobile-Expensify ref
39+
runs-on: 'blacksmith-4vcpu-ubuntu-2404'
40+
outputs:
41+
APP_PR_NUMBER: ${{ steps.extractAppPRNumber.outputs.PR_NUMBER }}
42+
MOBILE_EXPENSIFY_PR: ${{ steps.mobileExpensifyPR.outputs.result }}
43+
MOBILE_EXPENSIFY_REF: ${{ steps.getHeadRef.outputs.REF }}
44+
steps:
45+
- name: Extract App PR number from URL
46+
id: extractAppPRNumber
47+
if: ${{ inputs.APP_PULL_REQUEST_URL != '' }}
48+
run: |
49+
PR_NUMBER=$(echo '${{ inputs.APP_PULL_REQUEST_URL }}' | sed -E 's|.*/pull/([0-9]+).*|\1|')
50+
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
51+
echo "::error::❌ Could not extract PR number from the App PR URL. Please provide a valid GitHub PR URL (e.g., https://github.com/Expensify/App/pull/12345)"
52+
exit 1
53+
fi
54+
echo "PR_NUMBER=$PR_NUMBER" >> "$GITHUB_OUTPUT"
55+
56+
- name: Extract Mobile-Expensify PR number from URL
57+
id: extractMobilePRNumber
58+
if: ${{ inputs.MOBILE_EXPENSIFY_PULL_REQUEST_URL != '' }}
59+
run: |
60+
PR_NUMBER=$(echo '${{ inputs.MOBILE_EXPENSIFY_PULL_REQUEST_URL }}' | sed -E 's|.*/pull/([0-9]+).*|\1|')
61+
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
62+
echo "::error::❌ Could not extract PR number from the Mobile-Expensify PR URL. Please provide a valid GitHub PR URL (e.g., https://github.com/Expensify/Mobile-Expensify/pull/12345)"
63+
exit 1
64+
fi
65+
echo "PR_NUMBER=$PR_NUMBER" >> "$GITHUB_OUTPUT"
66+
67+
- name: Resolve which Mobile-Expensify PR to use
68+
id: mobileExpensifyPR
69+
# v8
70+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd
71+
with:
72+
github-token: ${{ github.token }}
73+
result-encoding: string
74+
script: |
75+
// An explicit Mobile-Expensify PR URL takes precedence over the App PR description
76+
if ('${{ steps.extractMobilePRNumber.outputs.PR_NUMBER }}') {
77+
return '${{ steps.extractMobilePRNumber.outputs.PR_NUMBER }}';
78+
}
79+
80+
if (!'${{ steps.extractAppPRNumber.outputs.PR_NUMBER }}') {
81+
return '';
82+
}
83+
84+
const pullRequest = await github.rest.pulls.get({
85+
owner: context.repo.owner,
86+
repo: context.repo.repo,
87+
pull_number: '${{ steps.extractAppPRNumber.outputs.PR_NUMBER }}',
88+
});
89+
90+
const body = pullRequest.data.body ?? '';
91+
const regex = /MOBILE-EXPENSIFY:\s*https:\/\/github.com\/Expensify\/Mobile-Expensify\/pull\/(?<prNumber>\d+)/;
92+
const found = body.match(regex)?.groups?.prNumber || "";
93+
94+
return found.trim();
95+
96+
- name: Resolve Mobile-Expensify head ref from PR number
97+
id: getHeadRef
98+
if: ${{ steps.mobileExpensifyPR.outputs.result != '' }}
99+
run: |
100+
set -e
101+
echo "REF=$(gh pr view ${{ steps.mobileExpensifyPR.outputs.result }} -R Expensify/Mobile-Expensify --json headRefOid --jq '.headRefOid')" >> "$GITHUB_OUTPUT"
102+
env:
103+
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}

.github/workflows/testBuild.yml

Lines changed: 13 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ jobs:
4141
outputs:
4242
APP_REF: ${{ steps.getHeadRef.outputs.REF || 'main' }}
4343
APP_PR_NUMBER: ${{ steps.extractAppPRNumber.outputs.PR_NUMBER }}
44-
MOBILE_PR_NUMBER: ${{ steps.extractMobilePRNumber.outputs.PR_NUMBER }}
4544
steps:
4645
- name: Checkout
4746
uses: useblacksmith/checkout@c9796daa2a4bdebdab5bd16be2c09a70cd4e1121 # v1
@@ -69,17 +68,6 @@ jobs:
6968
fi
7069
echo "PR_NUMBER=$PR_NUMBER" >> "$GITHUB_OUTPUT"
7170
72-
- name: Extract Mobile-Expensify PR number from URL
73-
id: extractMobilePRNumber
74-
if: ${{ inputs.MOBILE_EXPENSIFY_PULL_REQUEST_URL != '' }}
75-
run: |
76-
PR_NUMBER=$(echo '${{ inputs.MOBILE_EXPENSIFY_PULL_REQUEST_URL }}' | sed -E 's|.*/pull/([0-9]+).*|\1|')
77-
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
78-
echo "::error::❌ Could not extract PR number from URL. Please provide a valid GitHub PR URL (e.g., https://github.com/Expensify/Mobile-Expensify/pull/12345)"
79-
exit 1
80-
fi
81-
echo "PR_NUMBER=$PR_NUMBER" >> "$GITHUB_OUTPUT"
82-
8371
- name: Check if App pull request number is correct
8472
id: getHeadRef
8573
run: |
@@ -92,70 +80,26 @@ jobs:
9280
env:
9381
GITHUB_TOKEN: ${{ github.token }}
9482

95-
getMobileExpensifyPR:
96-
runs-on: blacksmith-4vcpu-ubuntu-2404
97-
needs: [prep]
98-
outputs:
99-
MOBILE_EXPENSIFY_PR: ${{ steps.mobileExpensifyPR.outputs.result }}
100-
steps:
101-
- name: Check if author specified Expensify/Mobile-Expensify PR
102-
id: mobileExpensifyPR
103-
# v8
104-
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd
105-
with:
106-
github-token: ${{ github.token }}
107-
result-encoding: string
108-
script: |
109-
if ('${{ needs.prep.outputs.MOBILE_PR_NUMBER }}') {
110-
return '${{ needs.prep.outputs.MOBILE_PR_NUMBER }}';
111-
}
112-
113-
if (!'${{ needs.prep.outputs.APP_PR_NUMBER }}') {
114-
return '';
115-
}
116-
117-
const pullRequest = await github.rest.pulls.get({
118-
owner: context.repo.owner,
119-
repo: context.repo.repo,
120-
pull_number: '${{ needs.prep.outputs.APP_PR_NUMBER }}',
121-
});
122-
123-
const body = pullRequest.data.body;
124-
const regex = /MOBILE-EXPENSIFY:\s*https:\/\/github.com\/Expensify\/Mobile-Expensify\/pull\/(?<prNumber>\d+)/;
125-
const found = body.match(regex)?.groups?.prNumber || "";
126-
127-
return found.trim();
128-
83+
# Resolves the Mobile-Expensify ref from the explicit ME PR URL or the App PR's MOBILE-EXPENSIFY entry.
84+
# `needs: [prep]` gates this behind prep's actor validation before any token is used.
12985
getMobileExpensifyRef:
130-
runs-on: blacksmith-4vcpu-ubuntu-2404
131-
needs: [prep, getMobileExpensifyPR]
132-
outputs:
133-
MOBILE_EXPENSIFY_REF: ${{ steps.getHeadRef.outputs.REF || 'main' }}
134-
steps:
135-
- name: Checkout
136-
uses: useblacksmith/checkout@c9796daa2a4bdebdab5bd16be2c09a70cd4e1121 # v1
137-
138-
- name: Check if Expensify/Mobile-Expensify pull request number is correct
139-
id: getHeadRef
140-
run: |
141-
set -e
142-
if [[ -z "${{ needs.prep.outputs.MOBILE_PR_NUMBER }}" && -z "${{ needs.getMobileExpensifyPR.outputs.MOBILE_EXPENSIFY_PR }}" ]]; then
143-
echo "REF=" >> "$GITHUB_OUTPUT"
144-
else
145-
echo "PR=${{ needs.prep.outputs.MOBILE_PR_NUMBER || needs.getMobileExpensifyPR.outputs.MOBILE_EXPENSIFY_PR }}" >> "$GITHUB_OUTPUT"
146-
echo "REF=$(gh pr view ${{ needs.prep.outputs.MOBILE_PR_NUMBER || needs.getMobileExpensifyPR.outputs.MOBILE_EXPENSIFY_PR }} -R Expensify/Mobile-Expensify --json headRefOid --jq '.headRefOid')" >> "$GITHUB_OUTPUT"
147-
fi
148-
env:
149-
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
86+
needs: [prep]
87+
uses: ./.github/workflows/resolveMobileExpensifyRef.yml
88+
with:
89+
APP_PULL_REQUEST_URL: ${{ inputs.APP_PULL_REQUEST_URL }}
90+
MOBILE_EXPENSIFY_PULL_REQUEST_URL: ${{ inputs.MOBILE_EXPENSIFY_PULL_REQUEST_URL }}
91+
secrets:
92+
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
15093

15194
buildApps:
152-
needs: [prep, getMobileExpensifyPR, getMobileExpensifyRef]
95+
needs: [prep, getMobileExpensifyRef]
15396
uses: ./.github/workflows/buildAdHoc.yml
15497
with:
15598
APP_REF: ${{ needs.prep.outputs.APP_REF }}
15699
APP_PR_NUMBER: ${{ needs.prep.outputs.APP_PR_NUMBER }}
157-
MOBILE_EXPENSIFY_REF: ${{ needs.getMobileExpensifyRef.outputs.MOBILE_EXPENSIFY_REF }}
158-
MOBILE_EXPENSIFY_PR: ${{ needs.getMobileExpensifyPR.outputs.MOBILE_EXPENSIFY_PR }}
100+
# Fall back to Mobile-Expensify main when nothing is resolved (test builds track the latest OldDot).
101+
MOBILE_EXPENSIFY_REF: ${{ needs.getMobileExpensifyRef.outputs.MOBILE_EXPENSIFY_REF || 'main' }}
102+
MOBILE_EXPENSIFY_PR: ${{ needs.getMobileExpensifyRef.outputs.MOBILE_EXPENSIFY_PR }}
159103
BUILD_WEB: ${{ inputs.WEB && 'true' || 'false' }}
160104
BUILD_IOS: ${{ inputs.IOS && 'true' || 'false' }}
161105
BUILD_ANDROID: ${{ inputs.ANDROID && 'true' || 'false' }}

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ android {
111111
minSdkVersion rootProject.ext.minSdkVersion
112112
targetSdkVersion rootProject.ext.targetSdkVersion
113113
multiDexEnabled rootProject.ext.multiDexEnabled
114-
versionCode 1009042600
115-
versionName "9.4.26-0"
114+
versionCode 1009042604
115+
versionName "9.4.26-4"
116116
// Supported language variants must be declared here to avoid from being removed during the compilation.
117117
// This also helps us to not include unnecessary language variants in the APK.
118118
resConfigs "en", "es"

android/app/src/debug/AndroidManifest.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,12 @@
44

55
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
66
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
7-
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
7+
<!-- Debug builds use a pin-free network security config so local dev servers and debugging
8+
proxies keep working. tools:replace overrides the release config from the main manifest. -->
9+
<application
10+
android:networkSecurityConfig="@xml/network_security_config_debug"
11+
android:usesCleartextTraffic="true"
12+
tools:targetApi="28"
13+
tools:ignore="GoogleAppIndexingWarning"
14+
tools:replace="android:networkSecurityConfig" />
815
</manifest>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Debug-only network security config. Intentionally contains NO <pin-set> so that local
4+
development against dev/proxy/ngrok servers (and debugging proxies such as Charles/Proxyman)
5+
keeps working. Permits cleartext traffic and trusts user-installed CA certificates.
6+
7+
Release builds use res/xml/network_security_config.xml (monitor-only, no <pin-set>) or
8+
network_security_config_enforce.xml when enforcePinning is enabled.
9+
-->
10+
<network-security-config>
11+
<base-config cleartextTrafficPermitted="true">
12+
<trust-anchors>
13+
<certificates src="system" />
14+
<certificates src="user" />
15+
</trust-anchors>
16+
</base-config>
17+
</network-security-config>

android/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
android:hardwareAccelerated="true"
2222
android:icon="@mipmap/ic_launcher"
2323
android:label="@string/app_name"
24+
android:networkSecurityConfig="@xml/network_security_config"
2425
android:resizeableActivity="false"
2526
android:supportsRtl="false"
2627
android:theme="@style/AppTheme"

0 commit comments

Comments
 (0)