diff --git a/Justfile b/Justfile index a962c6b..ce49ce3 100644 --- a/Justfile +++ b/Justfile @@ -71,6 +71,14 @@ preview: deploy *args: bun turbo deploy "$@" +# Apply D1 migrations (rooms + auth own them). Defaults to --remote; pass `-- --local` +# for the dev db. Scope with -F, e.g. `just migrate -F rooms`. +[group('2. local dev')] +[positional-arguments] +[no-cd] +migrate *args: + bun turbo migrate "$@" + # =============================== # # GENERATOR COMMANDS # # =============================== # diff --git a/README.md b/README.md index 8cba5f0..64e111a 100644 --- a/README.md +++ b/README.md @@ -193,22 +193,16 @@ wrangler d1 create recflare ``` Then apply the schema. The `rooms` and `auth` workers own the migrations under -their `apps//migrations/` directories. Remote operations need the real id -in the config (the committed file only has the `"local"` placeholder), so splice -it in the same way the deploy does — from each owning worker, with `RECFLARE_D1` -exported: +their `apps//migrations/` directories. `just migrate` applies them to the +remote database (splicing `RECFLARE_D1` into the `"local"` placeholder the same way +`just deploy` does, so you don't edit any config): ```bash -cd apps/rooms # then repeat for apps/auth -sed -E "s/\"database_id\": *\"local\"/\"database_id\": \"$RECFLARE_D1\"/" \ - wrangler.jsonc >wrangler.generated.jsonc -wrangler d1 migrations apply recflare --remote --config wrangler.generated.jsonc -rm wrangler.generated.jsonc +just migrate # migrate every worker that owns migrations +just migrate -F rooms # or scope to one worker +just migrate -- --local # target the local dev db instead of remote ``` -For the local dev database no id is needed — it uses the `"local"` placeholder -directly: `wrangler d1 migrations apply recflare --local`. - _KV — two namespaces_ (`RECFLARE_MATCH_PRESENCE` for `match`/`auth`, `RECFLARE_PLAYER_SETTINGS` for `playersettings`): diff --git a/apps/auth/package.json b/apps/auth/package.json index 4f37f49..3fc996f 100644 --- a/apps/auth/package.json +++ b/apps/auth/package.json @@ -12,6 +12,7 @@ "deploy": "run-wrangler-deploy", "dev": "run-wrangler-dev", "fix:workers-types": "run-wrangler-types", + "migrate": "run-wrangler-migrate", "test": "run-vitest" }, "dependencies": { diff --git a/apps/rooms/package.json b/apps/rooms/package.json index c5a64f9..9f0ce09 100644 --- a/apps/rooms/package.json +++ b/apps/rooms/package.json @@ -12,6 +12,7 @@ "deploy": "run-wrangler-deploy", "dev": "run-wrangler-dev", "fix:workers-types": "run-wrangler-types", + "migrate": "run-wrangler-migrate", "test": "run-vitest" }, "dependencies": { diff --git a/packages/tools/bin/run-wrangler-migrate b/packages/tools/bin/run-wrangler-migrate new file mode 100755 index 0000000..6749729 --- /dev/null +++ b/packages/tools/bin/run-wrangler-migrate @@ -0,0 +1,64 @@ +#!/bin/sh +set -eu + +# Apply this worker's D1 migrations. Run from a worker directory (e.g. via +# `bun turbo -F rooms migrate`). Defaults to --remote; pass --local to target the +# dev SQLite db. Extra args pass through to `wrangler d1 migrations apply`. +# +# Remote/preview migrations need the real database id, but the committed +# wrangler.jsonc carries a "local" placeholder. This splices the id from +# RECFLARE_D1 (gitignored .env / CI secrets) into a generated config alongside the +# original — exactly like run-wrangler-deploy — so relative paths (migrations_dir) +# still resolve. Local migrations use the placeholder directly and need no id. + +if ! grep -q '"database_id": *"local"' wrangler.jsonc 2>/dev/null; then + echo "error: this worker has no D1 database to migrate (no \"local\" placeholder in wrangler.jsonc)" >&2 + exit 1 +fi + +# Target the database by its name from the committed config. +DB_NAME=$(grep '"database_name"' wrangler.jsonc | head -1 | + sed -E 's/.*"database_name": *"([^"]*)".*/\1/') + +# Detect a caller-supplied target flag; default to --remote when none is given. +LOCAL=0 +HAS_TARGET=0 +for arg in "$@"; do + case "$arg" in + --local) LOCAL=1 HAS_TARGET=1 ;; + --remote | --preview) HAS_TARGET=1 ;; + esac +done + +if [ "$LOCAL" -eq 1 ]; then + # Local db keys off the "local" placeholder, so the committed config is fine. + exec wrangler d1 migrations apply "$DB_NAME" "$@" +fi + +# Load RECFLARE_D1 from the gitignored root .env if not already set (mirrors +# run-wrangler-deploy's handling of RECFLARE_DOMAIN). An already-set value wins. +if [ -z "${RECFLARE_D1:-}" ]; then + ENV_FILE="$(git rev-parse --show-toplevel)/.env" + if [ -f "$ENV_FILE" ]; then + set -a + . "$ENV_FILE" + set +a + fi +fi + +DB_ID=${RECFLARE_D1:-} +if [ -z "$DB_ID" ]; then + echo "error: RECFLARE_D1 is not set — add the recflare D1 id to .env (see .env.example)" >&2 + exit 1 +fi + +# Generated alongside the original so its relative paths still resolve. Gitignored; +# removed on exit so `wrangler dev` is unaffected. +trap 'rm -f wrangler.generated.jsonc' EXIT +sed -E 's/("database_id"[[:space:]]*:[[:space:]]*")[^"]*(")/\1'"$DB_ID"'\2/' \ + wrangler.jsonc >wrangler.generated.jsonc + +# Default to --remote when the caller passed no target flag. +[ "$HAS_TARGET" -eq 1 ] || set -- "$@" --remote + +wrangler d1 migrations apply "$DB_NAME" --config wrangler.generated.jsonc "$@" diff --git a/turbo.jsonc b/turbo.jsonc index 6329ca0..d356679 100644 --- a/turbo.jsonc +++ b/turbo.jsonc @@ -41,6 +41,13 @@ "env": ["CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_TOKEN"], "outputLogs": "new-only" }, + // Apply D1 migrations. Only workers that own migrations define a `migrate` + // script, so `turbo migrate` runs just those. No build needed. + "migrate": { + "cache": false, + "env": ["CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_TOKEN"], + "outputLogs": "new-only" + }, // build:wrangler isn't used much, but can be useful for debugging "build:wrangler": { "dependsOn": ["build", "topo"],