History

chore: setup eas ci (#2911)

Yash Singh committed 5 months ago

Commit dca93d01 parent 128890910 files · +255 −6Browse files

Unified · Split

10 files
  1. .github/workflows/mobile-eas-preview.yml +78 −0
  2. apps/mobile/.fingerprintignore +24 −0
  3. apps/mobile/README.md +9 −0
  4. apps/mobile/app.config.ts +2 −1
  5. apps/mobile/eas.json +15 −0
  6. apps/mobile/package.json +3 −0
  7. package.json +2 −0
  8. patches/@expo%2Fmetro-config@56.0.13.patch +93 −0
  9. pnpm-lock.yaml +28 −5
  10. pnpm-workspace.yaml +1 −0
.github/workflows/mobile-eas-preview.yml+78−0
@@ -0,0 +1,78 @@
1+name: Mobile EAS Preview
2+
3+on:
4+ pull_request:
5+
6+jobs:
7+ preview:
8+ name: EAS Preview
9+ runs-on: blacksmith-8vcpu-ubuntu-2404
10+ permissions:
11+ contents: read
12+ pull-requests: write
13+ env:
14+ APP_VARIANT: preview
15+ NODE_OPTIONS: --max-old-space-size=8192
16+ MOBILE_VERSION_POLICY: fingerprint
17+ steps:
18+ - id: expo-token
19+ name: Check for EXPO_TOKEN
20+ env:
21+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
22+ run: |
23+ if [ -n "$EXPO_TOKEN" ]; then
24+ echo "present=true" >> "$GITHUB_OUTPUT"
25+ else
26+ echo "present=false" >> "$GITHUB_OUTPUT"
27+ echo "EXPO_TOKEN is not available; skipping EAS preview."
28+ fi
29+
30+ - name: Checkout
31+ if: steps.expo-token.outputs.present == 'true'
32+ uses: actions/checkout@v6
33+ with:
34+ fetch-depth: 0
35+
36+ - name: Setup Vite+
37+ if: steps.expo-token.outputs.present == 'true'
38+ uses: voidzero-dev/setup-vp@v1
39+ with:
40+ node-version-file: package.json
41+ cache: true
42+ run-install: true
43+
44+ - name: Expose pnpm
45+ if: steps.expo-token.outputs.present == 'true'
46+ run: |
47+ pnpm_version="$(node --print "require('./package.json').packageManager.split('@').pop()")"
48+ vp_pnpm_bin="$HOME/.vite-plus/package_manager/pnpm/$pnpm_version/pnpm/bin"
49+ echo "$vp_pnpm_bin" >> "$GITHUB_PATH"
50+ "$vp_pnpm_bin/pnpm" --version
51+
52+ - name: Setup EAS
53+ if: steps.expo-token.outputs.present == 'true'
54+ uses: expo/expo-github-action@v8
55+ with:
56+ eas-version: latest
57+ token: ${{ secrets.EXPO_TOKEN }}
58+ packager: pnpm
59+
60+ - name: Pull preview environment variables
61+ if: steps.expo-token.outputs.present == 'true'
62+ working-directory: apps/mobile
63+ env:
64+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
65+ run: eas env:pull preview --non-interactive
66+
67+ - name: Deploy with fingerprint check
68+ if: steps.expo-token.outputs.present == 'true'
69+ uses: expo/expo-github-action/continuous-deploy-fingerprint@main
70+ env:
71+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
72+ with:
73+ profile: preview:dev
74+ branch: pr-${{ github.event.pull_request.number }}
75+ platform: all
76+ environment: preview
77+ working-directory: apps/mobile
78+ github-token: ${{ secrets.GITHUB_TOKEN }}
apps/mobile/.fingerprintignore+24−0
@@ -0,0 +1,24 @@
1+# Expo artifacts
2+.expo/
3+.eas/
4+
5+# Build outputs
6+android/
7+ios/
8+dist/
9+web-build/
10+
11+# Test files
12+**/*.test.ts
13+**/*.test.tsx
14+
15+# Docs
16+*.md
17+
18+# Local env
19+.env
20+.env.local
21+.env*.local
22+
23+# TypeScript
24+*.tsbuildinfo
apps/mobile/README.md+9−0
@@ -61,6 +61,14 @@ The native lint task runs SwiftLint for Swift plus ktlint and detekt for Kotlin. · 60 unmodified lines
6161
6262 ## EAS Builds
6363
64+CI uses Expo fingerprinting with the `preview:dev` profile to reuse an existing compatible build when possible, or start a new internal EAS build when native runtime inputs change. Production and default local builds continue to use the `appVersion` runtime policy.
65+
66+Create a PR preview dev-client build manually:
67+
68+```bash
69+vp run eas:ios:preview:dev
70+```
71+
6472 Create a cloud dev-client build:
6573
6674 ```bash
@@ -77,5 +85,6 @@ Android equivalents: · 10 unmodified lines
7785
7886 ```bash
7987 vp run eas:android:dev
88+vp run eas:android:preview:dev
8089 vp run eas:android:preview
8190 ```
apps/mobile/app.config.ts+2−1
@@ -53,10 +53,11 @@ const variant = VARIANT_CONFIG[APP_VARIANT]; · 52 unmodified lines
5353 const config: ExpoConfig = {
5454 name: variant.appName,
5555 slug: "t3-code",
56+ platforms: ["ios", "android"],
5657 scheme: variant.scheme,
5758 version: "0.1.0",
5859 runtimeVersion: {
59− policy: "appVersion",
60+ policy: process.env.MOBILE_VERSION_POLICY ?? "appVersion",
6061 },
6162 orientation: "portrait",
6263 icon: "./assets/icon.png",
apps/mobile/eas.json+15−0
@@ -17,13 +17,28 @@ · 16 unmodified lines
1717 "APP_VARIANT": "preview"
1818 },
1919 "channel": "preview",
20+ "environment": "preview",
2021 "distribution": "internal"
2122 },
23+ "preview:dev": {
24+ "env": {
25+ "APP_VARIANT": "preview",
26+ "MOBILE_VERSION_POLICY": "fingerprint"
27+ },
28+ "channel": "preview",
29+ "environment": "preview",
30+ "developmentClient": true,
31+ "distribution": "internal",
32+ "android": {
33+ "buildType": "apk"
34+ }
35+ },
2236 "production": {
2337 "env": {
2438 "APP_VARIANT": "production"
2539 },
2640 "channel": "production",
41+ "environment": "production",
2742 "autoIncrement": true
2843 }
2944 },
apps/mobile/package.json+3−0
@@ -16,6 +16,7 @@ · 15 unmodified lines
1616 "android:prod": "APP_VARIANT=production EXPO_NO_GIT_STATUS=1 expo prebuild --clean --platform android && expo run:android",
1717 "eas:android:dev": "eas build --profile development -p android",
1818 "eas:android:preview": "eas build --profile preview -p android",
19+ "eas:android:preview:dev": "eas build --profile preview:dev -p android",
1920 "eas:android:prod": "eas build --profile production -p android",
2021 "ios": "EXPO_NO_GIT_STATUS=1 expo prebuild --clean --platform ios && expo run:ios",
2122 "ios:dev": "APP_VARIANT=development EXPO_NO_GIT_STATUS=1 expo prebuild --clean --platform ios && expo run:ios",
@@ -23,9 +24,11 @@ · 1 unmodified line
2324 "ios:prod": "APP_VARIANT=production EXPO_NO_GIT_STATUS=1 expo prebuild --clean --platform ios && expo run:ios",
2425 "eas:ios:dev": "eas build --profile development -p ios",
2526 "eas:ios:preview": "eas build --profile preview -p ios",
27+ "eas:ios:preview:dev": "eas build --profile preview:dev -p ios",
2628 "eas:ios:prod": "eas build --profile production -p ios",
2729 "eas:dev": "eas build --profile development",
2830 "eas:preview": "eas build --profile preview",
31+ "eas:preview:dev": "eas build --profile preview:dev",
2932 "eas:prod": "eas build --profile production",
3033 "config:dev": "APP_VARIANT=development expo config",
3134 "config:preview": "APP_VARIANT=preview expo config",
package.json+2−0
@@ -67,6 +67,7 @@ · 66 unmodified lines
6767 "sync:repos": "node scripts/sync-reference-repos.ts"
6868 },
6969 "devDependencies": {
70+ "@babel/plugin-transform-react-jsx": "7.28.6",
7071 "@effect/tsgo": "catalog:",
7172 "@oxlint/plugins": "^1.63.0",
7273 "@types/node": "catalog:",
@@ -99,6 +100,7 @@ · 26 unmodified lines
99100 ]
100101 },
101102 "patchedDependencies": {
103+ "@expo/metro-config@56.0.13": "patches/@expo%2Fmetro-config@56.0.13.patch",
102104 "@pierre/diffs@1.1.20@1.1.20": "patches/@pierre%2Fdiffs@1.1.20.patch",
103105 "effect@4.0.0-beta.73@4.0.0-beta.73": "patches/effect@4.0.0-beta.73.patch",
104106 "react-native-nitro-modules@0.35.9@0.35.9": "patches/react-native-nitro-modules@0.35.9.patch"
patches/@expo%2Fmetro-config@56.0.13.patch+93−0
@@ -0,0 +1,93 @@
1+diff --git a/build/serializer/sourceMap.js b/build/serializer/sourceMap.js
2+index 4cc9aa4..703dfe0 100644
3+--- a/build/serializer/sourceMap.js
4++++ b/build/serializer/sourceMap.js
5+@@ -20,6 +20,20 @@ function loadRemapping() {
6+ }
7+ return _remapping;
8+ }
9++let _sourceMapCodec;
10++function loadSourceMapCodec() {
11++ if (!_sourceMapCodec) {
12++ _sourceMapCodec = require('@jridgewell/sourcemap-codec');
13++ }
14++ return _sourceMapCodec;
15++}
16++let _traceMapping;
17++function loadTraceMapping() {
18++ if (!_traceMapping) {
19++ _traceMapping = require('@jridgewell/trace-mapping');
20++ }
21++ return _traceMapping;
22++}
23+ let _Generator;
24+ function loadGenerator() {
25+ if (!_Generator) {
26+@@ -199,6 +213,58 @@ function patchMetroSourceMapStringForPackedMaps() {
27+ stock.sourceMapString = sourceMapString;
28+ stock.sourceMapStringNonBlocking = sourceMapStringNonBlocking;
29+ }
30++// Hermes can emit mappings for Metro trailer/debug lines that have no
31++// corresponding Metro source-map line. @jridgewell/remapping assumes every
32++// referenced generated line exists, so strip those invalid bridge segments.
33++function getGeneratedLineCount(map) {
34++ const { TraceMap, decodedMappings } = loadTraceMapping();
35++ return decodedMappings(new TraceMap(map)).length;
36++}
37++function dropInvalidOriginalSegments(map, maxOriginalLine) {
38++ const { TraceMap, decodedMappings } = loadTraceMapping();
39++ const decoded = decodedMappings(new TraceMap(map));
40++ let didChange = false;
41++ const filtered = decoded.map((line) => {
42++ const filteredLine = line.filter((segment) => {
43++ if (segment.length < 4) {
44++ return true;
45++ }
46++ const sourceIndex = segment[1];
47++ const sourceLine = segment[2];
48++ const sourceColumn = segment[3];
49++ return (sourceIndex >= 0 &&
50++ sourceIndex < map.sources.length &&
51++ sourceLine >= 0 &&
52++ sourceLine < maxOriginalLine &&
53++ sourceColumn >= 0);
54++ });
55++ if (filteredLine.length !== line.length) {
56++ didChange = true;
57++ }
58++ return filteredLine;
59++ });
60++ if (!didChange) {
61++ return map;
62++ }
63++ return {
64++ ...map,
65++ mappings: loadSourceMapCodec().encode(filtered),
66++ };
67++}
68++function sanitizeSourceMapsForComposition(maps) {
69++ let sanitized = maps;
70++ for (let index = 1; index < maps.length; index++) {
71++ const maxOriginalLine = getGeneratedLineCount(sanitized[index - 1]);
72++ const next = dropInvalidOriginalSegments(sanitized[index], maxOriginalLine);
73++ if (next !== sanitized[index]) {
74++ if (sanitized === maps) {
75++ sanitized = maps.slice();
76++ }
77++ sanitized[index] = next;
78++ }
79++ }
80++ return sanitized;
81++}
82+ // `maps[0]` is the original-most transform; `maps[maps.length - 1]` is
83+ // the most recent. Built on `@jridgewell/remapping` instead of mozilla's
84+ // `SourceMapConsumer`-based composer.
85+@@ -226,7 +292,7 @@ function composeSourceMaps(maps) {
86+ return { ...map, ignoreList: map.x_google_ignoreList };
87+ });
88+ // Metro convention is original-first; remapping is most-recent first.
89+- const reversed = normalized.slice().reverse();
90++ const reversed = sanitizeSourceMapsForComposition(normalized).slice().reverse();
91+ const composed = loadRemapping()(reversed, () => null);
92+ // Re-emit as a plain object — remapping returns a `SourceMap` class
93+ // instance, which doesn't round-trip JSON cleanly.
pnpm-lock.yaml+28−5
@@ -49,6 +49,9 @@ overrides: · 48 unmodified lines
4949 packageExtensionsChecksum: sha256-MDpMSm2Rk8Y7FDIbaAgFkT45PZBPV7JBzjTAft+noEM=
5050
5151 patchedDependencies:
52+ '@expo/metro-config@56.0.13':
53+ hash: 8cb08b5bb7051ed9d2dbe46a2c293c5a1e17f1bd6ddf30de27909e18c921ff46
54+ path: patches/@expo%2Fmetro-config@56.0.13.patch
5255 '@pierre/diffs@1.1.20':
5356 hash: e4e35ba95100de3708f900e0d9ea62bca732b1e4486024b5055f48cd128dd9e0
5457 path: patches/@pierre%2Fdiffs@1.1.20.patch
@@ -63,6 +66,9 @@ importers: · 8 unmodified lines
6366
6467 .:
6568 devDependencies:
69+ '@babel/plugin-transform-react-jsx':
70+ specifier: 7.28.6
71+ version: 7.28.6(@babel/core@7.29.7)
6672 '@effect/tsgo':
6773 specifier: 'catalog:'
6874 version: 0.11.4
@@ -1223,6 +1229,12 @@ packages: · 1154 unmodified lines
12231229 peerDependencies:
12241230 '@babel/core': ^7.0.0-0
12251231
1232+ '@babel/plugin-transform-react-jsx@7.28.6':
1233+ resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==}
1234+ engines: {node: '>=6.9.0'}
1235+ peerDependencies:
1236+ '@babel/core': ^7.0.0-0
1237+
12261238 '@babel/plugin-transform-react-jsx@7.29.7':
12271239 resolution: {integrity: sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==}
12281240 engines: {node: '>=6.9.0'}
@@ -8196,6 +8208,17 @@ snapshots: · 6967 unmodified lines
81968208 '@babel/core': 7.29.7
81978209 '@babel/helper-plugin-utils': 7.29.7
81988210
8211+ '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.7)':
8212+ dependencies:
8213+ '@babel/core': 7.29.7
8214+ '@babel/helper-annotate-as-pure': 7.29.7
8215+ '@babel/helper-module-imports': 7.29.7
8216+ '@babel/helper-plugin-utils': 7.29.7
8217+ '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7)
8218+ '@babel/types': 7.29.7
8219+ transitivePeerDependencies:
8220+ - supports-color
8221+
81998222 '@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7)':
82008223 dependencies:
82018224 '@babel/core': 7.29.7
@@ -8607,7 +8630,7 @@ snapshots: · 405 unmodified lines
86078630 '@expo/json-file': 10.2.0
86088631 '@expo/log-box': 56.0.12(@expo/dom-webview@56.0.5)(expo@56.0.8)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)
86098632 '@expo/metro': 56.0.0
8610− '@expo/metro-config': 56.0.13(expo@56.0.8)(typescript@6.0.3)
8633+ '@expo/metro-config': 56.0.13(patch_hash=8cb08b5bb7051ed9d2dbe46a2c293c5a1e17f1bd6ddf30de27909e18c921ff46)(expo@56.0.8)(typescript@6.0.3)
86118634 '@expo/metro-file-map': 56.0.3
86128635 '@expo/osascript': 2.6.0
86138636 '@expo/package-manager': 1.12.1
@@ -8800,7 +8823,7 @@ snapshots: · 186 unmodified lines
88008823 react-native: 0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3)
88018824 stacktrace-parser: 0.1.11
88028825
8803− '@expo/metro-config@56.0.13(expo@56.0.8)(typescript@6.0.3)':
8826+ '@expo/metro-config@56.0.13(patch_hash=8cb08b5bb7051ed9d2dbe46a2c293c5a1e17f1bd6ddf30de27909e18c921ff46)(expo@56.0.8)(typescript@6.0.3)':
88048827 dependencies:
88058828 '@babel/code-frame': 7.29.7
88068829 '@babel/core': 7.29.7
@@ -9831,7 +9854,7 @@ snapshots: · 1024 unmodified lines
98319854 '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7)
98329855 '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7)
98339856 '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7)
9834− '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7)
9857+ '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.7)
98359858 '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7)
98369859 '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7)
98379860 '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7)
@@ -11092,7 +11115,7 @@ snapshots: · 1254 unmodified lines
1109211115 '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7)
1109311116 '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7)
1109411117 '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7)
11095− '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7)
11118+ '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.7)
1109611119 '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7)
1109711120 '@babel/plugin-transform-react-pure-annotations': 7.29.7(@babel/core@7.29.7)
1109811121 '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7)
@@ -11959,7 +11982,7 @@ snapshots: · 860 unmodified lines
1195911982 '@expo/local-build-cache-provider': 56.0.8(typescript@6.0.3)
1196011983 '@expo/log-box': 56.0.12(@expo/dom-webview@56.0.5)(expo@56.0.8)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)
1196111984 '@expo/metro': 56.0.0
11962− '@expo/metro-config': 56.0.13(expo@56.0.8)(typescript@6.0.3)
11985+ '@expo/metro-config': 56.0.13(patch_hash=8cb08b5bb7051ed9d2dbe46a2c293c5a1e17f1bd6ddf30de27909e18c921ff46)(expo@56.0.8)(typescript@6.0.3)
1196311986 '@ungap/structured-clone': 1.3.1
1196411987 babel-preset-expo: 56.0.14(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo@56.0.8)(react-refresh@0.14.2)
1196511988 expo-asset: 56.0.15(expo@56.0.8)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)
pnpm-workspace.yaml+1−0
@@ -57,6 +57,7 @@ packageExtensions: · 56 unmodified lines
5757 dependencies:
5858 "@vitest/runner": "catalog:"
5959 patchedDependencies:
60+ "@expo/metro-config@56.0.13": patches/@expo%2Fmetro-config@56.0.13.patch
6061 "@pierre/diffs@1.1.20": patches/@pierre%2Fdiffs@1.1.20.patch
6162 effect@4.0.0-beta.73: patches/effect@4.0.0-beta.73.patch
6263 react-native-nitro-modules@0.35.9: patches/react-native-nitro-modules@0.35.9.patch