diff --git a/runbot/__manifest__.py b/runbot/__manifest__.py
index 5085df56..84d15e5d 100644
--- a/runbot/__manifest__.py
+++ b/runbot/__manifest__.py
@@ -6,7 +6,7 @@
'author': "Odoo SA",
'website': "http://runbot.odoo.com",
'category': 'Website',
- 'version': '5.9',
+ 'version': '5.10',
'application': True,
'depends': ['base', 'base_automation', 'website'],
'data': [
diff --git a/runbot/container.py b/runbot/container.py
index 4134c9d3..0687f82e 100644
--- a/runbot/container.py
+++ b/runbot/container.py
@@ -137,6 +137,24 @@ def _docker_build(build_dir, image_tag):
return dm.result
+def docker_tag(identifier_or_tag, new_tag):
+ return _docker_tag(identifier_or_tag, new_tag)
+
+def _docker_tag(identifier_or_tag, new_tag):
+ if not identifier_or_tag:
+ return
+ _logger.info('Tagging image %s to "%s"', identifier_or_tag, new_tag)
+ docker_client = docker.from_env()
+ repo, tag = new_tag.split(':') # runbot DockerFile tags contains the repo part
+ try:
+ image = docker_client.images.get(identifier_or_tag)
+ image.tag(repo, tag)
+ except docker.errors.ImageNotFound:
+ _logger.warning('failed to find docker image with identifier %s', identifier_or_tag)
+ except docker.errors.APIError:
+ _logger.warning('failed to retag docker image with identifier %s', identifier_or_tag)
+
+
def docker_push(image_tag, push_url='127.0.0.1:5001'):
return _docker_push(image_tag, push_url)
diff --git a/runbot/data/dockerfile_data.xml b/runbot/data/dockerfile_data.xml
index 9e384bc6..c131f8a6 100644
--- a/runbot/data/dockerfile_data.xml
+++ b/runbot/data/dockerfile_data.xml
@@ -199,4 +199,15 @@ ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN python3 -m pip install --no-cache-dir -r /tmp/requirements.txt
+
+ Sync Identifiers
+
+
+ ir.actions.server
+ code
+
+ records.action_sync_identifiers()
+
+
+
diff --git a/runbot/migrations/18.0.5.10/post-migration.py b/runbot/migrations/18.0.5.10/post-migration.py
new file mode 100644
index 00000000..d1449926
--- /dev/null
+++ b/runbot/migrations/18.0.5.10/post-migration.py
@@ -0,0 +1,14 @@
+import logging
+
+_logger = logging.getLogger(__name__)
+
+def migrate(cr, version):
+ cr.execute("""
+ UPDATE runbot_dockerfile
+ SET image_identifier = subq.identifier, image_future_identifier = subq.identifier
+ FROM (SELECT DISTINCT ON (dockerfile_id) dockerfile_id, identifier
+ FROM runbot_docker_build_result
+ WHERE result='success' order by dockerfile_id, create_date desc)
+ AS subq
+ WHERE runbot_dockerfile.id = subq.dockerfile_id;
+ """)
diff --git a/runbot/models/build.py b/runbot/models/build.py
index c191d9c9..9c0673c0 100644
--- a/runbot/models/build.py
+++ b/runbot/models/build.py
@@ -853,6 +853,8 @@ class BuildResult(models.Model):
ro_volumes[f'/data/build/{dest}'] = source
if 'image_tag' not in kwargs:
kwargs.update({'image_tag': self.params_id.dockerfile_id.image_tag})
+ if self.params_id.config_data.get('docker_use_future') and not kwargs['image_tag'].endswith('.future'):
+ kwargs['image_tag'] = self.params_id.dockerfile_id.image_future_tag
self._log('Preparing', 'Using Dockerfile Tag [%s](/runbot/dockerfile/tag/%s)', kwargs['image_tag'], kwargs['image_tag'], log_type='markdown')
docker_registry_url = self.host_id._get_docker_registry_url()
if docker_registry_url and self.host_id.use_remote_docker_registry:
diff --git a/runbot/models/docker.py b/runbot/models/docker.py
index 6c407b2a..59821502 100644
--- a/runbot/models/docker.py
+++ b/runbot/models/docker.py
@@ -124,7 +124,10 @@ class Dockerfile(models.Model):
name = fields.Char('Dockerfile name', required=True, help="Name of Dockerfile")
active = fields.Boolean('Active', default=True, tracking=True)
+ image_identifier = fields.Char('Identifier')
+ image_future_identifier = fields.Char('Future Identifier')
image_tag = fields.Char(compute='_compute_image_tag', store=True)
+ image_future_tag = fields.Char(compute='_compute_image_future_tag')
template_id = fields.Many2one('ir.ui.view', string='Docker Template', domain=[('type', '=', 'qweb')], context={'default_type': 'qweb', 'default_arch_base': ''})
arch_base = fields.Text(related='template_id.arch_base', readonly=False, related_sudo=True)
dockerfile = fields.Text(compute='_compute_dockerfile', tracking=True)
@@ -198,12 +201,22 @@ class Dockerfile(models.Model):
if rec.name:
rec.image_tag = 'odoo:%s' % re.sub(r'[ /:\(\)\[\]]', '', rec.name)
+ @api.depends('image_tag')
+ def _compute_image_future_tag(self):
+ for rec in self:
+ rec.image_future_tag = f'{rec.image_tag}.future'
+
@api.depends('template_id')
def _compute_view_ids(self):
for rec in self:
keys = re.findall(r'
+
+
+
@@ -97,7 +100,7 @@
runbot.dockerfile.list
runbot.dockerfile
-
+
diff --git a/runbot/views/res_config_settings_views.xml b/runbot/views/res_config_settings_views.xml
index 745fdf5f..f6d864b7 100644
--- a/runbot/views/res_config_settings_views.xml
+++ b/runbot/views/res_config_settings_views.xml
@@ -97,6 +97,9 @@
+
+
+