Skip to content

ci(migrations): fail dev schema push with an actionable error on rename/drop prompt#4999

Open
TheodoreSpeaks wants to merge 1 commit into
mainfrom
fix/dev-push-interactive-prompt-guard
Open

ci(migrations): fail dev schema push with an actionable error on rename/drop prompt#4999
TheodoreSpeaks wants to merge 1 commit into
mainfrom
fix/dev-push-interactive-prompt-guard

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Problem

The dev DB migration step runs bun run db:push --force. When CI ran it against the dev DB it crashed with:

Error: Interactive prompts require a TTY terminal ... at promptNamedWithSchemasConflict ... at tablesResolver

--force only suppresses drizzle's data-loss confirmation. It does not suppress the rename-vs-drop disambiguation prompt (promptNamedWithSchemasConflict), which fires whenever a diff contains both new and missing objects at the same level — drizzle can't tell a rename from a drop+create, so it asks. In CI there's no TTY, so hanji throws before reading input (piping an answer can't help).

This happened because the dev DB drifted: migration 0231_sim_trigger_workspace_events.sql (#4941) creates sim_trigger_state and drops workspace_notification_delivery / workspace_notification_subscription in one shot. Staging/prod run db:migrate and apply it cleanly; only dev (which uses db:push, no migration journal) sees it as an ambiguous diff and prompts.

Change

CI already failed here — just opaquely. This converts the bare stack trace into an actionable failure: the dev push step captures the output, and on the specific Interactive prompts require a TTY error emits a GitHub ::error:: annotation explaining the cause and the fix (drop the stale objects on the dev DB to match schema.ts — the same DROPs the versioned migration already applied to staging/prod). Exit status is preserved either way; success path is unchanged.

No detection/auto-reconcile script — deliberately fail loud and let a human reconcile, matching how staging/prod already handle the drop via the versioned migration.

Test

Verified the capture + exit-code logic under bash -e -o pipefail: failure captures status, emits the annotation, and propagates the non-zero exit; success path falls through untouched. YAML validated.

🤖 Generated with Claude Code

…me/drop prompt

`drizzle-kit push --force` only suppresses the data-loss confirm, not the
rename-vs-drop disambiguation prompt. That prompt fires whenever a diff both
adds and drops tables/columns at once (e.g. migration 0231 created
sim_trigger_state while dropping the workspace_notification_* tables), and in
CI it crashes with a bare "Interactive prompts require a TTY" stack trace.

Catch that specific failure in the dev push step and emit a GitHub error
annotation explaining the cause and the fix (drop the stale objects on the dev
DB to match schema.ts — the same DROPs the versioned migration already applied
to staging/prod), instead of leaving an opaque trace. Exit status is preserved
either way.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jun 12, 2026 5:49pm

Request Review

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile review

@cursor

cursor Bot commented Jun 12, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Workflow-only change for the dev migration path; staging/prod db:migrate is untouched and success/failure semantics are preserved.

Overview
Dev migrations in Database Migrations no longer run db:push --force as a bare command. The step captures stdout/stderr, reprints it, and on failure checks for drizzle’s “Interactive prompts require a TTY” message (rename-vs-drop when the dev DB drifts from schema.ts).

When that specific error appears, CI emits a GitHub ::error:: annotation with title Dev schema push needs manual reconciliation, explaining that --force cannot bypass the prompt and pointing operators to align the dev DB with schema.ts (same DROPs as recent versioned migrations). Exit code is unchanged; successful pushes behave as before.

Reviewed by Cursor Bugbot for commit 2626482. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This CI-only change converts a bare drizzle-kit stack trace into an actionable GitHub annotation when db:push crashes because CI has no TTY to answer the rename-vs-drop disambiguation prompt.

  • Wraps bun run db:push --force in a subshell that captures combined stdout/stderr, echoes it, and on failure greps for the Interactive prompts require a TTY string before emitting a ::error:: annotation explaining the manual reconciliation step.
  • Exit-code semantics are fully preserved: a failing push still fails the job; the success path is untouched.

Confidence Score: 4/5

Safe to merge — the change only wraps the existing dev push command to improve error reporting; the success path is identical to before.

The bash exit-code capture pattern is correct, the annotation format is valid, and failure still propagates the original exit code. The two minor concerns — a brittle grep string that could miss the annotation on a drizzle upgrade, and loss of real-time log streaming — don't affect correctness or reliability of the workflow.

.github/workflows/migrations.yml line 79: the grep -q 'Interactive prompts require a TTY' match string is worth keeping in sync with the drizzle/hanji version in use.

Important Files Changed

Filename Overview
.github/workflows/migrations.yml Wraps bun run db:push --force in a subshell to capture output, emits a GitHub ::error:: annotation on the specific drizzle TTY-prompt crash, then exits with the original status — success path is unchanged

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[CI: environment == dev] --> B["push_output=$(bun run db:push --force 2>&1)"]
    B --> C{push_status == 0?}
    C -- yes --> D[echo output\ncontinue job ✅]
    C -- no --> E[echo output]
    E --> F{output contains\n'Interactive prompts\nrequire a TTY'?}
    F -- yes --> G["emit ::error:: annotation\n(reconciliation instructions)"]
    F -- no --> H[no annotation]
    G --> I[exit push_status ❌]
    H --> I
Loading

Reviews (1): Last reviewed commit: "ci(migrations): fail dev schema push wit..." | Re-trigger Greptile

Comment on lines +79 to +81
if printf '%s' "$push_output" | grep -q 'Interactive prompts require a TTY'; then
echo "::error title=Dev schema push needs manual reconciliation::drizzle-kit push hit an interactive rename/drop prompt that CI cannot answer. The dev DB has drifted from schema.ts: it still holds table(s)/column(s) the schema no longer declares while the schema also adds new ones, so drizzle cannot tell a rename from a drop+create. Fix: drop the stale objects on the dev DB to match schema.ts — the same DROPs the latest versioned migration already applied to staging/prod (grep packages/db/migrations for the most recent DROP TABLE / DROP COLUMN) — then re-run this workflow. --force cannot bypass this prompt."
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Brittle error-string match

The annotation is gated on grep -q 'Interactive prompts require a TTY', which is a string from hanji's internals. If drizzle-kit upgrades hanji and the message changes (e.g. to "requires a TTY terminal" — already seen in the PR description itself vs the exact string in the grep), the check silently misses, the job still fails correctly, but the helpful annotation is never emitted. The failure mode is quiet degradation of the diagnostic, not a broken workflow, but it's worth documenting the expected string or widening the pattern to 'TTY'.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +76 to +77
push_output="$(bun run db:push --force 2>&1)" && push_status=0 || push_status=$?
echo "$push_output"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Output buffering silences real-time logs

Capturing into push_output="$(…)" holds all stdout/stderr in memory and releases it only after the process exits. For a quick schema push this is fine, but if db:push hangs (e.g. waiting on a connection) the GitHub Actions log stays blank until the step times out — there's no streaming visibility. Consider adding a timeout flag (e.g. --timeout if drizzle-kit supports it) or at least a note that live output is unavailable while this step is running.

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR converts an opaque hanji TTY crash from db:push in CI into an actionable GitHub Actions annotation that explains the drift condition and the manual fix, without changing the success path.

  • The dev-environment push step now captures stdout+stderr, checks the exit code, and emits a ::error:: annotation with remediation instructions when drizzle's rename-vs-drop prompt fires (the specific failure that triggered this PR).
  • Exit status is faithfully preserved in both the failure and the success cases; staging/production migration paths are untouched.

Confidence Score: 4/5

Safe to merge — the dev-environment push now fails louder with an actionable annotation; staging/prod paths are untouched.

The change is small and well-scoped: one modified code path in the dev branch, with exit-code propagation and the success path left untouched. The only practical downside is that buffering db:push output could make a slow push appear stuck in the logs, which is a minor operational nuisance rather than a correctness issue.

No files require special attention; the single changed file is straightforward CI scripting.

Important Files Changed

Filename Overview
.github/workflows/migrations.yml Wraps db:push in output-capture + exit-status logic so the TTY-prompt crash emits an actionable GitHub annotation; success path is unchanged.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Apply database schema changes step] --> B{ENVIRONMENT == dev?}
    B -- No --> C[bun run ./scripts/migrate.ts]
    B -- Yes --> D["bun run db:push --force\n(stdout+stderr captured)"]
    D --> E{exit status == 0?}
    E -- Yes --> F[echo output\nstep succeeds]
    E -- No --> G[echo output]
    G --> H{"output contains\n'Interactive prompts\nrequire a TTY'?"}
    H -- Yes --> I["emit ::error:: annotation\n(actionable fix message)"]
    H -- No --> J[no annotation]
    I --> K[exit with original status]
    J --> K
    C --> L[step succeeds or fails normally]
Loading

Reviews (2): Last reviewed commit: "ci(migrations): fail dev schema push wit..." | Re-trigger Greptile

Comment on lines +76 to +77
push_output="$(bun run db:push --force 2>&1)" && push_status=0 || push_status=$?
echo "$push_output"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Output buffering hides progress for long-running push

Because db:push output is captured in full before echo "$push_output" prints it, the CI log shows nothing until the command finishes. For a quick push this is fine, but against a large schema the step can appear hung for minutes with no feedback. Consider using a tee approach (e.g., a temp file) to stream output in real time while still being able to inspect it after the fact.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Base automatically changed from staging to main June 13, 2026 02:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant