fix(supervisor): stop infinite deploy loop in web_code_changed()
HEAD~1..HEAD always shows the same diff after os.execv reloads the process — every tick triggers deploy.sh if the last commit touched web/. Fix: track the last-seen HEAD in a module-level variable. On first call (fresh process after os.execv), fall back to HEAD~1 so the newly-deployed commit is evaluated once. Recording HEAD before returning means the same commit never fires twice, regardless of how many ticks pass. Also remove two unused imports (json, urllib.request) caught by ruff. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,14 +17,12 @@ Usage:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import tomllib
|
import tomllib
|
||||||
import urllib.request
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
@@ -269,14 +267,46 @@ def run_export() -> None:
|
|||||||
send_alert(f"[export] {err}")
|
send_alert(f"[export] {err}")
|
||||||
|
|
||||||
|
|
||||||
|
_last_seen_head: str | None = None
|
||||||
|
|
||||||
|
|
||||||
def web_code_changed() -> bool:
|
def web_code_changed() -> bool:
|
||||||
"""Check if web app code or secrets changed since last deploy (after git pull)."""
|
"""True on the first tick after a commit that changed web app code or secrets.
|
||||||
|
|
||||||
|
Compares the current HEAD to the HEAD from the previous tick. On first call
|
||||||
|
after process start (e.g. after os.execv reloads new code), falls back to
|
||||||
|
HEAD~1 so the just-deployed commit is evaluated exactly once.
|
||||||
|
|
||||||
|
Records HEAD before returning so the same commit never triggers twice.
|
||||||
|
"""
|
||||||
|
global _last_seen_head
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["git", "diff", "--name-only", "HEAD~1", "HEAD", "--",
|
["git", "rev-parse", "HEAD"], capture_output=True, text=True, timeout=10,
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
return False
|
||||||
|
current_head = result.stdout.strip()
|
||||||
|
|
||||||
|
if _last_seen_head is None:
|
||||||
|
# Fresh process — use HEAD~1 as base (evaluates the newly deployed tag).
|
||||||
|
base_result = subprocess.run(
|
||||||
|
["git", "rev-parse", "HEAD~1"], capture_output=True, text=True, timeout=10,
|
||||||
|
)
|
||||||
|
base = base_result.stdout.strip() if base_result.returncode == 0 else current_head
|
||||||
|
else:
|
||||||
|
base = _last_seen_head
|
||||||
|
|
||||||
|
_last_seen_head = current_head # advance now — won't fire again for this HEAD
|
||||||
|
|
||||||
|
if base == current_head:
|
||||||
|
return False
|
||||||
|
|
||||||
|
diff = subprocess.run(
|
||||||
|
["git", "diff", "--name-only", base, current_head, "--",
|
||||||
"web/", "Dockerfile", ".env.prod.sops"],
|
"web/", "Dockerfile", ".env.prod.sops"],
|
||||||
capture_output=True, text=True, timeout=30,
|
capture_output=True, text=True, timeout=30,
|
||||||
)
|
)
|
||||||
return bool(result.stdout.strip())
|
return bool(diff.stdout.strip())
|
||||||
|
|
||||||
|
|
||||||
def current_deployed_tag() -> str | None:
|
def current_deployed_tag() -> str | None:
|
||||||
|
|||||||
Reference in New Issue
Block a user