diff --git a/.github/workflows/scripts/run_ci_command.py b/.github/workflows/scripts/run_ci_command.py index 142249476d..64ec8cb762 100644 --- a/.github/workflows/scripts/run_ci_command.py +++ b/.github/workflows/scripts/run_ci_command.py @@ -621,6 +621,16 @@ def blocks_new_run(command: str, build: Mapping[str, Any]) -> bool: return is_active_build(build) +def list_commit_builds( + buildkite: BuildkiteClient, command: str, commit: str +) -> list[dict[str, Any]]: + builds = buildkite.list_builds(commit) + if command not in AMD_CI_COMMANDS: + return builds + # bootstrap-amd.sh exits before uploading any test steps for PR webhook builds. + return [build for build in builds if build.get("source") != "webhook"] + + def select_latest_build( builds: Sequence[dict[str, Any]], pr_number: int, @@ -968,7 +978,7 @@ def handle_run_ci( f"{ci_name} was already requested by this comment: {duplicate['web_url']}" ) - current_builds = buildkite.list_builds(pr["head"]["sha"]) + current_builds = list_commit_builds(buildkite, command, pr["head"]["sha"]) active_build = next( ( build @@ -1023,7 +1033,7 @@ def handle_retry_failed( ci_name = ci_name_for_command(command) run_command = run_command_for_command(command) retry_command = retry_command_for_command(command) - builds = buildkite.list_builds(pr["head"]["sha"]) + builds = list_commit_builds(buildkite, command, pr["head"]["sha"]) build = select_latest_build(builds, pr["number"]) if build: metadata = build.get("meta_data") or {} diff --git a/.github/workflows/scripts/test_run_ci_command.py b/.github/workflows/scripts/test_run_ci_command.py index 220af20e8b..823f363385 100644 --- a/.github/workflows/scripts/test_run_ci_command.py +++ b/.github/workflows/scripts/test_run_ci_command.py @@ -883,6 +883,42 @@ class RunCiCommandTest(unittest.TestCase): self.assertEqual(buildkite.created_builds, []) self.assertIn("AMD CI is already running", github.comments[0]) + def test_amd_run_ignores_finished_webhook_build_for_author(self) -> None: + webhook_build = { + "created_at": "2026-08-18T01:00:00Z", + "meta_data": {}, + "number": 122, + "pull_request": {"id": 42}, + "source": "webhook", + "state": "passed", + "web_url": "https://buildkite.example/amd-ci/builds/122", + } + ui_build = {**webhook_build, "source": "ui"} + command_build = { + **webhook_build, + "meta_data": {"github-comment-id": "98"}, + "source": "api", + } + for build, allowed in ( + (webhook_build, True), + (ui_build, False), + (command_build, False), + ): + with self.subTest(source=build["source"]): + github = FakeGitHub( + permission="read", + pr=make_pr(labels=[{"name": "ready"}]), + ) + buildkite = FakeBuildkite([[], [build]]) + + run(make_event(COMMAND_RUN_AMD_CI, "author"), github, buildkite) + + self.assertEqual(bool(buildkite.created_builds), allowed) + if not allowed: + self.assertIn( + "AMD CI already ran on this commit", github.comments[0] + ) + def test_run_all_sets_buildkite_environment(self) -> None: github = FakeGitHub() buildkite = FakeBuildkite([[], []]) @@ -1229,6 +1265,29 @@ class RunCiCommandTest(unittest.TestCase): ) self.assertIn("Use `/amd-ci run`", github.comments[0]) + def test_amd_ci_retry_ignores_webhook_build_for_the_current_head(self) -> None: + github = FakeGitHub( + permission="read", + pr=make_pr(labels=[{"name": "ready"}]), + ) + webhook_build = { + "created_at": "2026-08-18T01:00:00Z", + "meta_data": {}, + "number": 122, + "pull_request": {"id": 42}, + "source": "webhook", + "state": "passed", + "web_url": "https://buildkite.example/amd-ci/builds/122", + } + buildkite = FakeBuildkite([[webhook_build]]) + + run(make_event(COMMAND_RETRY_AMD_FAILED, "author"), github, buildkite) + + self.assertEqual(buildkite.retry_calls, []) + self.assertIn( + "No AMD CI build exists for the current PR head", github.comments[0] + ) + def test_ci_retry_creates_filtered_build_for_new_head(self) -> None: github = FakeGitHub( behind=100,