diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java index 65129da3bfa..54cc2af3660 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java @@ -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 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 { + + 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); + } + } + + } + } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java index 566a2780344..3fea13289ac 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java @@ -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 { 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 { } - private static final class StripUnrepeatableOutputAction implements Action { - - 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); - } - } - - } - } diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 78e32f8f921..5acb77a103e 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -7,6 +7,7 @@ plugins { description = "Spring Boot Dependencies" bom { + effectiveBomArtifact() upgrade { policy = "same-major-version" gitHub {