Skip to content
80 changes: 80 additions & 0 deletions .github/workflows/app-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: App Tests (Unit + App only)

on:
workflow_call:
secrets:
DATABASE_URL:
required: true
SUPABASE_SECRET_KEY:
required: true
RESEND_API_KEY:
required: true
SEATS_AERO_API_KEY:
required: true
WORKER_URL:
required: true
WORKER_API_KEY:
required: true
NEXT_PUBLIC_SUPABASE_URL:
required: true
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY:
required: true
NEXT_PUBLIC_MAPKIT_TOKEN:
required: true

jobs:
app-tests:
name: Run App Tests (exclude workers & fli)
runs-on: ubuntu-latest
timeout-minutes: 30
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SUPABASE_SECRET_KEY: ${{ secrets.SUPABASE_SECRET_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
SEATS_AERO_API_KEY: ${{ secrets.SEATS_AERO_API_KEY }}
WORKER_URL: ${{ secrets.WORKER_URL }}
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_MAPKIT_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPKIT_TOKEN }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.30

- name: Cache Bun dependencies
uses: actions/cache@v4
with:
path: |
~/.bun/install/cache
~/.cache/bun
node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb', 'bun.lock', 'bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Validate required environment variables
run: |
set -euo pipefail
required_vars=(DATABASE_URL SUPABASE_SECRET_KEY RESEND_API_KEY SEATS_AERO_API_KEY WORKER_URL WORKER_API_KEY NEXT_PUBLIC_SUPABASE_URL NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY NEXT_PUBLIC_MAPKIT_TOKEN)
missing=0
for v in "${required_vars[@]}"; do
if [ -z "${!v:-}" ]; then
echo "Missing required env: $v" >&2
missing=1
fi
done
if [ "$missing" -ne 0 ]; then
exit 1
fi

- name: Run tests (app only; serialized to avoid global mock conflicts)
run: bun test --timeout 60000 --jobs 1 --preload ./src/test/setup.ts src/components src/core src/lib/notifications
136 changes: 136 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: CI/CD

on:
pull_request:
push:
branches: [ main ]

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

jobs:
lint_format:
name: Lint and Format
uses: ./.github/workflows/lint-format.yml

build:
name: Build
needs: [lint_format]
runs-on: ubuntu-latest
steps:
- run: echo "placeholder step to enable job fan-out" # GitHub requires at least one step

worker_build:
name: Worker Build (Dry Run)
needs: [build]
uses: ./.github/workflows/worker-build.yml
secrets:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SUPABASE_SECRET_KEY: ${{ secrets.SUPABASE_SECRET_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
SEATS_AERO_API_KEY: ${{ secrets.SEATS_AERO_API_KEY }}
WORKER_URL: ${{ secrets.WORKER_URL }}
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_MAPKIT_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPKIT_TOKEN }}

web_build:
name: Web App Build
needs: [build]
uses: ./.github/workflows/web-build.yml
secrets:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SUPABASE_SECRET_KEY: ${{ secrets.SUPABASE_SECRET_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
SEATS_AERO_API_KEY: ${{ secrets.SEATS_AERO_API_KEY }}
WORKER_URL: ${{ secrets.WORKER_URL }}
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_MAPKIT_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPKIT_TOKEN }}

migrate_db:
name: Database Migrate (main only)
if: github.ref == 'refs/heads/main'
needs: [web_build, worker_build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.30
- run: bun install --frozen-lockfile
- name: Run migrations
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: bun run db:migrate

migrate_dry_run:
name: Database Migration Dry-Run (PRs)
if: github.event_name == 'pull_request'
needs: [web_build, worker_build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.30
- run: bun install --frozen-lockfile
- name: Drizzle schema check
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: npx drizzle-kit check

tests:
name: Tests
needs: [web_build, worker_build]
runs-on: ubuntu-latest
steps:
- run: echo "placeholder step to enable job fan-out"

app_tests:
name: App Tests
needs: [tests]
uses: ./.github/workflows/app-tests.yml
secrets:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SUPABASE_SECRET_KEY: ${{ secrets.SUPABASE_SECRET_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
SEATS_AERO_API_KEY: ${{ secrets.SEATS_AERO_API_KEY }}
WORKER_URL: ${{ secrets.WORKER_URL }}
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_MAPKIT_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPKIT_TOKEN }}

worker_tests:
name: Worker Tests
needs: [tests]
uses: ./.github/workflows/worker-tests.yml
secrets:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SUPABASE_SECRET_KEY: ${{ secrets.SUPABASE_SECRET_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
SEATS_AERO_API_KEY: ${{ secrets.SEATS_AERO_API_KEY }}
WORKER_URL: ${{ secrets.WORKER_URL }}
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_MAPKIT_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPKIT_TOKEN }}

fli_tests:
name: Fli Tests
needs: [tests]
uses: ./.github/workflows/fli-tests.yml
secrets:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SUPABASE_SECRET_KEY: ${{ secrets.SUPABASE_SECRET_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
SEATS_AERO_API_KEY: ${{ secrets.SEATS_AERO_API_KEY }}
WORKER_URL: ${{ secrets.WORKER_URL }}
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_MAPKIT_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPKIT_TOKEN }}
81 changes: 81 additions & 0 deletions .github/workflows/fli-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Fli Tests (only)

on:
workflow_call:
secrets:
DATABASE_URL:
required: true
SUPABASE_SECRET_KEY:
required: true
RESEND_API_KEY:
required: true
SEATS_AERO_API_KEY:
required: true
WORKER_URL:
required: true
WORKER_API_KEY:
required: true
NEXT_PUBLIC_SUPABASE_URL:
required: true
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY:
required: true
NEXT_PUBLIC_MAPKIT_TOKEN:
required: true

jobs:
fli-tests:
name: Run Fli Tests Only
runs-on: ubuntu-latest
timeout-minutes: 30
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SUPABASE_SECRET_KEY: ${{ secrets.SUPABASE_SECRET_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
SEATS_AERO_API_KEY: ${{ secrets.SEATS_AERO_API_KEY }}
WORKER_URL: ${{ secrets.WORKER_URL }}
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_MAPKIT_TOKEN: ${{ secrets.NEXT_PUBLIC_MAPKIT_TOKEN }}
RUN_INTEGRATION_TESTS: true

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.30

- name: Cache Bun dependencies
uses: actions/cache@v4
with:
path: |
~/.bun/install/cache
~/.cache/bun
node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb', 'bun.lock', 'bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Validate required environment variables
run: |
set -euo pipefail
required_vars=(DATABASE_URL SUPABASE_SECRET_KEY RESEND_API_KEY SEATS_AERO_API_KEY WORKER_URL WORKER_API_KEY NEXT_PUBLIC_SUPABASE_URL NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY NEXT_PUBLIC_MAPKIT_TOKEN)
missing=0
for v in "${required_vars[@]}"; do
if [ -z "${!v:-}" ]; then
echo "Missing required env: $v" >&2
missing=1
fi
done
if [ "$missing" -ne 0 ]; then
exit 1
fi

- name: Run Fli tests only (100s timeout)
run: bun test --concurrent --timeout 100000 --preload ./src/test/setup.ts src/lib/fli
42 changes: 42 additions & 0 deletions .github/workflows/lint-format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Lint and Format

on:
workflow_call:

jobs:
lint-format:
name: Biome Lint and Format (auto-fix, then verify)
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Cache Bun dependencies
uses: actions/cache@v4
with:
path: |
~/.bun/install/cache
~/.cache/bun
node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb', 'bun.lock', 'bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Auto-format
run: bun run format

- name: Auto-lint (with fixes)
run: bun run lint

- name: Verify formatting and lint are clean
run: bunx @biomejs/biome check --no-errors-on-unmatched --reporter=github .
Loading
Loading