Merge main into feat/chart-engine

Resolves main.py: the branch's application supersedes the placeholder, and
/api/version + /api/health now live in app/api/meta.py so bin/wait-deploy
keeps working.
This commit is contained in:
Chris Amow 2026-08-10 04:43:51 +00:00
commit 1f1544bab1
2 changed files with 65 additions and 3 deletions

View file

@ -57,17 +57,36 @@ daily MAs (score `36`) and should be revisited as more varied tapes are recorded
| `static/` | `index.html`, `app.js`, `style.css` — Vue 3 loaded from unpkg | | `static/` | `index.html`, `app.js`, `style.css` — Vue 3 loaded from unpkg |
| `requirements.txt` | Python deps | | `requirements.txt` | Python deps |
| `Procfile` | Start command; **nixpacks needs this** or the deploy has nothing to run | | `Procfile` | Start command; **nixpacks needs this** or the deploy has nothing to run |
| `bin/wait-deploy` | Blocks until the live site serves your latest commit |
| `Dockerfile.dev`, `docker-compose.yml` | Local dev only — production does not use them | | `Dockerfile.dev`, `docker-compose.yml` | Local dev only — production does not use them |
## Deployment ## Deployment
Push to `main` → Forgejo webhook → Coolify rebuilds with nixpacks → live in Push to `main` → Forgejo webhook → Coolify rebuilds with nixpacks → live.
roughly 25 seconds. Rebuild time depends on whether Docker's build cache is warm: measured at
**~20s warm** (you pushed recently) and **~90s cold** (the cache goes stale
after an idle hour or so, which is the usual case). Nothing changes on the site
until the new container swaps in at the very end, so the old version keeps
serving for the whole build.
To know when your commit is actually live, rather than guessing:
```bash ```bash
git push git push && bin/wait-deploy
``` ```
It polls `/api/version` (which returns the `SOURCE_COMMIT` Coolify bakes into
the container) until it matches your local `HEAD`, then exits. Runs from any
machine — no Coolify token, no SSH tunnel. Check by hand any time with:
```bash
curl -s https://chart.amow.com/api/version
```
One more trap worth naming: if your change only touches an `/api` endpoint, the
HTML is byte-identical and a browser refresh looks like nothing happened even
after a successful deploy. Verify the endpoint, not the page.
Two things to know before changing the deploy config: Two things to know before changing the deploy config:
- The Coolify domain is registered as `https://chart.amow.com:8000`. The port - The Coolify domain is registered as `https://chart.amow.com:8000`. The port

43
bin/wait-deploy Executable file
View file

@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Block until the deployed site is serving the commit at local HEAD.
#
# git push && bin/wait-deploy
#
# Works from any machine — it only reads the public /api/version endpoint, so
# no Coolify token and no SSH tunnel are needed.
set -uo pipefail
URL=${URL:-https://chart.amow.com}
TIMEOUT=${TIMEOUT:-300}
want=$(git rev-parse HEAD) || exit 1
short=${want:0:8}
echo "waiting for $URL to serve $short (timeout ${TIMEOUT}s)"
start=$(date +%s)
last=""
while :; do
now=$(date +%s)
elapsed=$(( now - start ))
if [ "$elapsed" -ge "$TIMEOUT" ]; then
echo "TIMEOUT after ${elapsed}s — still serving ${last:-unknown}"
echo "check the build log: https://chart.amow.com is fine but Coolify may have failed"
exit 1
fi
# 502 during the rolling container swap is normal; keep polling.
got=$(curl -fsS -m 5 "$URL/api/version" 2>/dev/null \
| sed -n 's/.*"commit"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
if [ "$got" = "$want" ]; then
echo "deployed ${short} after ${elapsed}s"
exit 0
fi
if [ "$got" != "$last" ]; then
echo " ${elapsed}s: serving ${got:-unreachable}"
last="$got"
fi
sleep 3
done