@@ -345,10 +345,15 @@ class BuildResult(models.Model):
345345 string = 'Build type' )
346346
347347 parent_id = fields .Many2one ('runbot.build' , 'Parent Build' , index = True )
348+ parent_link_ids = fields .One2many ('runbot.build.link' , 'child_id' , string = 'Used in links' )
349+ linked_parent_ids = fields .Many2many ('runbot.build' , compute = '_compute_linked_parent_ids' , string = 'All parent builds' )
350+
351+ child_link_ids = fields .One2many ('runbot.build.link' , 'parent_id' , string = 'Child links' )
352+ linked_children_ids = fields .Many2many ('runbot.build' , compute = '_compute_linked_child_ids' , string = 'All child builds' )
353+
348354 parent_path = fields .Char ('Parent path' , index = True )
349355 top_parent = fields .Many2one ('runbot.build' , compute = '_compute_top_parent' )
350356 ancestors = fields .Many2many ('runbot.build' , compute = '_compute_ancestors' )
351- # should we add a has children stored boolean?
352357 children_ids = fields .One2many ('runbot.build' , 'parent_id' )
353358
354359 # config of top_build is inherithed from params, but subbuild will have different configs
@@ -385,12 +390,22 @@ def _compute_host_id(self):
385390 for record in self :
386391 record .host_id = get_host (record .host )
387392
393+ def _compute_linked_parent_ids (self ):
394+ for build in self :
395+ build .linked_parent_ids = build .parent_link_ids .parent_id
396+
397+ def _compute_linked_child_ids (self ):
398+ for build in self :
399+ build .linked_child_ids = build .child_link_ids .child_id
400+
388401 def _update_global_state (self ):
389402 for record in self :
390403 waiting_score = record ._get_state_score ('waiting' )
391- children_ids = [child for child in record .children_ids if not child .orphan_result ]
392- if record ._get_state_score (record .local_state ) > waiting_score and children_ids : # if finish, check children
393- children_state = record ._get_youngest_state ([child .global_state for child in children_ids ])
404+ children_ids = [child .id for child in record .children_ids if not child .orphan_result ]
405+ children_ids += [link .child_id .id for link in record .child_link_ids if not link .orphan_result ]
406+ children = self .browse (children_ids )
407+ if record ._get_state_score (record .local_state ) > waiting_score and children : # if finish, check children
408+ children_state = record ._get_youngest_state ([child .global_state for child in children ])
394409 if record ._get_state_score (children_state ) > waiting_score :
395410 record .global_state = record .local_state
396411 else :
@@ -403,9 +418,11 @@ def _update_global_result(self):
403418 if record .local_result and record ._get_result_score (record .local_result ) >= record ._get_result_score ('ko' ):
404419 record .global_result = record .local_result
405420 else :
406- children_ids = [child for child in record .children_ids if not child .orphan_result ]
407- if children_ids :
408- children_result = record ._get_worst_result ([child .global_result for child in children_ids ], max_res = 'ko' )
421+ children_ids = [child .id for child in record .children_ids if not child .orphan_result ]
422+ children_ids += [link .child_id .id for link in record .child_link_ids if not link .orphan_result ]
423+ children = self .browse (children_ids )
424+ if children :
425+ children_result = record ._get_worst_result ([child .global_result for child in children ], max_res = 'ko' )
409426 if record .local_result :
410427 record .global_result = record ._get_worst_result ([record .local_result , children_result ])
411428 else :
@@ -548,7 +565,7 @@ def write(self, values):
548565
549566 return res
550567
551- def _add_child (self , param_values , orphan = False , description = False , additionnal_commit_links = False ):
568+ def _add_child (self , param_values , orphan = False , description = False , additionnal_commit_links = False , link = False ):
552569 build_values = {key : value for key , value in param_values .items () if key not in self .params_id ._fields }
553570 param_values = {key : value for key , value in param_values .items () if key in self .params_id ._fields }
554571
@@ -561,17 +578,40 @@ def _add_child(self, param_values, orphan=False, description=False, additionnal_
561578 commit_link_ids |= additionnal_commit_links
562579 param_values ['commit_link_ids' ] = commit_link_ids
563580
564- return self .create ({
565- 'params_id' : self .params_id .copy (param_values ).id ,
566- 'parent_id' : self .id ,
581+ params = self .params_id .copy (param_values )
582+
583+ build_values = {
584+ 'params_id' : params .id ,
567585 'build_type' : self .build_type ,
568586 'priority_level' : self .priority_level ,
569587 'description' : description ,
570588 'orphan_result' : orphan ,
571589 'keep_host' : self .keep_host ,
572590 'host' : self .host if self .keep_host else False ,
573591 ** build_values ,
574- })
592+ }
593+
594+ if link :
595+ existing_builds = params .build_ids
596+ if self .keep_host :
597+ existing_builds = existing_builds .filtered (lambda b : b .host == self .host )
598+ if existing_builds :
599+ build = existing_builds .sorted ('id' )[- 1 ]
600+ build .killable = False
601+
602+ if build :
603+ build = self .create (build_values )
604+
605+ self .env ['runbot.build.link' ].create ({
606+ 'parent_id' : self .id ,
607+ 'child_id' : link ,
608+ })
609+ return build
610+ else :
611+ return self .create ({
612+ 'parent_id' : self .id ,
613+ ** build_values ,
614+ })
575615
576616 @api .depends ('params_id.version_id.name' )
577617 def _compute_dest (self ):
@@ -634,6 +674,7 @@ def _compute_last_update(self):
634674 def _compute_load_time (self ):
635675 for build in self :
636676 build .load_time = sum ([build .build_time ] + [child .load_time for child in build .children_ids ])
677+ # TODO check, we don't count linked childrent in load time to avoid duplicate, but we need to ensure we take them into account
637678
638679 @api .depends ('job_start' )
639680 def _compute_build_age (self ):
@@ -663,6 +704,15 @@ def _rebuild(self, message=None):
663704 self .orphan_result = True
664705
665706 new_build = self .create (values )
707+
708+ if self .parent_link_ids : # TODO check, should we forbid rebuild in some cases if we have multiple parents? Or just link to an active parent?
709+ for link in self .parent_link_ids :
710+ link .orphan_result = True
711+ self .env ['runbot.build.link' ].create ({
712+ 'parent_id' : link .parent_id .id ,
713+ 'child_id' : new_build .id ,
714+ })
715+
666716 if self .parent_id :
667717 new_build ._github_status () # not sure this is needed since creating a child should trigger an update of parent global state.
668718 user = self .env .user
@@ -1650,5 +1700,5 @@ class BuildLink(models.Model):
16501700
16511701 parent_id = fields .Many2one ('runbot.build' , string = 'Parent Build' , required = True , ondelete = 'cascade' )
16521702 child_id = fields .Many2one ('runbot.build' , string = 'Child Build' , required = True , ondelete = 'cascade' )
1653- params_id = fields .Many2one ('runbot.params' , string = 'Params' , related = 'child_id.params_id' , store = True )
1654-
1703+ params_id = fields .Many2one ('runbot.build. params' , string = 'Params' , related = 'child_id.params_id' , store = True )
1704+ orphan_result = fields . Boolean ( string = 'Orphan Result' , help = 'If set, the result of the child build will not be taken into account for the parent build result' )
0 commit comments