Set Spring Boot version in ephemeral builder
This commit adds a `createdBy` structure to the metadata of the ephemeral builder container image that identifies Spring Boot as the creator of the image, along with the Spring Boot version. See gh-20126
This commit is contained in:
parent
97af0b2f3a
commit
191dce3f5e
|
|
@ -44,6 +44,8 @@ public class BuildRequest {
|
|||
|
||||
private final ImageReference builder;
|
||||
|
||||
private final Creator creator;
|
||||
|
||||
private final Map<String, String> env;
|
||||
|
||||
private final boolean cleanCache;
|
||||
|
|
@ -59,13 +61,15 @@ public class BuildRequest {
|
|||
this.env = Collections.emptyMap();
|
||||
this.cleanCache = false;
|
||||
this.verboseLogging = false;
|
||||
this.creator = Creator.withVersion("");
|
||||
}
|
||||
|
||||
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent, ImageReference builder,
|
||||
Map<String, String> env, boolean cleanCache, boolean verboseLogging) {
|
||||
Creator creator, Map<String, String> env, boolean cleanCache, boolean verboseLogging) {
|
||||
this.name = name;
|
||||
this.applicationContent = applicationContent;
|
||||
this.builder = builder;
|
||||
this.creator = creator;
|
||||
this.env = env;
|
||||
this.cleanCache = cleanCache;
|
||||
this.verboseLogging = verboseLogging;
|
||||
|
|
@ -78,7 +82,18 @@ public class BuildRequest {
|
|||
*/
|
||||
public BuildRequest withBuilder(ImageReference builder) {
|
||||
Assert.notNull(builder, "Builder must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, builder.inTaggedForm(), this.env, this.cleanCache,
|
||||
return new BuildRequest(this.name, this.applicationContent, builder.inTaggedForm(), this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an updated builder.
|
||||
* @param creator the new {@code Creator} to use
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withCreator(Creator creator) {
|
||||
Assert.notNull(creator, "Creator must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, creator, this.env, this.cleanCache,
|
||||
this.verboseLogging);
|
||||
}
|
||||
|
||||
|
|
@ -93,8 +108,8 @@ public class BuildRequest {
|
|||
Assert.hasText(value, "Value must not be empty");
|
||||
Map<String, String> env = new LinkedHashMap<>(this.env);
|
||||
env.put(name, value);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, Collections.unmodifiableMap(env),
|
||||
this.cleanCache, this.verboseLogging);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator,
|
||||
Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +121,7 @@ public class BuildRequest {
|
|||
Assert.notNull(env, "Env must not be null");
|
||||
Map<String, String> updatedEnv = new LinkedHashMap<>(this.env);
|
||||
updatedEnv.putAll(env);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder,
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator,
|
||||
Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +131,7 @@ public class BuildRequest {
|
|||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withCleanCache(boolean cleanCache) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.env, cleanCache,
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator, this.env, cleanCache,
|
||||
this.verboseLogging);
|
||||
}
|
||||
|
||||
|
|
@ -126,8 +141,8 @@ public class BuildRequest {
|
|||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withVerboseLogging(boolean verboseLogging) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.env, this.cleanCache,
|
||||
verboseLogging);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator, this.env,
|
||||
this.cleanCache, verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -157,6 +172,14 @@ public class BuildRequest {
|
|||
return this.builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Creator} the builder should use.
|
||||
* @return the {@code Creator}
|
||||
*/
|
||||
public Creator getCreator() {
|
||||
return this.creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any env variable that should be passed to the builder.
|
||||
* @return the builder env
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ public class Builder {
|
|||
ImageReference runImageReference = getRunImageReference(builderMetadata.getStack());
|
||||
Image runImage = pullRunImage(request, runImageReference);
|
||||
assertHasExpectedStackId(runImage, stackId);
|
||||
EphemeralBuilder builder = new EphemeralBuilder(buildOwner, builderImage, builderMetadata, request.getEnv());
|
||||
EphemeralBuilder builder = new EphemeralBuilder(buildOwner, builderImage, builderMetadata, request.getCreator(),
|
||||
request.getEnv());
|
||||
this.docker.image().load(builder.getArchive(), UpdateListener.none());
|
||||
try {
|
||||
executeLifecycle(request, runImageReference, builder);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Identifying information about the tooling that created a builder.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class Creator {
|
||||
|
||||
private final String version;
|
||||
|
||||
Creator(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the builder creator.
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return "Spring Boot";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version of the builder creator.
|
||||
* @return the version
|
||||
*/
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code Creator} using the provided version.
|
||||
* @param version the creator version
|
||||
* @return a new creator instance
|
||||
*/
|
||||
public static Creator withVersion(String version) {
|
||||
Assert.notNull(version, "Version must not be null");
|
||||
return new Creator(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName() + " version " + getVersion();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -42,17 +42,20 @@ class EphemeralBuilder {
|
|||
|
||||
private final ImageArchive archive;
|
||||
|
||||
private final Creator creator;
|
||||
|
||||
/**
|
||||
* Create a new {@link EphemeralBuilder} instance.
|
||||
* @param buildOwner the build owner
|
||||
* @param builderImage the image
|
||||
* @param builderMetadata the builder metadata
|
||||
* @param creator the builder creator
|
||||
* @param env the builder env
|
||||
* @throws IOException on IO error
|
||||
*/
|
||||
EphemeralBuilder(BuildOwner buildOwner, Image builderImage, BuilderMetadata builderMetadata,
|
||||
EphemeralBuilder(BuildOwner buildOwner, Image builderImage, BuilderMetadata builderMetadata, Creator creator,
|
||||
Map<String, String> env) throws IOException {
|
||||
this(Clock.systemUTC(), buildOwner, builderImage, builderMetadata, env);
|
||||
this(Clock.systemUTC(), buildOwner, builderImage, builderMetadata, creator, env);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -61,13 +64,15 @@ class EphemeralBuilder {
|
|||
* @param buildOwner the build owner
|
||||
* @param builderImage the image
|
||||
* @param builderMetadata the builder metadata
|
||||
* @param creator the builder creator
|
||||
* @param env the builder env
|
||||
* @throws IOException on IO error
|
||||
*/
|
||||
EphemeralBuilder(Clock clock, BuildOwner buildOwner, Image builderImage, BuilderMetadata builderMetadata,
|
||||
Map<String, String> env) throws IOException {
|
||||
Creator creator, Map<String, String> env) throws IOException {
|
||||
ImageReference name = ImageReference.random("pack.local/builder/").inTaggedForm();
|
||||
this.buildOwner = buildOwner;
|
||||
this.creator = creator;
|
||||
this.builderMetadata = builderMetadata.copy(this::updateMetadata);
|
||||
this.archive = ImageArchive.from(builderImage, (update) -> {
|
||||
update.withUpdatedConfig(this.builderMetadata::attachTo);
|
||||
|
|
@ -80,7 +85,7 @@ class EphemeralBuilder {
|
|||
}
|
||||
|
||||
private void updateMetadata(BuilderMetadata.Update update) {
|
||||
update.withCreatedBy("Spring Boot", "dev");
|
||||
update.withCreatedBy(this.creator.getName(), this.creator.getVersion());
|
||||
}
|
||||
|
||||
private Layer getEnvLayer(Map<String, String> env) throws IOException {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.entry;
|
|||
* Tests for {@link BuildRequest}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class BuildRequestTests {
|
||||
|
||||
|
|
@ -97,6 +98,16 @@ public class BuildRequestTests {
|
|||
assertThat(request.getBuilder().toString()).isEqualTo("docker.io/spring/builder:latest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCreatorUpdatesCreator() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
BuildRequest withCreator = request.withCreator(Creator.withVersion("1.0.0"));
|
||||
assertThat(request.getCreator().getName()).isEqualTo("Spring Boot");
|
||||
assertThat(request.getCreator().getVersion()).isEqualTo("");
|
||||
assertThat(withCreator.getCreator().getName()).isEqualTo("Spring Boot");
|
||||
assertThat(withCreator.getCreator().getVersion()).isEqualTo("1.0.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withEnvAddsEnvEntry() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ class EphemeralBuilderTests extends AbstractJsonTests {
|
|||
|
||||
private Map<String, String> env;
|
||||
|
||||
private Creator creator = Creator.withVersion("dev");
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
this.image = Image.of(getContent("image.json"));
|
||||
|
|
@ -71,23 +73,24 @@ class EphemeralBuilderTests extends AbstractJsonTests {
|
|||
|
||||
@Test
|
||||
void getNameHasRandomName() throws Exception {
|
||||
EphemeralBuilder b1 = new EphemeralBuilder(this.owner, this.image, this.metadata, this.env);
|
||||
EphemeralBuilder b2 = new EphemeralBuilder(this.owner, this.image, this.metadata, this.env);
|
||||
EphemeralBuilder b1 = new EphemeralBuilder(this.owner, this.image, this.metadata, this.creator, this.env);
|
||||
EphemeralBuilder b2 = new EphemeralBuilder(this.owner, this.image, this.metadata, this.creator, this.env);
|
||||
assertThat(b1.getName().toString()).startsWith("pack.local/builder/").endsWith(":latest");
|
||||
assertThat(b1.getName().toString()).isNotEqualTo(b2.getName().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getArchiveHasCreatedByConfig() throws Exception {
|
||||
EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.env);
|
||||
EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.creator, this.env);
|
||||
ImageConfig config = builder.getArchive().getImageConfig();
|
||||
BuilderMetadata ephemeralMetadata = BuilderMetadata.fromImageConfig(config);
|
||||
assertThat(ephemeralMetadata.getCreatedBy().getName()).isEqualTo("Spring Boot");
|
||||
assertThat(ephemeralMetadata.getCreatedBy().getVersion()).isEqualTo("dev");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getArchiveHasTag() throws Exception {
|
||||
EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.env);
|
||||
EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.creator, this.env);
|
||||
ImageReference tag = builder.getArchive().getTag();
|
||||
assertThat(tag.toString()).startsWith("pack.local/builder/").endsWith(":latest");
|
||||
}
|
||||
|
|
@ -95,13 +98,14 @@ class EphemeralBuilderTests extends AbstractJsonTests {
|
|||
@Test
|
||||
void getArchiveHasCreateDate() throws Exception {
|
||||
Clock clock = Clock.fixed(Instant.now(), ZoneOffset.UTC);
|
||||
EphemeralBuilder builder = new EphemeralBuilder(clock, this.owner, this.image, this.metadata, this.env);
|
||||
EphemeralBuilder builder = new EphemeralBuilder(clock, this.owner, this.image, this.metadata, this.creator,
|
||||
this.env);
|
||||
assertThat(builder.getArchive().getCreateDate()).isEqualTo(Instant.now(clock));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getArchiveContainsEnvLayer() throws Exception {
|
||||
EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.env);
|
||||
EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.creator, this.env);
|
||||
File folder = unpack(getLayer(builder.getArchive(), 0), "env");
|
||||
assertThat(new File(folder, "platform/env/spring")).usingCharset(StandardCharsets.UTF_8).hasContent("boot");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,8 @@
|
|||
|
||||
package org.springframework.boot.gradle.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Plugin;
|
||||
|
|
@ -45,11 +38,12 @@ import org.springframework.boot.gradle.tasks.bundling.BootWar;
|
|||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @author Danny Hyun
|
||||
* @author Scott Frederick
|
||||
* @since 1.2.7
|
||||
*/
|
||||
public class SpringBootPlugin implements Plugin<Project> {
|
||||
|
||||
private static final String SPRING_BOOT_VERSION = determineSpringBootVersion();
|
||||
private static final String SPRING_BOOT_VERSION = VersionExtractor.forClass(DependencyManagementPluginAction.class);
|
||||
|
||||
/**
|
||||
* The name of the {@link Configuration} that contains Spring Boot archives.
|
||||
|
|
@ -135,29 +129,4 @@ public class SpringBootPlugin implements Plugin<Project> {
|
|||
project.getGradle().buildFinished((buildResult) -> unresolvedDependenciesAnalyzer.buildFinished(project));
|
||||
}
|
||||
|
||||
private static String determineSpringBootVersion() {
|
||||
String implementationVersion = DependencyManagementPluginAction.class.getPackage().getImplementationVersion();
|
||||
if (implementationVersion != null) {
|
||||
return implementationVersion;
|
||||
}
|
||||
URL codeSourceLocation = DependencyManagementPluginAction.class.getProtectionDomain().getCodeSource()
|
||||
.getLocation();
|
||||
try {
|
||||
URLConnection connection = codeSourceLocation.openConnection();
|
||||
if (connection instanceof JarURLConnection) {
|
||||
return getImplementationVersion(((JarURLConnection) connection).getJarFile());
|
||||
}
|
||||
try (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) {
|
||||
return getImplementationVersion(jarFile);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getImplementationVersion(JarFile jarFile) throws IOException {
|
||||
return jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.gradle.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* Extracts version information for a Class.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public final class VersionExtractor {
|
||||
|
||||
private VersionExtractor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version information for the provided {@link Class}.
|
||||
* @param cls the Class to retrieve the version for
|
||||
* @return the version, or {@code null} if a version can not be extracted
|
||||
*/
|
||||
public static String forClass(Class<?> cls) {
|
||||
String implementationVersion = cls.getPackage().getImplementationVersion();
|
||||
if (implementationVersion != null) {
|
||||
return implementationVersion;
|
||||
}
|
||||
URL codeSourceLocation = cls.getProtectionDomain().getCodeSource().getLocation();
|
||||
try {
|
||||
URLConnection connection = codeSourceLocation.openConnection();
|
||||
if (connection instanceof JarURLConnection) {
|
||||
return getImplementationVersion(((JarURLConnection) connection).getJarFile());
|
||||
}
|
||||
try (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) {
|
||||
return getImplementationVersion(jarFile);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getImplementationVersion(JarFile jarFile) throws IOException {
|
||||
return jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,10 +30,12 @@ import org.gradle.api.tasks.TaskAction;
|
|||
|
||||
import org.springframework.boot.buildpack.platform.build.BuildRequest;
|
||||
import org.springframework.boot.buildpack.platform.build.Builder;
|
||||
import org.springframework.boot.buildpack.platform.build.Creator;
|
||||
import org.springframework.boot.buildpack.platform.docker.DockerException;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageName;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
|
||||
import org.springframework.boot.buildpack.platform.io.ZipFileTarArchive;
|
||||
import org.springframework.boot.gradle.plugin.VersionExtractor;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -41,6 +43,7 @@ import org.springframework.util.StringUtils;
|
|||
* <a href="https://buildpacks.io">buildpack</a>.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class BootBuildImage extends DefaultTask {
|
||||
|
|
@ -51,7 +54,7 @@ public class BootBuildImage extends DefaultTask {
|
|||
|
||||
private String builder;
|
||||
|
||||
private Map<String, String> environment = new HashMap<String, String>();
|
||||
private Map<String, String> environment = new HashMap<>();
|
||||
|
||||
private boolean cleanCache;
|
||||
|
||||
|
|
@ -210,6 +213,10 @@ public class BootBuildImage extends DefaultTask {
|
|||
if (this.environment != null && !this.environment.isEmpty()) {
|
||||
request = request.withEnv(this.environment);
|
||||
}
|
||||
String springBootVersion = VersionExtractor.forClass(BootBuildImage.class);
|
||||
if (StringUtils.hasText(springBootVersion)) {
|
||||
request = request.withCreator(Creator.withVersion(springBootVersion));
|
||||
}
|
||||
request = request.withCleanCache(this.cleanCache);
|
||||
request = request.withVerboseLogging(this.verboseLogging);
|
||||
return request;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* Tests for {@link BootBuildImage}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class BootBuildImageTests {
|
||||
|
||||
|
|
@ -81,6 +82,13 @@ class BootBuildImageTests {
|
|||
assertThat(request.getName().getDigest()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void springBootVersionDefaultValueIsUsed() {
|
||||
BuildRequest request = this.buildImage.createRequest();
|
||||
assertThat(request.getCreator().getName()).isEqualTo("Spring Boot");
|
||||
assertThat(request.getCreator().getVersion()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenIndividualEntriesAreAddedToTheEnvironmentThenTheyAreIncludedInTheRequest() {
|
||||
this.buildImage.environment("ALPHA", "a");
|
||||
|
|
@ -91,7 +99,7 @@ class BootBuildImageTests {
|
|||
|
||||
@Test
|
||||
void whenEntriesAreAddedToTheEnvironmentThenTheyAreIncludedInTheRequest() {
|
||||
Map<String, String> environment = new HashMap<String, String>();
|
||||
Map<String, String> environment = new HashMap<>();
|
||||
environment.put("ALPHA", "a");
|
||||
environment.put("BRAVO", "b");
|
||||
this.buildImage.environment(environment);
|
||||
|
|
@ -101,7 +109,7 @@ class BootBuildImageTests {
|
|||
|
||||
@Test
|
||||
void whenTheEnvironmentIsSetItIsIncludedInTheRequest() {
|
||||
Map<String, String> environment = new HashMap<String, String>();
|
||||
Map<String, String> environment = new HashMap<>();
|
||||
environment.put("ALPHA", "a");
|
||||
environment.put("BRAVO", "b");
|
||||
this.buildImage.setEnvironment(environment);
|
||||
|
|
@ -111,7 +119,7 @@ class BootBuildImageTests {
|
|||
|
||||
@Test
|
||||
void whenTheEnvironmentIsSetItReplacesAnyExistingEntriesAndIsIncludedInTheRequest() {
|
||||
Map<String, String> environment = new HashMap<String, String>();
|
||||
Map<String, String> environment = new HashMap<>();
|
||||
environment.put("ALPHA", "a");
|
||||
environment.put("BRAVO", "b");
|
||||
this.buildImage.environment("C", "Charlie");
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import org.springframework.boot.buildpack.platform.build.AbstractBuildLog;
|
|||
import org.springframework.boot.buildpack.platform.build.BuildLog;
|
||||
import org.springframework.boot.buildpack.platform.build.BuildRequest;
|
||||
import org.springframework.boot.buildpack.platform.build.Builder;
|
||||
import org.springframework.boot.buildpack.platform.build.Creator;
|
||||
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
|
||||
import org.springframework.boot.buildpack.platform.io.Owner;
|
||||
import org.springframework.boot.buildpack.platform.io.TarArchive;
|
||||
|
|
@ -53,6 +54,7 @@ import org.springframework.util.StringUtils;
|
|||
* Package an application into a OCI image using a buildpack.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Mojo(name = "build-image", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true,
|
||||
|
|
@ -124,7 +126,8 @@ public class BuildImageMojo extends AbstractPackagerMojo {
|
|||
|
||||
private BuildRequest getBuildRequest(Libraries libraries) {
|
||||
Function<Owner, TarArchive> content = (owner) -> getApplicationContent(owner, libraries);
|
||||
return ((this.image != null) ? this.image : new Image()).getBuildRequest(this.project.getArtifact(), content);
|
||||
Image image = (this.image != null) ? this.image : new Image();
|
||||
return customize(image.getBuildRequest(this.project.getArtifact(), content));
|
||||
}
|
||||
|
||||
private TarArchive getApplicationContent(Owner owner, Libraries libraries) {
|
||||
|
|
@ -143,6 +146,14 @@ public class BuildImageMojo extends AbstractPackagerMojo {
|
|||
return new File(this.sourceDirectory, name.toString());
|
||||
}
|
||||
|
||||
private BuildRequest customize(BuildRequest request) {
|
||||
String springBootVersion = VersionExtractor.forClass(BuildImageMojo.class);
|
||||
if (StringUtils.hasText(springBootVersion)) {
|
||||
request = request.withCreator(Creator.withVersion(springBootVersion));
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link BuildLog} backed by Mojo logging.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* Extracts version information for a Class.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
final class VersionExtractor {
|
||||
|
||||
private VersionExtractor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version information for the provided {@link Class}.
|
||||
* @param cls the Class to retrieve the version for
|
||||
* @return the version, or {@code null} if a version can not be extracted
|
||||
*/
|
||||
static String forClass(Class<?> cls) {
|
||||
String implementationVersion = cls.getPackage().getImplementationVersion();
|
||||
if (implementationVersion != null) {
|
||||
return implementationVersion;
|
||||
}
|
||||
URL codeSourceLocation = cls.getProtectionDomain().getCodeSource().getLocation();
|
||||
try {
|
||||
URLConnection connection = codeSourceLocation.openConnection();
|
||||
if (connection instanceof JarURLConnection) {
|
||||
return getImplementationVersion(((JarURLConnection) connection).getJarFile());
|
||||
}
|
||||
try (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) {
|
||||
return getImplementationVersion(jarFile);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getImplementationVersion(JarFile jarFile) throws IOException {
|
||||
return jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue