mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-06 01:09:02 +00:00
Merge pull request #51893 from scottfrederick
Closes gh-51893 * gh-51893: Check distro instead of stack ID for run image
This commit is contained in:
+3
-3
@@ -129,9 +129,9 @@ public abstract class AbstractBuildLog implements BuildLog {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stackIdsDoNotMatch(String runImageStackId, String builderImageStackId) {
|
||||
log("Warning: Run image stack '%s' does not match builder stack '%s'. Stack IDs are deprecated, but the images may not be compatible."
|
||||
.formatted(runImageStackId, builderImageStackId));
|
||||
public void distrosDoNotMatch(String runImageDistro, String builderImageDistro) {
|
||||
log("Warning: Run image distribution '%s' does not match builder distribution '%s'. The images may not be compatible."
|
||||
.formatted(runImageDistro, builderImageDistro));
|
||||
log();
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -136,13 +136,13 @@ public interface BuildLog {
|
||||
void sensitiveTargetBindingDetected(Binding binding);
|
||||
|
||||
/**
|
||||
* Log that the stack ID of the run image does not match the stack ID of the builder
|
||||
* image.
|
||||
* @param runImageStackId the stack ID of the run image
|
||||
* @param builderImageStackId the stack ID of the builder image
|
||||
* Log that the OS distribution of the run image does not match the OS distribution of
|
||||
* the builder image.
|
||||
* @param runImageDistro the OS distribution of the run image
|
||||
* @param builderImageDistro the OS distribution of the builder image
|
||||
* @since 4.0.9
|
||||
*/
|
||||
default void stackIdsDoNotMatch(String runImageStackId, String builderImageStackId) {
|
||||
default void distrosDoNotMatch(String runImageDistro, String builderImageDistro) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-6
@@ -120,7 +120,7 @@ public class Builder {
|
||||
request = request.withRunImage(request.getRunImage().withDigest(runImage.getPrimaryDigest()));
|
||||
runImage = imageFetcher.fetchImage(ImageType.RUNNER, request.getRunImage(), platform);
|
||||
}
|
||||
warnIfStackIdsDoNotMatch(runImage, builderImage);
|
||||
warnIfDistrosDoNotMatch(runImage, builderImage);
|
||||
BuildOwner buildOwner = BuildOwner.fromEnv(builderImage.getConfig().getEnv());
|
||||
BuildpackLayersMetadata buildpackLayersMetadata = BuildpackLayersMetadata.fromImage(builderImage);
|
||||
Buildpacks buildpacks = getBuildpacks(request, imageFetcher, platform, builderMetadata,
|
||||
@@ -159,11 +159,11 @@ public class Builder {
|
||||
return ImageReference.of(runImageName).inTaggedOrDigestForm();
|
||||
}
|
||||
|
||||
private void warnIfStackIdsDoNotMatch(Image runImage, Image builderImage) {
|
||||
StackId runImageStackId = StackId.fromImage(runImage);
|
||||
StackId builderImageStackId = StackId.fromImage(builderImage);
|
||||
if (runImageStackId.hasId() && builderImageStackId.hasId() && !runImageStackId.equals(builderImageStackId)) {
|
||||
this.log.stackIdsDoNotMatch(runImageStackId.toString(), builderImageStackId.toString());
|
||||
private void warnIfDistrosDoNotMatch(Image runImage, Image builderImage) {
|
||||
Distro runImageDistro = Distro.fromImage(runImage);
|
||||
Distro builderImageDistro = Distro.fromImage(builderImage);
|
||||
if (!runImageDistro.matches(builderImageDistro)) {
|
||||
this.log.distrosDoNotMatch(runImageDistro.toString(), builderImageDistro.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The OS distribution of an image, as described by the target data of the CNB platform
|
||||
* specification.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
final class Distro {
|
||||
|
||||
private static final String NAME_LABEL = "io.buildpacks.base.distro.name";
|
||||
|
||||
private static final String VERSION_LABEL = "io.buildpacks.base.distro.version";
|
||||
|
||||
// Paketo images only set these non-spec labels
|
||||
private static final String STACK_NAME_LABEL = "io.buildpacks.stack.distro.name";
|
||||
|
||||
private static final String STACK_VERSION_LABEL = "io.buildpacks.stack.distro.version";
|
||||
|
||||
private final @Nullable String name;
|
||||
|
||||
private final @Nullable String version;
|
||||
|
||||
private Distro(@Nullable String name, @Nullable String version) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this distribution matches the given distribution. A missing name or
|
||||
* version matches any value.
|
||||
* @param other the distribution to compare with
|
||||
* @return {@code true} if the distributions match
|
||||
*/
|
||||
boolean matches(Distro other) {
|
||||
return matches(this.name, other.name) && matches(this.version, other.version);
|
||||
}
|
||||
|
||||
private static boolean matches(@Nullable String value, @Nullable String other) {
|
||||
if (value == null || other == null) {
|
||||
return true;
|
||||
}
|
||||
return value.equals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (this.name != null) {
|
||||
result.append(this.name);
|
||||
}
|
||||
if (this.version != null) {
|
||||
if (!result.isEmpty()) {
|
||||
result.append(" ");
|
||||
}
|
||||
result.append(this.version);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a {@link Distro} from an {@link Image}.
|
||||
* @param image the source image
|
||||
* @return the extracted distribution
|
||||
*/
|
||||
static Distro fromImage(Image image) {
|
||||
Assert.notNull(image, "'image' must not be null");
|
||||
Map<String, String> labels = image.getConfig().getLabels();
|
||||
String name = getLabel(labels, NAME_LABEL, STACK_NAME_LABEL);
|
||||
String version = getLabel(labels, VERSION_LABEL, STACK_VERSION_LABEL);
|
||||
return new Distro(name, version);
|
||||
}
|
||||
|
||||
private static @Nullable String getLabel(Map<String, String> labels, String label, String fallbackLabel) {
|
||||
String value = labels.get(label);
|
||||
if (StringUtils.hasText(value)) {
|
||||
return value;
|
||||
}
|
||||
value = labels.get(fallbackLabel);
|
||||
return StringUtils.hasText(value) ? value : null;
|
||||
}
|
||||
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.Objects;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A Stack ID.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class StackId {
|
||||
|
||||
private static final String LABEL_NAME = "io.buildpacks.stack.id";
|
||||
|
||||
private final @Nullable String value;
|
||||
|
||||
StackId(@Nullable String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(this.value, ((StackId) obj).value);
|
||||
}
|
||||
|
||||
boolean hasId() {
|
||||
return this.value != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (this.value != null) ? this.value : "<null>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a {@link StackId} from an {@link Image}.
|
||||
* @param image the source image
|
||||
* @return the extracted stack ID
|
||||
*/
|
||||
static StackId fromImage(Image image) {
|
||||
Assert.notNull(image, "'image' must not be null");
|
||||
return fromImageConfig(image.getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a {@link StackId} from an {@link ImageConfig}.
|
||||
* @param imageConfig the source image config
|
||||
* @return the extracted stack ID
|
||||
*/
|
||||
private static StackId fromImageConfig(ImageConfig imageConfig) {
|
||||
String value = imageConfig.getLabels().get(LABEL_NAME);
|
||||
return new StackId(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a {@link StackId} with a given value.
|
||||
* @param value the stack ID value
|
||||
* @return a new stack ID instance
|
||||
*/
|
||||
static StackId of(String value) {
|
||||
Assert.hasText(value, "'value' must not be empty");
|
||||
return new StackId(value);
|
||||
}
|
||||
|
||||
}
|
||||
+33
-16
@@ -447,22 +447,25 @@ class BuilderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWhenStackIdDoesNotMatchLogsWarning() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
DockerApi docker = mockDockerApi();
|
||||
Image builderImage = loadImage("image.json");
|
||||
Image runImage = loadImage("run-image-with-bad-stack.json");
|
||||
given(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))
|
||||
.willAnswer(withPulledImage(builderImage));
|
||||
given(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))
|
||||
.willAnswer(withPulledImage(runImage));
|
||||
Builder builder = new Builder(BuildLog.to(out), docker, null);
|
||||
BuildRequest request = getTestRequest();
|
||||
builder.build(request);
|
||||
assertThat(out.toString()).contains(
|
||||
"Warning: Run image stack 'org.cloudfoundry.stacks.cfwindowsfs3' does not match builder stack 'io.buildpacks.stacks.bionic'");
|
||||
assertThat(out.toString()).contains("Running creator");
|
||||
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
void shouldNotWarnWhenStackIdsDifferWithoutDistro() throws Exception {
|
||||
String output = buildWith("image.json", "run-image-with-bad-stack.json");
|
||||
assertThat(output).doesNotContain("Warning");
|
||||
assertThat(output).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotWarnWhenStackIdsDifferButDistrosMatch() throws Exception {
|
||||
String output = buildWith("image-with-distro.json", "run-image-with-same-distro.json");
|
||||
assertThat(output).doesNotContain("Warning");
|
||||
assertThat(output).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWarnWhenDistrosDoNotMatch() throws Exception {
|
||||
String output = buildWith("image-with-distro.json", "run-image-with-other-distro.json");
|
||||
assertThat(output).contains(
|
||||
"Warning: Run image distribution 'ubuntu 24.04' does not match builder distribution 'ubuntu 26.04'");
|
||||
assertThat(output).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -553,6 +556,20 @@ class BuilderTests {
|
||||
return BuildRequest.of(name, (owner) -> content).withTrustBuilder(true);
|
||||
}
|
||||
|
||||
private String buildWith(String builderImageName, String runImageName) throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
DockerApi docker = mockDockerApi();
|
||||
Image builderImage = loadImage(builderImageName);
|
||||
Image runImage = loadImage(runImageName);
|
||||
given(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))
|
||||
.willAnswer(withPulledImage(builderImage));
|
||||
given(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))
|
||||
.willAnswer(withPulledImage(runImage));
|
||||
Builder builder = new Builder(BuildLog.to(out), docker, null);
|
||||
builder.build(getTestRequest());
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private Image loadImage(String name) throws IOException {
|
||||
return Image.of(getClass().getResourceAsStream(name));
|
||||
}
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
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.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link Distro}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class DistroTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("NullAway") // Test null check
|
||||
void shouldFailWhenImageIsNull() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> Distro.fromImage(null))
|
||||
.withMessage("'image' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReadBaseLabels() {
|
||||
Distro distro = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.base.distro.name", "ubuntu", "io.buildpacks.base.distro.version", "26.04")));
|
||||
assertThat(distro).hasToString("ubuntu 26.04");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFormatNameOnly() {
|
||||
Distro distro = Distro.fromImage(image(Map.of("io.buildpacks.base.distro.name", "ubuntu")));
|
||||
assertThat(distro).hasToString("ubuntu");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFormatVersionOnly() {
|
||||
Distro distro = Distro.fromImage(image(Map.of("io.buildpacks.base.distro.version", "26.04")));
|
||||
assertThat(distro).hasToString("26.04");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFormatEmptyWhenLabelsAreMissing() {
|
||||
Distro distro = Distro.fromImage(image(Collections.emptyMap()));
|
||||
assertThat(distro).hasToString("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFallBackToStackLabels() {
|
||||
Distro distro = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.stack.distro.name", "ubuntu", "io.buildpacks.stack.distro.version", "26.04")));
|
||||
assertThat(distro).hasToString("ubuntu 26.04");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPreferBaseLabelsOverStackLabels() {
|
||||
Distro distro = Distro
|
||||
.fromImage(image(Map.of("io.buildpacks.base.distro.name", "ubuntu", "io.buildpacks.base.distro.version",
|
||||
"26.04", "io.buildpacks.stack.distro.name", "debian", "io.buildpacks.stack.distro.version", "13")));
|
||||
assertThat(distro).hasToString("ubuntu 26.04");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMatchWhenNameAndVersionAreEqual() {
|
||||
Distro distro = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.base.distro.name", "ubuntu", "io.buildpacks.base.distro.version", "26.04")));
|
||||
Distro other = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.stack.distro.name", "ubuntu", "io.buildpacks.stack.distro.version", "26.04")));
|
||||
assertThat(distro.matches(other)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotMatchWhenVersionDiffers() {
|
||||
Distro distro = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.base.distro.name", "ubuntu", "io.buildpacks.base.distro.version", "26.04")));
|
||||
Distro other = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.base.distro.name", "ubuntu", "io.buildpacks.base.distro.version", "24.04")));
|
||||
assertThat(distro.matches(other)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotMatchWhenNameDiffers() {
|
||||
Distro distro = Distro.fromImage(image(Map.of("io.buildpacks.base.distro.name", "ubuntu")));
|
||||
Distro other = Distro.fromImage(image(Map.of("io.buildpacks.base.distro.name", "debian")));
|
||||
assertThat(distro.matches(other)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMatchWhenVersionIsMissingOnOneSide() {
|
||||
Distro distro = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.base.distro.name", "ubuntu", "io.buildpacks.base.distro.version", "26.04")));
|
||||
Distro other = Distro.fromImage(image(Map.of("io.buildpacks.base.distro.name", "ubuntu")));
|
||||
assertThat(distro.matches(other)).isTrue();
|
||||
assertThat(other.matches(distro)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMatchWhenLabelsAreMissing() {
|
||||
Distro distro = Distro.fromImage(image(
|
||||
Map.of("io.buildpacks.base.distro.name", "ubuntu", "io.buildpacks.base.distro.version", "26.04")));
|
||||
Distro other = Distro.fromImage(image(Collections.emptyMap()));
|
||||
assertThat(distro.matches(other)).isTrue();
|
||||
assertThat(other.matches(distro)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldIgnoreStackId() {
|
||||
Distro distro = Distro.fromImage(image(Map.of("io.buildpacks.stack.id", "io.buildpacks.stacks.resolute")));
|
||||
Distro other = Distro.fromImage(image(Map.of("io.buildpacks.stack.id", "io.buildpacks.stacks.resolute.tiny")));
|
||||
assertThat(distro.matches(other)).isTrue();
|
||||
}
|
||||
|
||||
private Image image(Map<String, String> labels) {
|
||||
Image image = mock(Image.class);
|
||||
ImageConfig imageConfig = mock(ImageConfig.class);
|
||||
given(image.getConfig()).willReturn(imageConfig);
|
||||
given(imageConfig.getLabels()).willReturn(labels);
|
||||
return image;
|
||||
}
|
||||
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
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.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link StackId}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class StackIdTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("NullAway") // Test null check
|
||||
void fromImageWhenImageIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> StackId.fromImage(null))
|
||||
.withMessage("'image' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromImageWhenLabelIsMissingHasNoId() {
|
||||
Image image = mock(Image.class);
|
||||
ImageConfig imageConfig = mock(ImageConfig.class);
|
||||
given(image.getConfig()).willReturn(imageConfig);
|
||||
StackId stackId = StackId.fromImage(image);
|
||||
assertThat(stackId.hasId()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromImageCreatesStackId() {
|
||||
Image image = mock(Image.class);
|
||||
ImageConfig imageConfig = mock(ImageConfig.class);
|
||||
given(image.getConfig()).willReturn(imageConfig);
|
||||
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
|
||||
void ofCreatesStackId() {
|
||||
StackId stackId = StackId.of("test");
|
||||
assertThat(stackId).hasToString("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalsAndHashCode() {
|
||||
StackId s1 = StackId.of("a");
|
||||
StackId s2 = StackId.of("a");
|
||||
StackId s3 = StackId.of("b");
|
||||
assertThat(s1).hasSameHashCodeAs(s2);
|
||||
assertThat(s1).isEqualTo(s1).isEqualTo(s2).isNotEqualTo(s3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void toStringReturnsValue() {
|
||||
StackId stackId = StackId.of("test");
|
||||
assertThat(stackId).hasToString("test");
|
||||
}
|
||||
|
||||
}
|
||||
+134
File diff suppressed because one or more lines are too long
+101
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"Id": "sha256:1332879bc8e38793a45ebe5a750f2a1c35df07ec2aa9c18f694644a9de77359b",
|
||||
"RepoTags": [
|
||||
"cloudfoundry/run:base-cnb"
|
||||
],
|
||||
"RepoDigests": [
|
||||
"cloudfoundry/run@sha256:fb5ecb90a42b2067a859aab23fc1f5e9d9c2589d07ba285608879e7baa415aad"
|
||||
],
|
||||
"Parent": "",
|
||||
"Comment": "",
|
||||
"Created": "2020-03-20T20:18:18.117972538Z",
|
||||
"Container": "91d1af87c3bb6163cd9c7cb21e6891cd25f5fa3c7417779047776e288c0bc234",
|
||||
"ContainerConfig": {
|
||||
"Hostname": "91d1af87c3bb",
|
||||
"Domainname": "",
|
||||
"User": "1000:1000",
|
||||
"AttachStdin": false,
|
||||
"AttachStdout": false,
|
||||
"AttachStderr": false,
|
||||
"Tty": false,
|
||||
"OpenStdin": false,
|
||||
"StdinOnce": false,
|
||||
"Env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
],
|
||||
"Cmd": [
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"#(nop) ",
|
||||
"LABEL io.buildpacks.stack.id=io.buildpacks.stacks.bionic"
|
||||
],
|
||||
"ArgsEscaped": true,
|
||||
"Image": "sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994",
|
||||
"Volumes": null,
|
||||
"WorkingDir": "",
|
||||
"Entrypoint": null,
|
||||
"OnBuild": null,
|
||||
"Labels": {
|
||||
"io.buildpacks.base.distro.name": "ubuntu",
|
||||
"io.buildpacks.base.distro.version": "24.04",
|
||||
"io.buildpacks.stack.id": "io.buildpacks.stacks.bionic"
|
||||
}
|
||||
},
|
||||
"DockerVersion": "18.09.6",
|
||||
"Author": "",
|
||||
"Config": {
|
||||
"Hostname": "",
|
||||
"Domainname": "",
|
||||
"User": "1000:1000",
|
||||
"AttachStdin": false,
|
||||
"AttachStdout": false,
|
||||
"AttachStderr": false,
|
||||
"Tty": false,
|
||||
"OpenStdin": false,
|
||||
"StdinOnce": false,
|
||||
"Env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
],
|
||||
"Cmd": [
|
||||
"/bin/bash"
|
||||
],
|
||||
"ArgsEscaped": true,
|
||||
"Image": "sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994",
|
||||
"Volumes": null,
|
||||
"WorkingDir": "",
|
||||
"Entrypoint": null,
|
||||
"OnBuild": null,
|
||||
"Labels": {
|
||||
"io.buildpacks.base.distro.name": "ubuntu",
|
||||
"io.buildpacks.base.distro.version": "24.04",
|
||||
"io.buildpacks.stack.id": "io.buildpacks.stacks.bionic"
|
||||
}
|
||||
},
|
||||
"Architecture": "amd64",
|
||||
"Os": "linux",
|
||||
"Size": 71248531,
|
||||
"VirtualSize": 71248531,
|
||||
"GraphDriver": {
|
||||
"Data": {
|
||||
"LowerDir": "/var/lib/docker/overlay2/17f0a4530fbc3e2982f9dc8feb8c8ddc124473bdd50130dae20856ac597d82dd/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff",
|
||||
"MergedDir": "/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/merged",
|
||||
"UpperDir": "/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/diff",
|
||||
"WorkDir": "/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/work"
|
||||
},
|
||||
"Name": "overlay2"
|
||||
},
|
||||
"RootFS": {
|
||||
"Type": "layers",
|
||||
"Layers": [
|
||||
"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853",
|
||||
"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f",
|
||||
"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d",
|
||||
"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75",
|
||||
"sha256:c1daeb79beb276c7441d9a1d7281433e9a7edb9f652b8996ecc62b51e88a47b2",
|
||||
"sha256:eb195d29dc1aa6e4239f00e7868deebc5ac12bebe76104e0b774c1ef29ca78e3"
|
||||
]
|
||||
},
|
||||
"Metadata": {
|
||||
"LastTagTime": "0001-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"Id": "sha256:1332879bc8e38793a45ebe5a750f2a1c35df07ec2aa9c18f694644a9de77359b",
|
||||
"RepoTags": [
|
||||
"cloudfoundry/run:base-cnb"
|
||||
],
|
||||
"RepoDigests": [
|
||||
"cloudfoundry/run@sha256:fb5ecb90a42b2067a859aab23fc1f5e9d9c2589d07ba285608879e7baa415aad"
|
||||
],
|
||||
"Parent": "",
|
||||
"Comment": "",
|
||||
"Created": "2020-03-20T20:18:18.117972538Z",
|
||||
"Container": "91d1af87c3bb6163cd9c7cb21e6891cd25f5fa3c7417779047776e288c0bc234",
|
||||
"ContainerConfig": {
|
||||
"Hostname": "91d1af87c3bb",
|
||||
"Domainname": "",
|
||||
"User": "1000:1000",
|
||||
"AttachStdin": false,
|
||||
"AttachStdout": false,
|
||||
"AttachStderr": false,
|
||||
"Tty": false,
|
||||
"OpenStdin": false,
|
||||
"StdinOnce": false,
|
||||
"Env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
],
|
||||
"Cmd": [
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"#(nop) ",
|
||||
"LABEL io.buildpacks.stack.id=io.buildpacks.stacks.bionic"
|
||||
],
|
||||
"ArgsEscaped": true,
|
||||
"Image": "sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994",
|
||||
"Volumes": null,
|
||||
"WorkingDir": "",
|
||||
"Entrypoint": null,
|
||||
"OnBuild": null,
|
||||
"Labels": {
|
||||
"io.buildpacks.stack.distro.name": "ubuntu",
|
||||
"io.buildpacks.stack.distro.version": "26.04",
|
||||
"io.buildpacks.stack.id": "io.buildpacks.stacks.bionic.tiny"
|
||||
}
|
||||
},
|
||||
"DockerVersion": "18.09.6",
|
||||
"Author": "",
|
||||
"Config": {
|
||||
"Hostname": "",
|
||||
"Domainname": "",
|
||||
"User": "1000:1000",
|
||||
"AttachStdin": false,
|
||||
"AttachStdout": false,
|
||||
"AttachStderr": false,
|
||||
"Tty": false,
|
||||
"OpenStdin": false,
|
||||
"StdinOnce": false,
|
||||
"Env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
],
|
||||
"Cmd": [
|
||||
"/bin/bash"
|
||||
],
|
||||
"ArgsEscaped": true,
|
||||
"Image": "sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994",
|
||||
"Volumes": null,
|
||||
"WorkingDir": "",
|
||||
"Entrypoint": null,
|
||||
"OnBuild": null,
|
||||
"Labels": {
|
||||
"io.buildpacks.stack.distro.name": "ubuntu",
|
||||
"io.buildpacks.stack.distro.version": "26.04",
|
||||
"io.buildpacks.stack.id": "io.buildpacks.stacks.bionic.tiny"
|
||||
}
|
||||
},
|
||||
"Architecture": "amd64",
|
||||
"Os": "linux",
|
||||
"Size": 71248531,
|
||||
"VirtualSize": 71248531,
|
||||
"GraphDriver": {
|
||||
"Data": {
|
||||
"LowerDir": "/var/lib/docker/overlay2/17f0a4530fbc3e2982f9dc8feb8c8ddc124473bdd50130dae20856ac597d82dd/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff",
|
||||
"MergedDir": "/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/merged",
|
||||
"UpperDir": "/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/diff",
|
||||
"WorkDir": "/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/work"
|
||||
},
|
||||
"Name": "overlay2"
|
||||
},
|
||||
"RootFS": {
|
||||
"Type": "layers",
|
||||
"Layers": [
|
||||
"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853",
|
||||
"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f",
|
||||
"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d",
|
||||
"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75",
|
||||
"sha256:c1daeb79beb276c7441d9a1d7281433e9a7edb9f652b8996ecc62b51e88a47b2",
|
||||
"sha256:eb195d29dc1aa6e4239f00e7868deebc5ac12bebe76104e0b774c1ef29ca78e3"
|
||||
]
|
||||
},
|
||||
"Metadata": {
|
||||
"LastTagTime": "0001-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user