ci: gate the API deploy on what the API is running, not on the last push
The site is currently serving a frontend that asks for `window=3600` from an API that only knows `six_hours`, and every step behaved as designed: run 51ef367d5rust + web BUILD FAILED — nothing deployed run 522594190web only web deployed, deploy-api skipped run 5349f50bddocs only nothing deployed Run 52 diffed against `github.event.before`, which is run 51's commit — a commit whose Rust half never shipped. It correctly saw only `web/src/lib/routes.ts` and correctly skipped the API. The frontend went out alone. The gate was asking the wrong question. "What changed since the previous push" is only the same as "what changed since what is deployed" while every push deploys, and a failed run breaks that quietly — the workflow's own comment warns about "a binary on bob that does not match this commit, which nothing would report", and this is that case arriving by a route the path list cannot see. So ask the API. `/v1/healthz` now carries the commit it was built from, stamped via `GIT_SHA` at build time, and the gate diffs from there. `build.rs` exists only to make cargo notice the value changed, since `option_env!` is read at compile time and a warm cache would otherwise keep a stale stamp. Best effort throughout: an unreachable API, a binary too old to carry a stamp, or a commit this clone does not have all fall back to `github.event.before`, which is exactly today's behaviour. The gate only ever widens — a false positive costs a slow deploy, and that trade is already written down beside it. This commit touches `.gitea/` and `crates/`, so it deploys the API and unbreaks the site as it lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jp6a8EDar9ueEhAxzep4V5
This commit is contained in:
@@ -91,6 +91,29 @@ jobs:
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Prefer the commit the API is *actually running* over the previous
|
||||
# push. They are usually the same and the difference only shows up
|
||||
# when it matters: if a run fails, its changes never ship, and the
|
||||
# next push diffs against a commit that was never deployed. That is
|
||||
# how a frontend asking for `window=3600` came to be served by an API
|
||||
# that only knew `six_hours` — the run that would have taught it
|
||||
# failed, and the next push was frontend-only, so nothing rebuilt the
|
||||
# API and nothing said so.
|
||||
#
|
||||
# Best effort: an unreachable API, an old binary with no stamp, or a
|
||||
# commit this clone does not have all fall back to `event.before`,
|
||||
# which is no worse than before. The gate only ever widens.
|
||||
live=$(curl -sS --max-time 10 "http://${API_HOST}:${API_PORT}/v1/healthz" 2>/dev/null \
|
||||
| python3 -c 'import sys,json; print(json.load(sys.stdin).get("commit") or "")' 2>/dev/null || true)
|
||||
if [ -n "$live" ] && git cat-file -e "${live}^{commit}" 2>/dev/null; then
|
||||
if [ "$live" != "$base" ]; then
|
||||
echo "diffing against the running API at ${live}, not the previous push ${base}"
|
||||
fi
|
||||
base="$live"
|
||||
else
|
||||
echo "the running API did not name a commit we have; falling back to ${base}"
|
||||
fi
|
||||
|
||||
changed=$(git diff --name-only "$base" "${{ github.sha }}")
|
||||
echo "changed since ${base}:"
|
||||
echo "$changed" | sed 's/^/ /'
|
||||
@@ -127,6 +150,9 @@ jobs:
|
||||
# simpler when the runner matches the target fleet — it does not here:
|
||||
# `runner-rust` is Fedora 44 and the targets are Fedora 43, so a
|
||||
# glibc-linked binary built here would not load there.
|
||||
# Stamped so the API can answer "which commit am I?" — see the
|
||||
# deploy gate above, which asks exactly that.
|
||||
GIT_SHA="${{ github.sha }}" \
|
||||
cargo build --release --target x86_64-unknown-linux-musl \
|
||||
-p blackbeard-api -p blackbeard-cli
|
||||
file target/x86_64-unknown-linux-musl/release/blackbeard-api
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//! Stamp the commit into the binary, so the deploy gate can ask what is running.
|
||||
//!
|
||||
//! `option_env!("GIT_SHA")` is read at compile time, and cargo has no way to
|
||||
//! know that value changed unless it is told — without this, a rebuild in a
|
||||
//! warm cache would keep the previous commit's stamp and the gate would trust
|
||||
//! a stale answer.
|
||||
fn main() {
|
||||
println!("cargo::rerun-if-env-changed=GIT_SHA");
|
||||
}
|
||||
@@ -106,6 +106,14 @@ struct HealthResponse {
|
||||
/// alongside, for a human to read.
|
||||
healthy: bool,
|
||||
version: &'static str,
|
||||
/// The commit this binary was built from, or `null` for a local build.
|
||||
///
|
||||
/// The deploy gate reads it. Without it, "is the API on bob this commit?"
|
||||
/// could only be guessed from the previous push — and when a run fails, the
|
||||
/// next push diffs against a commit that never shipped and concludes
|
||||
/// nothing needs deploying. That is how a frontend expecting `window=3600`
|
||||
/// came to be served by an API that only knew `six_hours`.
|
||||
commit: Option<&'static str>,
|
||||
uptime_seconds: i64,
|
||||
database: bool,
|
||||
chains: Vec<ChainInfo>,
|
||||
@@ -116,6 +124,7 @@ async fn healthz(State(state): State<AppState>) -> Response {
|
||||
let body = HealthResponse {
|
||||
healthy: database,
|
||||
version: env!("CARGO_PKG_VERSION"),
|
||||
commit: option_env!("GIT_SHA"),
|
||||
uptime_seconds: (chrono::Utc::now() - state.started).num_seconds(),
|
||||
database,
|
||||
chains: state.chain_infos(),
|
||||
|
||||
Reference in New Issue
Block a user