mirror of
https://github.com/odoo/runbot.git
synced 2025-03-27 13:25:47 +07:00
[IMP] runbot: add trigger cross dependency
This commit is contained in:
parent
86b88d86c8
commit
9eb7f0d577
@ -6,7 +6,7 @@
|
|||||||
'author': "Odoo SA",
|
'author': "Odoo SA",
|
||||||
'website': "http://runbot.odoo.com",
|
'website': "http://runbot.odoo.com",
|
||||||
'category': 'Website',
|
'category': 'Website',
|
||||||
'version': '5.5',
|
'version': '5.6',
|
||||||
'application': True,
|
'application': True,
|
||||||
'depends': ['base', 'base_automation', 'website'],
|
'depends': ['base', 'base_automation', 'website'],
|
||||||
'data': [
|
'data': [
|
||||||
|
@ -232,6 +232,7 @@ class Runbot(Controller):
|
|||||||
batch = bundle.sudo()._force()
|
batch = bundle.sudo()._force()
|
||||||
batch._log('Batch forced by %s', request.env.user.name)
|
batch._log('Batch forced by %s', request.env.user.name)
|
||||||
batch._prepare(auto_rebase)
|
batch._prepare(auto_rebase)
|
||||||
|
batch._process()
|
||||||
return werkzeug.utils.redirect('/runbot/batch/%s' % batch.id)
|
return werkzeug.utils.redirect('/runbot/batch/%s' % batch.id)
|
||||||
|
|
||||||
@route(['/runbot/batch/<int:batch_id>'], website=True, auth='public', type='http', sitemap=False)
|
@route(['/runbot/batch/<int:batch_id>'], website=True, auth='public', type='http', sitemap=False)
|
||||||
|
7
runbot/migrations/17.0.5.6/pre-migration.py
Normal file
7
runbot/migrations/17.0.5.6/pre-migration.py
Normal 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')
|
@ -109,14 +109,16 @@ class Batch(models.Model):
|
|||||||
def _process(self):
|
def _process(self):
|
||||||
processed = self.browse()
|
processed = self.browse()
|
||||||
for batch in self:
|
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()
|
batch._prepare()
|
||||||
processed |= batch
|
processed |= batch
|
||||||
elif batch.state == 'ready' and all(slot.build_id.global_state in (False, 'running', 'done') for slot in batch.slot_ids):
|
if batch.state == 'ready':
|
||||||
_logger.info('Batch %s is done', self.id)
|
self._start_builds()
|
||||||
batch._log('Batch done')
|
if all(slot.build_id.global_state in (False, 'running', 'done') for slot in batch.slot_ids):
|
||||||
batch.state = 'done'
|
_logger.info('Batch %s is done', self.id)
|
||||||
processed |= batch
|
batch._log('Batch done')
|
||||||
|
batch.state = 'done'
|
||||||
|
processed |= batch
|
||||||
return processed
|
return processed
|
||||||
|
|
||||||
def _create_build(self, params):
|
def _create_build(self, params):
|
||||||
@ -326,7 +328,6 @@ class Batch(models.Model):
|
|||||||
for commit_link in self.commit_link_ids:
|
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.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}
|
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
|
version_id = self.bundle_id.version_id.id
|
||||||
project_id = self.bundle_id.project_id.id
|
project_id = self.bundle_id.project_id.id
|
||||||
trigger_customs = {}
|
trigger_customs = {}
|
||||||
@ -360,19 +361,11 @@ class Batch(models.Model):
|
|||||||
|
|
||||||
params = self.env['runbot.build.params'].create(params_value)
|
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({
|
self.env['runbot.batch.slot'].create({
|
||||||
'batch_id': self.id,
|
'batch_id': self.id,
|
||||||
'trigger_id': trigger.id,
|
'trigger_id': trigger.id,
|
||||||
'build_id': build.id,
|
|
||||||
'params_id': params.id,
|
'params_id': params.id,
|
||||||
'link_type': link_type,
|
'link_type': 'created',
|
||||||
})
|
})
|
||||||
|
|
||||||
######################################
|
######################################
|
||||||
@ -388,6 +381,29 @@ class Batch(models.Model):
|
|||||||
])
|
])
|
||||||
skippable._skip()
|
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):
|
def _update_commits_infos(self, base_head_per_repo):
|
||||||
for link_commit in self.commit_link_ids:
|
for link_commit in self.commit_link_ids:
|
||||||
commit = link_commit.commit_id
|
commit = link_commit.commit_id
|
||||||
|
@ -158,6 +158,7 @@ class BuildResult(models.Model):
|
|||||||
version_id = fields.Many2one('runbot.version', related='params_id.version_id', store=True, index=True)
|
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)
|
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)
|
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
|
# state machine
|
||||||
global_state = fields.Selection(make_selection(state_order), string='Status', compute='_compute_global_state', store=True, recursive=True)
|
global_state = fields.Selection(make_selection(state_order), string='Status', compute='_compute_global_state', store=True, recursive=True)
|
||||||
|
@ -29,6 +29,13 @@ class ModuleFilter(models.Model):
|
|||||||
description = fields.Char(string="Description")
|
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):
|
class Trigger(models.Model):
|
||||||
"""
|
"""
|
||||||
List of repo parts that must be part of the same bundle
|
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)
|
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)]")
|
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")
|
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')
|
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)
|
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")
|
batch_dependent = fields.Boolean('Batch Dependent', help="Force adding batch in build parameters to make it unique and give access to bundle")
|
||||||
|
@ -139,7 +139,7 @@ class Runbot(models.AbstractModel):
|
|||||||
non_allocated_domain = expression.AND([non_allocated_domain, domain])
|
non_allocated_domain = expression.AND([non_allocated_domain, domain])
|
||||||
e = expression.expression(non_allocated_domain, self.env['runbot.build'])
|
e = expression.expression(non_allocated_domain, self.env['runbot.build'])
|
||||||
query = e.query
|
query = e.query
|
||||||
query.order = '"runbot_build".parent_path'
|
query.order = 'runbot_build.create_batch_id'
|
||||||
select_query, select_params = query.select()
|
select_query, select_params = query.select()
|
||||||
# self-assign to be sure that another runbot batch cannot self assign the same builds
|
# self-assign to be sure that another runbot batch cannot self assign the same builds
|
||||||
query = """UPDATE
|
query = """UPDATE
|
||||||
|
@ -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_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_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_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
|
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_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
|
access_runbot_host_message,access_runbot_host_message,runbot.model_runbot_host_message,runbot.group_runbot_admin,1,0,0,0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
|
from odoo import fields
|
||||||
from odoo.tests.common import TransactionCase
|
from odoo.tests.common import TransactionCase
|
||||||
from unittest.mock import patch, DEFAULT
|
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)
|
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 = self.branch_addons.bundle_id._force()
|
||||||
batch._prepare()
|
batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
|
||||||
|
batch._process()
|
||||||
|
|
||||||
|
|
||||||
class RunbotCaseMinimalSetup(RunbotCase):
|
class RunbotCaseMinimalSetup(RunbotCase):
|
||||||
|
@ -90,7 +90,8 @@ class TestBuildParams(RunbotCaseMinimalSetup):
|
|||||||
|
|
||||||
# prepare last_batch
|
# prepare last_batch
|
||||||
bundle = self.env['runbot.bundle'].search([('name', '=', branch_a_name), ('project_id', '=', self.project.id)])
|
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)
|
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.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")
|
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,
|
'bundle_id': bundle.id,
|
||||||
'config_id': custom_config.id
|
'config_id': custom_config.id
|
||||||
})
|
})
|
||||||
|
bundle.last_batch.last_update = fields.Datetime.now() - datetime.timedelta(seconds=60)
|
||||||
bundle.last_batch._prepare()
|
bundle.last_batch._process()
|
||||||
build_slot = bundle.last_batch.slot_ids.filtered(lambda rec: rec.trigger_id == self.trigger_server)
|
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)
|
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):
|
class TestBuildResult(RunbotCase):
|
||||||
|
|
||||||
@ -558,11 +616,14 @@ class TestGc(RunbotCaseMinimalSetup):
|
|||||||
|
|
||||||
# prepare last_batch
|
# prepare last_batch
|
||||||
bundle_a = self.env['runbot.bundle'].search([('name', '=', branch_a_name)])
|
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
|
# now we should have a build in pending state in the bundle
|
||||||
self.assertEqual(len(bundle_a.last_batch.slot_ids), 2)
|
self.assertEqual(len(bundle_a.last_batch.slot_ids), 2)
|
||||||
build_a = bundle_a.last_batch.slot_ids[0].build_id
|
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')
|
self.assertEqual(build_a.global_state, 'pending')
|
||||||
|
|
||||||
# now another commit is found in another branch
|
# 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.push_commit(self.remote_server_dev, branch_b_name, 'other subject', sha='cacad0d0')
|
||||||
self.repo_server._update_batches()
|
self.repo_server._update_batches()
|
||||||
bundle_b = self.env['runbot.bundle'].search([('name', '=', branch_b_name)])
|
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
|
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.push_commit(self.remote_server_dev, branch_a_name, 'new subject', sha='d0cad0ca')
|
||||||
self.repo_server._update_batches()
|
self.repo_server._update_batches()
|
||||||
bundle_a = self.env['runbot.bundle'].search([('name', '=', branch_a_name)])
|
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
|
build_a_last = bundle_a.last_batch.slot_ids[0].build_id
|
||||||
self.assertEqual(build_a_last.local_state, 'pending')
|
self.assertEqual(build_a_last.local_state, 'pending')
|
||||||
self.assertTrue(build_a.killable, 'The previous build in the batch should be killable')
|
self.assertTrue(build_a.killable, 'The previous build in the batch should be killable')
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
from unittest.mock import patch, mock_open
|
from unittest.mock import patch, mock_open
|
||||||
from odoo import Command
|
from odoo import Command, fields
|
||||||
from odoo.tools import mute_logger
|
from odoo.tools import mute_logger
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
from odoo.addons.runbot.common import RunbotException
|
from odoo.addons.runbot.common import RunbotException
|
||||||
@ -219,7 +220,8 @@ class TestBuildConfigStepRestore(TestBuildConfigStepCommon):
|
|||||||
# setup master branch
|
# setup master branch
|
||||||
master_batch = self.master_bundle._force()
|
master_batch = self.master_bundle._force()
|
||||||
with mute_logger('odoo.addons.runbot.models.batch'):
|
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
|
reference_slot = master_batch.slot_ids
|
||||||
trigger = reference_slot.trigger_id
|
trigger = reference_slot.trigger_id
|
||||||
self.assertEqual(trigger.name, 'Server trigger', 'Just checking that we have a single slot')
|
self.assertEqual(trigger.name, 'Server trigger', 'Just checking that we have a single slot')
|
||||||
@ -246,7 +248,8 @@ class TestBuildConfigStepRestore(TestBuildConfigStepCommon):
|
|||||||
# create dev build
|
# create dev build
|
||||||
dev_batch = self.dev_bundle._force()
|
dev_batch = self.dev_bundle._force()
|
||||||
with mute_logger('odoo.addons.runbot.models.batch'):
|
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_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
|
dev_build = dev_batch.slot_ids.build_id
|
||||||
self.assertEqual(dev_build.params_id.config_data, config_data)
|
self.assertEqual(dev_build.params_id.config_data, config_data)
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from unittest import skip
|
from unittest import skip
|
||||||
from unittest.mock import patch, Mock
|
from unittest.mock import patch, Mock
|
||||||
from subprocess import CalledProcessError
|
from subprocess import CalledProcessError
|
||||||
|
|
||||||
|
from odoo import fields
|
||||||
from odoo.tests import common, TransactionCase
|
from odoo.tests import common, TransactionCase
|
||||||
from odoo.tools import mute_logger
|
from odoo.tools import mute_logger
|
||||||
import logging
|
|
||||||
import time
|
|
||||||
|
|
||||||
from .common import RunbotCase, RunbotCaseMinimalSetup
|
from .common import RunbotCase, RunbotCaseMinimalSetup
|
||||||
|
|
||||||
@ -248,7 +252,8 @@ class TestRepo(RunbotCaseMinimalSetup):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
self.patchers['github_patcher'].side_effect = github2
|
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.commit_link_ids.commit_id.mapped('subject'), ['Server subject', 'Addons subject'])
|
||||||
|
|
||||||
self.assertEqual(last_batch.state, 'ready')
|
self.assertEqual(last_batch.state, 'ready')
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import datetime
|
||||||
import getpass
|
import getpass
|
||||||
import logging
|
import logging
|
||||||
|
from odoo import fields
|
||||||
from unittest.mock import patch, mock_open
|
from unittest.mock import patch, mock_open
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
from odoo.tools import mute_logger
|
from odoo.tools import mute_logger
|
||||||
@ -206,7 +208,8 @@ class TestUpgradeFlow(RunbotCase):
|
|||||||
# create nightly
|
# create nightly
|
||||||
|
|
||||||
batch_nigthly = bundle._force(self.nightly_category.id)
|
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)
|
self.assertEqual(batch_nigthly.category_id, self.nightly_category)
|
||||||
builds_nigthly = {}
|
builds_nigthly = {}
|
||||||
host = self.env['runbot.host']._get_current()
|
host = self.env['runbot.host']._get_current()
|
||||||
@ -232,7 +235,8 @@ class TestUpgradeFlow(RunbotCase):
|
|||||||
batch_nigthly.state = 'done'
|
batch_nigthly.state = 'done'
|
||||||
|
|
||||||
batch_weekly = bundle._force(self.weekly_category.id)
|
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)
|
self.assertEqual(batch_weekly.category_id, self.weekly_category)
|
||||||
builds_weekly = {}
|
builds_weekly = {}
|
||||||
build = batch_weekly.slot_ids.filtered(lambda s: s.trigger_id == self.trigger_addons_weekly).build_id
|
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_weekly.state = 'done'
|
||||||
|
|
||||||
batch_default = bundle._force()
|
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 = batch_default.slot_ids.filtered(lambda s: s.trigger_id == self.trigger_server).build_id
|
||||||
build.local_state = 'done'
|
build.local_state = 'done'
|
||||||
batch_default.state = 'done'
|
batch_default.state = 'done'
|
||||||
@ -268,7 +273,8 @@ class TestUpgradeFlow(RunbotCase):
|
|||||||
self.trigger_upgrade_server.flush_recordset(['upgrade_step_id'])
|
self.trigger_upgrade_server.flush_recordset(['upgrade_step_id'])
|
||||||
|
|
||||||
batch = self.master_bundle._force()
|
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
|
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()
|
#host = self.env['runbot.host']._get_current()
|
||||||
#upgrade_current_build.host = host.name
|
#upgrade_current_build.host = host.name
|
||||||
@ -334,7 +340,8 @@ class TestUpgradeFlow(RunbotCase):
|
|||||||
})
|
})
|
||||||
|
|
||||||
batch = self.master_bundle._force(self.nightly_category.id)
|
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 = batch.slot_ids.filtered(lambda slot: slot.trigger_id == trigger_upgrade_addons_nightly).build_id
|
||||||
#upgrade_nightly.host = host.name
|
#upgrade_nightly.host = host.name
|
||||||
upgrade_nightly._schedule()
|
upgrade_nightly._schedule()
|
||||||
@ -484,7 +491,8 @@ class TestUpgradeFlow(RunbotCase):
|
|||||||
|
|
||||||
# test_build_references
|
# test_build_references
|
||||||
batch = self.master_bundle._force()
|
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)
|
upgrade_slot = batch.slot_ids.filtered(lambda slot: slot.trigger_id == self.trigger_upgrade_server)
|
||||||
self.assertTrue(upgrade_slot)
|
self.assertTrue(upgrade_slot)
|
||||||
upgrade_build = upgrade_slot.build_id
|
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
|
self.trigger_upgrade_server.upgrade_step_id.upgrade_from_all_intermediate_version = True
|
||||||
batch = self.master_bundle._force()
|
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
|
upgrade_build = batch.slot_ids.filtered(lambda slot: slot.trigger_id == self.trigger_upgrade_server).build_id
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
upgrade_build.params_id.builds_reference_ids,
|
upgrade_build.params_id.builds_reference_ids,
|
||||||
@ -539,7 +548,8 @@ class TestUpgradeFlow(RunbotCase):
|
|||||||
self.assertEqual(bundle_133.name, 'saas-13.3')
|
self.assertEqual(bundle_133.name, 'saas-13.3')
|
||||||
|
|
||||||
batch13 = bundle_13._force()
|
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 = batch13.slot_ids.filtered(lambda slot: slot.trigger_id == trigger_upgrade_complement).build_id
|
||||||
# upgrade_complement_build_13.host = host.name
|
# upgrade_complement_build_13.host = host.name
|
||||||
self.assertEqual(upgrade_complement_build_13.params_id.config_id, config_upgrade_complement)
|
self.assertEqual(upgrade_complement_build_13.params_id.config_id, config_upgrade_complement)
|
||||||
|
@ -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 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 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_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"/>
|
<menuitem id="runbot_menu_job_tree" parent="runbot_menu_configs" sequence="20" action="open_view_job_tree"/>
|
||||||
|
@ -33,6 +33,20 @@
|
|||||||
<group string="Dependencies">
|
<group string="Dependencies">
|
||||||
<field name="dependency_ids" nolabel="1" colspan="2"/>
|
<field name="dependency_ids" nolabel="1" colspan="2"/>
|
||||||
</group>
|
</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">
|
<group string="Module filters">
|
||||||
<field name="module_filters" nolabel="1" colspan="4">
|
<field name="module_filters" nolabel="1" colspan="4">
|
||||||
<tree string="Module filters" editable="bottom">
|
<tree string="Module filters" editable="bottom">
|
||||||
@ -85,12 +99,40 @@
|
|||||||
<field name="ci_context"/>
|
<field name="ci_context"/>
|
||||||
<field name="repo_ids" widget="many2many_tags"/>
|
<field name="repo_ids" widget="many2many_tags"/>
|
||||||
<field name="dependency_ids" widget="many2many_tags"/>
|
<field name="dependency_ids" widget="many2many_tags"/>
|
||||||
|
<field name="starts_after_ids" widget="many2many_tags"/>
|
||||||
<field name="manual"/>
|
<field name="manual"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</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="name">runbot.category.form</field>
|
||||||
<field name="model">runbot.category</field>
|
<field name="model">runbot.category</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
@ -224,10 +266,17 @@
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="runbot_triggers_action" model="ir.actions.act_window">
|
<record id="runbot_triggers_action" model="ir.actions.act_window">
|
||||||
<field name="name">Triggers</field>
|
<field name="name">Triggers</field>
|
||||||
<field name="res_model">runbot.trigger</field>
|
<field name="res_model">runbot.trigger</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
</record>
|
</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">
|
<record id="runbot_remotes_action" model="ir.actions.act_window">
|
||||||
<field name="name">Remotes</field>
|
<field name="name">Remotes</field>
|
||||||
<field name="res_model">runbot.remote</field>
|
<field name="res_model">runbot.remote</field>
|
||||||
|
@ -115,8 +115,7 @@ class Runbot(models.AbstractModel):
|
|||||||
|
|
||||||
mock_git.side_effect = git
|
mock_git.side_effect = git
|
||||||
with mute_logger('odoo.addons.runbot.models.batch'):
|
with mute_logger('odoo.addons.runbot.models.batch'):
|
||||||
batch._prepare()
|
batch._process()
|
||||||
|
|
||||||
if i != nb_batch - 1:
|
if i != nb_batch - 1:
|
||||||
for slot in batch.slot_ids:
|
for slot in batch.slot_ids:
|
||||||
if slot.build_id:
|
if slot.build_id:
|
||||||
|
Loading…
Reference in New Issue
Block a user