[IMP] runbot: implement public model mixin for bundle

Implements the public model mixin for `runbot.bundle` and make enough
fields public to be able to render the runbot homepage.
This commit is contained in:
William Braeckman 2025-03-17 13:37:24 +01:00
parent b51909fab6
commit 06690b1810
11 changed files with 160 additions and 69 deletions

View File

@ -12,16 +12,17 @@ _logger = logging.getLogger(__name__)
class Batch(models.Model): class Batch(models.Model):
_name = 'runbot.batch' _name = 'runbot.batch'
_description = "Bundle batch" _description = "Bundle batch"
_inherit = ['runbot.public.model.mixin']
last_update = fields.Datetime('Last ref update') last_update = fields.Datetime('Last ref update', public=True)
bundle_id = fields.Many2one('runbot.bundle', required=True, index=True, ondelete='cascade') bundle_id = fields.Many2one('runbot.bundle', required=True, index=True, ondelete='cascade')
commit_link_ids = fields.Many2many('runbot.commit.link') commit_link_ids = fields.Many2many('runbot.commit.link', public=True)
commit_ids = fields.Many2many('runbot.commit', compute='_compute_commit_ids') commit_ids = fields.Many2many('runbot.commit', compute='_compute_commit_ids')
slot_ids = fields.One2many('runbot.batch.slot', 'batch_id') slot_ids = fields.One2many('runbot.batch.slot', 'batch_id', public=True)
all_build_ids = fields.Many2many('runbot.build', compute='_compute_all_build_ids', help="Recursive builds") all_build_ids = fields.Many2many('runbot.build', compute='_compute_all_build_ids', help="Recursive builds")
state = fields.Selection([('preparing', 'Preparing'), ('ready', 'Ready'), ('done', 'Done'), ('skipped', 'Skipped')]) state = fields.Selection([('preparing', 'Preparing'), ('ready', 'Ready'), ('done', 'Done'), ('skipped', 'Skipped')], public=True)
hidden = fields.Boolean('Hidden', default=False) hidden = fields.Boolean('Hidden', default=False)
age = fields.Integer(compute='_compute_age', string='Build age') age = fields.Integer(compute='_compute_age', string='Build age', public=True)
category_id = fields.Many2one('runbot.category', index=True, default=lambda self: self.env.ref('runbot.default_category', raise_if_not_found=False)) category_id = fields.Many2one('runbot.category', index=True, default=lambda self: self.env.ref('runbot.default_category', raise_if_not_found=False))
log_ids = fields.One2many('runbot.batch.log', 'batch_id') log_ids = fields.One2many('runbot.batch.log', 'batch_id')
has_warning = fields.Boolean("Has warning") has_warning = fields.Boolean("Has warning")
@ -34,6 +35,10 @@ class Batch(models.Model):
column2='referenced_batch_id', column2='referenced_batch_id',
) )
@api.model
def _api_project_id_field_path(self):
return 'bundle_id.project_id'
@api.depends('slot_ids.build_id') @api.depends('slot_ids.build_id')
def _compute_all_build_ids(self): def _compute_all_build_ids(self):
all_builds = self.env['runbot.build'].search([('id', 'child_of', self.slot_ids.build_id.ids)]) all_builds = self.env['runbot.build'].search([('id', 'child_of', self.slot_ids.build_id.ids)])
@ -522,20 +527,25 @@ class BatchSlot(models.Model):
_name = 'runbot.batch.slot' _name = 'runbot.batch.slot'
_description = 'Link between a bundle batch and a build' _description = 'Link between a bundle batch and a build'
_order = 'trigger_id,id' _order = 'trigger_id,id'
_inherit = ['runbot.public.model.mixin']
batch_id = fields.Many2one('runbot.batch', index=True) batch_id = fields.Many2one('runbot.batch', index=True, public=True)
trigger_id = fields.Many2one('runbot.trigger', index=True) trigger_id = fields.Many2one('runbot.trigger', index=True, public=True)
build_id = fields.Many2one('runbot.build', index=True) build_id = fields.Many2one('runbot.build', index=True, public=True)
all_build_ids = fields.Many2many('runbot.build', compute='_compute_all_build_ids') all_build_ids = fields.Many2many('runbot.build', compute='_compute_all_build_ids', public=True)
params_id = fields.Many2one('runbot.build.params', index=True, required=True) params_id = fields.Many2one('runbot.build.params', index=True, required=True)
link_type = fields.Selection([('created', 'Build created'), ('matched', 'Existing build matched'), ('rebuild', 'Rebuild')], required=True) # rebuild type? link_type = fields.Selection([('created', 'Build created'), ('matched', 'Existing build matched'), ('rebuild', 'Rebuild')], required=True, public=True) # rebuild type?
active = fields.Boolean('Attached', default=True) active = fields.Boolean('Attached', default=True, public=True)
skipped = fields.Boolean('Skipped', default=False) skipped = fields.Boolean('Skipped', default=False)
# rebuild, what to do: since build can be in multiple batch: # rebuild, what to do: since build can be in multiple batch:
# - replace for all batch? # - replace for all batch?
# - only available on batch and replace for batch only? # - only available on batch and replace for batch only?
# - create a new bundle batch will new linked build? # - create a new bundle batch will new linked build?
@api.model
def _api_request_allow_direct_access(self):
return False
@api.depends('build_id') @api.depends('build_id')
def _compute_all_build_ids(self): def _compute_all_build_ids(self):
all_builds = self.env['runbot.build'].search([('id', 'child_of', self.build_id.ids)]) all_builds = self.env['runbot.build'].search([('id', 'child_of', self.build_id.ids)])

View File

@ -13,10 +13,11 @@ class Branch(models.Model):
_description = "Branch" _description = "Branch"
_order = 'name' _order = 'name'
_rec_name = 'dname' _rec_name = 'dname'
_inherit = ['runbot.public.model.mixin']
_sql_constraints = [('branch_repo_uniq', 'unique (name,remote_id)', 'The branch must be unique per repository !')] _sql_constraints = [('branch_repo_uniq', 'unique (name,remote_id)', 'The branch must be unique per repository !')]
name = fields.Char('Name', required=True) name = fields.Char('Name', required=True, public=True)
remote_id = fields.Many2one('runbot.remote', 'Remote', required=True, ondelete='cascade', index=True) remote_id = fields.Many2one('runbot.remote', 'Remote', required=True, ondelete='cascade', index=True)
head = fields.Many2one('runbot.commit', 'Head Commit', index=True) head = fields.Many2one('runbot.commit', 'Head Commit', index=True)
@ -25,7 +26,7 @@ class Branch(models.Model):
reference_name = fields.Char(compute='_compute_reference_name', string='Bundle name', store=True) reference_name = fields.Char(compute='_compute_reference_name', string='Bundle name', store=True)
bundle_id = fields.Many2one('runbot.bundle', 'Bundle', ondelete='cascade', index=True) bundle_id = fields.Many2one('runbot.bundle', 'Bundle', ondelete='cascade', index=True)
is_pr = fields.Boolean('IS a pr', required=True) is_pr = fields.Boolean('IS a pr', required=True, public=True)
pr_title = fields.Char('Pr Title') pr_title = fields.Char('Pr Title')
pr_body = fields.Char('Pr Body') pr_body = fields.Char('Pr Body')
pr_author = fields.Char('Pr Author') pr_author = fields.Char('Pr Author')
@ -37,12 +38,16 @@ class Branch(models.Model):
reflog_ids = fields.One2many('runbot.ref.log', 'branch_id') reflog_ids = fields.One2many('runbot.ref.log', 'branch_id')
branch_url = fields.Char(compute='_compute_branch_url', string='Branch url', readonly=True) branch_url = fields.Char(compute='_compute_branch_url', string='Branch url', readonly=True, public=True)
dname = fields.Char('Display name', compute='_compute_dname', search='_search_dname') dname = fields.Char('Display name', compute='_compute_dname', search='_search_dname', public=True)
alive = fields.Boolean('Alive', default=True) alive = fields.Boolean('Alive', default=True)
draft = fields.Boolean('Draft', store=True) draft = fields.Boolean('Draft', store=True)
@api.model
def _api_project_id_field_path(self):
return 'bundle_id.project_id'
@api.depends('name', 'remote_id.short_name') @api.depends('name', 'remote_id.short_name')
def _compute_dname(self): def _compute_dname(self):
for branch in self: for branch in self:

View File

@ -49,6 +49,7 @@ def make_selection(array):
class BuildParameters(models.Model): class BuildParameters(models.Model):
_name = 'runbot.build.params' _name = 'runbot.build.params'
_description = "All information used by a build to run, should be unique and set on create only" _description = "All information used by a build to run, should be unique and set on create only"
_inherit = ['runbot.public.model.mixin']
# on param or on build? # on param or on build?
# execution parametter # execution parametter
@ -56,17 +57,17 @@ class BuildParameters(models.Model):
commit_ids = fields.Many2many('runbot.commit', compute='_compute_commit_ids') commit_ids = fields.Many2many('runbot.commit', compute='_compute_commit_ids')
version_id = fields.Many2one('runbot.version', required=True, index=True) version_id = fields.Many2one('runbot.version', required=True, index=True)
project_id = fields.Many2one('runbot.project', required=True, index=True) # for access rights project_id = fields.Many2one('runbot.project', required=True, index=True) # for access rights
trigger_id = fields.Many2one('runbot.trigger', index=True) # for access rights trigger_id = fields.Many2one('runbot.trigger', index=True, public=True) # for access rights
create_batch_id = fields.Many2one('runbot.batch', index=True) create_batch_id = fields.Many2one('runbot.batch', index=True, public=True)
category = fields.Char('Category', index=True) # normal vs nightly vs weekly, ... category = fields.Char('Category', index=True, public=True) # normal vs nightly vs weekly, ...
dockerfile_id = fields.Many2one('runbot.dockerfile', index=True, default=lambda self: self.env.ref('runbot.docker_default', raise_if_not_found=False)) dockerfile_id = fields.Many2one('runbot.dockerfile', index=True, default=lambda self: self.env.ref('runbot.docker_default', raise_if_not_found=False))
skip_requirements = fields.Boolean('Skip requirements.txt auto install') skip_requirements = fields.Boolean('Skip requirements.txt auto install')
# other informations # other informations
extra_params = fields.Char('Extra cmd args') extra_params = fields.Char('Extra cmd args')
config_id = fields.Many2one('runbot.build.config', 'Run Config', required=True, config_id = fields.Many2one('runbot.build.config', 'Run Config', required=True, public=True,
default=lambda self: self.env.ref('runbot.runbot_build_config_default', raise_if_not_found=False), index=True) default=lambda self: self.env.ref('runbot.runbot_build_config_default', raise_if_not_found=False), index=True)
config_data = JsonDictField('Config Data') config_data = JsonDictField('Config Data', public=True)
used_custom_trigger = fields.Boolean('Custom trigger was used to generate this build') used_custom_trigger = fields.Boolean('Custom trigger was used to generate this build', public=True)
build_ids = fields.One2many('runbot.build', 'params_id') build_ids = fields.One2many('runbot.build', 'params_id')
builds_reference_ids = fields.Many2many('runbot.build', relation='runbot_build_params_references', copy=True) builds_reference_ids = fields.Many2many('runbot.build', relation='runbot_build_params_references', copy=True)
@ -84,6 +85,10 @@ class BuildParameters(models.Model):
('unique_fingerprint', 'unique (fingerprint)', 'avoid duplicate params'), ('unique_fingerprint', 'unique (fingerprint)', 'avoid duplicate params'),
] ]
@api.model
def _api_request_allow_direct_access(self):
return False
# @api.depends('version_id', 'project_id', 'extra_params', 'config_id', 'config_data', 'modules', 'commit_link_ids', 'builds_reference_ids') # @api.depends('version_id', 'project_id', 'extra_params', 'config_id', 'config_data', 'modules', 'commit_link_ids', 'builds_reference_ids')
def _compute_fingerprint(self): def _compute_fingerprint(self):
for param in self: for param in self:
@ -141,6 +146,7 @@ class BuildResult(models.Model):
_name = 'runbot.build' _name = 'runbot.build'
_description = "Build" _description = "Build"
_inherit = ['runbot.public.model.mixin']
_parent_store = True _parent_store = True
_order = 'id desc' _order = 'id desc'
@ -154,27 +160,27 @@ class BuildResult(models.Model):
no_auto_run = fields.Boolean('No run') no_auto_run = fields.Boolean('No run')
# could be a default value, but possible to change it to allow duplicate accros branches # could be a default value, but possible to change it to allow duplicate accros branches
description = fields.Char('Description', help='Informative description') description = fields.Char('Description', help='Informative description', public=True)
md_description = fields.Html(compute='_compute_md_description', string='MD Parsed Description', help='Informative description markdown parsed', sanitize=False) md_description = fields.Html(compute='_compute_md_description', string='MD Parsed Description', help='Informative description markdown parsed', sanitize=False, public=True)
display_name = fields.Char(compute='_compute_display_name') display_name = fields.Char(compute='_compute_display_name', public=True)
# Related fields for convenience # Related fields for convenience
version_id = fields.Many2one('runbot.version', related='params_id.version_id', store=True, index=True) version_id = fields.Many2one('runbot.version', related='params_id.version_id', store=True, index=True, public=True)
config_id = fields.Many2one('runbot.build.config', related='params_id.config_id', store=True, index=True) config_id = fields.Many2one('runbot.build.config', related='params_id.config_id', store=True, index=True, public=True)
trigger_id = fields.Many2one('runbot.trigger', related='params_id.trigger_id', store=True, index=True) trigger_id = fields.Many2one('runbot.trigger', related='params_id.trigger_id', store=True, index=True, public=True)
create_batch_id = fields.Many2one('runbot.batch', related='params_id.create_batch_id', store=True, index=True) create_batch_id = fields.Many2one('runbot.batch', related='params_id.create_batch_id', store=True, index=True, public=True)
create_bundle_id = fields.Many2one('runbot.bundle', related='params_id.create_batch_id.bundle_id', index=True) create_bundle_id = fields.Many2one('runbot.bundle', related='params_id.create_batch_id.bundle_id', index=True, public=True)
# state machine # state machine
global_state = fields.Selection(make_selection(state_order), string='Status', compute='_compute_global_state', store=True, recursive=True) global_state = fields.Selection(make_selection(state_order), string='Status', compute='_compute_global_state', store=True, recursive=True, public=True)
local_state = fields.Selection(make_selection(state_order), string='Build Status', default='pending', required=True, index=True) local_state = fields.Selection(make_selection(state_order), string='Build Status', default='pending', required=True, index=True, public=True)
global_result = fields.Selection(make_selection(result_order), string='Result', compute='_compute_global_result', store=True, recursive=True) global_result = fields.Selection(make_selection(result_order), string='Result', compute='_compute_global_result', store=True, recursive=True, public=True)
local_result = fields.Selection(make_selection(result_order), string='Build Result', default='ok') local_result = fields.Selection(make_selection(result_order), string='Build Result', default='ok', public=True)
requested_action = fields.Selection([('wake_up', 'To wake up'), ('deathrow', 'To kill')], string='Action requested', index=True) requested_action = fields.Selection([('wake_up', 'To wake up'), ('deathrow', 'To kill')], string='Action requested', index=True, public=True)
# web infos # web infos
host = fields.Char('Host name') host = fields.Char('Host name', public=True)
host_id = fields.Many2one('runbot.host', string="Host", compute='_compute_host_id') host_id = fields.Many2one('runbot.host', string="Host", compute='_compute_host_id', public=True)
keep_host = fields.Boolean('Keep host on rebuild and for children') keep_host = fields.Boolean('Keep host on rebuild and for children')
port = fields.Integer('Port') port = fields.Integer('Port')
@ -184,7 +190,7 @@ class BuildResult(models.Model):
log_ids = fields.One2many('ir.logging', 'build_id', string='Logs') log_ids = fields.One2many('ir.logging', 'build_id', string='Logs')
error_log_ids = fields.One2many('ir.logging', 'build_id', domain=[('level', 'in', ['WARNING', 'ERROR', 'CRITICAL'])], string='Error Logs') error_log_ids = fields.One2many('ir.logging', 'build_id', domain=[('level', 'in', ['WARNING', 'ERROR', 'CRITICAL'])], string='Error Logs')
stat_ids = fields.One2many('runbot.build.stat', 'build_id', string='Statistics values') stat_ids = fields.One2many('runbot.build.stat', 'build_id', string='Statistics values')
log_list = fields.Char('Comma separted list of step_ids names with logs') log_list = fields.Char('Comma separted list of step_ids names with logs', public=True)
active_step = fields.Many2one('runbot.build.config.step', 'Active step') active_step = fields.Many2one('runbot.build.config.step', 'Active step')
job = fields.Char('Active step display name', compute='_compute_job') job = fields.Char('Active step display name', compute='_compute_job')
@ -235,13 +241,17 @@ class BuildResult(models.Model):
slot_ids = fields.One2many('runbot.batch.slot', 'build_id') slot_ids = fields.One2many('runbot.batch.slot', 'build_id')
killable = fields.Boolean('Killable') killable = fields.Boolean('Killable')
database_ids = fields.One2many('runbot.database', 'build_id') database_ids = fields.One2many('runbot.database', 'build_id', public=True)
commit_export_ids = fields.One2many('runbot.commit.export', 'build_id') commit_export_ids = fields.One2many('runbot.commit.export', 'build_id')
static_run = fields.Char('Static run URL') static_run = fields.Char('Static run URL')
access_token = fields.Char('Token', default=lambda self: uuid.uuid4().hex) access_token = fields.Char('Token', default=lambda self: uuid.uuid4().hex)
@api.model
def _api_project_id_field_path(self):
return 'params_id.project_id'
@api.depends('description', 'params_id.config_id') @api.depends('description', 'params_id.config_id')
def _compute_display_name(self): def _compute_display_name(self):
for build in self: for build in self:

View File

@ -1,3 +1,5 @@
from werkzeug.exceptions import BadRequest
import time import time
import logging import logging
import datetime import datetime
@ -5,40 +7,41 @@ import subprocess
from collections import defaultdict from collections import defaultdict
from odoo import models, fields, api, tools from odoo import models, fields, api, tools
from odoo.osv import expression
from ..common import dt2time, s2human_long from ..common import dt2time, s2human_long
class Bundle(models.Model): class Bundle(models.Model):
_name = 'runbot.bundle' _name = 'runbot.bundle'
_description = "Bundle" _description = "Bundle"
_inherit = 'mail.thread' _inherit = ['mail.thread', 'runbot.public.model.mixin']
name = fields.Char('Bundle name', required=True, help="Name of the base branch") name = fields.Char('Bundle name', required=True, help="Name of the base branch", public=True)
project_id = fields.Many2one('runbot.project', required=True, index=True) project_id = fields.Many2one('runbot.project', required=True, index=True, public=True)
branch_ids = fields.One2many('runbot.branch', 'bundle_id') branch_ids = fields.One2many('runbot.branch', 'bundle_id', public=True)
# custom behaviour # custom behaviour
no_build = fields.Boolean('No build') no_build = fields.Boolean('No build', public=True)
no_auto_run = fields.Boolean('No run') no_auto_run = fields.Boolean('No run')
build_all = fields.Boolean('Force all triggers') build_all = fields.Boolean('Force all triggers')
always_use_foreign = fields.Boolean('Use foreign bundle', help='By default, check for the same bundle name in another project to fill missing commits.', default=lambda self: self.project_id.always_use_foreign) always_use_foreign = fields.Boolean('Use foreign bundle', help='By default, check for the same bundle name in another project to fill missing commits.', default=lambda self: self.project_id.always_use_foreign)
modules = fields.Char("Modules to install", help="Comma-separated list of modules to install and test.") modules = fields.Char("Modules to install", help="Comma-separated list of modules to install and test.")
batch_ids = fields.One2many('runbot.batch', 'bundle_id') batch_ids = fields.One2many('runbot.batch', 'bundle_id')
last_batch = fields.Many2one('runbot.batch', index=True, domain=lambda self: [('category_id', '=', self.env.ref('runbot.default_category').id)]) last_batch = fields.Many2one('runbot.batch', index=True, domain=lambda self: [('category_id', '=', self.env.ref('runbot.default_category').id)], public=True)
last_batchs = fields.Many2many('runbot.batch', 'Last batchs', compute='_compute_last_batchs') last_batchs = fields.Many2many('runbot.batch', 'Last batchs', compute='_compute_last_batchs', public=True)
last_done_batch = fields.Many2many('runbot.batch', 'Last batchs', compute='_compute_last_done_batch') last_done_batch = fields.Many2many('runbot.batch', 'Last batchs', compute='_compute_last_done_batch')
sticky = fields.Boolean('Sticky', compute='_compute_sticky', store=True, index=True) sticky = fields.Boolean('Sticky', compute='_compute_sticky', store=True, index=True, public=True)
is_base = fields.Boolean('Is base', index=True) is_base = fields.Boolean('Is base', index=True, public=True)
defined_base_id = fields.Many2one('runbot.bundle', 'Forced base bundle', domain="[('project_id', '=', project_id), ('is_base', '=', True)]") defined_base_id = fields.Many2one('runbot.bundle', 'Forced base bundle', domain="[('project_id', '=', project_id), ('is_base', '=', True)]")
base_id = fields.Many2one('runbot.bundle', 'Base bundle', compute='_compute_base_id', store=True) base_id = fields.Many2one('runbot.bundle', 'Base bundle', compute='_compute_base_id', store=True)
to_upgrade = fields.Boolean('To upgrade To', compute='_compute_to_upgrade', store=True, index=False) to_upgrade = fields.Boolean('To upgrade To', compute='_compute_to_upgrade', store=True, index=False)
to_upgrade_from = fields.Boolean('To upgrade From', compute='_compute_to_upgrade_from', store=True, index=False) to_upgrade_from = fields.Boolean('To upgrade From', compute='_compute_to_upgrade_from', store=True, index=False)
has_pr = fields.Boolean('Has PR', compute='_compute_has_pr', store=True) has_pr = fields.Boolean('Has PR', compute='_compute_has_pr', store=True, public=True)
version_id = fields.Many2one('runbot.version', 'Version', compute='_compute_version_id', store=True, recursive=True) version_id = fields.Many2one('runbot.version', 'Version', compute='_compute_version_id', store=True, recursive=True, public=True)
version_number = fields.Char(related='version_id.number', store=True, index=True) version_number = fields.Char(related='version_id.number', store=True, index=True)
previous_major_version_base_id = fields.Many2one('runbot.bundle', 'Previous base bundle', compute='_compute_relations_base_id') previous_major_version_base_id = fields.Many2one('runbot.bundle', 'Previous base bundle', compute='_compute_relations_base_id')
@ -56,7 +59,36 @@ class Bundle(models.Model):
disable_codeowner = fields.Boolean("Disable codeowners", tracking=True) disable_codeowner = fields.Boolean("Disable codeowners", tracking=True)
# extra_info # extra_info
for_next_freeze = fields.Boolean('Should be in next freeze') for_next_freeze = fields.Boolean('Should be in next freeze', public=True)
@api.model
def _api_request_allowed_keys(self):
return super()._api_request_allowed_keys() | {'category_id'}
@api.model
def _api_project_id_field_path(self):
return 'project_id'
@api.model
def _api_request_read_get_records(self, request_data):
if 'category_id' in request_data:
if not isinstance(request_data['category_id'], int):
raise BadRequest('Invalid category_id')
category_id = request_data['category_id']
else:
category_id = self.env['ir.model.data']._xmlid_to_res_id('runbot.default_category')
self = self.with_context(category_id=category_id)
limit, offset = self._api_request_read_get_offset_limit(request_data)
e = expression.expression(request_data['domain'], self)
query = e.query
query.order = """
(case when "runbot_bundle".sticky then 1 when "runbot_bundle".sticky is null then 2 else 2 end),
case when "runbot_bundle".sticky then "runbot_bundle".version_number end collate "C" desc,
"runbot_bundle".last_batch desc
"""
query.limit = limit
query.offset = offset
return self.browse(query)
@api.depends('name') @api.depends('name')
def _compute_host_id(self): def _compute_host_id(self):

View File

@ -16,6 +16,7 @@ _logger = logging.getLogger(__name__)
class Commit(models.Model): class Commit(models.Model):
_name = 'runbot.commit' _name = 'runbot.commit'
_description = "Commit" _description = "Commit"
_inherit = ['runbot.public.model.mixin']
_sql_constraints = [ _sql_constraints = [
( (
@ -24,7 +25,7 @@ class Commit(models.Model):
"Commit must be unique to ensure correct duplicate matching", "Commit must be unique to ensure correct duplicate matching",
) )
] ]
name = fields.Char('SHA') name = fields.Char('SHA', public=True)
tree_hash = fields.Char('Tree hash', readonly=True) tree_hash = fields.Char('Tree hash', readonly=True)
repo_id = fields.Many2one('runbot.repo', string='Repo group') repo_id = fields.Many2one('runbot.repo', string='Repo group')
date = fields.Datetime('Commit date') date = fields.Datetime('Commit date')
@ -32,10 +33,14 @@ class Commit(models.Model):
author_email = fields.Char('Author Email') author_email = fields.Char('Author Email')
committer = fields.Char('Committer') committer = fields.Char('Committer')
committer_email = fields.Char('Committer Email') committer_email = fields.Char('Committer Email')
subject = fields.Text('Subject') subject = fields.Text('Subject', public=True)
dname = fields.Char('Display name', compute='_compute_dname') dname = fields.Char('Display name', compute='_compute_dname', public=True)
rebase_on_id = fields.Many2one('runbot.commit', 'Rebase on commit') rebase_on_id = fields.Many2one('runbot.commit', 'Rebase on commit')
@api.model
def _api_project_id_field_path(self):
return 'repo_id.project_id'
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
for vals in vals_list: for vals in vals_list:
@ -194,10 +199,11 @@ class Commit(models.Model):
class CommitLink(models.Model): class CommitLink(models.Model):
_name = 'runbot.commit.link' _name = 'runbot.commit.link'
_description = "Build commit" _description = "Build commit"
_inherit = ['runbot.public.model.mixin']
commit_id = fields.Many2one('runbot.commit', 'Commit', required=True, index=True) commit_id = fields.Many2one('runbot.commit', 'Commit', required=True, index=True, public=True)
# Link info # Link info
match_type = fields.Selection([('new', 'New head of branch'), ('head', 'Head of branch'), ('base_head', 'Found on base branch'), ('base_match', 'Found on base branch')]) # HEAD, DEFAULT match_type = fields.Selection([('new', 'New head of branch'), ('head', 'Head of branch'), ('base_head', 'Found on base branch'), ('base_match', 'Found on base branch')], public=True) # HEAD, DEFAULT
branch_id = fields.Many2one('runbot.branch', string='Found in branch') # Shouldn't be use for anything else than display branch_id = fields.Many2one('runbot.branch', string='Found in branch') # Shouldn't be use for anything else than display
base_commit_id = fields.Many2one('runbot.commit', 'Base head commit', index=True) base_commit_id = fields.Many2one('runbot.commit', 'Base head commit', index=True)
@ -208,6 +214,10 @@ class CommitLink(models.Model):
diff_add = fields.Integer('# line added') diff_add = fields.Integer('# line added')
diff_remove = fields.Integer('# line removed') diff_remove = fields.Integer('# line removed')
@api.model
def _api_request_allow_direct_access(self):
return False
class CommitStatus(models.Model): class CommitStatus(models.Model):
_name = 'runbot.commit.status' _name = 'runbot.commit.status'

View File

@ -6,11 +6,16 @@ _logger = logging.getLogger(__name__)
class Database(models.Model): class Database(models.Model):
_name = 'runbot.database' _name = 'runbot.database'
_description = "Database" _description = "Database"
_inherit = ['runbot.public.model.mixin']
name = fields.Char('Host name', required=True) name = fields.Char('Host name', required=True, public=True)
build_id = fields.Many2one('runbot.build', index=True, required=True) build_id = fields.Many2one('runbot.build', index=True, required=True)
db_suffix = fields.Char(compute='_compute_db_suffix') db_suffix = fields.Char(compute='_compute_db_suffix')
@api.model
def _api_request_allow_direct_access(self):
return False
def _compute_db_suffix(self): def _compute_db_suffix(self):
for record in self: for record in self:
record.db_suffix = record.name.replace('%s-' % record.build_id.dest, '') record.db_suffix = record.name.replace('%s-' % record.build_id.dest, '')

View File

@ -15,9 +15,9 @@ class Host(models.Model):
_name = 'runbot.host' _name = 'runbot.host'
_description = "Host" _description = "Host"
_order = 'id' _order = 'id'
_inherit = 'mail.thread' _inherit = ['mail.thread', 'runbot.public.model.mixin']
name = fields.Char('Host name', required=True) name = fields.Char('Host name', required=True, public=True)
disp_name = fields.Char('Display name') disp_name = fields.Char('Display name')
active = fields.Boolean('Active', default=True, tracking=True) active = fields.Boolean('Active', default=True, tracking=True)
last_start_loop = fields.Datetime('Last start') last_start_loop = fields.Datetime('Last start')
@ -49,6 +49,10 @@ class Host(models.Model):
use_remote_docker_registry = fields.Boolean('Use remote Docker Registry', default=False, help="Use docker registry for pulling images") use_remote_docker_registry = fields.Boolean('Use remote Docker Registry', default=False, help="Use docker registry for pulling images")
docker_registry_url = fields.Char('Registry Url', help="Override global registry URL for this host.") docker_registry_url = fields.Char('Registry Url', help="Override global registry URL for this host.")
@api.model
def _api_request_requires_project(self):
return False
def _compute_nb(self): def _compute_nb(self):
# Array of tuple (host, state, count) # Array of tuple (host, state, count)
groups = self.env['runbot.build']._read_group( groups = self.env['runbot.build']._read_group(

View File

@ -6,11 +6,12 @@ class Project(models.Model):
_name = 'runbot.project' _name = 'runbot.project'
_description = 'Project' _description = 'Project'
_order = 'sequence, id' _order = 'sequence, id'
_inherit = ['runbot.public.model.mixin']
name = fields.Char('Project name', required=True) name = fields.Char('Project name', required=True, public=True)
group_ids = fields.Many2many('res.groups', string='Required groups') group_ids = fields.Many2many('res.groups', string='Required groups')
keep_sticky_running = fields.Boolean('Keep last sticky builds running') keep_sticky_running = fields.Boolean('Keep last sticky builds running')
trigger_ids = fields.One2many('runbot.trigger', 'project_id', string='Triggers') trigger_ids = fields.One2many('runbot.trigger', 'project_id', string='Triggers', public=True)
dockerfile_id = fields.Many2one('runbot.dockerfile', index=True, help="Project Default Dockerfile") dockerfile_id = fields.Many2one('runbot.dockerfile', index=True, help="Project Default Dockerfile")
repo_ids = fields.One2many('runbot.repo', 'project_id', string='Repos') repo_ids = fields.One2many('runbot.repo', 'project_id', string='Repos')
sequence = fields.Integer('Sequence') sequence = fields.Integer('Sequence')
@ -25,6 +26,10 @@ class Project(models.Model):
active = fields.Boolean("Active", default=True) active = fields.Boolean("Active", default=True)
process_delay = fields.Integer('Process delay', default=60, required=True, help="Delay between a push and a batch starting its process.") process_delay = fields.Integer('Process delay', default=60, required=True, help="Delay between a push and a batch starting its process.")
@api.model
def _api_request_requires_project(self):
return False
@api.constrains('process_delay') @api.constrains('process_delay')
def _constraint_process_delay(self): def _constraint_process_delay(self):
if any(project.process_delay < 0 for project in self): if any(project.process_delay < 0 for project in self):

View File

@ -43,14 +43,14 @@ class Trigger(models.Model):
""" """
_name = 'runbot.trigger' _name = 'runbot.trigger'
_inherit = 'mail.thread' _inherit = ['mail.thread', 'runbot.public.model.mixin']
_description = 'Triggers' _description = 'Triggers'
_order = 'sequence, id' _order = 'sequence, id'
sequence = fields.Integer('Sequence') sequence = fields.Integer('Sequence')
name = fields.Char("Name") name = fields.Char("Name", public=True)
description = fields.Char("Description", help="Informative description") description = fields.Char("Description", help="Informative description", public=True)
project_id = fields.Many2one('runbot.project', string="Project id", required=True) project_id = fields.Many2one('runbot.project', string="Project id", required=True)
repo_ids = fields.Many2many('runbot.repo', relation='runbot_trigger_triggers', string="Triggers", domain="[('project_id', '=', project_id)]") repo_ids = fields.Many2many('runbot.repo', relation='runbot_trigger_triggers', string="Triggers", domain="[('project_id', '=', project_id)]")
dependency_ids = fields.Many2many('runbot.repo', relation='runbot_trigger_dependencies', string="Dependencies") dependency_ids = fields.Many2many('runbot.repo', relation='runbot_trigger_dependencies', string="Dependencies")
@ -77,8 +77,8 @@ class Trigger(models.Model):
ci_context = fields.Char("CI context", tracking=True) ci_context = fields.Char("CI context", tracking=True)
category_id = fields.Many2one('runbot.category', default=lambda self: self.env.ref('runbot.default_category', raise_if_not_found=False)) category_id = fields.Many2one('runbot.category', default=lambda self: self.env.ref('runbot.default_category', raise_if_not_found=False))
version_domain = fields.Char(string="Version domain") version_domain = fields.Char(string="Version domain")
hide = fields.Boolean('Hide trigger on main page') hide = fields.Boolean('Hide trigger on main page', public=True)
manual = fields.Boolean('Only start trigger manually', default=False) manual = fields.Boolean('Only start trigger manually', default=False, public=True)
restore_trigger_id = fields.Many2one('runbot.trigger', string='Restore Trigger ID for custom triggers', help="Mainly usefull to automatically define where to find a reference database when creating a custom trigger", tracking=True) restore_trigger_id = fields.Many2one('runbot.trigger', string='Restore Trigger ID for custom triggers', help="Mainly usefull to automatically define where to find a reference database when creating a custom trigger", tracking=True)
upgrade_dumps_trigger_id = fields.Many2one('runbot.trigger', string='Template/complement trigger', tracking=True) upgrade_dumps_trigger_id = fields.Many2one('runbot.trigger', string='Template/complement trigger', tracking=True)
@ -98,6 +98,10 @@ class Trigger(models.Model):
context={'default_type': 'qweb', 'default_arch_base': '<t></t>'}, context={'default_type': 'qweb', 'default_arch_base': '<t></t>'},
) )
@api.model
def _api_project_id_field_path(self):
return 'project_id'
@api.depends('config_id.step_order_ids.step_id.make_stats') @api.depends('config_id.step_order_ids.step_id.make_stats')
def _compute_has_stats(self): def _compute_has_stats(self):
for trigger in self: for trigger in self:
@ -200,9 +204,9 @@ class Remote(models.Model):
_name = 'runbot.remote' _name = 'runbot.remote'
_description = 'Remote' _description = 'Remote'
_order = 'sequence, id' _order = 'sequence, id'
_inherit = 'mail.thread' _inherit = ['mail.thread', 'runbot.public.model.mixin']
name = fields.Char('Url', required=True, tracking=True) name = fields.Char('Url', required=True, tracking=True, public=True)
repo_id = fields.Many2one('runbot.repo', required=True, tracking=True) repo_id = fields.Many2one('runbot.repo', required=True, tracking=True)
owner = fields.Char(compute='_compute_base_infos', string='Repo Owner', store=True, readonly=True, tracking=True) owner = fields.Char(compute='_compute_base_infos', string='Repo Owner', store=True, readonly=True, tracking=True)
@ -211,7 +215,7 @@ class Remote(models.Model):
base_url = fields.Char(compute='_compute_base_url', string='Base URL', readonly=True, tracking=True) base_url = fields.Char(compute='_compute_base_url', string='Base URL', readonly=True, tracking=True)
short_name = fields.Char('Short name', compute='_compute_short_name', tracking=True) short_name = fields.Char('Short name', compute='_compute_short_name', tracking=True, public=True)
remote_name = fields.Char('Remote name', compute='_compute_remote_name', tracking=True) remote_name = fields.Char('Remote name', compute='_compute_remote_name', tracking=True)
sequence = fields.Integer('Sequence', tracking=True) sequence = fields.Integer('Sequence', tracking=True)
@ -221,6 +225,10 @@ class Remote(models.Model):
token = fields.Char("Github token", groups="runbot.group_runbot_admin") token = fields.Char("Github token", groups="runbot.group_runbot_admin")
@api.model
def _api_request_allow_direct_access(self):
return False
@api.depends('name') @api.depends('name')
def _compute_base_infos(self): def _compute_base_infos(self):
for remote in self: for remote in self:

View File

@ -57,7 +57,7 @@ class UpgradeRegex(models.Model):
class BuildResult(models.Model): class BuildResult(models.Model):
_inherit = 'runbot.build' _inherit = ['runbot.build']
def _parse_upgrade_errors(self): def _parse_upgrade_errors(self):
ir_logs = self.env['ir.logging'].search([('level', 'in', ('ERROR', 'WARNING', 'CRITICAL')), ('type', '=', 'server'), ('build_id', 'in', self.ids)]) ir_logs = self.env['ir.logging'].search([('level', 'in', ('ERROR', 'WARNING', 'CRITICAL')), ('type', '=', 'server'), ('build_id', 'in', self.ids)])

View File

@ -12,3 +12,5 @@ rule_commit,"limited to groups",model_runbot_commit,group_user,"['|', ('repo_id.
rule_commit_mgmt,"manager can see all",model_runbot_commit,group_runbot_admin,"[(1, '=', 1)]",1,1,1,1 rule_commit_mgmt,"manager can see all",model_runbot_commit,group_runbot_admin,"[(1, '=', 1)]",1,1,1,1
rule_build,"limited to groups",model_runbot_build,group_user,"['|', ('params_id.project_id.group_ids', '=', False), ('params_id.project_id.group_ids', 'in', [g.id for g in user.groups_id])]",1,1,1,1 rule_build,"limited to groups",model_runbot_build,group_user,"['|', ('params_id.project_id.group_ids', '=', False), ('params_id.project_id.group_ids', 'in', [g.id for g in user.groups_id])]",1,1,1,1
rule_build_mgmt,"manager can see all",model_runbot_build,group_runbot_admin,"[(1, '=', 1)]",1,1,1,1 rule_build_mgmt,"manager can see all",model_runbot_build,group_runbot_admin,"[(1, '=', 1)]",1,1,1,1
rule_batch,"limited to groups",model_runbot_batch,group_user,"['|', ('bundle_id.project_id.group_ids', '=', False), ('bundle_id.project_id.group_ids', 'in', [g.id for g in user.groups_id])]",1,1,1,1
rule_batch_mgmt,"manager can see all",model_runbot_batch,group_runbot_admin,"[(1, '=', 1)]",1,1,1,1

1 id name model_id/id groups/id domain_force perm_read perm_create perm_write perm_unlink
12 rule_batch limited to groups model_runbot_batch group_user ['|', ('bundle_id.project_id.group_ids', '=', False), ('bundle_id.project_id.group_ids', 'in', [g.id for g in user.groups_id])] 1 1 1 1
13 rule_batch_mgmt manager can see all model_runbot_batch group_runbot_admin [(1, '=', 1)] 1 1 1 1
14
15
16