This commit was merged in pull request #1280.
This commit is contained in:
@@ -4,10 +4,13 @@
|
||||
Connects to local Gitea, fetches candidate issues, and produces a concise agenda
|
||||
plus a day summary (review mode).
|
||||
|
||||
The Daily Run begins with a Quick Health Snapshot (#710) to ensure mandatory
|
||||
systems are green before burning cycles on work that cannot land.
|
||||
|
||||
Run: python3 timmy_automations/daily_run/orchestrator.py [--review]
|
||||
Env: See timmy_automations/config/daily_run.json for configuration
|
||||
|
||||
Refs: #703
|
||||
Refs: #703, #923
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -30,6 +33,11 @@ sys.path.insert(
|
||||
)
|
||||
from utils.token_rules import TokenRules, compute_token_reward
|
||||
|
||||
# Health snapshot lives in the same package
|
||||
from health_snapshot import generate_snapshot as _generate_health_snapshot
|
||||
from health_snapshot import get_token as _hs_get_token
|
||||
from health_snapshot import load_config as _hs_load_config
|
||||
|
||||
# ── Configuration ─────────────────────────────────────────────────────────
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
@@ -495,6 +503,16 @@ def parse_args() -> argparse.Namespace:
|
||||
default=None,
|
||||
help="Override max agenda items",
|
||||
)
|
||||
p.add_argument(
|
||||
"--skip-health-check",
|
||||
action="store_true",
|
||||
help="Skip the pre-flight health snapshot (not recommended)",
|
||||
)
|
||||
p.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="Continue even if health snapshot is red (overrides abort-on-red)",
|
||||
)
|
||||
return p.parse_args()
|
||||
|
||||
|
||||
@@ -535,6 +553,76 @@ def compute_daily_run_tokens(success: bool = True) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def run_health_snapshot(args: argparse.Namespace) -> int:
|
||||
"""Run pre-flight health snapshot and return 0 (ok) or 1 (abort).
|
||||
|
||||
Prints a concise summary of CI, issues, flakiness, and token economy.
|
||||
Returns 1 if the overall status is red AND --force was not passed.
|
||||
Returns 0 for green/yellow or when --force is active.
|
||||
On any import/runtime error the check is skipped with a warning.
|
||||
"""
|
||||
try:
|
||||
hs_config = _hs_load_config()
|
||||
hs_token = _hs_get_token(hs_config)
|
||||
snapshot = _generate_health_snapshot(hs_config, hs_token)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
print(f"[health] Warning: health snapshot failed ({exc}) — skipping", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
# Print concise pre-flight header
|
||||
status_emoji = {"green": "🟢", "yellow": "🟡", "red": "🔴"}.get(
|
||||
snapshot.overall_status, "⚪"
|
||||
)
|
||||
print("─" * 60)
|
||||
print(f"PRE-FLIGHT HEALTH CHECK {status_emoji} {snapshot.overall_status.upper()}")
|
||||
print("─" * 60)
|
||||
|
||||
ci_emoji = {"pass": "✅", "fail": "❌", "unknown": "⚠️", "unavailable": "⚪"}.get(
|
||||
snapshot.ci.status, "⚪"
|
||||
)
|
||||
print(f" {ci_emoji} CI: {snapshot.ci.message}")
|
||||
|
||||
if snapshot.issues.p0_count > 0:
|
||||
issue_emoji = "🔴"
|
||||
elif snapshot.issues.p1_count > 0:
|
||||
issue_emoji = "🟡"
|
||||
else:
|
||||
issue_emoji = "✅"
|
||||
critical_str = f"{snapshot.issues.count} critical"
|
||||
if snapshot.issues.p0_count:
|
||||
critical_str += f" (P0: {snapshot.issues.p0_count})"
|
||||
if snapshot.issues.p1_count:
|
||||
critical_str += f" (P1: {snapshot.issues.p1_count})"
|
||||
print(f" {issue_emoji} Issues: {critical_str}")
|
||||
|
||||
flak_emoji = {"healthy": "✅", "degraded": "🟡", "critical": "🔴", "unknown": "⚪"}.get(
|
||||
snapshot.flakiness.status, "⚪"
|
||||
)
|
||||
print(f" {flak_emoji} Flakiness: {snapshot.flakiness.message}")
|
||||
|
||||
token_emoji = {"balanced": "✅", "inflationary": "🟡", "deflationary": "🔵", "unknown": "⚪"}.get(
|
||||
snapshot.tokens.status, "⚪"
|
||||
)
|
||||
print(f" {token_emoji} Tokens: {snapshot.tokens.message}")
|
||||
print()
|
||||
|
||||
if snapshot.overall_status == "red" and not args.force:
|
||||
print(
|
||||
"🛑 Health status is RED — aborting Daily Run to avoid burning cycles.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(
|
||||
" Fix the issues above or re-run with --force to override.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
if snapshot.overall_status == "red":
|
||||
print("⚠️ Health is RED but --force passed — proceeding anyway.", file=sys.stderr)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
config = load_config()
|
||||
@@ -542,6 +630,15 @@ def main() -> int:
|
||||
if args.max_items:
|
||||
config["max_agenda_items"] = args.max_items
|
||||
|
||||
# ── Step 0: Pre-flight health snapshot ──────────────────────────────────
|
||||
if not args.skip_health_check:
|
||||
health_rc = run_health_snapshot(args)
|
||||
if health_rc != 0:
|
||||
tokens = compute_daily_run_tokens(success=False)
|
||||
if args.json:
|
||||
print(json.dumps({"error": "health_check_failed", "tokens": tokens}))
|
||||
return health_rc
|
||||
|
||||
token = get_token(config)
|
||||
client = GiteaClient(config, token)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user