Skip to content

simplify calendar into a month-first agenda #133

simplify calendar into a month-first agenda

simplify calendar into a month-first agenda #133

Workflow file for this run

name: Validate
on:
push:
branches:
- main
pull_request:
concurrency:
group: validate-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
BETTER_AUTH_SECRET: ci-build-secret-gradientpeak-2026-validate-32chars
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
POSTGRES_URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
SUPABASE_DB_URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
NEXT_PRIVATE_SUPABASE_URL: https://example.supabase.co
NEXT_PUBLIC_SUPABASE_URL: https://example.supabase.co
NEXT_PRIVATE_SUPABASE_SECRET_KEY: ci-build-service-role-key
SUPABASE_SERVICE_ROLE_KEY: ci-build-service-role-key
jobs:
changes:
name: Changes
runs-on: ubuntu-latest
outputs:
docs_only: ${{ steps.filter.outputs.docs == 'true' && steps.filter.outputs.non_docs != 'true' }}
api_live_db_related: ${{ steps.filter.outputs.api_live_db_related }}
db_schema_related: ${{ steps.filter.outputs.db_schema_related }}
mobile_runtime_related: ${{ steps.filter.outputs.mobile_runtime_related }}
mobile_test_related: ${{ steps.filter.outputs.mobile_test_related }}
web_related: ${{ steps.filter.outputs.web_related }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect docs-only changes
id: filter
uses: dorny/paths-filter@v3
with:
filters: |
docs:
- '**/*.md'
- '**/*.mdx'
- 'docs/**'
- '.github/workflows/validate.yml'
non_docs:
- '**'
- '!**/*.md'
- '!**/*.mdx'
- '!docs/**'
- '!.github/workflows/validate.yml'
mobile_runtime_related:
- 'apps/mobile/**'
- '!apps/mobile/.maestro/**'
- '!apps/mobile/scripts/generate-maestro-preview-flow.mts'
- '!apps/mobile/scripts/maestro-local.sh'
- '!apps/mobile/scripts/prepare-maestro-device.sh'
- '!apps/mobile/scripts/run-maestro-lane.mjs'
- 'packages/api/**'
- 'packages/auth/**'
- 'packages/core/**'
- 'packages/db/**'
- 'packages/tailwindcss/**'
- 'packages/ui/**'
- 'tooling/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'turbo.json'
db_schema_related:
- 'packages/db/**'
api_live_db_related:
- 'packages/api/**'
- 'packages/db/**'
- 'packages/supabase/**'
mobile_test_related:
- 'apps/mobile/.maestro/**'
- 'apps/mobile/scripts/generate-maestro-preview-flow.mts'
- 'apps/mobile/scripts/maestro-local.sh'
- 'apps/mobile/scripts/prepare-maestro-device.sh'
- 'apps/mobile/scripts/run-maestro-lane.mjs'
- 'scripts/ci-export-local-env.sh'
- 'scripts/test-e2e.sh'
web_related:
- 'apps/web/**'
- 'packages/api/**'
- 'packages/auth/**'
- 'packages/core/**'
- 'packages/db/**'
- 'packages/tailwindcss/**'
- 'packages/ui/**'
- 'tooling/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'turbo.json'
docs-only:
name: Docs Only
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only == 'true'
steps:
- name: Skip full validation for docs-only changes
run: |
printf 'Docs-only change detected; skipping full validation suite.\n'
format-and-lint:
name: Format And Lint
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Biome check
run: pnpm check
typecheck:
name: Typecheck
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run type checks
run: pnpm check-types
build:
name: Build
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run builds
run: pnpm build
unit-and-integration:
name: Unit And Integration
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run unit and integration tests
run: pnpm test
db-schema-parity:
name: DB Schema Parity
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true'
steps:
- name: Checkout
if: needs.changes.outputs.db_schema_related == 'true'
uses: actions/checkout@v4
- name: Setup pnpm
if: needs.changes.outputs.db_schema_related == 'true'
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
if: needs.changes.outputs.db_schema_related == 'true'
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
if: needs.changes.outputs.db_schema_related == 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
if: needs.changes.outputs.db_schema_related == 'true'
uses: supabase/setup-cli@v1
with:
version: latest
- name: Start local Supabase
if: needs.changes.outputs.db_schema_related == 'true'
run: pnpm run self-host:up
- name: Wait for Supabase
if: needs.changes.outputs.db_schema_related == 'true'
run: bash ./scripts/wait-for-port.sh 127.0.0.1 54321 supabase 180
- name: Apply local app schema migrations
if: needs.changes.outputs.db_schema_related == 'true'
run: pnpm --filter @repo/db db:migrate
- name: Check schema parity
if: needs.changes.outputs.db_schema_related == 'true'
run: pnpm --filter @repo/db db:schema:check
- name: Skip schema parity when DB schema is unchanged
if: needs.changes.outputs.db_schema_related != 'true'
run: |
printf 'No packages/db changes detected; skipping schema parity check.\n'
api-live-db:
name: API Live DB Smoke
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true'
steps:
- name: Checkout
if: needs.changes.outputs.api_live_db_related == 'true'
uses: actions/checkout@v4
- name: Setup pnpm
if: needs.changes.outputs.api_live_db_related == 'true'
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
if: needs.changes.outputs.api_live_db_related == 'true'
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
if: needs.changes.outputs.api_live_db_related == 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
if: needs.changes.outputs.api_live_db_related == 'true'
uses: supabase/setup-cli@v1
with:
version: latest
- name: Start local Supabase
if: needs.changes.outputs.api_live_db_related == 'true'
run: pnpm run self-host:up
- name: Wait for Supabase
if: needs.changes.outputs.api_live_db_related == 'true'
run: bash ./scripts/wait-for-port.sh 127.0.0.1 54321 supabase 180
- name: Apply local app schema migrations
if: needs.changes.outputs.api_live_db_related == 'true'
run: pnpm --filter @repo/db db:migrate
- name: Run API live DB smoke tests
if: needs.changes.outputs.api_live_db_related == 'true'
run: pnpm --filter @repo/api test:live-db
- name: Skip live DB smoke when API and DB are unchanged
if: needs.changes.outputs.api_live_db_related != 'true'
run: |
printf 'No API or DB changes detected; skipping API live DB smoke tests.\n'
mobile-component-and-jest:
name: Mobile Component And Jest
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true' && needs.changes.outputs.mobile_runtime_related == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run mobile Jest tests
run: pnpm --filter mobile test:jest
full-validation-suite:
name: Full Validation Suite
runs-on: ubuntu-latest
needs:
- changes
- format-and-lint
- typecheck
- build
- unit-and-integration
- db-schema-parity
- api-live-db
if: needs.changes.outputs.docs_only != 'true'
steps:
- name: Validation gate passed
run: |
printf 'All prerequisite validation jobs passed.\n'
mobile-e2e-build:
name: Mobile E2E Build
runs-on: ubuntu-latest
needs:
- changes
if: needs.changes.outputs.docs_only != 'true' && (needs.changes.outputs.mobile_runtime_related == 'true' || needs.changes.outputs.mobile_test_related == 'true')
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
- name: Restore generated Android project cache
uses: actions/cache@v4
with:
path: apps/mobile/android
key: mobile-android-project-${{ runner.os }}-${{ hashFiles('apps/mobile/app.config.ts', 'apps/mobile/package.json', 'apps/mobile/scripts/android-emulator.sh', 'pnpm-lock.yaml') }}
- name: Restore Android E2E APK cache
id: mobile-e2e-apk-cache
uses: actions/cache@v4
with:
path: apps/mobile/android/app/build/outputs/apk/release
key: mobile-e2e-apk-${{ runner.os }}-${{ hashFiles('apps/mobile/app.config.ts', 'apps/mobile/package.json', 'apps/mobile/scripts/android-emulator.sh', 'pnpm-lock.yaml') }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build bundled Android E2E APK
if: needs.changes.outputs.mobile_runtime_related == 'true' || steps.mobile-e2e-apk-cache.outputs.cache-hit != 'true'
run: pnpm --filter mobile android:e2e:build
- name: Upload Android E2E APK
uses: actions/upload-artifact@v4
with:
name: mobile-e2e-apk
path: apps/mobile/android/app/build/outputs/apk/release/*.apk
compression-level: 0
retention-days: 3
if-no-files-found: error
web-e2e:
name: Web E2E
runs-on: ubuntu-latest
needs:
- changes
- full-validation-suite
if: needs.changes.outputs.docs_only != 'true' && needs.changes.outputs.web_related == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Start local Supabase
run: pnpm run self-host:up
- name: Wait for Supabase
run: bash ./scripts/wait-for-port.sh 127.0.0.1 54321 supabase 180
- name: Apply local app schema migrations
run: pnpm --filter @repo/db db:migrate
- name: Export local test environment
run: bash ./scripts/ci-export-local-env.sh >> "$GITHUB_ENV"
- name: Seed E2E users
run: node ./apps/mobile/scripts/seed-e2e-users.mjs
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium
- name: Start web E2E server
run: nohup pnpm run dev:e2e:web > /tmp/gradientpeak-web-e2e.log 2>&1 &
- name: Wait for web server
run: bash ./scripts/wait-for-port.sh 127.0.0.1 3000 web-e2e 180
- name: Run Playwright
run: pnpm --filter web test:e2e
- name: Upload Playwright artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-artifacts
path: |
apps/web/playwright-report
apps/web/test-results
/tmp/gradientpeak-web-e2e.log
if-no-files-found: ignore
mobile-e2e-core:
name: Mobile E2E
runs-on: ubuntu-latest
needs:
- changes
- full-validation-suite
- mobile-component-and-jest
- mobile-e2e-build
if: needs.changes.outputs.docs_only != 'true' && (needs.changes.outputs.mobile_runtime_related == 'true' || needs.changes.outputs.mobile_test_related == 'true')
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.33.0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Start local Supabase
run: pnpm run self-host:up
- name: Wait for Supabase
run: bash ./scripts/wait-for-port.sh 127.0.0.1 54321 supabase 180
- name: Apply local app schema migrations
run: pnpm --filter @repo/db db:migrate
- name: Export local test environment
run: bash ./scripts/ci-export-local-env.sh >> "$GITHUB_ENV"
- name: Seed E2E users
run: node ./apps/mobile/scripts/seed-e2e-users.mjs
- name: Install Maestro
run: |
curl -Ls "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"
- name: Download bundled Android E2E APK
uses: actions/download-artifact@v4
with:
name: mobile-e2e-apk
path: apps/mobile/.maestro/build-artifacts
- name: Generate Maestro assets
run: pnpm --filter mobile generate:maestro
- name: Start E2E web server
run: nohup pnpm run dev:e2e:web > /tmp/gradientpeak-web-e2e.log 2>&1 &
- name: Wait for E2E web server
run: bash ./scripts/wait-for-port.sh 127.0.0.1 3000 web-e2e 180
- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Restore Android emulator snapshot cache
id: avd-cache
uses: actions/cache@v4
with:
path: |
~/.android/avd/*
~/.android/adb*
key: validate-avd-${{ runner.os }}-api30-x86_64-pixel_7
- name: Create Android emulator snapshot
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 30
arch: x86_64
profile: pixel_7
force-avd-creation: false
emulator-boot-timeout: 900
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
script: echo "Android emulator snapshot ready."
- name: Run Maestro smoke flows
uses: reactivecircus/android-emulator-runner@v2
env:
GP_MAESTRO_RUNTIME: installed
with:
api-level: 30
arch: x86_64
profile: pixel_7
force-avd-creation: false
emulator-boot-timeout: 900
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
script: |
adb install -r "$(echo "$GITHUB_WORKSPACE"/apps/mobile/.maestro/build-artifacts/*.apk)"
pnpm --filter mobile maestro:flow -- --device emulator-5554 .maestro/flows/main/auth_navigation.yaml
pnpm --filter mobile maestro:flow -- --device emulator-5554 .maestro/flows/main/tabs_smoke.yaml
- name: Upload Maestro artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: maestro-mobile-e2e
path: |
apps/mobile/.maestro/artifacts
apps/mobile/.maestro/emulator.log
/tmp/gradientpeak-web-e2e.log
if-no-files-found: ignore