mirror of
https://github.com/odoo/runbot.git
synced 2025-03-15 23:45:44 +07:00
[IMP] runbot: add the possibility to disable a test per version
When disabling tests on runbot by using the test_tags on a build error, the tests are disabled on every tested version. This can be annoying when a test only fails from one version up to another. With this commit, a min and max version can be specified on a build_error when the test_tags field is used. If the min and max are not used, the test will be disabled cross versions.
This commit is contained in:
parent
dff50b49c4
commit
33452d27e7
@ -455,7 +455,7 @@ class ConfigStep(models.Model):
|
|||||||
test_tags += self.test_tags.replace(' ', '').split(',')
|
test_tags += self.test_tags.replace(' ', '').split(',')
|
||||||
if self.enable_auto_tags and not build.params_id.config_data.get('disable_auto_tags', False):
|
if self.enable_auto_tags and not build.params_id.config_data.get('disable_auto_tags', False):
|
||||||
if grep(config_path, "[/module][:class]"):
|
if grep(config_path, "[/module][:class]"):
|
||||||
auto_tags = self.env['runbot.build.error']._disabling_tags()
|
auto_tags = self.env['runbot.build.error']._disabling_tags(build)
|
||||||
if auto_tags:
|
if auto_tags:
|
||||||
test_tags += auto_tags
|
test_tags += auto_tags
|
||||||
|
|
||||||
|
@ -73,6 +73,8 @@ class BuildError(models.Model):
|
|||||||
last_seen_build_id = fields.Many2one('runbot.build', compute='_compute_last_seen_build_id', string='Last Seen build', store=True)
|
last_seen_build_id = fields.Many2one('runbot.build', compute='_compute_last_seen_build_id', string='Last Seen build', store=True)
|
||||||
last_seen_date = fields.Datetime(string='Last Seen Date', compute='_compute_seen_date', store=True)
|
last_seen_date = fields.Datetime(string='Last Seen Date', compute='_compute_seen_date', store=True)
|
||||||
test_tags = fields.Char(string='Test tags', help="Comma separated list of test_tags to use to reproduce/remove this error", tracking=True)
|
test_tags = fields.Char(string='Test tags', help="Comma separated list of test_tags to use to reproduce/remove this error", tracking=True)
|
||||||
|
tags_min_version_id = fields.Many2one('runbot.version', 'Tags Min version', help="Minimal version where the test tags will be applied.")
|
||||||
|
tags_max_version_id = fields.Many2one('runbot.version', 'Tags Max version', help="Maximal version where the test tags will be applied.")
|
||||||
|
|
||||||
@api.constrains('test_tags')
|
@api.constrains('test_tags')
|
||||||
def _check_test_tags(self):
|
def _check_test_tags(self):
|
||||||
@ -80,6 +82,12 @@ class BuildError(models.Model):
|
|||||||
if build_error.test_tags and '-' in build_error.test_tags:
|
if build_error.test_tags and '-' in build_error.test_tags:
|
||||||
raise ValidationError('Build error test_tags should not be negated')
|
raise ValidationError('Build error test_tags should not be negated')
|
||||||
|
|
||||||
|
@api.onchange('test_tags')
|
||||||
|
def _onchange_test_tags(self):
|
||||||
|
for record in self:
|
||||||
|
record.tags_min_version_id = min(record.version_ids, key=lambda rec: rec.number)
|
||||||
|
record.tags_max_version_id = max(record.version_ids, key=lambda rec: rec.number)
|
||||||
|
|
||||||
@api.model_create_multi
|
@api.model_create_multi
|
||||||
def create(self, vals_list):
|
def create(self, vals_list):
|
||||||
cleaners = self.env['runbot.error.regex'].search([('re_type', '=', 'cleaning')])
|
cleaners = self.env['runbot.error.regex'].search([('re_type', '=', 'cleaning')])
|
||||||
@ -263,14 +271,22 @@ class BuildError(models.Model):
|
|||||||
return window_action
|
return window_action
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _test_tags_list(self):
|
def _test_tags_list(self, build_id=False):
|
||||||
active_errors = self.search([('test_tags', '!=', False)])
|
version = build_id.params_id.version_id.number if build_id else False
|
||||||
test_tag_list = active_errors.mapped('test_tags')
|
|
||||||
|
def filter_tags(e):
|
||||||
|
if version:
|
||||||
|
min_v = e.tags_min_version_id.number or ''
|
||||||
|
max_v = e.tags_max_version_id.number or '~'
|
||||||
|
return min_v <= version and max_v >= version
|
||||||
|
return True
|
||||||
|
|
||||||
|
test_tag_list = self.search([('test_tags', '!=', False)]).filtered(filter_tags).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).split(',')]
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _disabling_tags(self):
|
def _disabling_tags(self, build_id=False):
|
||||||
return ['-%s' % tag for tag in self._test_tags_list()]
|
return ['-%s' % tag for tag in self._test_tags_list(build_id)]
|
||||||
|
|
||||||
def _search_version(self, operator, value):
|
def _search_version(self, operator, value):
|
||||||
exclude_domain = []
|
exclude_domain = []
|
||||||
|
@ -29,6 +29,16 @@ class TestBuildError(RunbotCase):
|
|||||||
create_vals.update(vals)
|
create_vals.update(vals)
|
||||||
return self.Build.create(create_vals)
|
return self.Build.create(create_vals)
|
||||||
|
|
||||||
|
def create_params(self, vals):
|
||||||
|
create_vals = {
|
||||||
|
'version_id': self.version_13.id,
|
||||||
|
'project_id': self.project.id,
|
||||||
|
'config_id': self.default_config.id,
|
||||||
|
'create_batch_id': self.dev_batch.id,
|
||||||
|
}
|
||||||
|
create_vals.update(vals)
|
||||||
|
return self.BuildParameters.create(create_vals)
|
||||||
|
|
||||||
def create_log(self, vals):
|
def create_log(self, vals):
|
||||||
log_vals = {
|
log_vals = {
|
||||||
'level': 'ERROR',
|
'level': 'ERROR',
|
||||||
@ -301,7 +311,7 @@ class TestBuildError(RunbotCase):
|
|||||||
self.assertEqual(error_a.build_count, 1)
|
self.assertEqual(error_a.build_count, 1)
|
||||||
self.assertEqual(error_b.build_count, 2)
|
self.assertEqual(error_b.build_count, 2)
|
||||||
|
|
||||||
def test_build_error_test_tags(self):
|
def test_build_error_test_tags_no_version(self):
|
||||||
build_a = self.create_test_build({'local_result': 'ko'})
|
build_a = self.create_test_build({'local_result': 'ko'})
|
||||||
build_b = self.create_test_build({'local_result': 'ko'})
|
build_b = self.create_test_build({'local_result': 'ko'})
|
||||||
|
|
||||||
@ -309,34 +319,74 @@ class TestBuildError(RunbotCase):
|
|||||||
'content': 'foo',
|
'content': 'foo',
|
||||||
'build_ids': [(6, 0, [build_a.id])],
|
'build_ids': [(6, 0, [build_a.id])],
|
||||||
'random': True,
|
'random': True,
|
||||||
'active': True
|
'active': True,
|
||||||
|
'test_tags': 'foo,bar',
|
||||||
})
|
})
|
||||||
|
|
||||||
error_b = self.BuildError.create({
|
error_b = self.BuildError.create({
|
||||||
'content': 'bar',
|
'content': 'bar',
|
||||||
'build_ids': [(6, 0, [build_b.id])],
|
'build_ids': [(6, 0, [build_b.id])],
|
||||||
'random': True,
|
'random': True,
|
||||||
'active': False
|
'active': False,
|
||||||
|
'test_tags': 'blah',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
error_a.test_tags = 'foo,bar'
|
|
||||||
error_b.test_tags = 'blah'
|
|
||||||
self.assertIn('foo', self.BuildError._test_tags_list())
|
|
||||||
self.assertIn('bar', self.BuildError._test_tags_list())
|
|
||||||
self.assertIn('-foo', self.BuildError._disabling_tags())
|
self.assertIn('-foo', self.BuildError._disabling_tags())
|
||||||
self.assertIn('-bar', self.BuildError._disabling_tags())
|
self.assertIn('-bar', self.BuildError._disabling_tags())
|
||||||
|
|
||||||
# test that test tags on fixed errors are not taken into account
|
# test that test tags on fixed errors are not taken into account
|
||||||
self.assertNotIn('blah', self.BuildError._test_tags_list())
|
|
||||||
self.assertNotIn('-blah', self.BuildError._disabling_tags())
|
self.assertNotIn('-blah', self.BuildError._disabling_tags())
|
||||||
|
|
||||||
error_a.test_tags = False
|
error_a.test_tags = False
|
||||||
error_b.active = True
|
error_b.active = True
|
||||||
error_b.parent_id = error_a.id
|
error_b.parent_id = error_a.id
|
||||||
self.assertEqual(error_b.test_tags, False)
|
self.assertEqual(error_b.test_tags, False)
|
||||||
self.assertEqual(self.BuildError._disabling_tags(), ['-blah',])
|
self.assertEqual(self.BuildError._disabling_tags(), ['-blah'])
|
||||||
|
|
||||||
|
def test_build_error_test_tags_min_max_version(self):
|
||||||
|
version_17 = self.Version.create({'name': '17.0'})
|
||||||
|
version_saas_171 = self.Version.create({'name': 'saas-17.1'})
|
||||||
|
version_master = self.Version.create({'name': 'master'})
|
||||||
|
|
||||||
|
build_v13 = self.create_test_build({'local_result': 'ko'})
|
||||||
|
build_v17 = self.create_test_build({'local_result': 'ko', 'params_id': self.create_params({'version_id': version_17.id}).id})
|
||||||
|
build_saas_171 = self.create_test_build({'local_result': 'ko', 'params_id': self.create_params({'version_id': version_saas_171.id}).id})
|
||||||
|
build_master = self.create_test_build({'local_result': 'ko', 'params_id': self.create_params({'version_id': version_master.id}).id})
|
||||||
|
|
||||||
|
self.BuildError.create(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"content": "foobar",
|
||||||
|
"build_ids": [(6, 0, [build_v13.id])],
|
||||||
|
"test_tags": "every,where",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "blah",
|
||||||
|
"build_ids": [(6, 0, [build_v17.id])],
|
||||||
|
"test_tags": "tag_17_up_to_master",
|
||||||
|
"tags_min_version_id": version_17.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "spam",
|
||||||
|
"build_ids": [(6, 0, [build_v17.id])],
|
||||||
|
"test_tags": "tag_up_to_17",
|
||||||
|
"tags_max_version_id": version_17.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "eggs",
|
||||||
|
"build_ids": [(6, 0, [build_saas_171.id])],
|
||||||
|
"test_tags": "tag_only_17.1",
|
||||||
|
"tags_min_version_id": version_saas_171.id,
|
||||||
|
"tags_max_version_id": version_saas_171.id,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(sorted(['-every', '-where', '-tag_17_up_to_master', '-tag_up_to_17', '-tag_only_17.1']), sorted(self.BuildError._disabling_tags()), "Should return the whole list without parameters")
|
||||||
|
self.assertEqual(sorted(['-every', '-where', '-tag_up_to_17']), sorted(self.BuildError._disabling_tags(build_v13)))
|
||||||
|
self.assertEqual(sorted(['-every', '-where', '-tag_up_to_17', '-tag_17_up_to_master']), sorted(self.BuildError._disabling_tags(build_v17)))
|
||||||
|
self.assertEqual(sorted(['-every', '-where', '-tag_17_up_to_master', '-tag_only_17.1']), sorted(self.BuildError._disabling_tags(build_saas_171)))
|
||||||
|
self.assertEqual(sorted(['-every', '-where', '-tag_17_up_to_master']), sorted(self.BuildError._disabling_tags(build_master)))
|
||||||
|
|
||||||
def test_build_error_team_wildcards(self):
|
def test_build_error_team_wildcards(self):
|
||||||
website_team = self.BuildErrorTeam.create({
|
website_team = self.BuildErrorTeam.create({
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
<field name="active"/>
|
<field name="active"/>
|
||||||
<field name="test_tags" decoration-danger="True" readonly="1" groups="!runbot.group_runbot_admin"/>
|
<field name="test_tags" decoration-danger="True" readonly="1" groups="!runbot.group_runbot_admin"/>
|
||||||
<field name="test_tags" decoration-danger="True" groups="runbot.group_runbot_admin" readonly="parent_id and not test_tags"/>
|
<field name="test_tags" decoration-danger="True" groups="runbot.group_runbot_admin" readonly="parent_id and not test_tags"/>
|
||||||
|
<field name="tags_min_version_id" invisible="not test_tags"/>
|
||||||
|
<field name="tags_max_version_id" invisible="not test_tags"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="version_ids" widget="many2many_tags"/>
|
<field name="version_ids" widget="many2many_tags"/>
|
||||||
@ -147,8 +149,8 @@
|
|||||||
<field name="name">runbot.build.error.tree</field>
|
<field name="name">runbot.build.error.tree</field>
|
||||||
<field name="model">runbot.build.error</field>
|
<field name="model">runbot.build.error</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="Errors"
|
<tree string="Errors"
|
||||||
decoration-danger="test_tags and (fixing_pr_alive or not fixing_pr_id)"
|
decoration-danger="test_tags and (fixing_pr_alive or not fixing_pr_id)"
|
||||||
decoration-success="fixing_pr_id and not test_tags and not fixing_pr_alive"
|
decoration-success="fixing_pr_id and not test_tags and not fixing_pr_alive"
|
||||||
decoration-warning="test_tags and fixing_pr_id and not fixing_pr_alive"
|
decoration-warning="test_tags and fixing_pr_id and not fixing_pr_alive"
|
||||||
multi_edit="1"
|
multi_edit="1"
|
||||||
@ -157,14 +159,17 @@
|
|||||||
<header>
|
<header>
|
||||||
<button name="%(runbot.runbot_open_bulk_wizard)d" string="Bulk Update" type="action" groups="runbot.group_runbot_admin,runbot.group_runbot_error_manager"/>
|
<button name="%(runbot.runbot_open_bulk_wizard)d" string="Bulk Update" type="action" groups="runbot.group_runbot_admin,runbot.group_runbot_error_manager"/>
|
||||||
</header>
|
</header>
|
||||||
<field name="module_name" readonly="1"/>
|
<field name="module_name" optional="show" readonly="1"/>
|
||||||
<field name="summary" readonly="1"/>
|
<field name="summary" optional="show" readonly="1"/>
|
||||||
<field name="random" string="Random"/>
|
<field name="random" string="Random"/>
|
||||||
|
<field name="first_seen_date" string="First Seen" optional="hide" readonly="1"/>
|
||||||
<field name="last_seen_date" string="Last Seen" readonly="1"/>
|
<field name="last_seen_date" string="Last Seen" readonly="1"/>
|
||||||
<field name="build_count" readonly="1"/>
|
<field name="build_count" readonly="1"/>
|
||||||
<field name="responsible"/>
|
<field name="responsible"/>
|
||||||
<field name="team_id"/>
|
<field name="team_id"/>
|
||||||
<field name="test_tags"/>
|
<field name="test_tags"/>
|
||||||
|
<field name="tags_min_version_id" string="Tags Min" optional="show"/>
|
||||||
|
<field name="tags_max_version_id" string="Tags Max" optional="show"/>
|
||||||
<field name="fixing_pr_id"/>
|
<field name="fixing_pr_id"/>
|
||||||
<field name="fixing_pr_alive" invisible="1"/>
|
<field name="fixing_pr_alive" invisible="1"/>
|
||||||
<field name="fixing_pr_url" widget="url" text="view PR" readonly="1" invisible="not fixing_pr_url"/>
|
<field name="fixing_pr_url" widget="url" text="view PR" readonly="1" invisible="not fixing_pr_url"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user