fix(deploy): stop docker compose exec -T from draining the heredoc
Symptom observed twice (migrations 012 and 013): deploy-erosi.sh ran the migration loop's first iteration (the `CREATE TABLE IF NOT EXISTS _applied_migrations` step) then silently skipped every file in supabase/migrations/*.sql without printing a single skip/apply line. Had to `psql -f <new-migration>` by hand on ambrosio after every deploy. Root cause: the deploy uses `ssh host bash -s << 'REMOTE' ... REMOTE` so the outer bash on the remote reads its own script from stdin. Any `docker compose exec -T db psql ...` inside that script — particularly inside a command substitution like `already=$(docker compose exec -T ...)` — inherits that stdin and consumes it, eating the rest of the heredoc. Fix: pass `</dev/null` (or the migration file for the actual `apply` step) to every `docker compose exec -T` call so docker gets an empty / file-scoped stdin instead of the parent's heredoc. Verified on ambrosio: deploy now prints all 13 `skip ... (applied)` lines as expected, and will apply new migrations going forward without manual intervention. - CLAUDE.md: gotcha #20 documenting the pattern; applies to any heredoc-delivered remote script using `docker compose exec -T` or `kubectl exec`.
This commit is contained in:
@@ -116,13 +116,21 @@ for i in $(seq 1 60); do
|
||||
done
|
||||
|
||||
echo "--- Applying migrations"
|
||||
# Every `docker compose exec -T` call below pipes in `</dev/null` (or the
|
||||
# migration file for the apply step). This matters because the outer bash
|
||||
# is reading its own script from stdin (`ssh ... bash -s << REMOTE`); a
|
||||
# `docker compose exec -T` without its own stdin source drains the heredoc,
|
||||
# silently eating the remainder of the script — observed as "first iteration
|
||||
# runs, every subsequent migration vanishes from the log".
|
||||
docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
|
||||
psql -U postgres -d postgres -c "CREATE TABLE IF NOT EXISTS public._applied_migrations (filename TEXT PRIMARY KEY, applied_at TIMESTAMPTZ DEFAULT now());"
|
||||
psql -U postgres -d postgres </dev/null \
|
||||
-c "CREATE TABLE IF NOT EXISTS public._applied_migrations (filename TEXT PRIMARY KEY, applied_at TIMESTAMPTZ DEFAULT now());"
|
||||
|
||||
for f in supabase/migrations/*.sql; do
|
||||
fn=$(basename "$f")
|
||||
already=$(docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
|
||||
psql -U postgres -d postgres -tAq -c "SELECT count(*) FROM public._applied_migrations WHERE filename='$fn'")
|
||||
psql -U postgres -d postgres -tAq </dev/null \
|
||||
-c "SELECT count(*) FROM public._applied_migrations WHERE filename='$fn'")
|
||||
if [ "${already:-0}" -gt 0 ]; then
|
||||
echo " skip $fn (applied)"
|
||||
continue
|
||||
@@ -131,7 +139,8 @@ for f in supabase/migrations/*.sql; do
|
||||
if docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
|
||||
psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q < "$f"; then
|
||||
docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
|
||||
psql -U postgres -d postgres -c "INSERT INTO public._applied_migrations (filename) VALUES ('$fn') ON CONFLICT DO NOTHING;"
|
||||
psql -U postgres -d postgres </dev/null \
|
||||
-c "INSERT INTO public._applied_migrations (filename) VALUES ('$fn') ON CONFLICT DO NOTHING;"
|
||||
echo "ok"
|
||||
else
|
||||
echo "FAIL"; exit 1
|
||||
|
||||
Reference in New Issue
Block a user