diff --git a/runbot/common.py b/runbot/common.py index 0ac783df..6c1b0950 100644 --- a/runbot/common.py +++ b/runbot/common.py @@ -99,13 +99,3 @@ def local_pgadmin_cursor(): finally: if cnx: cnx.close() - -def get_py_version(build): - """return the python name to use from build instance""" - executables = [ 'odoo-bin', 'openerp-server' ] - for server_path in map(build._path, executables): - if os.path.exists(server_path): - with open(server_path, 'r') as f: - if f.readline().strip().endswith('python3'): - return 'python3' - return 'python' diff --git a/runbot/container.py b/runbot/container.py index dc3b2269..20938e30 100644 --- a/runbot/container.py +++ b/runbot/container.py @@ -31,19 +31,27 @@ ENV COVERAGE_FILE /data/build/.coverage """ % {'group_id': os.getgid(), 'user_id': os.getuid()} -def build_odoo_cmd(odoo_cmd): - """ returns the chain of commands necessary to run odoo inside the container - : param odoo_cmd: odoo command as a list - : returns: a string with the command chain to execute in the docker container - """ - # build cmd - cmd_chain = [] - cmd_chain.append('cd /data/build') - server_path = odoo_cmd[0] - requirement_path = os.path.join(os.path.dirname(server_path), 'requirements.txt') - cmd_chain.append('head -1 %s | grep -q python3 && sudo pip3 install -r %s || sudo pip install -r %s' % (server_path, requirement_path, requirement_path)) - cmd_chain.append(' '.join(odoo_cmd)) - return ' && '.join(cmd_chain) +class Command(): + def __init__(self, pres, cmd, posts): + self.pres = pres or [] + self.cmd = cmd + self.posts = posts or [] + + def __getattr__(self, name): + return getattr(self.cmd, name) + + def __getitem__(self, key): + return self.cmd[key] + + def __add__(self, l): + return Command(self.pres, self.cmd + l, self.posts) + + def build(self): + cmd_chain = [] + cmd_chain += [' '.join(pre) for pre in self.pres if pre] + cmd_chain.append(' '.join(self)) + cmd_chain += [' '.join(post) for post in self.posts if post] + return ' && '.join(cmd_chain) def docker_build(log_path, build_dir): @@ -62,6 +70,7 @@ def docker_build(log_path, build_dir): dbuild = subprocess.Popen(['docker', 'build', '--tag', 'odoo:runbot_tests', '.'], stdout=logs, stderr=logs, cwd=docker_dir) dbuild.wait() + def docker_run(run_cmd, log_path, build_dir, container_name, exposed_ports=None, cpu_limit=None, preexec_fn=None, ro_volumes=None): """Run tests in a docker container :param run_cmd: command string to run in container @@ -74,7 +83,8 @@ def docker_run(run_cmd, log_path, build_dir, container_name, exposed_ports=None, """ _logger.debug('Docker run command: %s', run_cmd) logs = open(log_path, 'w') - logs.write("Docker command:\n%s\n=================================================\n" % run_cmd.replace('&& ', '&&\n').replace('|| ','||\n\t')) + run_cmd = 'cd /data/build && %s' % run_cmd + logs.write("Docker command:\n%s\n=================================================\n" % run_cmd.replace('&& ', '&&\n').replace('|| ', '||\n\t')) # create start script docker_command = [ 'docker', 'run', '--rm', @@ -154,7 +164,8 @@ def tests(args): if args.kill: logfile = os.path.join(args.build_dir, 'logs', 'logs-partial.txt') container_name = 'odoo-container-test-%s' % datetime.datetime.now().microsecond - docker_run(build_odoo_cmd(odoo_cmd), logfile, args.build_dir, container_name) + # FIXME + # docker_run(build_odoo_cmd(odoo_cmd), logfile, args.build_dir, container_name) # Test stopping the container _logger.info('Waiting 30 sec before killing the build') time.sleep(30) @@ -169,7 +180,8 @@ def tests(args): with open(os.path.join(args.build_dir, 'odoo-bin'), 'r') as exfile: pyversion = 'python3' if 'python3' in exfile.readline() else 'python' odoo_cmd = [ pyversion, '-m', 'coverage', 'run', '--branch', '--source', '/data/build'] + omit + odoo_cmd - docker_run(build_odoo_cmd(odoo_cmd), logfile, args.build_dir, container_name) + # FIXME + # docker_run(build_odoo_cmd(odoo_cmd), logfile, args.build_dir, container_name) time.sleep(1) # give time for the container to start while docker_is_running(container_name): @@ -200,7 +212,9 @@ def tests(args): if smtp_host: odoo_cmd.extend(['--smtp', smtp_host]) container_name = 'odoo-container-test-%s' % datetime.datetime.now().microsecond - docker_run(build_odoo_cmd(odoo_cmd), logfile, args.build_dir, container_name, exposed_ports=[args.odoo_port, args.odoo_port + 1], cpu_limit=300) + + # FIXME + # docker_run(build_odoo_cmd(odoo_cmd), logfile, args.build_dir, container_name, exposed_ports=[args.odoo_port, args.odoo_port + 1], cpu_limit=300) if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s: %(message)s') diff --git a/runbot/models/build.py b/runbot/models/build.py index 885fcd6b..4be7863c 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -9,7 +9,7 @@ import subprocess import time import datetime from ..common import dt2time, fqdn, now, grep, uniq_list, local_pgadmin_cursor, s2human, Commit -from ..container import docker_build, docker_stop, docker_is_running +from ..container import docker_build, docker_stop, docker_is_running, Command from odoo.addons.runbot.models.repo import HashMissingException from odoo import models, fields, api from odoo.exceptions import UserError, ValidationError @@ -283,7 +283,7 @@ class runbot_build(models.Model): # maybe update duplicate priority if needed docker_source_folders = set() - for commit in build_id.get_all_commit(): + for commit in build_id._get_all_commit(): docker_source_folder = build_id._docker_source_folder(commit) if docker_source_folder in docker_source_folders: extra_info['commit_path_mode'] = 'rep_sha' @@ -384,6 +384,14 @@ class runbot_build(models.Model): params['dep'][result[0]] = result[1] return params + def _copy_dependency_ids(self): + return [(0, 0, { + 'match_type': dep.match_type, + 'closest_branch_id': dep.closest_branch_id.id, + 'dependency_hash': dep.dependency_hash, + 'dependecy_repo_id': dep.dependecy_repo_id.id, + }) for dep in self.dependency_ids] + def _force(self, message=None, exact=False): """Force a rebuild and return a recordset of forced builds""" forced_builds = self.env['runbot.build'] @@ -408,19 +416,13 @@ class runbot_build(models.Model): 'build_type': 'rebuild', } if exact: - if build.dependency_ids: - values['dependency_ids'] = [(0, 0, { - 'match_type': dep.match_type, - 'closest_branch_id': dep.closest_branch_id.id, - 'dependency_hash': dep.dependency_hash, - 'dependecy_repo_id': dep.dependecy_repo_id.id, - }) for dep in build.dependency_ids] values.update({ 'config_id': build.config_id.id, 'extra_params': build.extra_params, 'orphan_result': build.orphan_result, + 'dependency_ids': build._copy_dependency_ids(), }) - #if replace: ? + # if replace: ? if build.parent_id: values.update({ 'parent_id': build.parent_id.id, # attach it to parent @@ -643,7 +645,7 @@ class runbot_build(models.Model): def _server(self, *path): """Return the absolute path to the direcory containing the server file, adding optional *path""" self.ensure_one() - commit = self.get_server_commit() + commit = self._get_server_commit() if os.path.exists(commit._source_path('odoo')): return commit._source_path('odoo', *path) return commit._source_path('openerp', *path) @@ -688,7 +690,7 @@ class runbot_build(models.Model): self.ensure_one() # will raise exception if hash not found, we don't want to fail for all build. # checkout branch exports = {} - for commit in commits or self.get_all_commit(): + for commit in commits or self._get_all_commit(): build_export_path = self._docker_source_folder(commit) if build_export_path in exports: self._log('_checkout', 'Multiple repo have same export path in build, some source may be missing for %s' % build_export_path, level='ERROR') @@ -705,7 +707,7 @@ class runbot_build(models.Model): # checkout branch repo_modules = [] available_modules = [] - for commit in commits or self.get_all_commit(): + for commit in commits or self._get_all_commit(): for (addons_path, module, manifest_file_name) in self._get_available_modules(commit): if commit.repo == self.repo_id: repo_modules.append(module) @@ -819,54 +821,58 @@ class runbot_build(models.Model): if not child.duplicate_id: child._ask_kill() - def get_all_commit(self): - return [Commit(self.repo_id, self.name)] + [Commit(dep.get_repo(), dep.dependency_hash) for dep in self.dependency_ids] + def _get_all_commit(self): + return [Commit(self.repo_id, self.name)] + [Commit(dep._get_repo(), dep.dependency_hash) for dep in self.dependency_ids] - def get_server_commit(self, commits=None): + def _get_server_commit(self, commits=None): """ returns a Commit() of the first repo containing server files found in commits or in build commits the commits param is not used in code base but could be usefull for jobs and crons """ - for commit in (commits or self.get_all_commit()): + for commit in (commits or self._get_all_commit()): if commit.repo.server_files: return commit raise ValidationError('No repo found with defined server_files') - def get_addons_path(self, commits=None): - for commit in (commits or self.get_all_commit()): + def _get_addons_path(self, commits=None): + for commit in (commits or self._get_all_commit()): source_path = self._docker_source_folder(commit) for addons_path in commit.repo.addons_paths.split(','): if os.path.isdir(commit._source_path(addons_path)): yield os.path.join(source_path, addons_path).strip(os.sep) - def get_server_info(self, commit=None): + def _get_server_info(self, commit=None): server_dir = False server = False - commit = commit or self.get_server_commit() + commit = commit or self._get_server_commit() for server_file in commit.repo.server_files.split(','): if os.path.isfile(commit._source_path(server_file)): - return (self._docker_source_folder(commit), server_file) + return (commit, server_file) self._log('server_info', 'No server found in %s' % commit, level='ERROR') raise ValidationError('No server found in %s' % commit) - def _cmd(self): - """Return a tuple describing the command to start the build - First part is list with the command and parameters - Second part is a list of Odoo modules + def _cmd(self, python_params=None, py_version=None): + """Return a list describing the command to start the build """ self.ensure_one() build = self + python_params = python_params or [] + py_version = py_version if py_version is not None else build._get_py_version() + (server_commit, server_file) = self._get_server_info() + server_dir = self._docker_source_folder(server_commit) + addons_paths = self._get_addons_path() + requirement_path = os.path.join(server_dir, 'requirements.txt') + pres = [['sudo', 'pip%s' % py_version, 'install', '-r', '%s' % requirement_path]] - (server_dir, server_file) = self.get_server_info() - addons_paths = self.get_addons_path() # commandline - cmd = [os.path.join('/data/build', server_dir, server_file), '--addons-path', ",".join(addons_paths)] + cmd = ['python%s' % py_version] + python_params + [os.path.join(server_dir, server_file), '--addons-path', ",".join(addons_paths)] # options - if grep(build._server("tools/config.py"), "no-xmlrpcs"): # move that to configs ? + config_path = build._server("tools/config.py") + if grep(config_path, "no-xmlrpcs"): # move that to configs ? cmd.append("--no-xmlrpcs") - if grep(build._server("tools/config.py"), "no-netrpc"): + if grep(config_path, "no-netrpc"): cmd.append("--no-netrpc") - if grep(build._server("tools/config.py"), "log-db"): + if grep(config_path, "log-db"): logdb_uri = self.env['ir.config_parameter'].get_param('runbot.runbot_logdb_uri') logdb = self.env.cr.dbname if logdb_uri and grep(build._server('sql_db.py'), 'allow_uri'): @@ -875,7 +881,7 @@ class runbot_build(models.Model): if grep(build._server('tools/config.py'), 'log-db-level'): cmd += ["--log-db-level", '25'] - if grep(build._server("tools/config.py"), "data-dir"): + if grep(config_path, "data-dir"): datadir = build._path('datadir') if not os.path.exists(datadir): os.mkdir(datadir) @@ -883,8 +889,7 @@ class runbot_build(models.Model): # use the username of the runbot host to connect to the databases cmd += ['-r %s' % pwd.getpwuid(os.getuid()).pw_name] - - return cmd + return Command(pres, cmd, []) def _github_status_notify_all(self, status): """Notify each repo with a status""" @@ -936,6 +941,15 @@ class runbot_build(models.Model): new_step = step_ids[next_index] # job to do, state is job_state (testing or running) return {'active_step': new_step.id, 'local_state': new_step._step_state()} + def _get_py_version(self): + """return the python name to use from build instance""" + (server_commit, server_file) = self._get_server_info() + server_path = server_commit._source_path(server_file) + with open(server_path, 'r') as f: + if f.readline().strip().endswith('python3'): + return '3' + return '' + def read_file(self, file, mode='r'): file_path = self._path(file) try: diff --git a/runbot/models/build_config.py b/runbot/models/build_config.py index f3e6f649..d3c56e78 100644 --- a/runbot/models/build_config.py +++ b/runbot/models/build_config.py @@ -5,8 +5,8 @@ import os import re import shlex import time -from ..common import now, grep, get_py_version, time2str, rfind, Commit -from ..container import docker_run, docker_get_gateway_ip, build_odoo_cmd +from ..common import now, grep, time2str, rfind, Commit +from ..container import docker_run, docker_get_gateway_ip, Command from odoo import models, fields, api from odoo.exceptions import UserError, ValidationError from odoo.tools.safe_eval import safe_eval, test_python_expr @@ -201,7 +201,7 @@ class ConfigStep(models.Model): build._logger('Too much build created') break children = Build.create({ - 'dependency_ids': [(4, did.id) for did in build.dependency_ids], + 'dependency_ids': build._copy_dependency_ids(), 'config_id': create_config.id, 'parent_id': build.id, 'branch_id': build.branch_id.id, @@ -228,12 +228,11 @@ class ConfigStep(models.Model): '_logger': _logger, 'log_path': log_path, 'glob': glob.glob, - 'build_odoo_cmd': build_odoo_cmd, + 'Command': Command, 'base64': base64, 're': re, 'time': time, 'grep': grep, - 'get_py_version': get_py_version, 'rfind': rfind, } return safe_eval(self.sudo().python_code.strip(), eval_ctx, mode="exec", nocopy=True) @@ -244,8 +243,7 @@ class ConfigStep(models.Model): build._log('run', 'Start running build %s' % build.dest) # run server cmd = build._cmd() - server = build._server() - if os.path.exists(os.path.join(server, 'addons/im_livechat')): + if os.path.exists(build._get_server_commit()._source_path('addons/im_livechat')): cmd += ["--workers", "2"] cmd += ["--longpolling-port", "8070"] cmd += ["--max-cron-threads", "1"] @@ -257,7 +255,7 @@ class ConfigStep(models.Model): # we need to have at least one job of type install_odoo to run odoo, take the last one for db_name. cmd += ['-d', '%s-%s' % (build.dest, db_name)] - if grep(os.path.join(server, "tools/config.py"), "db-filter"): + if grep(build._server("tools/config.py"), "db-filter"): if build.repo_id.nginx: cmd += ['--db-filter', '%d.*$'] else: @@ -271,19 +269,26 @@ class ConfigStep(models.Model): build_port = build.port self.env.cr.commit() # commit before docker run to be 100% sure that db state is consistent with dockers self.invalidate_cache() - return docker_run(build_odoo_cmd(cmd), log_path, build_path, docker_name, exposed_ports=[build_port, build_port + 1], ro_volumes=exports) + return docker_run(cmd.build(), log_path, build_path, docker_name, exposed_ports=[build_port, build_port + 1], ro_volumes=exports) def _run_odoo_install(self, build, log_path): exports = build._checkout() - cmd = build._cmd() + + modules_to_install = self._modules_to_install(build) + mods = ",".join(modules_to_install) + python_params = [] + py_version = build._get_py_version() + if self.coverage: + build.coverage = True + coverage_extra_params = self._coverage_params(build, modules_to_install) + python_params = ['-m', 'coverage', 'run', '--branch', '--source', '/data/build'] + coverage_extra_params + cmd = build._cmd(python_params, py_version) # create db if needed db_name = "%s-%s" % (build.dest, self.db_name) if self.create_db: build._local_pg_createdb(db_name) cmd += ['-d', db_name] # list module to install - modules_to_install = self._modules_to_install(build) - mods = ",".join(modules_to_install) if mods: cmd += ['-i', mods] if self.test_enable: @@ -301,17 +306,11 @@ class ConfigStep(models.Model): if self.extra_params: cmd.extend(shlex.split(self.extra_params)) - if self.coverage: - build.coverage = True - coverage_extra_params = self._coverage_params(build, modules_to_install) - py_version = get_py_version(build) - cmd = [py_version, '-m', 'coverage', 'run', '--branch', '--source', '/data/build'] + coverage_extra_params + cmd - - cmd += self._post_install_command(build, modules_to_install) # coverage post, extra-checks, ... + cmd.posts.append(self._post_install_command(build, modules_to_install, py_version)) # coverage post, extra-checks, ... max_timeout = int(self.env['ir.config_parameter'].get_param('runbot.runbot_timeout', default=10000)) timeout = min(self.cpu_limit, max_timeout) - return docker_run(build_odoo_cmd(cmd), log_path, build._path(), build._get_docker_name(), cpu_limit=timeout, ro_volumes=exports) + return docker_run(cmd.build(), log_path, build._path(), build._get_docker_name(), cpu_limit=timeout, ro_volumes=exports) def _modules_to_install(self, build): modules_to_install = set([mod.strip() for mod in self.install_modules.split(',')]) @@ -322,18 +321,18 @@ class ConfigStep(models.Model): # todo add without support return modules_to_install - def _post_install_command(self, build, modules_to_install): + def _post_install_command(self, build, modules_to_install, py_version=None): if self.coverage: - py_version = get_py_version(build) + py_version = py_version if py_version is not None else build._get_py_version() # prepare coverage result cov_path = build._path('coverage') os.makedirs(cov_path, exist_ok=True) - return ['&&', py_version, "-m", "coverage", "html", "-d", "/data/build/coverage", "--ignore-errors"] + return ['python%s' % py_version, "-m", "coverage", "html", "-d", "/data/build/coverage", "--ignore-errors"] return [] def _coverage_params(self, build, modules_to_install): pattern_to_omit = set() - for commit in build.get_all_commit(): + for commit in build._get_all_commit(): docker_source_folder = build._docker_source_folder(commit) for manifest_file in commit.repo.manifest_files.split(','): pattern_to_omit.add('*%s' % manifest_file) diff --git a/runbot/models/build_dependency.py b/runbot/models/build_dependency.py index 02ad98ac..5cdaa70e 100644 --- a/runbot/models/build_dependency.py +++ b/runbot/models/build_dependency.py @@ -10,6 +10,6 @@ class RunbotBuildDependency(models.Model): closest_branch_id = fields.Many2one('runbot.branch', 'Branch', required=True, ondelete='cascade') match_type = fields.Char('Match Type') - def get_repo(self): + def _get_repo(self): return self.closest_branch_id.repo_id or self.dependecy_repo_id diff --git a/runbot/models/repo.py b/runbot/models/repo.py index d539ae03..15c11412 100644 --- a/runbot/models/repo.py +++ b/runbot/models/repo.py @@ -59,7 +59,7 @@ class runbot_repo(models.Model): config_id = fields.Many2one('runbot.build.config', 'Run Config', compute='_compute_config_id', inverse='_inverse_config_id') server_files = fields.Char('Server files', help='Comma separated list of possible server files') # odoo-bin,openerp-server,openerp-server.py - manifest_files = fields.Char('Addons files', help='Comma separated list of possible addons files', default='__manifest__.py,__openerp__.py') + manifest_files = fields.Char('Addons files', help='Comma separated list of possible addons files', default='__manifest__.py') addons_paths = fields.Char('Addons files', help='Comma separated list of possible addons path', default='') def _compute_config_id(self): diff --git a/runbot/tests/test_build.py b/runbot/tests/test_build.py index 2b25dce0..80247ef5 100644 --- a/runbot/tests/test_build.py +++ b/runbot/tests/test_build.py @@ -84,7 +84,7 @@ class Test_Build(common.TransactionCase): 'name': 'd0d0caca0000ffffffffffffffffffffffffffff', 'port': '1234', }) - cmd = build._cmd() + cmd = build._cmd(py_version=3) self.assertIn('--log-db=%s' % uri, cmd) @patch('odoo.addons.runbot.models.build.os.path.isdir') @@ -100,8 +100,9 @@ class Test_Build(common.TransactionCase): 'name': 'd0d0caca0000ffffffffffffffffffffffffffff', 'port': '1234', }) - cmd = build._cmd() - self.assertEqual('/data/build/bar/server.py', cmd[0]) + cmd = build._cmd(py_version=3) + self.assertEqual('python3', cmd[0]) + self.assertEqual('bar/server.py', cmd[1]) self.assertIn('--addons-path', cmd) addons_path_pos = cmd.index('--addons-path') + 1 self.assertEqual(cmd[addons_path_pos], 'bar/addons,bar/core/addons') @@ -151,11 +152,12 @@ class Test_Build(common.TransactionCase): 'name': 'd0d0caca0000ffffffffffffffffffffffffffff', 'port': '1234', }) - cmd = build._cmd() + cmd = build._cmd(py_version=3) self.assertIn('--addons-path', cmd) addons_path_pos = cmd.index('--addons-path') + 1 self.assertEqual(cmd[addons_path_pos], 'bar-ent,bar/addons,bar/core/addons') - self.assertEqual('/data/build/bar/server.py', cmd[0]) + self.assertEqual('bar/server.py', cmd[1]) + self.assertEqual('python3', cmd[0]) @patch('odoo.addons.runbot.models.branch.runbot_branch._is_on_remote') @patch('odoo.addons.runbot.models.build.os.path.isdir') @@ -193,11 +195,12 @@ class Test_Build(common.TransactionCase): 'name': 'd0d0caca0000ffffffffffffffffffffffffffff', 'port': '1234', }) - cmd = build._cmd() + cmd = build._cmd(py_version=3) self.assertIn('--addons-path', cmd) addons_path_pos = cmd.index('--addons-path') + 1 self.assertEqual(cmd[addons_path_pos], 'bar-d0d0caca,bar-dfdfcfcf/addons,bar-dfdfcfcf/core/addons') - self.assertEqual('/data/build/bar-dfdfcfcf/server.py', cmd[0]) + self.assertEqual('bar-dfdfcfcf/server.py', cmd[1]) + self.assertEqual('python3', cmd[0]) def test_build_config_from_branch_default(self): """test build config_id is computed from branch default config_id""" diff --git a/runbot/tests/test_build_config_step.py b/runbot/tests/test_build_config_step.py index 9dbf151f..89aa5293 100644 --- a/runbot/tests/test_build_config_step.py +++ b/runbot/tests/test_build_config_step.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from unittest.mock import patch from odoo.tests import common @@ -79,3 +80,36 @@ class TestBuildConfigStep(common.TransactionCase): child_build.local_result = 'ko' self.assertFalse(self.parent_build.global_result) + + + @patch('odoo.addons.runbot.models.build.runbot_build._local_pg_createdb') + @patch('odoo.addons.runbot.models.build.runbot_build._get_server_info') + @patch('odoo.addons.runbot.models.build.runbot_build._get_addons_path') + @patch('odoo.addons.runbot.models.build.runbot_build._get_py_version') + @patch('odoo.addons.runbot.models.build.runbot_build._server') + @patch('odoo.addons.runbot.models.build.runbot_build._checkout') + @patch('odoo.addons.runbot.models.build_config.docker_run') + def test_coverage(self, mock_docker_run, mock_checkout, mock_server, mock_get_py_version, mock_get_addons_path, mock_get_server_info, mock_local_pg_createdb): + config_step = self.ConfigStep.create({ + 'name': 'coverage', + 'job_type': 'install_odoo', + 'coverage': True + }) + + mock_checkout.return_value = {} + mock_server.return_value = 'bar' + mock_get_py_version.return_value = '3' + mock_get_addons_path.return_value = ['bar/addons'] + mock_get_server_info.return_value = (self.parent_build._get_all_commit()[0], 'server.py') + mock_local_pg_createdb.return_value = True + + def docker_run(cmd, log_path, build_dir, *args, **kwargs): + cmds = cmd.split(' && ') + self.assertEqual(cmds[0], 'sudo pip3 install -r bar/requirements.txt') + self.assertEqual(cmds[1].split(' bar/server.py')[0], 'python3 -m coverage run --branch --source /data/build --omit *__manifest__.py') + self.assertEqual(cmds[2], 'python3 -m coverage html -d /data/build/coverage --ignore-errors') + self.assertEqual(log_path, 'dev/null/logpath') + + mock_docker_run.side_effect = docker_run + + config_step._run_odoo_install(self.parent_build, 'dev/null/logpath') diff --git a/runbot_cla/build_config.py b/runbot_cla/build_config.py index e4dc4055..b32fb711 100644 --- a/runbot_cla/build_config.py +++ b/runbot_cla/build_config.py @@ -22,7 +22,7 @@ class Step(models.Model): def _runbot_cla_check(self, build, log_path): build._checkout() - cla_glob = glob.glob(build.get_server_commit()._source_path("doc/cla/*/*.md")) + cla_glob = glob.glob(build._get_server_commit()._source_path("doc/cla/*/*.md")) if cla_glob: description = "%s Odoo CLA signature check" % build.author mo = re.search('[^ <@]+@[^ @>]+', build.author_email or '')