Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add options to the Add Gradle Enterprise Maven recipe #3233

Merged
merged 2 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -56,23 +62,6 @@ public class AddGradleEnterpriseMavenExtension extends Recipe {
" <artifactId>gradle-enterprise-maven-extension</artifactId>\n" +
"</extension>";

@Language("xml")
private static final String GRADLE_ENTERPRISE_XML_FORMAT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n" +
"<gradleEnterprise\n" +
" xmlns=\"https://www.gradle.com/gradle-enterprise-maven\" " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"https://www.gradle.com/gradle-enterprise-maven" +
" https://www.gradle.com/schema/gradle-enterprise-maven.xsd\">\n" +
" <server>\n" +
" <url>%s</url>\n" +
" <allowUntrusted>%b</allowUntrusted>\n" +
" </server>\n" +
" <buildScan>\n" +
" <backgroundBuildScanUpload>false</backgroundBuildScanUpload>\n" +
" <publish>ALWAYS</publish>\n" +
" </buildScan>\n" +
"</gradleEnterprise>";

@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")
Expand All @@ -85,13 +74,50 @@ public class AddGradleEnterpriseMavenExtension extends Recipe {
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.",
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 {
alextu marked this conversation as resolved.
Show resolved Hide resolved
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";
Expand Down Expand Up @@ -132,8 +158,7 @@ protected List<SourceFile> visit(List<SourceFile> 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)) {
Expand All @@ -158,6 +183,59 @@ protected List<SourceFile> visit(List<SourceFile> 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);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how those kind of exceptions are usually handled in recipes ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing a mix of ctx.getOnError().accept(e), Markup.error(e) and throw new RuntimeException, and possibly others.

I think it will mostly depend on if your recipe will be executed as part of a larger chain, in which case you might want to go for "elegant" handing over just throwing a runtime exception. I'm guessing in this case you're fine with a RuntimeException, since we're also not expecting a lot of different failure modes here.

}
}

@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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -74,18 +75,10 @@ void addGradleEnterpriseMavenExtensionToExistingExtensionsXmlFile() {
xml(
null,
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<gradleEnterprise
xmlns="https://www.gradle.com/gradle-enterprise-maven" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.gradle.com/gradle-enterprise-maven https://www.gradle.com/schema/gradle-enterprise-maven.xsd">
<gradleEnterprise>
<server>
<url>https://foo</url>
<allowUntrusted>true</allowUntrusted>
</server>
<buildScan>
<backgroundBuildScanUpload>false</backgroundBuildScanUpload>
<publish>ALWAYS</publish>
</buildScan>
</gradleEnterprise>
""",
spec -> spec.path(".mvn/gradle-enterprise.xml")
Expand Down Expand Up @@ -114,19 +107,11 @@ void createNewExtensionsXmlFileIfNotExist() {
xml(
null,
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<gradleEnterprise
xmlns="https://www.gradle.com/gradle-enterprise-maven" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.gradle.com/gradle-enterprise-maven https://www.gradle.com/schema/gradle-enterprise-maven.xsd">
<server>
<url>https://foo</url>
<allowUntrusted>true</allowUntrusted>
</server>
<buildScan>
<backgroundBuildScanUpload>false</backgroundBuildScanUpload>
<publish>ALWAYS</publish>
</buildScan>
</gradleEnterprise>
<gradleEnterprise>
<server>
<url>https://foo</url>
</server>
</gradleEnterprise>
""",
spec -> spec.path(".mvn/gradle-enterprise.xml")
)
Expand All @@ -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,
Expand All @@ -156,18 +141,10 @@ void noVersionSpecified() {
xml(
null,
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<gradleEnterprise
xmlns="https://www.gradle.com/gradle-enterprise-maven" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.gradle.com/gradle-enterprise-maven https://www.gradle.com/schema/gradle-enterprise-maven.xsd">
<gradleEnterprise>
<server>
<url>https://foo</url>
<allowUntrusted>true</allowUntrusted>
</server>
<buildScan>
<backgroundBuildScanUpload>false</backgroundBuildScanUpload>
<publish>ALWAYS</publish>
</buildScan>
</gradleEnterprise>
""",
spec -> spec.path(".mvn/gradle-enterprise.xml")
Expand All @@ -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,
"""
<?xml version="1.0" encoding="UTF-8"?>
<extensions>
<extension>
<groupId>com.gradle</groupId>
<artifactId>gradle-enterprise-maven-extension</artifactId>
<version>1.17</version>
</extension>
</extensions>
""",
spec -> spec.path(".mvn/extensions.xml")
),
xml(
null,
"""
<gradleEnterprise>
<server>
<url>https://foo</url>
<allowUntrusted>true</allowUntrusted>
</server>
<buildScan>
<backgroundBuildScanUpload>false</backgroundBuildScanUpload>
<publish>ON_FAILURE</publish>
<capture>
<goalInputFiles>true</goalInputFiles>
</capture>
</buildScan>
</gradleEnterprise>
""",
spec -> spec.path(".mvn/gradle-enterprise.xml")
)
);
}

}