mirror of
https://github.com/odoo/runbot.git
synced 2025-03-30 14:55:45 +07:00
91 lines
4.0 KiB
Python
91 lines
4.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
import logging
|
|
import re
|
|
from subprocess import CalledProcessError
|
|
from odoo import models, fields, api
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
_re_coverage = re.compile(r'\bcoverage\b')
|
|
_re_patch = re.compile(r'.*patch-\d+$')
|
|
|
|
class runbot_branch(models.Model):
|
|
|
|
_name = "runbot.branch"
|
|
_order = 'name'
|
|
_sql_constraints = [('branch_repo_uniq', 'unique (name,repo_id)', 'The branch must be unique per repository !')]
|
|
|
|
repo_id = fields.Many2one('runbot.repo', 'Repository', required=True, ondelete='cascade')
|
|
name = fields.Char('Ref Name', required=True)
|
|
branch_name = fields.Char(compute='_get_branch_infos', string='Branch', readonly=1, store=True)
|
|
branch_url = fields.Char(compute='_get_branch_infos', string='Branch url', readonly=1)
|
|
pull_head_name = fields.Char(compute='_get_branch_infos', string='PR HEAD name', readonly=1, store=True)
|
|
target_branch_name = fields.Char(compute='_get_branch_infos', string='PR target branch', readonly=1, store=True)
|
|
sticky = fields.Boolean('Sticky')
|
|
coverage = fields.Boolean('Coverage')
|
|
coverage_result = fields.Float(compute='_get_last_coverage', type='Float', string='Last coverage', store=False)
|
|
state = fields.Char('Status')
|
|
modules = fields.Char("Modules to Install", help="Comma-separated list of modules to install and test.")
|
|
job_timeout = fields.Integer('Job Timeout (minutes)', help='For default timeout: Mark it zero')
|
|
priority = fields.Boolean('Build priority', default=False)
|
|
|
|
@api.depends('name')
|
|
def _get_branch_infos(self):
|
|
"""compute branch_name, branch_url, pull_head_name and target_branch_name based on name"""
|
|
for branch in self:
|
|
if branch.name:
|
|
branch.branch_name = branch.name.split('/')[-1]
|
|
if re.match('^[0-9]+$', branch.branch_name):
|
|
branch.branch_url = "https://%s/pull/%s" % (branch.repo_id.base, branch.branch_name)
|
|
else:
|
|
branch.branch_url = "https://%s/tree/%s" % (branch.repo_id.base, branch.branch_name)
|
|
pi = branch._get_pull_info()
|
|
if pi:
|
|
branch.target_branch_name = pi['base']['ref']
|
|
if not _re_patch.match(pi['head']['label']):
|
|
# label is used to disambiguate PR with same branch name
|
|
branch.pull_head_name = pi['head']['label']
|
|
|
|
def _get_pull_info(self):
|
|
self.ensure_one()
|
|
repo = self.repo_id
|
|
if repo.token and self.name.startswith('refs/pull/'):
|
|
pull_number = self.name[len('refs/pull/'):]
|
|
return repo._github('/repos/:owner/:repo/pulls/%s' % pull_number, ignore_errors=True) or {}
|
|
return {}
|
|
|
|
def _is_on_remote(self):
|
|
# check that a branch still exists on remote
|
|
self.ensure_one()
|
|
branch = self
|
|
repo = branch.repo_id
|
|
try:
|
|
repo._git(['ls-remote', '-q', '--exit-code', repo.name, branch.name])
|
|
except CalledProcessError:
|
|
return False
|
|
return True
|
|
|
|
def create(self, vals):
|
|
vals.setdefault('coverage', _re_coverage.search(vals.get('name') or '') is not None)
|
|
return super(runbot_branch, self).create(vals)
|
|
|
|
def _get_branch_quickconnect_url(self, fqdn, dest):
|
|
self.ensure_one()
|
|
r = {}
|
|
r[self.id] = "http://%s/web/login?db=%s-all&login=admin&redirect=/web?debug=1" % (fqdn, dest)
|
|
return r
|
|
|
|
def _get_last_coverage_build(self):
|
|
""" Return the last build with a coverage value > 0"""
|
|
self.ensure_one()
|
|
return self.env['runbot.build'].search([
|
|
('branch_id.id', '=', self.id),
|
|
('state', 'in', ['done', 'running']),
|
|
('coverage_result', '>=', 0.0),
|
|
], order='sequence desc', limit=1)
|
|
|
|
def _get_last_coverage(self):
|
|
""" Compute the coverage result of the last build in branch """
|
|
for branch in self:
|
|
last_build = branch._get_last_coverage_build()
|
|
branch.coverage_result = last_build.coverage_result or 0.0
|