diff --git a/apps/backend/runners/github/models.py b/apps/backend/runners/github/models.py index e6aac73c..e1d5e660 100644 --- a/apps/backend/runners/github/models.py +++ b/apps/backend/runners/github/models.py @@ -12,7 +12,7 @@ from __future__ import annotations import json from dataclasses import dataclass, field -from datetime import datetime +from datetime import datetime, timezone from enum import Enum from pathlib import Path @@ -22,6 +22,11 @@ except (ImportError, ValueError, SystemError): from file_lock import locked_json_update, locked_json_write +def _utc_now_iso() -> str: + """Return current UTC time as ISO 8601 string with timezone info.""" + return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + class ReviewSeverity(str, Enum): """Severity levels for PR review findings.""" @@ -521,7 +526,7 @@ class PRReviewResult: summary: str = "" overall_status: str = "comment" # approve, request_changes, comment review_id: int | None = None - reviewed_at: str = field(default_factory=lambda: datetime.now().isoformat()) + reviewed_at: str = field(default_factory=lambda: _utc_now_iso()) error: str | None = None # NEW: Enhanced verdict system @@ -610,7 +615,7 @@ class PRReviewResult: summary=data.get("summary", ""), overall_status=data.get("overall_status", "comment"), review_id=data.get("review_id"), - reviewed_at=data.get("reviewed_at", datetime.now().isoformat()), + reviewed_at=data.get("reviewed_at", _utc_now_iso()), error=data.get("error"), # NEW fields verdict=MergeVerdict(data.get("verdict", "ready_to_merge")), @@ -691,7 +696,7 @@ class PRReviewResult: reviews.append(entry) current_data["reviews"] = reviews - current_data["last_updated"] = datetime.now().isoformat() + current_data["last_updated"] = _utc_now_iso() return current_data @@ -762,7 +767,7 @@ class TriageResult: suggested_breakdown: list[str] = field(default_factory=list) priority: str = "medium" # high, medium, low comment: str | None = None - triaged_at: str = field(default_factory=lambda: datetime.now().isoformat()) + triaged_at: str = field(default_factory=lambda: _utc_now_iso()) def to_dict(self) -> dict: return { @@ -798,7 +803,7 @@ class TriageResult: suggested_breakdown=data.get("suggested_breakdown", []), priority=data.get("priority", "medium"), comment=data.get("comment"), - triaged_at=data.get("triaged_at", datetime.now().isoformat()), + triaged_at=data.get("triaged_at", _utc_now_iso()), ) async def save(self, github_dir: Path) -> None: @@ -836,8 +841,8 @@ class AutoFixState: pr_url: str | None = None bot_comments: list[str] = field(default_factory=list) error: str | None = None - created_at: str = field(default_factory=lambda: datetime.now().isoformat()) - updated_at: str = field(default_factory=lambda: datetime.now().isoformat()) + created_at: str = field(default_factory=lambda: _utc_now_iso()) + updated_at: str = field(default_factory=lambda: _utc_now_iso()) def to_dict(self) -> dict: return { @@ -875,8 +880,8 @@ class AutoFixState: pr_url=data.get("pr_url"), bot_comments=data.get("bot_comments", []), error=data.get("error"), - created_at=data.get("created_at", datetime.now().isoformat()), - updated_at=data.get("updated_at", datetime.now().isoformat()), + created_at=data.get("created_at", _utc_now_iso()), + updated_at=data.get("updated_at", _utc_now_iso()), ) def update_status(self, status: AutoFixStatus) -> None: @@ -886,7 +891,7 @@ class AutoFixState: f"Invalid state transition: {self.status.value} -> {status.value}" ) self.status = status - self.updated_at = datetime.now().isoformat() + self.updated_at = _utc_now_iso() async def save(self, github_dir: Path) -> None: """Save auto-fix state to .auto-claude/github/issues/ with file locking.""" @@ -938,7 +943,7 @@ class AutoFixState: queue.append(entry) current_data["auto_fix_queue"] = queue - current_data["last_updated"] = datetime.now().isoformat() + current_data["last_updated"] = _utc_now_iso() return current_data diff --git a/apps/backend/runners/github/services/followup_reviewer.py b/apps/backend/runners/github/services/followup_reviewer.py index cd275aac..2299faca 100644 --- a/apps/backend/runners/github/services/followup_reviewer.py +++ b/apps/backend/runners/github/services/followup_reviewer.py @@ -18,7 +18,6 @@ from __future__ import annotations import hashlib import logging import re -from datetime import datetime from pathlib import Path from typing import TYPE_CHECKING, Any @@ -33,6 +32,7 @@ try: PRReviewResult, ReviewCategory, ReviewSeverity, + _utc_now_iso, ) from .category_utils import map_category from .io_utils import safe_print @@ -46,6 +46,7 @@ except (ImportError, ValueError, SystemError): PRReviewResult, ReviewCategory, ReviewSeverity, + _utc_now_iso, ) from services.category_utils import map_category from services.io_utils import safe_print @@ -265,7 +266,7 @@ class FollowupReviewer: verdict=verdict, verdict_reasoning=verdict_reasoning, blockers=blockers, - reviewed_at=datetime.now().isoformat(), + reviewed_at=_utc_now_iso(), # Follow-up specific fields reviewed_commit_sha=context.current_commit_sha, reviewed_file_blobs=file_blobs,