Only create effective bom artifact when needed

Closes gh-22143
This commit is contained in:
Andy Wilkinson 2020-06-29 13:39:54 +01:00
parent c000ccdaea
commit d33a01a13f
3 changed files with 104 additions and 91 deletions

View File

@ -16,6 +16,10 @@
package org.springframework.boot.build.bom;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
@ -23,21 +27,42 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import groovy.lang.Closure;
import groovy.lang.GroovyObjectSupport;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.InvalidUserCodeException;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.plugins.JavaPlatformPlugin;
import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
import org.gradle.api.tasks.Sync;
import org.gradle.api.tasks.TaskExecutionException;
import org.gradle.util.ConfigureUtil;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.springframework.boot.build.DeployedPlugin;
import org.springframework.boot.build.bom.Library.Exclusion;
import org.springframework.boot.build.bom.Library.Group;
import org.springframework.boot.build.bom.Library.Module;
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
import org.springframework.boot.build.mavenplugin.MavenExec;
import org.springframework.util.FileCopyUtils;
/**
* DSL extensions for {@link BomPlugin}.
@ -56,8 +81,11 @@ public class BomExtension {
private final DependencyHandler dependencyHandler;
public BomExtension(DependencyHandler dependencyHandler) {
private final Project project;
public BomExtension(DependencyHandler dependencyHandler, Project project) {
this.dependencyHandler = dependencyHandler;
this.project = project;
}
public List<Library> getLibraries() {
@ -80,6 +108,43 @@ public class BomExtension {
libraryHandler.prohibitedVersions));
}
public void effectiveBomArtifact() {
Configuration effectiveBomConfiguration = this.project.getConfigurations().create("effectiveBom");
this.project.getTasks().matching((task) -> task.getName().equals(DeployedPlugin.GENERATE_POM_TASK_NAME))
.all((task) -> {
Sync syncBom = this.project.getTasks().create("syncBom", Sync.class);
syncBom.dependsOn(task);
File generatedBomDir = new File(this.project.getBuildDir(), "generated/bom");
syncBom.setDestinationDir(generatedBomDir);
syncBom.from(((GenerateMavenPom) task).getDestination(), (pom) -> pom.rename((name) -> "pom.xml"));
try {
String settingsXmlContent = FileCopyUtils
.copyToString(new InputStreamReader(
getClass().getClassLoader().getResourceAsStream("effective-bom-settings.xml"),
StandardCharsets.UTF_8))
.replace("localRepositoryPath",
new File(this.project.getBuildDir(), "local-m2-repository").getAbsolutePath());
syncBom.from(this.project.getResources().getText().fromString(settingsXmlContent),
(settingsXml) -> settingsXml.rename((name) -> "settings.xml"));
}
catch (IOException ex) {
throw new GradleException("Failed to prepare settings.xml", ex);
}
MavenExec generateEffectiveBom = this.project.getTasks().create("generateEffectiveBom",
MavenExec.class);
generateEffectiveBom.setProjectDir(generatedBomDir);
File effectiveBom = new File(this.project.getBuildDir(),
"generated/effective-bom/" + this.project.getName() + "-effective-bom.xml");
generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom",
"-Doutput=" + effectiveBom);
generateEffectiveBom.dependsOn(syncBom);
generateEffectiveBom.getOutputs().file(effectiveBom);
generateEffectiveBom.doLast(new StripUnrepeatableOutputAction(effectiveBom));
this.project.getArtifacts().add(effectiveBomConfiguration.getName(), effectiveBom,
(artifact) -> artifact.builtBy(generateEffectiveBom));
});
}
private String createDependencyNotation(String groupId, String artifactId, DependencyVersion version) {
return groupId + ":" + artifactId + ":" + version;
}
@ -298,4 +363,38 @@ public class BomExtension {
}
private static final class StripUnrepeatableOutputAction implements Action<Task> {
private final File effectiveBom;
private StripUnrepeatableOutputAction(File xmlFile) {
this.effectiveBom = xmlFile;
}
@Override
public void execute(Task task) {
try {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(this.effectiveBom);
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList comments = (NodeList) xpath.evaluate("//comment()", document, XPathConstants.NODESET);
for (int i = 0; i < comments.getLength(); i++) {
org.w3c.dom.Node comment = comments.item(i);
comment.getParentNode().removeChild(comment);
}
org.w3c.dom.Node build = (org.w3c.dom.Node) xpath.evaluate("/project/build", document,
XPathConstants.NODE);
build.getParentNode().removeChild(build);
org.w3c.dom.Node reporting = (org.w3c.dom.Node) xpath.evaluate("/project/reporting", document,
XPathConstants.NODE);
reporting.getParentNode().removeChild(reporting);
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document),
new StreamResult(this.effectiveBom));
}
catch (Exception ex) {
throw new TaskExecutionException(task, ex);
}
}
}
}

View File

@ -16,28 +16,13 @@
package org.springframework.boot.build.bom;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import groovy.util.Node;
import groovy.xml.QName;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.plugins.JavaPlatformExtension;
import org.gradle.api.plugins.JavaPlatformPlugin;
@ -45,18 +30,11 @@ import org.gradle.api.plugins.PluginContainer;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPom;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
import org.gradle.api.tasks.Sync;
import org.gradle.api.tasks.TaskExecutionException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.springframework.boot.build.DeployedPlugin;
import org.springframework.boot.build.MavenRepositoryPlugin;
import org.springframework.boot.build.bom.Library.Group;
import org.springframework.boot.build.bom.bomr.UpgradeBom;
import org.springframework.boot.build.mavenplugin.MavenExec;
import org.springframework.util.FileCopyUtils;
/**
* {@link Plugin} for defining a bom. Dependencies are added as constraints in the
@ -78,43 +56,12 @@ public class BomPlugin implements Plugin<Project> {
JavaPlatformExtension javaPlatform = project.getExtensions().getByType(JavaPlatformExtension.class);
javaPlatform.allowDependencies();
createApiEnforcedConfiguration(project);
BomExtension bom = project.getExtensions().create("bom", BomExtension.class, project.getDependencies());
BomExtension bom = project.getExtensions().create("bom", BomExtension.class, project.getDependencies(),
project);
project.getTasks().create("bomrCheck", CheckBom.class, bom);
project.getTasks().create("bomrUpgrade", UpgradeBom.class, bom);
new PublishingCustomizer(project, bom).customize();
Configuration effectiveBomConfiguration = project.getConfigurations().create("effectiveBom");
project.getTasks().matching((task) -> task.getName().equals(DeployedPlugin.GENERATE_POM_TASK_NAME))
.all((task) -> {
Sync syncBom = project.getTasks().create("syncBom", Sync.class);
syncBom.dependsOn(task);
File generatedBomDir = new File(project.getBuildDir(), "generated/bom");
syncBom.setDestinationDir(generatedBomDir);
syncBom.from(((GenerateMavenPom) task).getDestination(), (pom) -> pom.rename((name) -> "pom.xml"));
try {
String settingsXmlContent = FileCopyUtils
.copyToString(new InputStreamReader(
getClass().getClassLoader().getResourceAsStream("effective-bom-settings.xml"),
StandardCharsets.UTF_8))
.replace("localRepositoryPath",
new File(project.getBuildDir(), "local-m2-repository").getAbsolutePath());
syncBom.from(project.getResources().getText().fromString(settingsXmlContent),
(settingsXml) -> settingsXml.rename((name) -> "settings.xml"));
}
catch (IOException ex) {
throw new GradleException("Failed to prepare settings.xml", ex);
}
MavenExec generateEffectiveBom = project.getTasks().create("generateEffectiveBom", MavenExec.class);
generateEffectiveBom.setProjectDir(generatedBomDir);
File effectiveBom = new File(project.getBuildDir(),
"generated/effective-bom/" + project.getName() + "-effective-bom.xml");
generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom",
"-Doutput=" + effectiveBom);
generateEffectiveBom.dependsOn(syncBom);
generateEffectiveBom.getOutputs().file(effectiveBom);
generateEffectiveBom.doLast(new StripUnrepeatableOutputAction(effectiveBom));
project.getArtifacts().add(effectiveBomConfiguration.getName(), effectiveBom,
(artifact) -> artifact.builtBy(generateEffectiveBom));
});
}
private void createApiEnforcedConfiguration(Project project) {
@ -276,38 +223,4 @@ public class BomPlugin implements Plugin<Project> {
}
private static final class StripUnrepeatableOutputAction implements Action<Task> {
private final File effectiveBom;
private StripUnrepeatableOutputAction(File xmlFile) {
this.effectiveBom = xmlFile;
}
@Override
public void execute(Task task) {
try {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(this.effectiveBom);
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList comments = (NodeList) xpath.evaluate("//comment()", document, XPathConstants.NODESET);
for (int i = 0; i < comments.getLength(); i++) {
org.w3c.dom.Node comment = comments.item(i);
comment.getParentNode().removeChild(comment);
}
org.w3c.dom.Node build = (org.w3c.dom.Node) xpath.evaluate("/project/build", document,
XPathConstants.NODE);
build.getParentNode().removeChild(build);
org.w3c.dom.Node reporting = (org.w3c.dom.Node) xpath.evaluate("/project/reporting", document,
XPathConstants.NODE);
reporting.getParentNode().removeChild(reporting);
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document),
new StreamResult(this.effectiveBom));
}
catch (Exception ex) {
throw new TaskExecutionException(task, ex);
}
}
}
}

View File

@ -7,6 +7,7 @@ plugins {
description = "Spring Boot Dependencies"
bom {
effectiveBomArtifact()
upgrade {
policy = "same-major-version"
gitHub {