Skip to content

feat(notifications): notify users of their own actions by default #2360

feat(notifications): notify users of their own actions by default

feat(notifications): notify users of their own actions by default #2360

Workflow file for this run

name: CI
on:
push:
branches:
- main
- claude/**
pull_request:
branches:
- main
- claude/**
# Cancel in-progress runs when a new run is triggered
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Setup job caches dependencies for reuse by other jobs
setup:
name: Setup Dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Cache node_modules
uses: actions/cache@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
typecheck:
name: TypeScript Type Check
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Run type checking
run: pnpm run typecheck
lint:
name: ESLint
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Run linting
run: pnpm run lint
format:
name: Prettier Format Check
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Check formatting
run: pnpm run format
yamllint:
name: YAML Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install yamllint
run: |
sudo apt-get update
sudo apt-get install -y yamllint
- name: Run yamllint
run: yamllint .github/workflows/
build:
name: Build
runs-on: ubuntu-latest
needs: [setup, typecheck, lint, format, yamllint, test-unit, test-integration]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Build application
run: |
# Load CI environment variables for build-time evaluation
set -a
source .env.ci
set +a
pnpm run build
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Run unit tests with coverage
run: |
set -a
source .env.ci
set +a
pnpm run test:coverage -- --reporter=verbose
- name: Upload coverage to Codecov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
with:
files: ./coverage/lcov.info
fail_ci_if_error: true
verbose: false
test-integration:
name: Integration Tests
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Run integration tests
run: |
set -a
source .env.ci
set +a
pnpm run test:integration -- --reporter=verbose
# ==============================================================================
# Migration Verification
#
# Validates that Drizzle migrations can apply cleanly to a fresh database.
# Uses Supabase CLI since migrations reference auth.users (Supabase-specific).
# This catches broken migrations before they reach production.
# ==============================================================================
test-migrations:
name: Verify Migrations
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Generate config.toml from template
run: cp supabase/config.toml.template supabase/config.toml
- name: Start Supabase (minimal services for migrations)
run: |
supabase start -x "studio,realtime,storage-api,edge-runtime,logflare,vector,imgproxy,supavisor,postgres-meta"
- name: Export Supabase environment
run: |
eval "$(supabase status -o env | sed 's/=/=\"/;s/$/\"/')"
echo "DATABASE_URL=${DB_URL}" >> $GITHUB_ENV
echo "DIRECT_URL=${DB_URL}" >> $GITHUB_ENV
- name: Apply migrations to fresh database
run: pnpm run db:migrate
- name: Ensure test schema is current
run: |
set -a
source .env.ci
set +a
pnpm run test:ensure-schema
test-integration-supabase:
name: Supabase Integration Tests
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs: [setup, typecheck, lint, format, yamllint, test-unit, test-integration, test-migrations]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Generate config.toml from template
run: cp supabase/config.toml.template supabase/config.toml
- name: Make Supabase integration script executable
run: chmod +x ./scripts/run-supabase-integration-tests.sh ./scripts/supabase-init-for-tests.sh
- name: Run Supabase integration tests
run: ./scripts/run-supabase-integration-tests.sh
test-e2e-smoke:
# ==============================================================================
# E2E Smoke Tests (Chromium Only)
#
# Runs smoke tests with chromium browser only for fast feedback.
# ==============================================================================
name: E2E Smoke Tests (Chromium)
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs: [setup, typecheck, lint, format, yamllint, test-unit, test-integration, test-migrations]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Cache Playwright browsers
uses: actions/cache@v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-chromium-
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps chromium
- name: Generate config.toml from template
run: cp supabase/config.toml.template supabase/config.toml
- name: Make E2E script executable
run: chmod +x ./scripts/supabase-init-for-tests.sh
- name: Initialize Supabase
run: ./scripts/supabase-init-for-tests.sh
- name: Run Smoke Tests (Chromium)
env:
MOCK_BLOB_STORAGE: "true"
PLAYWRIGHT_STDOUT: "pipe"
PLAYWRIGHT_STDERR: "pipe"
run: pnpm exec playwright test e2e/smoke --project=chromium --reporter=dot
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v6
with:
name: playwright-report-smoke-chromium
path: playwright-report/
retention-days: 7
test-e2e-smoke-mobile-chrome:
# ==============================================================================
# E2E Smoke Tests (Mobile Chrome)
#
# Runs smoke tests with Mobile Chrome browser to catch mobile-specific issues.
# ==============================================================================
name: E2E Smoke Tests (Mobile Chrome)
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs: [setup, typecheck, lint, format, yamllint, test-unit, test-integration, test-migrations]
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Cache Playwright browsers
uses: actions/cache@v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-chromium-
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps chromium
- name: Generate config.toml from template
run: cp supabase/config.toml.template supabase/config.toml
- name: Make E2E script executable
run: chmod +x ./scripts/supabase-init-for-tests.sh
- name: Initialize Supabase
run: ./scripts/supabase-init-for-tests.sh
- name: Run Smoke Tests (Mobile Chrome)
env:
MOCK_BLOB_STORAGE: "true"
PLAYWRIGHT_STDOUT: "pipe"
PLAYWRIGHT_STDERR: "pipe"
run: pnpm exec playwright test e2e/smoke --project="Mobile Chrome" --reporter=dot
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v6
with:
name: playwright-report-smoke-mobile-chrome
path: playwright-report/
retention-days: 7
test-e2e-full-chromium:
# ==============================================================================
# E2E Full Tests (Chromium)
#
# Runs full test suite with chromium browser.
# ==============================================================================
name: E2E Full Tests (Chromium)
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs: [setup, typecheck, lint, format, yamllint, test-unit, test-integration, test-migrations]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Cache Playwright browsers
uses: actions/cache@v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-chromium-
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps chromium
- name: Generate config.toml from template
run: cp supabase/config.toml.template supabase/config.toml
- name: Make E2E script executable
run: chmod +x ./scripts/supabase-init-for-tests.sh
- name: Initialize Supabase
run: ./scripts/supabase-init-for-tests.sh
- name: Run Full Tests (Chromium)
env:
MOCK_BLOB_STORAGE: "true"
PLAYWRIGHT_STDOUT: "pipe"
PLAYWRIGHT_STDERR: "pipe"
run: pnpm exec playwright test --config=playwright.config.full.ts --project=chromium --reporter=dot
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v6
with:
name: playwright-report-full-chromium
path: playwright-report/
retention-days: 7
test-e2e-full-mobile-chrome:
# ==============================================================================
# E2E Full Tests (Mobile Chrome)
#
# Runs full test suite with Mobile Chrome browser.
# ==============================================================================
name: E2E Full Tests (Mobile Chrome)
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs: [setup, typecheck, lint, format, yamllint, test-unit, test-integration, test-migrations]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Cache Playwright browsers
uses: actions/cache@v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-chromium-
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps chromium
- name: Generate config.toml from template
run: cp supabase/config.toml.template supabase/config.toml
- name: Make E2E script executable
run: chmod +x ./scripts/supabase-init-for-tests.sh
- name: Initialize Supabase
run: ./scripts/supabase-init-for-tests.sh
- name: Run Full Tests (Mobile Chrome)
env:
MOCK_BLOB_STORAGE: "true"
PLAYWRIGHT_STDOUT: "pipe"
PLAYWRIGHT_STDERR: "pipe"
run: pnpm exec playwright test --config=playwright.config.full.ts --project="Mobile Chrome" --reporter=dot
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v6
with:
name: playwright-report-full-mobile-chrome
path: playwright-report/
retention-days: 7
test-e2e-full-mobile-safari:
# ==============================================================================
# E2E Full Tests (Mobile Safari)
#
# Runs full test suite with Mobile Safari (WebKit) browser.
# ==============================================================================
name: E2E Full Tests (Mobile Safari)
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs: [setup, typecheck, lint, format, yamllint, test-unit, test-integration, test-migrations]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Cache Playwright browsers
uses: actions/cache@v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-webkit-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-webkit-
- name: Install Playwright system dependencies
run: pnpm exec playwright install-deps webkit
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install webkit
- name: Generate config.toml from template
run: cp supabase/config.toml.template supabase/config.toml
- name: Make E2E script executable
run: chmod +x ./scripts/supabase-init-for-tests.sh
- name: Initialize Supabase
run: ./scripts/supabase-init-for-tests.sh
- name: Run Full Tests (Mobile Safari)
env:
MOCK_BLOB_STORAGE: "true"
PLAYWRIGHT_STDOUT: "pipe"
PLAYWRIGHT_STDERR: "pipe"
run: pnpm exec playwright test --config=playwright.config.full.ts --project="Mobile Safari" --reporter=dot
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v6
with:
name: playwright-report-full-mobile-safari
path: playwright-report/
retention-days: 7
gitleaks:
name: Gitleaks Secret Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
pnpm-audit:
name: pnpm audit
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Restore node_modules
id: cache-restore
uses: actions/cache/restore@v5
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install dependencies (if cache miss)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
- name: Run pnpm audit
run: pnpm audit --audit-level=high