diff --git a/runbot/container.py b/runbot/container.py index 8dc1793b..b9dae93c 100644 --- a/runbot/container.py +++ b/runbot/container.py @@ -32,10 +32,11 @@ ENV COVERAGE_FILE /data/build/.coverage class Command(): - def __init__(self, pres, cmd, posts): + def __init__(self, pres, cmd, posts, finals=None): self.pres = pres or [] self.cmd = cmd self.posts = posts or [] + self.finals = finals or [] def __getattr__(self, name): return getattr(self.cmd, name) @@ -44,14 +45,16 @@ class Command(): return self.cmd[key] def __add__(self, l): - return Command(self.pres, self.cmd + l, self.posts) + return Command(self.pres, self.cmd + l, self.posts, self.finals) 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) + cmd_chain = [' && '.join(cmd_chain)] + cmd_chain += [' '.join(final) for final in self.finals if final] + return ' ; '.join(cmd_chain) def docker_build(log_path, build_dir): @@ -138,7 +141,7 @@ def docker_get_gateway_ip(): def docker_ps(): """Return a list of running containers names""" docker_ps = subprocess.run(['docker', 'ps', '--format', '{{.Names}}'], stderr=subprocess.DEVNULL, stdout=subprocess.PIPE) - if docker_ps.returncode !=0: + if docker_ps.returncode != 0: return [] return docker_ps.stdout.decode().strip().split('\n') diff --git a/runbot/models/build.py b/runbot/models/build.py index 0ea40f3b..a8ec7094 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -642,7 +642,8 @@ class runbot_build(models.Model): if ending_build: build.update_build_end() - step_end_message = 'Step %s finished in %s' % (build.job, s2human(build.job_time)) + step_end_message = 'Step %s finished in %s $$fa-download$$' % (build.job, s2human(build.job_time)) + step_end_link = 'http://%s/runbot/static/build/%s/logs/%s-%s.sql.gz' % (build.host, build.dest, build.dest, build.active_step.db_name) build.write(build_values) if ending_build: @@ -652,7 +653,7 @@ class runbot_build(models.Model): build._logger("No result set, setting ok by default") if notify_end_job: - build._log('end_job', step_end_message) + build._log('end_job', step_end_message, log_type='link', path=step_end_link) else: build._logger(step_end_message) diff --git a/runbot/models/build_config.py b/runbot/models/build_config.py index 9f3b1218..4e2a7e6f 100644 --- a/runbot/models/build_config.py +++ b/runbot/models/build_config.py @@ -334,6 +334,8 @@ class ConfigStep(models.Model): cmd.posts.append(self._post_install_command(build, modules_to_install, py_version)) # coverage post, extra-checks, ... + cmd.finals.append(['pg_dump', db_name, '|', 'gzip', '>', '/data/build/logs/%s.sql.gz' % db_name]) + 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(cmd.build(), log_path, build._path(), build._get_docker_name(), cpu_limit=timeout, ro_volumes=exports) diff --git a/runbot/models/event.py b/runbot/models/event.py index 97f4e611..5a888a7e 100644 --- a/runbot/models/event.py +++ b/runbot/models/event.py @@ -6,7 +6,7 @@ from odoo import models, fields, api, tools _logger = logging.getLogger(__name__) -TYPES = [(t, t.capitalize()) for t in 'client server runbot subbuild'.split()] +TYPES = [(t, t.capitalize()) for t in 'client server runbot subbuild link'.split()] class runbot_event(models.Model): diff --git a/runbot/templates/build.xml b/runbot/templates/build.xml index b664d500..d4dacdb2 100644 --- a/runbot/templates/build.xml +++ b/runbot/templates/build.xml @@ -259,15 +259,26 @@ - - + + - + Sub build # : - -
+ + + + + + + + + + + +
+
diff --git a/runbot/tests/test_build_config_step.py b/runbot/tests/test_build_config_step.py index 89aa5293..3e46901d 100644 --- a/runbot/tests/test_build_config_step.py +++ b/runbot/tests/test_build_config_step.py @@ -107,7 +107,8 @@ class TestBuildConfigStep(common.TransactionCase): 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(cmds[2].split(' ; ')[0], 'python3 -m coverage html -d /data/build/coverage --ignore-errors') + self.assertEqual(cmds[2].split(' ; ')[1], 'pg_dump %s-coverage | gzip > /data/build/logs/%s-coverage.sql.gz' % (self.parent_build.dest, self.parent_build.dest)) self.assertEqual(log_path, 'dev/null/logpath') mock_docker_run.side_effect = docker_run