Skip to content

Commit 35bc82a

Browse files
Use CNB creator all-in-one lifecycle
This commit modifies the buildpack platform invocation logic used by the build plugins to invoke the single creator lifecycle introduced in the CNB API 0.3, instead of invoking discrete lifecycle phases separately. It also removes support for CNB API 0.2. Fixes gh-21273
1 parent d067cc6 commit 35bc82a

File tree

17 files changed

+62
-172
lines changed

17 files changed

+62
-172
lines changed

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, 2), ApiVersion.of(0, 3));
35+
static final ApiVersions SUPPORTED_PLATFORMS = new ApiVersions(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: 13 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -115,85 +115,34 @@ void execute() throws IOException {
115115
if (this.request.isCleanCache()) {
116116
deleteVolume(this.buildCacheVolume);
117117
}
118-
run(detectPhase());
119-
run(analyzePhase());
120-
if (this.request.isCleanCache()) {
121-
this.log.skippingPhase("restorer", "due to cleaning cache");
122-
}
123-
else {
124-
run(restorePhase());
125-
}
126-
run(buildPhase());
127-
run(exportPhase());
118+
run(createPhase());
128119
this.log.executedLifecycle(this.request);
129120
}
130121

131-
private Phase detectPhase() {
132-
Phase phase = createPhase("detector");
122+
private Phase createPhase() {
123+
Phase phase = new Phase("creator", isVerboseLogging());
124+
phase.withDaemonAccess();
125+
phase.withLogLevelArg();
133126
phase.withArgs("-app", Directory.APPLICATION);
134127
phase.withArgs("-platform", Directory.PLATFORM);
135-
phase.withLogLevelArg();
136-
return phase;
137-
}
138-
139-
private Phase restorePhase() {
140-
Phase phase = createPhase("restorer");
141-
phase.withDaemonAccess();
142-
phase.withArgs("-cache-dir", Directory.CACHE);
128+
phase.withArgs("-run-image", this.runImageReference);
143129
phase.withArgs("-layers", Directory.LAYERS);
144-
phase.withLogLevelArg();
145-
phase.withBinds(this.buildCacheVolume, Directory.CACHE);
146-
return phase;
147-
}
148-
149-
private Phase analyzePhase() {
150-
Phase phase = createPhase("analyzer");
151-
phase.withDaemonAccess();
152-
phase.withLogLevelArg();
130+
phase.withArgs("-cache-dir", Directory.CACHE);
131+
phase.withArgs("-launch-cache", Directory.LAUNCH_CACHE);
153132
phase.withArgs("-daemon");
154133
if (this.request.isCleanCache()) {
155-
phase.withArgs("-skip-layers");
156-
}
157-
else {
158-
phase.withArgs("-cache-dir", Directory.CACHE);
134+
phase.withArgs("-skip-restore");
159135
}
160-
phase.withArgs("-layers", Directory.LAYERS);
161136
phase.withArgs(this.request.getName());
137+
phase.withBinds(this.layersVolume, Directory.LAYERS);
138+
phase.withBinds(this.applicationVolume, Directory.APPLICATION);
162139
phase.withBinds(this.buildCacheVolume, Directory.CACHE);
163-
return phase;
164-
}
165-
166-
private Phase buildPhase() {
167-
Phase phase = createPhase("builder");
168-
phase.withArgs("-layers", Directory.LAYERS);
169-
phase.withArgs("-app", Directory.APPLICATION);
170-
phase.withArgs("-platform", Directory.PLATFORM);
171-
return phase;
172-
}
173-
174-
private Phase exportPhase() {
175-
Phase phase = createPhase("exporter");
176-
phase.withDaemonAccess();
177-
phase.withLogLevelArg();
178-
phase.withArgs("-image", this.runImageReference);
179-
phase.withArgs("-layers", Directory.LAYERS);
180-
phase.withArgs("-app", Directory.APPLICATION);
181-
phase.withArgs("-daemon");
182-
phase.withArgs("-launch-cache", Directory.LAUNCH_CACHE);
183-
phase.withArgs("-cache-dir", Directory.CACHE);
184-
phase.withArgs(this.request.getName());
185140
phase.withBinds(this.launchCacheVolume, Directory.LAUNCH_CACHE);
186-
phase.withBinds(this.buildCacheVolume, Directory.CACHE);
187141
return phase;
188142
}
189143

190-
private Phase createPhase(String name) {
191-
boolean verboseLogging = this.request.isVerboseLogging()
192-
&& this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION);
193-
Phase phase = new Phase(name, verboseLogging);
194-
phase.withBinds(this.layersVolume, Directory.LAYERS);
195-
phase.withBinds(this.applicationVolume, Directory.APPLICATION);
196-
return phase;
144+
private boolean isVerboseLogging() {
145+
return this.request.isVerboseLogging() && this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION);
197146
}
198147

199148
private void run(Phase phase) throws IOException {

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,7 @@ void buildInvokesBuilder() throws Exception {
7979
Builder builder = new Builder(BuildLog.to(out), docker);
8080
BuildRequest request = getTestRequest();
8181
builder.build(request);
82-
assertThat(out.toString()).contains("Running detector");
83-
assertThat(out.toString()).contains("Running restorer");
84-
assertThat(out.toString()).contains("Running analyzer");
85-
assertThat(out.toString()).contains("Running builder");
86-
assertThat(out.toString()).contains("Running exporter");
82+
assertThat(out.toString()).contains("Running creator");
8783
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
8884
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
8985
verify(docker.image()).load(archive.capture(), any());
@@ -119,7 +115,7 @@ void buildWhenBuilderReturnsErrorThrowsException() throws Exception {
119115
Builder builder = new Builder(BuildLog.to(out), docker);
120116
BuildRequest request = getTestRequest();
121117
assertThatExceptionOfType(BuilderException.class).isThrownBy(() -> builder.build(request))
122-
.withMessage("Builder lifecycle 'detector' failed with status code 9");
118+
.withMessage("Builder lifecycle 'creator' failed with status code 9");
123119
}
124120

125121
private DockerApi mockDockerApi() throws IOException {

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

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ class LifecycleTests {
6868

6969
private DockerApi docker;
7070

71-
private Map<String, ContainerConfig> configs = new LinkedHashMap<>();
71+
private final Map<String, ContainerConfig> configs = new LinkedHashMap<>();
7272

73-
private Map<String, ContainerContent> content = new LinkedHashMap<>();
73+
private final Map<String, ContainerContent> content = new LinkedHashMap<>();
7474

7575
@BeforeEach
7676
void setup() {
@@ -84,11 +84,7 @@ void executeExecutesPhases() throws Exception {
8484
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
8585
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
8686
createLifecycle().execute();
87-
assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json"));
88-
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json"));
89-
assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json"));
90-
assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json"));
91-
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json"));
87+
assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator.json"));
9288
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
9389
}
9490

@@ -118,7 +114,7 @@ void executeWhenBuilderReturnsErrorThrowsException() throws Exception {
118114
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
119115
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(9, null));
120116
assertThatExceptionOfType(BuilderException.class).isThrownBy(() -> createLifecycle().execute())
121-
.withMessage("Builder lifecycle 'detector' failed with status code 9");
117+
.withMessage("Builder lifecycle 'creator' failed with status code 9");
122118
}
123119

124120
@Test
@@ -128,11 +124,7 @@ void executeWhenCleanCacheClearsCache() throws Exception {
128124
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
129125
BuildRequest request = getTestRequest().withCleanCache(true);
130126
createLifecycle(request).execute();
131-
assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json"));
132-
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-clean-cache.json"));
133-
assertPhaseWasNotRun("restorer");
134-
assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json"));
135-
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json"));
127+
assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-clean-cache.json"));
136128
VolumeName name = VolumeName.of("pack-cache-b35197ac41ea.build");
137129
verify(this.docker.volume()).delete(name, true);
138130
}
@@ -206,11 +198,6 @@ private void assertPhaseWasRun(String name, IOConsumer<ContainerConfig> configCo
206198
configConsumer.accept(this.configs.get(containerReference.toString()));
207199
}
208200

209-
private void assertPhaseWasNotRun(String name) {
210-
ContainerReference containerReference = ContainerReference.of("lifecycle-" + name);
211-
assertThat(this.configs.get(containerReference.toString())).isNull();
212-
}
213-
214201
private IOConsumer<ContainerConfig> withExpectedConfig(String name) {
215202
return (config) -> {
216203
InputStream in = getClass().getResourceAsStream(name);

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-clean-cache.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder.json

Lines changed: 0 additions & 10 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"User" : "root",
3+
"Image" : "pack.local/ephemeral-builder",
4+
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-skip-restore", "docker.io/library/my-application:latest" ],
5+
"Labels" : {
6+
"author" : "spring-boot"
7+
},
8+
"HostConfig" : {
9+
"Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" ]
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"User" : "root",
3+
"Image" : "pack.local/ephemeral-builder",
4+
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "docker.io/library/my-application:latest" ],
5+
"Labels" : {
6+
"author" : "spring-boot"
7+
},
8+
"HostConfig" : {
9+
"Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" ]
10+
}
11+
}

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector.json

Lines changed: 0 additions & 10 deletions
This file was deleted.

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,14 @@ void buildsImageWithCustomName() throws IOException {
8989
}
9090

9191
@TestTemplate
92-
void buildsImageWithV2Builder() throws IOException {
92+
void buildsImageWithCustomBuilder() throws IOException {
9393
writeMainClass();
9494
writeLongNameResource();
9595
BuildResult result = this.gradleBuild.build("bootBuildImage");
9696
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
97-
assertThat(result.getOutput()).contains("example/test-image-v2");
98-
assertThat(result.getOutput()).contains("paketo-buildpacks/builder:base-platform-api-0.2");
99-
ImageReference imageReference = ImageReference.of(ImageName.of("example/test-image-v2"));
97+
assertThat(result.getOutput()).contains("example/test-image-custom");
98+
assertThat(result.getOutput()).contains("paketo-buildpacks/builder:full-cf-platform-api-0.3");
99+
ImageReference imageReference = ImageReference.of(ImageName.of("example/test-image-custom"));
100100
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
101101
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
102102
}
@@ -109,12 +109,12 @@ void buildsImageWithV2Builder() throws IOException {
109109
void buildsImageWithCommandLineOptions() throws IOException {
110110
writeMainClass();
111111
writeLongNameResource();
112-
BuildResult result = this.gradleBuild.build("bootBuildImage", "--imageName=example/test-image-v2",
113-
"--builder=gcr.io/paketo-buildpacks/builder:base-platform-api-0.2");
112+
BuildResult result = this.gradleBuild.build("bootBuildImage", "--imageName=example/test-image-cmd",
113+
"--builder=gcr.io/paketo-buildpacks/builder:full-cf-platform-api-0.3");
114114
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
115-
assertThat(result.getOutput()).contains("example/test-image-v2");
116-
assertThat(result.getOutput()).contains("paketo-buildpacks/builder:base-platform-api-0.2");
117-
ImageReference imageReference = ImageReference.of(ImageName.of("example/test-image-v2"));
115+
assertThat(result.getOutput()).contains("example/test-image-cmd");
116+
assertThat(result.getOutput()).contains("paketo-buildpacks/builder:full-cf-platform-api-0.3");
117+
ImageReference imageReference = ImageReference.of(ImageName.of("example/test-image-cmd"));
118118
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
119119
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
120120
}
@@ -129,7 +129,7 @@ void failsWithBuilderError() {
129129
writeLongNameResource();
130130
BuildResult result = this.gradleBuild.buildAndFail("bootBuildImage");
131131
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.FAILED);
132-
assertThat(result.getOutput()).contains("Builder lifecycle 'builder' failed with status code");
132+
assertThat(result.getOutput()).containsPattern("Builder lifecycle '.*' failed with status code");
133133
}
134134

135135
private void writeMainClass() {
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ sourceCompatibility = '1.8'
77
targetCompatibility = '1.8'
88

99
bootBuildImage {
10-
imageName = "example/test-image-v2"
11-
builder = "gcr.io/paketo-buildpacks/builder:base-platform-api-0.2"
10+
imageName = "example/test-image-custom"
11+
builder = "gcr.io/paketo-buildpacks/builder:full-cf-platform-api-0.3"
1212
}

spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ void whenBuildImageIsInvokedWithCommandLineParameters(MavenBuild mavenBuild) {
9494
mavenBuild.project("build-image").goals("package")
9595
.systemProperty("spring-boot.build-image.imageName", "example.com/test/cmd-property-name:v1")
9696
.systemProperty("spring-boot.build-image.builder",
97-
"gcr.io/paketo-buildpacks/builder:base-platform-api-0.2")
97+
"gcr.io/paketo-buildpacks/builder:full-cf-platform-api-0.3")
9898
.execute((project) -> {
9999
assertThat(buildLog(project)).contains("Building image")
100100
.contains("example.com/test/cmd-property-name:v1")
101-
.contains("paketo-buildpacks/builder:base-platform-api-0.2")
101+
.contains("paketo-buildpacks/builder:full-cf-platform-api-0.3")
102102
.contains("Successfully built image");
103103
ImageReference imageReference = ImageReference.of("example.com/test/cmd-property-name:v1");
104104
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
@@ -111,10 +111,10 @@ void whenBuildImageIsInvokedWithCommandLineParameters(MavenBuild mavenBuild) {
111111
}
112112

113113
@TestTemplate
114-
void whenBuildImageIsInvokedWithV2BuilderImage(MavenBuild mavenBuild) {
115-
mavenBuild.project("build-image-v2-builder").goals("package").execute((project) -> {
114+
void whenBuildImageIsInvokedWithCustomBuilderImage(MavenBuild mavenBuild) {
115+
mavenBuild.project("build-image-custom-builder").goals("package").execute((project) -> {
116116
assertThat(buildLog(project)).contains("Building image")
117-
.contains("paketo-buildpacks/builder:base-platform-api-0.2")
117+
.contains("paketo-buildpacks/builder:full-cf-platform-api-0.3")
118118
.contains("docker.io/library/build-image-v2-builder:0.0.1.BUILD-SNAPSHOT")
119119
.contains("Successfully built image");
120120
ImageReference imageReference = ImageReference
@@ -132,7 +132,7 @@ void whenBuildImageIsInvokedWithV2BuilderImage(MavenBuild mavenBuild) {
132132
void failsWhenBuilderFails(MavenBuild mavenBuild) {
133133
mavenBuild.project("build-image-builder-error").goals("package")
134134
.executeAndFail((project) -> assertThat(buildLog(project)).contains("Building image")
135-
.contains("Builder lifecycle 'builder' failed with status code"));
135+
.containsPattern("Builder lifecycle '.*' failed with status code"));
136136
}
137137

138138
private void writeLongNameResource(File project) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</goals>
2424
<configuration>
2525
<image>
26-
<builder>gcr.io/paketo-buildpacks/builder:base-platform-api-0.2</builder>
26+
<builder>gcr.io/paketo-buildpacks/builder:full-cf-platform-api-0.3</builder>
2727
</image>
2828
</configuration>
2929
</execution>

0 commit comments

Comments
 (0)