From 6c3e359f030acd2511a42d457800b96f662bca39 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Wed, 20 Aug 2025 09:52:01 +0200 Subject: [PATCH] [IMP] runbot: use batch date for first seen date The log date can be useful to identify a pattern in apparition (alway arround midnight, ...) but it is usually less relevant for apparition when when usually focus on the "commit" so the batch date Moreover the log date can be misleading when the build ran in faketime. Even if it is not always the case, it is possible to have log_dates in the future. --- runbot/__manifest__.py | 2 +- runbot/migrations/18.0.5.13/pre-migration.py | 9 +++ runbot/models/build_error.py | 6 +- runbot/tests/test_build_error.py | 70 +++++++++++--------- runbot/views/build_error_views.xml | 2 +- 5 files changed, 52 insertions(+), 37 deletions(-) create mode 100644 runbot/migrations/18.0.5.13/pre-migration.py diff --git a/runbot/__manifest__.py b/runbot/__manifest__.py index a5ba3408e..173a849df 100644 --- a/runbot/__manifest__.py +++ b/runbot/__manifest__.py @@ -6,7 +6,7 @@ 'author': "Odoo SA", 'website': "http://runbot.odoo.com", 'category': 'Website', - 'version': '5.12', + 'version': '5.13', 'application': True, 'depends': ['base', 'base_automation', 'website'], 'data': [ diff --git a/runbot/migrations/18.0.5.13/pre-migration.py b/runbot/migrations/18.0.5.13/pre-migration.py new file mode 100644 index 000000000..bbdc1b9d2 --- /dev/null +++ b/runbot/migrations/18.0.5.13/pre-migration.py @@ -0,0 +1,9 @@ +def migrate(cr, version): + cr.execute('ALTER TABLE runbot_build_error_link ADD COLUMN batch_id INT') + cr.execute('ALTER TABLE runbot_build_error_link ADD COLUMN batch_date TIMESTAMP WITHOUT TIME ZONE') + cr.execute(''' + UPDATE runbot_build_error_link SET batch_id = batch.id, batch_date = batch.create_date + FROM runbot_batch as batch + JOIN runbot_build build on build.create_batch_id = batch.id + JOIN runbot_build_error_link as link on link.build_id = build.id + ''') \ No newline at end of file diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index 03aec74c5..3efdffec6 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -39,6 +39,8 @@ class BuildErrorLink(models.Model): build_id = fields.Many2one('runbot.build', required=True, index=True) error_content_id = fields.Many2one('runbot.build.error.content', required=True, index=True, ondelete='cascade') log_date = fields.Datetime(string='Log date') + batch_id = fields.Many2one('runbot.batch', related='build_id.create_batch_id', string='Batch', store=True, readonly=True) + batch_date = fields.Datetime(related='batch_id.create_date', string='Batch date', store=True, readonly=True) host = fields.Char(related='build_id.host') dest = fields.Char(related='build_id.dest') version_id = fields.Many2one(related='build_id.version_id') @@ -75,8 +77,8 @@ def _compute_seen(self): if error_link_ids: first_error_link = error_link_ids[0] last_error_link = error_link_ids[-1] - record.first_seen_date = first_error_link.log_date - record.last_seen_date = last_error_link.log_date + record.first_seen_date = first_error_link.batch_date + record.last_seen_date = last_error_link.batch_date record.first_seen_build_id = first_error_link.build_id record.last_seen_build_id = last_error_link.build_id record.build_count = len(error_link_ids.build_id) diff --git a/runbot/tests/test_build_error.py b/runbot/tests/test_build_error.py index 941dc6521..9a8054581 100644 --- a/runbot/tests/test_build_error.py +++ b/runbot/tests/test_build_error.py @@ -39,9 +39,10 @@ def setUpClass(cls): cls.x_test_class = cls.env['ir.model.fields'].search([('name', '=', 'x_test_class'), ('model_id', '=', model)], limit=1) cls.x_test_method = cls.env['ir.model.fields'].search([('name', '=', 'x_test_method'), ('model_id', '=', model)], limit=1) - def create_test_build(self, vals): + def create_test_build(self, vals, params_vals=None): + params = self.create_params(params_vals or {}) create_vals = { - 'params_id': self.base_params.id, + 'params_id': params.id, 'port': '1234', 'local_result': 'ok' } @@ -380,48 +381,51 @@ def test_build_scan(self): def test_seen_date(self): # create all the records before the tests to evaluate compute dependencies - build_a = self.create_test_build({'local_result': 'ok', 'local_state': 'testing'}) - first_seen_date = fields.Datetime.from_string('2023-08-29 00:46:21') - self.create_log({'create_date': first_seen_date, 'message': RTE_ERROR, 'build_id': build_a.id}) - - build_b = self.create_test_build({'local_result': 'ok', 'local_state': 'testing'}) - new_seen_date = fields.Datetime.from_string('2023-08-29 02:46:21') - self.create_log({'create_date': new_seen_date, 'message': RTE_ERROR, 'build_id': build_b.id}) - - build_c = self.create_test_build({'local_result': 'ok', 'local_state': 'testing'}) - child_seen_date = fields.Datetime.from_string('2023-09-01 12:00:00') - self.create_log({'create_date': child_seen_date, 'message': 'Fail: foo bar error', 'build_id': build_c.id}) + trigger = self.Trigger.create({ + 'name': 'test-trigger', + 'batch_dependent': True, + 'project_id': self.project.id, + 'config_id': self.default_config.id, + }) + batch_date = fields.Datetime.from_string('2023-08-28 19:00:01') + log_date = fields.Datetime.from_string('2023-08-29 00:46:21') + self.fist_batch = self.Batch.create({ + 'bundle_id': self.dev_bundle.id, + }) + self.env.cr.execute('UPDATE runbot_batch SET create_date = %s WHERE id = %s', (batch_date, self.fist_batch.id)) # Update in sql to avoid getting removed + self.fist_batch.invalidate_recordset() + self.assertEqual(self.fist_batch.create_date, batch_date, 'Batch create date should be set') - build_d = self.create_test_build({'local_result': 'ok', 'local_state': 'testing'}) - new_child_seen_date = fields.Datetime.from_string('2023-09-02 12:00:00') - self.create_log({'create_date': new_child_seen_date, 'message': 'Fail: foo bar error', 'build_id': build_d.id}) + build_a = self.create_test_build({'local_result': 'ok', 'local_state': 'testing'}, {'create_batch_id': self.fist_batch.id, 'trigger_id': trigger.id}) + self.assertEqual(build_a.create_batch_id, self.fist_batch, 'Build should be linked to the batch') + self.create_log({'create_date': log_date, 'message': RTE_ERROR, 'build_id': build_a.id}) build_a._parse_logs() build_error_a = build_a.build_error_ids - self.assertEqual(build_error_a.first_seen_date, first_seen_date) self.assertEqual(build_error_a.first_seen_build_id, build_a) - self.assertEqual(build_error_a.last_seen_date, first_seen_date) + self.assertEqual(build_error_a.first_seen_build_id.create_batch_id, self.fist_batch) + self.assertEqual(build_error_a.first_seen_date, batch_date) self.assertEqual(build_error_a.last_seen_build_id, build_a) + self.assertEqual(build_error_a.last_seen_build_id.create_batch_id, self.fist_batch) + self.assertEqual(build_error_a.last_seen_date, batch_date) + + new_batch_date = fields.Datetime.from_string('2023-08-29 19:00:01') + new_log_date = fields.Datetime.from_string('2023-08-30 00:48:21') + self.new_batch = self.Batch.create({ + 'bundle_id': self.dev_bundle.id, + }) + self.env.cr.execute('UPDATE runbot_batch SET create_date = %s WHERE id = %s', (new_batch_date, self.new_batch.id)) # Update in sql to avoid getting removed + self.new_batch.invalidate_recordset() + self.assertEqual(self.new_batch.create_date, new_batch_date, 'New batch create date should be set') + + build_b = self.create_test_build({'local_result': 'ok', 'local_state': 'testing'}, {'create_batch_id': self.new_batch.id, 'trigger_id': trigger.id}) + self.create_log({'create_date': new_log_date, 'message': RTE_ERROR, 'build_id': build_b.id}) # a new build with the same error should be the last seen build_b._parse_logs() - self.assertEqual(build_error_a.last_seen_date, new_seen_date) + self.assertEqual(build_error_a.last_seen_date, new_batch_date) self.assertEqual(build_error_a.last_seen_build_id, build_b) - # a new build error is linked to the current one - build_c._parse_logs() - build_error_c = build_c.build_error_ids - self.assertNotIn(build_c, build_error_a.build_ids) - build_error_a._merge(build_error_c) - self.assertIn(build_c, build_error_a.build_ids) - self.assertEqual(build_error_a.last_seen_date, child_seen_date) - self.assertEqual(build_error_a.last_seen_build_id, build_c) - - # a new build appears in the linked error - build_d._parse_logs() - self.assertEqual(build_error_a.last_seen_date, new_child_seen_date) - self.assertEqual(build_error_a.last_seen_build_id, build_d) - def test_build_error_links(self): build_a = self.create_test_build({'local_result': 'ko'}) build_b = self.create_test_build({'local_result': 'ko'}) diff --git a/runbot/views/build_error_views.xml b/runbot/views/build_error_views.xml index 7f5646211..b382b3651 100644 --- a/runbot/views/build_error_views.xml +++ b/runbot/views/build_error_views.xml @@ -34,7 +34,6 @@ - @@ -50,6 +49,7 @@ +