diff --git a/cinny/lotus_deploy.sh b/cinny/lotus_deploy.sh index 1d84d8a..e1badb8 100755 --- a/cinny/lotus_deploy.sh +++ b/cinny/lotus_deploy.sh @@ -54,6 +54,19 @@ if [ -n "${GITEA_API_TOKEN:-}" ]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] Waiting for CI '$GATE_CONTEXT' on $COMMIT_SHA..." while [ "$elapsed" -lt "$MAX_WAIT" ]; do + # Follow origin/lotus. A newer push supersedes ours — with CI + # cancel-in-progress its run is CANCELLED (reported error/failure), and a + # newer deploy is skipped by our flock — so polling the latched (now + # cancelled) SHA would abort and strand the newest commit undeployed. + # Re-resolve HEAD each iteration and retarget the gate if it advanced, + # giving the fresh commit a full MAX_WAIT window. + git fetch --quiet origin lotus 2>/dev/null || true + newest=$(git rev-parse origin/lotus 2>/dev/null || echo "$COMMIT_SHA") + if [ "$newest" != "$COMMIT_SHA" ]; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] origin/lotus advanced ${COMMIT_SHA:0:8} -> ${newest:0:8}; retargeting CI gate." + COMMIT_SHA="$newest" + elapsed=0 + fi state=$(curl -s -H "Authorization: token $GITEA_API_TOKEN" \ "$GITEA_API/repos/$REPO_PATH/commits/$COMMIT_SHA/status" \ | GATE="$GATE_CONTEXT" python3 -c " @@ -72,7 +85,23 @@ else: case "$state" in success) ci_result=success; break ;; - failure|error) ci_result="$state"; break ;; + failure|error) + # Before aborting: a superseded run reports its status as + # error/failure (cancel-in-progress). If a fetch blip on the + # retarget iteration left us on a stale SHA, re-check HEAD — if it + # advanced, follow it and keep waiting rather than aborting on a + # commit that a newer push already replaced. Only a genuine + # failure of the CURRENT HEAD aborts the deploy. + git fetch --quiet origin lotus 2>/dev/null || true + head_now=$(git rev-parse origin/lotus 2>/dev/null || echo "$COMMIT_SHA") + if [ "$head_now" != "$COMMIT_SHA" ]; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] gated ${COMMIT_SHA:0:8} reported ${state}, but origin/lotus advanced to ${head_now:0:8}; retargeting." + COMMIT_SHA="$head_now" + elapsed=0 + else + ci_result="$state"; break + fi + ;; esac echo "[$(date '+%Y-%m-%d %H:%M:%S')] CI not yet passed (${elapsed}s elapsed, '$GATE_CONTEXT': ${state}), waiting..." sleep "$POLL_INTERVAL" @@ -88,7 +117,10 @@ else echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: GITEA_API_TOKEN not set, deploying without CI gate." fi -git reset --hard origin/lotus +# Reset to the exact commit we gated on (which the poll loop keeps in step with +# origin/lotus), not a bare origin/lotus that may have advanced past the gate +# after the loop exited — so we deploy precisely what passed CI. +git reset --hard "$COMMIT_SHA" # Tag this build with the exact commit so Sentry can link errors to source export VITE_APP_VERSION=$COMMIT_SHA