diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersion.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersion.java index fc03474503..fdac62b48a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersion.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersion.java @@ -22,16 +22,14 @@ import java.util.regex.Pattern; import org.springframework.util.Assert; /** - * API Version number comprised a major and minor value. + * API Version number comprised of a major and minor value. * * @author Phillip Webb + * @author Scott Frederick */ final class ApiVersion { - /** - * The platform API version supported by this release. - */ - static final ApiVersion PLATFORM = new ApiVersion(0, 1); + private static final ApiVersion PLATFORM_0_1 = new ApiVersion(0, 1); private static final Pattern PATTERN = Pattern.compile("^v?(\\d+)\\.(\\d*)$"); @@ -68,7 +66,7 @@ final class ApiVersion { void assertSupports(ApiVersion other) { if (!supports(other)) { throw new IllegalStateException( - "Version '" + other + "' is not supported by this version ('" + this + "')"); + "Detected platform API version '" + other + "' does not match supported version '" + this + "'"); } } @@ -77,7 +75,7 @@ final class ApiVersion { * the same version number. A 1.x or higher release matches when the versions have the * same major version and a minor that is equal or greater. * @param other the version to check against - * @return of the specified API is supported + * @return if the specified API is supported * @see #assertSupports(ApiVersion) */ boolean supports(ApiVersion other) { @@ -90,6 +88,25 @@ final class ApiVersion { return this.minor >= other.minor; } + /** + * Returns a value indicating whether the API version has a separate cache phase, or + * caching is distributed across other stages. + * @return {@code true} if the API has a separate cache phase, {@code false} otherwise + */ + boolean hasCachePhase() { + return supports(PLATFORM_0_1); + } + + /** + * Returns a value indicating whether the API version requires that the analyze phase + * must follow the restore phase, or if the reverse order is required. + * @return {@code true} if the analyze phase follows restore, {@code false} if restore + * follows analyze + */ + boolean analyzeFollowsRestore() { + return supports(PLATFORM_0_1); + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -132,4 +149,8 @@ final class ApiVersion { } } + static ApiVersion of(int major, int minor) { + return new ApiVersion(major, minor); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersions.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersions.java new file mode 100644 index 0000000000..0749e4552a --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersions.java @@ -0,0 +1,91 @@ +/* + * Copyright 2012-2020 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.buildpack.platform.build; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.util.StringUtils; + +/** + * A set of API Version numbers comprised of major and minor values. + * + * @author Scott Frederick + */ +final class ApiVersions { + + /** + * The platform API versions supported by this release. + */ + static final ApiVersions SUPPORTED_PLATFORMS = new ApiVersions(ApiVersion.of(0, 1), ApiVersion.of(0, 2)); + + private final ApiVersion[] apiVersions; + + private ApiVersions(ApiVersion... versions) { + this.apiVersions = versions; + } + + /** + * Assert that the specified version is supported by these API versions. + * @param other the version to check against + */ + void assertSupports(ApiVersion other) { + for (ApiVersion apiVersion : this.apiVersions) { + if (apiVersion.supports(other)) { + return; + } + } + throw new IllegalStateException( + "Detected platform API version '" + other + "' is not included in supported versions '" + this + "'"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + ApiVersions other = (ApiVersions) obj; + return Arrays.equals(this.apiVersions, other.apiVersions); + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.apiVersions); + } + + @Override + public String toString() { + return StringUtils.arrayToCommaDelimitedString(this.apiVersions); + } + + /** + * Factory method to parse strings into an {@link ApiVersions} instance. + * @param values the values to parse. + * @return the corresponding {@link ApiVersions} + * @throws IllegalArgumentException if any values could not be parsed + */ + static ApiVersions parse(String... values) { + List versions = Arrays.stream(values).map(ApiVersion::parse).collect(Collectors.toList()); + return new ApiVersions(versions.toArray(new ApiVersion[] {})); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java index 6db3d556b0..e6343f2b30 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java @@ -30,7 +30,6 @@ import org.springframework.boot.buildpack.platform.docker.type.ImageReference; import org.springframework.boot.buildpack.platform.docker.type.VolumeName; import org.springframework.boot.buildpack.platform.io.TarArchive; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; /** * A buildpack lifecycle used to run the build {@link Phase phases} needed to package an @@ -40,7 +39,7 @@ import org.springframework.util.StringUtils; */ class Lifecycle implements Closeable { - private static final LifecycleVersion LOGGING_SUPPORTED_VERSION = LifecycleVersion.parse("0.0.5"); + private static final LifecycleVersion LOGGING_MINIMUM_VERSION = LifecycleVersion.parse("0.0.5"); private final BuildLog log; @@ -52,7 +51,9 @@ class Lifecycle implements Closeable { private final EphemeralBuilder builder; - private final LifecycleVersion version; + private final LifecycleVersion lifecycleVersion; + + private final ApiVersion platformVersion; private final VolumeName layersVolume; @@ -76,17 +77,18 @@ class Lifecycle implements Closeable { */ Lifecycle(BuildLog log, DockerApi docker, BuildRequest request, ImageReference runImageReference, EphemeralBuilder builder) { - checkPlatformVersion(builder); this.log = log; this.docker = docker; this.request = request; this.runImageReference = runImageReference; this.builder = builder; - this.version = LifecycleVersion.parse(builder.getBuilderMetadata().getLifecycle().getVersion()); + this.lifecycleVersion = LifecycleVersion.parse(builder.getBuilderMetadata().getLifecycle().getVersion()); + this.platformVersion = ApiVersion.parse(builder.getBuilderMetadata().getLifecycle().getApi().getPlatform()); this.layersVolume = createRandomVolumeName("pack-layers-"); this.applicationVolume = createRandomVolumeName("pack-app-"); this.buildCacheVolume = createCacheVolumeName(request, ".build"); this.launchCacheVolume = createCacheVolumeName(request, ".launch"); + checkPlatformVersion(this.platformVersion); } protected VolumeName createRandomVolumeName(String prefix) { @@ -97,11 +99,8 @@ class Lifecycle implements Closeable { return VolumeName.basedOn(request.getName(), ImageReference::toLegacyString, "pack-cache-", suffix, 6); } - private void checkPlatformVersion(EphemeralBuilder ephemeralBuilder) { - String platformVersion = ephemeralBuilder.getBuilderMetadata().getLifecycle().getApi().getPlatform(); - if (StringUtils.hasText(platformVersion)) { - ApiVersion.PLATFORM.assertSupports(ApiVersion.parse(platformVersion)); - } + private void checkPlatformVersion(ApiVersion platformVersion) { + ApiVersions.SUPPORTED_PLATFORMS.assertSupports(platformVersion); } /** @@ -111,16 +110,24 @@ class Lifecycle implements Closeable { void execute() throws IOException { Assert.state(!this.executed, "Lifecycle has already been executed"); this.executed = true; - this.log.executingLifecycle(this.request, this.version, this.buildCacheVolume); + this.log.executingLifecycle(this.request, this.lifecycleVersion, this.buildCacheVolume); if (this.request.isCleanCache()) { deleteVolume(this.buildCacheVolume); } run(detectPhase()); - run(restorePhase()); - run(analyzePhase()); + if (this.platformVersion.analyzeFollowsRestore()) { + run(restorePhase()); + run(analyzePhase()); + } + else { + run(analyzePhase()); + run(restorePhase()); + } run(buildPhase()); run(exportPhase()); - run(cachePhase()); + if (this.platformVersion.hasCachePhase()) { + run(cachePhase()); + } this.log.executedLifecycle(this.request); } @@ -133,9 +140,10 @@ class Lifecycle implements Closeable { } private Phase restorePhase() { + String cacheDirArg = this.platformVersion.hasCachePhase() ? "-path" : "-cache-dir"; Phase phase = createPhase("restorer"); phase.withDaemonAccess(); - phase.withArgs("-path", Folder.CACHE); + phase.withArgs(cacheDirArg, Folder.CACHE); phase.withArgs("-layers", Folder.LAYERS); phase.withLogLevelArg(); phase.withBinds(this.buildCacheVolume, Folder.CACHE); @@ -151,7 +159,13 @@ class Lifecycle implements Closeable { } phase.withArgs("-daemon"); phase.withArgs("-layers", Folder.LAYERS); + if (!this.platformVersion.hasCachePhase()) { + phase.withArgs("-cache-dir", Folder.CACHE); + } phase.withArgs(this.request.getName()); + if (!this.platformVersion.hasCachePhase()) { + phase.withBinds(this.buildCacheVolume, Folder.CACHE); + } return phase; } @@ -172,8 +186,14 @@ class Lifecycle implements Closeable { phase.withArgs("-app", Folder.APPLICATION); phase.withArgs("-daemon"); phase.withArgs("-launch-cache", Folder.LAUNCH_CACHE); + if (!this.platformVersion.hasCachePhase()) { + phase.withArgs("-cache-dir", Folder.CACHE); + } phase.withArgs(this.request.getName()); phase.withBinds(this.launchCacheVolume, Folder.LAUNCH_CACHE); + if (!this.platformVersion.hasCachePhase()) { + phase.withBinds(this.buildCacheVolume, Folder.CACHE); + } return phase; } @@ -189,7 +209,7 @@ class Lifecycle implements Closeable { private Phase createPhase(String name) { boolean verboseLogging = this.request.isVerboseLogging() - && this.version.isEqualOrGreaterThan(LOGGING_SUPPORTED_VERSION); + && this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION); Phase phase = new Phase(name, verboseLogging); phase.withBinds(this.layersVolume, Folder.LAYERS); phase.withBinds(this.applicationVolume, Folder.APPLICATION); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionTests.java index 47af377570..e2fd3b106f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionTests.java @@ -26,6 +26,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; * Tests for {@link ApiVersion}. * * @author Phillip Webb + * @author Scott Frederick */ class ApiVersionTests { @@ -63,7 +64,7 @@ class ApiVersionTests { void assertSupportsWhenDoesNotSupportThrowsException() { assertThatIllegalStateException() .isThrownBy(() -> ApiVersion.parse("1.2").assertSupports(ApiVersion.parse("1.3"))) - .withMessage("Version 'v1.3' is not supported by this version ('v1.2')"); + .withMessage("Detected platform API version 'v1.3' does not match supported version 'v1.2'"); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionsTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionsTests.java new file mode 100644 index 0000000000..d516d25f44 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionsTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2020 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.buildpack.platform.build; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; + +/** + * Tests for {@link ApiVersions}. + * + * @author Scott Frederick + */ +class ApiVersionsTests { + + @Test + void assertSupportsWhenAllSupports() { + ApiVersions.parse("1.1", "2.2").assertSupports(ApiVersion.parse("1.0")); + } + + @Test + void assertSupportsWhenDoesNoneSupportedThrowsException() { + assertThatIllegalStateException() + .isThrownBy(() -> ApiVersions.parse("1.1", "1.2").assertSupports(ApiVersion.parse("1.3"))) + .withMessage("Detected platform API version 'v1.3' is not included in supported versions 'v1.1,v1.2'"); + } + + @Test + void toStringReturnsString() { + assertThat(ApiVersions.parse("1.1", "2.2", "3.3").toString()).isEqualTo("v1.1,v2.2,v3.3"); + } + + @Test + void equalsAndHashCode() { + ApiVersions v12a = ApiVersions.parse("1.2", "2.3"); + ApiVersions v12b = ApiVersions.parse("1.2", "2.3"); + ApiVersions v13 = ApiVersions.parse("1.3", "2.4"); + assertThat(v12a.hashCode()).isEqualTo(v12b.hashCode()); + assertThat(v12a).isEqualTo(v12a).isEqualTo(v12b).isNotEqualTo(v13); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java index 0bc249defd..971de6d738 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java @@ -60,6 +60,7 @@ import static org.mockito.Mockito.verify; * Tests for {@link Lifecycle}. * * @author Phillip Webb + * @author Scott Frederick */ class LifecycleTests { @@ -67,52 +68,52 @@ class LifecycleTests { private DockerApi docker; - private Lifecycle lifecycle; - private Map configs = new LinkedHashMap<>(); private Map content = new LinkedHashMap<>(); @BeforeEach - void setup() throws Exception { + void setup() { this.out = new TestPrintStream(); this.docker = mockDockerApi(); - BuildRequest request = getTestRequest(); - this.lifecycle = createLifecycle(request); - } - - private DockerApi mockDockerApi() { - DockerApi docker = mock(DockerApi.class); - ImageApi imageApi = mock(ImageApi.class); - ContainerApi containerApi = mock(ContainerApi.class); - VolumeApi volumeApi = mock(VolumeApi.class); - given(docker.image()).willReturn(imageApi); - given(docker.container()).willReturn(containerApi); - given(docker.volume()).willReturn(volumeApi); - return docker; } @Test - void executeExecutesPhases() throws Exception { + void executeExecutesPhasesWithCacherPhase() throws Exception { given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); - this.lifecycle.execute(); + createLifecycle("0.5").execute(); assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); - assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json")); - assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-0.1.json")); + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-0.1.json")); assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); - assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-0.1.json")); assertPhaseWasRun("cacher", withExpectedConfig("lifecycle-cacher.json")); assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); } + @Test + void executeExecutesPhasesWithEmbeddedCaching() throws Exception { + given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId()); + given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); + given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); + createLifecycle("0.6").execute(); + assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json")); + assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-0.2.json")); + assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-0.2.json")); + assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json")); + assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-0.2.json")); + assertPhaseWasNotRun("cacher"); + assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); + } + @Test void executeOnlyUploadsContentOnce() throws Exception { given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); - this.lifecycle.execute(); + createLifecycle().execute(); assertThat(this.content).hasSize(1); } @@ -121,8 +122,9 @@ class LifecycleTests { given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); - this.lifecycle.execute(); - assertThatIllegalStateException().isThrownBy(this.lifecycle::execute) + Lifecycle lifecycle = createLifecycle(); + lifecycle.execute(); + assertThatIllegalStateException().isThrownBy(lifecycle::execute) .withMessage("Lifecycle has already been executed"); } @@ -131,7 +133,7 @@ class LifecycleTests { given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(9, null)); - assertThatExceptionOfType(BuilderException.class).isThrownBy(() -> this.lifecycle.execute()) + assertThatExceptionOfType(BuilderException.class).isThrownBy(() -> createLifecycle().execute()) .withMessage("Builder lifecycle 'detector' failed with status code 9"); } @@ -148,27 +150,50 @@ class LifecycleTests { @Test void closeClearsVolumes() throws Exception { - this.lifecycle.close(); + createLifecycle().close(); verify(this.docker.volume()).delete(VolumeName.of("pack-layers-aaaaaaaaaa"), true); verify(this.docker.volume()).delete(VolumeName.of("pack-app-aaaaaaaaaa"), true); } + private DockerApi mockDockerApi() { + DockerApi docker = mock(DockerApi.class); + ImageApi imageApi = mock(ImageApi.class); + ContainerApi containerApi = mock(ContainerApi.class); + VolumeApi volumeApi = mock(VolumeApi.class); + given(docker.image()).willReturn(imageApi); + given(docker.container()).willReturn(containerApi); + given(docker.volume()).willReturn(volumeApi); + return docker; + } + private BuildRequest getTestRequest() { TarArchive content = mock(TarArchive.class); ImageReference name = ImageReference.of("my-application"); - BuildRequest request = BuildRequest.of(name, (owner) -> content); - return request; + return BuildRequest.of(name, (owner) -> content); + } + + private Lifecycle createLifecycle() throws IOException { + return createLifecycle("0.6"); + } + + private Lifecycle createLifecycle(String version) throws IOException { + return createLifecycle(getTestRequest(), version); } private Lifecycle createLifecycle(BuildRequest request) throws IOException { - EphemeralBuilder builder = mockEphemeralBuilder(); + return createLifecycle(request, "0.6"); + } + + private Lifecycle createLifecycle(BuildRequest request, String version) throws IOException { + EphemeralBuilder builder = mockEphemeralBuilder((version != null) ? version : "0.5"); return new TestLifecycle(BuildLog.to(this.out), this.docker, request, ImageReference.of("cloudfoundry/run"), builder); } - private EphemeralBuilder mockEphemeralBuilder() throws IOException { + private EphemeralBuilder mockEphemeralBuilder(String version) throws IOException { EphemeralBuilder builder = mock(EphemeralBuilder.class); - byte[] metadataContent = FileCopyUtils.copyToByteArray(getClass().getResourceAsStream("builder-metadata.json")); + byte[] metadataContent = FileCopyUtils + .copyToByteArray(getClass().getResourceAsStream("builder-metadata-version-" + version + ".json")); BuilderMetadata metadata = BuilderMetadata.fromJson(new String(metadataContent, StandardCharsets.UTF_8)); given(builder.getName()).willReturn(ImageReference.of("pack.local/ephemeral-builder")); given(builder.getBuilderMetadata()).willReturn(metadata); @@ -201,6 +226,11 @@ class LifecycleTests { configConsumer.accept(this.configs.get(containerReference.toString())); } + private void assertPhaseWasNotRun(String name) { + ContainerReference containerReference = ContainerReference.of("lifecycle-" + name); + assertThat(this.configs.get(containerReference.toString())).isNull(); + } + private IOConsumer withExpectedConfig(String name) { return (config) -> { InputStream in = getClass().getResourceAsStream(name); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-version-0.5.json similarity index 100% rename from spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata.json rename to spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-version-0.5.json diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-version-0.6.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-version-0.6.json new file mode 100644 index 0000000000..1844135420 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-version-0.6.json @@ -0,0 +1,222 @@ +{ + "description": "Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang", + "buildpacks": [ + { + "id": "org.cloudfoundry.debug", + "version": "v1.0.106", + "latest": true + }, + { + "id": "org.cloudfoundry.go", + "version": "v0.0.2", + "latest": true + }, + { + "id": "org.cloudfoundry.springautoreconfiguration", + "version": "v1.0.113", + "latest": true + }, + { + "id": "org.cloudfoundry.buildsystem", + "version": "v1.0.133", + "latest": true + }, + { + "id": "org.cloudfoundry.procfile", + "version": "v1.0.41", + "latest": true + }, + { + "id": "org.cloudfoundry.nodejs", + "version": "v0.0.5", + "latest": true + }, + { + "id": "org.cloudfoundry.distzip", + "version": "v1.0.101", + "latest": true + }, + { + "id": "org.cloudfoundry.jdbc", + "version": "v1.0.107", + "latest": true + }, + { + "id": "org.cloudfoundry.azureapplicationinsights", + "version": "v1.0.105", + "latest": true + }, + { + "id": "org.cloudfoundry.springboot", + "version": "v1.0.112", + "latest": true + }, + { + "id": "org.cloudfoundry.openjdk", + "version": "v1.0.58", + "latest": true + }, + { + "id": "org.cloudfoundry.tomcat", + "version": "v1.1.24", + "latest": true + }, + { + "id": "org.cloudfoundry.googlestackdriver", + "version": "v1.0.54", + "latest": true + }, + { + "id": "org.cloudfoundry.jmx", + "version": "v1.0.107", + "latest": true + }, + { + "id": "org.cloudfoundry.archiveexpanding", + "version": "v1.0.99", + "latest": true + }, + { + "id": "org.cloudfoundry.jvmapplication", + "version": "v1.0.82", + "latest": true + }, + { + "id": "org.cloudfoundry.dep", + "version": "0.0.64", + "latest": true + }, + { + "id": "org.cloudfoundry.go-compiler", + "version": "0.0.55", + "latest": true + }, + { + "id": "org.cloudfoundry.go-mod", + "version": "0.0.58", + "latest": true + }, + { + "id": "org.cloudfoundry.node-engine", + "version": "0.0.102", + "latest": true + }, + { + "id": "org.cloudfoundry.npm", + "version": "0.0.63", + "latest": true + }, + { + "id": "org.cloudfoundry.yarn", + "version": "0.0.69", + "latest": true + } + ], + "groups": [ + { + "buildpacks": [ + { + "id": "org.cloudfoundry.archiveexpanding", + "version": "v1.0.99", + "optional": true + }, + { + "id": "org.cloudfoundry.openjdk", + "version": "v1.0.58" + }, + { + "id": "org.cloudfoundry.buildsystem", + "version": "v1.0.133", + "optional": true + }, + { + "id": "org.cloudfoundry.jvmapplication", + "version": "v1.0.82" + }, + { + "id": "org.cloudfoundry.tomcat", + "version": "v1.1.24", + "optional": true + }, + { + "id": "org.cloudfoundry.springboot", + "version": "v1.0.112", + "optional": true + }, + { + "id": "org.cloudfoundry.distzip", + "version": "v1.0.101", + "optional": true + }, + { + "id": "org.cloudfoundry.procfile", + "version": "v1.0.41", + "optional": true + }, + { + "id": "org.cloudfoundry.azureapplicationinsights", + "version": "v1.0.105", + "optional": true + }, + { + "id": "org.cloudfoundry.debug", + "version": "v1.0.106", + "optional": true + }, + { + "id": "org.cloudfoundry.googlestackdriver", + "version": "v1.0.54", + "optional": true + }, + { + "id": "org.cloudfoundry.jdbc", + "version": "v1.0.107", + "optional": true + }, + { + "id": "org.cloudfoundry.jmx", + "version": "v1.0.107", + "optional": true + }, + { + "id": "org.cloudfoundry.springautoreconfiguration", + "version": "v1.0.113", + "optional": true + } + ] + }, + { + "buildpacks": [ + { + "id": "org.cloudfoundry.nodejs", + "version": "v0.0.5" + } + ] + }, + { + "buildpacks": [ + { + "id": "org.cloudfoundry.go", + "version": "v0.0.2" + } + ] + } + ], + "stack": { + "runImage": { + "image": "cloudfoundry/run:base-cnb", + "mirrors": null + } + }, + "lifecycle": { + "version": "0.6.0", + "api": { + "buildpack": "0.2", + "platform": "0.2" + } + }, + "createdBy": { + "name": "Pack CLI", + "version": "dev-2019-11-19-22:34:59" + } +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-0.1.json similarity index 100% rename from spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer.json rename to spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-0.1.json diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-0.2.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-0.2.json new file mode 100644 index 0000000000..5b86308adf --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-0.2.json @@ -0,0 +1,11 @@ +{ + "User" : "root", + "Image" : "pack.local/ephemeral-builder", + "Cmd" : [ "/lifecycle/analyzer", "-daemon", "-layers", "/layers", "-cache-dir", "/cache", "docker.io/library/my-application:latest" ], + "Labels" : { + "author" : "spring-boot" + }, + "HostConfig" : { + "Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache" ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-0.1.json similarity index 100% rename from spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter.json rename to spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-0.1.json diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-0.2.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-0.2.json new file mode 100644 index 0000000000..840eea6c66 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-0.2.json @@ -0,0 +1,11 @@ +{ + "User" : "root", + "Image" : "pack.local/ephemeral-builder", + "Cmd" : [ "/lifecycle/exporter", "-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-app", "/workspace", "-daemon", "-launch-cache", "/launch-cache", "-cache-dir", "/cache", "docker.io/library/my-application:latest" ], + "Labels" : { + "author" : "spring-boot" + }, + "HostConfig" : { + "Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.launch:/launch-cache", "pack-cache-b35197ac41ea.build:/cache" ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-0.1.json similarity index 100% rename from spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer.json rename to spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-0.1.json diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-0.2.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-0.2.json new file mode 100644 index 0000000000..6aab9fb629 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-0.2.json @@ -0,0 +1,11 @@ +{ + "User" : "root", + "Image" : "pack.local/ephemeral-builder", + "Cmd" : [ "/lifecycle/restorer", "-cache-dir", "/cache", "-layers", "/layers" ], + "Labels" : { + "author" : "spring-boot" + }, + "HostConfig" : { + "Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache" ] + } +} \ No newline at end of file