Skip to content

Migrations Preview #498

Migrations Preview

Migrations Preview #498

name: Migrations Preview
on:
workflow_run:
workflows:
- Deploy Preview
types:
- completed
workflow_dispatch:
permissions: {}
jobs:
migrations-preview:
name: Migrations Preview
runs-on: ubuntu-latest
environment: preview
if: github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
permissions:
contents: read
steps:
- name: Checkout repository (trusted base)
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: main
- name: Determine deployed SHA
id: context
run: |
set -euo pipefail
if [ "${GITHUB_EVENT_NAME}" = 'workflow_dispatch' ]; then
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
echo 'trigger_event=workflow_dispatch' >> "$GITHUB_OUTPUT"
echo 'head_branch=main' >> "$GITHUB_OUTPUT"
exit 0
fi
echo "sha=${{ github.event.workflow_run.head_sha }}" >> "$GITHUB_OUTPUT"
echo "trigger_event=${{ github.event.workflow_run.event }}" >> "$GITHUB_OUTPUT"
echo "head_branch=${{ github.event.workflow_run.head_branch }}" >> "$GITHUB_OUTPUT"
echo "head_repo_full_name=${{ github.event.workflow_run.head_repository.full_name }}" >> "$GITHUB_OUTPUT"
echo "is_fork=${{ github.event.workflow_run.head_repository.fork }}" >> "$GITHUB_OUTPUT"
shell: bash
- name: Gate migrations (skip forks/hotfix/unexpected triggers)
id: gate
run: |
set -euo pipefail
# For workflow_dispatch we allow manual runs (environment protections still apply).
if [ "${GITHUB_EVENT_NAME}" = 'workflow_dispatch' ]; then
echo 'should_migrate=true' >> "$GITHUB_OUTPUT"
exit 0
fi
# This workflow is intended to run after a successful preview deployment.
if [ '${{ steps.context.outputs.trigger_event }}' != 'pull_request' ]; then
echo 'should_migrate=false' >> "$GITHUB_OUTPUT"
exit 0
fi
# Skip fork PRs (Deploy Preview is skipped for forks, but the workflow_run
# event can still conclude "success" when jobs are skipped).
if [ '${{ steps.context.outputs.is_fork }}' = 'true' ]; then
echo 'should_migrate=false' >> "$GITHUB_OUTPUT"
exit 0
fi
if [ '${{ steps.context.outputs.head_repo_full_name }}' != '${{ github.repository }}' ]; then
echo 'should_migrate=false' >> "$GITHUB_OUTPUT"
exit 0
fi
case '${{ steps.context.outputs.head_branch }}' in
hotfix/*)
echo 'should_migrate=false' >> "$GITHUB_OUTPUT"
exit 0
;;
esac
echo 'should_migrate=true' >> "$GITHUB_OUTPUT"
- name: Checkout deployed SHA (validated)
# CodeQL can flag privileged workflows which checkout untrusted refs via actions/checkout.
# We checkout main first (trusted) to load local actions/tooling, then fetch+detach the
# deployed SHA. This SHA comes from the upstream Deploy workflow context.
if: steps.gate.outputs.should_migrate == 'true'
run: |
set -euo pipefail
sha='${{ steps.context.outputs.sha }}'
git fetch origin "$sha" --depth=1
git checkout --detach "$sha"
- name: Setup Node.js
if: steps.gate.outputs.should_migrate == 'true'
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24.x"
cache: "npm"
- name: Install dependencies
if: steps.gate.outputs.should_migrate == 'true'
run: npm ci
- name: Verify database schema is up to date
id: verify
if: steps.gate.outputs.should_migrate == 'true'
env:
ASTRO_DB_REMOTE_URL: ${{ secrets.ASTRO_DB_REMOTE_URL }}
ASTRO_DB_APP_TOKEN: ${{ secrets.ASTRO_DB_APP_TOKEN }}
run: |
set -uo pipefail
set +e
output=$(npx astro db verify 2>&1)
exit_code=$?
set -e
printf '%s\n' "$output"
if [ "$exit_code" -ne 0 ]; then
exit "$exit_code"
fi
if printf '%s' "$output" | grep -Fq 'Database schema is up to date.'; then
echo 'needs_push=false' >> "$GITHUB_OUTPUT"
exit 0
fi
if printf '%s' "$output" | grep -Fq 'Database schema is out of date.'; then
echo 'needs_push=true' >> "$GITHUB_OUTPUT"
exit 0
fi
echo 'Unexpected output from astro db verify' >&2
exit 1
- name: Push database migrations (preview)
if: steps.gate.outputs.should_migrate == 'true' &&
steps.verify.outputs.needs_push == 'true'
env:
ASTRO_DB_REMOTE_URL: ${{ secrets.ASTRO_DB_REMOTE_URL }}
ASTRO_DB_APP_TOKEN: ${{ secrets.ASTRO_DB_APP_TOKEN }}
run: npx astro db push --remote