diff --git a/src/main/java/io/fabric8/maven/docker/BuildMojo.java b/src/main/java/io/fabric8/maven/docker/BuildMojo.java index f703e4a0d..a9ca73db3 100644 --- a/src/main/java/io/fabric8/maven/docker/BuildMojo.java +++ b/src/main/java/io/fabric8/maven/docker/BuildMojo.java @@ -105,7 +105,9 @@ private void proceedWithDockerBuild(ServiceHub hub, BuildService.BuildContext bu } else { buildService.buildImage(imageConfig, pullManager, buildContext, buildArchiveFile); if (!skipTag) { - buildService.tagImage(imageConfig); + if (!imageConfig.getBuildConfiguration().skipTag()) { + buildService.tagImage(imageConfig); + } } } } diff --git a/src/main/java/io/fabric8/maven/docker/TagMojo.java b/src/main/java/io/fabric8/maven/docker/TagMojo.java index d72b4f6ad..d15143c9f 100644 --- a/src/main/java/io/fabric8/maven/docker/TagMojo.java +++ b/src/main/java/io/fabric8/maven/docker/TagMojo.java @@ -39,7 +39,7 @@ public void executeInternal(ServiceHub hub) throws DockerAccessException, MojoEx continue; } if (buildConfig.isBuildX()) { - // Tag happens the building stage. + // Tag happens at the building stage. continue; } diff --git a/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java b/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java index 4d3bcb611..f535a4f53 100644 --- a/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java +++ b/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java @@ -11,6 +11,8 @@ import io.fabric8.maven.docker.service.BuildService; import io.fabric8.maven.docker.service.BuildXService; import io.fabric8.maven.docker.service.ImagePullManager; +import io.fabric8.maven.docker.util.ImageName; + import org.apache.maven.plugin.MojoExecutionException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -31,6 +33,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @ExtendWith(MockitoExtension.class) class BuildMojoTest extends MojoTestBase { @@ -241,6 +244,75 @@ void buildUsingBuildxWithMultipleAuth() throws IOException, MojoExecutionExcepti thenAuthContainsRegistry("custom-registry.org"); } + void buildUsingBuildxWithTag(boolean skipTag) throws IOException, MojoExecutionException { + givenBuildXService(); + + List tags = new ArrayList<>(); + tags.add("tag-" + System.currentTimeMillis()); + tags.add("tag-" + System.currentTimeMillis()); + + givenMavenProject(buildMojo); + ImageConfiguration imageConfiguration = singleImageConfiguration(builder -> { + builder.buildx(getBuildXPlatforms(TWO_BUILDX_PLATFORMS).build()); + builder.tags(tags); + builder.skipTag(skipTag); + }); + givenResolvedImages(buildMojo, Collections.singletonList(imageConfiguration)); + givenPackaging("jar"); + + whenMojoExecutes(); + + List fullTags = skipTag ? Collections.emptyList() : tags.stream() + .map(tag -> new ImageName(imageConfiguration.getName(), tag).getFullName()) + .collect(Collectors.toList()); + thenBuildxRun(null, null, true, null, fullTags); + } + + @Test + void buildUsingBuildxWithTag() throws IOException, MojoExecutionException { + buildUsingBuildxWithTag(false); + } + + @Test + void buildUsingBuildxWithSkipTag() throws IOException, MojoExecutionException { + buildUsingBuildxWithTag(true); + } + + void buildWithTag(boolean skipTag) throws IOException, MojoExecutionException { + givenMavenProject(buildMojo); + + List tags = new ArrayList<>(); + tags.add("tag-" + System.currentTimeMillis()); + tags.add("tag-" + System.currentTimeMillis()); + + ImageConfiguration imageConfiguration = singleImageConfiguration(builder -> { + builder.skipTag(skipTag); + builder.tags(tags); + }); + givenResolvedImages(buildMojo, Collections.singletonList(imageConfiguration)); + givenPackaging("jar"); + givenSkipPom(true); + + whenMojoExecutes(); + + thenBuildRun(); + + if (!skipTag) { + Mockito.verify(buildService, Mockito.times(1)) + .tagImage(Mockito.any(ImageConfiguration.class)); + } + } + + @Test + void buildWithTag() throws IOException, MojoExecutionException { + buildWithTag(false); + } + + @Test + void buildWithSkipTag() throws IOException, MojoExecutionException { + buildWithTag(true); + } + private void givenBuildXService() { BuildXService buildXService = new BuildXService(dockerAccess, dockerAssemblyManager, log, exec); @@ -288,24 +360,39 @@ private void verifyBuild(int wantedNumberOfInvocations) throws DockerAccessExcep .buildImage(Mockito.any(ImageConfiguration.class), Mockito.any(ImagePullManager.class), Mockito.any(BuildService.BuildContext.class), Mockito.any()); } + private void thenBuildxRun(String relativeConfigFile, String contextDir, boolean nativePlatformIncluded, + String attestation) throws MojoExecutionException { + thenBuildxRun(relativeConfigFile, contextDir, nativePlatformIncluded, attestation, Collections.emptyList()); + } + private void thenBuildxRun(String relativeConfigFile, String contextDir, - boolean nativePlatformIncluded, String attestation) throws MojoExecutionException { + boolean nativePlatformIncluded, String attestation, List tags) + throws MojoExecutionException { Path buildPath = projectBaseDirectory.toPath().resolve("target/docker/example/latest"); String config = getOsDependentBuild(buildPath, "docker"); - String configFile = relativeConfigFile != null ? getOsDependentBuild(projectBaseDirectory.toPath(), relativeConfigFile) : null; + String configFile = + relativeConfigFile != null ? getOsDependentBuild(projectBaseDirectory.toPath(), relativeConfigFile) : + null; List cmds = - BuildXService.append(new ArrayList<>(), "docker", "--config", config, "buildx", - "create", "--driver", "docker-container", "--name", "maven" , "--node", "maven0"); + BuildXService.append(new ArrayList<>(), "docker", "--config", config, "buildx", + "create", "--driver", "docker-container", "--name", "maven", "--node", "maven0"); if (configFile != null) { BuildXService.append(cmds, "--config", configFile.replace('/', File.separatorChar)); } Mockito.verify(exec).process(cmds); if (nativePlatformIncluded) { - List buildXLine = BuildXService.append(new ArrayList<>(), "docker", "--config", config, "buildx", + List buildXLine = BuildXService.append(new ArrayList<>(), "docker", "--config", config, "buildx", "build", "--progress=plain", "--builder", "maven", - "--platform", NATIVE_PLATFORM, "--tag", "example:latest", "--build-arg", "foo=bar"); + "--platform", NATIVE_PLATFORM, "--tag", "example:latest"); + + tags.forEach(tag -> { + buildXLine.add("--tag"); + buildXLine.add(tag); + }); + buildXLine.add("--build-arg"); + buildXLine.add("foo=bar"); if (attestation != null) { buildXLine.add(attestation); @@ -315,7 +402,7 @@ private void thenBuildxRun(String relativeConfigFile, String contextDir, buildXLine.add(getOsDependentBuild(buildPath, "build")); } else { Path contextPath = tmpDir.resolve("docker-build"); - BuildXService.append(buildXLine, "--file=" + contextPath.resolve("Dockerfile"), contextPath.toString() ); + BuildXService.append(buildXLine, "--file=" + contextPath.resolve("Dockerfile"), contextPath.toString()); } buildXLine.add("--load"); diff --git a/src/test/java/io/fabric8/maven/docker/MojoTestBase.java b/src/test/java/io/fabric8/maven/docker/MojoTestBase.java index 3855b55ee..19887c79c 100644 --- a/src/test/java/io/fabric8/maven/docker/MojoTestBase.java +++ b/src/test/java/io/fabric8/maven/docker/MojoTestBase.java @@ -17,6 +17,7 @@ import io.fabric8.maven.docker.util.AnsiLogger; import io.fabric8.maven.docker.util.AuthConfigFactory; import io.fabric8.maven.docker.util.GavLabel; +import java.util.function.Consumer; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Build; import org.apache.maven.monitor.logging.DefaultLog; @@ -113,18 +114,25 @@ protected ImageConfiguration singleImageWithBuild() { } ImageConfiguration singleImageConfiguration(BuildXConfiguration buildx, String contextDir) { - BuildImageConfiguration buildImageConfiguration = new BuildImageConfiguration.Builder() - .from("scratch") - .buildx(buildx) - .args(Collections.singletonMap("foo", "bar")) - .contextDir(contextDir) - .build(); + return singleImageConfiguration(builder -> { + builder.buildx(buildx); + builder.contextDir(contextDir); + }); + } + + ImageConfiguration singleImageConfiguration( + Consumer buildImageConfigurationConsumer) { + BuildImageConfiguration.Builder builder = new BuildImageConfiguration.Builder() + .from("scratch") + .args(Collections.singletonMap("foo", "bar")); + buildImageConfigurationConsumer.accept(builder); + BuildImageConfiguration buildImageConfiguration = builder.build(); buildImageConfiguration.initAndValidate(log); return new Builder() - .name("example:latest") - .buildConfig(buildImageConfiguration) - .build(); + .name("example:latest") + .buildConfig(buildImageConfiguration) + .build(); } ImageConfiguration singleImageConfigurationWithBuildWithSquash(BuildXConfiguration buildx, String contextDir) { diff --git a/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java b/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java index d3ab43ef0..129bb6787 100644 --- a/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java @@ -1,8 +1,10 @@ package io.fabric8.maven.docker.service; +import io.fabric8.maven.docker.util.ImageName; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.io.File; @@ -261,6 +263,40 @@ void useBuilder_whenDockerBuildXIncompatibleWithConfigOverride_thenCopyBuildXBin } } + void testBuildWithTag(boolean skipTag) throws Exception { + List tags = new ArrayList<>(); + tags.add("tag-" + System.currentTimeMillis()); + tags.add("tag-" + System.currentTimeMillis()); + + //Given + buildConfigUsingBuildx(temporaryFolder, (buildX, buildImage) -> { + buildImage.skipTag(skipTag); + buildImage.tags(tags); + }); + + // When + buildx.build(projectPaths, imageConfig, configuredRegistry, authConfigList, buildArchive); + + String[] fullTags = tags.stream() + .map(tag -> new ImageName(imageConfig.getName(), tag).getFullName(configuredRegistry)) + .toArray(String[]::new); + if (skipTag) { + verifyBuildXArgumentNotPresentInExec(fullTags); + } else { + verifyBuildXArgumentPresentInExec(fullTags); + } + } + + @Test + void testBuildWithSkipTag() throws Exception { + testBuildWithTag(true); + } + + @Test + void testBuildWithTag() throws Exception { + testBuildWithTag(false); + } + private void givenAnImageConfiguration(String... platforms) { final BuildXConfiguration buildxConfig = new BuildXConfiguration.Builder() .platforms(Arrays.asList(platforms))