Skip to content

Commit 125bac1

Browse files
committed
Merge pull request #124 from rootstrap/feat/eas_build_with_github_actions
feat: EAS build with GitHub Actions
2 parents c3ae61e + 446821a commit 125bac1

File tree

5 files changed

+195
-55
lines changed

5 files changed

+195
-55
lines changed

.github/workflows/eas-build.yml

Lines changed: 132 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,54 +6,104 @@
66
# This workflow is used to trigger a build on EAS.
77
# Can be triggered manually from the actions tab.
88

9-
# This action accepts those inputs:
10-
# `environment`, which is used to generate a build for a specific environment (development, staging, QA, production). We use staging by default.
11-
# `android`, true by default, set to true if you don't want to trigger build for Android.
12-
# `ios`, false by default, set to true if you want to trigger build for IOS.
13-
149
# Before triggering the build, we run a pre-build script to generate the necessary native folders based on the APP_ENV.
1510
# Based on the ANDROID and IOS inputs, we trigger the build for the corresponding platform with the corresponding flags.
1611

1712
# 🚨 GITHUB SECRETS REQUIRED:
18-
# - EXPO_TOKEN: Expo token to authenticate with EAS
19-
# - You can get it from https://expo.dev/settings/access-tokens
13+
# - EXPO_TOKEN: Expo token to authenticate with EAS to sync version numbers and submit the build.
14+
# You can get it from https://expo.dev/settings/access-tokens
15+
# - NEW_VERSION_NUMBER_PAT: A fine-grained Personal Access Token.
16+
# This token is used to commit and push to protected branches.
17+
# You can generate one from here: https://github.com/settings/tokens?type=beta
18+
# Set the token name to something meaningful, e.g. "New version number PAT for <Project name>".
19+
# Set the Repository access to "Only select repositories" and select this repository.
20+
# Set the following Repo permissions:
21+
# - Contents: Read & write (to commit and push)
22+
# Make sure to add it to the repo secrets with the name NEW_VERSION_NUMBER_PAT:
23+
# - Go to Repository Settings > Secrets and variables > Actions > New repository secret
24+
# - Name: NEW_VERSION_NUMBER_PAT
25+
# - Value: The Personal Access Token you created
2026

21-
name: 'EAS Build (Android & IOS) (EAS)'
27+
name: 'Build & Deploy'
2228

2329
on:
2430
workflow_dispatch:
2531
inputs:
26-
environment:
32+
platform:
2733
type: choice
28-
description: 'Environment'
29-
required: true
30-
default: 'staging'
34+
description: Platform to build for
3135
options:
32-
- development
33-
- staging
34-
- qa
35-
- production
36-
android:
37-
type: boolean
38-
description: 'Build for Android'
39-
required: true
40-
default: true
41-
ios:
36+
- android
37+
- ios
38+
new-version:
39+
type: string
40+
description: 'New version (e.g. 1.0.0) (optional)'
41+
auto-submit:
4242
type: boolean
43-
description: 'Build for iOS'
44-
required: true
43+
description: 'Auto-submit the build to the store'
44+
required: false
4545
default: true
4646

4747
jobs:
48-
Build:
48+
validate-new-version:
4949
runs-on: ubuntu-latest
50+
permissions:
51+
contents: read
52+
steps:
53+
- name: Checkout
54+
if: inputs.new-version
55+
uses: actions/checkout@v3
56+
with:
57+
fetch-depth: 0
58+
- name: Install Node.js
59+
if: inputs.new-version
60+
uses: actions/setup-node@v4
61+
with:
62+
node-version: 20
63+
- name: Validate new version
64+
if: inputs.new-version
65+
run: |
66+
CURRENT_VERSION=$(node -p "require('./package.json').version")
67+
NEW_VERSION="${{ inputs.new-version }}"
68+
69+
echo "Current version: $CURRENT_VERSION"
70+
echo "New version: $NEW_VERSION"
71+
72+
npx semver -r ">=$CURRENT_VERSION" "$NEW_VERSION" > /dev/null || (echo "❌ New version must be greater than or equal to current version ($CURRENT_VERSION)" && exit 1)
73+
74+
echo "✅ New version is valid"
75+
76+
build:
77+
needs: validate-new-version
78+
runs-on: ${{ inputs.platform == 'ios' && 'macos-latest' || 'ubuntu-latest' }}
79+
permissions:
80+
contents: write
81+
environment: ${{ github.ref_name == 'main' && 'production' || github.ref_name == 'staging' && 'staging' || github.ref_name == 'qa' && 'qa' || github.ref_name == 'development' && 'development' }}
5082
steps:
51-
- name: Check for EXPO_TOKEN
83+
- name: Set environment variable
84+
run: |
85+
if [[ "${{ github.ref_name }}" == "main" ]]; then
86+
echo "ENV=production" >> $GITHUB_ENV
87+
elif [[ "${{ github.ref_name }}" == "staging" ]]; then
88+
echo "ENV=staging" >> $GITHUB_ENV
89+
elif [[ "${{ github.ref_name }}" == "qa" ]]; then
90+
echo "ENV=qa" >> $GITHUB_ENV
91+
elif [[ "${{ github.ref_name }}" == "development" ]]; then
92+
echo "ENV=development" >> $GITHUB_ENV
93+
else
94+
echo "Invalid branch: ${{ github.ref_name }}. You can only build for main, staging, qa or development branches."
95+
exit 1
96+
fi
97+
- name: Check if all required secrets exist
5298
run: |
5399
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
54100
echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
55101
exit 1
56102
fi
103+
if [ -z "${{ secrets.NEW_VERSION_NUMBER_PAT }}" ]; then
104+
echo "NEW_VERSION_NUMBER_PAT secret not found. Please create a fine-grained Personal Access Token following the instructions in the workflow file."
105+
exit 1
106+
fi
57107
58108
- name: 📦 Setup Expo and EAS
59109
uses: expo/expo-github-action@v8
@@ -65,17 +115,66 @@ jobs:
65115
uses: actions/checkout@v3
66116
with:
67117
fetch-depth: 0
118+
token: ${{ secrets.NEW_VERSION_NUMBER_PAT }}
68119

69120
- name: 📦 Setup Node + PNPM + install deps
70121
uses: ./.github/actions/setup-node-pnpm-install
71122

123+
- name: Create environment file
124+
run: echo "${{ secrets.ENVIRONMENT_FILE }}" > .env.${{ env.ENV }}
125+
126+
- name: Update version in package.json
127+
if: inputs.new-version
128+
run: |
129+
CURRENT_VERSION=$(node -p "require('./package.json').version")
130+
if [ "$CURRENT_VERSION" == "${{inputs.new-version}}" ]; then
131+
echo "Current version is already ${{ inputs.new-version }}, no need to update"
132+
exit 0
133+
fi
134+
135+
git config --global user.name "github-actions[bot]"
136+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
137+
pnpm version ${{ inputs.new-version }} -m "chore: set app version to ${{ inputs.new-version }}"
138+
139+
- name: Setup latest version of Xcode
140+
uses: maxim-lobanov/setup-xcode@v1
141+
if: inputs.platform == 'ios'
142+
with:
143+
xcode-version: latest
144+
145+
- name: Set Up JDK
146+
uses: actions/setup-java@v3
147+
if: inputs.platform == 'android'
148+
with:
149+
distribution: 'zulu' # See 'Supported distributions' for available options
150+
java-version: '17'
151+
72152
- name: ⚙️ Run Prebuild
73-
run: pnpm prebuild:${{ inputs.environment }}
153+
run: pnpm prebuild:${{ env.ENV }}
74154

75-
- name: 📱 Run Android Build
76-
if: ${{ inputs.android == true }}
77-
run: pnpm build:${{ inputs.environment }}:android --non-interactive --no-wait --message "Build ${{ inputs.environment }}"
155+
- name: 📱 Run Build for ${{ inputs.platform }}
156+
run: |
157+
pnpm build:${{ env.ENV }}:${{ inputs.platform }} --non-interactive --no-wait --message "Build ${{ env.ENV }} for ${{ inputs.platform }}" --local
158+
if [ "${{ inputs.platform }}" = "android" ]; then
159+
ls -1 ./*.aab > path.txt
160+
elif [ "${{ inputs.platform }}" = "ios" ]; then
161+
ls -1 ./*.ipa > path.txt
162+
fi
163+
- name: Upload ${{ inputs.platform }} Build
164+
uses: actions/upload-artifact@v4
165+
with:
166+
name: ${{ inputs.platform }}-build-${{ env.ENV }}
167+
path: |
168+
*.apks
169+
*.apk
170+
*.aab
171+
*.ipa
172+
173+
- name: 📱 Submit ${{ inputs.platform }} app to the store
174+
if: inputs.auto-submit
175+
run: pnpm submit:${{ env.ENV }}:mobile --platform=${{ inputs.platform }} --path=$(cat path.txt) --no-wait --non-interactive
78176

79-
- name: 📱 Run IOS Build
80-
if: ${{ inputs.ios == true }}
81-
run: pnpm build:${{ inputs.environment }}:ios --non-interactive --no-wait --message "Build ${{ inputs.environment }}"
177+
- name: 📦 Push changes to repository
178+
if: inputs.new-version
179+
run: |
180+
git push || echo "Skipping push: version was already updated."

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ yarn-error.log
2020

2121
# macOS
2222
.DS_Store
23+
24+
# artifacts
25+
*.apks
2326
*.apk
2427
*.ipa
25-
28+
*.aab
2629

2730
# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
2831
# The following patterns were generated by expo-cli

app.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
3030
ios: {
3131
supportsTablet: true,
3232
bundleIdentifier: Env.BUNDLE_ID,
33+
config: {
34+
usesNonExemptEncryption: false,
35+
},
3336
},
3437
experiments: {
3538
typedRoutes: true,

eas.json

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"cli": {
3-
"version": ">= 0.57.0"
3+
"version": ">= 0.57.0",
4+
"appVersionSource": "remote"
45
},
56
"build": {
67
"production": {
8+
"autoIncrement": true,
79
"channel": "production",
810
"distribution": "store",
911
"pnpm": "8.15.4",
@@ -17,69 +19,76 @@
1719
"env": {
1820
"EXPO_NO_DOTENV": "1",
1921
"APP_ENV": "production",
20-
"FLIPPER_DISABLE": "1"
22+
"FLIPPER_DISABLE": "1",
23+
"EAS_NO_DOCTOR": "1"
2124
},
2225
"prebuildCommand": "prebuild --skip-dependency-update react",
2326
"cache": {
2427
"key": "eas-1"
2528
}
2629
},
2730
"staging": {
31+
"autoIncrement": true,
2832
"channel": "staging",
2933
"distribution": "store",
3034
"pnpm": "8.15.4",
3135
"ios": {
3236
"image": "latest"
3337
},
3438
"android": {
35-
"buildType": "apk",
39+
"buildType": "app-bundle",
3640
"image": "latest"
3741
},
3842
"env": {
3943
"APP_ENV": "staging",
4044
"EXPO_NO_DOTENV": "1",
41-
"FLIPPER_DISABLE": "1"
45+
"FLIPPER_DISABLE": "1",
46+
"EAS_NO_DOCTOR": "1"
4247
},
4348
"prebuildCommand": "prebuild --skip-dependency-update react",
4449
"cache": {
4550
"key": "eas-1"
4651
}
4752
},
4853
"qa": {
54+
"autoIncrement": true,
4955
"channel": "qa",
5056
"distribution": "store",
5157
"pnpm": "8.15.4",
5258
"ios": {
5359
"image": "latest"
5460
},
5561
"android": {
56-
"buildType": "apk",
62+
"buildType": "app-bundle",
5763
"image": "latest"
5864
},
5965
"env": {
6066
"APP_ENV": "qa",
6167
"EXPO_NO_DOTENV": "1",
62-
"FLIPPER_DISABLE": "1"
68+
"FLIPPER_DISABLE": "1",
69+
"EAS_NO_DOCTOR": "1"
6370
},
64-
6571
"prebuildCommand": "prebuild --skip-dependency-update react",
6672
"cache": {
6773
"key": "eas-1"
6874
}
6975
},
7076
"development": {
77+
"autoIncrement": true,
7178
"developmentClient": true,
72-
"distribution": "internal",
79+
"distribution": "store",
7380
"pnpm": "8.15.4",
7481
"ios": {
7582
"image": "latest"
7683
},
7784
"android": {
85+
"buildType": "app-bundle",
7886
"image": "latest"
7987
},
8088
"env": {
8189
"APP_ENV": "development",
82-
"EXPO_NO_DOTENV": "1"
90+
"EXPO_NO_DOTENV": "1",
91+
"EAS_NO_DOCTOR": "1"
8392
},
8493
"prebuildCommand": "prebuild --skip-dependency-update react",
8594
"cache": {
@@ -108,6 +117,34 @@
108117
}
109118
},
110119
"submit": {
111-
"production": {}
120+
"production": {
121+
"ios": {
122+
"ascAppId": "6746460022"
123+
}
124+
},
125+
"staging": {
126+
"ios": {
127+
"ascAppId": "6745524568"
128+
},
129+
"android": {
130+
"releaseStatus": "draft"
131+
}
132+
},
133+
"qa": {
134+
"ios": {
135+
"ascAppId": "6745527331"
136+
},
137+
"android": {
138+
"releaseStatus": "draft"
139+
}
140+
},
141+
"development": {
142+
"ios": {
143+
"ascAppId": "6746459808"
144+
},
145+
"android": {
146+
"releaseStatus": "draft"
147+
}
148+
}
112149
}
113-
}
150+
}

0 commit comments

Comments
 (0)