Skip to content

Mobile CI/CD Workflows

This guide provides detailed information about the GitHub Actions workflows that power the CI/CD pipeline for the PersiaNation mobile application.

The mobile app uses several GitHub Actions workflows to ensure code quality, automate builds, and streamline releases:

WorkflowTriggerPurposeDuration
test.ymlPush, PRUnit & integration tests~3-5 min
lint-ts.ymlPush, PRTypeScript linting~2-3 min
type-check.ymlPush, PRTypeScript type checking~1-2 min
e2e-android.ymlPush, PREnd-to-end testing~10-15 min
preview.ymlHotfix branchPreview builds & OTA updates~5-8 min
new-github-release.ymlGit tagsGitHub releases~1-2 min

1. TypeScript Type Checking (type-check.yml)

Section titled “1. TypeScript Type Checking (type-check.yml)”

Purpose: Ensures type safety across the entire codebase.

name: Type Check
on: [push, pull_request]
jobs:
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18.x
- uses: pnpm/action-setup@v2
with:
version: latest
- run: pnpm install
- run: pnpm type-check

What it checks:

  • TypeScript compilation errors
  • Type mismatches and inconsistencies
  • Missing type definitions
  • Interface compatibility

Purpose: Enforces code style and catches common issues.

name: Lint TypeScript
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: pnpm/action-setup@v2
- run: pnpm install
- run: pnpm lint

What it checks:

  • ESLint rule violations
  • Code formatting consistency
  • Import/export issues
  • Unused variables and imports
  • React/React Native specific issues

Purpose: Runs the complete test suite to ensure functionality.

name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: pnpm/action-setup@v2
- run: pnpm install
- run: pnpm test

What it tests:

  • Component rendering and behavior
  • Utility function correctness
  • API integration logic
  • Navigation flows
  • State management

Purpose: Tests complete user workflows on Android emulator.

name: E2E Android
on: [push, pull_request]
jobs:
e2e-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: pnpm/action-setup@v2
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Run E2E tests
run: pnpm e2e:android

What it tests:

  • Complete user registration flow
  • Authentication and login
  • Core app navigation
  • Critical user interactions
  • App performance under load

Purpose: Creates quick preview builds for testing hotfixes and urgent changes.

name: Preview
on:
pull_request:
branches: [hotfix]
push:
branches: [hotfix]
jobs:
update:
name: EAS Update
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Check for EXPO_TOKEN
run: |
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
echo "EXPO_TOKEN secret required"
exit 1
fi
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18.x
- uses: pnpm/action-setup@v2
with:
version: latest
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- run: pnpm install
- name: Create preview
uses: expo/expo-github-action/preview@v8
with:
command: eas update --auto

Features:

  • Triggers on hotfix branch changes
  • Creates EAS Update for immediate testing
  • Posts preview QR code in PR comments
  • Uses staging channel for safe testing
  • Automatic deployment without manual intervention

2. GitHub Release Creation (new-github-release.yml)

Section titled “2. GitHub Release Creation (new-github-release.yml)”

Purpose: Automatically creates GitHub releases when version tags are pushed.

name: New GitHub Release
on:
push:
tags: ["*"]
jobs:
release:
name: New GitHub Release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: ncipollo/release-action@v1
with:
generateReleaseNotes: true
draft: false

Features:

  • Triggered by any git tag push
  • Automatically generates release notes from commits
  • Creates public GitHub release
  • Links to build artifacts and changelogs

Configure these secrets in your GitHub repository settings:

Terminal window
# Repository Settings > Secrets and Variables > Actions
EXPO_TOKEN # Expo account authentication token
GOOGLE_SERVICES_JSON # Android Google Services configuration
APPLE_TEAM_ID # iOS development team identifier
ANDROID_KEYSTORE_PASSWORD # Android app signing keystore password
ANDROID_KEY_ALIAS # Android signing key alias
ANDROID_KEY_PASSWORD # Android signing key password
Terminal window
# Automatically set by workflows
GITHUB_TOKEN # GitHub API access (auto-provided)
RUNNER_OS # Operating system (ubuntu-latest)
NODE_VERSION # Node.js version (18.x)
PNPM_VERSION # Package manager version (latest)
# Runs on every push to any branch
on: [push]
# Runs on push to specific branches
on:
push:
branches: [main, staging, develop]
# Runs on tag pushes
on:
push:
tags: ['v*', 'release/*']
# Runs on PR creation and updates
on: [pull_request]
# Runs on PR to specific branches
on:
pull_request:
branches: [main, staging]
types: [opened, synchronize, reopened]
# Allows manual workflow execution
on:
workflow_dispatch:
inputs:
environment:
description: "Environment to deploy to"
required: true
default: "staging"
type: choice
options:
- staging
- production
# Cache node_modules for faster installs
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
# Cache Expo CLI and tools
- name: Cache Expo
uses: actions/cache@v3
with:
path: ~/.expo
key: ${{ runner.os }}-expo-${{ hashFiles('**/app.config.ts') }}
jobs:
test:
strategy:
matrix:
platform: [ios, android]
environment: [staging, production]
runs-on: ubuntu-latest
steps:
- name: Test ${{ matrix.platform }} on ${{ matrix.environment }}
run: pnpm test:${{ matrix.platform }}
# Only run on specific file changes
- name: Run tests
if: contains(github.event.head_commit.modified, 'src/')
run: pnpm test
# Skip workflows on documentation changes
- name: Check for docs changes
if: "!contains(github.event.head_commit.message, '[skip ci]')"
run: pnpm build
Terminal window
# View workflow runs
gh run list --workflow="test.yml"
# Get specific run details
gh run view <run-id>
# Download workflow logs
gh run download <run-id>
# Increase timeout for long-running jobs
jobs:
build:
timeout-minutes: 30 # Default is 6 hours
runs-on: ubuntu-latest
# Debug secret availability
- name: Check secrets
run: |
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
echo "EXPO_TOKEN not available"
exit 1
fi
# Retry failed installations
- name: Install dependencies
run: |
for i in {1..3}; do
pnpm install && break || sleep 15
done
MetricTargetTypical
Type Check< 2 min1.5 min
Linting< 3 min2.5 min
Unit Tests< 5 min4 min
E2E Tests< 15 min12 min
EAS Update< 8 min6 min
  • Keep workflows focused on single responsibilities
  • Use reusable actions for common tasks
  • Organize jobs logically with clear dependencies
  • Use meaningful names and descriptions
  • Never log sensitive information
  • Use secrets for all credentials
  • Limit workflow permissions to minimum required
  • Regularly rotate authentication tokens
  • Cache dependencies and build artifacts
  • Use matrix builds for parallel execution
  • Skip unnecessary jobs based on file changes
  • Optimize Docker image usage
  • Add retry logic for flaky operations
  • Use appropriate timeouts
  • Handle edge cases gracefully
  • Monitor workflow success rates
name: Custom EAS Build
on:
workflow_dispatch:
inputs:
platform:
type: choice
options: [ios, android, all]
profile:
type: choice
options: [development, staging, production]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: pnpm/action-setup@v2
- uses: expo/expo-github-action@v8
with:
token: ${{ secrets.EXPO_TOKEN }}
- run: pnpm install
- name: Build app
run: |
eas build \
--platform ${{ github.event.inputs.platform }} \
--profile ${{ github.event.inputs.profile }} \
--non-interactive
name: Store Submission
on:
release:
types: [published]
jobs:
submit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: expo/expo-github-action@v8
with:
token: ${{ secrets.EXPO_TOKEN }}
- name: Submit to stores
run: |
eas submit \
--platform all \
--profile production \
--latest \
--non-interactive