C0: suggest mise run runner-logs in container-build-and-release
After dispatching, poll the Forgejo API for the run matching our head_sha and print `mise run runner-logs <N>` so the suggested monitor command is one copy-paste away. Falls back to the bare command if the poll times out. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0ceafc374d
commit
e6a6a6042e
2 changed files with 60 additions and 2 deletions
|
|
@ -0,0 +1 @@
|
||||||
|
`container-build-and-release` now prints the specific `mise run runner-logs <N>` command after dispatching, polling the Forgejo API to resolve the run number for the commit it just triggered.
|
||||||
|
|
@ -15,6 +15,7 @@ Dockerfile and Nix builds in a single workflow.
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
@ -48,6 +49,52 @@ def get_forge_token() -> str:
|
||||||
return result.stdout.strip()
|
return result.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def max_run_number(headers: dict[str, str]) -> int:
|
||||||
|
"""Return the highest current run_number for WORKFLOW, or 0 if none."""
|
||||||
|
resp = httpx.get(
|
||||||
|
f"{FORGE_API}/repos/{REPO}/actions/tasks",
|
||||||
|
params={"limit": 50},
|
||||||
|
headers=headers,
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
if resp.status_code != 200:
|
||||||
|
return 0
|
||||||
|
runs = [
|
||||||
|
t["run_number"]
|
||||||
|
for t in resp.json().get("workflow_runs", [])
|
||||||
|
if t.get("workflow_id") == WORKFLOW
|
||||||
|
]
|
||||||
|
return max(runs, default=0)
|
||||||
|
|
||||||
|
|
||||||
|
def find_dispatched_run(
|
||||||
|
ref: str, floor: int, headers: dict[str, str], timeout_s: int = 20
|
||||||
|
) -> int | None:
|
||||||
|
"""Poll the tasks endpoint for the run triggered by our dispatch.
|
||||||
|
|
||||||
|
Matches by head_sha + workflow + run_number > floor so we don't pick up
|
||||||
|
an older build of the same commit or a concurrent unrelated dispatch.
|
||||||
|
"""
|
||||||
|
deadline = time.monotonic() + timeout_s
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
resp = httpx.get(
|
||||||
|
f"{FORGE_API}/repos/{REPO}/actions/tasks",
|
||||||
|
params={"limit": 20},
|
||||||
|
headers=headers,
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
if resp.status_code == 200:
|
||||||
|
for task in resp.json().get("workflow_runs", []):
|
||||||
|
if (
|
||||||
|
task.get("head_sha") == ref
|
||||||
|
and task.get("workflow_id") == WORKFLOW
|
||||||
|
and task.get("run_number", 0) > floor
|
||||||
|
):
|
||||||
|
return task["run_number"]
|
||||||
|
time.sleep(1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def list_containers() -> None:
|
def list_containers() -> None:
|
||||||
typer.echo("Available containers:")
|
typer.echo("Available containers:")
|
||||||
for d in sorted(Path("containers").iterdir()):
|
for d in sorted(Path("containers").iterdir()):
|
||||||
|
|
@ -112,7 +159,8 @@ def main(
|
||||||
if dry_run:
|
if dry_run:
|
||||||
typer.echo(f"[dry-run] Would dispatch {WORKFLOW}")
|
typer.echo(f"[dry-run] Would dispatch {WORKFLOW}")
|
||||||
typer.echo()
|
typer.echo()
|
||||||
typer.echo(f"Monitor builds at: {FORGE_ACTIONS}")
|
typer.echo("Monitor builds with: mise run runner-logs")
|
||||||
|
typer.echo(f" or visit: {FORGE_ACTIONS}")
|
||||||
return
|
return
|
||||||
|
|
||||||
token = get_forge_token()
|
token = get_forge_token()
|
||||||
|
|
@ -132,6 +180,10 @@ def main(
|
||||||
typer.echo("Push your changes before triggering a build: git push origin main")
|
typer.echo("Push your changes before triggering a build: git push origin main")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
# Snapshot the highest existing run_number so we can identify the one
|
||||||
|
# our dispatch creates.
|
||||||
|
floor = max_run_number(headers)
|
||||||
|
|
||||||
url = f"{FORGE_API}/repos/{REPO}/actions/workflows/{WORKFLOW}/dispatches"
|
url = f"{FORGE_API}/repos/{REPO}/actions/workflows/{WORKFLOW}/dispatches"
|
||||||
payload = {
|
payload = {
|
||||||
"ref": "main",
|
"ref": "main",
|
||||||
|
|
@ -148,7 +200,12 @@ def main(
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
typer.echo()
|
typer.echo()
|
||||||
typer.echo(f"Monitor builds at: {FORGE_ACTIONS}")
|
run_number = find_dispatched_run(ref, floor, headers)
|
||||||
|
if run_number is not None:
|
||||||
|
typer.echo(f"Monitor builds with: mise run runner-logs {run_number}")
|
||||||
|
else:
|
||||||
|
typer.echo("Monitor builds with: mise run runner-logs")
|
||||||
|
typer.echo(f" or visit: {FORGE_ACTIONS}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue