diff --git a/Dockerfile b/Dockerfile index a92391e36..1ab42f700 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM fedora:latest RUN dnf -y install python3-setuptools flatpak python3-pip git \ gcc krb5-devel python3-devel popt-devel && dnf clean all RUN mkdir /tmp/atomic-reactor -ADD . /tmp/atomic-reactor +COPY . /tmp/atomic-reactor RUN pip3 install git+https://github.com/containerbuildsystem/osbs-client RUN cd /tmp/atomic-reactor && python3 setup.py install CMD ["atomic-reactor", "--verbose", "inside-build"] diff --git a/atomic_reactor/plugins/add_dockerfile.py b/atomic_reactor/plugins/add_dockerfile.py index f992d30e4..1ebfb8ac2 100644 --- a/atomic_reactor/plugins/add_dockerfile.py +++ b/atomic_reactor/plugins/add_dockerfile.py @@ -8,7 +8,7 @@ Include user-provided Dockerfile in the IMAGE_BUILD_INFO_DIR (or other if provided) directory in the built image. -This is accomplished by appending an ADD command to it. +This is accomplished by appending a COPY command to it. Name of the Dockerfile is changed to include N-V-R of the build. N-V-R is specified either by nvr argument OR from Name/Version/Release labels in Dockerfile. @@ -98,12 +98,12 @@ def add_dockerfile(self, build_dir: BuildDir) -> None: if self.use_final_dockerfile: # when using final dockerfile, we should use DOCKERFILE_FILENAME - add_line = f'ADD {DOCKERFILE_FILENAME} {self.df_path}\n' + add_line = f'COPY {DOCKERFILE_FILENAME} {self.df_path}\n' allow_path_in_dockerignore(build_dir.path, DOCKERFILE_FILENAME) else: # otherwise we should copy current snapshot and use the copied version shutil.copy2(build_dir.dockerfile_path, build_dir.path / self.df_name) - add_line = f'ADD {self.df_name} {self.df_path}\n' + add_line = f'COPY {self.df_name} {self.df_path}\n' allow_path_in_dockerignore(build_dir.path, self.df_name) # put it before last instruction diff --git a/atomic_reactor/plugins/add_filesystem.py b/atomic_reactor/plugins/add_filesystem.py index 34507d161..262583973 100644 --- a/atomic_reactor/plugins/add_filesystem.py +++ b/atomic_reactor/plugins/add_filesystem.py @@ -331,6 +331,7 @@ def _add_filesystem_to_dockerfile(self, file_name, build_dir: BuildDir): """ Put an ADD instruction into the Dockerfile (to include the filesystem into the container image to be built) + NOTE: this must be ADD instruction as it un-TARs the source """ content = 'ADD {0} /\n'.format(file_name) lines = build_dir.dockerfile.lines diff --git a/atomic_reactor/plugins/add_help.py b/atomic_reactor/plugins/add_help.py index fa571e9d1..a1f490693 100644 --- a/atomic_reactor/plugins/add_help.py +++ b/atomic_reactor/plugins/add_help.py @@ -8,7 +8,7 @@ Convert a help markdown file a man page and store it to /help.1 in the image so that 'atomic help' could display it. -This is accomplished by appending an ADD command to it. +This is accomplished by appending a COPY command to it. Example configuration: { @@ -138,7 +138,7 @@ def add_help_file_to_df(self, build_dir: BuildDir) -> None: dockerfile = build_dir.dockerfile lines = dockerfile.lines - content = 'ADD {0} /{0}'.format(self.man_filename) + content = 'COPY {0} /{0}'.format(self.man_filename) # put it before last instruction lines.insert(-1, content + '\n') diff --git a/atomic_reactor/plugins/add_image_content_manifest.py b/atomic_reactor/plugins/add_image_content_manifest.py index a43b86c3f..034e973fc 100644 --- a/atomic_reactor/plugins/add_image_content_manifest.py +++ b/atomic_reactor/plugins/add_image_content_manifest.py @@ -188,11 +188,11 @@ def _write_json_file(self, icm: dict, build_dir: BuildDir) -> None: def _add_to_dockerfile(self, build_dir: BuildDir) -> None: """ - Put an ADD instruction into the Dockerfile (to include the ICM file + Put a COPY instruction into the Dockerfile (to include the ICM file into the container image to be built) """ dest_file_path = os.path.join(self.content_manifests_dir, self.icm_file_name) - content = 'ADD {0} {1}'.format(self.icm_file_name, dest_file_path) + content = 'COPY {0} {1}'.format(self.icm_file_name, dest_file_path) lines = build_dir.dockerfile.lines # Put it before last instruction diff --git a/atomic_reactor/plugins/flatpak_create_dockerfile.py b/atomic_reactor/plugins/flatpak_create_dockerfile.py index b9d3d380f..9682334cf 100644 --- a/atomic_reactor/plugins/flatpak_create_dockerfile.py +++ b/atomic_reactor/plugins/flatpak_create_dockerfile.py @@ -42,9 +42,9 @@ LABEL release="@RELEASE@" RUN rm -f {yum_repos_dir}* -ADD {relative_repos_path}* {yum_repos_dir} +COPY {relative_repos_path}* {yum_repos_dir} -ADD {includepkgs} /tmp/ +COPY {includepkgs} /tmp/ RUN cat /tmp/atomic-reactor-includepkgs >> /etc/dnf/dnf.conf && \\ INSTALLDIR=/var/tmp/flatpak-build && \\ diff --git a/atomic_reactor/plugins/inject_yum_repos.py b/atomic_reactor/plugins/inject_yum_repos.py index b724d43d2..efdb8a6d2 100644 --- a/atomic_reactor/plugins/inject_yum_repos.py +++ b/atomic_reactor/plugins/inject_yum_repos.py @@ -226,7 +226,7 @@ def _inject_repo_files(self, build_dir: BuildDir) -> None: def _inject_into_dockerfile(self, build_dir: BuildDir): build_dir.dockerfile.add_lines( - "ADD %s* %s" % (RELATIVE_REPOS_PATH, YUM_REPOS_DIR), + "COPY %s* %s" % (RELATIVE_REPOS_PATH, YUM_REPOS_DIR), all_stages=True, at_start=True, skip_scratch=True ) @@ -236,7 +236,7 @@ def _inject_into_dockerfile(self, build_dir: BuildDir): build_dir.path / self._ca_bundle_pem ) build_dir.dockerfile.add_lines( - f'ADD {self._ca_bundle_pem} /tmp/{self._ca_bundle_pem}', + f'COPY {self._ca_bundle_pem} /tmp/{self._ca_bundle_pem}', all_stages=True, at_start=True, skip_scratch=True ) allow_path_in_dockerignore(build_dir.path, self._ca_bundle_pem) diff --git a/docs/plugins.md b/docs/plugins.md index 08a8d513a..4e7de1e44 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -177,7 +177,7 @@ containing the Dockerfile. and other metadata, and ADDs it to the built image - **add_dockerfile** - Status: Enabled - - The Dockerfile used to build the image has a line added to ADD itself into + - The Dockerfile used to build the image has a line added to COPY itself into the built image - **distgit_fetch_artefacts** - Status: Enabled diff --git a/tests/plugins/test_add_dockerfile.py b/tests/plugins/test_add_dockerfile.py index e288d0611..482ad4dfa 100644 --- a/tests/plugins/test_add_dockerfile.py +++ b/tests/plugins/test_add_dockerfile.py @@ -81,7 +81,7 @@ def test_adddockerfile_plugin(tmpdir, workflow): # noqa expected_df_content = """ FROM fedora RUN yum install -y python-django -ADD Dockerfile-rhel-server-docker-7.1-20 /root/buildinfo/Dockerfile-rhel-server-docker-7.1-20 +COPY Dockerfile-rhel-server-docker-7.1-20 /root/buildinfo/Dockerfile-rhel-server-docker-7.1-20 CMD blabla""" # the copied Dockerfile should have the *original* content expected_df_copy = DockerfileCopy("Dockerfile-rhel-server-docker-7.1-20", df_content) @@ -105,7 +105,7 @@ def test_adddockerfile_todest(tmpdir, workflow): # noqa expected_df_content = """ FROM fedora RUN yum install -y python-django -ADD Dockerfile-jboss-eap-6-docker-6.4-77 /usr/share/doc/Dockerfile-jboss-eap-6-docker-6.4-77 +COPY Dockerfile-jboss-eap-6-docker-6.4-77 /usr/share/doc/Dockerfile-jboss-eap-6-docker-6.4-77 CMD blabla""" expected_df_copy = DockerfileCopy("Dockerfile-jboss-eap-6-docker-6.4-77", df_content) @@ -128,7 +128,7 @@ def test_adddockerfile_nvr_from_labels(tmpdir, workflow): # noqa FROM fedora RUN yum install -y python-django LABEL Name="jboss-eap-6-docker" "Version"="6.4" "Release"=77 -ADD Dockerfile-jboss-eap-6-docker-6.4-77 /root/buildinfo/Dockerfile-jboss-eap-6-docker-6.4-77 +COPY Dockerfile-jboss-eap-6-docker-6.4-77 /root/buildinfo/Dockerfile-jboss-eap-6-docker-6.4-77 CMD blabla""" expected_df_copy = DockerfileCopy("Dockerfile-jboss-eap-6-docker-6.4-77", df_content) @@ -161,7 +161,7 @@ def test_adddockerfile_final(tmpdir, workflow): # noqa expected_df_content = """ FROM fedora RUN yum install -y python-django -ADD Dockerfile /root/buildinfo/Dockerfile-rhel-server-docker-7.1-20 +COPY Dockerfile /root/buildinfo/Dockerfile-rhel-server-docker-7.1-20 CMD blabla""" workflow.build_dir.for_each_platform(check_outputs(expected_df_content)) diff --git a/tests/plugins/test_add_help.py b/tests/plugins/test_add_help.py index b64b4b493..0ff6ff64d 100644 --- a/tests/plugins/test_add_help.py +++ b/tests/plugins/test_add_help.py @@ -170,7 +170,7 @@ def check_df_and_man_file(build_dir): f""" FROM fedora RUN yum install -y python-django - ADD {AddHelpPlugin.man_filename} /{AddHelpPlugin.man_filename} + COPY {AddHelpPlugin.man_filename} /{AddHelpPlugin.man_filename} CMD blabla """ ) diff --git a/tests/plugins/test_add_image_content_manifest.py b/tests/plugins/test_add_image_content_manifest.py index b920b7c46..99bf9c9fd 100644 --- a/tests/plugins/test_add_image_content_manifest.py +++ b/tests/plugins/test_add_image_content_manifest.py @@ -311,7 +311,7 @@ def check_in_build_dir(build_dir): dedent("""\ FROM base_image CMD build /spam/eggs - ADD eggs-1.0-42.json /root/buildinfo/content_manifests/eggs-1.0-42.json + COPY eggs-1.0-42.json /root/buildinfo/content_manifests/eggs-1.0-42.json LABEL com.redhat.component=eggs version=1.0 release=42 """), 2, @@ -326,7 +326,7 @@ def check_in_build_dir(build_dir): dedent("""\ FROM base_image CMD build /spam/eggs - ADD eggs-1.0-42.json /root/buildinfo/content_manifests/eggs-1.0-42.json + COPY eggs-1.0-42.json /root/buildinfo/content_manifests/eggs-1.0-42.json LABEL com.redhat.component=eggs version=1.0 release=42 """), 3, @@ -341,7 +341,7 @@ def check_in_build_dir(build_dir): dedent("""\ FROM scratch CMD build /spam/eggs - ADD eggs-1.0-42.json /root/buildinfo/content_manifests/eggs-1.0-42.json + COPY eggs-1.0-42.json /root/buildinfo/content_manifests/eggs-1.0-42.json LABEL com.redhat.component=eggs version=1.0 release=42 """), 0, diff --git a/tests/plugins/test_flatpak_create_dockerfile.py b/tests/plugins/test_flatpak_create_dockerfile.py index 0dedc7150..9c4320ef7 100644 --- a/tests/plugins/test_flatpak_create_dockerfile.py +++ b/tests/plugins/test_flatpak_create_dockerfile.py @@ -156,7 +156,7 @@ def test_flatpak_create_dockerfile(workflow, source_dir, config_name, override_b assert 'name="{}"'.format(config['name']) in df assert 'com.redhat.component="{}"'.format(config['component']) in df assert "RUN rm -f /etc/yum.repos.d/*" in df - assert "ADD atomic-reactor-repos/* /etc/yum.repos.d/" in df + assert "COPY atomic-reactor-repos/* /etc/yum.repos.d/" in df def test_skip_plugin(workflow, source_dir, caplog): diff --git a/tests/plugins/test_inject_yum_repos.py b/tests/plugins/test_inject_yum_repos.py index 6d9dafc6e..1b5c223bd 100644 --- a/tests/plugins/test_inject_yum_repos.py +++ b/tests/plugins/test_inject_yum_repos.py @@ -277,8 +277,8 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r '''), dedent(f'''\ FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN dnf update -y RUN rm -f '/etc/yum.repos.d/custom-{{}}.repo' RUN rm -f /tmp/{CA_BUNDLE_PEM} @@ -308,8 +308,8 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r '''), dedent(f'''\ FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN dnf update -y RUN rm -f '/etc/yum.repos.d/target-bd4b1.repo' '/etc/yum.repos.d/custom-{{}}.repo' RUN rm -f /tmp/{CA_BUNDLE_PEM} @@ -355,14 +355,14 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r '''), dedent(f'''\ FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN dnf update -y FROM scratch RUN touch /tmp/hello.txt FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN echo hello RUN rm -f '/etc/yum.repos.d/odcs-1234-{{}}.repo' RUN rm -f /tmp/{CA_BUNDLE_PEM} @@ -405,14 +405,14 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r '''), dedent(f'''\ FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN dnf update -y FROM scratch RUN touch /tmp/hello.txt FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN echo hello RUN rm -f '/etc/yum.repos.d/target-bd4b1.repo' '/etc/yum.repos.d/odcs-1234-{{}}.repo' RUN rm -f /tmp/{CA_BUNDLE_PEM} @@ -455,16 +455,16 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r """), dedent(f"""\ FROM golang:1.9 AS builder1 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ USER grahamchapman RUN build /spam/eggs FROM scratch USER somebody RUN build /somebody FROM jdk:1.8 AS builder2 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ USER ericidle RUN yum -y update FROM scratch @@ -506,16 +506,16 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r """), dedent(f"""\ FROM golang:1.9 AS builder1 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ USER grahamchapman RUN build /spam/eggs FROM scratch USER somebody RUN build /somebody FROM jdk:1.8 AS builder2 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ USER ericidle RUN yum -y update FROM scratch @@ -551,12 +551,12 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r """), dedent(f"""\ FROM golang:1.9 AS builder1 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN build /spam/eggs FROM base - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ COPY --from=builder1 /some/stuff /bin/spam USER root RUN rm -f '/etc/yum.repos.d/custom-{{}}.repo' @@ -593,13 +593,13 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r """), dedent(f"""\ FROM golang:1.9 AS builder1 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ USER grahamchapman RUN build /spam/eggs FROM base - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ COPY --from=builder1 /some/stuff /bin/spam USER root RUN rm -f '/etc/yum.repos.d/custom-{{}}.repo' @@ -647,8 +647,8 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r '''), dedent(f'''\ FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN dnf update -y RUN rm -f '/etc/yum.repos.d/custom-{{}}.repo' '/etc/yum.repos.d/custom-2-{{}}.repo' RUN rm -f /tmp/{CA_BUNDLE_PEM} @@ -689,8 +689,8 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r ''', dedent(f'''\ FROM fedora - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN yum install -y httpd uwsgi RUN rm -f '/etc/yum.repos.d/custom-{{}}.repo' RUN rm -f /tmp/{CA_BUNDLE_PEM} @@ -721,7 +721,7 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r '''), dedent('''\ FROM fedora:33 - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN dnf update -y RUN rm -f '/etc/yum.repos.d/custom-{}.repo' '''), @@ -757,12 +757,12 @@ def test_no_base_image_in_dockerfile(workflow, build_dir, configure_ca_bundle, r '''), dedent(f'''\ FROM base - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ RUN gcc main.c FROM fedora:33 - ADD {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} - ADD atomic-reactor-repos/* /etc/yum.repos.d/ + COPY {CA_BUNDLE_PEM} /tmp/{CA_BUNDLE_PEM} + COPY atomic-reactor-repos/* /etc/yum.repos.d/ USER 1001 WORKDIR /src USER root @@ -1018,10 +1018,10 @@ def test_some_platform_has_no_repos(workflow, build_dir, repourl, repo_filename, aarch64_dir = workflow.build_dir.platform_dir("aarch64") assert (x86_dir.path / RELATIVE_REPOS_PATH / repo_filename).exists() - assert "ADD atomic-reactor-repos/* /etc/yum.repos.d" in x86_dir.dockerfile.content + assert "COPY atomic-reactor-repos/* /etc/yum.repos.d" in x86_dir.dockerfile.content assert not (aarch64_dir.path / RELATIVE_REPOS_PATH).exists() - assert "ADD atomic-reactor-repos/* /etc/yum.repos.d" not in aarch64_dir.dockerfile.content + assert "COPY atomic-reactor-repos/* /etc/yum.repos.d" not in aarch64_dir.dockerfile.content assert "no repos to inject for aarch64 platform" in caplog.text diff --git a/tests/test_inner.py b/tests/test_inner.py index 39fc5dce7..50339d026 100644 --- a/tests/test_inner.py +++ b/tests/test_inner.py @@ -351,7 +351,7 @@ def test_parent_images_to_str(workflow, caplog): def test_no_base_image(context_dir, build_dir): source = DummySource("git", "https://git.host/") dfp = DockerfileParser(source.source_path) - dfp.content = "# no FROM\nADD spam /eggs" + dfp.content = "# no FROM\nCOPY spam /eggs" with pytest.raises(RuntimeError, match="no base image specified"): DockerBuildWorkflow(context_dir, build_dir,