Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support skipping tags #1787

Merged
merged 7 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/io/fabric8/maven/docker/BuildMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private void proceedWithDockerBuild(ServiceHub hub, BuildService.BuildContext bu
hub.getBuildXService().build(createProjectPaths(), imageConfig, null, createCompleteAuthConfigList(false, imageConfig, getRegistryConfig(pullRegistry), createMojoParameters()), buildArchiveFile);
} else {
buildService.buildImage(imageConfig, pullManager, buildContext, buildArchiveFile);
if (!skipTag) {
if (!skipTag && !imageConfig.getBuildConfiguration().skipTag()) {
buildService.tagImage(imageConfig);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/io/fabric8/maven/docker/TagMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public void executeInternal(ServiceHub hub) throws DockerAccessException, MojoEx
List<ImageConfiguration> imageConfigs = getResolvedImages();
for (ImageConfiguration imageConfig : imageConfigs) {
BuildImageConfiguration buildConfig = imageConfig.getBuildConfiguration();
if (buildConfig.skipTag() || buildConfig.isBuildX()) {
// Tag happens at the building stage.
continue;
}

hub.getBuildService().tagImage(imageConfig.getName(), tagName, repo, buildConfig.cleanupMode());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ public class BuildImageConfiguration implements Serializable {
@Parameter
private Boolean skipPush;

@Parameter
private Boolean skipTag;
nodece marked this conversation as resolved.
Show resolved Hide resolved

@Parameter
private ArchiveCompression compression = ArchiveCompression.none;

Expand Down Expand Up @@ -411,6 +414,10 @@ public boolean skipPush() {
return skipPush != null ? skipPush : false;
}

public boolean skipTag() {
return skipTag != null && skipTag;
}

public boolean useDefaultExcludes() {

return useDefaultExcludes != null ? useDefaultExcludes : true;
Expand Down Expand Up @@ -733,6 +740,11 @@ public Builder skipPush(Boolean skipPush) {
return this;
}

public Builder skipTag(Boolean skipTag) {
config.skipTag = skipTag;
return this;
}

public Builder buildOptions(Map<String,String> buildOptions) {
config.buildOptions = buildOptions;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public enum ConfigKey {
SHMSIZE,
SKIP_BUILD("skip.build"),
SKIP_PUSH,
SKIP_TAG("skip.tag"),
SKIP_RUN("skip.run"),
STOP_NAME_PATTERN,
COPY_NAME_PATTERN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ private BuildImageConfiguration extractBuildConfiguration(ImageConfiguration fro
.workdir(valueProvider.getString(WORKDIR, config.getWorkdir()))
.skip(valueProvider.getBoolean(SKIP_BUILD, config.getSkip()))
.skipPush(valueProvider.getBoolean(SKIP_PUSH, config.getSkipPush()))
.skipTag(valueProvider.getBoolean(SKIP_TAG, config.skipTag()))
.imagePullPolicy(valueProvider.getString(IMAGE_PULL_POLICY_BUILD, config.getImagePullPolicy()))
.contextDir(valueProvider.getString(CONTEXT_DIR, config.getContextDirRaw()))
.dockerArchive(valueProvider.getString(DOCKER_ARCHIVE, config.getDockerArchiveRaw()))
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/io/fabric8/maven/docker/service/BuildXService.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,12 @@ protected void buildX(List<String> buildX, String builderName, BuildDirs buildDi
append(cmdLine, "build", "--progress=plain", "--builder", builderName, "--platform",
String.join(",", platforms), "--tag",
new ImageName(imageConfig.getName()).getFullName(configuredRegistry));
buildConfiguration.getTags().forEach(t -> {
cmdLine.add("--tag");
cmdLine.add(new ImageName(imageConfig.getName(), t).getFullName(configuredRegistry));
});
if (!buildConfiguration.skipTag()) {
buildConfiguration.getTags().forEach(t -> {
cmdLine.add("--tag");
cmdLine.add(new ImageName(imageConfig.getName(), t).getFullName(configuredRegistry));
});
}
nodece marked this conversation as resolved.
Show resolved Hide resolved

Map<String, String> args = buildConfiguration.getArgs();
if (args != null) {
Expand Down
101 changes: 94 additions & 7 deletions src/test/java/io/fabric8/maven/docker/BuildMojoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -241,6 +244,75 @@ void buildUsingBuildxWithMultipleAuth() throws IOException, MojoExecutionExcepti
thenAuthContainsRegistry("custom-registry.org");
}

void buildUsingBuildxWithTag(boolean skipTag) throws IOException, MojoExecutionException {
givenBuildXService();

List<String> 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<String> 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<String> 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);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to somehow use @Nested annotation to group normal build and buildX tests? Initially, I was a bit confused by the test names. Can we use JUnit5 parameterized tests here to reduce duplication?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


private void givenBuildXService() {
BuildXService buildXService = new BuildXService(dockerAccess, dockerAssemblyManager, log, exec);

Expand Down Expand Up @@ -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<String> 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<String> 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<String> buildXLine = BuildXService.append(new ArrayList<>(), "docker", "--config", config, "buildx",
List<String> 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);
Expand All @@ -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");
Expand Down
26 changes: 17 additions & 9 deletions src/test/java/io/fabric8/maven/docker/MojoTestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<BuildImageConfiguration.Builder> 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) {
Expand Down
60 changes: 60 additions & 0 deletions src/test/java/io/fabric8/maven/docker/TagMojoTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.fabric8.maven.docker;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import io.fabric8.maven.docker.config.BuildXConfiguration;
import io.fabric8.maven.docker.config.ImageConfiguration;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.maven.plugin.MojoExecutionException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class TagMojoTest extends MojoTestBase {

private static final String NON_NATIVE_PLATFORM = "linux/amd64";
private static final String NATIVE_PLATFORM = "linux/arm64";

@InjectMocks
private TagMojo tagMojo;

void tag(boolean skipTag, boolean buildx) throws IOException, MojoExecutionException {
givenMavenProject(tagMojo);

ImageConfiguration imageConfiguration = singleImageConfiguration(builder -> {
builder.skipTag(skipTag);
if (buildx) {
ArrayList<String> platforms = new ArrayList<>();
platforms.add(NON_NATIVE_PLATFORM);
platforms.add(NATIVE_PLATFORM);
BuildXConfiguration buildXConfiguration = new BuildXConfiguration.Builder().platforms(platforms).build();
builder.buildx(buildXConfiguration);
}
});
givenResolvedImages(tagMojo, Collections.singletonList(imageConfiguration));

tagMojo.executeInternal(serviceHub);

verify(buildService, times(skipTag || buildx ? 0 : 1)).tagImage(any(), any(), any(), any());
}

@Test
void skipTag() throws IOException, MojoExecutionException {
tag(true, false);
}

@Test
void tag() throws IOException, MojoExecutionException {
tag(false, false);
}

@Test
void tagWhenUsingBuildx() throws IOException, MojoExecutionException {
tag(false, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,13 @@ void multipleAssembliesUniqueNames() {
assemblies(Arrays.asList(assemblyConfigurationOne, assemblyConfigurationTwo)).build();
Assertions.assertThrows(IllegalArgumentException.class, () -> config.initAndValidate(logger));
}

@Test
void skipTag() {
BuildImageConfiguration config =
new BuildImageConfiguration.Builder().skipTag(true)
.build();
config.initAndValidate(logger);
Assertions.assertTrue(config.skipTag());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ void testSkipPush() {
Assertions.assertFalse(resolveExternalImageConfig(new String[] { k(ConfigKey.NAME), "image", k(ConfigKey.FROM), "busybox" }).getBuildConfiguration().skipPush());
}

@Test
void testSkipTag() {
Assertions.assertFalse(
resolveExternalImageConfig(getSkipTestData(ConfigKey.SKIP_TAG, false)).getBuildConfiguration()
.skipTag());
Assertions.assertTrue(
resolveExternalImageConfig(getSkipTestData(ConfigKey.SKIP_TAG, true)).getBuildConfiguration()
.skipTag());

Assertions.assertFalse(resolveExternalImageConfig(
new String[]{k(ConfigKey.NAME), "image", k(ConfigKey.FROM), "busybox"}).getBuildConfiguration()
.skipTag());
}

@Test
void testSkipRun() {
Assertions.assertFalse(resolveExternalImageConfig(getSkipTestData(ConfigKey.SKIP_RUN, false)).getRunConfiguration().skip());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,14 @@ void testGetMap() {
Assertions.assertEquals("notignored1", m.get("ckey"));
}

@Test
void testSkipTag() {
configure(PropertyMode.Override);
Assertions.assertNull(provider.getBoolean(ConfigKey.SKIP_TAG, null));

props.put("docker.skip.tag", "true");
Assertions.assertTrue(provider.getBoolean(ConfigKey.SKIP_TAG, null));
props.put("docker.skip.tag", "false");
Assertions.assertFalse(provider.getBoolean(ConfigKey.SKIP_TAG, null));
}
}
Loading
Loading