diff --git a/src/main/java/io/fabric8/maven/docker/service/BuildXService.java b/src/main/java/io/fabric8/maven/docker/service/BuildXService.java index 71c0e4e25..ba43ac0c5 100644 --- a/src/main/java/io/fabric8/maven/docker/service/BuildXService.java +++ b/src/main/java/io/fabric8/maven/docker/service/BuildXService.java @@ -14,7 +14,6 @@ import io.fabric8.maven.docker.util.ImageName; import io.fabric8.maven.docker.util.Logger; import io.fabric8.maven.docker.util.ProjectPaths; -import org.apache.commons.lang3.StringUtils; import org.apache.maven.plugin.MojoExecutionException; import java.io.BufferedReader; @@ -27,6 +26,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; @@ -36,10 +36,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; -import static io.fabric8.maven.docker.util.AuthConfigFactory.hasAuthForRegistryInDockerConfig; - public class BuildXService { - private static final int DOCKER_CLI_BUILDX_CONFIG_COMPATIBLE_MAJOR_VERSION = 23; private static final String DOCKER = "docker"; private final DockerAccess dockerAccess; private final DockerAssemblyManager dockerAssemblyManager; @@ -71,13 +68,12 @@ protected void useBuilder(ProjectPaths projectPaths, ImageConfiguration imag BuildDirs buildDirs = new BuildDirs(projectPaths, imageConfig.getName()); Path configPath = getDockerStateDir(imageConfig.getBuildConfiguration(), buildDirs); - List buildX = new ArrayList<>(); - buildX.add(DOCKER); - if (isDockerCLINotLegacy() || shouldAddConfigInLegacyDockerCLI(authConfig, configuredRegistry)) { - buildX.add("--config"); - buildX.add(configPath.toString()); + List buildX = new ArrayList<>(Arrays.asList(DOCKER, "--config", configPath.toString(), "buildx")); + if (!isDockerBuildXWorkingWithOverriddenConfig(configPath)) { + logger.debug("Detected current version of BuildX not working with --config override"); + logger.debug("Copying BuildX binary to " + configPath); + copyBuildXToConfigPathIfBuildXBinaryInDefaultDockerConfig(configPath); } - buildX.add("buildx"); String builderName = createBuilder(configPath, buildX, imageConfig, buildDirs); Path configJson = configPath.resolve("config.json"); @@ -89,29 +85,16 @@ protected void useBuilder(ProjectPaths projectPaths, ImageConfiguration imag } } - private boolean shouldAddConfigInLegacyDockerCLI(AuthConfigList authConfigList, String configuredRegistry) throws MojoExecutionException { - return authConfigList != null && !authConfigList.isEmpty() && - !hasAuthForRegistryInDockerConfig(logger, configuredRegistry, authConfigList); - } - - private boolean isDockerCLINotLegacy() { - DockerVersionExternalCommand dockerVersionExternalCommand = new DockerVersionExternalCommand(logger); + private void copyBuildXToConfigPathIfBuildXBinaryInDefaultDockerConfig(Path configPath) { try { - dockerVersionExternalCommand.execute(); - } catch (IOException e) { - logger.info("Failure in getting docker CLI version", e); - } - String version = dockerVersionExternalCommand.getVersion(); - if (StringUtils.isNotBlank(version)) { - version = version.replaceAll("(^')|('$)", ""); - String[] versionParts = version.split("\\."); - logger.info("Using Docker CLI " + version); - if (versionParts.length >= 3) { - int cliMajorVersion = Integer.parseInt(versionParts[0]); - return cliMajorVersion >= DOCKER_CLI_BUILDX_CONFIG_COMPATIBLE_MAJOR_VERSION; + File buildXInUserHomeDockerConfig = Paths.get(EnvUtil.getUserHome(), ".docker/cli-plugins/docker-buildx").toFile(); + Files.createDirectory(configPath.resolve("cli-plugins")); + if (buildXInUserHomeDockerConfig.exists() && buildXInUserHomeDockerConfig.isFile()) { + Files.copy(buildXInUserHomeDockerConfig.toPath(), configPath.resolve("cli-plugins").resolve("docker-buildx"), StandardCopyOption.COPY_ATTRIBUTES); } + } catch (IOException exception) { + logger.debug(exception.getMessage()); } - return false; } protected void createConfigJson(Path configJson, AuthConfigList authConfig) throws MojoExecutionException { @@ -335,27 +318,30 @@ private void pumpStream(InputStream is) { } } - public static class DockerVersionExternalCommand extends ExternalCommand { - private final StringBuilder outputBuilder; - public DockerVersionExternalCommand(Logger logger) { - super(logger); - outputBuilder = new StringBuilder(); + private boolean isDockerBuildXWorkingWithOverriddenConfig(Path configPath) { + BuildXListWithConfigCommand buildXList = new BuildXListWithConfigCommand(logger, configPath); + try { + buildXList.execute(); + return buildXList.isSuccessFul(); + } catch (IOException e) { + return false; } + } - @Override - protected String[] getArgs() { - return new String[] {DOCKER, "version", "--format", "'{{.Client.Version}}'"}; + static class BuildXListWithConfigCommand extends ExternalCommand { + private final Path configPath; + public BuildXListWithConfigCommand(Logger logger, Path configPath) { + super(logger); + this.configPath = configPath; } @Override - protected void processLine(String line) { - if (StringUtils.isNotBlank(line)) { - outputBuilder.append(line); - } + protected String[] getArgs() { + return new String[] { DOCKER, "--config", configPath.toString(), "buildx", "ls"}; } - public String getVersion() { - return outputBuilder.toString(); + public boolean isSuccessFul() { + return getStatusCode() == 0; } } } diff --git a/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java b/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java index 42ec5e37a..5bf1b0602 100644 --- a/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java +++ b/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java @@ -3,7 +3,6 @@ import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java b/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java index 6c6b7a70b..4d3bcb611 100644 --- a/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java +++ b/src/test/java/io/fabric8/maven/docker/BuildMojoTest.java @@ -12,16 +12,13 @@ import io.fabric8.maven.docker.service.BuildXService; import io.fabric8.maven.docker.service.ImagePullManager; import org.apache.maven.plugin.MojoExecutionException; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockedConstruction; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -54,22 +51,11 @@ class BuildMojoTest extends MojoTestBase { @Mock private BuildXService.Exec exec; - private MockedConstruction dockerVersionExternalCommandMockedConstruction; private static String getOsDependentBuild(Path buildPath, String docker) { return buildPath.resolve(docker).toString().replace('/', File.separatorChar); } - @BeforeEach - void setUp() { - dockerVersionExternalCommandMockedConstruction = Mockito.mockConstruction(BuildXService.DockerVersionExternalCommand.class); - } - - @AfterEach - void tearDown() { - dockerVersionExternalCommandMockedConstruction.close(); - } - @Test void skipWhenPom() throws IOException, MojoExecutionException { @@ -305,10 +291,11 @@ private void verifyBuild(int wantedNumberOfInvocations) throws DockerAccessExcep private void thenBuildxRun(String relativeConfigFile, String contextDir, boolean nativePlatformIncluded, String attestation) 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; List cmds = - BuildXService.append(new ArrayList<>(), "docker", "buildx", + 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)); @@ -316,7 +303,7 @@ private void thenBuildxRun(String relativeConfigFile, String contextDir, Mockito.verify(exec).process(cmds); if (nativePlatformIncluded) { - List buildXLine = BuildXService.append(new ArrayList<>(), "docker", "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"); diff --git a/src/test/java/io/fabric8/maven/docker/PushMojoBuildXTest.java b/src/test/java/io/fabric8/maven/docker/PushMojoBuildXTest.java index fa80d772d..3e79ca19a 100644 --- a/src/test/java/io/fabric8/maven/docker/PushMojoBuildXTest.java +++ b/src/test/java/io/fabric8/maven/docker/PushMojoBuildXTest.java @@ -1,6 +1,5 @@ package io.fabric8.maven.docker; -import io.fabric8.maven.docker.access.AuthConfig; import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.config.BuildImageConfiguration; import io.fabric8.maven.docker.config.BuildXConfiguration; @@ -10,7 +9,6 @@ import io.fabric8.maven.docker.service.DockerAccessFactory; import io.fabric8.maven.docker.service.ServiceHubFactory; import io.fabric8.maven.docker.util.AuthConfigFactory; -import io.fabric8.maven.docker.util.DockerFileUtil; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; @@ -23,10 +21,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.MockedConstruction; -import org.mockito.MockedStatic; import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException; @@ -46,7 +41,6 @@ import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockConstruction; -import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -59,8 +53,6 @@ class PushMojoBuildXTest { private File expectedDockerStateConfigDir; private Settings mockedMavenSettings; private MockedConstruction defaultExecMockedConstruction; - private MockedConstruction dockerVersionExternalCommandMockedConstruction; - private String dockerClIVersion; @BeforeEach void setup() throws MojoExecutionException, MojoFailureException, IOException, ComponentLookupException, SecDispatcherException { @@ -88,9 +80,6 @@ void setup() throws MojoExecutionException, MojoFailureException, IOException, C when(mockedSecDispatcher.decrypt(anyString())).thenReturn("testpassword"); Map pluginContext = new HashMap<>(); defaultExecMockedConstruction = mockConstruction(BuildXService.DefaultExec.class); - dockerVersionExternalCommandMockedConstruction = mockConstruction(BuildXService.DockerVersionExternalCommand.class, (mock, ctx) -> { - when(mock.getVersion()).thenReturn(dockerClIVersion); - }); this.pushMojo = new PushMojo(); this.pushMojo.setPluginContext(pluginContext); pushMojo.verbose = "true"; @@ -107,78 +96,12 @@ void setup() throws MojoExecutionException, MojoFailureException, IOException, C @AfterEach void tearDown() { defaultExecMockedConstruction.close(); - dockerVersionExternalCommandMockedConstruction.close(); } @Test - @DisplayName("legacy docker CLI, docker:push buildx, no auth, then don't add --config option to buildx") - void execute_whenNoAuthConfig_thenRunBuildXCommandWithNoConfig() throws MojoExecutionException, MojoFailureException { + @DisplayName("docker:push buildx, auth from ~/.m2/settings.xml, then add --config option to buildx") + void execute_whenAuthConfigFromMavenSettings_thenAddConfigToDockerBuildXCommand() throws MojoExecutionException, MojoFailureException { // Given - givenDockerCLIVersion("20.0.14"); - - // When - pushMojo.execute(); - - // Then - verifyNoDockerConfigAddedToBuildX(); - } - - @Test - @DisplayName("docker CLI 23.0.6, docker:push buildx, no auth, then add --config option to buildx") - void execute_whenNoAuthConfigAndDockerCLIPost23_thenRunBuildXCommandWithAddedConfig() throws MojoExecutionException, MojoFailureException { - // Given - givenDockerCLIVersion("23.0.6+azure-2"); - - // When - pushMojo.execute(); - - // Then - verifyDockerConfigOptionAddedToBuildX(); - } - - @Test - @DisplayName("legacy docker CLI, docker:push buildx, auth from ~/.docker/config.json, then don't add --config option to buildx") - void execute_whenLegacyDockerCLIAndAuthConfigFromLocalDockerConfig_thenDoNotAddConfigToDockerBuildXCommand() throws MojoExecutionException, MojoFailureException { - try (MockedStatic dockerFileUtilMockedStatic = mockStatic(DockerFileUtil.class)) { - // Given - givenDockerCLIVersion("20.0.14"); - AuthConfig authConfig = new AuthConfig("testuser", "testpassword", null, null, null); - authConfig.setRegistry("test.example.org"); - dockerFileUtilMockedStatic.when(DockerFileUtil::readDockerConfig) - .thenReturn(authConfig.toJsonObject()); - - // When - pushMojo.execute(); - - // Then - verifyNoDockerConfigAddedToBuildX(); - } - } - - @Test - @DisplayName("23.0.6+azure-2 docker CLI, docker:push buildx, auth from ~/.docker/config.json, then don't add --config option to buildx") - void execute_whenAuthConfigFromLocalDockerConfig_thenAddConfigToDockerBuildXCommand() throws MojoExecutionException, MojoFailureException { - try (MockedStatic dockerFileUtilMockedStatic = mockStatic(DockerFileUtil.class)) { - // Given - givenDockerCLIVersion("'23.0.6+azure-2'"); - AuthConfig authConfig = new AuthConfig("testuser", "testpassword", null, null, null); - authConfig.setRegistry("test.example.org"); - dockerFileUtilMockedStatic.when(DockerFileUtil::readDockerConfig) - .thenReturn(authConfig.toJsonObject()); - - // When - pushMojo.execute(); - - // Then - verifyDockerConfigOptionAddedToBuildX(); - } - } - - @ParameterizedTest(name = "docker CLI {0} docker:push buildx, auth from ~/.m2/settings.xml, then add --config option to buildx") - @ValueSource(strings = {"20.0.14", "'23.0.6+azure-2'"}) - void execute_whenAuthConfigFromMavenSettings_thenAddConfigToDockerBuildXCommand(String dockerClIVersion) throws MojoExecutionException, MojoFailureException { - // Given - givenDockerCLIVersion(dockerClIVersion); Server server = new Server(); server.setId("test.example.org"); server.setUsername("testuser"); @@ -192,12 +115,11 @@ void execute_whenAuthConfigFromMavenSettings_thenAddConfigToDockerBuildXCommand( verifyDockerConfigOptionAddedToBuildX(); } - @ParameterizedTest(name = "docker CLI {0} docker:push buildx, auth from properties, then add --config option to buildx") - @ValueSource(strings = {"20.0.14", "'23.0.6+azure-2'"}) - void execute_whenAuthConfigFromProperties_thenAddConfigOptionToBuildXCommand(String dockerClIVersion) throws MojoExecutionException, MojoFailureException { + @Test + @DisplayName("docker:push buildx, auth from properties, then add --config option to buildx") + void execute_whenAuthConfigFromProperties_thenAddConfigOptionToBuildXCommand() throws MojoExecutionException, MojoFailureException { try { // Given - givenDockerCLIVersion(dockerClIVersion); System.setProperty("docker.push.username", "testuser"); System.setProperty("docker.push.password", "testpassword"); @@ -247,8 +169,4 @@ private ImageConfiguration createImageConfiguration() { .build()) .build(); } - - private void givenDockerCLIVersion(String version) { - dockerClIVersion = version; - } } diff --git a/src/test/java/io/fabric8/maven/docker/service/BuildXListWithConfigCommandTest.java b/src/test/java/io/fabric8/maven/docker/service/BuildXListWithConfigCommandTest.java new file mode 100644 index 000000000..24f5e5fe1 --- /dev/null +++ b/src/test/java/io/fabric8/maven/docker/service/BuildXListWithConfigCommandTest.java @@ -0,0 +1,36 @@ +package io.fabric8.maven.docker.service; + +import io.fabric8.maven.docker.util.Logger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class BuildXListWithConfigCommandTest { + @TempDir + private File temporaryFolder; + + private BuildXService.BuildXListWithConfigCommand buildXListWithConfigCommand; + + @BeforeEach + void setUp() { + Logger logger = mock(Logger.class); + buildXListWithConfigCommand = new BuildXService.BuildXListWithConfigCommand(logger, temporaryFolder.toPath()); + } + + @Test + void getArgs() { + assertArrayEquals(new String[] {"docker", "--config", temporaryFolder.getAbsolutePath(), "buildx", "ls"}, buildXListWithConfigCommand.getArgs()); + } + + @Test + void isSuccessFul() { + // Given + assertTrue(buildXListWithConfigCommand.isSuccessFul()); + } +} \ No newline at end of file diff --git a/src/test/java/io/fabric8/maven/docker/service/BuildXServiceDockerVersionExternalCommandTest.java b/src/test/java/io/fabric8/maven/docker/service/BuildXServiceDockerVersionExternalCommandTest.java deleted file mode 100644 index 609b54c45..000000000 --- a/src/test/java/io/fabric8/maven/docker/service/BuildXServiceDockerVersionExternalCommandTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.fabric8.maven.docker.service; - -import io.fabric8.maven.docker.util.Logger; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; - -class BuildXServiceDockerVersionExternalCommandTest { - private BuildXService.DockerVersionExternalCommand dockerVersionExternalCommand; - - @BeforeEach - void setUp() { - Logger logger = mock(Logger.class); - dockerVersionExternalCommand = new BuildXService.DockerVersionExternalCommand(logger); - } - - @Test - void getArgs() { - assertArrayEquals(new String[] {"docker", "version", "--format", "'{{.Client.Version}}'"}, dockerVersionExternalCommand.getArgs()); - } - - @Test - void getVersion() { - // Given - dockerVersionExternalCommand.processLine("'24.0.6+azure-2'"); - // When - String version = dockerVersionExternalCommand.getVersion(); - // Then - assertEquals("'24.0.6+azure-2'", version); - } -} 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 fdb9d9445..d3ab43ef0 100644 --- a/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java @@ -1,14 +1,17 @@ package io.fabric8.maven.docker.service; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.List; import java.io.File; import java.nio.file.Paths; import io.fabric8.maven.docker.access.AuthConfig; -import io.fabric8.maven.docker.util.DockerFileUtil; import java.util.function.BiConsumer; + +import io.fabric8.maven.docker.util.EnvUtil; import org.apache.maven.plugin.MojoExecutionException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -43,6 +46,8 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.WARN) @@ -68,31 +73,32 @@ class BuildXServiceTest { @Spy private BuildXService buildx; + @TempDir + private File temporaryFolder; + private ImageConfiguration imageConfig; - private final ProjectPaths projectPaths = new ProjectPaths(new File("project-base-dir"), "output-dir"); + private ProjectPaths projectPaths; private final String configuredRegistry = "configured-registry"; private final File buildArchive = new File("build-archive"); private AuthConfigList authConfigList; - private MockedConstruction dockerVersionExternalCommandMockedConstruction; @BeforeEach void setup() throws Exception { - Mockito.when(dockerAccess.getNativePlatform()).thenReturn(NATIVE); + when(dockerAccess.getNativePlatform()).thenReturn(NATIVE); Mockito.doNothing().when(buildx).createConfigJson(Mockito.any(), Mockito.any()); Mockito.doNothing().when(buildx).removeConfigJson(Mockito.any()); - Mockito.doReturn(Paths.get("docker-state-dir")).when(buildx).getDockerStateDir(Mockito.any(), Mockito.any()); + Mockito.doReturn(Paths.get(temporaryFolder.getPath(), "docker-state-dir")).when(buildx).getDockerStateDir(Mockito.any(), Mockito.any()); Mockito.doReturn("maven").when(buildx).createBuilder(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()); authConfigList = null; - dockerVersionExternalCommandMockedConstruction = mockConstruction(BuildXService.DockerVersionExternalCommand.class); + projectPaths = new ProjectPaths(new File(temporaryFolder, "project-base-dir"), "output-dir"); } @AfterEach void tearDown() { - dockerVersionExternalCommandMockedConstruction.close(); } @Test @@ -120,7 +126,7 @@ void testBuildNativePlatformWithForeign() throws Exception { } @Test - void testNoCacheIsPropagatedToBuildx(@TempDir File temporaryFolder) throws Exception { + void testNoCacheIsPropagatedToBuildx() throws Exception { //Given buildConfigUsingBuildx(temporaryFolder, (buildX, buildImage) -> buildImage.noCache(true)); @@ -133,7 +139,7 @@ void testNoCacheIsPropagatedToBuildx(@TempDir File temporaryFolder) throws Excep } @Test - void testBuildXCacheFromIsNotPresentIfNotProvided(@TempDir File temporaryFolder) throws Exception { + void testBuildXCacheFromIsNotPresentIfNotProvided() throws Exception { //Given buildConfigUsingBuildx(temporaryFolder, (buildX, buildImage) -> buildX.cacheFrom(null)); @@ -159,7 +165,7 @@ void testBuildXCacheFromIsPresentIfProvided(@TempDir File temporaryFolder) throw } @Test - void testBuildXCacheToIsNotPresentIfNotProvided(@TempDir File temporaryFolder) throws Exception { + void testBuildXCacheToIsNotPresentIfNotProvided() throws Exception { //Given buildConfigUsingBuildx(temporaryFolder, (buildX, buildImage) -> buildX.cacheTo(null)); @@ -172,7 +178,7 @@ void testBuildXCacheToIsNotPresentIfNotProvided(@TempDir File temporaryFolder) t } @Test - void testBuildXCacheToIsPresentIfProvided(@TempDir File temporaryFolder) throws Exception { + void testBuildXCacheToIsPresentIfProvided() throws Exception { //Given buildConfigUsingBuildx(temporaryFolder, (buildX, buildImage) -> buildX.cacheTo("cacheToSpec")); @@ -209,7 +215,7 @@ void testBuildForeignPlatforms() throws Exception { } @Test - void useBuilder_whenConfiguredRegistryAbsentInDockerRegistry_thenAddConfigOptionToBuildX(@TempDir File temporaryFolder) throws MojoExecutionException, IOException { + void useBuilder_whenConfiguredRegistryAbsentInDockerRegistry_thenAddConfigOptionToBuildX() throws MojoExecutionException, IOException { // Given BuildXService.Builder builder = Mockito.mock(BuildXService.Builder.class); Mockito.doReturn(temporaryFolder.toPath()).when(buildx).getDockerStateDir(Mockito.any(), Mockito.any()); @@ -229,26 +235,29 @@ void useBuilder_whenConfiguredRegistryAbsentInDockerRegistry_thenAddConfigOption } @Test - void useBuilder_whenAuthConfigFromDockerConfig_thenDoNotAddConfigOptionToBuildX() throws MojoExecutionException { - try (MockedStatic dockerFileUtilMockedStatic = mockStatic(DockerFileUtil.class)) { + void useBuilder_whenDockerBuildXIncompatibleWithConfigOverride_thenCopyBuildXBinaryToTemporaryConfig() throws IOException, MojoExecutionException { + try (MockedStatic envUtilMockedStatic = mockStatic(EnvUtil.class); + MockedConstruction ignore = mockConstruction(BuildXService.BuildXListWithConfigCommand.class, (mock, ctx) -> { + when(mock.isSuccessFul()).thenReturn(false); + })) { // Given - AuthConfig registryAuthConfig = new AuthConfig("user", "password", null, null); - registryAuthConfig.setRegistry(configuredRegistry); - authConfigList = new AuthConfigList(registryAuthConfig); - dockerFileUtilMockedStatic.when(DockerFileUtil::readDockerConfig) - .thenReturn(registryAuthConfig.toJsonObject()); + Path configDirPath = temporaryFolder.toPath().resolve("docker-state-dir"); + Files.createDirectory(configDirPath); + Files.createDirectory(temporaryFolder.toPath().resolve(".docker")); + Files.createDirectory(temporaryFolder.toPath().resolve(".docker").resolve("cli-plugins")); + Files.createFile(temporaryFolder.toPath().resolve(".docker").resolve("cli-plugins").resolve("docker-buildx")); + envUtilMockedStatic.when(EnvUtil::getUserHome).thenReturn(temporaryFolder.getAbsolutePath()); BuildXService.Builder builder = Mockito.mock(BuildXService.Builder.class); - givenAnImageConfiguration(new BuildXConfiguration.Builder() - .platforms(Arrays.asList(FOREIGN1, FOREIGN2)) - .build()); + givenAnImageConfiguration("linux/arm46", "linux/amd64"); // When buildx.useBuilder(projectPaths, imageConfig, configuredRegistry, authConfigList, buildArchive, builder); // Then - ArgumentCaptor> buildXArgCaptor = ArgumentCaptor.forClass(List.class); - Mockito.verify(builder).useBuilder(buildXArgCaptor.capture(), anyString(), any(), eq(imageConfig), eq(configuredRegistry), eq(buildArchive)); - assertEquals(Arrays.asList("docker", "buildx"), buildXArgCaptor.getValue()); + assertTrue(configDirPath.resolve("cli-plugins").toFile().exists()); + assertTrue(configDirPath.resolve("cli-plugins").resolve("docker-buildx").toFile().exists()); + verify(logger).debug("Detected current version of BuildX not working with --config override"); + verify(logger).debug("Copying BuildX binary to " + temporaryFolder.toPath().resolve("docker-state-dir")); } } diff --git a/src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java b/src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java index ebddf0b59..d542dfa17 100644 --- a/src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java @@ -16,7 +16,6 @@ import io.fabric8.maven.docker.util.Logger; import io.fabric8.maven.docker.util.ProjectPaths; import org.apache.maven.plugin.MojoExecutionException; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,7 +25,6 @@ import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -41,8 +39,6 @@ import java.util.Map; import java.util.Objects; -import static org.mockito.Mockito.mockConstruction; -import static org.mockito.Mockito.mockStatic; /** * @author roland @@ -64,7 +60,6 @@ class RegistryServiceTest { private boolean hasImage; private Map authConfig; private MockedStatic dockerFileUtilMockedStatic; - private MockedConstruction dockerVersionExternalCommandMockedConstruction; @TempDir private File projectBaseDir; @@ -104,14 +99,6 @@ void setup() { hasImage = false; registry = null; imageConfiguration = null; - dockerFileUtilMockedStatic = mockStatic(DockerFileUtil.class); - dockerVersionExternalCommandMockedConstruction = mockConstruction(BuildXService.DockerVersionExternalCommand.class); - } - - @AfterEach - void tearDown() { - dockerFileUtilMockedStatic.close(); - dockerVersionExternalCommandMockedConstruction.close(); } @ParameterizedTest @@ -326,7 +313,6 @@ void pushBuildXImage() throws MojoExecutionException { givenBuildxImageConfiguration("user/test:1.0.1", null, null, null); givenCredentials("skroob", "12345"); givenRegistry(registry); - givenRegistryCredentialsPresentInLocalDockerConfig(); whenPushImage(); @@ -340,7 +326,6 @@ void pushBuildXImageWithDockerfile() throws MojoExecutionException { givenBuildxImageConfiguration("user/test:1.0.1", null, dockerFile, null); givenCredentials("skroob", "12345"); givenRegistry(registry); - givenRegistryCredentialsPresentInLocalDockerConfig(); whenPushImage(); @@ -353,7 +338,6 @@ void pushBuildXImageProvidedBuilder() throws MojoExecutionException { givenBuildxImageConfiguration("user/test:1.0.1", "provided-builder", null, null); givenCredentials("King_Roland_of_Druidia", "12345"); givenRegistry(registry); - givenRegistryCredentialsPresentInLocalDockerConfig(); whenPushImage(); @@ -366,7 +350,6 @@ void pushBuildXImageTag() throws MojoExecutionException { givenBuildxImageConfiguration("user/test:1.0.1", null, null, "perri-air"); givenCredentials("King_Roland_of_Druidia", "12345"); givenRegistry(registry); - givenRegistryCredentialsPresentInLocalDockerConfig(); whenPushImage(); @@ -380,7 +363,6 @@ void pushBuildXImageWithRegistry() throws MojoExecutionException { givenBuildxImageConfiguration("user/test:1.0.1", null, null, "perri-air"); givenCredentials("King_Roland_of_Druidia", "12345"); givenRegistry(registry); - givenRegistryCredentialsPresentInLocalDockerConfig(); whenPushImage(); @@ -394,7 +376,6 @@ void pushBuildXImageWithImageRegistry() throws MojoExecutionException { givenBuildxImageConfiguration(registry + "/" + "user/test:1.0.1", null, null, "perri-air"); givenCredentials("King_Roland_of_Druidia", "12345"); givenRegistry(registry); - givenRegistryCredentialsPresentInLocalDockerConfig(); whenPushImage(); @@ -409,7 +390,6 @@ void pushBuildXImageWithImageConfigRegistry() throws MojoExecutionException { andImageConfigRegistry(registry); givenCredentials("King_Roland_of_Druidia", "12345"); givenRegistry(registry); - givenRegistryCredentialsPresentInLocalDockerConfig(); whenPushImage(); @@ -467,11 +447,11 @@ private void thenBuildxImageHasBeenPushed(String providedBuilder, String relativ String builderName = providedBuilder != null ? providedBuilder : "maven"; if (providedBuilder == null) { - Mockito.verify(exec).process(Arrays.asList("docker", "buildx", "create", "--driver", "docker-container", "--name", builderName, "--node", builderName+"0")); + Mockito.verify(exec).process(Arrays.asList("docker","--config", config, "buildx", "create", "--driver", "docker-container", "--name", builderName, "--node", builderName+"0")); } List cmds = - BuildXService.append(new ArrayList<>(), "docker", "buildx", "build", + BuildXService.append(new ArrayList<>(), "docker", "--config", config, "buildx", "build", "--progress=plain", "--builder", builderName, "--platform", "linux/amd64,linux/arm64", "--tag", new ImageName(imageConfiguration.getName()).getFullName(registry)); @@ -598,14 +578,6 @@ private void andImageConfigRegistry(String registry) { imageConfiguration.setRegistry(registry); } - private void givenRegistryCredentialsPresentInLocalDockerConfig() { - AuthConfig testAuth = new AuthConfig(authConfig); - testAuth.setRegistry(registry); - - dockerFileUtilMockedStatic.when(DockerFileUtil::readDockerConfig) - .thenReturn(testAuth.toJsonObject()); - } - private void givenCredentials(String username, String password) throws MojoExecutionException { authConfig.put(AuthConfig.AUTH_USERNAME, username); authConfig.put(AuthConfig.AUTH_PASSWORD, password);