""" Forgejo integration — webhook handler for push events. Kicks off a build when a push event arrives. The actual webhook endpoint should live in main.py (or a dedicated webhooks router); this function encapsulates the "convert push → BuildBody → start build" logic. """ from typing import Any, Dict, Optional def on_push_event(project: str, repo: str, ref: str = "main", runner=None) -> Dict[str, Any]: """Handle a Forgejo push webhook. Args: project: project name (e.g. "linux-tool") repo: full clone URL ref: git ref that was pushed (e.g. "main", "refs/tags/v1.0") runner: BuildRunner instance (if None, returns the BuildBody that would have been dispatched) Returns: dict with build_id + status, OR the BuildBody if no runner. """ # Build a project spec for the engine body = { "cmd": f"git fetch && git checkout {ref} && make -j$(nproc)", "dir": f"/home/user/builds/{project}", "project": project, "arch": "x86_64", "target": "linux-gnu", "toolchain": "gcc", } if runner is None: return {"status": "no_runner", "body": body} # Dispatch through the runner (async, but we can't await from sync) import asyncio try: loop = asyncio.get_running_loop() except RuntimeError: loop = None if loop: # We're inside an async context — schedule the build task = loop.create_task(runner.start(_BuildBodyShim(**body))) return {"status": "scheduled", "body": body} else: # Sync context — run in a new loop (blocks) async def _start(): return await runner.start(_BuildBodyShim(**body)) build_id = asyncio.run(_start()) return {"status": "started", "build_id": build_id, "body": body} class _BuildBodyShim: """Tiny shim so we can pass a body-like object to BuildRunner.start without importing pydantic (which would create a circular import).""" def __init__(self, cmd, dir, project=None, arch="x86_64", target="linux-gnu", toolchain="gcc"): self.cmd = cmd self.dir = dir self.project = project self.arch = arch self.target = target self.toolchain = toolchain