Caracal Starter
CI/CD

GitHub Actions Workflows Reference

Complete reference for all 14 GitHub Actions workflows and 3 custom actions included in Caracal.

Caracal comes with 14 production-ready GitHub Actions workflows and 3 reusable custom actions that automate quality checks, testing, building, releasing, and maintenance tasks.

Overview

All workflows are self-documented with detailed comments inside each YAML file, making them easy to understand and customize without switching between files.

Location:

  • Workflows: .github/workflows/
  • Custom actions: .github/actions/

Each workflow file includes:

  • Links: Source file URL and related documentation
  • Description: What the workflow does and when it runs
  • Secrets Required: GitHub secrets needed (if any)
  • Usage Examples: How to trigger or use the workflow

Workflow Categories

CategoryWorkflowsTotal
Quality ChecksLint, Type Check, Expo Doctor3
TestingUnit Tests, E2E Tests (3 variants)4
BuildingEAS Build QA, EAS Build Prod2
ReleasingNew App Version, New GitHub Release2
MaintenanceCompress Images, Stale Issues/PRs2
DocumentationDeploy Docs to GitHub Pages1
TOTAL14

Custom Actions (Reusable)

Custom actions encapsulate common tasks and can be reused across multiple workflows, reducing duplication and improving maintainability.

1. Setup Node + pnpm + Install Dependencies

Purpose: Sets up Node.js, pnpm package manager, and installs project dependencies with caching.

Location: .github/actions/setup-node-pnpm-install/action.yml

Used in: Almost every workflow (lint, type-check, test, build, etc.)

Benefits:

  • Centralized Node.js and pnpm version management
  • Automatic dependency caching for faster runs
  • Single place to update package manager across all workflows

Usage:

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

2. Setup JDK & Generate APK

Purpose: Sets up Java Development Kit and generates Android APK for testing.

Location: .github/actions/setup-jdk-generate-apk/action.yml

Used in: E2E Android testing workflows

What it does:

  1. Sets up JDK (Java 17)
  2. Configures Gradle caching
  3. Runs prebuild for Android
  4. Generates debug APK
  5. Outputs APK path for testing

Usage:

- name: Setup JDK & Generate APK
  uses: ./.github/actions/setup-jdk-generate-apk
  id: apk

- name: Use APK path
  run: echo "APK at ${{ steps.apk.outputs.apk-path }}"

3. EAS Build

Purpose: Triggers Expo Application Services (EAS) build for iOS or Android.

Location: .github/actions/eas-build/action.yml

Used in: EAS Build workflows (QA, Production)

Inputs:

  • platform: iOS or Android
  • profile: Build profile from eas.json (e.g., qa, production)

Secrets Required:

  • EXPO_TOKEN: EAS authentication token

Usage:

- name: EAS Build Android
  uses: ./.github/actions/eas-build
  with:
    platform: android
    profile: qa
  env:
    EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}

Quality Check Workflows

Lint TS (ESLint + Prettier)

File: .github/workflows/lint-ts.yml

Triggers:

  • Push to main/master branches
  • Pull requests targeting main/master

What it does:

  • Runs ESLint and Prettier checks
  • On PR: Annotates code with errors/warnings via Reviewdog
  • On push: Fails if linting errors exist

Secrets: None required

Fix linting issues:

pnpm lint:fix

Type Check (TypeScript)

File: .github/workflows/type-check.yml

Triggers:

  • Push to main/master branches
  • Pull requests targeting main/master

What it does:

  • Runs TypeScript compiler in check mode
  • Verifies type safety across entire codebase
  • Fails on type errors

Secrets: None required

Run type check locally:

pnpm type-check

Expo Doctor

File: .github/workflows/expo-doctor.yml

Triggers:

  • Push to main/master branches
  • Pull requests targeting main/master

What it does:

  • Runs expo-doctor to check project health
  • Validates Expo configuration
  • Checks for common setup issues
  • Verifies dependency compatibility

Secrets: None required

Run doctor locally:

pnpm doctor

Testing Workflows

Unit Tests + Coverage

File: .github/workflows/test.yml

Triggers:

  • Push to main/master branches
  • Pull requests targeting main/master

What it does:

  • Runs Jest unit tests
  • Generates coverage report
  • Uploads coverage to Codecov (optional)
  • Fails if tests fail or coverage drops below threshold

Secrets:

  • CODECOV_TOKEN (optional): For coverage reporting

Run tests locally:

pnpm test              # Run all tests
pnpm test:watch        # Watch mode
pnpm test:coverage     # With coverage report

E2E Testing (3 Variants)

Caracal includes 3 different E2E testing workflows to support various testing strategies.

Variant 1: E2E Android (Local Emulator)

File: .github/workflows/e2e-android.yml

Triggers: Manual via workflow_dispatch

What it does:

  1. Sets up Android emulator on GitHub runner
  2. Generates debug APK
  3. Installs Maestro
  4. Runs Maestro tests locally
  5. Uploads test results as artifacts

Best for: CI/CD pipelines with self-hosted runners

Secrets: None required


Variant 2: E2E Android Maestro Cloud

File: .github/workflows/e2e-android-maestro.yml

Triggers: Manual via workflow_dispatch

What it does:

  1. Generates debug APK
  2. Uploads APK to Maestro Cloud
  3. Runs tests on Maestro Cloud infrastructure
  4. Returns test results

Best for: Teams using Maestro Cloud (faster, no emulator setup)

Secrets:

  • MAESTRO_CLOUD_API_KEY: Maestro Cloud authentication

Variant 3: E2E Android with EAS Build

File: .github/workflows/e2e-android-eas-build.yml

Triggers: Manual via workflow_dispatch

What it does:

  1. Triggers EAS build for Android
  2. Waits for build to complete
  3. Downloads APK from EAS
  4. Uploads to Maestro Cloud
  5. Runs tests on cloud infrastructure

Best for: Testing production-like builds on Maestro Cloud

Secrets:

  • EXPO_TOKEN: EAS authentication
  • MAESTRO_CLOUD_API_KEY: Maestro Cloud authentication

Choose the right variant:

VariantUse CaseProsCons
Local EmulatorSelf-hosted runnersFree, full controlSlow, requires powerful runners
Maestro CloudFast feedbackVery fast, no emulator setupRequires Maestro Cloud subscription
EAS + MaestroProduction testingTests real buildsSlowest (build + upload time)

Building Workflows

EAS Build QA

File: .github/workflows/eas-build-qa.yml

Triggers: Manual via workflow_dispatch

Inputs:

  • platform: Choose iOS, Android, or both

What it does:

  • Triggers EAS build using qa profile from eas.json
  • Builds development/staging version of the app
  • Suitable for internal testing

Secrets:

  • EXPO_TOKEN: EAS authentication token

Trigger manually:

  1. Go to Actions tab in GitHub
  2. Select "EAS Build QA"
  3. Click "Run workflow"
  4. Choose platform (iOS, Android, or both)

EAS Build Production

File: .github/workflows/eas-build-prod.yml

Triggers: Manual via workflow_dispatch

Inputs:

  • platform: Choose iOS, Android, or both

What it does:

  • Triggers EAS build using production profile
  • Builds release/store version of the app
  • Optimized for App Store and Google Play submission

Secrets:

  • EXPO_TOKEN: EAS authentication token

Production builds use release configuration and may require additional setup:

  • iOS: Apple Developer account and certificates
  • Android: Play Store signing keys
  • Configure secrets in EAS: eas secret:create

Releasing Workflows

New App Version

File: .github/workflows/new-app-version.yml

Triggers: Manual via workflow_dispatch

Inputs:

  • release-type: Choose patch, minor, or major

What it does:

  1. Bumps version in package.json based on release type
  2. Runs pnpm prebuild to sync version with native code
  3. Creates Git tag with new version
  4. Pushes tag to repository
  5. Triggers other workflows (like builds)

Secrets:

  • GH_TOKEN: GitHub Personal Access Token with write access

Versioning:

  • Patch (1.0.0 → 1.0.1): Bug fixes
  • Minor (1.0.0 → 1.1.0): New features, backward compatible
  • Major (1.0.0 → 2.0.0): Breaking changes

How to use:

  1. Go to Actions → New App Version
  2. Click "Run workflow"
  3. Select release type (patch/minor/major)
  4. Workflow creates version bump and tag
  5. Check releases page for new tag

New GitHub Release

File: .github/workflows/new-github-release.yml

Triggers: When a new tag is pushed (usually by the New App Version workflow)

What it does:

  1. Detects new version tag
  2. Extracts changelog from CHANGELOG.md
  3. Creates GitHub Release with notes
  4. Marks as pre-release if version contains -beta, -alpha, etc.

Secrets: None required (uses GITHUB_TOKEN)


Maintenance Workflows

Compress Images

File: .github/workflows/compress-images.yml

Triggers:

  • Pull requests that modify image files (.png, .jpg, .jpeg, .gif)

What it does:

  1. Detects image changes in PR
  2. Compresses images using calibreapp/image-actions
  3. Commits optimized images back to PR
  4. Reduces bundle size automatically

Secrets: None required

Compression settings:

  • PNG: Lossless compression
  • JPEG: Quality 80%
  • GIF: Optimized without losing animation

Stale Issues and PRs

File: .github/workflows/stale.yml

Triggers: Daily at midnight (cron: 0 0 * * *)

What it does:

  • Marks issues/PRs stale after 60 days of inactivity
  • Adds label: no-issue-activity or no-pr-activity
  • Posts comment warning about closure
  • Closes stale items after 14 more days

Secrets: None required (uses GITHUB_TOKEN)

Prevent closure:

  • Comment on the issue/PR
  • Remove the stale label
  • Push new commits (for PRs)

Customize by editing .github/workflows/stale.yml:

  • days-before-stale: Days before marking stale (default: 60)
  • days-before-close: Days before closing after stale (default: 14)

Documentation Workflow

Deploy Docs to GitHub Pages

File: .github/workflows/deploy-docs.yml

Triggers:

  • Push to master branch with changes in docs/**
  • Manual via workflow_dispatch

What it does:

  1. Builds the documentation site
  2. Uploads to GitHub Pages
  3. Deploys to configured URL
  4. Automatically updates live docs

Secrets: None required (uses built-in GITHUB_TOKEN)

Setup GitHub Pages:

  1. Go to Settings → Pages
  2. Source: GitHub Actions
  3. Push to docs/ folder
  4. Docs deploy automatically

Local development:

cd docs
pnpm install
pnpm dev        # Start dev server
pnpm build      # Build for production

Workflow Triggers Reference

TriggerDescriptionExample Workflows
pushOn push to specific brancheslint-ts, type-check, test, deploy-docs
pull_requestOn PR to specific brancheslint-ts, type-check, test, expo-doctor
workflow_dispatchManual trigger from Actions tabeas-build-qa, eas-build-prod, new-app-version
scheduleCron-based schedulestale (daily)
push (tags)On new tag creationnew-github-release

Required GitHub Secrets

Configure these secrets in Settings → Secrets and variables → Actions.

Required for EAS Builds

EXPO_TOKEN

  • Used in: eas-build-qa, eas-build-prod, e2e-android-eas-build
  • How to get: Create token at https://expo.dev/accounts/[account]/settings/access-tokens
  • Permissions: Build and submit apps

Required for Versioning

GH_TOKEN

  • Used in: new-app-version
  • How to get: GitHub Settings → Developer settings → Personal access tokens → Generate new token (classic)
  • Permissions: repo (Full control of private repositories)

Optional for E2E Testing

MAESTRO_CLOUD_API_KEY

  • Used in: e2e-android-maestro, e2e-android-eas-build
  • How to get: Maestro Cloud dashboard → API Keys
  • Required: Only if using Maestro Cloud

Optional for Coverage

CODECOV_TOKEN

  • Used in: test (optional)
  • How to get: Codecov.io dashboard
  • Required: Only if uploading coverage reports

Best Practices

1. Enable Required Workflows

Mark critical workflows as required in branch protection:

Settings → Branches → Branch protection rules → Add rule

Required checks:

  • Lint TS
  • Type Check
  • Unit Tests
  • Expo Doctor

This prevents merging PRs with failing checks.

2. Customize Workflow Triggers

# Run only on specific branches
on:
  push:
    branches: [main, develop]

# Run only on specific file changes
on:
  push:
    paths:
      - 'src/**'
      - 'package.json'

# Exclude documentation changes
on:
  push:
    paths-ignore:
      - 'docs/**'
      - '**.md'

3. Use Concurrency Controls

Prevent multiple runs of the same workflow:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

4. Cache Dependencies

All workflows use pnpm caching via the custom action. When adding new workflows:

- name: Setup Node + pnpm + install
  uses: ./.github/actions/setup-node-pnpm-install

Troubleshooting

Workflow Fails: "Resource not accessible by integration"

Problem: Workflow lacks required permissions.

Solution: Add permissions to workflow:

permissions:
  contents: write
  pull-requests: write

EAS Build Fails: "Invalid Expo token"

Problem: EXPO_TOKEN secret not configured or expired.

Solution:

  1. Generate new token at https://expo.dev/accounts/[account]/settings/access-tokens
  2. Add to GitHub secrets: Settings → Secrets → New repository secret
  3. Name: EXPO_TOKEN, Value: token from Expo

New App Version Fails: "Permission denied"

Problem: GH_TOKEN lacks write permissions.

Solution: Generate new GitHub PAT with repo scope and update the secret.

Maestro E2E Fails: "APK not found"

Problem: APK path incorrect or build failed.

Solution:

  1. Check "Setup JDK & Generate APK" step succeeded
  2. Verify APK path: android/app/build/outputs/apk/debug/app-debug.apk
  3. Check Android build logs for errors

Type Check Fails Locally but Passes in CI

Solution:

# Clear TypeScript cache
rm -rf node_modules/.cache

# Reinstall dependencies
pnpm install --frozen-lockfile

# Run type check
pnpm type-check

Workflow Execution Order

For a typical release process:

1. Development
   ├─ [On every commit/PR]
   │  ├─ Lint TS
   │  ├─ Type Check
   │  ├─ Unit Tests
   │  └─ Expo Doctor

2. Ready to Release
   ├─ [Manual] New App Version
   │  ├─ Bumps version
   │  └─ Creates git tag

3. Automatic on Tag
   ├─ New GitHub Release
   │  └─ Creates release with changelog

4. Build for Distribution
   ├─ [Manual] EAS Build Prod
   │  ├─ iOS Build
   │  └─ Android Build

5. E2E Testing (Optional)
   └─ [Manual] E2E Android Maestro
      └─ Validates build quality

Additional Resources


Summary

14 Workflows Included:

#WorkflowTriggerPurpose
1Lint TSPR/PushCode quality (ESLint + Prettier)
2Type CheckPR/PushTypeScript type safety
3Expo DoctorPR/PushExpo configuration health
4Unit TestsPR/PushJest tests + coverage
5E2E AndroidManualE2E tests (local emulator)
6E2E Maestro CloudManualE2E tests (Maestro Cloud)
7E2E EAS + MaestroManualE2E tests (production build)
8EAS Build QAManualQA/staging builds
9EAS Build ProdManualProduction builds
10New App VersionManualVersion bumps + tags
11New GitHub ReleaseTag pushGitHub releases
12Compress ImagesPRImage optimization
13Stale Issues/PRsDailyHousekeeping
14Deploy DocsPushDocumentation site

3 Custom Actions:

  1. Setup Node + pnpm + Install
  2. Setup JDK & Generate APK
  3. EAS Build

On this page