diff --git a/.github/workflows/scripts/run_ci_command.py b/.github/workflows/scripts/run_ci_command.py index b6ef1c3ae8..142249476d 100644 --- a/.github/workflows/scripts/run_ci_command.py +++ b/.github/workflows/scripts/run_ci_command.py @@ -861,14 +861,24 @@ def merge_base_into_pr( for _ in range(BRANCH_UPDATE_POLL_ATTEMPTS): time.sleep(BRANCH_UPDATE_POLL_SECONDS) current_pr = github.get_pr(pr["number"]) - if current_pr["head"]["sha"] != pr["head"]["sha"]: - break + if current_pr["head"]["sha"] == pr["head"]["sha"]: + continue + try: + behind = github.get_commits_behind_base( + base_ref, current_pr["head"]["sha"] + ) + except ApiError as error: + # A fork's new head is briefly unknown to the base repository. + if error.status == 404: + continue + raise + break else: raise merge_failed("the merge commit did not appear in time") if ( current_pr["state"] != "open" or current_pr["base"]["ref"] != base_ref - or github.get_commits_behind_base(base_ref, current_pr["head"]["sha"]) + or behind ): raise merge_failed("the PR changed during the merge") except ApiError as error: diff --git a/.github/workflows/scripts/test_run_ci_command.py b/.github/workflows/scripts/test_run_ci_command.py index 2061ff895e..220af20e8b 100644 --- a/.github/workflows/scripts/test_run_ci_command.py +++ b/.github/workflows/scripts/test_run_ci_command.py @@ -677,6 +677,24 @@ class RunCiCommandTest(unittest.TestCase): self.assertIn("CI already ran on this commit", github.comments[0]) self.assertIn("`/ci retry`", github.comments[0]) + def test_run_waits_for_fork_merge_commit_to_reach_base_repo(self) -> None: + github = FakeGitHub(behind=5) + updater = FakeBranchUpdater(github) + buildkite = FakeBuildkite([[], []]) + + with ( + patch("run_ci_command.time.sleep"), + patch.object( + github, + "get_commits_behind_base", + side_effect=[5, ApiError(404, "Not Found"), 0], + ), + ): + run(make_event(COMMAND_RUN_CI), github, buildkite, "", updater) + + self.assertEqual(buildkite.created_builds[0]["commit"], "merge-commit-sha") + self.assertTrue(github.comments[0].startswith("✅ ")) + def test_run_reports_failed_merge_without_building(self) -> None: github = FakeGitHub(behind=5) updater = FakeBranchUpdater(github, error=ApiError(422, "merge conflict"))