From be616668fc82a5cbd9ef22a0ce4da4d0ce6f802a Mon Sep 17 00:00:00 2001 From: eezd Date: Fri, 30 Oct 2026 11:03:59 +0800 Subject: [PATCH] fix(ci): check exact main admission across pending runs --- scripts/release.py | 24 ++++++++++++++---------- scripts/tests/test_cicd.py | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/scripts/release.py b/scripts/release.py index 766a1e8..ac6c87e 100644 --- a/scripts/release.py +++ b/scripts/release.py @@ -299,6 +299,19 @@ def release_receipt(gitea, github, version): return build, receipt +def successful_main_ci(gitea, commit): + page = 1 + passed = False + while not passed: + runs = gitea.repo(f'/actions/runs?limit=100&page={page}')['workflow_runs'] + if not runs: + break + passed = any(r['head_sha'] == commit and r['event'] == 'push' and r.get('conclusion') == 'success' + and r['path'] == 'main.yml@refs/heads/main' for r in runs) + page += 1 + return passed + + def preflight(version, commit): state = selected_state() gitea, _ = clients() @@ -326,16 +339,7 @@ def preflight(version, commit): return main = fetch_main(gitea) run('git', 'merge-base', '--is-ancestor', commit, main) - page = 1 - passed = False - while not passed: - runs = gitea.repo(f'/actions/runs?limit=100&page={page}')['workflow_runs'] - if not runs: - break - passed = any(r['head_sha'] == commit and r['event'] == 'push' and r['conclusion'] == 'success' - and r['path'] == 'main.yml@refs/heads/main' for r in runs) - page += 1 - require(passed, 'The selected commit has no successful main-push CI') + require(successful_main_ci(gitea, commit), 'The selected commit has no successful main-push CI') remote = fetch_main(github) run('git', 'merge-base', '--is-ancestor', remote, commit) tag = version diff --git a/scripts/tests/test_cicd.py b/scripts/tests/test_cicd.py index 174e75f..d4c844b 100644 --- a/scripts/tests/test_cicd.py +++ b/scripts/tests/test_cicd.py @@ -361,3 +361,22 @@ class ReleaseReservationTests(unittest.TestCase): def test_release_version_uses_utc_commit_date_and_fixed_sha(self): with patch.object(release, 'run', return_value='0'): self.assertEqual(release.version_for(SHA), '19700101-aaaaaaaa') + + +class MainAdmissionTests(unittest.TestCase): + def test_pending_rows_do_not_hide_later_success(self): + api = Mock() + api.repo.side_effect = [ + {'workflow_runs': [{'head_sha': SHA, 'event': 'push', 'path': 'mirror.yml@refs/heads/main'}]}, + {'workflow_runs': [{'head_sha': SHA, 'event': 'push', 'path': 'main.yml@refs/heads/main', 'conclusion': 'success'}]}, + ] + self.assertTrue(release.successful_main_ci(api, SHA)) + + def test_other_sha_pr_or_dev_success_cannot_admit_main(self): + api = Mock() + api.repo.side_effect = [{'workflow_runs': [ + {'head_sha': 'b' * 40, 'event': 'push', 'path': 'main.yml@refs/heads/main', 'conclusion': 'success'}, + {'head_sha': SHA, 'event': 'pull_request', 'path': 'main.yml@refs/pull/3/head', 'conclusion': 'success'}, + {'head_sha': SHA, 'event': 'push', 'path': 'dev.yml@refs/heads/dev', 'conclusion': 'success'}, + ]}, {'workflow_runs': []}] + self.assertFalse(release.successful_main_ci(api, SHA))