Skip to content

Commit a01c845

Browse files
Support CNB builder platform API 0.3
This commit adds support for Cloud Native Buildpacks builder platform API 0.3, which is the latest platform API available currently. Support for platform API 0.1 has been removed, adopting the policy of the pack CLI to support the current platform API version and one version prior. Fixes gh-20757
1 parent bb9e37e commit a01c845

File tree

22 files changed

+289
-758
lines changed

22 files changed

+289
-758
lines changed

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersion.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
*/
3030
final class ApiVersion {
3131

32-
private static final ApiVersion PLATFORM_0_1 = new ApiVersion(0, 1);
33-
3432
private static final Pattern PATTERN = Pattern.compile("^v?(\\d+)\\.(\\d*)$");
3533

3634
private final int major;
@@ -88,25 +86,6 @@ boolean supports(ApiVersion other) {
8886
return this.minor >= other.minor;
8987
}
9088

91-
/**
92-
* Returns a value indicating whether the API version has a separate cache phase, or
93-
* caching is distributed across other stages.
94-
* @return {@code true} if the API has a separate cache phase, {@code false} otherwise
95-
*/
96-
boolean hasCachePhase() {
97-
return supports(PLATFORM_0_1);
98-
}
99-
100-
/**
101-
* Returns a value indicating whether the API version requires that the analyze phase
102-
* must follow the restore phase, or if the reverse order is required.
103-
* @return {@code true} if the analyze phase follows restore, {@code false} if restore
104-
* follows analyze
105-
*/
106-
boolean analyzeFollowsRestore() {
107-
return supports(PLATFORM_0_1);
108-
}
109-
11089
@Override
11190
public boolean equals(Object obj) {
11291
if (this == obj) {

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ final class ApiVersions {
3232
/**
3333
* The platform API versions supported by this release.
3434
*/
35-
static final ApiVersions SUPPORTED_PLATFORMS = new ApiVersions(ApiVersion.of(0, 1), ApiVersion.of(0, 2));
35+
static final ApiVersions SUPPORTED_PLATFORMS = new ApiVersions(ApiVersion.of(0, 2), ApiVersion.of(0, 3));
3636

3737
private final ApiVersion[] apiVersions;
3838

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,10 @@ void execute() throws IOException {
115115
deleteVolume(this.buildCacheVolume);
116116
}
117117
run(detectPhase());
118-
if (this.platformVersion.analyzeFollowsRestore()) {
119-
run(restorePhase());
120-
run(analyzePhase());
121-
}
122-
else {
123-
run(analyzePhase());
124-
run(restorePhase());
125-
}
118+
run(analyzePhase());
119+
run(restorePhase());
126120
run(buildPhase());
127121
run(exportPhase());
128-
if (this.platformVersion.hasCachePhase()) {
129-
run(cachePhase());
130-
}
131122
this.log.executedLifecycle(this.request);
132123
}
133124

@@ -140,10 +131,9 @@ private Phase detectPhase() {
140131
}
141132

142133
private Phase restorePhase() {
143-
String cacheDirArg = this.platformVersion.hasCachePhase() ? "-path" : "-cache-dir";
144134
Phase phase = createPhase("restorer");
145135
phase.withDaemonAccess();
146-
phase.withArgs(cacheDirArg, Folder.CACHE);
136+
phase.withArgs("-cache-dir", Folder.CACHE);
147137
phase.withArgs("-layers", Folder.LAYERS);
148138
phase.withLogLevelArg();
149139
phase.withBinds(this.buildCacheVolume, Folder.CACHE);
@@ -159,13 +149,9 @@ private Phase analyzePhase() {
159149
}
160150
phase.withArgs("-daemon");
161151
phase.withArgs("-layers", Folder.LAYERS);
162-
if (!this.platformVersion.hasCachePhase()) {
163-
phase.withArgs("-cache-dir", Folder.CACHE);
164-
}
152+
phase.withArgs("-cache-dir", Folder.CACHE);
165153
phase.withArgs(this.request.getName());
166-
if (!this.platformVersion.hasCachePhase()) {
167-
phase.withBinds(this.buildCacheVolume, Folder.CACHE);
168-
}
154+
phase.withBinds(this.buildCacheVolume, Folder.CACHE);
169155
return phase;
170156
}
171157

@@ -186,23 +172,9 @@ private Phase exportPhase() {
186172
phase.withArgs("-app", Folder.APPLICATION);
187173
phase.withArgs("-daemon");
188174
phase.withArgs("-launch-cache", Folder.LAUNCH_CACHE);
189-
if (!this.platformVersion.hasCachePhase()) {
190-
phase.withArgs("-cache-dir", Folder.CACHE);
191-
}
175+
phase.withArgs("-cache-dir", Folder.CACHE);
192176
phase.withArgs(this.request.getName());
193177
phase.withBinds(this.launchCacheVolume, Folder.LAUNCH_CACHE);
194-
if (!this.platformVersion.hasCachePhase()) {
195-
phase.withBinds(this.buildCacheVolume, Folder.CACHE);
196-
}
197-
return phase;
198-
}
199-
200-
private Phase cachePhase() {
201-
Phase phase = createPhase("cacher");
202-
phase.withDaemonAccess();
203-
phase.withArgs("-path", Folder.CACHE);
204-
phase.withArgs("-layers", Folder.LAYERS);
205-
phase.withLogLevelArg();
206178
phase.withBinds(this.buildCacheVolume, Folder.CACHE);
207179
return phase;
208180
}

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderMetadataTests.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,22 @@
3333
* Tests for {@link BuilderMetadata}.
3434
*
3535
* @author Phillip Webb
36+
* @author Scott Frederick
3637
*/
3738
class BuilderMetadataTests extends AbstractJsonTests {
3839

3940
@Test
4041
void fromImageLoadsMetadata() throws IOException {
4142
Image image = Image.of(getContent("image.json"));
4243
BuilderMetadata metadata = BuilderMetadata.fromImage(image);
43-
assertThat(metadata.getStack().getRunImage().getImage()).isEqualTo("cloudfoundry/run:full-cnb");
44+
assertThat(metadata.getStack().getRunImage().getImage()).isEqualTo("cloudfoundry/run:base-cnb");
4445
assertThat(metadata.getStack().getRunImage().getMirrors()).isEmpty();
45-
assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.5.0");
46+
assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.7.2");
4647
assertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo("0.2");
47-
assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.1");
48+
assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.3");
4849
assertThat(metadata.getCreatedBy().getName()).isEqualTo("Pack CLI");
4950
assertThat(metadata.getCreatedBy().getVersion())
50-
.isEqualTo("v0.5.0 (git sha: c9cfac75b49609524e1ea33f809c12071406547c)");
51+
.isEqualTo("v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)");
5152
}
5253

5354
@Test

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void buildInvokesBuilder() throws Exception {
7474
Image runImage = loadImage("run-image.json");
7575
given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
7676
.willAnswer(withPulledImage(builderImage));
77-
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
77+
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any()))
7878
.willAnswer(withPulledImage(runImage));
7979
Builder builder = new Builder(BuildLog.to(out), docker);
8080
BuildRequest request = getTestRequest();
@@ -84,7 +84,6 @@ void buildInvokesBuilder() throws Exception {
8484
assertThat(out.toString()).contains("Running analyzer");
8585
assertThat(out.toString()).contains("Running builder");
8686
assertThat(out.toString()).contains("Running exporter");
87-
assertThat(out.toString()).contains("Running cacher");
8887
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
8988
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
9089
verify(docker.image()).load(archive.capture(), any());
@@ -99,12 +98,12 @@ void buildWhenStackIdDoesNotMatchThrowsException() throws Exception {
9998
Image runImage = loadImage("run-image-with-bad-stack.json");
10099
given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
101100
.willAnswer(withPulledImage(builderImage));
102-
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
101+
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any()))
103102
.willAnswer(withPulledImage(runImage));
104103
Builder builder = new Builder(BuildLog.to(out), docker);
105104
BuildRequest request = getTestRequest();
106105
assertThatIllegalStateException().isThrownBy(() -> builder.build(request)).withMessage(
107-
"Run image stack 'org.cloudfoundry.stacks.cfwindowsfs3' does not match builder stack 'org.cloudfoundry.stacks.cflinuxfs3'");
106+
"Run image stack 'org.cloudfoundry.stacks.cfwindowsfs3' does not match builder stack 'io.buildpacks.stacks.bionic'");
108107
}
109108

110109
@Test
@@ -115,7 +114,7 @@ void buildWhenBuilderReturnsErrorThrowsException() throws Exception {
115114
Image runImage = loadImage("run-image.json");
116115
given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
117116
.willAnswer(withPulledImage(builderImage));
118-
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
117+
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any()))
119118
.willAnswer(withPulledImage(runImage));
120119
Builder builder = new Builder(BuildLog.to(out), docker);
121120
BuildRequest request = getTestRequest();

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -79,32 +79,16 @@ void setup() {
7979
}
8080

8181
@Test
82-
void executeExecutesPhasesWithCacherPhase() throws Exception {
82+
void executeExecutesPhases() throws Exception {
8383
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
8484
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
8585
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
86-
createLifecycle("0.5").execute();
87-
assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json"));
88-
assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-0.1.json"));
89-
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-0.1.json"));
90-
assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json"));
91-
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-0.1.json"));
92-
assertPhaseWasRun("cacher", withExpectedConfig("lifecycle-cacher.json"));
93-
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
94-
}
95-
96-
@Test
97-
void executeExecutesPhasesWithEmbeddedCaching() throws Exception {
98-
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
99-
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
100-
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
101-
createLifecycle("0.6").execute();
86+
createLifecycle().execute();
10287
assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json"));
103-
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-0.2.json"));
104-
assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-0.2.json"));
88+
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json"));
89+
assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json"));
10590
assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json"));
106-
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-0.2.json"));
107-
assertPhaseWasNotRun("cacher");
91+
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json"));
10892
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
10993
}
11094

@@ -173,27 +157,18 @@ private BuildRequest getTestRequest() {
173157
}
174158

175159
private Lifecycle createLifecycle() throws IOException {
176-
return createLifecycle("0.6");
177-
}
178-
179-
private Lifecycle createLifecycle(String version) throws IOException {
180-
return createLifecycle(getTestRequest(), version);
160+
return createLifecycle(getTestRequest());
181161
}
182162

183163
private Lifecycle createLifecycle(BuildRequest request) throws IOException {
184-
return createLifecycle(request, "0.6");
185-
}
186-
187-
private Lifecycle createLifecycle(BuildRequest request, String version) throws IOException {
188-
EphemeralBuilder builder = mockEphemeralBuilder((version != null) ? version : "0.5");
164+
EphemeralBuilder builder = mockEphemeralBuilder();
189165
return new TestLifecycle(BuildLog.to(this.out), this.docker, request, ImageReference.of("cloudfoundry/run"),
190166
builder);
191167
}
192168

193-
private EphemeralBuilder mockEphemeralBuilder(String version) throws IOException {
169+
private EphemeralBuilder mockEphemeralBuilder() throws IOException {
194170
EphemeralBuilder builder = mock(EphemeralBuilder.class);
195-
byte[] metadataContent = FileCopyUtils
196-
.copyToByteArray(getClass().getResourceAsStream("builder-metadata-version-" + version + ".json"));
171+
byte[] metadataContent = FileCopyUtils.copyToByteArray(getClass().getResourceAsStream("builder-metadata.json"));
197172
BuilderMetadata metadata = BuilderMetadata.fromJson(new String(metadataContent, StandardCharsets.UTF_8));
198173
given(builder.getName()).willReturn(ImageReference.of("pack.local/ephemeral-builder"));
199174
given(builder.getBuilderMetadata()).willReturn(metadata);
@@ -226,11 +201,6 @@ private void assertPhaseWasRun(String name, IOConsumer<ContainerConfig> configCo
226201
configConsumer.accept(this.configs.get(containerReference.toString()));
227202
}
228203

229-
private void assertPhaseWasNotRun(String name) {
230-
ContainerReference containerReference = ContainerReference.of("lifecycle-" + name);
231-
assertThat(this.configs.get(containerReference.toString())).isNull();
232-
}
233-
234204
private IOConsumer<ContainerConfig> withExpectedConfig(String name) {
235205
return (config) -> {
236206
InputStream in = getClass().getResourceAsStream(name);

0 commit comments

Comments
 (0)