Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 15 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# The only path to production that applies migrations - and once vercel.json
# lands (see below), the only one git can trigger at all.
# The only path to production that applies migrations, and the only one git can
# trigger at all - vercel.json disables Vercel's git trigger for main.
#
# Migrations used to run inside the Vercel build, in a script deleted with this
# change. Ordering was correct there - Vercel promotes only after a successful
Expand All @@ -11,14 +11,14 @@
# failed step ends the job, the deploy step simply never runs if it fails.
# Vercel keeps serving the previous deployment, which is the safe direction.
#
# A vercel.json disabling Vercel's git trigger for main is NOT in the repo yet.
# Until it is, Vercel also deploys main off the same push, in parallel with this
# workflow, and the two race - the failure mode in issue #6, made intermittent.
# That is deliberate and temporary: it leaves the git-triggered deploy as a
# fallback while `vercel deploy --prod` from this workflow is still unproven, so
# a first release that cannot deploy does not strand the project with no way to
# ship. It must be added promptly, and no schema-changing merge should happen
# before it is.
# vercel.json is load-bearing, not cosmetic. Without it Vercel deploys main off
# the same push, in parallel with this workflow, and the two race - the failure
# mode in issue #6, made intermittent. Deleting it silently reopens that race,
# and nothing in CI would catch it.
#
# It is also what makes this workflow the only way to deploy: if the deploy step
# below stops working, there is no git-triggered fallback. Revert vercel.json to
# get one back.
name: Release

on:
Expand Down Expand Up @@ -133,13 +133,11 @@ jobs:
echo "A migration that failed part-way is recorded in"
echo "_prisma_migrations with finished_at NULL, and every later"
echo "'migrate deploy' aborts with P3009 until that is resolved -"
echo "including releases that touch no schema at all. Once"
echo "vercel.json lands and this is the only deploy path git can"
echo "trigger, one bad migration freezes every deploy. Until then it"
echo "is the worse way round: migrations stall here while Vercel keeps"
echo "deploying main off the same push, so code ships without them -"
echo "issue #6 exactly. Either way, clear this before the next merge."
echo "A cancelled or timed-out run mid-migration leaves the same state."
echo "including releases that touch no schema at all. Since this is"
echo "the only deploy path git can trigger, one bad migration freezes"
echo "every deploy until it is cleared - so clear it before the next"
echo "merge. A cancelled or timed-out run mid-migration leaves the"
echo "same state."
echo
echo "So check whether the DDL actually landed in the database, then"
echo "tell Prisma which of the two happened:"
Expand Down
48 changes: 21 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,8 @@ is why the workflow's failure output points at `gh run list
### Deploying schema changes

`.github/workflows/release.yml` is the only path to production that applies
migrations, and once `vercel.json` lands (below) the only path to production that
git can trigger. It starts when CI completes successfully on `main` — chained
migrations, and the only path to production that git can trigger. It starts when
CI completes successfully on `main` — chained
off CI's completion rather than off the merge push, so a release cannot begin
until the migration gate, tests, and lint are green on that exact commit, which
it then checks out by SHA. It runs `prisma migrate deploy` first, and only if that
Expand All @@ -323,20 +323,18 @@ like a build failure, and every retried or concurrent build re-ran it.
`concurrency: release` now runs one release at a time, so migrations cannot
interleave.

**`vercel.json` is not in the repo yet.** When it lands it will disable Vercel's
git trigger for `main`, which is what stops Vercel deploying off the same push in
parallel with this workflow. Until then a merge to `main` produces *both* a
Vercel git deploy and this workflow's deploy, and the two race — harmless for a
release with nothing pending, a real race for any release that has a migration.
That is deliberate and temporary: whether `vercel deploy --prod` still works with
the git trigger disabled takes one real production deploy to find out, and
holding `vercel.json` back leaves the git deploy as a fallback if it does not, so
a broken deploy step cannot strand the project with no way to ship at all. It
follows in a one-file pull request as soon as the first release has proven the
CLI path, and no schema-changing merge should happen before it is in. Preview
deployments for other branches are unaffected either way.

Even with `vercel.json` in place, only *git-triggered* deploys are disabled. Each
**`vercel.json` is load-bearing.** It disables Vercel's git trigger for `main`,
which is what stops Vercel deploying off the same push in parallel with this
workflow. Without it, a merge produces *both* a Vercel git deploy and this
workflow's deploy with nothing ordering them — harmless for a release with
nothing pending, a real race for any release carrying a migration, which is
issue #6 made intermittent. Deleting the file silently reopens that race and no
check would catch it. Preview deployments for other branches are unaffected.

The cost of that is no git-triggered fallback: if the deploy step breaks, there
is no other way to ship until it is fixed or `vercel.json` is reverted.

`vercel.json` covers only *git-triggered* deploys. Each
of these still ships code whose migrations were never applied, and the daily
drift check cannot detect it — that check compares production's database to
`main`'s schema, not to whatever code is deployed. So don't:
Expand Down Expand Up @@ -376,13 +374,10 @@ gh workflow run release.yml
Fixing the migration and merging again is not enough on its own. A migration
that failed part-way is recorded in `_prisma_migrations` with `finished_at` NULL,
and **every later `prisma migrate deploy` aborts with `P3009`** until that record
is resolved — including releases that touch no schema at all. Once `vercel.json`
lands and this is the only deploy path git can trigger, one bad migration freezes
every deploy until it is cleared. Until then it is the worse way round: the
migration stalls here while Vercel keeps deploying `main` off the same push, so
code ships without its migrations — issue #6 exactly. Either way, clear the
`P3009` before the next merge. A release cancelled or timed out mid-migration
leaves the same state.
is resolved — including releases that touch no schema at all. Since this is the
only deploy path git can trigger, one bad migration freezes every deploy until it
is cleared, so clear the `P3009` before the next merge. A release cancelled or
timed out mid-migration leaves the same state.

So look at the database, decide whether the failed migration's DDL actually
landed, and tell Prisma which of the two happened:
Expand Down Expand Up @@ -506,10 +501,9 @@ Step 4 is the last deploy you trigger from the Vercel side. After that a release
is `.github/workflows/release.yml`: merge to `main`, CI passes, and the workflow
applies migrations and then deploys — or `gh workflow run release.yml` to release
by hand. Watch that workflow rather than the Vercel dashboard, because it is the
thing that applies migrations. Vercel does still deploy `main` off its own git
trigger for now, and will stop once `vercel.json` lands; see [Deploying schema
changes](#deploying-schema-changes) for why it is not in the repo yet and what
races until it is.
thing that applies migrations. `vercel.json` disables Vercel's own git trigger for
`main`, so a push no longer deploys on its own — see [Deploying schema
changes](#deploying-schema-changes).

`DATABASE_URL` is needed by the running app, not by the Vercel build — `next
build` never touches the database. It is needed separately by GitHub Actions, in
Expand Down
7 changes: 7 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"git": {
"deploymentEnabled": {
"main": false
}
}
}