runbot/runbot_merge/models/project.py

124 lines
4.4 KiB
Python
Raw Permalink Normal View History

import logging
import re
from odoo import models, fields
_logger = logging.getLogger(__name__)
class Project(models.Model):
_name = _description = 'runbot_merge.project'
name = fields.Char(required=True, index=True)
repo_ids = fields.One2many(
'runbot_merge.repository', 'project_id',
help="Repos included in that project, they'll be staged together. "\
"*Not* to be used for cross-repo dependencies (that is to be handled by the CI)"
)
branch_ids = fields.One2many(
'runbot_merge.branch', 'project_id',
context={'active_test': False},
help="Branches of all project's repos which are managed by the merge bot. Also "\
"target branches of PR this project handles."
)
ci_timeout = fields.Integer(
default=60, required=True, group_operator=None,
help="Delay (in minutes) before a staging is considered timed out and failed"
)
github_token = fields.Char("Github Token", required=True)
github_prefix = fields.Char(
required=True,
default="hanson", # mergebot du bot du bot du~
help="Prefix (~bot name) used when sending commands from PR "
"comments e.g. [hanson retry] or [hanson r+ p=1]"
)
batch_limit = fields.Integer(
default=8, group_operator=None, help="Maximum number of PRs staged together")
secret = fields.Char(
help="Webhook secret. If set, will be checked against the signature "
"of (valid) incoming webhook signatures, failing signatures "
"will lead to webhook rejection. Should only use ASCII."
)
freeze_id = fields.Many2one('runbot_merge.project.freeze', compute='_compute_freeze')
freeze_reminder = fields.Text()
def _check_stagings(self, commit=False):
for branch in self.search([]).mapped('branch_ids').filtered('active'):
staging = branch.active_staging_id
if not staging:
continue
try:
with self.env.cr.savepoint():
staging.check_status()
except Exception:
_logger.exception("Failed to check staging for branch %r (staging %s)",
branch.name, staging)
else:
if commit:
self.env.cr.commit()
def _create_stagings(self, commit=False):
for branch in self.search([]).mapped('branch_ids').filtered('active'):
if not branch.active_staging_id:
try:
with self.env.cr.savepoint():
branch.try_staging()
except Exception:
_logger.exception("Failed to create staging for branch %r", branch.name)
else:
if commit:
self.env.cr.commit()
def _find_commands(self, comment):
return re.findall(
r'^\s*[@|#]?{}:? (.*)$'.format(self.github_prefix),
comment, re.MULTILINE | re.IGNORECASE)
def _has_branch(self, name):
self.env.cr.execute("""
SELECT 1 FROM runbot_merge_branch
WHERE project_id = %s AND name = %s
LIMIT 1
""", (self.id, name))
return bool(self.env.cr.rowcount)
def _next_freeze(self):
prev = self.branch_ids[1:2].name
if not prev:
return None
m = re.search(r'(\d+)(?:\.(\d+))?$', prev)
if m:
return "%s.%d" % (m[1], (int(m[2] or 0) + 1))
else:
return f'post-{prev}'
def _compute_freeze(self):
freezes = {
f.project_id.id: f.id
for f in self.env['runbot_merge.project.freeze'].search([('project_id', 'in', self.ids)])
}
for project in self:
project.freeze_id = freezes.get(project.id) or False
def action_prepare_freeze(self):
""" Initialises the freeze wizard and returns the corresponding action.
"""
self.check_access_rights('write')
self.check_access_rule('write')
Freeze = self.env['runbot_merge.project.freeze'].sudo()
w = Freeze.search([('project_id', '=', self.id)]) or Freeze.create({
'project_id': self.id,
'branch_name': self._next_freeze(),
'release_pr_ids': [
(0, 0, {'repository_id': repo.id})
for repo in self.repo_ids
if repo.freeze
]
})
return w.action_open()