Skip to content

Commit 30c727b

Browse files
author
Lalit Sharma
committed
feat: update CI and EAS build workflows to use self-hosted macOS runners; enhance documentation for local builds and runner setup
1 parent e09ec25 commit 30c727b

6 files changed

Lines changed: 217 additions & 18 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ concurrency:
1313
jobs:
1414
ci:
1515
name: Typecheck · Lint · Test
16-
runs-on: ubuntu-latest
16+
runs-on: [self-hosted, macOS, eclipse-timer]
1717

1818
steps:
1919
- name: Checkout

.github/workflows/eas-build.yml

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: EAS Build & Submit
1+
name: Self-Hosted Mobile Build & Submit
22

33
on:
44
push:
@@ -25,13 +25,13 @@ on:
2525
type: boolean
2626

2727
concurrency:
28-
group: eas-${{ github.ref }}
28+
group: self-hosted-mobile-${{ github.ref }}
2929
cancel-in-progress: false
3030

3131
jobs:
3232
ci:
3333
name: CI checks
34-
runs-on: ubuntu-latest
34+
runs-on: [self-hosted, macOS, eclipse-timer]
3535
steps:
3636
- name: Checkout
3737
uses: actions/checkout@v4
@@ -58,9 +58,9 @@ jobs:
5858
run: pnpm test
5959

6060
build:
61-
name: EAS Build (${{ github.event.inputs.platform || 'all' }})
61+
name: Local Build (${{ github.event.inputs.platform || 'all' }})
6262
needs: ci
63-
runs-on: ubuntu-latest
63+
runs-on: [self-hosted, macOS, eclipse-timer]
6464
env:
6565
GOOGLE_MAPS_ANDROID_API_KEY: ${{ secrets.GOOGLE_MAPS_ANDROID_API_KEY }}
6666

@@ -97,15 +97,60 @@ jobs:
9797
9898
- name: Build
9999
working-directory: apps/mobile
100-
run: eas build --profile production --platform ${{ github.event.inputs.platform || 'all' }} --non-interactive
100+
env:
101+
EAS_LOCAL_BUILD_ARTIFACTS_DIR: ${{ github.workspace }}/artifacts/raw
102+
run: |
103+
set -euo pipefail
104+
platform="${{ github.event.inputs.platform || 'all' }}"
105+
106+
if [ "$platform" = "all" ] || [ "$platform" = "ios" ]; then
107+
pnpm exec eas build --profile production --platform ios --local --non-interactive
108+
fi
109+
110+
if [ "$platform" = "all" ] || [ "$platform" = "android" ]; then
111+
pnpm exec eas build --profile production --platform android --local --non-interactive
112+
fi
113+
114+
- name: Collect build artifacts
115+
run: |
116+
set -euo pipefail
117+
mkdir -p artifacts/submission
118+
platform="${{ github.event.inputs.platform || 'all' }}"
119+
120+
if [ "$platform" = "all" ] || [ "$platform" = "ios" ]; then
121+
ios_artifact="$(find artifacts/raw -type f -name '*.ipa' | head -n 1 || true)"
122+
if [ -z "$ios_artifact" ]; then
123+
echo "Missing iOS artifact (.ipa) in artifacts/raw."
124+
exit 1
125+
fi
126+
cp "$ios_artifact" artifacts/submission/ios.ipa
127+
fi
128+
129+
if [ "$platform" = "all" ] || [ "$platform" = "android" ]; then
130+
android_artifact="$(find artifacts/raw -type f -name '*.aab' | head -n 1 || true)"
131+
if [ -z "$android_artifact" ]; then
132+
echo "Missing Android artifact (.aab) in artifacts/raw."
133+
exit 1
134+
fi
135+
cp "$android_artifact" artifacts/submission/android.aab
136+
fi
137+
138+
ls -lah artifacts/submission
139+
140+
- name: Upload build artifacts
141+
uses: actions/upload-artifact@v4
142+
with:
143+
name: local-mobile-builds-${{ github.run_id }}
144+
path: artifacts/submission
145+
if-no-files-found: error
101146

102147
submit:
103148
name: Submit to stores
104149
needs: build
105150
if: >-
106151
github.event_name == 'workflow_dispatch' &&
107152
github.event.inputs.submit == 'true'
108-
runs-on: ubuntu-latest
153+
runs-on: [self-hosted, macOS, eclipse-timer]
109154
environment: production # Requires manual approval in GitHub settings
110155

111156
steps:
@@ -130,6 +175,31 @@ jobs:
130175
eas-version: latest
131176
token: ${{ secrets.EXPO_TOKEN }}
132177

133-
- name: Submit to App Store Connect & Google Play
178+
- name: Download build artifacts
179+
uses: actions/download-artifact@v4
180+
with:
181+
name: local-mobile-builds-${{ github.run_id }}
182+
path: artifacts/submission
183+
184+
- name: Submit local artifacts to App Store Connect & Google Play
134185
working-directory: apps/mobile
135-
run: eas submit --platform ${{ github.event.inputs.platform || 'all' }} --non-interactive --latest
186+
run: |
187+
set -euo pipefail
188+
platform="${{ github.event.inputs.platform || 'all' }}"
189+
artifact_root="${{ github.workspace }}/artifacts/submission"
190+
191+
if [ "$platform" = "all" ] || [ "$platform" = "ios" ]; then
192+
if [ ! -f "$artifact_root/ios.ipa" ]; then
193+
echo "Missing iOS artifact at $artifact_root/ios.ipa."
194+
exit 1
195+
fi
196+
pnpm exec eas submit --platform ios --path "$artifact_root/ios.ipa" --non-interactive
197+
fi
198+
199+
if [ "$platform" = "all" ] || [ "$platform" = "android" ]; then
200+
if [ ! -f "$artifact_root/android.aab" ]; then
201+
echo "Missing Android artifact at $artifact_root/android.aab."
202+
exit 1
203+
fi
204+
pnpm exec eas submit --platform android --path "$artifact_root/android.aab" --non-interactive
205+
fi

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ This repo now reads the key from `GOOGLE_MAPS_ANDROID_API_KEY` at build/config t
263263
- Value: your Android Maps key
264264
2. The workflow `.github/workflows/eas-build.yml` injects this secret into the build job.
265265
3. Android/all builds fail early with a clear message if the secret is missing.
266+
4. Builds run on a self-hosted macOS runner with label `eclipse-timer`.
267+
Runner setup instructions: `documents/self-hosted-macos-runner.md`.
266268

267269
### Security recommendations
268270

documents/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This folder contains the project documentation for the `eclipse-timer` monorepo.
77
### Planning
88
- `documents/01-documentation-plan.md`
99
- `documents/release-plan-eas.md`
10+
- `documents/self-hosted-macos-runner.md`
1011

1112
### High-Level
1213
- `documents/high-level/system-overview.md`

documents/release-plan-eas.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Eclipse Timer — Release Plan (Post v1.0.0)
22

33
> Scope: all releases after the first manual Android launch.
4-
> Goal: use EAS for build, submit, and OTA updates with a repeatable checklist.
4+
> Goal: use local/self-hosted build, submit, and OTA updates with a repeatable checklist.
55
66
---
77

@@ -12,6 +12,7 @@
1212
- EAS project ID: `a29a7662-96be-4509-a79e-fbe4b5dac1ff`.
1313
- Build profile for stores: `production` in `apps/mobile/eas.json` (`autoIncrement: true`).
1414
- Runtime policy: `runtimeVersion` is tied to app version in `apps/mobile/app.json`.
15+
- GitHub workflow path for builds is self-hosted macOS (`.github/workflows/eas-build.yml`).
1516

1617
---
1718

@@ -25,6 +26,7 @@
2526
## Prerequisites (One-Time)
2627

2728
- `EXPO_TOKEN` is available for CI and local CLI login is valid (`eas whoami`).
29+
- Self-hosted macOS runner is online with labels `self-hosted`, `macOS`, `eclipse-timer`.
2830
- Google Play service account is configured for submit in `apps/mobile/eas.json` (or provided via EAS credentials).
2931
- Store listing metadata is kept current in:
3032
- `documents/store-metadata.md`
@@ -54,32 +56,34 @@ pnpm lint
5456
pnpm test
5557
```
5658

57-
### 4) Build production binaries with EAS
59+
### 4) Build production binaries locally
5860

5961
From repo root:
6062

6163
```bash
62-
pnpm -C apps/mobile exec eas build --profile production --platform all
64+
pnpm -C apps/mobile exec eas build --profile production --platform ios --local
65+
pnpm -C apps/mobile exec eas build --profile production --platform android --local
6366
```
6467

6568
Android-only:
6669

6770
```bash
68-
pnpm -C apps/mobile exec eas build --profile production --platform android
71+
pnpm -C apps/mobile exec eas build --profile production --platform android --local
6972
```
7073

7174
### 5) Submit via EAS
7275

73-
Submit latest successful builds:
76+
Submit local artifacts:
7477

7578
```bash
76-
pnpm -C apps/mobile exec eas submit --platform all --latest
79+
pnpm -C apps/mobile exec eas submit --platform ios --path /absolute/path/to/ios.ipa
80+
pnpm -C apps/mobile exec eas submit --platform android --path /absolute/path/to/android.aab
7781
```
7882

7983
Android-only:
8084

8185
```bash
82-
pnpm -C apps/mobile exec eas submit --platform android --latest
86+
pnpm -C apps/mobile exec eas submit --platform android --path /absolute/path/to/android.aab
8387
```
8488

8589
### 6) Play Console/App Store rollout
@@ -91,6 +95,7 @@ pnpm -C apps/mobile exec eas submit --platform android --latest
9195
### 7) Preferred automation path (GitHub Actions)
9296

9397
- Use `.github/workflows/eas-build.yml` for repeatable release execution.
98+
- Workflow runs on your self-hosted macOS runner.
9499
- Trigger `workflow_dispatch` with:
95100
- `platform: android` or `all`
96101
- `submit: true` when ready to upload automatically after build
@@ -134,7 +139,7 @@ Rules:
134139
- [ ] Changelog updated
135140
- [ ] Version updated (`app.json`, `package.json`)
136141
- [ ] Typecheck/lint/test passed
137-
- [ ] EAS build completed
142+
- [ ] Local build completed
138143
- [ ] EAS submit completed
139144
- [ ] Release notes entered in store consoles
140145
- [ ] Rollout started and monitored
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Self-Hosted macOS Runner Setup (Mac mini)
2+
3+
This project can build both iOS and Android on your own Mac mini using GitHub Actions self-hosted runners.
4+
The updated workflows run on the label set:
5+
6+
- `self-hosted`
7+
- `macOS`
8+
- `eclipse-timer`
9+
10+
Assumption: builds stay local (`eas build --local`) so they do not consume EAS cloud build quota.
11+
12+
## 1. One-time machine prerequisites
13+
14+
Run these on the Mac mini:
15+
16+
```bash
17+
xcode-select -p
18+
xcodebuild -version
19+
```
20+
21+
If needed:
22+
23+
1. Install full Xcode.
24+
2. Accept license and first-launch setup:
25+
```bash
26+
sudo xcodebuild -license accept
27+
sudo xcodebuild -runFirstLaunch
28+
```
29+
30+
Android toolchain:
31+
32+
1. Install Android Studio.
33+
2. Install SDK Platform, Build-Tools, Command-line Tools, and Platform Tools.
34+
3. Export SDK vars (for the runner user):
35+
```bash
36+
echo 'export ANDROID_HOME="$HOME/Library/Android/sdk"' >> ~/.zshrc
37+
echo 'export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"' >> ~/.zshrc
38+
echo 'export PATH="$ANDROID_SDK_ROOT/platform-tools:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$PATH"' >> ~/.zshrc
39+
source ~/.zshrc
40+
```
41+
42+
Node and pnpm:
43+
44+
```bash
45+
node -v
46+
corepack enable
47+
pnpm -v
48+
```
49+
50+
## 2. Create the self-hosted runner
51+
52+
In GitHub:
53+
54+
1. Open `Settings -> Actions -> Runners -> New self-hosted runner`.
55+
2. Choose macOS and copy the generated commands.
56+
3. On the Mac mini, run them in a dedicated folder, for example:
57+
58+
```bash
59+
mkdir -p ~/actions-runner && cd ~/actions-runner
60+
# Paste GitHub-provided download/config commands here.
61+
```
62+
63+
Important while configuring:
64+
65+
1. Runner group: your default or dedicated group.
66+
2. Labels: include `eclipse-timer` (keep default labels too).
67+
68+
## 3. Install runner as a service
69+
70+
From `~/actions-runner`:
71+
72+
```bash
73+
./svc.sh install
74+
./svc.sh start
75+
./svc.sh status
76+
```
77+
78+
If your org policy allows it, also set the Mac mini to auto-login and prevent sleep while plugged in for stable CI uptime.
79+
80+
## 4. Repo secrets needed
81+
82+
Set these in `Settings -> Secrets and variables -> Actions`:
83+
84+
1. `EXPO_TOKEN`
85+
2. `GOOGLE_MAPS_ANDROID_API_KEY`
86+
87+
If you use automated submit:
88+
89+
1. Make sure EAS submit credentials are already configured for Apple and Google Play.
90+
2. Keep `submit` job gated by the `production` environment approval in GitHub.
91+
92+
## 5. Workflow behavior after this change
93+
94+
- `.github/workflows/ci.yml`: runs typecheck/lint/test on self-hosted macOS runner.
95+
- `.github/workflows/eas-build.yml`:
96+
- Runs CI checks on self-hosted macOS.
97+
- Builds locally with:
98+
- `eas build --local --platform ios`
99+
- `eas build --local --platform android`
100+
- Uploads local artifacts (`ios.ipa`, `android.aab`) to the workflow run.
101+
- Optional submit job sends those artifacts using `eas submit --path ...`.
102+
103+
## 6. First validation run
104+
105+
1. In GitHub Actions, run `Self-Hosted Mobile Build & Submit`.
106+
2. Inputs:
107+
- `platform: ios` first, then `android`.
108+
- `submit: false`.
109+
3. Confirm build artifacts are attached to the run.
110+
4. Then run once with `submit: true` when store credentials are confirmed.
111+
112+
## 7. Common issues
113+
114+
1. Runner never picked:
115+
- Check runner is online and has label `eclipse-timer`.
116+
2. iOS signing failures:
117+
- Re-check distribution cert/profile setup in your EAS credentials.
118+
3. Android signing failures:
119+
- Re-check keystore credentials in EAS credentials.
120+
4. Missing Maps key:
121+
- Ensure `GOOGLE_MAPS_ANDROID_API_KEY` is present in repository secrets.

0 commit comments

Comments
 (0)