Skip to content

Commit 9811523

Browse files
committed
Only create effective bom artifact when needed
Closes gh-22143
1 parent 63cac4b commit 9811523

File tree

3 files changed

+104
-91
lines changed

3 files changed

+104
-91
lines changed

buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,53 @@
1616

1717
package org.springframework.boot.build.bom;
1818

19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.io.InputStreamReader;
22+
import java.nio.charset.StandardCharsets;
1923
import java.util.ArrayList;
2024
import java.util.HashMap;
2125
import java.util.LinkedHashMap;
2226
import java.util.List;
2327
import java.util.Map;
2428
import java.util.stream.Collectors;
2529

30+
import javax.xml.parsers.DocumentBuilderFactory;
31+
import javax.xml.transform.TransformerFactory;
32+
import javax.xml.transform.dom.DOMSource;
33+
import javax.xml.transform.stream.StreamResult;
34+
import javax.xml.xpath.XPath;
35+
import javax.xml.xpath.XPathConstants;
36+
import javax.xml.xpath.XPathFactory;
37+
2638
import groovy.lang.Closure;
2739
import groovy.lang.GroovyObjectSupport;
2840
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
2941
import org.apache.maven.artifact.versioning.VersionRange;
42+
import org.gradle.api.Action;
43+
import org.gradle.api.GradleException;
3044
import org.gradle.api.InvalidUserCodeException;
3145
import org.gradle.api.InvalidUserDataException;
46+
import org.gradle.api.Project;
47+
import org.gradle.api.Task;
48+
import org.gradle.api.artifacts.Configuration;
3249
import org.gradle.api.artifacts.dsl.DependencyHandler;
3350
import org.gradle.api.plugins.JavaPlatformPlugin;
51+
import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
52+
import org.gradle.api.tasks.Sync;
53+
import org.gradle.api.tasks.TaskExecutionException;
3454
import org.gradle.util.ConfigureUtil;
55+
import org.w3c.dom.Document;
56+
import org.w3c.dom.NodeList;
3557

58+
import org.springframework.boot.build.DeployedPlugin;
3659
import org.springframework.boot.build.bom.Library.Exclusion;
3760
import org.springframework.boot.build.bom.Library.Group;
3861
import org.springframework.boot.build.bom.Library.Module;
3962
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
4063
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
64+
import org.springframework.boot.build.mavenplugin.MavenExec;
65+
import org.springframework.util.FileCopyUtils;
4166

4267
/**
4368
* DSL extensions for {@link BomPlugin}.
@@ -56,8 +81,11 @@ public class BomExtension {
5681

5782
private final DependencyHandler dependencyHandler;
5883

59-
public BomExtension(DependencyHandler dependencyHandler) {
84+
private final Project project;
85+
86+
public BomExtension(DependencyHandler dependencyHandler, Project project) {
6087
this.dependencyHandler = dependencyHandler;
88+
this.project = project;
6189
}
6290

6391
public List<Library> getLibraries() {
@@ -80,6 +108,43 @@ public void library(String name, String version, Closure<?> closure) {
80108
libraryHandler.prohibitedVersions));
81109
}
82110

111+
public void effectiveBomArtifact() {
112+
Configuration effectiveBomConfiguration = this.project.getConfigurations().create("effectiveBom");
113+
this.project.getTasks().matching((task) -> task.getName().equals(DeployedPlugin.GENERATE_POM_TASK_NAME))
114+
.all((task) -> {
115+
Sync syncBom = this.project.getTasks().create("syncBom", Sync.class);
116+
syncBom.dependsOn(task);
117+
File generatedBomDir = new File(this.project.getBuildDir(), "generated/bom");
118+
syncBom.setDestinationDir(generatedBomDir);
119+
syncBom.from(((GenerateMavenPom) task).getDestination(), (pom) -> pom.rename((name) -> "pom.xml"));
120+
try {
121+
String settingsXmlContent = FileCopyUtils
122+
.copyToString(new InputStreamReader(
123+
getClass().getClassLoader().getResourceAsStream("effective-bom-settings.xml"),
124+
StandardCharsets.UTF_8))
125+
.replace("localRepositoryPath",
126+
new File(this.project.getBuildDir(), "local-m2-repository").getAbsolutePath());
127+
syncBom.from(this.project.getResources().getText().fromString(settingsXmlContent),
128+
(settingsXml) -> settingsXml.rename((name) -> "settings.xml"));
129+
}
130+
catch (IOException ex) {
131+
throw new GradleException("Failed to prepare settings.xml", ex);
132+
}
133+
MavenExec generateEffectiveBom = this.project.getTasks().create("generateEffectiveBom",
134+
MavenExec.class);
135+
generateEffectiveBom.setProjectDir(generatedBomDir);
136+
File effectiveBom = new File(this.project.getBuildDir(),
137+
"generated/effective-bom/" + this.project.getName() + "-effective-bom.xml");
138+
generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom",
139+
"-Doutput=" + effectiveBom);
140+
generateEffectiveBom.dependsOn(syncBom);
141+
generateEffectiveBom.getOutputs().file(effectiveBom);
142+
generateEffectiveBom.doLast(new StripUnrepeatableOutputAction(effectiveBom));
143+
this.project.getArtifacts().add(effectiveBomConfiguration.getName(), effectiveBom,
144+
(artifact) -> artifact.builtBy(generateEffectiveBom));
145+
});
146+
}
147+
83148
private String createDependencyNotation(String groupId, String artifactId, DependencyVersion version) {
84149
return groupId + ":" + artifactId + ":" + version;
85150
}
@@ -298,4 +363,38 @@ public List<String> getIssueLabels() {
298363

299364
}
300365

366+
private static final class StripUnrepeatableOutputAction implements Action<Task> {
367+
368+
private final File effectiveBom;
369+
370+
private StripUnrepeatableOutputAction(File xmlFile) {
371+
this.effectiveBom = xmlFile;
372+
}
373+
374+
@Override
375+
public void execute(Task task) {
376+
try {
377+
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(this.effectiveBom);
378+
XPath xpath = XPathFactory.newInstance().newXPath();
379+
NodeList comments = (NodeList) xpath.evaluate("//comment()", document, XPathConstants.NODESET);
380+
for (int i = 0; i < comments.getLength(); i++) {
381+
org.w3c.dom.Node comment = comments.item(i);
382+
comment.getParentNode().removeChild(comment);
383+
}
384+
org.w3c.dom.Node build = (org.w3c.dom.Node) xpath.evaluate("/project/build", document,
385+
XPathConstants.NODE);
386+
build.getParentNode().removeChild(build);
387+
org.w3c.dom.Node reporting = (org.w3c.dom.Node) xpath.evaluate("/project/reporting", document,
388+
XPathConstants.NODE);
389+
reporting.getParentNode().removeChild(reporting);
390+
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document),
391+
new StreamResult(this.effectiveBom));
392+
}
393+
catch (Exception ex) {
394+
throw new TaskExecutionException(task, ex);
395+
}
396+
}
397+
398+
}
399+
301400
}

buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java

Lines changed: 3 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,25 @@
1616

1717
package org.springframework.boot.build.bom;
1818

19-
import java.io.File;
20-
import java.io.IOException;
21-
import java.io.InputStreamReader;
22-
import java.nio.charset.StandardCharsets;
2319
import java.util.List;
2420
import java.util.stream.Collectors;
2521

26-
import javax.xml.parsers.DocumentBuilderFactory;
27-
import javax.xml.transform.TransformerFactory;
28-
import javax.xml.transform.dom.DOMSource;
29-
import javax.xml.transform.stream.StreamResult;
30-
import javax.xml.xpath.XPath;
31-
import javax.xml.xpath.XPathConstants;
32-
import javax.xml.xpath.XPathFactory;
33-
3422
import groovy.util.Node;
3523
import groovy.xml.QName;
36-
import org.gradle.api.Action;
37-
import org.gradle.api.GradleException;
3824
import org.gradle.api.Plugin;
3925
import org.gradle.api.Project;
40-
import org.gradle.api.Task;
4126
import org.gradle.api.artifacts.Configuration;
4227
import org.gradle.api.plugins.JavaPlatformExtension;
4328
import org.gradle.api.plugins.JavaPlatformPlugin;
4429
import org.gradle.api.plugins.PluginContainer;
4530
import org.gradle.api.publish.PublishingExtension;
4631
import org.gradle.api.publish.maven.MavenPom;
4732
import org.gradle.api.publish.maven.MavenPublication;
48-
import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
49-
import org.gradle.api.tasks.Sync;
50-
import org.gradle.api.tasks.TaskExecutionException;
51-
import org.w3c.dom.Document;
52-
import org.w3c.dom.NodeList;
5333

5434
import org.springframework.boot.build.DeployedPlugin;
5535
import org.springframework.boot.build.MavenRepositoryPlugin;
5636
import org.springframework.boot.build.bom.Library.Group;
5737
import org.springframework.boot.build.bom.bomr.UpgradeBom;
58-
import org.springframework.boot.build.mavenplugin.MavenExec;
59-
import org.springframework.util.FileCopyUtils;
6038

6139
/**
6240
* {@link Plugin} for defining a bom. Dependencies are added as constraints in the
@@ -78,43 +56,12 @@ public void apply(Project project) {
7856
JavaPlatformExtension javaPlatform = project.getExtensions().getByType(JavaPlatformExtension.class);
7957
javaPlatform.allowDependencies();
8058
createApiEnforcedConfiguration(project);
81-
BomExtension bom = project.getExtensions().create("bom", BomExtension.class, project.getDependencies());
59+
BomExtension bom = project.getExtensions().create("bom", BomExtension.class, project.getDependencies(),
60+
project);
8261
project.getTasks().create("bomrCheck", CheckBom.class, bom);
8362
project.getTasks().create("bomrUpgrade", UpgradeBom.class, bom);
8463
new PublishingCustomizer(project, bom).customize();
85-
Configuration effectiveBomConfiguration = project.getConfigurations().create("effectiveBom");
86-
project.getTasks().matching((task) -> task.getName().equals(DeployedPlugin.GENERATE_POM_TASK_NAME))
87-
.all((task) -> {
88-
Sync syncBom = project.getTasks().create("syncBom", Sync.class);
89-
syncBom.dependsOn(task);
90-
File generatedBomDir = new File(project.getBuildDir(), "generated/bom");
91-
syncBom.setDestinationDir(generatedBomDir);
92-
syncBom.from(((GenerateMavenPom) task).getDestination(), (pom) -> pom.rename((name) -> "pom.xml"));
93-
try {
94-
String settingsXmlContent = FileCopyUtils
95-
.copyToString(new InputStreamReader(
96-
getClass().getClassLoader().getResourceAsStream("effective-bom-settings.xml"),
97-
StandardCharsets.UTF_8))
98-
.replace("localRepositoryPath",
99-
new File(project.getBuildDir(), "local-m2-repository").getAbsolutePath());
100-
syncBom.from(project.getResources().getText().fromString(settingsXmlContent),
101-
(settingsXml) -> settingsXml.rename((name) -> "settings.xml"));
102-
}
103-
catch (IOException ex) {
104-
throw new GradleException("Failed to prepare settings.xml", ex);
105-
}
106-
MavenExec generateEffectiveBom = project.getTasks().create("generateEffectiveBom", MavenExec.class);
107-
generateEffectiveBom.setProjectDir(generatedBomDir);
108-
File effectiveBom = new File(project.getBuildDir(),
109-
"generated/effective-bom/" + project.getName() + "-effective-bom.xml");
110-
generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom",
111-
"-Doutput=" + effectiveBom);
112-
generateEffectiveBom.dependsOn(syncBom);
113-
generateEffectiveBom.getOutputs().file(effectiveBom);
114-
generateEffectiveBom.doLast(new StripUnrepeatableOutputAction(effectiveBom));
115-
project.getArtifacts().add(effectiveBomConfiguration.getName(), effectiveBom,
116-
(artifact) -> artifact.builtBy(generateEffectiveBom));
117-
});
64+
11865
}
11966

12067
private void createApiEnforcedConfiguration(Project project) {
@@ -276,38 +223,4 @@ private boolean isNodeWithName(Object candidate, String name) {
276223

277224
}
278225

279-
private static final class StripUnrepeatableOutputAction implements Action<Task> {
280-
281-
private final File effectiveBom;
282-
283-
private StripUnrepeatableOutputAction(File xmlFile) {
284-
this.effectiveBom = xmlFile;
285-
}
286-
287-
@Override
288-
public void execute(Task task) {
289-
try {
290-
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(this.effectiveBom);
291-
XPath xpath = XPathFactory.newInstance().newXPath();
292-
NodeList comments = (NodeList) xpath.evaluate("//comment()", document, XPathConstants.NODESET);
293-
for (int i = 0; i < comments.getLength(); i++) {
294-
org.w3c.dom.Node comment = comments.item(i);
295-
comment.getParentNode().removeChild(comment);
296-
}
297-
org.w3c.dom.Node build = (org.w3c.dom.Node) xpath.evaluate("/project/build", document,
298-
XPathConstants.NODE);
299-
build.getParentNode().removeChild(build);
300-
org.w3c.dom.Node reporting = (org.w3c.dom.Node) xpath.evaluate("/project/reporting", document,
301-
XPathConstants.NODE);
302-
reporting.getParentNode().removeChild(reporting);
303-
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document),
304-
new StreamResult(this.effectiveBom));
305-
}
306-
catch (Exception ex) {
307-
throw new TaskExecutionException(task, ex);
308-
}
309-
}
310-
311-
}
312-
313226
}

spring-boot-project/spring-boot-dependencies/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ plugins {
77
description = "Spring Boot Dependencies"
88

99
bom {
10+
effectiveBomArtifact()
1011
upgrade {
1112
policy = "same-minor-version"
1213
gitHub {

0 commit comments

Comments
 (0)