Skip to main content

CI/CD Pipeline

Overview

BookWish uses GitHub Actions for continuous integration and deployment. Every push and pull request triggers automated tests, builds, and deployments.

Pipeline Architecture

┌─────────────┐
│ Git Push │
└──────┬──────┘


┌─────────────────────────────┐
│ GitHub Actions Trigger │
└──────┬──────────────────────┘

├──────────────────┬──────────────────┬──────────────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Lint │ │ Test │ │ Build │ │ Deploy │
└──────────┘ └──────────┘ └──────────┘ └──────────┘

Workflows

Pull Request Workflow

Runs on every pull request to main:

# .github/workflows/pr.yml
name: Pull Request

on:
pull_request:
branches: [main]

jobs:
lint:
- ESLint (backend)
- Flutter analyze (app)
- TypeScript type check

test:
- Backend unit tests
- Flutter unit tests
- Integration tests

build:
- Backend build
- Flutter build (iOS, Android, Web)

Status: Must pass before merge is allowed

Continuous Integration (Main Branch)

Runs on every push to main:

# .github/workflows/ci.yml
name: CI

on:
push:
branches: [main]

jobs:
lint-and-test:
- Run all linting
- Run all tests
- Generate coverage reports

deploy-staging:
- Deploy backend to staging
- Deploy web app to staging
- Run smoke tests

Release Workflow

Runs when a version tag is pushed:

# .github/workflows/release.yml
name: Release

on:
push:
tags:
- 'v*'

jobs:
build-ios:
- Build iOS app
- Upload to TestFlight

build-android:
- Build Android app
- Upload to Play Store

build-web:
- Build web app
- Deploy to Vercel

create-release:
- Generate changelog
- Create GitHub release

Workflow Details

Linting

- name: Lint Backend
run: |
cd backend
npm run lint

- name: Lint Flutter
run: |
cd app
flutter analyze

Checks:

  • Code style compliance
  • No TypeScript any types
  • No console.log statements
  • No print() statements
  • Proper imports

Testing

- name: Backend Tests
run: |
cd backend
npm test

- name: Flutter Tests
run: |
cd app
flutter test --coverage

Coverage Requirements:

  • Backend: 80% minimum
  • Flutter: 70% minimum

Building

- name: Build Backend
run: |
cd backend
npm run build

- name: Build Flutter Web
run: |
cd app
flutter build web --release

- name: Build Flutter iOS
run: |
cd app/ios
bundle exec fastlane build

Secrets Management

All sensitive data is stored in GitHub Secrets:

Required Secrets

SecretUsed ForRequired By
APPLE_CERTIFICATE_BASE64iOS signingRelease workflow
ANDROID_KEYSTORE_BASE64Android signingRelease workflow
VERCEL_TOKENWeb deploymentRelease workflow
DATABASE_URLTest databaseCI workflow

Adding Secrets

  1. Go to Repository → Settings → Secrets and variables → Actions
  2. Click "New repository secret"
  3. Add name and value
  4. Reference in workflow: ${{ secrets.SECRET_NAME }}

Environment Variables

Development

NODE_ENV=development
DATABASE_URL=postgresql://localhost/bookwish_dev
API_BASE_URL=http://localhost:3000

Staging

NODE_ENV=staging
DATABASE_URL=${{ secrets.STAGING_DATABASE_URL }}
API_BASE_URL=https://staging-api.bookwish.io

Production

NODE_ENV=production
DATABASE_URL=${{ secrets.PRODUCTION_DATABASE_URL }}
API_BASE_URL=https://api.bookwish.io

Deployment Targets

Backend API

Platform: AWS ECS / Railway / Render (specify your platform)

Process:

  1. Build Docker image
  2. Push to container registry
  3. Deploy to production cluster
  4. Run database migrations
  5. Health check verification

Flutter Web

Platform: Vercel

Process:

  1. Build Flutter web
  2. Upload to Vercel
  3. Deploy to production domain
  4. Invalidate CDN cache

Mobile Apps

iOS:

  • Build with Xcode Cloud or GitHub Actions
  • Upload to TestFlight
  • Manual submission to App Store

Android:

  • Build with GitHub Actions
  • Upload to Play Store Internal Track
  • Promote to Beta/Production manually

Monitoring

Build Status

Monitor builds at:

  • GitHub Actions tab
  • Status badges in README
  • Slack/Discord notifications (if configured)

Deployment Status

Check deployment status:

  • Vercel dashboard (web)
  • App Store Connect (iOS)
  • Google Play Console (Android)
  • Your hosting provider (backend)

Notifications

Configure notifications in:

# .github/workflows/notify.yml
- name: Notify on Failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Caching

Speed up builds with caching:

- name: Cache Dependencies
uses: actions/cache@v3
with:
path: |
~/.npm
~/.pub-cache
key: ${{ runner.os }}-deps-${{ hashFiles('**/package-lock.json', '**/pubspec.lock') }}

Troubleshooting

Build Failures

  1. Check logs: Click on failed job in GitHub Actions
  2. Reproduce locally: Run same commands on your machine
  3. Check secrets: Ensure all required secrets are set
  4. Verify dependencies: Check for broken dependencies

Deployment Failures

  1. Check deployment logs in your hosting platform
  2. Verify environment variables are set correctly
  3. Check database migrations have run successfully
  4. Verify API connectivity from deployed app

Common Issues

Issue: Tests fail in CI but pass locally

  • Solution: Check for environment-specific code, ensure test database is seeded properly

Issue: Build timeout

  • Solution: Increase timeout in workflow, optimize build steps, add caching

Issue: Secrets not available

  • Solution: Verify secret names match exactly, check repository permissions

Best Practices

Do's

✅ Keep workflows fast (< 10 minutes) ✅ Use caching for dependencies ✅ Fail fast on critical errors ✅ Run tests in parallel when possible ✅ Use matrix builds for multiple platforms ✅ Keep secrets secure and rotated ✅ Monitor build status regularly

Don'ts

❌ Commit secrets to repository ❌ Skip tests to make builds faster ❌ Deploy without running tests ❌ Ignore failed builds ❌ Hard-code environment-specific values

Workflow Templates

Basic PR Check

name: PR Check
on: [pull_request]

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install
run: npm ci
- name: Lint
run: npm run lint
- name: Test
run: npm test
- name: Build
run: npm run build

Matrix Build

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [16, 18, 20]
steps:
- uses: actions/checkout@v3
- name: Setup Node ${{ matrix.node }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test

Performance Optimization

Parallel Jobs

jobs:
lint:
runs-on: ubuntu-latest
steps: [...]

test-backend:
runs-on: ubuntu-latest
steps: [...]

test-frontend:
runs-on: ubuntu-latest
steps: [...]

Conditional Execution

- name: Deploy
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: npm run deploy

References