Database Migrations #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Database Migrations | |
| on: | |
| workflow_call: | |
| inputs: | |
| environment: | |
| description: Target environment (production, staging, or dev) | |
| required: true | |
| type: string | |
| workflow_dispatch: | |
| inputs: | |
| environment: | |
| description: Target environment | |
| required: true | |
| type: choice | |
| options: | |
| - production | |
| - staging | |
| - dev | |
| permissions: | |
| contents: read | |
| jobs: | |
| migrate: | |
| name: Apply Database Migrations | |
| runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }} | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.3.14 | |
| - name: Cache Bun dependencies | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ~/.bun/install/cache | |
| node_modules | |
| **/node_modules | |
| key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-bun- | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile --ignore-scripts | |
| # The expression maps the explicit environment input to exactly one repo | |
| # secret, so the job never holds another environment's database URL. An | |
| # unknown environment resolves to empty and the guard below fails the job. | |
| # MIGRATION_DATABASE_URL is the optional direct (non-pooled) DSN preferred | |
| # by migrate.ts; when the secret is unset it resolves to empty and the | |
| # script falls back to DATABASE_URL. | |
| - name: Apply database schema changes | |
| working-directory: ./packages/db | |
| env: | |
| DATABASE_URL: ${{ inputs.environment == 'production' && secrets.DATABASE_URL || inputs.environment == 'staging' && secrets.STAGING_DATABASE_URL || inputs.environment == 'dev' && secrets.DEV_DATABASE_URL || '' }} | |
| MIGRATION_DATABASE_URL: ${{ inputs.environment == 'production' && secrets.MIGRATION_DATABASE_URL || inputs.environment == 'staging' && secrets.STAGING_MIGRATION_DATABASE_URL || '' }} | |
| ENVIRONMENT: ${{ inputs.environment }} | |
| run: | | |
| if [ -z "$DATABASE_URL" ]; then | |
| echo "ERROR: no database URL secret resolved for environment '${ENVIRONMENT}'" >&2 | |
| exit 1 | |
| fi | |
| if [ "${ENVIRONMENT}" = "dev" ]; then | |
| echo "Dev environment — pushing schema directly (db:push)" | |
| # drizzle-kit push needs a TTY to resolve ambiguous renames (--force only | |
| # covers data-loss). In CI it throws "Interactive prompts require a TTY | |
| # terminal" but still exits 0, so the job goes green without applying the | |
| # change. tee keeps the output live in the log; we then fail on drizzle's | |
| # own TTY error. A genuine non-zero exit already fails via `set -e`. | |
| bun run db:push --force < /dev/null 2>&1 | tee /tmp/db-push.log | |
| if grep -q "Interactive prompts require a TTY terminal" /tmp/db-push.log; then | |
| echo "ERROR: db:push needs an interactive rename decision; land it as a versioned migration instead of relying on push." >&2 | |
| exit 1 | |
| fi | |
| bun run ./scripts/apply-dev-workspace-file-size-cutover.ts | |
| else | |
| echo "Applying versioned migrations (db:migrate)" | |
| bun run ./scripts/migrate.ts | |
| fi |