Skip to content

Commit c2f7d87

Browse files
committed
fix: stop requiring REGISTRY and VERSION files in 'build-image' command
1 parent dd07d4d commit c2f7d87

File tree

7 files changed

+100
-15
lines changed

7 files changed

+100
-15
lines changed

src/taskgraph/docker.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,22 @@
1818
from taskgraph.util import docker
1919
from taskgraph.util.taskcluster import get_artifact_url, get_session
2020

21+
DEPLOY_WARNING = """
22+
*****************************************************************
23+
WARNING: Image is not suitable for deploying/pushing.
24+
25+
To automatically tag the image the following files are required:
26+
- {image_dir}/REGISTRY
27+
- {image_dir}/VERSION
28+
29+
The REGISTRY file contains the Docker registry hosting the image.
30+
A default REGISTRY file may also be defined in the parent docker
31+
directory.
32+
33+
The VERSION file contains the version of the image.
34+
*****************************************************************
35+
"""
36+
2137

2238
def get_image_digest(image_name):
2339
from taskgraph.generator import load_tasks_for_kind
@@ -105,19 +121,18 @@ def build_image(name, tag, args=None):
105121

106122
buf = BytesIO()
107123
docker.stream_context_tar(".", image_dir, buf, "", args)
108-
subprocess.run(
109-
["docker", "image", "build", "--no-cache", "-t", tag, "-"], input=buf.getvalue()
110-
)
124+
cmdargs = ["docker", "image", "build", "--no-cache", "-"]
125+
if tag:
126+
cmdargs.insert(-1, f"-t={tag}")
127+
subprocess.run(cmdargs, input=buf.getvalue())
111128

112-
print(f"Successfully built {name} and tagged with {tag}")
129+
msg = f"Successfully built {name}"
130+
if tag:
131+
msg += f" and tagged with {tag}"
132+
print(msg)
113133

114-
if tag.endswith(":latest"):
115-
print("*" * 50)
116-
print("WARNING: no VERSION file found in image directory.")
117-
print("Image is not suitable for deploying/pushing.")
118-
print("Create an image suitable for deploying/pushing by creating")
119-
print("a VERSION file in the image directory.")
120-
print("*" * 50)
134+
if not tag or tag.endswith(":latest"):
135+
print(DEPLOY_WARNING.format(image_dir=os.path.relpath(image_dir), image=name))
121136

122137

123138
def load_image(url, imageName=None, imageTag=None):

src/taskgraph/util/docker.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io
88
import os
99
import re
10+
from typing import Optional
1011

1112
from taskgraph.util.archive import create_tar_gz_from_files
1213
from taskgraph.util.memoize import memoize
@@ -16,25 +17,35 @@
1617
from .yaml import load_yaml
1718

1819

19-
def docker_image(name, by_tag=False):
20+
def docker_image(name: str, by_tag: bool = False) -> Optional[str]:
2021
"""
2122
Resolve in-tree prebuilt docker image to ``<registry>/<repository>@sha256:<digest>``,
2223
or ``<registry>/<repository>:<tag>`` if `by_tag` is `True`.
24+
25+
Args:
26+
name (str): The image to build.
27+
by_tag (bool): If True, will apply a tag based on VERSION file.
28+
Otherwise will apply a hash based on HASH file.
29+
Returns:
30+
Optional[str]: Image if it can be resolved, otherwise None.
2331
"""
2432
try:
2533
with open(os.path.join(IMAGE_DIR, name, "REGISTRY")) as f:
2634
registry = f.read().strip()
2735
except OSError:
28-
with open(os.path.join(IMAGE_DIR, "REGISTRY")) as f:
29-
registry = f.read().strip()
36+
try:
37+
with open(os.path.join(IMAGE_DIR, "REGISTRY")) as f:
38+
registry = f.read().strip()
39+
except OSError:
40+
return None
3041

3142
if not by_tag:
3243
hashfile = os.path.join(IMAGE_DIR, name, "HASH")
3344
try:
3445
with open(hashfile) as f:
3546
return f"{registry}/{name}@{f.read().strip()}"
3647
except OSError:
37-
raise Exception(f"Failed to read HASH file {hashfile}")
48+
return None
3849

3950
try:
4051
with open(os.path.join(IMAGE_DIR, name, "VERSION")) as f:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM hello-world
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM hello-world

test/test_docker.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import pytest
2+
3+
from taskgraph import docker
4+
5+
6+
@pytest.fixture(autouse=True, scope="module")
7+
def mock_docker_path(module_mocker, datadir):
8+
module_mocker.patch(
9+
"taskgraph.util.docker.IMAGE_DIR", str(datadir / "taskcluster" / "docker")
10+
)
11+
12+
13+
@pytest.fixture
14+
def mock_docker_build(mocker):
15+
def side_effect(topsrcdir, context_dir, out_file, image_name=None, args=None):
16+
out_file.write(b"xyz")
17+
18+
m_stream = mocker.patch.object(docker.docker, "stream_context_tar")
19+
m_stream.side_effect = side_effect
20+
21+
m_run = mocker.patch.object(docker.subprocess, "run")
22+
return (m_stream, m_run)
23+
24+
25+
def test_build_image(capsys, mock_docker_build):
26+
m_stream, m_run = mock_docker_build
27+
image = "hello-world-tag"
28+
tag = f"test/{image}:1.0"
29+
30+
assert docker.build_image(image, None) is None
31+
m_stream.assert_called_once()
32+
m_run.assert_called_once_with(
33+
["docker", "image", "build", "--no-cache", f"-t={tag}", "-"],
34+
input=b"xyz",
35+
)
36+
37+
out, _ = capsys.readouterr()
38+
assert f"Successfully built {image} and tagged with {tag}" in out
39+
assert "Image is not suitable for deploying/pushing" not in out
40+
41+
42+
def test_build_image_no_tag(capsys, mock_docker_build):
43+
m_stream, m_run = mock_docker_build
44+
image = "hello-world"
45+
46+
assert docker.build_image(image, None) is None
47+
m_stream.assert_called_once()
48+
m_run.assert_called_once_with(
49+
["docker", "image", "build", "--no-cache", "-"],
50+
input=b"xyz",
51+
)
52+
53+
out, _ = capsys.readouterr()
54+
assert f"Successfully built {image}" in out
55+
assert "Image is not suitable for deploying/pushing" in out

0 commit comments

Comments
 (0)