diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java index 68135780922d..7464be272bd1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,4 +90,9 @@ public DockerConfiguration withPublishRegistryUserAuthentication(String username new DockerRegistryUserAuthentication(username, password, url, email)); } + public DockerConfiguration withEmptyPublishRegistryAuthentication() { + return new DockerConfiguration(this.host, this.builderAuthentication, + new DockerRegistryUserAuthentication("", "", "", "")); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc index 9e5b64cf7ef8..661b0d412cb4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc @@ -368,7 +368,10 @@ An OCI image containing a https://buildpacks.io/docs/buildpack-author-guide/pack [[build-image.examples.publish]] === Image Publishing -The generated image can be published to a Docker registry by enabling a `publish` option and configuring authentication for the registry using `docker.publishRegistry` properties. +The generated image can be published to a Docker registry by enabling a `publish` option. + +If the Docker registry requires authentication, the credentials can be configured using `docker.publishRegistry` properties. +If the Docker registry does not require authentication, the `docker.publishRegistry` configuration can be omitted. [source,groovy,indent=0,subs="verbatim,attributes",role="primary"] .Groovy diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java index db58d4b0727e..46c9440b9055 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import groovy.lang.Closure; import org.gradle.api.Action; import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; import org.gradle.api.JavaVersion; import org.gradle.api.Project; import org.gradle.api.Task; @@ -605,11 +604,6 @@ private BuildRequest customizePullPolicy(BuildRequest request) { } private BuildRequest customizePublish(BuildRequest request) { - boolean publishRegistryAuthNotConfigured = this.docker == null || this.docker.getPublishRegistry() == null - || this.docker.getPublishRegistry().hasEmptyAuth(); - if (this.publish && publishRegistryAuthNotConfigured) { - throw new GradleException("Publishing an image requires docker.publishRegistry to be configured"); - } request = request.withPublish(this.publish); return request; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerSpec.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerSpec.java index b1a4d133ca76..9308a4c3fe59 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerSpec.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerSpec.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -179,7 +179,7 @@ private DockerConfiguration customizeBuilderAuthentication(DockerConfiguration d private DockerConfiguration customizePublishAuthentication(DockerConfiguration dockerConfiguration) { if (this.publishRegistry == null || this.publishRegistry.hasEmptyAuth()) { - return dockerConfiguration; + return dockerConfiguration.withEmptyPublishRegistryAuthentication(); } if (this.publishRegistry.hasTokenAuth() && !this.publishRegistry.hasUserAuth()) { return dockerConfiguration.withPublishRegistryTokenAuthentication(this.publishRegistry.getToken()); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java index 304f93b0c2d3..c7d309b86b9b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -313,15 +313,6 @@ void failsWithInvalidImageName() throws IOException { .containsPattern("example/Invalid-Image-Name"); } - @TestTemplate - void failsWithPublishMissingPublishRegistry() throws IOException { - writeMainClass(); - writeLongNameResource(); - BuildResult result = this.gradleBuild.buildAndFail("bootBuildImage", "--publishImage"); - assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.FAILED); - assertThat(result.getOutput()).contains("requires docker.publishRegistry"); - } - @TestTemplate void failsWithBuildpackNotInBuilder() throws IOException { writeMainClass(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java index 149219535ed5..f30070bea427 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Map; -import org.gradle.api.GradleException; import org.gradle.api.JavaVersion; import org.gradle.api.Project; import org.junit.jupiter.api.BeforeEach; @@ -36,7 +35,6 @@ import org.springframework.boot.gradle.junit.GradleProjectBuilder; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for {@link BootBuildImage}. @@ -189,13 +187,6 @@ void whenUsingDefaultConfigurationThenRequestHasPublishDisabled() { assertThat(this.buildImage.createRequest().isPublish()).isFalse(); } - @Test - void whenPublishIsEnabledWithoutPublishRegistryThenExceptionIsThrown() { - this.buildImage.setPublish(true); - assertThatExceptionOfType(GradleException.class).isThrownBy(this.buildImage::createRequest) - .withMessageContaining("Publishing an image requires docker.publishRegistry to be configured"); - } - @Test void whenNoBuilderIsConfiguredThenRequestHasDefaultBuilder() { assertThat(this.buildImage.createRequest().getBuilder().getName()).isEqualTo("paketobuildpacks/builder"); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerSpecTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerSpecTests.java index 846bc7d6841c..76c6792552a5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerSpecTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerSpecTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,9 +37,12 @@ class DockerSpecTests { @Test void asDockerConfigurationWithDefaults() { DockerSpec dockerSpec = new DockerSpec(); - assertThat(dockerSpec.asDockerConfiguration().getHost()).isNull(); - assertThat(dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull(); - assertThat(dockerSpec.asDockerConfiguration().getPublishRegistryAuthentication()).isNull(); + DockerConfiguration dockerConfiguration = dockerSpec.asDockerConfiguration(); + assertThat(dockerConfiguration.getHost()).isNull(); + assertThat(dockerConfiguration.getBuilderRegistryAuthentication()).isNull(); + assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader())) + .contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"") + .contains("\"serveraddress\" : \"\""); } @Test @@ -54,7 +57,9 @@ void asDockerConfigurationWithHostConfiguration() { assertThat(host.isSecure()).isEqualTo(true); assertThat(host.getCertificatePath()).isEqualTo("/tmp/ca-cert"); assertThat(dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull(); - assertThat(dockerSpec.asDockerConfiguration().getPublishRegistryAuthentication()).isNull(); + assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader())) + .contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"") + .contains("\"serveraddress\" : \"\""); } @Test @@ -67,7 +72,9 @@ void asDockerConfigurationWithHostConfigurationNoTlsVerify() { assertThat(host.isSecure()).isEqualTo(false); assertThat(host.getCertificatePath()).isNull(); assertThat(dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull(); - assertThat(dockerSpec.asDockerConfiguration().getPublishRegistryAuthentication()).isNull(); + assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader())) + .contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"") + .contains("\"serveraddress\" : \"\""); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageRegistryIntegrationTests.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageRegistryIntegrationTests.gradle index 3badc8b261a4..d6abd1d1618e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageRegistryIntegrationTests.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageRegistryIntegrationTests.gradle @@ -7,11 +7,6 @@ sourceCompatibility = '1.8' targetCompatibility = '1.8' bootBuildImage { + builder = "projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.1" publish = true - docker { - publishRegistry { - username = "user" - password = "secret" - } - } } \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc index 88e0d2960c77..ae5ebded1a94 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc @@ -338,7 +338,10 @@ An OCI image containing a https://buildpacks.io/docs/buildpack-author-guide/pack [[build-image.examples.publish]] === Image Publishing -The generated image can be published to a Docker registry by enabling a `publish` option and configuring authentication for the registry using `docker.publishRegistry` parameters. +The generated image can be published to a Docker registry by enabling a `publish` option. + +If the Docker registry requires authentication, the credentials can be configured using `docker.publishRegistry` parameters. +If the Docker registry does not require authentication, the `docker.publishRegistry` configuration can be omitted. [source,xml,indent=0,subs="verbatim,attributes",tabsize=4] ---- diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java index 87f5f7b3db89..f38272b00fef 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -330,12 +330,6 @@ void failsWhenBuildImageIsInvokedOnMultiModuleProjectWithBuildImageGoal(MavenBui (project) -> assertThat(buildLog(project)).contains("Error packaging archive for image")); } - @TestTemplate - void failsWhenPublishWithoutPublishRegistryConfigured(MavenBuild mavenBuild) { - mavenBuild.project("build-image").goals("package").systemProperty("spring-boot.build-image.publish", "true") - .executeAndFail((project) -> assertThat(buildLog(project)).contains("requires docker.publishRegistry")); - } - @TestTemplate void failsWhenBuilderFails(MavenBuild mavenBuild) { mavenBuild.project("build-image-builder-error").goals("package") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-publish/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-publish/pom.xml index ee4fe387ed05..852ca052cc9f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-publish/pom.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-publish/pom.xml @@ -23,14 +23,9 @@ + projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.1 true - - - user - secret - - diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java index 19d551dc814d..fa8ef92529bb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java @@ -224,7 +224,7 @@ private void buildImage() throws MojoExecutionException { Libraries libraries = getLibraries(Collections.emptySet()); try { DockerConfiguration dockerConfiguration = (this.docker != null) ? this.docker.asDockerConfiguration() - : null; + : new Docker().asDockerConfiguration(); BuildRequest request = getBuildRequest(libraries); Builder builder = new Builder(new MojoBuildLog(this::getLog), dockerConfiguration); builder.build(request); @@ -234,7 +234,7 @@ private void buildImage() throws MojoExecutionException { } } - private BuildRequest getBuildRequest(Libraries libraries) throws MojoExecutionException { + private BuildRequest getBuildRequest(Libraries libraries) { ImagePackager imagePackager = new ImagePackager(getArchiveFile(), getBackupFile()); Function content = (owner) -> getApplicationContent(owner, libraries, imagePackager); Image image = (this.image != null) ? this.image : new Image(); @@ -259,17 +259,9 @@ private BuildRequest getBuildRequest(Libraries libraries) throws MojoExecutionEx if (image.network == null && this.network != null) { image.setNetwork(this.network); } - if (image.publish != null && image.publish && publishRegistryNotConfigured()) { - throw new MojoExecutionException("Publishing an image requires docker.publishRegistry to be configured"); - } return customize(image.getBuildRequest(this.project.getArtifact(), content)); } - private boolean publishRegistryNotConfigured() { - return this.docker == null || this.docker.getPublishRegistry() == null - || this.docker.getPublishRegistry().isEmpty(); - } - private TarArchive getApplicationContent(Owner owner, Libraries libraries, ImagePackager imagePackager) { ImagePackager packager = getConfiguredPackager(() -> imagePackager); return new PackagedTarArchive(owner, libraries, packager); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java index 637de7d14833..64044dcb50d1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -146,7 +146,7 @@ private DockerConfiguration customizeBuilderAuthentication(DockerConfiguration d private DockerConfiguration customizePublishAuthentication(DockerConfiguration dockerConfiguration) { if (this.publishRegistry == null || this.publishRegistry.isEmpty()) { - return dockerConfiguration; + return dockerConfiguration.withEmptyPublishRegistryAuthentication(); } if (this.publishRegistry.hasTokenAuth() && !this.publishRegistry.hasUserAuth()) { return dockerConfiguration.withPublishRegistryTokenAuthentication(this.publishRegistry.getToken()); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerTests.java index eb91cdc90140..04d64c9842cd 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,9 +36,12 @@ class DockerTests { @Test void asDockerConfigurationWithDefaults() { Docker docker = new Docker(); - assertThat(docker.asDockerConfiguration().getHost()).isNull(); - assertThat(docker.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull(); - assertThat(docker.asDockerConfiguration().getPublishRegistryAuthentication()).isNull(); + DockerConfiguration dockerConfiguration = docker.asDockerConfiguration(); + assertThat(dockerConfiguration.getHost()).isNull(); + assertThat(dockerConfiguration.getBuilderRegistryAuthentication()).isNull(); + assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader())) + .contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"") + .contains("\"serveraddress\" : \"\""); } @Test @@ -53,7 +56,9 @@ void asDockerConfigurationWithHostConfiguration() { assertThat(host.isSecure()).isEqualTo(true); assertThat(host.getCertificatePath()).isEqualTo("/tmp/ca-cert"); assertThat(docker.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull(); - assertThat(docker.asDockerConfiguration().getPublishRegistryAuthentication()).isNull(); + assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader())) + .contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"") + .contains("\"serveraddress\" : \"\""); } @Test