Skip to content

Commit 845f1df

Browse files
Document Netlify deployment flow
Record the locked auto-publishing invariant and explain why GitHub Actions publishes Netlify-built production deploys.
1 parent 8db76f7 commit 845f1df

3 files changed

Lines changed: 68 additions & 0 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ Install Playwright browsers only if you plan to run browser-based tests locally.
1616

1717
npm start
1818

19+
## Deployment
20+
21+
Netlify builds deploy previews, branch deploys, and production deploys.
22+
Production auto publishing is locked in Netlify; GitHub Actions publishes the
23+
matching production deploy after CI passes. See [Deployment](docs/DEPLOYMENT.md)
24+
for the full production flow.
25+
1926
### Tests
2027

2128
npm test

docs/DEPLOYMENT.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Deployment
2+
3+
This site intentionally separates CI from production publishing.
4+
5+
Netlify owns the builds. GitHub Actions owns the production publishing gate.
6+
Auto publishing must stay locked in Netlify so production deploys can be built
7+
without going live before CI passes.
8+
9+
## Deploy Flow
10+
11+
- Pull requests get Netlify Deploy Previews through Netlify's Git integration.
12+
- Non-production branches get Netlify branch deploys, depending on the site's
13+
branch deploy settings in Netlify.
14+
- Pushes to `master` create Netlify production deploys, but Netlify does not
15+
publish them automatically while auto publishing is locked.
16+
- After GitHub Actions checks pass on `master`, the production deploy job finds
17+
the Netlify production deploy for the same commit SHA and publishes that
18+
deploy.
19+
20+
## Production Invariants
21+
22+
- Keep Netlify builds active.
23+
- Keep Netlify auto publishing locked.
24+
- Do not replace the GitHub Actions publish step with an artifact upload unless
25+
production should stop exercising Netlify's build environment.
26+
- Do not publish a Netlify deploy unless its commit SHA matches the GitHub
27+
Actions run that passed CI.
28+
29+
## Troubleshooting
30+
31+
If production does not publish after CI passes:
32+
33+
- Check the GitHub Actions production deploy job logs.
34+
- Confirm `NETLIFY_AUTH_TOKEN` and `NETLIFY_SITE_ID` are available to GitHub
35+
Actions.
36+
- Confirm Netlify has a production deploy for the same commit SHA.
37+
- Confirm the matching Netlify deploy reached the `ready` state.
38+
- Confirm Netlify auto publishing is still locked; the workflow publishes one
39+
matching deploy and does not unlock future automatic publishing.

src/scripts/publish-netlify-production-deploy.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
#!/usr/bin/env -S npx tsx
22

3+
/**
4+
* Publish the Netlify-built production deploy that matches the current GitHub
5+
* Actions commit. Netlify owns the build because production should exercise the
6+
* same platform path as deploy previews and branch deploys; GitHub Actions owns
7+
* the publish gate so production only changes after CI passes.
8+
*/
9+
310
import { pathToFileURL } from "node:url"
411

512
type Fetch = typeof fetch
@@ -52,6 +59,11 @@ const pendingStates = new Set([
5259

5360
const terminalFailureStates = new Set(["error", "rejected"])
5461

62+
/**
63+
* Poll Netlify for the production deploy that matches CI's commit, then publish
64+
* it once it is ready. This keeps the workflow from publishing an older or
65+
* unrelated deploy while Netlify auto publishing is locked.
66+
*/
5567
export async function publishNetlifyProductionDeploy(
5668
options: PublishOptions,
5769
dependencies: Partial<Dependencies> = {},
@@ -102,6 +114,11 @@ export async function publishNetlifyProductionDeploy(
102114
)
103115
}
104116

117+
/**
118+
* Select the Netlify production deploy for the exact branch and commit. The
119+
* explicit match is necessary because Netlify may list deploys from other
120+
* branches, contexts, or nearby commits while CI is waiting.
121+
*/
105122
export function findMatchingDeploy(
106123
deploys: NetlifyDeploy[],
107124
options: Pick<PublishOptions, "branch" | "commitRef">,
@@ -205,6 +222,11 @@ function readPositiveIntegerEnv(name: string, fallback: number): number {
205222
return parsed
206223
}
207224

225+
/**
226+
* Read the GitHub Actions and Netlify settings needed by the publish job.
227+
* Keeping this at the CLI boundary lets tests exercise the deploy logic without
228+
* depending on process environment state.
229+
*/
208230
export function readOptionsFromEnv(): PublishOptions {
209231
return {
210232
authToken: readRequiredEnv("NETLIFY_AUTH_TOKEN"),

0 commit comments

Comments
 (0)