[IMP] runbot: add coverage xml export

When coverage is computed, a post command is used to generate the HTML
report. In order to use the coverage result locally the HTML report is
not enough.

With this commit, an XML report is also generated. It's a single xml
file, downloadable from the build result web page.

The _post_install_command method is renamed into its plural form because
it was useless to return only one command.
This commit is contained in:
Christophe Monniez 2020-02-26 10:28:13 +01:00
parent 820adae5ac
commit 3918d266fa
3 changed files with 13 additions and 9 deletions

View File

@ -270,7 +270,7 @@ def tests(args):
if args.coverage: if args.coverage:
omit = ['--omit', '*__manifest__.py'] omit = ['--omit', '*__manifest__.py']
python_params = [ '-m', 'coverage', 'run', '--branch', '--source', '/data/build'] + omit python_params = [ '-m', 'coverage', 'run', '--branch', '--source', '/data/build'] + omit
posts = [['python%s' % py_version, "-m", "coverage", "html", "-d", "/data/build/coverage", "--ignore-errors"]] posts = [['python%s' % py_version, "-m", "coverage", "html", "-d", "/data/build/coverage", "--ignore-errors"], ['python%s' % py_version, "-m", "coverage", "xml", "--ignore-errors"]]
os.makedirs(os.path.join(args.build_dir, 'coverage'), exist_ok=True) os.makedirs(os.path.join(args.build_dir, 'coverage'), exist_ok=True)
elif args.flamegraph: elif args.flamegraph:
flame_log = '/data/build/logs/flame.log' flame_log = '/data/build/logs/flame.log'

View File

@ -388,7 +388,7 @@ class ConfigStep(models.Model):
if extra_params: if extra_params:
cmd.extend(shlex.split(extra_params)) cmd.extend(shlex.split(extra_params))
cmd.posts.append(self._post_install_command(build, modules_to_install, py_version)) # coverage post, extra-checks, ... cmd.posts.extend(self._post_install_commands(build, modules_to_install, py_version)) # coverage post, extra-checks, ...
dump_dir = '/data/build/logs/%s/' % db_name dump_dir = '/data/build/logs/%s/' % db_name
sql_dest = '%s/dump.sql' % dump_dir sql_dest = '%s/dump.sql' % dump_dir
filestore_path = '/data/build/datadir/filestore/%s' % db_name filestore_path = '/data/build/datadir/filestore/%s' % db_name
@ -421,6 +421,10 @@ class ConfigStep(models.Model):
kwargs['log_type'] = 'link' kwargs['log_type'] = 'link'
build._log('', **kwargs) build._log('', **kwargs)
if self.coverage:
message = 'Coverage xml: $$fa-download'
build._log('end_job', message, log_type='link', path='/data/build/logs/coverage.xml')
if self.flamegraph: if self.flamegraph:
link = self._perf_data_url(build, 'log.gz') link = self._perf_data_url(build, 'log.gz')
message = 'Flamegraph data: $$fa-download$$' message = 'Flamegraph data: $$fa-download$$'
@ -433,14 +437,16 @@ class ConfigStep(models.Model):
def _modules_to_install(self, build): def _modules_to_install(self, build):
return set(build._get_modules_to_test(modules_patterns=self.install_modules)) return set(build._get_modules_to_test(modules_patterns=self.install_modules))
def _post_install_command(self, build, modules_to_install, py_version=None): def _post_install_commands(self, build, modules_to_install, py_version=None):
cmds = []
if self.coverage: if self.coverage:
py_version = py_version if py_version is not None else build._get_py_version() py_version = py_version if py_version is not None else build._get_py_version()
# prepare coverage result # prepare coverage result
cov_path = build._path('coverage') cov_path = build._path('coverage')
os.makedirs(cov_path, exist_ok=True) os.makedirs(cov_path, exist_ok=True)
return ['python%s' % py_version, "-m", "coverage", "html", "-d", "/data/build/coverage", "--ignore-errors"] cmds.append(['python%s' % py_version, "-m", "coverage", "html", "-d", "/data/build/coverage", "--ignore-errors"])
return [] cmds.append(['python%s' % py_version, "-m", "coverage", "xml", "-o", "/data/build/logs/coverage.xml", "--ignore-errors"])
return cmds
def _perfs_data_path(self, ext='log'): def _perfs_data_path(self, ext='log'):
return '/data/build/logs/flame_%s.%s' % (self.name, ext) return '/data/build/logs/flame_%s.%s' % (self.name, ext)

View File

@ -153,12 +153,10 @@ class TestBuildConfigStep(RunbotCase):
}) })
def docker_run(cmd, log_path, *args, **kwargs): def docker_run(cmd, log_path, *args, **kwargs):
cmds = cmd.build().split(' && ')
dest = self.parent_build.dest
self.assertEqual(cmd.pres, [['sudo', 'pip3', 'install', '-r', 'bar/requirements.txt']]) self.assertEqual(cmd.pres, [['sudo', 'pip3', 'install', '-r', 'bar/requirements.txt']])
self.assertEqual(cmd.cmd[:10], ['python3', '-m', 'coverage', 'run', '--branch', '--source', '/data/build', '--omit', '*__manifest__.py', 'bar/server.py']) self.assertEqual(cmd.cmd[:10], ['python3', '-m', 'coverage', 'run', '--branch', '--source', '/data/build', '--omit', '*__manifest__.py', 'bar/server.py'])
#['bar/server.py', '--addons-path', 'bar', '--no-xmlrpcs', '--no-netrpc', '-d', '08732-master-d0d0ca-coverage', '--test-enable', '--stop-after-init', '--log-level=test', '--max-cron-threads=0'] self.assertIn(['python3', '-m', 'coverage', 'html', '-d', '/data/build/coverage', '--ignore-errors'], cmd.posts)
self.assertEqual(cmd.posts, [['python3', '-m', 'coverage', 'html', '-d', '/data/build/coverage', '--ignore-errors']]) self.assertIn(['python3', '-m', 'coverage', 'xml', '-o', '/data/build/logs/coverage.xml', '--ignore-errors'], cmd.posts)
self.assertEqual(log_path, 'dev/null/logpath') self.assertEqual(log_path, 'dev/null/logpath')
self.patchers['docker_run'].side_effect = docker_run self.patchers['docker_run'].side_effect = docker_run