mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-11 21:26:44 +00:00
fix(ci): find the privileged run of a fork PR by its head commit
The wait for fork CI images never found the privileged workflow run it watches. It selected a run only when the run's pull_requests array held the PR number, and for a run whose head repository is a fork the API returns that array empty. The job only runs for fork PRs, so the lookup matched in no case it exists for. The early exit for a failed privileged run was therefore unreachable. When that run failed, the job kept polling until its timeout of 1980 attempts and held a runner for about five and a half hours. The lookup now asks the API for the runs of the PR head commit and selects by head_sha. That also replaces a paginated listing of every run of the workflow with one small request per attempt. Without a known head commit the match by PR number stays. Refs #784 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
53f71d85c8
commit
3ab0153856
2 files changed
+64
-9
No files matched your search
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
@@ -9,25 +10,33 @@ from pathlib import Path
|
||||
from utils.cache.files import PROJECT_ROOT
|
||||
|
||||
SCRIPT = PROJECT_ROOT / "scripts" / "meta" / "wait" / "images.sh"
|
||||
HEAD_SHA = "5b002678df222f1095fae2f42e3bb10964adb8ef"
|
||||
STUBS = {
|
||||
"docker": '#!/usr/bin/env bash\n[[ -e "${STUB_DIR}/images-ready" ]]\n',
|
||||
"gh": (
|
||||
"#!/usr/bin/env bash\n"
|
||||
'printf "gh %s\\n" "$*" >&2\n'
|
||||
'if [[ -n "${STUB_IMAGES_APPEAR:-}" ]]; then\n'
|
||||
'\ttouch "${STUB_DIR}/images-ready"\n'
|
||||
"fi\n"
|
||||
'if [[ -e "${STUB_DIR}/gh-response" ]]; then\n'
|
||||
'\tcat "${STUB_DIR}/gh-response"\n'
|
||||
"\texit 0\n"
|
||||
"fi\n"
|
||||
'echo "HTTP 504" >&2\n'
|
||||
"exit 1\n"
|
||||
),
|
||||
"jq": "#!/usr/bin/env bash\ncat >/dev/null\n",
|
||||
}
|
||||
|
||||
|
||||
def wait_for_images(tmp: str, **overrides: str) -> subprocess.CompletedProcess:
|
||||
"""Run the wait script against a ``gh`` that fails every lookup.
|
||||
def wait_for_images(
|
||||
tmp: str, runs: list[dict] | None = None, **overrides: str
|
||||
) -> subprocess.CompletedProcess:
|
||||
"""Run the wait script against stubbed ``docker`` and ``gh``.
|
||||
|
||||
Args:
|
||||
tmp: directory that holds the ``docker``, ``gh`` and ``jq`` stubs and their state.
|
||||
tmp: directory that holds the stubs and their state.
|
||||
runs: workflow runs ``gh`` answers with; without them every lookup fails.
|
||||
overrides: environment entries layered over the defaults.
|
||||
"""
|
||||
stub_dir = Path(tmp)
|
||||
@@ -35,6 +44,8 @@ def wait_for_images(tmp: str, **overrides: str) -> subprocess.CompletedProcess:
|
||||
stub = stub_dir / name
|
||||
stub.write_text(body)
|
||||
stub.chmod(0o755)
|
||||
if runs is not None:
|
||||
(stub_dir / "gh-response").write_text(json.dumps({"workflow_runs": runs}))
|
||||
inherited = {k: v for k, v in os.environ.items() if k != "BASH_ENV"}
|
||||
env = {
|
||||
**inherited,
|
||||
@@ -45,6 +56,7 @@ def wait_for_images(tmp: str, **overrides: str) -> subprocess.CompletedProcess:
|
||||
"WORKFLOW_FILE": "entry.yml",
|
||||
"TARGET_EVENT": "pull_request_target",
|
||||
"PR_NUMBER": "1",
|
||||
"PR_HEAD_SHA": HEAD_SHA,
|
||||
"IMAGE_TAG": "ci-test",
|
||||
"INFINITO_DISTROS": "debian",
|
||||
"WAIT_ATTEMPTS": "100",
|
||||
@@ -77,6 +89,40 @@ class TestWaitForImages(unittest.TestCase):
|
||||
self.assertEqual(result.returncode, 1, result.stdout + result.stderr)
|
||||
self.assertIn("failed 30 times in a row", result.stderr)
|
||||
|
||||
def test_failed_privileged_run_of_a_fork_ends_the_wait(self) -> None:
|
||||
fork_run = {
|
||||
"id": 7,
|
||||
"status": "completed",
|
||||
"conclusion": "failure",
|
||||
"created_at": "2026-10-04T12:41:18Z",
|
||||
"head_sha": HEAD_SHA,
|
||||
"pull_requests": [],
|
||||
}
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
result = wait_for_images(tmp, runs=[fork_run])
|
||||
self.assertEqual(result.returncode, 1, result.stdout + result.stderr)
|
||||
self.assertIn(
|
||||
"Privileged run 7 finished with conclusion=failure", result.stderr
|
||||
)
|
||||
self.assertIn(f"head_sha={HEAD_SHA}", result.stderr)
|
||||
|
||||
def test_run_of_another_head_is_ignored(self) -> None:
|
||||
other_run = {
|
||||
"id": 8,
|
||||
"status": "completed",
|
||||
"conclusion": "failure",
|
||||
"created_at": "2026-10-04T12:41:18Z",
|
||||
"head_sha": "0" * 40,
|
||||
"pull_requests": [],
|
||||
}
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
result = wait_for_images(tmp, runs=[other_run], WAIT_ATTEMPTS="2")
|
||||
self.assertEqual(result.returncode, 1, result.stdout + result.stderr)
|
||||
self.assertIn(
|
||||
"No matching privileged workflow run found yet", result.stdout
|
||||
)
|
||||
self.assertIn("Timed out waiting for CI images", result.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user