Skip to content

Commit 5a7d8ce

Browse files
committed
wip
1 parent 3786efc commit 5a7d8ce

4 files changed

Lines changed: 86 additions & 22 deletions

File tree

runbot/controllers/frontend.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ def build(self, build_id, search=None, from_batch=None, **post):
306306
if not build.exists():
307307
return request.not_found()
308308
siblings = (build.parent_id.children_ids if build.parent_id else from_batch.slot_ids.build_id if from_batch else build).sorted('id')
309+
# TODO FIXME for linked builds. Sibling may depends on the context of the batch
309310
context = {
310311
'build': build,
311312
'from_batch': from_batch,

runbot/models/build.py

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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')

runbot/models/build_config.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,7 @@ def get_reference_builds_for_versions(versions):
10131013
'version_id': target.params_id.version_id.id,
10141014
'trigger_id': None,
10151015
'dockerfile_id': target.params_id.dockerfile_id.id,
1016-
})
1016+
}, link=True)
10171017
source_description = source.params_id.version_id.name
10181018
target_description = target.params_id.version_id.name
10191019
if source in build.create_batch_id.slot_ids.build_id:
@@ -1026,12 +1026,12 @@ def get_reference_builds_for_versions(versions):
10261026
db.name,
10271027
)
10281028

1029-
if self.allow_similar_build_quick_result:
1030-
existing_done_build = next((build for build in child.params_id.build_ids.sorted('id') if build.global_state == 'done' and build.local_result not in ('skipped', 'killed')), None)
1031-
if existing_done_build:
1032-
child._log('', 'A similar [build](%s) has been found, marking as done directly', existing_done_build.build_url, log_type='markdown')
1033-
child.local_state = 'done'
1034-
child.local_result = existing_done_build.local_result
1029+
#if self.allow_similar_build_quick_result:
1030+
# existing_done_build = next((build for build in child.params_id.build_ids.sorted('id') if build.global_state == 'done' and build.local_result not in ('skipped', 'killed')), None)
1031+
# if existing_done_build:
1032+
# child._log('', 'A similar [build](%s) has been found, marking as done directly', existing_done_build.build_url, log_type='markdown')
1033+
# child.local_state = 'done'
1034+
# child.local_result = existing_done_build.local_result
10351035

10361036
def _filter_upgrade_database(self, dbs, pattern):
10371037
pat_list = pattern.split(',') if pattern else []

runbot/models/runbot.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,22 @@ def _gc_testing(self, host):
131131
if available_slots > 0 or nb_pending == 0:
132132
return
133133

134+
killable_build = []
135+
134136
for build in testing_builds:
135137
if build.top_parent.killable:
136-
build.top_parent._ask_kill(message='Build automatically killed, new build found.')
138+
killable_build.append(build)
139+
continue
140+
if not build.parent_id and build.parent_ids:
141+
killable_build.append(build)
142+
continue
143+
144+
for build in killable_build:
145+
build._log('_ask_kill', "Build automatically killed, new build found.")
146+
if build.local_state == 'pending':
147+
build._skip()
148+
elif build.local_state in ['testing', 'running']:
149+
build.requested_action = 'deathrow'
137150

138151
def _allocate_builds(self, host, nb_slots, domain=None):
139152
if nb_slots <= 0:

0 commit comments

Comments
 (0)