feat(bot): клиент SourceCraft API — прогоны, логи кубов, sha коммита, ретраи
- SourceCraftClient (httpx): list_runs, get_run, get_cube_logs (постранично), run_commit_sha; ретраи на сетевые ошибки и 5xx с экспоненциальной задержкой, 4xx — SourceCraftError без повторов - модели: RunStatus/EventType из swagger, «1970-01-01» = не задано, failed_cubes без служебных #-кубов - у прогона в API нет sha → куб check/meta в tgit-uploads печатает TGIT_COMMIT_SHA (ADR-014) - CLI: python -m app.sourcecraft.cli runs - тесты на реальных ответах API (фикстуры), порог покрытия 45 → 80 Refs #10 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
"""Debug CLI: `python -m app.sourcecraft.cli runs [repo]` — recent CI runs with their commit and failed cubes."""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
from app.config import SourceCraftSettings
|
||||
from app.sourcecraft.client import SourceCraftClient
|
||||
|
||||
|
||||
async def runs(repo: str | None) -> None:
|
||||
settings = SourceCraftSettings()
|
||||
repo = repo or settings.uploads_repo
|
||||
async with SourceCraftClient(settings) as client:
|
||||
for run in await client.list_runs(repo, page_size=10):
|
||||
full = await client.get_run(repo, run.slug)
|
||||
sha = await client.run_commit_sha(repo, full)
|
||||
failed = ", ".join(f"{t}/{c.slug}" for _, t, c in full.failed_cubes()) or "-"
|
||||
print(f"{run.slug} {run.event_type:<8} {run.status:<10} sha={sha or '?':<40.12} failed={failed}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) < 2 or sys.argv[1] != "runs":
|
||||
sys.exit("usage: python -m app.sourcecraft.cli runs [org/repo]")
|
||||
asyncio.run(runs(sys.argv[2] if len(sys.argv) > 2 else None))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user