diff --git a/runbot/__manifest__.py b/runbot/__manifest__.py index b05c3648..5d3c77ac 100644 --- a/runbot/__manifest__.py +++ b/runbot/__manifest__.py @@ -41,6 +41,7 @@ 'views/build_error_views.xml', 'views/build_views.xml', 'views/bundle_views.xml', + 'views/codeowner_views.xml', 'views/commit_views.xml', 'views/config_views.xml', 'views/dashboard_views.xml', diff --git a/runbot/models/__init__.py b/runbot/models/__init__.py index b7acd3b0..3850b732 100644 --- a/runbot/models/__init__.py +++ b/runbot/models/__init__.py @@ -6,6 +6,7 @@ from . import build from . import build_config from . import build_error from . import bundle +from . import codeowner from . import commit from . import database from . import dockerfile @@ -22,5 +23,6 @@ from . import upgrade from . import user from . import version +# those imports have to be at the end otherwise the sql view cannot be initialised from . import build_stat from . import build_stat_regex diff --git a/runbot/models/codeowner.py b/runbot/models/codeowner.py new file mode 100644 index 00000000..342cc28e --- /dev/null +++ b/runbot/models/codeowner.py @@ -0,0 +1,30 @@ +import ast +import re + +from odoo import models, fields, api +from odoo.exceptions import ValidationError + + +class Codeowner(models.Model): + _name = 'runbot.codeowner' + _description = "Notify github teams based on filenames regex" + _inherit = "mail.thread" + + project_id = fields.Many2one('runbot.project', required=True) + regex = fields.Char('Regular Expression', help='Regex to match full file paths', required=True, tracking=True) + github_teams = fields.Char(help='Comma separated list of github teams to notify', required=True, tracking=True) + team_id = fields.Many2one('runbot.team', help='Not mandatory runbot team') + version_domain = fields.Char('Version Domain', help='Codeowner only applies to the filtered versions') + + @api.constrains('regex') + def _validate_regex(self): + for rec in self: + try: + r = re.compile(rec.regex) + except re.error as e: + raise ValidationError("Unable to compile regular expression: %s" % e) + + def _get_version_domain(self): + """ Helper to get the evaluated version domain """ + self.ensure_one() + return ast.eval(self.version_domain) if self.version_domain else [] diff --git a/runbot/security/ir.model.access.csv b/runbot/security/ir.model.access.csv index e5bdabbe..3fec37f8 100644 --- a/runbot/security/ir.model.access.csv +++ b/runbot/security/ir.model.access.csv @@ -111,3 +111,6 @@ access_runbot_upgrade_exception_admin,access_runbot_upgrade_exception_admin,runb access_runbot_dockerfile_user,access_runbot_dockerfile_user,runbot.model_runbot_dockerfile,runbot.group_user,1,0,0,0 access_runbot_dockerfile_admin,access_runbot_dockerfile_admin,runbot.model_runbot_dockerfile,runbot.group_runbot_admin,1,1,1,1 + +access_runbot_codeowner_admin,runbot_codeowner_admin,runbot.model_runbot_codeowner,runbot.group_runbot_admin,1,1,1,1 +access_runbot_codeowner_user,runbot_codeowner_user,runbot.model_runbot_codeowner,group_user,1,0,0,0 diff --git a/runbot/tests/test_build_error.py b/runbot/tests/test_build_error.py index 48686be3..b898ee94 100644 --- a/runbot/tests/test_build_error.py +++ b/runbot/tests/test_build_error.py @@ -191,3 +191,35 @@ class TestBuildError(RunbotCase): }) self.assertEqual(dashboard.build_ids, failed_build) + +class TestCodeOwner(RunbotCase): + + def setUp(self): + super().setUp() + self.cow_deb = self.env['runbot.codeowner'].create({ + 'project_id' : self.project.id, + 'github_teams': 'runbot', + 'regex': '.*debian.*' + }) + + self.cow_web = self.env['runbot.codeowner'].create({ + 'project_id' : self.project.id, + 'github_teams': 'website', + 'regex': '.*website.*' + }) + + self.cow_crm = self.env['runbot.codeowner'].create({ + 'project_id' : self.project.id, + 'github_teams': 'crm', + 'regex': '.*crm.*' + }) + + self.cow_all = self.cow_deb | self.cow_web | self.cow_crm + + def test_codeowner_invalid_regex(self): + with self.assertRaises(ValidationError): + self.env['runbot.codeowner'].create({ + 'project_id': self.project.id, + 'regex': '*debian.*', + 'github_teams': 'rd-test' + }) diff --git a/runbot/views/codeowner_views.xml b/runbot/views/codeowner_views.xml new file mode 100644 index 00000000..f8316b4b --- /dev/null +++ b/runbot/views/codeowner_views.xml @@ -0,0 +1,53 @@ + + + + runbot.codeowner.form + runbot.codeowner + +
+ + + + + + + + + +
+ + +
+
+
+
+ + + runbot.codeowner.tree + runbot.codeowner + + + + + + + + + + + + + Codeowner + runbot.codeowner + tree,form + + + +
+