diff --git a/runbot/__manifest__.py b/runbot/__manifest__.py index 5085df56..dbcad1d5 100644 --- a/runbot/__manifest__.py +++ b/runbot/__manifest__.py @@ -6,18 +6,20 @@ 'author': "Odoo SA", 'website': "http://runbot.odoo.com", 'category': 'Website', - 'version': '5.9', + 'version': '5.10', 'application': True, 'depends': ['base', 'base_automation', 'website'], 'data': [ 'templates/dockerfile.xml', 'data/dockerfile_data.xml', + 'data/build_error_stage.xml', 'data/build_parse.xml', 'data/error_link.xml', 'data/runbot_build_config_data.xml', 'data/runbot_data.xml', 'data/runbot_error_regex_data.xml', 'data/website_data.xml', + 'data/ir_cron_data.xml', 'security/runbot_security.xml', 'security/ir.model.access.csv', diff --git a/runbot/data/build_error_stage.xml b/runbot/data/build_error_stage.xml new file mode 100644 index 00000000..b98e7b70 --- /dev/null +++ b/runbot/data/build_error_stage.xml @@ -0,0 +1,24 @@ + + + New/Unsolved + 5 + New build error detected by the runbot platform + + + Solved + 10 + Issue should be solved. Will automatically move to the Done state after some time + + + Ignored + 15 + Issue can be ignored, but should eventually be solved (for instance, test-tags) + True + + + Done + 20 + Issue is solved or dissapeared + True + + diff --git a/runbot/data/ir_cron_data.xml b/runbot/data/ir_cron_data.xml new file mode 100644 index 00000000..f55bf3f9 --- /dev/null +++ b/runbot/data/ir_cron_data.xml @@ -0,0 +1,10 @@ + + + Runbot: Update Build Errors Stage + + code + model._update_stage() + 1 + days + + diff --git a/runbot/migrations/18.0.5.10/post-migration.py b/runbot/migrations/18.0.5.10/post-migration.py new file mode 100644 index 00000000..9634646e --- /dev/null +++ b/runbot/migrations/18.0.5.10/post-migration.py @@ -0,0 +1,14 @@ + +from odoo import api, SUPERUSER_ID + + +def migrate(cr, version): + env = api.Environment(cr, SUPERUSER_ID, {}) + # By default, the build_error_stage is set to the new stage + build_error_stage_ignored = env.ref('runbot.build_error_stage_ignored').id + build_error_stage_done = env.ref('runbot.build_error_stage_done').id + + # Archived build errors are set are considered Done + env['runbot.build.error'].search([['active', "=", False]]).write({'stage_id': build_error_stage_done}) + # Build errors with test_tags are set to Ignored + env['runbot.build.error'].search([['test_tags', '!=', False]]).write({'stage_id': build_error_stage_ignored}) diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index c2eccda4..7ed3b19e 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -90,6 +90,18 @@ def _search_related_error_content_ids(field_name): return [(f'error_content_ids.{field_name}', operator, value)] return _search + +class BuildErrorStage(models.Model): + _name = 'runbot.build.error.stage' + _description = 'Build Error Stage' + _order = 'sequence' + + name = fields.Char(string='Stage Name', required=True) + description = fields.Text(string='Stage description') + sequence = fields.Integer('Sequence', default=1) + fold = fields.Boolean(string='Folded in Kanban', default=False) + + class BuildError(models.Model): _name = "runbot.build.error" _description = "Build error" @@ -105,6 +117,7 @@ class BuildError(models.Model): error_count = fields.Integer("Error count", store=True, compute='_compute_count') previous_error_id = fields.Many2one('runbot.build.error', string="Already seen error") + stage_id = fields.Many2one('runbot.build.error.stage', required=True, tracking=True, group_expand='_read_group_expand_full', default=lambda self: self.env['runbot.build.error.stage'].search([], limit=1)) responsible = fields.Many2one('res.users', 'Assigned fixer', tracking=True) customer = fields.Many2one('res.users', 'Customer', tracking=True) team_id = fields.Many2one('runbot.team', 'Assigned team', tracking=True) @@ -347,6 +360,7 @@ class BuildError(models.Model): @api.constrains('test_tags') def _check_test_tags(self): + self.stage_id = self.env.ref('runbot.build_error_stage_ignored').id for build_error in self: if build_error.test_tags and '-' in build_error.test_tags: raise ValidationError('Build error test_tags should not be negated') @@ -586,6 +600,37 @@ class BuildError(models.Model): base_error = self_sorted[0] base_error._merge(self_sorted - base_error) + def _update_stage(self, nbr_day_solved_to_done=7, nbr_day_new_to_done=15, nbr_day_done_to_archive=30): + """Called automatically by scheduled action to update the stage of the error if necessary""" + now = fields.Datetime.now() + build_error_stage_new = self.env.ref('runbot.build_error_stage_new').id + build_error_stage_solved = self.env.ref('runbot.build_error_stage_solved').id + build_error_stage_done = self.env.ref('runbot.build_error_stage_done').id + + # Very old done error eventually get archived + self.search([ + ('stage_id', '=', build_error_stage_done), + ('last_seen_date', '<', now - relativedelta(days=nbr_day_done_to_archive)), + ]).write({'active': False}) + + # Done errors that did happen again recently are moved back to new + self.search([ + ('stage_id', '=', build_error_stage_done), + ('last_seen_date', '>=', now - relativedelta(days=nbr_day_new_to_done)), + ]).write({'stage_id': build_error_stage_new}) + + # New error that did not appear after a long time are marked as done + # Solved error that did not appear after a short time are marked as done + self.search([ + '|', + '&', + ('stage_id', '=', build_error_stage_new), + ('last_seen_date', '<', now - relativedelta(days=nbr_day_new_to_done)), + '&', + ('stage_id', '=', build_error_stage_solved), + ('last_seen_date', '<', now - relativedelta(days=nbr_day_solved_to_done)), + ]).write({'stage_id': build_error_stage_done}) + class BuildErrorContent(models.Model): diff --git a/runbot/security/ir.model.access.csv b/runbot/security/ir.model.access.csv index cd54fa04..9e4dc2f9 100644 --- a/runbot/security/ir.model.access.csv +++ b/runbot/security/ir.model.access.csv @@ -151,4 +151,5 @@ access_runbot_build_stat_regex_wizard,access_runbot_build_stat_regex_wizard,mode access_runbot_host_message,access_runbot_host_message,runbot.model_runbot_host_message,runbot.group_runbot_admin,1,0,0,0 - +access_runbot_build_error_stage_user,access_runbot_build_error_stage_user,runbot.model_runbot_build_error_stage,base.group_user,1,0,0,0 +access_runbot_build_error_stage_admin,access_runbot_build_error_stage_admin,runbot.model_runbot_build_error_stage,base.group_user,1,1,1,1 diff --git a/runbot/views/build_error_views.xml b/runbot/views/build_error_views.xml index b1c30c92..e8e3fcae 100644 --- a/runbot/views/build_error_views.xml +++ b/runbot/views/build_error_views.xml @@ -5,6 +5,9 @@ runbot.build.error + + + @@ -329,6 +332,59 @@ list + + runbot.build.error.kanban + runbot.build.error + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + runbot.build.error.list runbot.build.error @@ -478,7 +534,7 @@ Errors runbot.build.error error - list,form + kanban,list,form {'search_default_not_fixed_errors': True, 'active_test': False}