Configuring CI/CD Pipelines
1. Setting Up GitHub Actions
Example: Basic GitHub Actions Workflow
name: Build and Deploy
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Build Expo app
run: npx expo build:web
| Step | Description | Notes |
|---|---|---|
| name | Build and Deploy |
Workflow name |
| on.push.branches | [ main ] |
Triggers on push to main branch |
| jobs.build.runs-on | ubuntu-latest |
Runner OS for the job |
Note: Ensure that your GitHub repository has the necessary permissions and secrets configured for deployment.
2. Configuring EAS Build in CI
Example: EAS Build Configuration
{
"build": {
"production": {
"distribution": "store",
"android": {
"buildType": "app-bundle"
},
"ios": {
"buildType": "archive"
}
}
}
}
| Property | Description | Values |
|---|---|---|
| build.production | Production build configuration | object |
| build.production.distribution | Where the build is distributed | store, internal |
| build.production.android.buildType | Android build type | app-bundle, aab |
| build.production.ios.buildType | iOS build type | archive, ipa |
Note: EAS Build supports both Android App Bundles and iOS Archives for distribution.
Warning: Ensure that your CI environment has the necessary credentials and permissions to access EAS services.
3. Running Tests in CI
| Command | Description | Notes |
|---|---|---|
| npm test | Runs test suite defined in package.json | Ensure tests are configured to run in headless mode |
| expo test | Runs tests using Expo's test runner | Supports Jest and other testing frameworks |
Note: Configure your CI pipeline to run tests in a headless environment to avoid UI-related issues.
Warning: Make sure to set up proper test coverage reporting in your CI pipeline.
4. Building on Commit
Example: Building on Commit with GitHub Actions
name: Build and Deploy
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Build app
run: npx expo build:web
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
| Step | Description | Command | Notes |
|---|---|---|---|
| Checkout | Check out the repository code | actions/checkout@v3 |
Required for all CI workflows |
| Setup Node.js | Install Node.js runtime | actions/setup-node@v3 |
Ensure version matches local setup |
| Install dependencies | Install project dependencies | npm install |
Uses package-lock.json if present |
| Build app | Build the Expo web application | npx expo build:web |
Requires EXPO_TOKEN for publishing |
Note: Ensure that the
EXPO_TOKEN is stored as a secret in your repository settings for secure access.
5. Using GitHub Secrets
Example: Setting up GitHub Actions with Expo
name: Expo CI/CD
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Build Expo app
run: npx expo build:android
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
EAS_BUILD_SECRET: ${{ secrets.EAS_BUILD_SECRET }}
| Secret Name | Description | Usage |
|---|---|---|
| EXPO_TOKEN | Expo CLI token for publishing builds | Used by eas build or expo publish |
| EAS_BUILD_SECRET | Secret for EAS Build configuration | Required for secure EAS builds |
Note: Store all sensitive credentials as GitHub Secrets in your repository settings.
Warning: Never commit secrets to your repository's source code.
6. Implementing Code Signing
Example: Expo Code Signing Configuration
{
"expo": {
"codeSigning": {
"key": "path/to/code-signing-key.pem",
"certificate": "path/to/code-signing-cert.pem"
}
}
}
| Property | Description | Values |
|---|---|---|
| codeSigning.key | Path to the private key file used for signing | string |
| codeSigning.certificate | Path to the certificate file used for signing | string |
Note: Code signing is required for production builds on iOS and Android to ensure app integrity.
Warning: Keep your code signing keys secure and never commit them to version control.
Workflow: Setting Up Code Signing for Expo
- Generate a code signing key and certificate using OpenSSL
- Store the key and certificate in a secure location (e.g., CI/CD secrets)
- Update
app.jsonorapp.config.jswith the paths to these files - Configure your CI/CD pipeline to use these files during build
7. Automating Store Submission
Example: EAS Build and Submit Configuration
{
"build": {
"production": {
"distribution": "store",
"android": {
"buildType": "app-bundle"
},
"ios": {
"buildType": "archive"
}
}
},
"submit": {
"production": {
"android": {
"serviceAccount": "./path/to/service-account.json"
},
"ios": {
"appleId": "user@example.com",
"ascAppId": "123456789"
}
}
}
}
| Field | Description | Values | Notes |
|---|---|---|---|
| build.production.distribution | Target distribution channel | store |
Submits to app stores |
| build.android.buildType | Android build type | app-bundle, aab |
App bundle is preferred for Google Play |
| build.ios.buildType | iOS build type | archive, ipa |
Archive is preferred for App Store |
| submit.android.serviceAccount | Service account file path | string |
Required for Google Play submission |
| submit.ios.appleId | Apple ID for App Store Connect | string |
Used to authenticate with Apple |
| submit.ios.ascAppId | App Store Connect App ID | string |
Unique identifier for the app in App Store Connect |
Note: Ensure that the service account or Apple credentials are securely stored in CI/CD environment variables.
Warning: Store submissions require valid app signing keys and metadata. Misconfigurations can lead to failed submissions.
8. Deploying OTA Updates
| Property | Description | Default |
|---|---|---|
| branch | The branch to deploy the update to | main |
| message | Release message for the update | None |
| platform | Platform to deploy (ios, android, or all) | all |
Note: OTA updates are only available for managed workflow projects.
Warning: Ensure that your app's
app.json or app.config.js is correctly configured for EAS updates before deploying.
OTA Update Process
- Create a new build with EAS Build
- Configure EAS Update to use the correct branch
- Deploy the update using
eas update - Users will receive the update automatically on next app launch
9. Using Fastlane Integration
Example: Fastlane Configuration for Expo
lane :release do
ensure_git_status_clean
git_pull
cocoapods
match(type: "appstore")
build_ios_app(
scheme: "Expo",
export_method: "app-store"
)
upload_to_app_store
end
| Fastlane Action | Description | Parameters |
|---|---|---|
| build_ios_app | Builds the iOS app for distribution | scheme: "Expo", export_method: "app-store" |
| upload_to_app_store | Uploads the built app to App Store Connect | |
| match | Manages certificates and provisioning profiles | type: "appstore" |
Note: Ensure that your Fastlane configuration matches the Expo project's build settings and certificates.
Warning: Fastlane requires proper setup of Apple Developer credentials and certificates.
10. Implementing Beta Distribution
| Configuration | Description | Value |
|---|---|---|
| eas.json | Build profile for beta distribution | {"build": {"beta": {"distribution": "beta"}}} |
| build.profile | Build configuration name | "beta" |
| build.distribution | Release type for distribution | "beta" |
Note: Ensure your app version is incremented for beta releases to avoid conflicts.
Warning: Beta builds must be signed with a valid distribution certificate.
Key Steps for Beta Distribution
- Create a new build profile in
eas.json - Set
distributionto"beta" - Run
eas build --profile beta - Upload to TestFlight or Google Play Console
11. Monitoring Build Status
Example: Expo Build Status Endpoint
const buildStatus = await fetch(
'https://api.expo.dev/builds/123456789'
).then(res => res.json());
| Field | Description | Values |
|---|---|---|
| status | Current build status | pending, running, success, failed |
| logs | Build logs URL | https://expo.dev/logs/123456789 |
| buildId | Unique identifier for the build | 123456789 |
Note: Build status updates are available via the Expo CLI or API. Use
expo build:status to check progress.
Warning: Build logs are only available for a limited time (typically 7 days) after the build completes.
12. Caching Dependencies
Example: Setting up dependency caching in GitHub Actions
name: Build and Cache Dependencies
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Cache node modules
id: cache-modules
uses: actions/cache@v3
with:
path: |
**/node_modules
/app/.cache
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Install dependencies
if: steps.cache-modules.outputs.cache-hit != 'true'
run: npm ci
| Cache Key | Description | Usage |
|---|---|---|
| node_modules | Dependencies installed via npm or yarn | Cache directory for package dependencies |
| .cache | Expo and build cache directories | Stores intermediate build artifacts |
Note: Caching
node_modules and .cache can significantly speed up CI builds by avoiding redundant installations.