mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Merge branch '3.2.x'
Closes gh-41091
This commit is contained in:
commit
84956ad56b
@ -20,7 +20,6 @@ import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.BuilderMetadata.Stack;
|
||||
import org.springframework.boot.buildpack.platform.docker.DockerApi;
|
||||
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
|
||||
import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;
|
||||
@ -103,7 +102,7 @@ public class Builder {
|
||||
ImageFetcher imageFetcher = new ImageFetcher(domain, getBuilderAuthHeader(), pullPolicy);
|
||||
Image builderImage = imageFetcher.fetchImage(ImageType.BUILDER, request.getBuilder());
|
||||
BuilderMetadata builderMetadata = BuilderMetadata.fromImage(builderImage);
|
||||
request = withRunImageIfNeeded(request, builderMetadata.getStack());
|
||||
request = withRunImageIfNeeded(request, builderMetadata);
|
||||
Image runImage = imageFetcher.fetchImage(ImageType.RUNNER, request.getRunImage());
|
||||
assertStackIdsMatch(runImage, builderImage);
|
||||
BuildOwner buildOwner = BuildOwner.fromEnv(builderImage.getConfig().getEnv());
|
||||
@ -124,24 +123,30 @@ public class Builder {
|
||||
}
|
||||
}
|
||||
|
||||
private BuildRequest withRunImageIfNeeded(BuildRequest request, Stack builderStack) {
|
||||
private BuildRequest withRunImageIfNeeded(BuildRequest request, BuilderMetadata metadata) {
|
||||
if (request.getRunImage() != null) {
|
||||
return request;
|
||||
}
|
||||
return request.withRunImage(getRunImageReferenceForStack(builderStack));
|
||||
return request.withRunImage(getRunImageReference(metadata));
|
||||
}
|
||||
|
||||
private ImageReference getRunImageReferenceForStack(Stack stack) {
|
||||
String name = stack.getRunImage().getImage();
|
||||
Assert.state(StringUtils.hasText(name), "Run image must be specified in the builder image stack");
|
||||
return ImageReference.of(name).inTaggedOrDigestForm();
|
||||
private ImageReference getRunImageReference(BuilderMetadata metadata) {
|
||||
if (metadata.getRunImages() != null && !metadata.getRunImages().isEmpty()) {
|
||||
String runImageName = metadata.getRunImages().get(0).getImage();
|
||||
return ImageReference.of(runImageName).inTaggedOrDigestForm();
|
||||
}
|
||||
String runImageName = metadata.getStack().getRunImage().getImage();
|
||||
Assert.state(StringUtils.hasText(runImageName), "Run image must be specified in the builder image metadata");
|
||||
return ImageReference.of(runImageName).inTaggedOrDigestForm();
|
||||
}
|
||||
|
||||
private void assertStackIdsMatch(Image runImage, Image builderImage) {
|
||||
StackId runImageStackId = StackId.fromImage(runImage);
|
||||
StackId builderImageStackId = StackId.fromImage(builderImage);
|
||||
Assert.state(runImageStackId.equals(builderImageStackId), () -> "Run image stack '" + runImageStackId
|
||||
+ "' does not match builder stack '" + builderImageStackId + "'");
|
||||
if (runImageStackId.hasId() && builderImageStackId.hasId()) {
|
||||
Assert.state(runImageStackId.equals(builderImageStackId), () -> "Run image stack '" + runImageStackId
|
||||
+ "' does not match builder stack '" + builderImageStackId + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private Buildpacks getBuildpacks(BuildRequest request, ImageFetcher imageFetcher, BuilderMetadata builderMetadata,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@ -49,6 +49,8 @@ class BuilderMetadata extends MappedObject {
|
||||
|
||||
private final Stack stack;
|
||||
|
||||
private final List<RunImage> runImages;
|
||||
|
||||
private final Lifecycle lifecycle;
|
||||
|
||||
private final CreatedBy createdBy;
|
||||
@ -58,6 +60,7 @@ class BuilderMetadata extends MappedObject {
|
||||
BuilderMetadata(JsonNode node) {
|
||||
super(node, MethodHandles.lookup());
|
||||
this.stack = valueAt("/stack", Stack.class);
|
||||
this.runImages = childrenAt("/images", RunImage::new);
|
||||
this.lifecycle = valueAt("/lifecycle", Lifecycle.class);
|
||||
this.createdBy = valueAt("/createdBy", CreatedBy.class);
|
||||
this.buildpacks = extractBuildpacks(getNode().at("/buildpacks"));
|
||||
@ -80,6 +83,14 @@ class BuilderMetadata extends MappedObject {
|
||||
return this.stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return run images metadata.
|
||||
* @return the run images metadata
|
||||
*/
|
||||
List<RunImage> getRunImages() {
|
||||
return this.runImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return lifecycle metadata.
|
||||
* @return the lifecycle metadata
|
||||
@ -196,6 +207,32 @@ class BuilderMetadata extends MappedObject {
|
||||
|
||||
}
|
||||
|
||||
static class RunImage extends MappedObject {
|
||||
|
||||
private final String image;
|
||||
|
||||
private final List<String> mirrors;
|
||||
|
||||
/**
|
||||
* Create a new {@link MappedObject} instance.
|
||||
* @param node the source node
|
||||
*/
|
||||
RunImage(JsonNode node) {
|
||||
super(node, MethodHandles.lookup());
|
||||
this.image = valueAt("/image", String.class);
|
||||
this.mirrors = childrenAt("/mirrors", JsonNode::asText);
|
||||
}
|
||||
|
||||
String getImage() {
|
||||
return this.image;
|
||||
}
|
||||
|
||||
List<String> getMirrors() {
|
||||
return this.mirrors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle metadata.
|
||||
*/
|
||||
|
@ -19,7 +19,6 @@ package org.springframework.boot.buildpack.platform.build;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A Stack ID.
|
||||
@ -48,6 +47,10 @@ class StackId {
|
||||
return this.value.equals(((StackId) obj).value);
|
||||
}
|
||||
|
||||
boolean hasId() {
|
||||
return this.value != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
@ -75,7 +78,6 @@ class StackId {
|
||||
*/
|
||||
private static StackId fromImageConfig(ImageConfig imageConfig) {
|
||||
String value = imageConfig.getLabels().get(LABEL_NAME);
|
||||
Assert.state(StringUtils.hasText(value), () -> "Missing '" + LABEL_NAME + "' stack label");
|
||||
return new StackId(value);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@ -21,6 +21,7 @@ import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.build.BuilderMetadata.RunImage;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
||||
@ -46,6 +47,29 @@ class BuilderMetadataTests extends AbstractJsonTests {
|
||||
BuilderMetadata metadata = BuilderMetadata.fromImage(image);
|
||||
assertThat(metadata.getStack().getRunImage().getImage()).isEqualTo("cloudfoundry/run:base-cnb");
|
||||
assertThat(metadata.getStack().getRunImage().getMirrors()).isEmpty();
|
||||
assertThat(metadata.getRunImages()).isEmpty();
|
||||
assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.7.2");
|
||||
assertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo("0.2");
|
||||
assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.3");
|
||||
assertThat(metadata.getCreatedBy().getName()).isEqualTo("Pack CLI");
|
||||
assertThat(metadata.getCreatedBy().getVersion())
|
||||
.isEqualTo("v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)");
|
||||
assertThat(metadata.getBuildpacks()).extracting(BuildpackMetadata::getId, BuildpackMetadata::getVersion)
|
||||
.contains(tuple("paketo-buildpacks/java", "4.10.0"))
|
||||
.contains(tuple("paketo-buildpacks/spring-boot", "3.5.0"))
|
||||
.contains(tuple("paketo-buildpacks/executable-jar", "3.1.3"))
|
||||
.contains(tuple("paketo-buildpacks/graalvm", "4.1.0"))
|
||||
.contains(tuple("paketo-buildpacks/java-native-image", "4.7.0"))
|
||||
.contains(tuple("paketo-buildpacks/spring-boot-native-image", "2.0.1"))
|
||||
.contains(tuple("paketo-buildpacks/bellsoft-liberica", "6.2.0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromImageWithoutStackLoadsMetadata() throws IOException {
|
||||
Image image = Image.of(getContent("image-with-empty-stack.json"));
|
||||
BuilderMetadata metadata = BuilderMetadata.fromImage(image);
|
||||
assertThat(metadata.getRunImages()).extracting(RunImage::getImage, RunImage::getMirrors)
|
||||
.contains(tuple("cloudfoundry/run:base-cnb", Collections.emptyList()));
|
||||
assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.7.2");
|
||||
assertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo("0.2");
|
||||
assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.3");
|
||||
|
@ -185,6 +185,26 @@ class BuilderTests {
|
||||
then(docker.image()).should().remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildInvokesBuilderWithNoStack() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
DockerApi docker = mockDockerApi();
|
||||
Image builderImage = loadImage("image-with-empty-stack.json");
|
||||
Image runImage = loadImage("run-image.json");
|
||||
given(docker.image().pull(eq(ImageReference.of("gcr.io/paketo-buildpacks/builder:latest")), any(), isNull()))
|
||||
.willAnswer(withPulledImage(builderImage));
|
||||
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any(), isNull()))
|
||||
.willAnswer(withPulledImage(runImage));
|
||||
Builder builder = new Builder(BuildLog.to(out), docker, null);
|
||||
BuildRequest request = getTestRequest().withBuilder(ImageReference.of("gcr.io/paketo-buildpacks/builder"));
|
||||
builder.build(request);
|
||||
assertThat(out.toString()).contains("Running creator");
|
||||
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
|
||||
then(docker.image()).should().load(archive.capture(), any());
|
||||
then(docker.image()).should().remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildInvokesBuilderWithRunImageFromRequest() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
|
@ -25,7 +25,6 @@ import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@ -43,12 +42,12 @@ class StackIdTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromImageWhenLabelIsMissingThrowsException() {
|
||||
void fromImageWhenLabelIsMissingHasNoId() {
|
||||
Image image = mock(Image.class);
|
||||
ImageConfig imageConfig = mock(ImageConfig.class);
|
||||
given(image.getConfig()).willReturn(imageConfig);
|
||||
assertThatIllegalStateException().isThrownBy(() -> StackId.fromImage(image))
|
||||
.withMessage("Missing 'io.buildpacks.stack.id' stack label");
|
||||
StackId stackId = StackId.fromImage(image);
|
||||
assertThat(stackId.hasId()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -59,6 +58,7 @@ class StackIdTests {
|
||||
given(imageConfig.getLabels()).willReturn(Collections.singletonMap("io.buildpacks.stack.id", "test"));
|
||||
StackId stackId = StackId.fromImage(image);
|
||||
assertThat(stackId).hasToString("test");
|
||||
assertThat(stackId.hasId()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user