diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java b/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java index a95fb2cae8b..99834d3c7a6 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java @@ -15,12 +15,18 @@ */ package org.openrewrite.maven; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import lombok.EqualsAndHashCode; import lombok.Value; import org.intellij.lang.annotations.Language; import org.openrewrite.*; import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.maven.internal.MavenXmlMapper; import org.openrewrite.xml.*; import org.openrewrite.xml.tree.Xml; @@ -40,58 +46,80 @@ public class AddGradleEnterpriseMavenExtension extends Recipe { @Language("xml") private static final String EXTENSIONS_XML_FORMAT = "\n" + - "\n" + - ""; + "\n" + + ""; @Language("xml") private static final String ENTERPRISE_TAG_FORMAT = "\n" + - " com.gradle\n" + - " gradle-enterprise-maven-extension\n" + - " %s\n" + - ""; + " com.gradle\n" + + " gradle-enterprise-maven-extension\n" + + " %s\n" + + ""; @Language("xml") private static final String ENTERPRISE_TAG_FORMAT_WITHOUT_VERSION = "\n" + - " com.gradle\n" + - " gradle-enterprise-maven-extension\n" + - ""; - - @Language("xml") - private static final String GRADLE_ENTERPRISE_XML_FORMAT = "\n" + - "\n" + - " \n" + - " %s\n" + - " %b\n" + - " \n" + - " \n" + - " false\n" + - " ALWAYS\n" + - " \n" + - ""; + " com.gradle\n" + + " gradle-enterprise-maven-extension\n" + + ""; @Option(displayName = "Plugin version", - description = "An exact version number or node-style semver selector used to select the gradle-enterprise-maven-extension version.", - example = "1.x") + description = "An exact version number or node-style semver selector used to select the gradle-enterprise-maven-extension version.", + example = "1.x") @Nullable String version; @Option(displayName = "Server URL", - description = "The URL of the Gradle Enterprise server.", - example = "https://scans.gradle.com/") + description = "The URL of the Gradle Enterprise server.", + example = "https://scans.gradle.com/") String server; @Option(displayName = "Allow untrusted server", - description = "When set to `true` the plugin will be configured to allow unencrypted http connections with the server. " + - "If set to `false` or omitted, the plugin will refuse to communicate without transport layer security enabled.", - required = false, - example = "true") + description = "When set to `true` the extension will be configured to allow unencrypted http connections with the server. " + + "If set to `false` or omitted, the extension will refuse to communicate without transport layer security enabled.", + required = false, + example = "true") @Nullable Boolean allowUntrustedServer; + @Option(displayName = "Capture goal input files", + description = "When set to `true` the extension will capture additional information about the inputs to Maven goals. " + + "This increases the size of build scans, but is useful for diagnosing issues with goal caching. ", + required = false, + example = "true") + @Nullable + Boolean captureGoalInputFiles; + + @Option(displayName = "Upload in background", + description = "When set to `false` the extension will not upload build scan in the background. " + + "By default, build scans are uploaded in the background after the build has finished to avoid blocking the build process.", + required = false, + example = "false") + @Nullable + Boolean uploadInBackground; + + @Option(displayName = "Publish Criteria", + description = "When set to `always` the extension will publish build scans of every single build. " + + "This is the default behavior when omitted." + + "When set to `failure` the extension will only publish build scans when the build fails. " + + "When set to `demand` the extension will only publish build scans when explicitly requested.", + required = false, + valid = {"always", "failure", "demand"}, + example = "true") + @Nullable + PublishCriteria publishCriteria; + + public enum PublishCriteria { + Always("ALWAYS"), + Failure("ON_FAILURE"), + Demand("ON_DEMAND"); + + private final String xmlName; + + PublishCriteria(String xmlName) { + this.xmlName = xmlName; + } + } + @Override public String getDisplayName() { return "Add Gradle Enterprise Maven Extension to maven projects"; @@ -100,8 +128,8 @@ public String getDisplayName() { @Override public String getDescription() { return "To integrate gradle enterprise maven extension into maven projects, ensure that the " + - "`gradle-enterprise-maven-extension` is added to the `.mvn/extensions.xml` file if not already present. " + - "Additionally, configure the extension by adding the `.mvn/gradle-enterprise.xml` configuration file."; + "`gradle-enterprise-maven-extension` is added to the `.mvn/extensions.xml` file if not already present. " + + "Additionally, configure the extension by adding the `.mvn/gradle-enterprise.xml` configuration file."; } @Override @@ -132,15 +160,14 @@ protected List visit(List before, ExecutionContext ctx) return before; } - Xml.Document gradleEnterpriseXml = createNewXml(GRADLE_ENTERPRISE_XML_PATH, - String.format(GRADLE_ENTERPRISE_XML_FORMAT, server, allowUntrustedServer != null ? allowUntrustedServer : Boolean.FALSE)); + Xml.Document gradleEnterpriseXml = createNewXml(GRADLE_ENTERPRISE_XML_PATH, gradleEnterpriseConfiguration()); if (matchingExtensionsXmlFile.get() != null) { if (!(matchingExtensionsXmlFile.get() instanceof Xml.Document)) { throw new RuntimeException("The extensions.xml is not xml document type"); } - Xml.Document extensionsXml = ( Xml.Document) matchingExtensionsXmlFile.get(); + Xml.Document extensionsXml = (Xml.Document) matchingExtensionsXmlFile.get(); // find `gradle-enterprise-maven-extension` extension, do nothing if it already exists, boolean hasEnterpriseExtension = findExistingEnterpriseExtension(extensionsXml); @@ -158,6 +185,59 @@ protected List visit(List before, ExecutionContext ctx) return ListUtils.concat(ListUtils.concat(before, extensionsXml), gradleEnterpriseXml); } + @JacksonXmlRootElement(localName = "gradleEnterprise") + @Value + private static class GradleEnterpriseConfiguration { + ServerConfiguration server; + @Nullable + BuildScanConfiguration buildScan; + } + + @Value + private static class ServerConfiguration { + String url; + @Nullable + Boolean allowUntrusted; + } + + @Value + private static class BuildScanConfiguration { + @Nullable + Boolean backgroundBuildScanUpload; + @Nullable + String publish; + @Nullable + Capture capture; + } + + @Value + private static class Capture { + Boolean goalInputFiles; + } + + private String gradleEnterpriseConfiguration() { + BuildScanConfiguration buildScanConfiguration = buildScanConfiguration(); + ServerConfiguration serverConfiguration = new ServerConfiguration(server, allowUntrustedServer); + try { + ObjectMapper objectMapper = MavenXmlMapper.writeMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT); + return objectMapper.writeValueAsString(new GradleEnterpriseConfiguration(serverConfiguration, buildScanConfiguration)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Nullable + private BuildScanConfiguration buildScanConfiguration() { + if (uploadInBackground != null || publishCriteria != null || captureGoalInputFiles != null) { + return new BuildScanConfiguration(uploadInBackground, + publishCriteria != null ? publishCriteria.xmlName : null, + captureGoalInputFiles != null ? new Capture(captureGoalInputFiles) : null); + } + return null; + } + private static Xml.Document createNewXml(String filePath, String fileContents) { XmlParser parser = new XmlParser(); Xml.Document brandNewFile = parser.parse(fileContents).get(0); @@ -195,8 +275,8 @@ private Xml.Document addEnterpriseExtension(Xml.Document extensionsXml, Executio @Language("xml") String tagSource = version != null ? String.format(ENTERPRISE_TAG_FORMAT, version) : ENTERPRISE_TAG_FORMAT_WITHOUT_VERSION; AddToTagVisitor addToTagVisitor = new AddToTagVisitor<>( - extensionsXml.getRoot(), - Xml.Tag.build(tagSource)); + extensionsXml.getRoot(), + Xml.Tag.build(tagSource)); return (Xml.Document) addToTagVisitor.visit(extensionsXml, ctx); } } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtensionTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtensionTest.java index 88a5ac88457..1d1f8e966d5 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtensionTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtensionTest.java @@ -27,7 +27,8 @@ class AddGradleEnterpriseMavenExtensionTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(new AddGradleEnterpriseMavenExtension("1.17", "https://foo", true)); + spec.recipe(new AddGradleEnterpriseMavenExtension("1.17", "https://foo", null, + null, null, null)); } private static final SourceSpecs POM_XML_SOURCE_SPEC = pomXml( @@ -74,18 +75,10 @@ void addGradleEnterpriseMavenExtensionToExistingExtensionsXmlFile() { xml( null, """ - - + https://foo - true - - false - ALWAYS - """, spec -> spec.path(".mvn/gradle-enterprise.xml") @@ -114,19 +107,11 @@ void createNewExtensionsXmlFileIfNotExist() { xml( null, """ - - - - https://foo - true - - - false - ALWAYS - - + + + https://foo + + """, spec -> spec.path(".mvn/gradle-enterprise.xml") ) @@ -138,7 +123,7 @@ void createNewExtensionsXmlFileIfNotExist() { @Test void noVersionSpecified() { rewriteRun( - spec -> spec.recipe(new AddGradleEnterpriseMavenExtension(null, "https://foo", true)), + spec -> spec.recipe(new AddGradleEnterpriseMavenExtension(null, "https://foo", null, null, null, null)), POM_XML_SOURCE_SPEC, xml( null, @@ -156,18 +141,10 @@ void noVersionSpecified() { xml( null, """ - - + https://foo - true - - false - ALWAYS - """, spec -> spec.path(".mvn/gradle-enterprise.xml") @@ -190,4 +167,46 @@ void noChangeIfGradleEnterpriseXmlExists() { ) ); } + + @Test + void allSettings() { + rewriteRun( + spec -> spec.recipe(new AddGradleEnterpriseMavenExtension("1.17", "https://foo", true, true, false, AddGradleEnterpriseMavenExtension.PublishCriteria.Failure)), + POM_XML_SOURCE_SPEC, + xml( + null, + """ + + + + com.gradle + gradle-enterprise-maven-extension + 1.17 + + + """, + spec -> spec.path(".mvn/extensions.xml") + ), + xml( + null, + """ + + + https://foo + true + + + false + ON_FAILURE + + true + + + + """, + spec -> spec.path(".mvn/gradle-enterprise.xml") + ) + ); + } + }