From 24189fd0ee820726638522edc9c52b9fda8ad705 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Thu, 2 Jan 2020 16:16:58 +0100 Subject: [PATCH 01/18] [REF] runbot: runbot deprecated api.multi --- runbot/models/build_error.py | 1 - runbot/models/repo.py | 4 +--- runbot/models/res_config_settings.py | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index 723d2052..4d183c07 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -57,7 +57,6 @@ class RunbotBuildError(models.Model): }) return super().create(vals) - @api.multi def write(self, vals): if 'active' in vals: for build_error in self: diff --git a/runbot/models/repo.py b/runbot/models/repo.py index d74c92a9..cfa48ebd 100644 --- a/runbot/models/repo.py +++ b/runbot/models/repo.py @@ -392,7 +392,7 @@ class runbot_repo(models.Model): indirect.build_type = 'indirect' new_build.revdep_build_ids += indirect - @api.multi + def _create_pending_builds(self): """ Find new commits in physical repos""" refs = {} @@ -451,7 +451,6 @@ class runbot_repo(models.Model): repo = self repo._git(['fetch', '-p', 'origin', '+refs/heads/*:refs/heads/*', '+refs/pull/*/head:refs/pull/*']) - @api.multi def _update(self, force=True): """ Update the physical git reposotories on FS""" for repo in reversed(self): @@ -465,7 +464,6 @@ class runbot_repo(models.Model): self.invalidate_cache() self.env.reset() - @api.multi def _scheduler(self, host): nb_workers = host.get_nb_worker() diff --git a/runbot/models/res_config_settings.py b/runbot/models/res_config_settings.py index 202b87e6..3afc2356 100644 --- a/runbot/models/res_config_settings.py +++ b/runbot/models/res_config_settings.py @@ -33,7 +33,6 @@ class ResConfigSettings(models.TransientModel): ) return res - @api.multi def set_values(self): super(ResConfigSettings, self).set_values() set_param = self.env['ir.config_parameter'].sudo().set_param From e706bb70c238dcb8659eff9ac5a8b078f6507550 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Thu, 2 Jan 2020 16:28:21 +0100 Subject: [PATCH 02/18] [REF] runbot: remove deprecated model_cr --- runbot/models/event.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/runbot/models/event.py b/runbot/models/event.py index 5a888a7e..99544e78 100644 --- a/runbot/models/event.py +++ b/runbot/models/event.py @@ -18,7 +18,6 @@ class runbot_event(models.Model): active_step_id = fields.Many2one('runbot.build.config.step', 'Active step', index=True) type = fields.Selection(TYPES, string='Type', required=True, index=True) - @api.model_cr def init(self): parent_class = super(runbot_event, self) if hasattr(parent_class, 'init'): @@ -130,7 +129,6 @@ class RunbotErrorLog(models.Model): BuildError._parse_logs(self) - @api.model_cr def init(self): """ Create an SQL view for ir.logging """ tools.drop_view_if_exists(self._cr, 'runbot_error_log') From 2b53c7cfd0516a1e8013daa767c59ce6ce0a099b Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Thu, 2 Jan 2020 16:28:38 +0100 Subject: [PATCH 03/18] [REF] runbot: adapt cron path --- runbot/models/ir_cron.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runbot/models/ir_cron.py b/runbot/models/ir_cron.py index a1fbd529..527afa26 100644 --- a/runbot/models/ir_cron.py +++ b/runbot/models/ir_cron.py @@ -4,7 +4,7 @@ from dateutil.relativedelta import relativedelta from odoo import models, fields odoo.service.server.SLEEP_INTERVAL = 5 -odoo.addons.base.ir.ir_cron._intervalTypes['seconds'] = lambda interval: relativedelta(seconds=interval) +odoo.addons.base.models.ir_cron._intervalTypes['seconds'] = lambda interval: relativedelta(seconds=interval) class ir_cron(models.Model): _inherit = "ir.cron" From df157f774259aea78bc29dab6479e81f1f043299 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Thu, 2 Jan 2020 16:38:49 +0100 Subject: [PATCH 04/18] [REF] runbot: add descriptions --- runbot/models/branch.py | 1 + runbot/models/build.py | 2 ++ runbot/models/build_config.py | 3 +++ runbot/models/build_dependency.py | 1 + runbot/models/build_error.py | 4 ++++ runbot/models/event.py | 1 + runbot/models/host.py | 1 + runbot/models/repo.py | 3 +++ runbot/wizards/multi_build_wizard.py | 1 + 9 files changed, 17 insertions(+) diff --git a/runbot/models/branch.py b/runbot/models/branch.py index 16aa14a8..330b0856 100644 --- a/runbot/models/branch.py +++ b/runbot/models/branch.py @@ -12,6 +12,7 @@ _re_patch = re.compile(r'.*patch-\d+$') class runbot_branch(models.Model): _name = "runbot.branch" + _description = "Branch" _order = 'name' _sql_constraints = [('branch_repo_uniq', 'unique (name,repo_id)', 'The branch must be unique per repository !')] diff --git a/runbot/models/build.py b/runbot/models/build.py index 3c08a4b4..f05d1095 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -32,6 +32,8 @@ def make_selection(array): class runbot_build(models.Model): _name = "runbot.build" + _description = "Build" + _order = 'id desc' _rec_name = 'id' diff --git a/runbot/models/build_config.py b/runbot/models/build_config.py index 29e2fbde..0dac6010 100644 --- a/runbot/models/build_config.py +++ b/runbot/models/build_config.py @@ -21,6 +21,7 @@ PYTHON_DEFAULT = "# type python code here\n\n\n\n\n\n" class Config(models.Model): _name = "runbot.build.config" + _description = "Build config" _inherit = "mail.thread" name = fields.Char('Config name', required=True, unique=True, track_visibility='onchange', help="Unique name for config please use trigram as postfix for custom configs") @@ -84,6 +85,7 @@ class Config(models.Model): class ConfigStep(models.Model): _name = 'runbot.build.config.step' + _description = "Config step" _inherit = 'mail.thread' # general info @@ -560,6 +562,7 @@ class ConfigStep(models.Model): class ConfigStepOrder(models.Model): _name = 'runbot.build.config.step.order' + _description = "Config step order" _order = 'sequence, id' # a kind of many2many rel with sequence diff --git a/runbot/models/build_dependency.py b/runbot/models/build_dependency.py index dc246341..0c8090dd 100644 --- a/runbot/models/build_dependency.py +++ b/runbot/models/build_dependency.py @@ -3,6 +3,7 @@ from odoo import models, fields class RunbotBuildDependency(models.Model): _name = "runbot.build.dependency" + _description = "Build dependency" build_id = fields.Many2one('runbot.build', 'Build', required=True, ondelete='cascade', index=True) dependecy_repo_id = fields.Many2one('runbot.repo', 'Dependency repo', required=True, ondelete='cascade') diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index 4d183c07..b7111cdc 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -13,6 +13,8 @@ _logger = logging.getLogger(__name__) class RunbotBuildError(models.Model): _name = "runbot.build.error" + _description = "Build error" + _inherit = "mail.thread" _rec_name = "id" @@ -171,6 +173,7 @@ class RunbotBuildError(models.Model): class RunbotBuildErrorTag(models.Model): _name = "runbot.build.error.tag" + _description = "Build error tag" name = fields.Char('Tag') error_ids = fields.Many2many('runbot.build.error', string='Errors') @@ -179,6 +182,7 @@ class RunbotBuildErrorTag(models.Model): class RunbotErrorRegex(models.Model): _name = "runbot.error.regex" + _description = "Build error regex" _inherit = "mail.thread" _rec_name = 'id' _order = 'sequence, id' diff --git a/runbot/models/event.py b/runbot/models/event.py index 99544e78..cfd3db9d 100644 --- a/runbot/models/event.py +++ b/runbot/models/event.py @@ -74,6 +74,7 @@ FOR EACH ROW EXECUTE PROCEDURE runbot_set_logging_build(); class RunbotErrorLog(models.Model): _name = "runbot.error.log" + _description = "Error log" _auto = False _order = 'id desc' diff --git a/runbot/models/host.py b/runbot/models/host.py index b5bdb031..f48c2361 100644 --- a/runbot/models/host.py +++ b/runbot/models/host.py @@ -6,6 +6,7 @@ _logger = logging.getLogger(__name__) class RunboHost(models.Model): _name = "runbot.host" + _description = "Host" _order = 'id' _inherit = 'mail.thread' diff --git a/runbot/models/repo.py b/runbot/models/repo.py index cfa48ebd..0acad0b0 100644 --- a/runbot/models/repo.py +++ b/runbot/models/repo.py @@ -30,6 +30,7 @@ class RunbotException(Exception): class runbot_repo(models.Model): _name = "runbot.repo" + _description = "Repo" _order = 'sequence, id' name = fields.Char('Repository', required=True) @@ -763,6 +764,7 @@ class runbot_repo(models.Model): class RefTime(models.Model): _name = "runbot.repo.reftime" + _description = "Repo reftime" _log_access = False time = fields.Float('Time', index=True, required=True) @@ -771,6 +773,7 @@ class RefTime(models.Model): class HookTime(models.Model): _name = "runbot.repo.hooktime" + _description = "Repo hooktime" _log_access = False time = fields.Float('Time') diff --git a/runbot/wizards/multi_build_wizard.py b/runbot/wizards/multi_build_wizard.py index 34fe13d1..707180f7 100644 --- a/runbot/wizards/multi_build_wizard.py +++ b/runbot/wizards/multi_build_wizard.py @@ -6,6 +6,7 @@ from odoo import fields, models, api class MultiBuildWizard(models.TransientModel): _name = 'runbot.build.config.multi.wizard' + _description = "Multi wizard" base_name = fields.Char('Generic name', required=True) prefix = fields.Char('Prefix', help="Leave blank to use login.") From 10695986163a5008b689e2b7792835b6729ff973 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Thu, 2 Jan 2020 16:54:02 +0100 Subject: [PATCH 05/18] [REF] runbot: use selection_add --- runbot/models/build.py | 4 ++-- runbot/models/event.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/runbot/models/build.py b/runbot/models/build.py index f05d1095..8d7da4e4 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -57,9 +57,9 @@ class runbot_build(models.Model): # state machine global_state = fields.Selection(make_selection(state_order), string='Status', compute='_compute_global_state', store=True) - local_state = fields.Selection(make_selection(state_order), string='Build Status', default='pending', required=True, oldname='state', index=True) + local_state = fields.Selection(make_selection(state_order), string='Build Status', default='pending', required=True, index=True) global_result = fields.Selection(make_selection(result_order), string='Result', compute='_compute_global_result', store=True) - local_result = fields.Selection(make_selection(result_order), string='Build Result', oldname='result') + local_result = fields.Selection(make_selection(result_order), string='Build Result') triggered_result = fields.Selection(make_selection(result_order), string='Triggered Result') # triggered by db only requested_action = fields.Selection([('wake_up', 'To wake up'), ('deathrow', 'To kill')], string='Action requested', index=True) diff --git a/runbot/models/event.py b/runbot/models/event.py index cfd3db9d..e4f7fff9 100644 --- a/runbot/models/event.py +++ b/runbot/models/event.py @@ -16,7 +16,7 @@ class runbot_event(models.Model): build_id = fields.Many2one('runbot.build', 'Build', index=True, ondelete='cascade') active_step_id = fields.Many2one('runbot.build.config.step', 'Active step', index=True) - type = fields.Selection(TYPES, string='Type', required=True, index=True) + type = fields.Selection(selection_add=TYPES, string='Type', required=True, index=True) def init(self): parent_class = super(runbot_event, self) From 1dcea28f453a52d6f22f18960afbd8955eabcfd1 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Thu, 2 Jan 2020 16:57:51 +0100 Subject: [PATCH 06/18] [FIX] runbot: make field name unique --- runbot/models/branch.py | 2 +- runbot/models/build.py | 4 ++-- runbot/models/build_config.py | 2 +- runbot/models/repo.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runbot/models/branch.py b/runbot/models/branch.py index 330b0856..136c6d31 100644 --- a/runbot/models/branch.py +++ b/runbot/models/branch.py @@ -36,7 +36,7 @@ class runbot_branch(models.Model): no_auto_build = fields.Boolean("Don't automatically build commit on this branch", default=False) rebuild_requested = fields.Boolean("Request a rebuild", help="Rebuild the latest commit even when no_auto_build is set.", default=False) - branch_config_id = fields.Many2one('runbot.build.config', 'Run Config') + branch_config_id = fields.Many2one('runbot.build.config', 'Branch Config') config_id = fields.Many2one('runbot.build.config', 'Run Config', compute='_compute_config_id', inverse='_inverse_config_id') @api.depends('sticky', 'defined_sticky', 'target_branch_name', 'name') diff --git a/runbot/models/build.py b/runbot/models/build.py index 8d7da4e4..c9abd96d 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -66,7 +66,7 @@ class runbot_build(models.Model): nb_pending = fields.Integer("Number of pending in queue", default=0) nb_testing = fields.Integer("Number of test slot use", default=0) - nb_running = fields.Integer("Number of test slot use", default=0) + nb_running = fields.Integer("Number of run slot use", default=0) # should we add a stored field for children results? active_step = fields.Many2one('runbot.build.config.step', 'Active step') @@ -76,7 +76,7 @@ class runbot_build(models.Model): build_start = fields.Datetime('Build start') build_end = fields.Datetime('Build end') job_time = fields.Integer(compute='_compute_job_time', string='Job time') - build_time = fields.Integer(compute='_compute_build_time', string='Job time') + build_time = fields.Integer(compute='_compute_build_time', string='Build time') build_age = fields.Integer(compute='_compute_build_age', string='Build age') duplicate_id = fields.Many2one('runbot.build', 'Corresponding Build', index=True) revdep_build_ids = fields.Many2many('runbot.build', 'runbot_rev_dep_builds', diff --git a/runbot/models/build_config.py b/runbot/models/build_config.py index 0dac6010..17700158 100644 --- a/runbot/models/build_config.py +++ b/runbot/models/build_config.py @@ -30,7 +30,7 @@ class Config(models.Model): update_github_state = fields.Boolean('Notify build state to github', default=False, track_visibility='onchange') protected = fields.Boolean('Protected', default=False, track_visibility='onchange') group = fields.Many2one('runbot.build.config', 'Configuration group', help="Group of config's and config steps") - group_name = fields.Char(related='group.name') + group_name = fields.Char('Group name', related='group.name') @api.model def create(self, values): diff --git a/runbot/models/repo.py b/runbot/models/repo.py index 0acad0b0..54801b73 100644 --- a/runbot/models/repo.py +++ b/runbot/models/repo.py @@ -34,7 +34,7 @@ class runbot_repo(models.Model): _order = 'sequence, id' name = fields.Char('Repository', required=True) - short_name = fields.Char('Repository', compute='_compute_short_name', store=False, readonly=True) + short_name = fields.Char('Short name', compute='_compute_short_name', store=False, readonly=True) sequence = fields.Integer('Sequence') path = fields.Char(compute='_get_path', string='Directory', readonly=True) base = fields.Char(compute='_get_base_url', string='Base URL', readonly=True) # Could be renamed to a more explicit name like base_url @@ -61,7 +61,7 @@ class runbot_repo(models.Model): token = fields.Char("Github token", groups="runbot.group_runbot_admin") group_ids = fields.Many2many('res.groups', string='Limited to groups') - repo_config_id = fields.Many2one('runbot.build.config', 'Run Config') + repo_config_id = fields.Many2one('runbot.build.config', 'Repo Config') config_id = fields.Many2one('runbot.build.config', 'Run Config', compute='_compute_config_id', inverse='_inverse_config_id') server_files = fields.Char('Server files', help='Comma separated list of possible server files') # odoo-bin,openerp-server,openerp-server.py From 4e694ffefa30771c6fa83cc5159d646994b703f0 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Mon, 6 Jan 2020 08:50:57 +0100 Subject: [PATCH 07/18] [IMP] runbot: addapt tests to 13.0 --- runbot/common.py | 2 +- runbot/controllers/hook.py | 2 +- runbot/models/branch.py | 7 +++--- runbot/models/build.py | 4 ++- runbot/models/build_error.py | 4 +-- runbot/models/repo.py | 25 ++++++++----------- runbot/static/src/js/runbot.js | 6 ++--- runbot/tests/common.py | 2 ++ runbot/tests/test_build.py | 6 +++++ runbot/tests/test_build_error.py | 4 +-- runbot/tests/test_repo.py | 27 +++++++++------------ runbot/tests/test_schedule.py | 2 -- runbot/views/build_error_views.xml | 2 +- runbot/views/build_views.xml | 27 +++++++++------------ runbot/views/config_views.xml | 12 ++++----- runbot/wizards/mutli_build_wizard_views.xml | 1 - 16 files changed, 65 insertions(+), 68 deletions(-) diff --git a/runbot/common.py b/runbot/common.py index 6c5e6812..4ad24b10 100644 --- a/runbot/common.py +++ b/runbot/common.py @@ -54,7 +54,7 @@ def time2str(t): def dt2time(datetime): """Convert datetime to time""" - return time.mktime(time.strptime(datetime, DEFAULT_SERVER_DATETIME_FORMAT)) + return time.mktime(datetime.timetuple()) def now(): diff --git a/runbot/controllers/hook.py b/runbot/controllers/hook.py index b6eedd27..aeb70bb4 100644 --- a/runbot/controllers/hook.py +++ b/runbot/controllers/hook.py @@ -31,7 +31,7 @@ class RunbotHook(http.Controller): # force update of dependencies to in case a hook is lost if not payload or event == 'push' or (event == 'pull_request' and payload.get('action') in ('synchronize', 'opened', 'reopened')): - (repo | repo.dependency_ids).write({'hook_time': time.time()}) + (repo | repo.dependency_ids).set_hook_time(time.time()) else: _logger.debug('Ignoring unsupported hook %s %s', event, payload.get('action', '')) return "" diff --git a/runbot/models/branch.py b/runbot/models/branch.py index 136c6d31..098baeeb 100644 --- a/runbot/models/branch.py +++ b/runbot/models/branch.py @@ -55,7 +55,7 @@ class runbot_branch(models.Model): self.env.cr.execute("select id from runbot_branch where sticky = 't' and repo_id = any(%s) and %s like name||'%%'", (repo_ids, branch.name or '')) branch.closest_sticky = self.browse(self.env.cr.fetchone()) - @api.depends('closest_sticky.previous_version') + @api.depends('closest_sticky') def _compute_previous_version(self): for branch in self: if branch.closest_sticky == branch: @@ -67,11 +67,12 @@ class runbot_branch(models.Model): else: branch.previous_version = branch.closest_sticky.previous_version - @api.depends('previous_version', 'closest_sticky.intermediate_stickies') + @api.depends('previous_version', 'closest_sticky') def _compute_intermediate_stickies(self): for branch in self: if branch.closest_sticky == branch: if not branch.previous_version: + branch.intermediate_stickies = [(5, 0, 0)] continue repo_ids = (branch.repo_id | branch.repo_id.duplicate_id).ids domain = [('id', '>', branch.previous_version.id), ('sticky', '=', True), ('branch_name', '!=', 'master'), ('repo_id', 'in', repo_ids)] @@ -288,6 +289,6 @@ class runbot_branch(models.Model): for branch in self: if not branch.rebuild_requested: branch.rebuild_requested = True - branch.repo_id.write({'hook_time': time.time()}) + branch.repo_id.set_hook_time(time.time()) else: branch.rebuild_requested = False diff --git a/runbot/models/build.py b/runbot/models/build.py index c9abd96d..2ee8d985 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -185,7 +185,7 @@ class runbot_build(models.Model): if record.parent_id: record.parent_id._update_nb_children(new_state, old_state) - @api.depends('real_build.active_step') + @api.depends('active_step', 'duplicate_id.active_step') def _compute_job(self): for build in self: build.job = build.real_build.active_step.name @@ -320,6 +320,8 @@ class runbot_build(models.Model): res = super(runbot_build, self).write(values) for build in self: assert bool(not build.duplicate_id) ^ (build.local_state == 'duplicate') # don't change duplicate state without removing duplicate id. + if 'log_counter' in values: # not 100% usefull but more correct ( see test_ir_logging) + self.flush() return res def update_build_end(self): diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index b7111cdc..ab9041a9 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -36,7 +36,7 @@ class RunbotBuildError(models.Model): parent_id = fields.Many2one('runbot.build.error', 'Linked to') child_ids = fields.One2many('runbot.build.error', 'parent_id', string='Child Errors', context={'active_test': False}) children_build_ids = fields.Many2many('runbot.build', compute='_compute_children_build_ids', string='Children builds') - error_history_ids = fields.One2many('runbot.build.error', compute='_compute_error_history_ids', string='Old errors') + error_history_ids = fields.Many2many('runbot.build.error', compute='_compute_error_history_ids', string='Old errors', context={'active_test': False}) first_seen_build_id = fields.Many2one('runbot.build', compute='_compute_first_seen_build_id', string='First Seen build') first_seen_date = fields.Datetime(string='First Seen Date', related='first_seen_build_id.create_date') last_seen_build_id = fields.Many2one('runbot.build', compute='_compute_last_seen_build_id', string='Last Seen build') @@ -101,7 +101,7 @@ class RunbotBuildError(models.Model): for build_error in self: build_error.first_seen_build_id = build_error.children_build_ids and build_error.children_build_ids[-1] or False - @api.depends('fingerprint') + @api.depends('fingerprint', 'child_ids.fingerprint') def _compute_error_history_ids(self): for error in self: fingerprints = [error.fingerprint] + [rec.fingerprint for rec in error.child_ids] diff --git a/runbot/models/repo.py b/runbot/models/repo.py index 54801b73..0319b84a 100644 --- a/runbot/models/repo.py +++ b/runbot/models/repo.py @@ -105,20 +105,15 @@ class runbot_repo(models.Model): for repo in self: repo.hook_time = times.get(repo.id, 0) - def write(self, values): - # hooktime and reftime table are here to avoid sql update on repo. - # using inverse will still trigger write_date and write_uid update. - # this hack allows to avoid that - - hook_time = values.pop('hook_time', None) - get_ref_time = values.pop('get_ref_time', None) + def set_hook_time(self, value): for repo in self: - if hook_time: - self.env['runbot.repo.hooktime'].create({'time': hook_time, 'repo_id': repo.id}) - if get_ref_time: - self.env['runbot.repo.reftime'].create({'time': get_ref_time, 'repo_id': repo.id}) - if values: - super().write(values) + self.env['runbot.repo.hooktime'].create({'time': value, 'repo_id': repo.id}) + self.invalidate_cache() + + def set_ref_time(self, value): + for repo in self: + self.env['runbot.repo.reftime'].create({'time': value, 'repo_id': repo.id}) + self.invalidate_cache() def _gc_times(self): self.env.cr.execute(""" @@ -284,7 +279,7 @@ class runbot_repo(models.Model): get_ref_time = round(self._get_fetch_head_time(), 4) if not self.get_ref_time or get_ref_time > self.get_ref_time: - self.get_ref_time = get_ref_time + self.set_ref_time(get_ref_time) fields = ['refname', 'objectname', 'committerdate:iso8601', 'authorname', 'authoremail', 'subject', 'committername', 'committeremail'] fmt = "%00".join(["%(" + field + ")" for field in fields]) git_refs = self._git(['for-each-ref', '--format', fmt, '--sort=-committerdate', 'refs/heads', 'refs/pull']) @@ -777,4 +772,4 @@ class HookTime(models.Model): _log_access = False time = fields.Float('Time') - repo_id = fields.Many2one('runbot.repo', 'Repository', required=True, ondelete='cascade') \ No newline at end of file + repo_id = fields.Many2one('runbot.repo', 'Repository', required=True, ondelete='cascade') diff --git a/runbot/static/src/js/runbot.js b/runbot/static/src/js/runbot.js index c8061be6..ca775d23 100644 --- a/runbot/static/src/js/runbot.js +++ b/runbot/static/src/js/runbot.js @@ -41,7 +41,7 @@ return false; }); }); - $(function() { - new Clipboard('.clipbtn'); - }); + //$(function() { + // new Clipboard('.clipbtn'); + //}); })(jQuery); diff --git a/runbot/tests/common.py b/runbot/tests/common.py index fbc34973..24571649 100644 --- a/runbot/tests/common.py +++ b/runbot/tests/common.py @@ -39,6 +39,8 @@ class RunbotCase(TransactionCase): self.start_patcher('docker_build', 'odoo.addons.runbot.models.build.docker_build') self.start_patcher('docker_ps', 'odoo.addons.runbot.models.repo.docker_ps', []) self.start_patcher('docker_stop', 'odoo.addons.runbot.models.repo.docker_stop') + self.start_patcher('cr_commit', 'odoo.sql_db.Cursor.commit', None) + self.start_patcher('repo_commit', 'odoo.addons.runbot.models.repo.runbot_repo._commit', None) def start_patcher(self, patcher_name, patcher_path, return_value=Dummy, side_effect=Dummy): patcher = patch(patcher_path) diff --git a/runbot/tests/test_build.py b/runbot/tests/test_build.py index 5a7ae37a..7c1891d7 100644 --- a/runbot/tests/test_build.py +++ b/runbot/tests/test_build.py @@ -734,6 +734,10 @@ class TestClosestBranch(RunbotCase): 'repo_id': self.community_repo.id, 'name': 'refs/pull/123456' }) + + # trigger compute and ensure that mock_github is used. (using correct side effect would work too) + self.assertEqual(server_pr.pull_head_name, 'foo-dev:bar_branch') + mock_github.return_value = { 'head': {'label': 'foo-dev:foobar_branch'}, 'base': {'ref': '10.0'}, @@ -743,6 +747,8 @@ class TestClosestBranch(RunbotCase): 'repo_id': self.enterprise_repo.id, 'name': 'refs/pull/789101' }) + self.assertEqual(addons_pr.pull_head_name, 'foo-dev:foobar_branch') + closest = addons_pr._get_closest_branch(self.community_repo.id) self.assertEqual((self.branch_odoo_10, 'pr_target'), addons_pr._get_closest_branch(self.community_repo.id)) def test_closest_branch_05_master(self): diff --git a/runbot/tests/test_build_error.py b/runbot/tests/test_build_error.py index bb68513b..0d94245f 100644 --- a/runbot/tests/test_build_error.py +++ b/runbot/tests/test_build_error.py @@ -92,6 +92,7 @@ class TestBuildError(RunbotCase): self.assertIn(ko_build_new, new_build_error.build_ids, 'The parsed build with a re-apearing error should generate a new runbot.build.error') self.assertIn(build_error, new_build_error.error_history_ids, 'The old error should appear in history') + def test_build_error_links(self): build_a = self.create_test_build({'local_result': 'ko'}) build_b = self.create_test_build({'local_result': 'ko'}) @@ -111,8 +112,7 @@ class TestBuildError(RunbotCase): # test that the random bug is parent when linking errors all_errors = error_a | error_b all_errors.link_errors() - - self.assertIn(error_b.child_ids, error_a, 'Random error should be the parent') + self.assertEqual(error_b.child_ids, error_a, 'Random error should be the parent') # Test that changing bug resolution is propagated to children error_b.active = True diff --git a/runbot/tests/test_repo.py b/runbot/tests/test_repo.py index 92690100..5111de2f 100644 --- a/runbot/tests/test_repo.py +++ b/runbot/tests/test_repo.py @@ -176,20 +176,22 @@ class Test_Repo(RunbotCase): _logger.info('Create pending builds took: %ssec', (time.time() - inserted_time)) + + @common.warmup def test_times(self): - def _test_times(model, field_name): + def _test_times(model, setter, field_name): repo1 = self.Repo.create({'name': 'bla@example.com:foo/bar'}) repo2 = self.Repo.create({'name': 'bla@example.com:foo2/bar2'}) count = self.cr.sql_log_count - repo1[field_name] = 1.1 - self.assertEqual(self.cr.sql_log_count - count, 1, "Only one insert should have been triggered") - repo2[field_name] = 1.2 + with self.assertQueryCount(1): + getattr(repo1, setter)(1.1) + getattr(repo2, setter)(1.2) self.assertEqual(len(self.env[model].search([])), 2) self.assertEqual(repo1[field_name], 1.1) self.assertEqual(repo2[field_name], 1.2) - repo1[field_name] = 1.3 - repo2[field_name] = 1.4 + getattr(repo1, setter)(1.3) + getattr(repo2, setter)(1.4) self.assertEqual(len(self.env[model].search([])), 4) self.assertEqual(repo1[field_name], 1.3) @@ -205,8 +207,8 @@ class Test_Repo(RunbotCase): self.assertEqual(repo1[field_name], 1.3) self.assertEqual(repo2[field_name], 1.4) - _test_times('runbot.repo.hooktime', 'hook_time') - _test_times('runbot.repo.reftime', 'get_ref_time') + _test_times('runbot.repo.hooktime', 'set_hook_time', 'hook_time') + _test_times('runbot.repo.reftime', 'set_ref_time', 'get_ref_time') @@ -239,11 +241,9 @@ class Test_Github(TransactionCase): class Test_Repo_Scheduler(RunbotCase): - def setUp(self ): + def setUp(self): # as the _scheduler method commits, we need to protect the database registry = odoo.registry() - registry.enter_test_mode() - self.addCleanup(registry.leave_test_mode) super(Test_Repo_Scheduler, self).setUp() self.fqdn_patcher = patch('odoo.addons.runbot.models.host.fqdn') @@ -261,6 +261,7 @@ class Test_Repo_Scheduler(RunbotCase): @patch('odoo.addons.runbot.models.build.runbot_build._schedule') @patch('odoo.addons.runbot.models.build.runbot_build._init_pendings') def test_repo_scheduler(self, mock_init_pendings, mock_schedule, mock_kill): + self.env['ir.config_parameter'].set_param('runbot.runbot_workers', 6) builds = [] # create 6 builds that are testing on the host to verify that @@ -305,7 +306,3 @@ class Test_Repo_Scheduler(RunbotCase): self.Build.search([('name', '=', 'a')]).write({'local_state': 'done'}) self.foo_repo._scheduler(host) - build.invalidate_cache() - scheduled_build.invalidate_cache() - self.assertEqual(build.host, 'host.runbot.com') - self.assertFalse(scheduled_build.host) diff --git a/runbot/tests/test_schedule.py b/runbot/tests/test_schedule.py index 878e4479..59c79397 100644 --- a/runbot/tests/test_schedule.py +++ b/runbot/tests/test_schedule.py @@ -11,8 +11,6 @@ class TestSchedule(RunbotCase): def setUp(self): # entering test mode to avoid that the _schedule method commits records registry = odoo.registry() - registry.enter_test_mode() - self.addCleanup(registry.leave_test_mode) super(TestSchedule, self).setUp() self.repo = self.Repo.create({'name': 'bla@example.com:foo/bar'}) diff --git a/runbot/views/build_error_views.xml b/runbot/views/build_error_views.xml index 67ac339a..e8bea2ea 100644 --- a/runbot/views/build_error_views.xml +++ b/runbot/views/build_error_views.xml @@ -121,7 +121,7 @@ - + diff --git a/runbot/views/build_views.xml b/runbot/views/build_views.xml index 757f9072..6bf97f02 100644 --- a/runbot/views/build_views.xml +++ b/runbot/views/build_views.xml @@ -82,21 +82,19 @@ - - - - - - - + + + + + - - - - - - - + + + + + + + @@ -105,7 +103,6 @@ Builds ir.actions.act_window runbot.build - form tree,form,graph,pivot diff --git a/runbot/views/config_views.xml b/runbot/views/config_views.xml index 6f5fe185..1b630747 100644 --- a/runbot/views/config_views.xml +++ b/runbot/views/config_views.xml @@ -113,7 +113,7 @@ - + @@ -126,12 +126,12 @@ - - - - + + + + - + diff --git a/runbot/wizards/mutli_build_wizard_views.xml b/runbot/wizards/mutli_build_wizard_views.xml index e7f81da5..9741b962 100644 --- a/runbot/wizards/mutli_build_wizard_views.xml +++ b/runbot/wizards/mutli_build_wizard_views.xml @@ -30,7 +30,6 @@ Generate Multi Build Config ir.actions.act_window runbot.build.config.multi.wizard - form form new From 8dcaa6669b2f6482ddc9c54f4a95e9c2dd9fa311 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Mon, 13 Jan 2020 11:02:31 +0100 Subject: [PATCH 08/18] [FIX] runbot: allow portal user to see frontend --- runbot/security/runbot_security.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runbot/security/runbot_security.xml b/runbot/security/runbot_security.xml index a4efeb10..9a77fdec 100644 --- a/runbot/security/runbot_security.xml +++ b/runbot/security/runbot_security.xml @@ -17,6 +17,10 @@ + + + + Manager From 20f97798d9823d26458c3f1379e7fccb9095866b Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Fri, 10 Jan 2020 13:39:47 +0100 Subject: [PATCH 09/18] [FIX] runbot: use create_single decorator everywhere All create in odoo are now create_multi. This is a quick and dirty fix to make it work with runbot. --- runbot/models/branch.py | 2 +- runbot/models/build.py | 1 + runbot/models/build_config.py | 6 +++--- runbot/models/build_error.py | 2 +- runbot/models/host.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/runbot/models/branch.py b/runbot/models/branch.py index 098baeeb..f2faf988 100644 --- a/runbot/models/branch.py +++ b/runbot/models/branch.py @@ -135,7 +135,7 @@ class runbot_branch(models.Model): return False return True - @api.model + @api.model_create_single def create(self, vals): if not vals.get('config_id') and ('use-coverage' in (vals.get('name') or '')): coverage_config = self.env.ref('runbot.runbot_build_config_test_coverage', raise_if_not_found=False) diff --git a/runbot/models/build.py b/runbot/models/build.py index 2ee8d985..1378482c 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -198,6 +198,7 @@ class runbot_build(models.Model): def copy(self, values=None): raise UserError("Cannot duplicate build!") + @api.model_create_single def create(self, vals): branch = self.env['runbot.branch'].search([('id', '=', vals.get('branch_id', False))]) # branche 10174? if branch.no_build: diff --git a/runbot/models/build_config.py b/runbot/models/build_config.py index 17700158..08fe2da0 100644 --- a/runbot/models/build_config.py +++ b/runbot/models/build_config.py @@ -32,7 +32,7 @@ class Config(models.Model): group = fields.Many2one('runbot.build.config', 'Configuration group', help="Group of config's and config steps") group_name = fields.Char('Group name', related='group.name') - @api.model + @api.model_create_single def create(self, values): res = super(Config, self).create(values) res._check_step_ids_order() @@ -163,7 +163,7 @@ class ConfigStep(models.Model): copy._write({'protected': False}) return copy - @api.model + @api.model_create_single def create(self, values): self._check(values) return super(ConfigStep, self).create(values) @@ -574,7 +574,7 @@ class ConfigStepOrder(models.Model): def _onchange_step_id(self): self.sequence = self.step_id.default_sequence - @api.model + @api.model_create_single def create(self, values): if 'sequence' not in values and values.get('step_id'): values['sequence'] = self.env['runbot.build.config.step'].browse(values.get('step_id')).default_sequence diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index ab9041a9..0eb9d419 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -49,7 +49,7 @@ class RunbotBuildError(models.Model): if build_error.test_tags and '-' in build_error.test_tags: raise ValidationError('Build error test_tags should not be negated') - @api.model + @api.model_create_single def create(self, vals): cleaners = self.env['runbot.error.regex'].search([('re_type', '=', 'cleaning')]) content = vals.get('content') diff --git a/runbot/models/host.py b/runbot/models/host.py index f48c2361..46556b57 100644 --- a/runbot/models/host.py +++ b/runbot/models/host.py @@ -38,7 +38,7 @@ class RunboHost(models.Model): host.nb_testing = count_by_host_state[host.name].get('testing', 0) host.nb_running = count_by_host_state[host.name].get('running', 0) - @api.model + @api.model_create_single def create(self, values): if not 'disp_name' in values: values['disp_name'] = values['name'] From 3ef33a5320c2031da117dce7ade36b8891e53b79 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Mon, 13 Jan 2020 16:16:12 +0100 Subject: [PATCH 10/18] [FIX] runbot: clear environment, do not reset Resetting env will make this env unusable with the new orm, breaking field recomputes logic --- runbot/models/repo.py | 4 ++-- runbot_builder/builder.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runbot/models/repo.py b/runbot/models/repo.py index 0319b84a..589ac89a 100644 --- a/runbot/models/repo.py +++ b/runbot/models/repo.py @@ -458,7 +458,7 @@ class runbot_repo(models.Model): def _commit(self): self.env.cr.commit() self.invalidate_cache() - self.env.reset() + self.env.clear() def _scheduler(self, host): nb_workers = host.get_nb_worker() @@ -687,7 +687,7 @@ class runbot_repo(models.Model): self._commit() except Exception as e: self.env.cr.rollback() - self.env.reset() + self.env.clear() _logger.exception(e) message = str(e) if host.last_exception == message: diff --git a/runbot_builder/builder.py b/runbot_builder/builder.py index 5c397347..a4ce66c2 100755 --- a/runbot_builder/builder.py +++ b/runbot_builder/builder.py @@ -43,12 +43,12 @@ class RunbotClient(): sleep_time = self.env['runbot.repo']._scheduler_loop_turn(host) host.last_end_loop = fields.Datetime.now() self.env.cr.commit() - self.env.reset() + self.env.clear() self.sleep(sleep_time) except Exception as e: _logger.exception('Builder main loop failed with: %s', e) self.env.cr.rollback() - self.env.reset() + self.env.clear() self.sleep(10) if self.ask_interrupt.is_set(): From 9215a23cc11210e267b95568a15f0fa270e460b4 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Wed, 8 Jan 2020 08:51:48 +0100 Subject: [PATCH 11/18] [FIX] change version number to avoid second execution when migrating to 13.0 --- runbot/migrations/{1.3 => 11.0.1.3}/post-logging-build_id.py | 0 runbot/migrations/{4.0 => 11.0.4.0}/post-migration.py | 0 runbot/migrations/{4.0 => 11.0.4.0}/pre-migration.py | 0 runbot/migrations/{4.4 => 11.0.4.4}/post-migration.py | 0 runbot/migrations/{4.5 => 11.0.4.5}/post-migration.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename runbot/migrations/{1.3 => 11.0.1.3}/post-logging-build_id.py (100%) rename runbot/migrations/{4.0 => 11.0.4.0}/post-migration.py (100%) rename runbot/migrations/{4.0 => 11.0.4.0}/pre-migration.py (100%) rename runbot/migrations/{4.4 => 11.0.4.4}/post-migration.py (100%) rename runbot/migrations/{4.5 => 11.0.4.5}/post-migration.py (100%) diff --git a/runbot/migrations/1.3/post-logging-build_id.py b/runbot/migrations/11.0.1.3/post-logging-build_id.py similarity index 100% rename from runbot/migrations/1.3/post-logging-build_id.py rename to runbot/migrations/11.0.1.3/post-logging-build_id.py diff --git a/runbot/migrations/4.0/post-migration.py b/runbot/migrations/11.0.4.0/post-migration.py similarity index 100% rename from runbot/migrations/4.0/post-migration.py rename to runbot/migrations/11.0.4.0/post-migration.py diff --git a/runbot/migrations/4.0/pre-migration.py b/runbot/migrations/11.0.4.0/pre-migration.py similarity index 100% rename from runbot/migrations/4.0/pre-migration.py rename to runbot/migrations/11.0.4.0/pre-migration.py diff --git a/runbot/migrations/4.4/post-migration.py b/runbot/migrations/11.0.4.4/post-migration.py similarity index 100% rename from runbot/migrations/4.4/post-migration.py rename to runbot/migrations/11.0.4.4/post-migration.py diff --git a/runbot/migrations/4.5/post-migration.py b/runbot/migrations/11.0.4.5/post-migration.py similarity index 100% rename from runbot/migrations/4.5/post-migration.py rename to runbot/migrations/11.0.4.5/post-migration.py From 93b901dcdd461280cc0fc6e2e61d989b750c4a41 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Fri, 10 Jan 2020 11:54:29 +0100 Subject: [PATCH 12/18] [IMP] runbot: simplify views and adapt to odoo13 mainly fixes datetime and bootstrap layouts --- runbot/__manifest__.py | 3 +- runbot/controllers/badge.py | 2 +- runbot/controllers/frontend.py | 43 +++--- runbot/data/website_data.xml | 5 + runbot/models/build.py | 6 + runbot/models/build_config.py | 1 + runbot/models/build_error.py | 2 +- runbot/models/host.py | 7 +- runbot/static/src/css/runbot.css | 80 ++++++++++ runbot/static/src/less/runbot.less | 12 -- runbot/templates/branch.xml | 2 +- runbot/templates/build.xml | 92 +++++------- runbot/templates/dashboard.xml | 22 +-- runbot/templates/frontend.xml | 145 ++++++++++--------- runbot/tests/test_build.py | 2 + runbot/tests/test_frontend.py | 3 - runbot/views/assets.xml | 2 +- runbot/views/config_views.xml | 1 + runbot_cla/__manifest__.py | 2 +- runbot_cla/data/runbot_build_config_data.xml | 7 - 20 files changed, 239 insertions(+), 200 deletions(-) create mode 100644 runbot/data/website_data.xml create mode 100644 runbot/static/src/css/runbot.css delete mode 100644 runbot/static/src/less/runbot.less diff --git a/runbot/__manifest__.py b/runbot/__manifest__.py index 1583afd0..f29a7c28 100644 --- a/runbot/__manifest__.py +++ b/runbot/__manifest__.py @@ -6,7 +6,7 @@ 'author': "Odoo SA", 'website': "http://runbot.odoo.com", 'category': 'Website', - 'version': '4.6', + 'version': '4.8', 'depends': ['website', 'base'], 'data': [ 'security/runbot_security.xml', @@ -33,5 +33,6 @@ 'data/build_parse.xml', 'data/runbot_error_regex_data.xml', 'data/error_link.xml', + 'data/website_data.xml', ], } diff --git a/runbot/controllers/badge.py b/runbot/controllers/badge.py index 5903ac34..e6890e78 100644 --- a/runbot/controllers/badge.py +++ b/runbot/controllers/badge.py @@ -35,7 +35,7 @@ class RunbotBadge(Controller): build = builds[0] etag = request.httprequest.headers.get('If-None-Match') - retag = hashlib.md5(build[last_update].encode()).hexdigest() + retag = hashlib.md5(str(build[last_update]).encode()).hexdigest() if etag == retag: return werkzeug.wrappers.Response(status=304) diff --git a/runbot/controllers/frontend.py b/runbot/controllers/frontend.py index 4ad29ddf..12b6442c 100644 --- a/runbot/controllers/frontend.py +++ b/runbot/controllers/frontend.py @@ -39,6 +39,7 @@ class Runbot(Controller): 'host_stats': [], 'pending_total': pending[0], 'pending_level': pending[1], + 'hosts_data': request.env['runbot.host'].search([]), 'search': search, 'refresh': refresh, } @@ -101,15 +102,11 @@ class Runbot(Controller): def branch_info(branch): return { 'branch': branch, - 'fqdn': fqdn(), 'builds': [build_dict[build_id] for build_id in build_by_branch_ids.get(branch.id) or []] } context.update({ 'branches': [branch_info(b) for b in branches], - 'testing': build_obj.search_count([('repo_id', '=', repo.id), ('local_state', '=', 'testing')]), - 'running': build_obj.search_count([('repo_id', '=', repo.id), ('local_state', '=', 'running')]), - 'pending': build_obj.search_count([('repo_id', '=', repo.id), ('local_state', '=', 'pending')]), 'qu': QueryURL('/runbot/repo/' + slug(repo), search=search, refresh=refresh), 'fqdn': fqdn(), }) @@ -117,14 +114,6 @@ class Runbot(Controller): # consider host gone if no build in last 100 build_threshold = max(build_ids or [0]) - 100 - for result in build_obj.read_group([('id', '>', build_threshold)], ['host'], ['host']): - if result['host']: - context['host_stats'].append({ - 'host': result['host'], - 'testing': build_obj.search_count([('local_state', '=', 'testing'), ('host', '=', result['host'])]), - 'running': build_obj.search_count([('local_state', '=', 'running'), ('host', '=', result['host'])]), - }) - context.update({'message': request.env['ir.config_parameter'].sudo().get_param('runbot.runbot_message')}) return request.render('runbot.repo', context) @@ -302,21 +291,27 @@ class Runbot(Controller): return request.render("runbot.glances", qctx) @route('/runbot/monitoring', type='http', auth='user', website=True) - def monitoring(self, refresh=None): + @route('/runbot/monitoring/', type='http', auth='user', website=True) + @route('/runbot/monitoring//', type='http', auth='user', website=True) + def monitoring(self, config_id=None, view_id=None, refresh=None): glances_ctx = self._glances_ctx() pending = self._pending() hosts_data = request.env['runbot.host'].search([]) - monitored_config_id = int(request.env['ir.config_parameter'].sudo().get_param('runbot.monitored_config_id', 1)) - request.env.cr.execute("""SELECT DISTINCT ON (branch_id) branch_id, id FROM runbot_build - WHERE config_id = %s - AND global_state in ('running', 'done') - AND branch_id in (SELECT id FROM runbot_branch where sticky='t') - AND local_state != 'duplicate' - ORDER BY branch_id ASC, id DESC""", [int(monitored_config_id)]) - last_monitored = request.env['runbot.build'].browse([r[1] for r in request.env.cr.fetchall()]) + last_monitored = None + if config_id or config_id is None: + monitored_config_id = config_id or int(request.env['ir.config_parameter'].sudo().get_param('runbot.monitored_config_id', 1)) + request.env.cr.execute("""SELECT DISTINCT ON (branch_id) branch_id, id FROM runbot_build + WHERE config_id = %s + AND global_state in ('running', 'done') + AND branch_id in (SELECT id FROM runbot_branch where sticky='t') + AND local_state != 'duplicate' + ORDER BY branch_id ASC, id DESC""", [int(monitored_config_id)]) + last_monitored = request.env['runbot.build'].browse([r[1] for r in request.env.cr.fetchall()]) + config = request.env['runbot.build.config'].browse(monitored_config_id) qctx = { + 'config': config, 'refresh': refresh, 'pending_total': pending[0], 'pending_level': pending[1], @@ -326,7 +321,7 @@ class Runbot(Controller): 'auto_tags': request.env['runbot.build.error'].disabling_tags(), 'build_errors': request.env['runbot.build.error'].search([('random', '=', True)]) } - return request.render("runbot.monitoring", qctx) + return request.render(request.env['ir.ui.view'].browse('view_id') if view_id else config.monitoring_view_id.id or "runbot.monitoring", qctx) @route(['/runbot/branch/', '/runbot/branch//page/'], website=True, auth='public', type='http') def branch_builds(self, branch_id=None, search='', page=1, limit=50, refresh='', **kwargs): @@ -337,9 +332,9 @@ class Runbot(Controller): url='/runbot/branch/%s' % branch_id, total=builds_count, page=page, - step=50 + step=50, ) builds = request.env['runbot.build'].search(domain, limit=limit, offset=pager.get('offset',0)) - context = {'pager': pager, 'builds': builds} + context = {'pager': pager, 'builds': builds, 'repo': request.env['runbot.branch'].browse(branch_id).repo_id} return request.render("runbot.branch", context) diff --git a/runbot/data/website_data.xml b/runbot/data/website_data.xml new file mode 100644 index 00000000..104c9acf --- /dev/null +++ b/runbot/data/website_data.xml @@ -0,0 +1,5 @@ + + + /home + + diff --git a/runbot/models/build.py b/runbot/models/build.py index 1378482c..f76052b3 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -365,6 +365,8 @@ class runbot_build(models.Model): build.job_time = int(dt2time(build.job_end) - dt2time(build.job_start)) elif build.job_start: build.job_time = int(time.time() - dt2time(build.job_start)) + else: + build.job_time = 0 @api.depends('build_start', 'build_end', 'duplicate_id.build_time') def _compute_build_time(self): @@ -375,6 +377,8 @@ class runbot_build(models.Model): build.build_time = int(dt2time(build.build_end) - dt2time(build.build_start)) elif build.build_start: build.build_time = int(time.time() - dt2time(build.build_start)) + else: + build.build_time = 0 @api.depends('job_start', 'duplicate_id.build_age') def _compute_build_age(self): @@ -384,6 +388,8 @@ class runbot_build(models.Model): build.build_age = build.duplicate_id.build_age elif build.job_start: build.build_age = int(time.time() - dt2time(build.build_start)) + else: + build.build_age = 0 def _get_params(self): try: diff --git a/runbot/models/build_config.py b/runbot/models/build_config.py index 08fe2da0..8518844c 100644 --- a/runbot/models/build_config.py +++ b/runbot/models/build_config.py @@ -31,6 +31,7 @@ class Config(models.Model): protected = fields.Boolean('Protected', default=False, track_visibility='onchange') group = fields.Many2one('runbot.build.config', 'Configuration group', help="Group of config's and config steps") group_name = fields.Char('Group name', related='group.name') + monitoring_view_id = fields.Many2one('ir.ui.view', 'Monitoring view') @api.model_create_single def create(self, values): diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index 0eb9d419..94ddef09 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -163,7 +163,7 @@ class RunbotBuildError(models.Model): def test_tags_list(self): active_errors = self.search([('test_tags', '!=', 'False'), ('random', '=', True)]) test_tag_list = active_errors.mapped('test_tags') - return [test_tag for error_tags in test_tag_list for test_tag in error_tags.split(',')] + return [test_tag for error_tags in test_tag_list for test_tag in (error_tags or '').split(',')] @api.model def disabling_tags(self): diff --git a/runbot/models/host.py b/runbot/models/host.py index 46556b57..6ac52778 100644 --- a/runbot/models/host.py +++ b/runbot/models/host.py @@ -58,10 +58,15 @@ class RunboHost(models.Model): return int(icp.get_param('runbot.runbot_running_max', default=75)) def set_psql_conn_count(self): - _logger.debug('Updating psql connection count...') self.ensure_one() with local_pgadmin_cursor() as local_cr: local_cr.execute("SELECT sum(numbackends) FROM pg_stat_database;") res = local_cr.fetchone() self.psql_conn_count = res and res[0] or 0 + + def _total_testing(self): + return sum(host.nb_testing for host in self) + + def _total_workers(self): + return sum(host.get_nb_worker() for host in self) diff --git a/runbot/static/src/css/runbot.css b/runbot/static/src/css/runbot.css new file mode 100644 index 00000000..97439884 --- /dev/null +++ b/runbot/static/src/css/runbot.css @@ -0,0 +1,80 @@ +.separator { + border-top: 2px solid #666; + font-weight: bold; +} + +[data-toggle="collapse"] .fa:before { + content: "\f139"; +} + +[data-toggle="collapse"].collapsed .fa:before { + content: "\f13a"; +} + +body, .table{ + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + color:#444; +} + +.btn-default { + background-color: #fff; + color: #444; + border-color: #ccc; +} + +.btn-default:hover { + background-color: #ccc; + color: #444; + border-color: #ccc; +} + +.btn-sm, .btn-group-sm > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.89rem; + line-height: 1.5; + border-radius: 0.2rem; +} +.btn-ssm, .btn-group-ssm > .btn { + padding: 0.22rem 0.4rem; + font-size: 0.82rem; + line-height: 1; + border-radius: 0.2rem; +} + +.killed, .bg-killed, .bg-killed-light { + background-color: #aaa; +} + +.dropdown-toggle:after { content: none } + +.branch_name { + max-width: 250px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.branch_time { + float:right; + margin-left:10px; +} + +.bg-success-light { + background-color: #dff0d8; +} +.bg-danger-light { + background-color: #f2dede; +} +.bg-info-light { + background-color: #d9edf7; +} + +.text-info{ + color: #096b72 !important; +} +.build_subject_buttons { + display: flex; +} +.build_buttons { + margin-left: auto +} diff --git a/runbot/static/src/less/runbot.less b/runbot/static/src/less/runbot.less deleted file mode 100644 index dbad1694..00000000 --- a/runbot/static/src/less/runbot.less +++ /dev/null @@ -1,12 +0,0 @@ -.separator { - border-top: 2px solid #666; - font-weight: bold; -} - -[data-toggle="collapse"] .fa:before { - content: "\f139"; -} - -[data-toggle="collapse"].collapsed .fa:before { - content: "\f13a"; -} diff --git a/runbot/templates/branch.xml b/runbot/templates/branch.xml index 9e5f5f79..d92f8eb8 100644 --- a/runbot/templates/branch.xml +++ b/runbot/templates/branch.xml @@ -33,7 +33,7 @@ default killed - + diff --git a/runbot/templates/build.xml b/runbot/templates/build.xml index 1aa8b790..c2a1a2d9 100644 --- a/runbot/templates/build.xml +++ b/runbot/templates/build.xml @@ -40,13 +40,6 @@ - - - - - - - diff --git a/runbot/templates/dashboard.xml b/runbot/templates/dashboard.xml index da5630b3..07394522 100644 --- a/runbot/templates/dashboard.xml +++ b/runbot/templates/dashboard.xml @@ -141,21 +141,7 @@
- Pending: - 0 - 0 - - - - - - success - - info - warning - danger - - Testing: / +
@@ -178,9 +164,9 @@ danger / - - - + + + success info diff --git a/runbot/templates/frontend.xml b/runbot/templates/frontend.xml index 943a4650..c7a29692 100644 --- a/runbot/templates/frontend.xml +++ b/runbot/templates/frontend.xml @@ -2,13 +2,48 @@ - + + +