[IMP] runbot: add trigger cross dependency

This commit is contained in:
Xavier-Do 2024-03-29 11:12:27 +01:00
parent 86b88d86c8
commit e9cdcdc807
16 changed files with 237 additions and 47 deletions

View File

@ -6,7 +6,7 @@
'author': "Odoo SA",
'website': "http://runbot.odoo.com",
'category': 'Website',
'version': '5.5',
'version': '5.6',
'application': True,
'depends': ['base', 'base_automation', 'website'],
'data': [

View File

@ -232,6 +232,7 @@ class Runbot(Controller):
batch = bundle.sudo()._force()
batch._log('Batch forced by %s', request.env.user.name)
batch._prepare(auto_rebase)
batch._process()
return werkzeug.utils.redirect('/runbot/batch/%s' % batch.id)
@route(['/runbot/batch/<int:batch_id>'], website=True, auth='public', type='http', sitemap=False)

View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
import logging
def migrate(cr, version):
cr.execute('ALTER TABLE runbot_build ADD COLUMN create_batch_id INT')

View File

@ -109,14 +109,16 @@ class Batch(models.Model):
def _process(self):
processed = self.browse()
for batch in self:
if batch.state == 'preparing' and batch.last_update < fields.Datetime.now() - datetime.timedelta(seconds=60):
if batch.state == 'preparing' and batch.last_update <= fields.Datetime.now() - datetime.timedelta(seconds=60):
batch._prepare()
processed |= batch
elif batch.state == 'ready' and all(slot.build_id.global_state in (False, 'running', 'done') for slot in batch.slot_ids):
_logger.info('Batch %s is done', self.id)
batch._log('Batch done')
batch.state = 'done'
processed |= batch
if batch.state == 'ready':
self._start_builds()
if all(slot.build_id.global_state in (False, 'running', 'done') for slot in batch.slot_ids):
_logger.info('Batch %s is done', self.id)
batch._log('Batch done')
batch.state = 'done'
processed |= batch
return processed
def _create_build(self, params):
@ -326,7 +328,6 @@ class Batch(models.Model):
for commit_link in self.commit_link_ids:
commit_link.commit_id = commit_link.commit_id._rebase_on(commit_link.base_commit_id)
commit_link_by_repos = {commit_link.commit_id.repo_id.id: commit_link for commit_link in self.commit_link_ids}
bundle_repos = bundle.branch_ids.mapped('remote_id.repo_id')
version_id = self.bundle_id.version_id.id
project_id = self.bundle_id.project_id.id
trigger_customs = {}
@ -360,19 +361,11 @@ class Batch(models.Model):
params = self.env['runbot.build.params'].create(params_value)
build = self.env['runbot.build']
link_type = 'created'
force_trigger = trigger_custom and trigger_custom.start_mode == 'force'
skip_trigger = (trigger_custom and trigger_custom.start_mode == 'disabled') or trigger.manual
should_start = ((trigger.repo_ids & bundle_repos) or bundle.build_all or bundle.sticky)
if force_trigger or (should_start and not skip_trigger): # only auto link build if bundle has a branch for this trigger
link_type, build = self._create_build(params)
self.env['runbot.batch.slot'].create({
'batch_id': self.id,
'trigger_id': trigger.id,
'build_id': build.id,
'params_id': params.id,
'link_type': link_type,
'link_type': 'created',
})
######################################
@ -388,6 +381,29 @@ class Batch(models.Model):
])
skippable._skip()
def _start_builds(self):
self.ensure_one()
bundle = self.bundle_id
bundle_repos = bundle.branch_ids.mapped('remote_id.repo_id')
success_trigger = self.slot_ids.filtered(lambda s: s.build_id.global_state in ('running', 'done') and s.build_id.global_result == "ok").trigger_id
trigger_customs = {}
for trigger_custom in self.bundle_id.trigger_custom_ids:
trigger_customs[trigger_custom.trigger_id] = trigger_custom
for slot in self.slot_ids:
if slot.build_id:
continue
trigger = slot.trigger_id
if trigger.starts_after_ids - success_trigger: # some required triggers are missing
continue
trigger_custom = trigger_customs.get(trigger, self.env['runbot.bundle.trigger.custom'])
force_trigger = trigger_custom and trigger_custom.start_mode == 'force'
skip_trigger = (trigger_custom and trigger_custom.start_mode == 'disabled') or trigger.manual
should_start = ((trigger.repo_ids & bundle_repos) or bundle.build_all or bundle.sticky)
if force_trigger or (should_start and not skip_trigger):
slot.link_type, slot.build_id = self._create_build(slot.params_id)
def _update_commits_infos(self, base_head_per_repo):
for link_commit in self.commit_link_ids:
commit = link_commit.commit_id

View File

@ -158,6 +158,7 @@ class BuildResult(models.Model):
version_id = fields.Many2one('runbot.version', related='params_id.version_id', store=True, index=True)
config_id = fields.Many2one('runbot.build.config', related='params_id.config_id', store=True, index=True)
trigger_id = fields.Many2one('runbot.trigger', related='params_id.trigger_id', store=True, index=True)
create_batch_id = fields.Many2one('runbot.batch', related='params_id.create_batch_id', store=True, index=True)
# state machine
global_state = fields.Selection(make_selection(state_order), string='Status', compute='_compute_global_state', store=True, recursive=True)

View File

@ -29,6 +29,13 @@ class ModuleFilter(models.Model):
description = fields.Char(string="Description")
class TriggerDependency(models.Model):
_name = 'runbot.trigger.dependency'
_description = 'Trigger Dependency'
dependency_id = fields.Many2one('runbot.trigger', string="Dependency", required=True)
dependant_id = fields.Many2one('runbot.trigger', string="Dependant", required=True)
class Trigger(models.Model):
"""
List of repo parts that must be part of the same bundle
@ -46,6 +53,21 @@ class Trigger(models.Model):
project_id = fields.Many2one('runbot.project', string="Project id", required=True)
repo_ids = fields.Many2many('runbot.repo', relation='runbot_trigger_triggers', string="Triggers", domain="[('project_id', '=', project_id)]")
dependency_ids = fields.Many2many('runbot.repo', relation='runbot_trigger_dependencies', string="Dependencies")
starts_before_ids = fields.Many2many(
'runbot.trigger',
string="Start before",
relation='runbot_trigger_dependency',
column1='dependency_id',
column2='dependant_id',
)
starts_after_ids = fields.Many2many(
'runbot.trigger',
string="Start after",
relation='runbot_trigger_dependency',
column2='dependency_id',
column1='dependant_id',
)
module_filters = fields.One2many('runbot.module.filter', 'trigger_id', string="Module filters", help='Will be combined with repo module filters when used with this trigger')
config_id = fields.Many2one('runbot.build.config', string="Config", required=True)
batch_dependent = fields.Boolean('Batch Dependent', help="Force adding batch in build parameters to make it unique and give access to bundle")

View File

@ -139,7 +139,7 @@ class Runbot(models.AbstractModel):
non_allocated_domain = expression.AND([non_allocated_domain, domain])
e = expression.expression(non_allocated_domain, self.env['runbot.build'])
query = e.query
query.order = '"runbot_build".parent_path'
query.order = 'runbot_build.create_batch_id'
select_query, select_params = query.select()
# self-assign to be sure that another runbot batch cannot self assign the same builds
query = """UPDATE

View File

@ -67,6 +67,9 @@ access_runbot_build_stat_regex_admin,access_runbot_build_stat_regex_admin,runbot
access_runbot_trigger_user,access_runbot_trigger_user,runbot.model_runbot_trigger,runbot.group_user,1,0,0,0
access_runbot_trigger_runbot_admin,access_runbot_trigger_runbot_admin,runbot.model_runbot_trigger,runbot.group_runbot_admin,1,1,1,1
access_runbot_trigger_dependency_user,access_runbot_trigger_dependency_user,runbot.model_runbot_trigger_dependency,runbot.group_user,1,0,0,0
access_runbot_trigger_dependency_runbot_admin,access_runbot_trigger_dependency_runbot_admin,runbot.model_runbot_trigger_dependency,runbot.group_runbot_admin,1,1,1,1
access_runbot_module_filter_user,access_runbot_module_filter_user,runbot.model_runbot_module_filter,runbot.group_user,1,0,0,0
access_runbot_module_filter_runbot_admin,access_runbot_module_filter_runbot_admin,runbot.model_runbot_module_filter,runbot.group_runbot_admin,1,1,1,1
@ -135,3 +138,5 @@ access_runbot_trigger_custom_wizard,access_runbot_trigger_custom_wizard,model_ru
access_runbot_build_stat_regex_wizard,access_runbot_build_stat_regex_wizard,model_runbot_build_stat_regex_wizard,runbot.group_runbot_admin,1,1,1,1
access_runbot_host_message,access_runbot_host_message,runbot.model_runbot_host_message,runbot.group_runbot_admin,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
67 access_runbot_project_runbot_admin access_runbot_version_runbot_admin access_runbot_project_runbot_admin access_runbot_version_runbot_admin runbot.model_runbot_project runbot.model_runbot_version runbot.group_runbot_admin 1 1 1 1
68 access_runbot_bundle_user access_runbot_project_user access_runbot_bundle_user access_runbot_project_user runbot.model_runbot_bundle runbot.model_runbot_project runbot.group_user 1 0 0 0
69 access_runbot_bundle_runbot_admin access_runbot_project_runbot_admin access_runbot_bundle_runbot_admin access_runbot_project_runbot_admin runbot.model_runbot_bundle runbot.model_runbot_project runbot.group_runbot_admin 1 1 1 1
70 access_runbot_bundle_user access_runbot_bundle_user runbot.model_runbot_bundle runbot.group_user 1 0 0 0
71 access_runbot_bundle_runbot_admin access_runbot_bundle_runbot_admin runbot.model_runbot_bundle runbot.group_runbot_admin 1 1 1 1
72 access_runbot_batch_user access_runbot_batch_user runbot.model_runbot_batch runbot.group_user 1 0 0 0
73 access_runbot_batch_user access_runbot_batch_runbot_admin access_runbot_batch_user access_runbot_batch_runbot_admin runbot.model_runbot_batch runbot.group_user runbot.group_runbot_admin 1 0 1 0 1 0 1
74 access_runbot_batch_runbot_admin access_runbot_batch_slot_user access_runbot_batch_runbot_admin access_runbot_batch_slot_user runbot.model_runbot_batch runbot.model_runbot_batch_slot runbot.group_runbot_admin runbot.group_user 1 1 0 1 0 1 0
75 access_runbot_batch_slot_user access_runbot_batch_slot_runbot_admin access_runbot_batch_slot_user access_runbot_batch_slot_runbot_admin runbot.model_runbot_batch_slot runbot.group_user runbot.group_runbot_admin 1 0 1 0 1 0 1
138
139
140
141
142

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import datetime
import time
from odoo import fields
from odoo.tests.common import TransactionCase
from unittest.mock import patch, DEFAULT
@ -249,7 +250,8 @@ class RunbotCase(TransactionCase):
self.assertEqual(triggers.repo_ids + triggers.dependency_ids, self.remote_addons.repo_id + self.remote_server.repo_id)
batch = self.branch_addons.bundle_id._force()
batch._prepare()
batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch._process()
class RunbotCaseMinimalSetup(RunbotCase):

View File

@ -90,7 +90,8 @@ class TestBuildParams(RunbotCaseMinimalSetup):
# prepare last_batch
bundle = self.env['runbot.bundle'].search([('name', '=', branch_a_name), ('project_id', '=', self.project.id)])
bundle.last_batch._prepare()
bundle.last_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
bundle.last_batch._process()
build_slot = bundle.last_batch.slot_ids.filtered(lambda rec: rec.trigger_id == self.trigger_server)
self.assertEqual(build_slot.build_id.params_id.config_id, self.trigger_server.config_id)
self.assertEqual(build_slot.build_id.description, expected_description, "A build description should reflect the trigger description")
@ -118,11 +119,68 @@ class TestBuildParams(RunbotCaseMinimalSetup):
'bundle_id': bundle.id,
'config_id': custom_config.id
})
bundle.last_batch._prepare()
bundle.last_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
bundle.last_batch._process()
build_slot = bundle.last_batch.slot_ids.filtered(lambda rec: rec.trigger_id == self.trigger_server)
self.assertEqual(build_slot.build_id.params_id.config_id, custom_config)
def test_trigger_dependency(self):
self.start_patchers()
self.additionnal_setup()
self.assertEqual(self.project.trigger_ids, self.trigger_server | self.trigger_addons)
minimal_config = self.env['runbot.build.config'].create({'name': 'Minimal Check'})
other_triggers = self.project.trigger_ids
self.assertEqual(other_triggers.mapped('name'), ['Server trigger', 'Addons trigger'])
trigger_minimal_check = self.Trigger.create({
'sequence': 0,
'name': 'minimal_check',
'repo_ids': [(4, self.repo_addons.id), (4, self.repo_server.id)],
'config_id': minimal_config.id,
'project_id': self.project.id,
'starts_before_ids': other_triggers.ids,
})
self.assertEqual(self.trigger_server.starts_after_ids, trigger_minimal_check)
self.assertEqual(self.trigger_addons.starts_after_ids, trigger_minimal_check)
branch_a_name = 'master-test-something'
self.push_commit(self.remote_server_dev, branch_a_name, 'nice subject', sha='d0d0caca')
self.repo_server._update_batches()
bundle = self.Bundle.search([('name', '=', branch_a_name), ('project_id', '=', self.project.id)])
batch = bundle.last_batch
batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch._process()
self.assertEqual(batch.slot_ids.mapped('trigger_id.name'), ['minimal_check', 'Server trigger', 'Addons trigger'], 'All three slot should have been created')
minimal_check_build = batch.slot_ids.build_id
self.assertEqual(len(minimal_check_build), 1, 'Only minimal check should have started')
self.assertEqual(minimal_check_build.trigger_id.name, 'minimal_check', 'Only minimal check should have started')
with self.env.cr.savepoint() as sp:
minimal_check_build.local_result = 'ko'
minimal_check_build.local_state = 'done'
batch._process()
all_builds = batch.slot_ids.build_id
self.assertEqual(len(all_builds), 1, 'Only minimal check should have started')
self.assertEqual(batch.state, 'done')
sp.rollback()
minimal_check_build.local_result = 'ok'
minimal_check_build.local_state = 'done'
batch._process()
all_builds = batch.slot_ids.build_id
self.assertEqual(
all_builds.trigger_id.mapped('name'),
['minimal_check', 'Server trigger'],
'Other builds should have started (server only since addons was not updated)',
)
self.assertEqual(batch.state, 'ready')
self.assertEqual(all_builds.mapped('local_state'), ['done', 'pending'])
server_builds = all_builds[1]
server_builds.local_result = 'ok'
server_builds.local_state = 'done'
batch._process()
self.assertEqual(batch.state, 'done')
class TestBuildResult(RunbotCase):
@ -558,11 +616,14 @@ class TestGc(RunbotCaseMinimalSetup):
# prepare last_batch
bundle_a = self.env['runbot.bundle'].search([('name', '=', branch_a_name)])
bundle_a.last_batch._prepare()
bundle_a.last_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
bundle_a.last_batch._process()
# now we should have a build in pending state in the bundle
self.assertEqual(len(bundle_a.last_batch.slot_ids), 2)
build_a = bundle_a.last_batch.slot_ids[0].build_id
self.assertEqual(build_a.local_state, 'pending')
self.assertEqual(build_a.local_state, 'pending')
self.assertEqual(build_a.global_state, 'pending')
# now another commit is found in another branch
@ -570,7 +631,9 @@ class TestGc(RunbotCaseMinimalSetup):
self.push_commit(self.remote_server_dev, branch_b_name, 'other subject', sha='cacad0d0')
self.repo_server._update_batches()
bundle_b = self.env['runbot.bundle'].search([('name', '=', branch_b_name)])
bundle_b.last_batch._prepare()
bundle_b.last_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
bundle_b.last_batch._process()
build_b = bundle_b.last_batch.slot_ids[0].build_id
@ -588,7 +651,8 @@ class TestGc(RunbotCaseMinimalSetup):
self.push_commit(self.remote_server_dev, branch_a_name, 'new subject', sha='d0cad0ca')
self.repo_server._update_batches()
bundle_a = self.env['runbot.bundle'].search([('name', '=', branch_a_name)])
bundle_a.last_batch._prepare()
bundle_a.last_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
bundle_a.last_batch._process()
build_a_last = bundle_a.last_batch.slot_ids[0].build_id
self.assertEqual(build_a_last.local_state, 'pending')
self.assertTrue(build_a.killable, 'The previous build in the batch should be killable')

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import datetime
from unittest.mock import patch, mock_open
from odoo import Command
from odoo import Command, fields
from odoo.tools import mute_logger
from odoo.exceptions import UserError
from odoo.addons.runbot.common import RunbotException
@ -219,7 +220,8 @@ class TestBuildConfigStepRestore(TestBuildConfigStepCommon):
# setup master branch
master_batch = self.master_bundle._force()
with mute_logger('odoo.addons.runbot.models.batch'):
master_batch._prepare()
master_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
master_batch._process()
reference_slot = master_batch.slot_ids
trigger = reference_slot.trigger_id
self.assertEqual(trigger.name, 'Server trigger', 'Just checking that we have a single slot')
@ -246,7 +248,8 @@ class TestBuildConfigStepRestore(TestBuildConfigStepCommon):
# create dev build
dev_batch = self.dev_bundle._force()
with mute_logger('odoo.addons.runbot.models.batch'):
dev_batch._prepare()
dev_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
dev_batch._process()
dev_batch.base_reference_batch_id = master_batch # not tested, this is not the purpose of this test
dev_build = dev_batch.slot_ids.build_id
self.assertEqual(dev_build.params_id.config_data, config_data)

View File

@ -1,12 +1,16 @@
# -*- coding: utf-8 -*-
import datetime
import logging
import time
import re
from unittest import skip
from unittest.mock import patch, Mock
from subprocess import CalledProcessError
from odoo import fields
from odoo.tests import common, TransactionCase
from odoo.tools import mute_logger
import logging
import time
from .common import RunbotCase, RunbotCaseMinimalSetup
@ -248,7 +252,8 @@ class TestRepo(RunbotCaseMinimalSetup):
return {}
self.patchers['github_patcher'].side_effect = github2
last_batch._prepare()
bundle.last_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
bundle.last_batch._process()
self.assertEqual(last_batch.commit_link_ids.commit_id.mapped('subject'), ['Server subject', 'Addons subject'])
self.assertEqual(last_batch.state, 'ready')

View File

@ -1,5 +1,7 @@
import datetime
import getpass
import logging
from odoo import fields
from unittest.mock import patch, mock_open
from odoo.exceptions import UserError
from odoo.tools import mute_logger
@ -206,7 +208,8 @@ class TestUpgradeFlow(RunbotCase):
# create nightly
batch_nigthly = bundle._force(self.nightly_category.id)
batch_nigthly._prepare()
batch_nigthly.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch_nigthly._process()
self.assertEqual(batch_nigthly.category_id, self.nightly_category)
builds_nigthly = {}
host = self.env['runbot.host']._get_current()
@ -232,7 +235,8 @@ class TestUpgradeFlow(RunbotCase):
batch_nigthly.state = 'done'
batch_weekly = bundle._force(self.weekly_category.id)
batch_weekly._prepare()
batch_weekly.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch_weekly._process()
self.assertEqual(batch_weekly.category_id, self.weekly_category)
builds_weekly = {}
build = batch_weekly.slot_ids.filtered(lambda s: s.trigger_id == self.trigger_addons_weekly).build_id
@ -249,7 +253,8 @@ class TestUpgradeFlow(RunbotCase):
batch_weekly.state = 'done'
batch_default = bundle._force()
batch_default._prepare()
batch_default.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch_default._process()
build = batch_default.slot_ids.filtered(lambda s: s.trigger_id == self.trigger_server).build_id
build.local_state = 'done'
batch_default.state = 'done'
@ -268,7 +273,8 @@ class TestUpgradeFlow(RunbotCase):
self.trigger_upgrade_server.flush_recordset(['upgrade_step_id'])
batch = self.master_bundle._force()
batch._prepare()
batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch._process()
upgrade_current_build = batch.slot_ids.filtered(lambda slot: slot.trigger_id == self.trigger_upgrade_server).build_id
#host = self.env['runbot.host']._get_current()
#upgrade_current_build.host = host.name
@ -334,7 +340,8 @@ class TestUpgradeFlow(RunbotCase):
})
batch = self.master_bundle._force(self.nightly_category.id)
batch._prepare()
batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch._process()
upgrade_nightly = batch.slot_ids.filtered(lambda slot: slot.trigger_id == trigger_upgrade_addons_nightly).build_id
#upgrade_nightly.host = host.name
upgrade_nightly._schedule()
@ -484,7 +491,8 @@ class TestUpgradeFlow(RunbotCase):
# test_build_references
batch = self.master_bundle._force()
batch._prepare()
batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch._process()
upgrade_slot = batch.slot_ids.filtered(lambda slot: slot.trigger_id == self.trigger_upgrade_server)
self.assertTrue(upgrade_slot)
upgrade_build = upgrade_slot.build_id
@ -501,7 +509,8 @@ class TestUpgradeFlow(RunbotCase):
self.trigger_upgrade_server.upgrade_step_id.upgrade_from_all_intermediate_version = True
batch = self.master_bundle._force()
batch._prepare()
batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch._process()
upgrade_build = batch.slot_ids.filtered(lambda slot: slot.trigger_id == self.trigger_upgrade_server).build_id
self.assertEqual(
upgrade_build.params_id.builds_reference_ids,
@ -539,7 +548,8 @@ class TestUpgradeFlow(RunbotCase):
self.assertEqual(bundle_133.name, 'saas-13.3')
batch13 = bundle_13._force()
batch13._prepare()
batch13.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
batch13._process()
upgrade_complement_build_13 = batch13.slot_ids.filtered(lambda slot: slot.trigger_id == trigger_upgrade_complement).build_id
# upgrade_complement_build_13.host = host.name
self.assertEqual(upgrade_complement_build_13.params_id.config_id, config_upgrade_complement)

View File

@ -14,8 +14,14 @@
<menuitem name="Hosts" id="runbot_menu_host_tree" parent="runbot_menu_root" sequence="300" action="open_view_host_tree" groups="runbot.group_runbot_admin"/>
<menuitem id="runbot_menu_trigger" parent="runbot_menu_root" sequence="500" action="runbot_triggers_action" groups="runbot.group_runbot_admin"/>
<menuitem id="runbot_menu_trigger_root" parent="runbot_menu_root" sequence="500" name="Triggers" groups="runbot.group_runbot_admin"/>
<menuitem id="runbot_menu_trigger" parent="runbot_menu_trigger_root" sequence="501" action="runbot_triggers_action" groups="runbot.group_runbot_admin"/>
<menuitem id="runbot_menu_trigger_dependency" parent="runbot_menu_trigger_root" sequence="502" action="runbot_triggers_dependency_action" groups="runbot.group_runbot_admin"/>
<menuitem name="Configs" id="runbot_menu_configs" parent="runbot_menu_root" sequence="600" groups="runbot.group_build_config_user"/>
<menuitem id="runbot_menu_job_config_tree" parent="runbot_menu_configs" sequence="10" action="open_view_job_config_tree"/>
<menuitem id="runbot_menu_job_tree" parent="runbot_menu_configs" sequence="20" action="open_view_job_tree"/>

View File

@ -33,6 +33,20 @@
<group string="Dependencies">
<field name="dependency_ids" nolabel="1" colspan="2"/>
</group>
<group string="Starts after" invisible="manual" colspan="2">
<field
name="starts_after_ids"
domain="[('category_id', '=', category_id), ('manual', '=', False), ('project_id', '=', project_id), ('id', '!=', id), ('id', 'not in', starts_before_ids)]"
widget="many2many_tags">
</field>
</group>
<group string="Starts before" invisible="manual" colspan="2">
<field
name="starts_before_ids"
domain="[('category_id', '=', category_id), ('manual', '=', False), ('project_id', '=', project_id), ('id', '!=', id), ('id', 'not in', starts_after_ids)]"
widget="many2many_tags">
</field>
</group>
<group string="Module filters">
<field name="module_filters" nolabel="1" colspan="4">
<tree string="Module filters" editable="bottom">
@ -85,12 +99,40 @@
<field name="ci_context"/>
<field name="repo_ids" widget="many2many_tags"/>
<field name="dependency_ids" widget="many2many_tags"/>
<field name="starts_after_ids" widget="many2many_tags"/>
<field name="manual"/>
</tree>
</field>
</record>
<record id="repo_trigger_dependency_form" model="ir.ui.view">
<field name="name">runbot.trigger.dependency.form</field>
<field name="model">runbot.trigger.dependency</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="dependency_id"/>
<field name="dependant_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="repo_trigger_catgory_form" model="ir.ui.view">
<record id="repo_trigger_dependency_tree" model="ir.ui.view">
<field name="name">runbot.trigger.dependency.tree</field>
<field name="model">runbot.trigger.dependency</field>
<field name="arch" type="xml">
<tree>
<field name="dependency_id"/>
<field name="dependant_id"/>
</tree>
</field>
</record>
<record id="repo_trigger_category_form" model="ir.ui.view">
<field name="name">runbot.category.form</field>
<field name="model">runbot.category</field>
<field name="arch" type="xml">
@ -224,10 +266,17 @@
</record>
<record id="runbot_triggers_action" model="ir.actions.act_window">
<field name="name">Triggers</field>
<field name="res_model">runbot.trigger</field>
<field name="view_mode">tree,form</field>
</record>
<field name="name">Triggers</field>
<field name="res_model">runbot.trigger</field>
<field name="view_mode">tree,form</field>
</record>
<record id="runbot_triggers_dependency_action" model="ir.actions.act_window">
<field name="name">Triggers dependency</field>
<field name="res_model">runbot.trigger.dependency</field>
<field name="view_mode">tree,form</field>
</record>
<record id="runbot_remotes_action" model="ir.actions.act_window">
<field name="name">Remotes</field>
<field name="res_model">runbot.remote</field>

View File

@ -115,8 +115,7 @@ class Runbot(models.AbstractModel):
mock_git.side_effect = git
with mute_logger('odoo.addons.runbot.models.batch'):
batch._prepare()
batch._process()
if i != nb_batch - 1:
for slot in batch.slot_ids:
if slot.build_id: