Commit bb9e37e1 authored by Scott Frederick's avatar Scott Frederick

Use platform API builder image tags

CNB builder images are now being tagged in a manner that indicates
the version of the platform API implemented. This allows Spring Boot
to default to a builder tag that guarantees API compatibility while
allowing for updates to bundled buildpacks.

Fixes gh-20171
parent 4dad56a4
...@@ -36,7 +36,9 @@ import org.springframework.util.Assert; ...@@ -36,7 +36,9 @@ import org.springframework.util.Assert;
*/ */
public class BuildRequest { public class BuildRequest {
private static final ImageReference DEFAULT_BUILDER = ImageReference.of("cloudfoundry/cnb:0.0.53-bionic"); static final String DEFAULT_BUILDER_IMAGE_NAME = "cloudfoundry/cnb:bionic-platform-api-0.2";
private static final ImageReference DEFAULT_BUILDER = ImageReference.of(DEFAULT_BUILDER_IMAGE_NAME);
private final ImageReference name; private final ImageReference name;
......
...@@ -55,7 +55,7 @@ public class BuildRequestTests { ...@@ -55,7 +55,7 @@ public class BuildRequestTests {
writeTestJarFile(jarFile); writeTestJarFile(jarFile);
BuildRequest request = BuildRequest.forJarFile(jarFile); BuildRequest request = BuildRequest.forJarFile(jarFile);
assertThat(request.getName().toString()).isEqualTo("docker.io/library/my-app:0.0.1"); assertThat(request.getName().toString()).isEqualTo("docker.io/library/my-app:0.0.1");
assertThat(request.getBuilder().toString()).isEqualTo("docker.io/cloudfoundry/cnb:0.0.53-bionic"); assertThat(request.getBuilder().toString()).isEqualTo("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME);
assertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent); assertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent);
assertThat(request.getEnv()).isEmpty(); assertThat(request.getEnv()).isEmpty();
} }
...@@ -66,7 +66,7 @@ public class BuildRequestTests { ...@@ -66,7 +66,7 @@ public class BuildRequestTests {
writeTestJarFile(jarFile); writeTestJarFile(jarFile);
BuildRequest request = BuildRequest.forJarFile(ImageReference.of("test-app"), jarFile); BuildRequest request = BuildRequest.forJarFile(ImageReference.of("test-app"), jarFile);
assertThat(request.getName().toString()).isEqualTo("docker.io/library/test-app:latest"); assertThat(request.getName().toString()).isEqualTo("docker.io/library/test-app:latest");
assertThat(request.getBuilder().toString()).isEqualTo("docker.io/cloudfoundry/cnb:0.0.53-bionic"); assertThat(request.getBuilder().toString()).isEqualTo("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME);
assertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent); assertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent);
assertThat(request.getEnv()).isEmpty(); assertThat(request.getEnv()).isEmpty();
} }
......
...@@ -72,7 +72,7 @@ class BuilderTests { ...@@ -72,7 +72,7 @@ class BuilderTests {
DockerApi docker = mockDockerApi(); DockerApi docker = mockDockerApi();
Image builderImage = loadImage("image.json"); Image builderImage = loadImage("image.json");
Image runImage = loadImage("run-image.json"); Image runImage = loadImage("run-image.json");
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/cnb:0.0.53-bionic")), any())) given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
.willAnswer(withPulledImage(builderImage)); .willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any())) given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
.willAnswer(withPulledImage(runImage)); .willAnswer(withPulledImage(runImage));
...@@ -97,7 +97,7 @@ class BuilderTests { ...@@ -97,7 +97,7 @@ class BuilderTests {
DockerApi docker = mockDockerApi(); DockerApi docker = mockDockerApi();
Image builderImage = loadImage("image.json"); Image builderImage = loadImage("image.json");
Image runImage = loadImage("run-image-with-bad-stack.json"); Image runImage = loadImage("run-image-with-bad-stack.json");
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/cnb:0.0.53-bionic")), any())) given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
.willAnswer(withPulledImage(builderImage)); .willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any())) given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
.willAnswer(withPulledImage(runImage)); .willAnswer(withPulledImage(runImage));
...@@ -113,7 +113,7 @@ class BuilderTests { ...@@ -113,7 +113,7 @@ class BuilderTests {
DockerApi docker = mockDockerApiLifecycleError(); DockerApi docker = mockDockerApiLifecycleError();
Image builderImage = loadImage("image.json"); Image builderImage = loadImage("image.json");
Image runImage = loadImage("run-image.json"); Image runImage = loadImage("run-image.json");
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/cnb:0.0.53-bionic")), any())) given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
.willAnswer(withPulledImage(builderImage)); .willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any())) given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
.willAnswer(withPulledImage(runImage)); .willAnswer(withPulledImage(runImage));
......
...@@ -48,7 +48,7 @@ The following table summarizes the available properties and their default values ...@@ -48,7 +48,7 @@ The following table summarizes the available properties and their default values
| `builder` | `builder`
| `--builder` | `--builder`
| Name of the Builder image to use. | Name of the Builder image to use.
| `cloudfoundry/cnb:0.0.53-bionic` | `cloudfoundry/cnb:bionic-platform-api-0.2`
| `imageName` | `imageName`
| `--imageName` | `--imageName`
......
...@@ -61,7 +61,7 @@ class BootBuildImageIntegrationTests { ...@@ -61,7 +61,7 @@ class BootBuildImageIntegrationTests {
String projectName = this.gradleBuild.getProjectDir().getName(); String projectName = this.gradleBuild.getProjectDir().getName();
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
assertThat(result.getOutput()).contains("docker.io/library/" + projectName); assertThat(result.getOutput()).contains("docker.io/library/" + projectName);
assertThat(result.getOutput()).contains("cloudfoundry/cnb:0.0.53-bionic"); assertThat(result.getOutput()).contains("cloudfoundry/cnb:bionic-platform-api");
ImageReference imageReference = ImageReference.of(ImageName.of(projectName)); ImageReference imageReference = ImageReference.of(ImageName.of(projectName));
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) { try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
...@@ -78,7 +78,7 @@ class BootBuildImageIntegrationTests { ...@@ -78,7 +78,7 @@ class BootBuildImageIntegrationTests {
BuildResult result = this.gradleBuild.build("bootBuildImage"); BuildResult result = this.gradleBuild.build("bootBuildImage");
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
assertThat(result.getOutput()).contains("example.com/test-image-name"); assertThat(result.getOutput()).contains("example.com/test-image-name");
assertThat(result.getOutput()).contains("cloudfoundry/cnb:0.0.53-bionic"); assertThat(result.getOutput()).contains("cloudfoundry/cnb:bionic-platform-api");
ImageReference imageReference = ImageReference.of(ImageName.of("example.com/test-image-name")); ImageReference imageReference = ImageReference.of(ImageName.of("example.com/test-image-name"));
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) { try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
...@@ -96,7 +96,7 @@ class BootBuildImageIntegrationTests { ...@@ -96,7 +96,7 @@ class BootBuildImageIntegrationTests {
String projectName = this.gradleBuild.getProjectDir().getName(); String projectName = this.gradleBuild.getProjectDir().getName();
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
assertThat(result.getOutput()).contains("docker.io/library/" + projectName); assertThat(result.getOutput()).contains("docker.io/library/" + projectName);
assertThat(result.getOutput()).contains("cloudfoundry/cnb:0.0.43-bionic"); assertThat(result.getOutput()).contains("cloudfoundry/cnb:bionic-platform-api-0.1");
ImageReference imageReference = ImageReference.of(ImageName.of(projectName)); ImageReference imageReference = ImageReference.of(ImageName.of(projectName));
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) { try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
......
...@@ -7,5 +7,5 @@ sourceCompatibility = '1.8' ...@@ -7,5 +7,5 @@ sourceCompatibility = '1.8'
targetCompatibility = '1.8' targetCompatibility = '1.8'
bootBuildImage { bootBuildImage {
builder = "cloudfoundry/cnb:0.0.43-bionic" builder = "cloudfoundry/cnb:bionic-platform-api-0.1"
} }
...@@ -73,7 +73,7 @@ The following table summarizes the available parameters and their default values ...@@ -73,7 +73,7 @@ The following table summarizes the available parameters and their default values
| `builder` | `builder`
| Name of the Builder image to use. | Name of the Builder image to use.
| `spring-boot.build-image.builder` | `spring-boot.build-image.builder`
| `cloudfoundry/cnb:0.0.53-bionic` | `cloudfoundry/cnb:bionic-platform-api-0.2`
| `name` | `name`
| {spring-boot-api}/buildpack/platform/docker/type/ImageReference.html#of-java.lang.String-[Image name] for the generated image. | {spring-boot-api}/buildpack/platform/docker/type/ImageReference.html#of-java.lang.String-[Image name] for the generated image.
......
...@@ -52,7 +52,7 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests { ...@@ -52,7 +52,7 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests {
assertThat(jar).isFile(); assertThat(jar).isFile();
File original = new File(project, "target/build-image-0.0.1.BUILD-SNAPSHOT.jar.original"); File original = new File(project, "target/build-image-0.0.1.BUILD-SNAPSHOT.jar.original");
assertThat(original).doesNotExist(); assertThat(original).doesNotExist();
assertThat(buildLog(project)).contains("Building image").contains("cloudfoundry/cnb:0.0.53-bionic") assertThat(buildLog(project)).contains("Building image").contains("cloudfoundry/cnb:bionic-platform-api")
.contains("docker.io/library/build-image:0.0.1.BUILD-SNAPSHOT") .contains("docker.io/library/build-image:0.0.1.BUILD-SNAPSHOT")
.contains("Successfully built image"); .contains("Successfully built image");
ImageReference imageReference = ImageReference.of(ImageName.of("build-image"), "0.0.1.BUILD-SNAPSHOT"); ImageReference imageReference = ImageReference.of(ImageName.of("build-image"), "0.0.1.BUILD-SNAPSHOT");
...@@ -93,11 +93,11 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests { ...@@ -93,11 +93,11 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests {
void whenBuildImageIsInvokedWithCommandLineParameters(MavenBuild mavenBuild) { void whenBuildImageIsInvokedWithCommandLineParameters(MavenBuild mavenBuild) {
mavenBuild.project("build-image").goals("package") mavenBuild.project("build-image").goals("package")
.systemProperty("spring-boot.build-image.imageName", "example.com/test/cmd-property-name:v1") .systemProperty("spring-boot.build-image.imageName", "example.com/test/cmd-property-name:v1")
.systemProperty("spring-boot.build-image.builder", "cloudfoundry/cnb:0.0.43-bionic") .systemProperty("spring-boot.build-image.builder", "cloudfoundry/cnb:bionic-platform-api-0.1")
.execute((project) -> { .execute((project) -> {
assertThat(buildLog(project)).contains("Building image") assertThat(buildLog(project)).contains("Building image")
.contains("example.com/test/cmd-property-name:v1") .contains("example.com/test/cmd-property-name:v1")
.contains("cloudfoundry/cnb:0.0.43-bionic").contains("Successfully built image"); .contains("cloudfoundry/cnb:bionic-platform-api-0.1").contains("Successfully built image");
ImageReference imageReference = ImageReference.of("example.com/test/cmd-property-name:v1"); ImageReference imageReference = ImageReference.of("example.com/test/cmd-property-name:v1");
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) { try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start(); container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
...@@ -111,7 +111,8 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests { ...@@ -111,7 +111,8 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests {
@TestTemplate @TestTemplate
void whenBuildImageIsInvokedWithV1BuilderImage(MavenBuild mavenBuild) { void whenBuildImageIsInvokedWithV1BuilderImage(MavenBuild mavenBuild) {
mavenBuild.project("build-image-v1-builder").goals("package").execute((project) -> { mavenBuild.project("build-image-v1-builder").goals("package").execute((project) -> {
assertThat(buildLog(project)).contains("Building image").contains("cloudfoundry/cnb:0.0.43-bionic") assertThat(buildLog(project)).contains("Building image")
.contains("cloudfoundry/cnb:bionic-platform-api-0.1")
.contains("docker.io/library/build-image-v1-builder:0.0.1.BUILD-SNAPSHOT") .contains("docker.io/library/build-image-v1-builder:0.0.1.BUILD-SNAPSHOT")
.contains("Successfully built image"); .contains("Successfully built image");
ImageReference imageReference = ImageReference ImageReference imageReference = ImageReference
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</goals> </goals>
<configuration> <configuration>
<image> <image>
<builder>cloudfoundry/cnb:0.0.43-bionic</builder> <builder>cloudfoundry/cnb:bionic-platform-api-0.1</builder>
</image> </image>
</configuration> </configuration>
</execution> </execution>
......
...@@ -57,7 +57,7 @@ class ImageTests { ...@@ -57,7 +57,7 @@ class ImageTests {
void getBuildRequestWhenNoCustomizationsUsesDefaults() { void getBuildRequestWhenNoCustomizationsUsesDefaults() {
BuildRequest request = new Image().getBuildRequest(createArtifact(), mockAplicationContent()); BuildRequest request = new Image().getBuildRequest(createArtifact(), mockAplicationContent());
assertThat(request.getName().toString()).isEqualTo("docker.io/library/my-app:0.0.1-SNAPSHOT"); assertThat(request.getName().toString()).isEqualTo("docker.io/library/my-app:0.0.1-SNAPSHOT");
assertThat(request.getBuilder().toString()).isEqualTo("docker.io/cloudfoundry/cnb:0.0.53-bionic"); assertThat(request.getBuilder().toString()).contains("docker.io/cloudfoundry/cnb:bionic-platform-api");
assertThat(request.getEnv()).isEmpty(); assertThat(request.getEnv()).isEmpty();
assertThat(request.isCleanCache()).isFalse(); assertThat(request.isCleanCache()).isFalse();
assertThat(request.isVerboseLogging()).isFalse(); assertThat(request.isVerboseLogging()).isFalse();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment