-
Notifications
You must be signed in to change notification settings - Fork 4
116 lines (105 loc) · 4.2 KB
/
Copy pathcd.yml
File metadata and controls
116 lines (105 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
name: CD
# Deploys flows.2plot.dev, then checks the live site.
#
# The deploy step POSTs to a Render deploy hook held in the
# RENDER_DEPLOY_HOOK_URL secret. Without that secret the step is skipped and
# the workflow goes straight to verification — which is the right behaviour
# here, because render.yaml sets `autoDeploy: true` and Render is already
# deploying from GitHub on its own. The hook only makes the timing explicit so
# the wait loop below knows what it is waiting for.
on:
push:
branches: [main]
workflow_dispatch:
inputs:
target_url:
description: Site to verify (skips the deploy when set to another host)
required: false
type: string
permissions:
contents: read
concurrency:
group: cd-production
cancel-in-progress: false
env:
PIP_DISABLE_PIP_VERSION_CHECK: "1"
SITE_URL: ${{ inputs.target_url || 'https://flows.2plot.dev' }}
jobs:
test:
name: ci
uses: ./.github/workflows/ci.yml
deploy:
name: deploy to render
needs: [test]
runs-on: ubuntu-latest
# Long enough for the wait loop below (a 120s settle plus up to 40 × 15s)
# and no longer. Without it the job inherits GitHub's six-hour default,
# which is how a platform that never comes back healthy holds the
# `cd-production` concurrency group all day.
timeout-minutes: 20
environment:
name: production
url: https://flows.2plot.dev
outputs:
deployed: ${{ steps.hook.outputs.deployed }}
steps:
- name: Trigger the Render deploy hook
id: hook
env:
HOOK: ${{ secrets.RENDER_DEPLOY_HOOK_URL }}
run: |
if [ -z "$HOOK" ]; then
echo "::notice::RENDER_DEPLOY_HOOK_URL is not set. Skipping the deploy trigger and verifying whatever is currently live."
echo "deployed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
curl -fsS -X POST "$HOOK" > /dev/null
echo "deployed=true" >> "$GITHUB_OUTPUT"
- name: Wait for the new build to serve traffic
if: steps.hook.outputs.deployed == 'true'
run: |
# Render swaps instances rather than restarting in place, so the old
# build answers /healthz throughout. Waiting for a 200 proves
# nothing; give the build time, then require sustained health.
sleep 120
ok=0
for _ in $(seq 1 40); do
if curl -fsS "$SITE_URL/healthz" > /dev/null; then
ok=$((ok + 1))
[ "$ok" -ge 5 ] && break
else
ok=0
fi
sleep 15
done
if [ "$ok" -lt 5 ]; then
echo "::error::$SITE_URL never became reliably healthy"
exit 1
fi
verify:
name: verify the live site
needs: [deploy]
if: always() && needs.deploy.result != 'cancelled'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
# The network battery first: it is the same script, with the same check
# names, that CI ran against the container this deploy shipped. A name
# that passed in CI and fails here isolates the fault to the deploy.
- name: Network smoke battery
run: python scripts/network_smoke.py --base-url "$SITE_URL"
# Then the satellite-specific checks the battery does not make: every
# canonical, every crawler body, the social card's real pixels, and
# every peer llms.txt in the directory actually resolving. Peer checks
# WARN; own-host checks FAIL — a hub outage must never block this
# satellite's deploy, and this satellite's regressions always must.
- name: Smoke-test the deployment
run: python scripts/smoke_live.py "$SITE_URL"
- name: Report
if: failure()
run: |
echo "::error::Live verification failed for $SITE_URL. Every failure these check for is silent in production: a site identity that fell back to a framework default, a stale dash-improve-my-llms artifact, a canonical on the wrong host, a page serving the JavaScript stub, a blank or reshaped social card, a missing network directory, and dead peer llms.txt links."