1616from buildbot .plugins import steps , util , worker
1717from buildbot .process .builder import Builder
1818from buildbot .process .buildstep import BuildStep
19- from buildbot .process .results import FAILURE , SUCCESS
19+ from buildbot .process .results import CANCELLED , FAILURE , SUCCESS
2020from buildbot .process .workerforbuilder import AbstractWorkerForBuilder
2121from buildbot .worker import AbstractWorker
2222from constants import (
@@ -682,11 +682,11 @@ def mtrEnv(props: IProperties) -> dict:
682682
683683
684684class CancelDuplicateBuildRequests (BuildStep ):
685- """BuildStep to cancel duplicate buildrequests for the same commit on the same builder
686- if the current build is for a pull request event. It checks for other pending buildrequests
687- with the same builder and if they have a sourcestamp with the same revision as
688- the current build, it cancels them. It only cancels normal branch builds, not other
689- pull request refs, and avoids important branches like main, release or merge branches .
685+ """Stop duplicate push builds when a matching pull request build exists.
686+
687+ When GitHub sends push and pull_request events for the same commit, both can
688+ queue tarball-docker requests. A normal branch push should yield to a matching
689+ pull request buildrequest on the same builder .
690690 """
691691
692692 name = "cancel duplicate buildrequests"
@@ -717,17 +717,15 @@ def _fmt_ss(ss):
717717
718718 @staticmethod
719719 def _branch_is_cancelable (branch ):
720- """Only cancel duplicate builds originating from normal branch pushes."""
720+ """Only let disposable normal branch pushes yield to pull request builds ."""
721721 if not branch :
722722 return False
723723
724724 branch_lc = branch .lower ()
725725 return (
726726 len (branch ) > 5
727727 and not branch_lc .startswith ("refs/" )
728- and "release" not in branch_lc
729- and "merge" not in branch_lc
730- and "preview" not in branch_lc
728+ and not fnmatch_any (branch , SAVED_PACKAGE_BRANCHES )
731729 )
732730
733731 @defer .inlineCallbacks
@@ -744,8 +742,8 @@ def run(self):
744742 self .addCompleteLog ("duplicate-buildrequests" , "\n " .join (lines ) + "\n " )
745743 return SUCCESS
746744
747- if event != "pull_request " :
748- lines .append ("Event is not 'pull_request '; nothing to do." )
745+ if event != "push " :
746+ lines .append ("Event is not 'push '; nothing to do." )
749747 self .addCompleteLog ("duplicate-buildrequests" , "\n " .join (lines ) + "\n " )
750748 return SUCCESS
751749
@@ -768,15 +766,17 @@ def run(self):
768766 self .addCompleteLog ("duplicate-buildrequests" , "\n " .join (lines ) + "\n " )
769767 return SUCCESS
770768
771- current_revisions = {
772- ss .get ("revision" )
769+ current_targets = {
770+ ( ss .get ("revision" ), ss . get ( "repository" ), ss . get ( "codebase" , "" ) )
773771 for ss in current_sourcestamps
774772 if ss .get ("revision" ) is not None
773+ and self ._branch_is_cancelable (ss .get ("branch" ))
775774 }
776775
777- if not current_revisions :
776+ if not current_targets :
778777 lines .append (
779- "Current buildset has no revision in sourcestamps; nothing to do."
778+ "Current buildset has no cancelable push sourcestamp with a "
779+ "revision; nothing to do."
780780 )
781781 self .addCompleteLog ("duplicate-buildrequests" , "\n " .join (lines ) + "\n " )
782782 return SUCCESS
@@ -787,20 +787,12 @@ def run(self):
787787 if ss .get ("branch" ) is not None
788788 }
789789
790- if not any (branch .startswith ("refs/pull/" ) for branch in current_branches ):
791- lines .append (
792- "Current build is a pull_request event, but no pull request ref "
793- "was found in sourcestamps; nothing to do."
794- )
795- self .addCompleteLog ("duplicate-buildrequests" , "\n " .join (lines ) + "\n " )
796- return SUCCESS
797-
798790 lines .append ("Current:" )
799791 lines .append (f" buildid={ current_buildid } " )
800792 lines .append (f" buildrequestid={ current_buildrequestid } " )
801793 lines .append (f" builderid={ current_builderid } " )
802794 lines .append (f" buildsetid={ current_buildsetid } " )
803- lines .append (f" revisions ={ sorted (current_revisions )!r} " )
795+ lines .append (f" targets ={ sorted (current_targets )!r} " )
804796 lines .append (f" branches={ sorted (current_branches )!r} " )
805797 current_url = self ._buildrequest_url (current_buildrequestid )
806798 if current_url :
@@ -829,8 +821,6 @@ def run(self):
829821
830822 matches = []
831823 actions = []
832- cancel_errors = []
833-
834824 for br in buildrequests :
835825 brid = br ["buildrequestid" ]
836826
@@ -848,16 +838,19 @@ def run(self):
848838 for other_ss in other_sourcestamps :
849839 other_revision = other_ss .get ("revision" )
850840 other_branch = other_ss .get ("branch" )
841+ other_target = (
842+ other_revision ,
843+ other_ss .get ("repository" ),
844+ other_ss .get ("codebase" , "" ),
845+ )
851846
852- if other_revision not in current_revisions :
853- continue
854-
855- if not self ._branch_is_cancelable (other_branch ):
847+ if not other_branch or not other_branch .startswith ("refs/pull/" ):
856848 continue
857849
858- matched_revision = other_revision
859- matched_branch = other_branch
860- break
850+ if other_target in current_targets :
851+ matched_revision = other_revision
852+ matched_branch = other_branch
853+ break
861854
862855 if matched_revision is None :
863856 continue
@@ -876,47 +869,24 @@ def run(self):
876869
877870 if self .dry_run :
878871 msg = (
879- f"[DRY-RUN] would cancel buildrequest { brid } "
872+ f"[DRY-RUN] would stop current build "
873+ f"because pull request buildrequest { brid } exists "
880874 f"(claimed={ br .get ('claimed' )} , "
881875 f"revision={ matched_revision !r} , "
882876 f"branch={ matched_branch !r} )"
883877 )
884- if info ["url" ]:
885- msg += f" url={ info ['url' ]} "
886- actions .append (msg )
887878 else :
888- try :
889- yield self .master .data .control (
890- "cancel" ,
891- {"reason" : "Duplicate build for same commit on same builder" },
892- ("buildrequests" , brid ),
893- )
894- except Exception as e :
895- msg = (
896- f"Failed to request cancel for buildrequest { brid } "
897- f"(claimed={ br .get ('claimed' )} , "
898- f"revision={ matched_revision !r} , "
899- f"branch={ matched_branch !r} , "
900- f"error={ e !r} )"
901- )
902- if info ["url" ]:
903- msg += f" url={ info ['url' ]} "
904- actions .append (msg )
905- cancel_errors .append (msg )
906- log .err (e , f"Failed to request cancel for buildrequest { brid } " )
907- else :
908- msg = (
909- f"Requested cancel for buildrequest { brid } "
910- f"(claimed={ br .get ('claimed' )} , "
911- f"revision={ matched_revision !r} , "
912- f"branch={ matched_branch !r} )"
913- )
914- if info ["url" ]:
915- msg += f" url={ info ['url' ]} "
916- actions .append (msg )
879+ msg = (
880+ f"Stopping current build because pull request buildrequest { brid } "
881+ f"exists (claimed={ br .get ('claimed' )} , "
882+ f"revision={ matched_revision !r} , "
883+ f"branch={ matched_branch !r} )"
884+ )
885+ if info ["url" ]:
886+ msg += f" url={ info ['url' ]} "
887+ actions .append (msg )
917888
918- lines .append (f"Matched duplicate buildrequests: { len (matches )} " )
919- lines .append (f"Cancel request failures: { len (cancel_errors )} " )
889+ lines .append (f"Matched pull request buildrequests: { len (matches )} " )
920890 lines .append ("" )
921891
922892 if matches :
@@ -934,9 +904,14 @@ def run(self):
934904 lines .append ("Actions:" )
935905 lines .extend (f" { a } " for a in actions )
936906 else :
937- lines .append ("No matching cancelable buildrequests found on this builder." )
907+ lines .append (
908+ "No matching pull request buildrequests found on this builder."
909+ )
938910
939911 self .addCompleteLog ("duplicate-buildrequests" , "\n " .join (lines ) + "\n " )
912+ if matches and not self .dry_run :
913+ self .build .stopBuild ("Superseded by pull request build for same commit" )
914+ return CANCELLED
940915 return SUCCESS
941916
942917
0 commit comments