diff --git a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-image-caches.gradle b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-image-caches.gradle new file mode 100644 index 000000000000..14ffe5e14446 --- /dev/null +++ b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-image-caches.gradle @@ -0,0 +1,24 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '{version-spring-boot}' +} + +tasks.named("bootJar") { + mainClass = 'com.example.ExampleApplication' +} + +// tag::caches[] +tasks.named("bootBuildImage") { + buildCache { + image { + name = "docker.io/library/${rootProject.name}:build" + } + } +} +// end::caches[] + +tasks.register("bootBuildImageCaches") { + doFirst { + bootBuildImage.buildCache.asCache().with { println "buildCache=$name" } + } +} diff --git a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-image-caches.gradle.kts b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-image-caches.gradle.kts new file mode 100644 index 000000000000..ea20581a168f --- /dev/null +++ b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-image-caches.gradle.kts @@ -0,0 +1,22 @@ +import org.springframework.boot.gradle.tasks.bundling.BootBuildImage + +plugins { + java + id("org.springframework.boot") version "{version-spring-boot}" +} + +// tag::caches[] +tasks.named("bootBuildImage") { + buildCache { + image { + name.set("docker.io/library/${rootProject.name}:build") + } + } +} +// end::caches[] + +tasks.register("bootBuildImageCaches") { + doFirst { + println("buildCache=" + tasks.getByName("bootBuildImage").buildCache.asCache()?.image?.name) + } +} diff --git a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc index 8e3b4bbfaded..9ffcbe13a296 100644 --- a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc +++ b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc @@ -573,6 +573,24 @@ include::example$packaging/boot-build-image-bind-caches.gradle.kts[tags=caches] ---- ====== +The build cache can also be stored in an image instead of a named volume, which allows the cache to be shared between hosts by pushing and pulling it from an image registry, as shown in the following example: + +[tabs] +====== +Groovy:: ++ +[source,groovy,indent=0,subs="verbatim,attributes"] +---- +include::example$packaging/boot-build-image-image-caches.gradle[tags=caches] +---- +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim,attributes"] +---- +include::example$packaging/boot-build-image-image-caches.gradle.kts[tags=caches] +---- +====== + [[build-image.examples.docker]] diff --git a/build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/CacheSpec.java b/build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/CacheSpec.java index b459b0cb205b..499f03fc754a 100644 --- a/build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/CacheSpec.java +++ b/build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/CacheSpec.java @@ -74,6 +74,19 @@ public void bind(Action action) { this.cache = Cache.bind(spec.getSource().get()); } + /** + * Configures an image cache using the given {@code action}. + * @param action the action + */ + public void image(Action action) { + if (this.cache != null) { + throw new GradleException("Each image building cache can be configured only once"); + } + ImageCacheSpec spec = this.objectFactory.newInstance(ImageCacheSpec.class); + action.execute(spec); + this.cache = Cache.image(spec.getName().get()); + } + /** * Configuration for an image building cache stored in a Docker volume. */ @@ -102,4 +115,18 @@ public abstract static class BindCacheSpec { } + /** + * Configuration for an image building cache stored in an image. + */ + public abstract static class ImageCacheSpec { + + /** + * Returns the name of the cache image. + * @return the cache image name + */ + @Input + public abstract Property getName(); + + } + } diff --git a/build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java b/build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java index a9a3488d0efd..6de73280aea5 100644 --- a/build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java +++ b/build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java @@ -324,6 +324,13 @@ void bootBuildImageWithBindCaches() { .containsPattern("launchCache=/tmp/cache-gradle-[\\d]+.launch"); } + @TestTemplate + void bootBuildImageWithImageCaches() { + BuildResult result = this.gradleBuild.script(Examples.DIR + "packaging/boot-build-image-image-caches") + .build("bootBuildImageCaches"); + assertThat(result.getOutput()).containsPattern("buildCache=docker.io/library/gradle-[\\d]+:build"); + } + protected void jarFile(File file) throws IOException { try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) { jar.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF")); diff --git a/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/image-caches-pom.xml b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/image-caches-pom.xml new file mode 100644 index 000000000000..ac8f689957dd --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/image-caches-pom.xml @@ -0,0 +1,22 @@ + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + docker.io/library/${project.artifactId}:build + + + + + + + + + \ No newline at end of file diff --git a/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc index e099dcef4ff3..0c492ca6b557 100644 --- a/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc +++ b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc @@ -494,6 +494,13 @@ The caches and the build workspace can be configured to use bind mounts instead include::example$packaging-oci-image/bind-caches-pom.xml[tags=caches] ---- +The build cache can also be stored in an image instead of a named volume, which allows the cache to be shared between hosts by pushing and pulling it from an image registry, as shown in the following example: + +[source,xml,indent=0,subs="verbatim,attributes"] +---- +include::example$packaging-oci-image/image-caches-pom.xml[tags=caches] +---- + [[build-image.examples.docker]] diff --git a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/CacheInfo.java b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/CacheInfo.java index 98d23db744bd..0a0df4d5c920 100644 --- a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/CacheInfo.java +++ b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/CacheInfo.java @@ -52,6 +52,13 @@ public void setBind(BindCacheInfo info) { this.cache = Cache.bind(source); } + public void setImage(ImageCacheInfo info) { + Assert.state(this.cache == null, "Each image building cache can be configured only once"); + String name = info.getName(); + Assert.state(name != null, "'name' must not be null"); + this.cache = Cache.image(name); + } + @Nullable Cache asCache() { return this.cache; } @@ -68,6 +75,12 @@ static CacheInfo fromBind(BindCacheInfo cacheInfo) { return new CacheInfo(Cache.bind(source)); } + static CacheInfo fromImage(ImageCacheInfo cacheInfo) { + String name = cacheInfo.getName(); + Assert.state(name != null, "'name' must not be null"); + return new CacheInfo(Cache.image(name)); + } + /** * Encapsulates configuration of an image building cache stored in a volume. */ @@ -116,4 +129,28 @@ void setSource(@Nullable String source) { } + /** + * Encapsulates configuration of an image building cache stored in an image. + */ + public static class ImageCacheInfo { + + private @Nullable String name; + + public ImageCacheInfo() { + } + + ImageCacheInfo(String name) { + this.name = name; + } + + public @Nullable String getName() { + return this.name; + } + + void setName(@Nullable String name) { + this.name = name; + } + + } + } diff --git a/build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java b/build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java index a6a2b4d55bac..e4c4dfb348b9 100644 --- a/build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java +++ b/build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java @@ -37,9 +37,11 @@ import org.springframework.boot.buildpack.platform.io.Owner; import org.springframework.boot.buildpack.platform.io.TarArchive; import org.springframework.boot.maven.CacheInfo.BindCacheInfo; +import org.springframework.boot.maven.CacheInfo.ImageCacheInfo; import org.springframework.boot.maven.CacheInfo.VolumeCacheInfo; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.entry; import static org.mockito.Mockito.mock; @@ -245,6 +247,23 @@ void getBuildRequestWhenHasLaunchCacheBindUsesCache() { assertThat(request.getLaunchCache()).isEqualTo(Cache.bind("launch-cache-dir")); } + @Test + void getBuildRequestWhenHasBuildCacheImageUsesCache() { + Image image = new Image(); + image.buildCache = CacheInfo.fromImage(new ImageCacheInfo("build-cache-image")); + BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent()); + assertThat(request.getBuildCache()).isEqualTo(Cache.image("build-cache-image")); + } + + @Test + void getBuildRequestWhenHasLaunchCacheImageThrowsException() { + Image image = new Image(); + image.launchCache = CacheInfo.fromImage(new ImageCacheInfo("launch-cache-image")); + assertThatIllegalArgumentException() + .isThrownBy(() -> image.getBuildRequest(createArtifact(), mockApplicationContent())) + .withMessage("Launch cache must not be an image cache"); + } + @Test void getBuildRequestWhenHasCreatedDateUsesCreatedDate() { Image image = new Image(); diff --git a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java index bdbf888926c2..d5f83e2f4ca2 100644 --- a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java +++ b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java @@ -423,6 +423,7 @@ public BuildRequest withBuildCache(Cache buildCache) { */ public BuildRequest withLaunchCache(Cache launchCache) { Assert.notNull(launchCache, "'launchCache' must not be null"); + Assert.isNull(launchCache.getImage(), "Launch cache must not be an image cache"); return new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage, this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache, diff --git a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Cache.java b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Cache.java index a3e4f98a815b..749ed1280747 100644 --- a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Cache.java +++ b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Cache.java @@ -45,7 +45,12 @@ public enum Format { /** * A cache stored as a bind mount. */ - BIND("bind mount"); + BIND("bind mount"), + + /** + * A cache stored as an image. + */ + IMAGE("image"); private final String description; @@ -81,6 +86,14 @@ public String getDescription() { return (this.format.equals(Format.BIND)) ? (Bind) this : null; } + /** + * Return the details of the cache if it is an image cache. + * @return the cache, or {@code null} if it is not an image cache + */ + public @Nullable Image getImage() { + return (this.format.equals(Format.IMAGE)) ? (Image) this : null; + } + /** * Create a new {@code Cache} that uses a volume with the provided name. * @param name the cache volume name @@ -111,6 +124,16 @@ public static Cache bind(String source) { return new Bind(source); } + /** + * Create a new {@code Cache} that uses an image with the provided name. + * @param name the cache image name + * @return a new cache instance + */ + public static Cache image(String name) { + Assert.notNull(name, "'name' must not be null"); + return new Image(name); + } + @Override public boolean equals(@Nullable Object obj) { if (this == obj) { @@ -222,4 +245,49 @@ public String toString() { } + /** + * Details of a cache stored in an image. + */ + public static class Image extends Cache { + + private final String name; + + Image(String name) { + super(Format.IMAGE); + this.name = name; + } + + public String getName() { + return this.name; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + if (!super.equals(obj)) { + return false; + } + Image other = (Image) obj; + return Objects.equals(this.name, other.name); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + ObjectUtils.nullSafeHashCode(this.name); + return result; + } + + @Override + public String toString() { + return this.format.getDescription() + " '" + this.name + "'"; + } + + } + } diff --git a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java index b5467db65173..1c1598524fce 100644 --- a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java +++ b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java @@ -195,7 +195,7 @@ private Phase createPhase() { Assert.state(runImage != null, "'runImage' must not be null"); phase.withRunImage(runImage); phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); - phase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); + configureBuildCache(phase); phase.withLaunchCache(Directory.LAUNCH_CACHE, Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE)); configureDaemonAccess(phase); @@ -215,6 +215,10 @@ private Phase createPhase() { private Phase analyzePhase() { Phase phase = new Phase("analyzer", isVerboseLogging()); configureDaemonAccess(phase); + Cache.Image buildCacheImage = this.buildCache.getImage(); + if (buildCacheImage != null) { + phase.withBuildCache(buildCacheImage.getName()); + } phase.withLaunchCache(Directory.LAUNCH_CACHE, Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE)); phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); @@ -239,7 +243,7 @@ private Phase detectPhase() { private Phase restorePhase() { Phase phase = new Phase("restorer", isVerboseLogging()); configureDaemonAccess(phase); - phase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); + configureBuildCache(phase); phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); configureOptions(phase); return phase; @@ -260,7 +264,7 @@ private Phase exportPhase() { configureDaemonAccess(phase); phase.withApp(this.applicationDirectory, Binding.from(getCacheBindingSource(this.application), this.applicationDirectory)); - phase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); + configureBuildCache(phase); phase.withLaunchCache(Directory.LAUNCH_CACHE, Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE)); phase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS)); @@ -343,6 +347,17 @@ private void configureDaemonAccess(Phase phase) { } } + private void configureBuildCache(Phase phase) { + Cache.Image image = this.buildCache.getImage(); + if (image != null) { + phase.withBuildCache(image.getName()); + } + else { + phase.withBuildCache(Directory.CACHE, + Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE)); + } + } + private void configureCreatedDate(Phase phase) { if (this.request.getCreatedDate() != null) { phase.withEnv(SOURCE_DATE_EPOCH_KEY, Long.toString(this.request.getCreatedDate().getEpochSecond())); diff --git a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java index d037d33b072e..985e6992b875 100644 --- a/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java +++ b/buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java @@ -75,6 +75,10 @@ void withBuildCache(String path, Binding binding) { withBinding(binding); } + void withBuildCache(String image) { + withArgs("-cache-image", image); + } + /** * Update this phase with Docker daemon access. */ diff --git a/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java b/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java index 7bbb13d3e72a..dab8563813ae 100644 --- a/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java +++ b/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java @@ -349,6 +349,14 @@ void withLaunchBindCacheAddsCache() throws IOException { assertThat(withCache.getLaunchCache()).isEqualTo(Cache.bind("/tmp/launch-cache")); } + @Test + void withLaunchImageCacheThrowsException() throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")); + assertThatIllegalArgumentException() + .isThrownBy(() -> request.withLaunchCache(Cache.image("launch-cache-image"))) + .withMessage("Launch cache must not be an image cache"); + } + @Test @SuppressWarnings("NullAway") // Test null check void withLaunchVolumeCacheWhenCacheIsNullThrowsException() throws IOException { diff --git a/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java b/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java index 69c8b8f477b3..eac76947b9fb 100644 --- a/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java +++ b/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java @@ -291,6 +291,27 @@ void executeWithCacheBindMountsExecutesPhases(boolean trustBuilder) throws Excep assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } + @ParameterizedTest + @BooleanValueSource + void executeWithImageBuildCacheExecutesPhases(boolean trustBuilder) throws Exception { + given(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId()); + given(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId()); + given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); + BuildRequest request = getTestRequest(trustBuilder).withBuildCache(Cache.image("my-cache-image")); + createLifecycle(request).execute(); + if (trustBuilder) { + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-image-cache.json")); + } + else { + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-image-cache.json")); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-image-cache.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-image-cache.json")); + } + assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); + } + @ParameterizedTest @BooleanValueSource void executeWithCreatedDateExecutesPhases(boolean trustBuilder) throws Exception { diff --git a/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java b/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java index 42d06b41f148..0771fed79281 100644 --- a/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java +++ b/buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java @@ -102,6 +102,17 @@ void applyWhenWithArgsUpdatesConfigurationWithArguments() { then(update).shouldHaveNoMoreInteractions(); } + @Test + void applyWhenWithImageBuildCacheUpdatesConfigurationWithCacheImage() { + Phase phase = new Phase("test", false); + phase.withBuildCache("my-cache-image"); + Update update = mock(Update.class); + phase.apply(update); + then(update).should().withCommand("/cnb/lifecycle/test", "-cache-image", "my-cache-image"); + then(update).should().withLabel("author", "spring-boot"); + then(update).shouldHaveNoMoreInteractions(); + } + @Test void applyWhenWithBindsUpdatesConfigurationWithBinds() { Phase phase = new Phase("test", false); diff --git a/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-image-cache.json b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-image-cache.json new file mode 100644 index 000000000000..e18ed997905c --- /dev/null +++ b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-image-cache.json @@ -0,0 +1,33 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/analyzer", + "-daemon", + "-cache-image", + "my-cache-image", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "docker.io/library/my-application:latest" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} diff --git a/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-image-cache.json b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-image-cache.json new file mode 100644 index 000000000000..babbd120c8ef --- /dev/null +++ b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-image-cache.json @@ -0,0 +1,38 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/creator", + "-app", + "/workspace", + "-platform", + "/platform", + "-run-image", + "docker.io/cloudfoundry/run:latest", + "-layers", + "/layers", + "-cache-image", + "my-cache-image", + "-launch-cache", + "/launch-cache", + "-daemon", + "docker.io/library/my-application:latest" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "pack-app-aaaaaaaaaa:/workspace", + "pack-layers-aaaaaaaaaa:/layers", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "/var/run/docker.sock:/var/run/docker.sock" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} diff --git a/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-image-cache.json b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-image-cache.json new file mode 100644 index 000000000000..34a4f76b2cad --- /dev/null +++ b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-image-cache.json @@ -0,0 +1,34 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/exporter", + "-daemon", + "-app", + "/workspace", + "-cache-image", + "my-cache-image", + "-launch-cache", + "/launch-cache", + "-layers", + "/layers", + "docker.io/library/my-application:latest" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "pack-app-aaaaaaaaaa:/workspace", + "pack-cache-b35197ac41ea.launch:/launch-cache", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +} diff --git a/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-image-cache.json b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-image-cache.json new file mode 100644 index 000000000000..a4e74529206a --- /dev/null +++ b/buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-image-cache.json @@ -0,0 +1,27 @@ +{ + "User": "root", + "Image": "pack.local/ephemeral-builder", + "Cmd": [ + "/cnb/lifecycle/restorer", + "-daemon", + "-cache-image", + "my-cache-image", + "-layers", + "/layers" + ], + "Env": [ + "CNB_PLATFORM_API=0.8" + ], + "Labels": { + "author": "spring-boot" + }, + "HostConfig": { + "Binds": [ + "/var/run/docker.sock:/var/run/docker.sock", + "pack-layers-aaaaaaaaaa:/layers" + ], + "SecurityOpt" : [ + "label=disable" + ] + } +}