From d3ae411d4d7f94dd6d1e191f74d6e31067455808 Mon Sep 17 00:00:00 2001 From: leanne Date: Mon, 6 Jan 2025 13:50:34 -0800 Subject: [PATCH 1/3] Fixing the estimated saved time in the gradle wrapper upgrade Moving the change to the markers to a different recipe which returns 0m as the estimated saved time --- .../gradle/UpdateGradleWrapper.java | 440 ++-------------- .../gradle/UpdateGradleWrapperFiles.java | 498 ++++++++++++++++++ .../gradle/UpdateGradleWrapperMarkers.java | 149 ++++++ 3 files changed, 679 insertions(+), 408 deletions(-) create mode 100755 rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperFiles.java create mode 100755 rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapper.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapper.java index 80fa69ba0c0..96f28479d6a 100755 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapper.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapper.java @@ -15,42 +15,32 @@ */ package org.openrewrite.gradle; -import lombok.*; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; import org.jspecify.annotations.Nullable; -import org.openrewrite.*; -import org.openrewrite.gradle.search.FindGradleProject; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; import org.openrewrite.gradle.util.DistributionInfos; import org.openrewrite.gradle.util.GradleWrapper; -import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.StringUtils; -import org.openrewrite.marker.BuildTool; -import org.openrewrite.marker.Markers; -import org.openrewrite.properties.PropertiesParser; -import org.openrewrite.properties.PropertiesVisitor; -import org.openrewrite.properties.search.FindProperties; -import org.openrewrite.properties.tree.Properties; -import org.openrewrite.quark.Quark; -import org.openrewrite.remote.Remote; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.tree.J; import org.openrewrite.semver.ExactVersion; import org.openrewrite.semver.Semver; -import org.openrewrite.semver.VersionComparator; -import org.openrewrite.text.PlainText; import java.net.URI; -import java.time.ZonedDateTime; -import java.util.*; - -import static java.util.Objects.requireNonNull; -import static org.openrewrite.PathUtils.equalIgnoringSeparators; -import static org.openrewrite.gradle.util.GradleWrapper.*; -import static org.openrewrite.internal.StringUtils.isBlank; +import java.util.Arrays; +import java.util.List; @RequiredArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false) -public class UpdateGradleWrapper extends ScanningRecipe { +public class UpdateGradleWrapper extends Recipe { @Override public String getDisplayName() { @@ -115,408 +105,42 @@ public String getDescription() { final String distributionChecksum; @Override - public Validated validate() { - Validated validated = super.validate(); - if (wrapperUri != null && (version != null || distribution != null)) { - return Validated.invalid("wrapperUri", wrapperUri, "WrapperUri cannot be used with version and/or distribution parameter"); - } - if (wrapperUri == null && distributionChecksum != null) { - return Validated.invalid("distributionChecksum", distributionChecksum, "DistributionChecksum can only be used with wrapperUri"); - } - if (version != null) { - validated = validated.and(Semver.validate(version, null)); - } - return validated; + public List getRecipeList() { + return Arrays.asList( + new UpdateGradleWrapperFiles(version, distribution, addIfMissing, wrapperUri, distributionChecksum), + new UpdateGradleWrapperMarkers(version, distribution, addIfMissing, wrapperUri, distributionChecksum) + ); } - @NonFinal - @Nullable - transient GradleWrapper gradleWrapper; + @Override + public TreeVisitor getVisitor() { + return new JavaIsoVisitor() { + @Override + public J preVisit(J tree, ExecutionContext ctx) { + return tree; + } + }; + } - private GradleWrapper getGradleWrapper(ExecutionContext ctx) { + public static GradleWrapper getGradleWrapper(ExecutionContext ctx, String wrapperUri, String distribution, String version, @Nullable GradleWrapper gradleWrapper) { if (gradleWrapper == null) { if (wrapperUri != null) { - return gradleWrapper = GradleWrapper.create(URI.create(wrapperUri), ctx); + return GradleWrapper.create(URI.create(wrapperUri), ctx); } try { - gradleWrapper = GradleWrapper.create(distribution, version, null, ctx); + return GradleWrapper.create(distribution, version, null, ctx); } catch (Exception e) { // services.gradle.org is unreachable // If the user didn't specify a wrapperUri, but they did provide a specific version we assume they know this version // is available from whichever distribution url they were previously using and update the version if (!StringUtils.isBlank(version) && Semver.validate(version, null).getValue() instanceof ExactVersion) { - return gradleWrapper = new GradleWrapper(version, new DistributionInfos("", null, null)); + return new GradleWrapper(version, new DistributionInfos("", null, null)); } throw new IllegalArgumentException( "Could not reach services.gradle.org. " + - "To use this recipe in environments where services.gradle.org is unavailable specify a wrapperUri or exact version.", e); + "To use this recipe in environments where services.gradle.org is unavailable specify a wrapperUri or exact version.", e); } } return gradleWrapper; } - - @Data - public static class GradleWrapperState { - boolean gradleProject = false; - boolean needsWrapperUpdate = false; - - @Nullable - BuildTool updatedMarker; - - boolean addGradleWrapperProperties = true; - boolean addGradleWrapperJar = true; - boolean addGradleShellScript = true; - boolean addGradleBatchScript = true; - } - - @Override - public GradleWrapperState getInitialValue(ExecutionContext ctx) { - return new GradleWrapperState(); - } - - @Override - public TreeVisitor getScanner(GradleWrapperState acc) { - return Preconditions.or( - new PropertiesVisitor() { - @Override - public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { - if (!super.isAcceptable(sourceFile, ctx)) { - return false; - } - - if (equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_PROPERTIES_LOCATION)) { - acc.addGradleWrapperProperties = false; - } else if (!PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_PROPERTIES_LOCATION_RELATIVE_PATH)) { - return false; - } - - Optional maybeBuildTool = sourceFile.getMarkers().findFirst(BuildTool.class); - if (!maybeBuildTool.isPresent()) { - return false; - } - BuildTool buildTool = maybeBuildTool.get(); - if (buildTool.getType() != BuildTool.Type.Gradle) { - return false; - } - - String gradleWrapperVersion = getGradleWrapper(ctx).getVersion(); - - VersionComparator versionComparator = requireNonNull(Semver.validate(isBlank(version) ? "latest.release" : version, null).getValue()); - int compare = versionComparator.compare(null, buildTool.getVersion(), gradleWrapperVersion); - // maybe we want to update the distribution type or url - if (compare < 0) { - acc.needsWrapperUpdate = true; - acc.updatedMarker = buildTool.withVersion(gradleWrapperVersion); - return true; - } else { - return compare == 0; - } - } - - @Override - public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) { - if (!"distributionUrl".equals(entry.getKey())) { - return entry; - } - - // Typical example: https://services.gradle.org/distributions/gradle-7.4-all.zip or https://company.com/repo/gradle-8.2-bin.zip - String currentDistributionUrl = entry.getValue().getText(); - - GradleWrapper gradleWrpr = getGradleWrapper(ctx); - if (StringUtils.isBlank(gradleWrpr.getDistributionUrl()) && !StringUtils.isBlank(version) && - Semver.validate(version, null).getValue() instanceof ExactVersion) { - String newDownloadUrl = currentDistributionUrl.replace("\\", "") - .replaceAll("(.*gradle-)(\\d+\\.\\d+(?:\\.\\d+)?)(.*-(?:bin|all).zip)", - "$1" + gradleWrapper.getVersion() + "$3"); - gradleWrapper = new GradleWrapper(version, new DistributionInfos(newDownloadUrl, null, null)); - } - String wrapperHost = currentDistributionUrl.substring(0, currentDistributionUrl.lastIndexOf("/")) + "/gradle-"; - if (StringUtils.isBlank(wrapperUri) && !StringUtils.isBlank(gradleWrpr.getDistributionUrl()) && - !gradleWrpr.getPropertiesFormattedUrl().startsWith(wrapperHost)) { - String newDownloadUrl = gradleWrpr.getDistributionUrl() - .replace("\\", "") - .replaceAll("(.*gradle-)(\\d+\\.\\d+(?:\\.\\d+)?)(.*-(?:bin|all).zip)", - wrapperHost + gradleWrapper.getVersion() + "$3"); - gradleWrapper = new GradleWrapper(gradleWrpr.getVersion(), new DistributionInfos(newDownloadUrl, null, null)); - } - - if (!gradleWrapper.getPropertiesFormattedUrl().equals(currentDistributionUrl)) { - acc.needsWrapperUpdate = true; - } - return entry; - } - }, - new TreeVisitor() { - @Override - public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { - if (new FindGradleProject(FindGradleProject.SearchCriteria.Marker).getVisitor().visitNonNull(sourceFile, ctx) != sourceFile) { - acc.gradleProject = true; - } - - if ((sourceFile instanceof Quark || sourceFile instanceof Remote) && - equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_JAR_LOCATION)) { - acc.addGradleWrapperJar = false; - return true; - } - - if (sourceFile instanceof PlainText) { - if (equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_BATCH_LOCATION)) { - acc.addGradleBatchScript = false; - return true; - } else if (equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_SCRIPT_LOCATION)) { - acc.addGradleShellScript = false; - return true; - } - } - - return false; - } - - @Override - public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { - // "work" already performed by `isAcceptable()`; no need to visit anymore - return tree; - } - } - ); - } - - @Override - public Collection generate(GradleWrapperState acc, ExecutionContext ctx) { - if (Boolean.FALSE.equals(addIfMissing)) { - return Collections.emptyList(); - } - - if (!acc.gradleProject) { - return Collections.emptyList(); - } - - if (!(acc.addGradleWrapperJar || acc.addGradleWrapperProperties || acc.addGradleBatchScript || acc.addGradleShellScript)) { - return Collections.emptyList(); - } - - List gradleWrapperFiles = new ArrayList<>(); - ZonedDateTime now = ZonedDateTime.now(); - - GradleWrapper gradleWrapper = getGradleWrapper(ctx); - - if (acc.addGradleWrapperProperties) { - String checksum = gradleWrapper.getDistributionChecksum() == null ? null : gradleWrapper.getDistributionChecksum().getHexValue(); - if (wrapperUri != null && distributionChecksum != null && checksum == null) { - checksum = distributionChecksum; - } - - //noinspection UnusedProperty - Properties.File gradleWrapperProperties = new PropertiesParser().parse( - "distributionBase=GRADLE_USER_HOME\n" + - "distributionPath=wrapper/dists\n" + - "distributionUrl=" + gradleWrapper.getPropertiesFormattedUrl() + "\n" + - (checksum == null ? "" : "distributionSha256Sum=" + checksum + "\n") + - "zipStoreBase=GRADLE_USER_HOME\n" + - "zipStorePath=wrapper/dists") - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Could not parse as properties")) - .withSourcePath(WRAPPER_PROPERTIES_LOCATION); - gradleWrapperFiles.add(gradleWrapperProperties); - } - - FileAttributes wrapperScriptAttributes = new FileAttributes(now, now, now, true, true, true, 1L); - if (acc.addGradleShellScript) { - String gradlewText = unixScript(gradleWrapper, ctx); - PlainText gradlew = PlainText.builder() - .text(gradlewText) - .sourcePath(WRAPPER_SCRIPT_LOCATION) - .fileAttributes(wrapperScriptAttributes) - .build(); - gradleWrapperFiles.add(gradlew); - } - - if (acc.addGradleBatchScript) { - String gradlewBatText = batchScript(gradleWrapper, ctx); - PlainText gradlewBat = PlainText.builder() - .text(gradlewBatText) - .sourcePath(WRAPPER_BATCH_LOCATION) - .fileAttributes(wrapperScriptAttributes) - .build(); - gradleWrapperFiles.add(gradlewBat); - } - - if (acc.addGradleWrapperJar) { - gradleWrapperFiles.add(gradleWrapper.wrapperJar()); - } - - return gradleWrapperFiles; - } - - @Override - public TreeVisitor getVisitor(GradleWrapperState acc) { - if (!acc.needsWrapperUpdate) { - return TreeVisitor.noop(); - } - - return new TreeVisitor() { - - @Override - public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { - if (!(tree instanceof SourceFile)) { - return tree; - } - - SourceFile sourceFile = (SourceFile) tree; - if (acc.updatedMarker != null) { - Optional maybeCurrentMarker = sourceFile.getMarkers().findFirst(BuildTool.class); - if (maybeCurrentMarker.isPresent()) { - BuildTool currentMarker = maybeCurrentMarker.get(); - if (currentMarker.getType() != BuildTool.Type.Gradle) { - return sourceFile; - } - VersionComparator versionComparator = requireNonNull(Semver.validate(isBlank(version) ? "latest.release" : version, null).getValue()); - int compare = versionComparator.compare(null, currentMarker.getVersion(), acc.updatedMarker.getVersion()); - if (compare < 0) { - sourceFile = sourceFile.withMarkers(sourceFile.getMarkers().setByType(acc.updatedMarker)); - } else { - return sourceFile; - } - } - } - - GradleWrapper gradleWrapper = getGradleWrapper(ctx); - if (sourceFile instanceof PlainText && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_SCRIPT_LOCATION_RELATIVE_PATH)) { - String gradlewText = unixScript(gradleWrapper, ctx); - PlainText gradlew = (PlainText) setExecutable(sourceFile); - if (!gradlewText.equals(gradlew.getText())) { - gradlew = gradlew.withText(gradlewText); - } - return gradlew; - } - if (sourceFile instanceof PlainText && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_BATCH_LOCATION_RELATIVE_PATH)) { - String gradlewBatText = batchScript(gradleWrapper, ctx); - PlainText gradlewBat = (PlainText) setExecutable(sourceFile); - if (!gradlewBatText.equals(gradlewBat.getText())) { - gradlewBat = gradlewBat.withText(gradlewBatText); - } - return gradlewBat; - } - if (sourceFile instanceof Properties.File && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_PROPERTIES_LOCATION_RELATIVE_PATH)) { - return new WrapperPropertiesVisitor(gradleWrapper).visitNonNull(sourceFile, ctx); - } - if ((sourceFile instanceof Quark || sourceFile instanceof Remote) && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_JAR_LOCATION_RELATIVE_PATH)) { - return gradleWrapper.wrapperJar(sourceFile); - } - return sourceFile; - } - }; - } - - private static T setExecutable(T sourceFile) { - FileAttributes attributes = sourceFile.getFileAttributes(); - if (attributes == null) { - ZonedDateTime now = ZonedDateTime.now(); - return sourceFile.withFileAttributes(new FileAttributes(now, now, now, true, true, true, 1)); - } else if (!attributes.isExecutable()) { - return sourceFile.withFileAttributes(attributes.withExecutable(true)); - } - return sourceFile; - } - - private String unixScript(GradleWrapper gradleWrapper, ExecutionContext ctx) { - Map binding = new HashMap<>(); - String defaultJvmOpts = defaultJvmOpts(gradleWrapper); - binding.put("defaultJvmOpts", StringUtils.isNotEmpty(defaultJvmOpts) ? "'" + defaultJvmOpts + "'" : ""); - binding.put("classpath", "$APP_HOME/gradle/wrapper/gradle-wrapper.jar"); - - String gradlewTemplate = StringUtils.readFully(gradleWrapper.gradlew().getInputStream(ctx)); - return renderTemplate(gradlewTemplate, binding, "\n"); - } - - private String batchScript(GradleWrapper gradleWrapper, ExecutionContext ctx) { - Map binding = new HashMap<>(); - binding.put("defaultJvmOpts", defaultJvmOpts(gradleWrapper)); - binding.put("classpath", "%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar"); - - String gradlewBatTemplate = StringUtils.readFully(gradleWrapper.gradlewBat().getInputStream(ctx)); - return renderTemplate(gradlewBatTemplate, binding, "\r\n"); - } - - private String defaultJvmOpts(GradleWrapper gradleWrapper) { - VersionComparator gradle53VersionComparator = requireNonNull(Semver.validate("[5.3,)", null).getValue()); - VersionComparator gradle50VersionComparator = requireNonNull(Semver.validate("[5.0,)", null).getValue()); - - if (gradle53VersionComparator.isValid(null, gradleWrapper.getVersion())) { - return "\"-Xmx64m\" \"-Xms64m\""; - } else if (gradle50VersionComparator.isValid(null, gradleWrapper.getVersion())) { - return "\"-Xmx64m\""; - } - return ""; - } - - private String renderTemplate(String source, Map parameters, String lineSeparator) { - Map binding = new HashMap<>(parameters); - binding.put("applicationName", "Gradle"); - binding.put("optsEnvironmentVar", "GRADLE_OPTS"); - binding.put("exitEnvironmentVar", "GRADLE_EXIT_CONSOLE"); - binding.put("mainClassName", "org.gradle.wrapper.GradleWrapperMain"); - binding.put("appNameSystemProperty", "org.gradle.appname"); - binding.put("appHomeRelativePath", ""); - binding.put("modulePath", ""); - - String script = source; - for (Map.Entry variable : binding.entrySet()) { - script = script.replace("${" + variable.getKey() + "}", variable.getValue()) - .replace("$" + variable.getKey(), variable.getValue()); - } - - script = script.replaceAll("(?sm)<% /\\*.*?\\*/ %>", ""); - script = script.replaceAll("(?sm)<% if \\( mainClassName\\.startsWith\\('--module '\\) \\) \\{.*?} %>", ""); - script = script.replaceAll("(?sm)<% if \\( appNameSystemProperty \\) \\{.*?%>(.*?)<% } %>", "$1"); - script = script.replace("\\$", "$"); - script = script.replaceAll("DIRNAME=\\.\\\\[\r\n]", "DIRNAME=."); - script = script.replace("\\\\", "\\"); - script = script.replaceAll("\r\n|\r|\n", lineSeparator); - - return script; - } - - private static class WrapperPropertiesVisitor extends PropertiesVisitor { - - private static final String DISTRIBUTION_SHA_256_SUM_KEY = "distributionSha256Sum"; - private final GradleWrapper gradleWrapper; - - public WrapperPropertiesVisitor(GradleWrapper gradleWrapper) { - this.gradleWrapper = gradleWrapper; - } - - @Override - public Properties visitFile(Properties.File file, ExecutionContext ctx) { - Properties p = super.visitFile(file, ctx); - Set checksumKey = FindProperties.find(p, DISTRIBUTION_SHA_256_SUM_KEY, false); - if (checksumKey.isEmpty() && gradleWrapper.getDistributionChecksum() != null) { - Properties.Value propertyValue = new Properties.Value(Tree.randomId(), "", Markers.EMPTY, gradleWrapper.getDistributionChecksum().getHexValue()); - Properties.Entry entry = new Properties.Entry(Tree.randomId(), "\n", Markers.EMPTY, DISTRIBUTION_SHA_256_SUM_KEY, "", Properties.Entry.Delimiter.EQUALS, propertyValue); - List contentList = ListUtils.concat(((Properties.File) p).getContent(), entry); - p = ((Properties.File) p).withContent(contentList); - } else if (!checksumKey.isEmpty() && gradleWrapper.getDistributionChecksum() == null) { - List contentList = ListUtils.map(((Properties.File) p).getContent(), c -> { - if (c instanceof Properties.Entry && DISTRIBUTION_SHA_256_SUM_KEY.equals(((Properties.Entry) c).getKey())) { - return null; - } - return c; - }); - p = ((Properties.File) p).withContent(contentList); - } - return p; - } - - @Override - public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) { - if ("distributionUrl".equals(entry.getKey())) { - Properties.Value value = entry.getValue(); - return entry.withValue(value.withText(gradleWrapper.getPropertiesFormattedUrl())); - } - if (DISTRIBUTION_SHA_256_SUM_KEY.equals(entry.getKey()) && gradleWrapper.getDistributionChecksum() != null) { - return entry.withValue(entry.getValue().withText(gradleWrapper.getDistributionChecksum().getHexValue())); - } - return entry; - } - } } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperFiles.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperFiles.java new file mode 100755 index 00000000000..1ca1b50e0bf --- /dev/null +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperFiles.java @@ -0,0 +1,498 @@ +/* + * Copyright 2022 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle; + +import lombok.*; +import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.gradle.search.FindGradleProject; +import org.openrewrite.gradle.util.DistributionInfos; +import org.openrewrite.gradle.util.GradleWrapper; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.marker.BuildTool; +import org.openrewrite.marker.Markers; +import org.openrewrite.properties.PropertiesParser; +import org.openrewrite.properties.PropertiesVisitor; +import org.openrewrite.properties.search.FindProperties; +import org.openrewrite.properties.tree.Properties; +import org.openrewrite.quark.Quark; +import org.openrewrite.remote.Remote; +import org.openrewrite.semver.ExactVersion; +import org.openrewrite.semver.Semver; +import org.openrewrite.semver.VersionComparator; +import org.openrewrite.text.PlainText; + +import java.time.ZonedDateTime; +import java.util.*; + +import static java.util.Objects.requireNonNull; +import static org.openrewrite.PathUtils.equalIgnoringSeparators; +import static org.openrewrite.gradle.util.GradleWrapper.*; +import static org.openrewrite.internal.StringUtils.isBlank; + +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +@EqualsAndHashCode(callSuper = false) +public class UpdateGradleWrapperFiles extends ScanningRecipe { + + @Override + public String getDisplayName() { + return "Update Gradle wrapper"; + } + + @Override + public String getDescription() { + return "Update the version of Gradle used in an existing Gradle wrapper. " + + "Queries services.gradle.org to determine the available releases, but prefers the artifact repository URL " + + "which already exists within the wrapper properties file. " + + "If your artifact repository does not contain the same Gradle distributions as services.gradle.org, " + + "then the recipe may suggest a version which is not available in your artifact repository."; + } + + @Getter + @Option(displayName = "New version", + description = "An exact version number or node-style semver selector used to select the version number. " + + "Defaults to the latest release available from services.gradle.org if not specified.", + example = "7.x", + required = false) + @Nullable + final String version; + + @Getter + @Option(displayName = "Distribution type", + description = "The distribution of Gradle to use. \"bin\" includes Gradle binaries. " + + "\"all\" includes Gradle binaries, source code, and documentation. " + + "Defaults to \"bin\".", + valid = {"bin", "all"}, + required = false + ) + @Nullable + final String distribution; + + @Getter + @Option(displayName = "Add if missing", + description = "Add a Gradle wrapper, if it's missing. Defaults to `true`.", + required = false) + @Nullable + final Boolean addIfMissing; + + @Getter + @Option(example = "https://services.gradle.org/distributions/gradle-${version}-${distribution}.zip", + displayName = "Wrapper URI", + description = "The URI of the Gradle wrapper distribution. " + + "Lookup of available versions still requires access to https://services.gradle.org " + + "When this is specified the exact literal values supplied for `version` and `distribution` " + + "will be interpolated into this string wherever `${version}` and `${distribution}` appear respectively. " + + "Defaults to https://services.gradle.org/distributions/gradle-${version}-${distribution}.zip.", + required = false) + @Nullable + final String wrapperUri; + + @Getter + @Option(example = "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda", + displayName = "SHA-256 checksum", + description = "The SHA-256 checksum of the Gradle distribution. " + + "If specified, the recipe will add the checksum along with the custom distribution URL.", + required = false) + @Nullable + final String distributionChecksum; + + @Override + public Validated validate() { + Validated validated = super.validate(); + if (wrapperUri != null && (version != null || distribution != null)) { + return Validated.invalid("wrapperUri", wrapperUri, "WrapperUri cannot be used with version and/or distribution parameter"); + } + if (wrapperUri == null && distributionChecksum != null) { + return Validated.invalid("distributionChecksum", distributionChecksum, "DistributionChecksum can only be used with wrapperUri"); + } + if (version != null) { + validated = validated.and(Semver.validate(version, null)); + } + return validated; + } + + @NonFinal + @Nullable + transient GradleWrapper gradleWrapper; + + private GradleWrapper getGradleWrapper(ExecutionContext ctx) { + gradleWrapper = UpdateGradleWrapper.getGradleWrapper(ctx, wrapperUri, distribution, version, gradleWrapper); + return gradleWrapper; + } + + @Data + public static class GradleWrapperState { + boolean gradleProject = false; + boolean needsWrapperUpdate = false; + + boolean addGradleWrapperProperties = true; + boolean addGradleWrapperJar = true; + boolean addGradleShellScript = true; + boolean addGradleBatchScript = true; + } + + @Override + public GradleWrapperState getInitialValue(ExecutionContext ctx) { + return new GradleWrapperState(); + } + + @Override + public TreeVisitor getScanner(GradleWrapperState acc) { + return Preconditions.or( + new PropertiesVisitor() { + @Override + public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { + if (!super.isAcceptable(sourceFile, ctx)) { + return false; + } + + if (equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_PROPERTIES_LOCATION)) { + acc.addGradleWrapperProperties = false; + } else if (!PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_PROPERTIES_LOCATION_RELATIVE_PATH)) { + return false; + } + + Optional maybeBuildTool = sourceFile.getMarkers().findFirst(BuildTool.class); + if (!maybeBuildTool.isPresent()) { + return false; + } + BuildTool buildTool = maybeBuildTool.get(); + if (buildTool.getType() != BuildTool.Type.Gradle) { + return false; + } + + String gradleWrapperVersion = getGradleWrapper(ctx).getVersion(); + + VersionComparator versionComparator = requireNonNull(Semver.validate(isBlank(version) ? "latest.release" : version, null).getValue()); + int compare = versionComparator.compare(null, buildTool.getVersion(), gradleWrapperVersion); + // maybe we want to update the distribution type or url + if (compare < 0) { + acc.needsWrapperUpdate = true; + return true; + } else { + return compare == 0; + } + } + + @Override + public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) { + if (!"distributionUrl".equals(entry.getKey())) { + return entry; + } + + // Typical example: https://services.gradle.org/distributions/gradle-7.4-all.zip or https://company.com/repo/gradle-8.2-bin.zip + String currentDistributionUrl = entry.getValue().getText(); + + GradleWrapper gradleWrpr = getGradleWrapper(ctx); + if (StringUtils.isBlank(gradleWrpr.getDistributionUrl()) && !StringUtils.isBlank(version) && + Semver.validate(version, null).getValue() instanceof ExactVersion) { + String newDownloadUrl = currentDistributionUrl.replace("\\", "") + .replaceAll("(.*gradle-)(\\d+\\.\\d+(?:\\.\\d+)?)(.*-(?:bin|all).zip)", + "$1" + gradleWrapper.getVersion() + "$3"); + gradleWrapper = new GradleWrapper(version, new DistributionInfos(newDownloadUrl, null, null)); + } + String wrapperHost = currentDistributionUrl.substring(0, currentDistributionUrl.lastIndexOf("/")) + "/gradle-"; + if (StringUtils.isBlank(wrapperUri) && !StringUtils.isBlank(gradleWrpr.getDistributionUrl()) && + !gradleWrpr.getPropertiesFormattedUrl().startsWith(wrapperHost)) { + String newDownloadUrl = gradleWrpr.getDistributionUrl() + .replace("\\", "") + .replaceAll("(.*gradle-)(\\d+\\.\\d+(?:\\.\\d+)?)(.*-(?:bin|all).zip)", + wrapperHost + gradleWrapper.getVersion() + "$3"); + gradleWrapper = new GradleWrapper(gradleWrpr.getVersion(), new DistributionInfos(newDownloadUrl, null, null)); + } + + if (!gradleWrapper.getPropertiesFormattedUrl().equals(currentDistributionUrl)) { + acc.needsWrapperUpdate = true; + } + return entry; + } + }, + new TreeVisitor() { + @Override + public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { + if (new FindGradleProject(FindGradleProject.SearchCriteria.Marker).getVisitor().visitNonNull(sourceFile, ctx) != sourceFile) { + acc.gradleProject = true; + } + + if ((sourceFile instanceof Quark || sourceFile instanceof Remote) && + equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_JAR_LOCATION)) { + acc.addGradleWrapperJar = false; + return true; + } + + if (sourceFile instanceof PlainText) { + if (equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_BATCH_LOCATION)) { + acc.addGradleBatchScript = false; + return true; + } else if (equalIgnoringSeparators(sourceFile.getSourcePath(), WRAPPER_SCRIPT_LOCATION)) { + acc.addGradleShellScript = false; + return true; + } + } + + return false; + } + + @Override + public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + // "work" already performed by `isAcceptable()`; no need to visit anymore + return tree; + } + } + ); + } + + @Override + public Collection generate(GradleWrapperState acc, ExecutionContext ctx) { + if (Boolean.FALSE.equals(addIfMissing)) { + return Collections.emptyList(); + } + + if (!acc.gradleProject) { + return Collections.emptyList(); + } + + if (!(acc.addGradleWrapperJar || acc.addGradleWrapperProperties || acc.addGradleBatchScript || acc.addGradleShellScript)) { + return Collections.emptyList(); + } + + List gradleWrapperFiles = new ArrayList<>(); + ZonedDateTime now = ZonedDateTime.now(); + + GradleWrapper gradleWrapper = getGradleWrapper(ctx); + + if (acc.addGradleWrapperProperties) { + String checksum = gradleWrapper.getDistributionChecksum() == null ? null : gradleWrapper.getDistributionChecksum().getHexValue(); + if (wrapperUri != null && distributionChecksum != null && checksum == null) { + checksum = distributionChecksum; + } + + //noinspection UnusedProperty + Properties.File gradleWrapperProperties = new PropertiesParser().parse( + "distributionBase=GRADLE_USER_HOME\n" + + "distributionPath=wrapper/dists\n" + + "distributionUrl=" + gradleWrapper.getPropertiesFormattedUrl() + "\n" + + (checksum == null ? "" : "distributionSha256Sum=" + checksum + "\n") + + "zipStoreBase=GRADLE_USER_HOME\n" + + "zipStorePath=wrapper/dists") + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Could not parse as properties")) + .withSourcePath(WRAPPER_PROPERTIES_LOCATION); + gradleWrapperFiles.add(gradleWrapperProperties); + } + + FileAttributes wrapperScriptAttributes = new FileAttributes(now, now, now, true, true, true, 1L); + if (acc.addGradleShellScript) { + String gradlewText = unixScript(gradleWrapper, ctx); + PlainText gradlew = PlainText.builder() + .text(gradlewText) + .sourcePath(WRAPPER_SCRIPT_LOCATION) + .fileAttributes(wrapperScriptAttributes) + .build(); + gradleWrapperFiles.add(gradlew); + } + + if (acc.addGradleBatchScript) { + String gradlewBatText = batchScript(gradleWrapper, ctx); + PlainText gradlewBat = PlainText.builder() + .text(gradlewBatText) + .sourcePath(WRAPPER_BATCH_LOCATION) + .fileAttributes(wrapperScriptAttributes) + .build(); + gradleWrapperFiles.add(gradlewBat); + } + + if (acc.addGradleWrapperJar) { + gradleWrapperFiles.add(gradleWrapper.wrapperJar()); + } + + return gradleWrapperFiles; + } + + @Override + public TreeVisitor getVisitor(GradleWrapperState acc) { + if (!acc.needsWrapperUpdate) { + return TreeVisitor.noop(); + } + + return new TreeVisitor() { + + @Override + public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + if (!(tree instanceof SourceFile)) { + return tree; + } + + SourceFile sourceFile = (SourceFile) tree; + GradleWrapper gradleWrapper = getGradleWrapper(ctx); + + Optional maybeCurrentMarker = tree.getMarkers().findFirst(BuildTool.class); + if (maybeCurrentMarker.isPresent()) { + BuildTool currentMarker = maybeCurrentMarker.get(); + if (currentMarker.getType() == BuildTool.Type.Gradle) { + String gradleWrapperVersion = getGradleWrapper(ctx).getVersion(); + VersionComparator versionComparator = requireNonNull(Semver.validate(isBlank(version) ? "latest.release" : version, null).getValue()); + int compare = versionComparator.compare(null, currentMarker.getVersion(), currentMarker.withVersion(gradleWrapperVersion).getVersion()); + if (compare > 0) { + return tree; + } + } + } + + if (sourceFile instanceof PlainText && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_SCRIPT_LOCATION_RELATIVE_PATH)) { + String gradlewText = unixScript(gradleWrapper, ctx); + PlainText gradlew = (PlainText) setExecutable(sourceFile); + if (!gradlewText.equals(gradlew.getText())) { + gradlew = gradlew.withText(gradlewText); + } + return gradlew; + } + + if (sourceFile instanceof PlainText && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_BATCH_LOCATION_RELATIVE_PATH)) { + String gradlewBatText = batchScript(gradleWrapper, ctx); + PlainText gradlewBat = (PlainText) setExecutable(sourceFile); + if (!gradlewBatText.equals(gradlewBat.getText())) { + gradlewBat = gradlewBat.withText(gradlewBatText); + } + return gradlewBat; + } + if (sourceFile instanceof Properties.File && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_PROPERTIES_LOCATION_RELATIVE_PATH)) { + return new WrapperPropertiesVisitor(gradleWrapper).visitNonNull(sourceFile, ctx); + } + if ((sourceFile instanceof Quark || sourceFile instanceof Remote) && PathUtils.matchesGlob(sourceFile.getSourcePath(), "**/" + WRAPPER_JAR_LOCATION_RELATIVE_PATH)) { + return gradleWrapper.wrapperJar(sourceFile); + } + return sourceFile; + } + }; + } + + private static T setExecutable(T sourceFile) { + FileAttributes attributes = sourceFile.getFileAttributes(); + if (attributes == null) { + ZonedDateTime now = ZonedDateTime.now(); + return sourceFile.withFileAttributes(new FileAttributes(now, now, now, true, true, true, 1)); + } else if (!attributes.isExecutable()) { + return sourceFile.withFileAttributes(attributes.withExecutable(true)); + } + return sourceFile; + } + + private String unixScript(GradleWrapper gradleWrapper, ExecutionContext ctx) { + Map binding = new HashMap<>(); + String defaultJvmOpts = defaultJvmOpts(gradleWrapper); + binding.put("defaultJvmOpts", StringUtils.isNotEmpty(defaultJvmOpts) ? "'" + defaultJvmOpts + "'" : ""); + binding.put("classpath", "$APP_HOME/gradle/wrapper/gradle-wrapper.jar"); + + String gradlewTemplate = StringUtils.readFully(gradleWrapper.gradlew().getInputStream(ctx)); + return renderTemplate(gradlewTemplate, binding, "\n"); + } + + private String batchScript(GradleWrapper gradleWrapper, ExecutionContext ctx) { + Map binding = new HashMap<>(); + binding.put("defaultJvmOpts", defaultJvmOpts(gradleWrapper)); + binding.put("classpath", "%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar"); + + String gradlewBatTemplate = StringUtils.readFully(gradleWrapper.gradlewBat().getInputStream(ctx)); + return renderTemplate(gradlewBatTemplate, binding, "\r\n"); + } + + private String defaultJvmOpts(GradleWrapper gradleWrapper) { + VersionComparator gradle53VersionComparator = requireNonNull(Semver.validate("[5.3,)", null).getValue()); + VersionComparator gradle50VersionComparator = requireNonNull(Semver.validate("[5.0,)", null).getValue()); + + if (gradle53VersionComparator.isValid(null, gradleWrapper.getVersion())) { + return "\"-Xmx64m\" \"-Xms64m\""; + } else if (gradle50VersionComparator.isValid(null, gradleWrapper.getVersion())) { + return "\"-Xmx64m\""; + } + return ""; + } + + private String renderTemplate(String source, Map parameters, String lineSeparator) { + Map binding = new HashMap<>(parameters); + binding.put("applicationName", "Gradle"); + binding.put("optsEnvironmentVar", "GRADLE_OPTS"); + binding.put("exitEnvironmentVar", "GRADLE_EXIT_CONSOLE"); + binding.put("mainClassName", "org.gradle.wrapper.GradleWrapperMain"); + binding.put("appNameSystemProperty", "org.gradle.appname"); + binding.put("appHomeRelativePath", ""); + binding.put("modulePath", ""); + + String script = source; + for (Map.Entry variable : binding.entrySet()) { + script = script.replace("${" + variable.getKey() + "}", variable.getValue()) + .replace("$" + variable.getKey(), variable.getValue()); + } + + script = script.replaceAll("(?sm)<% /\\*.*?\\*/ %>", ""); + script = script.replaceAll("(?sm)<% if \\( mainClassName\\.startsWith\\('--module '\\) \\) \\{.*?} %>", ""); + script = script.replaceAll("(?sm)<% if \\( appNameSystemProperty \\) \\{.*?%>(.*?)<% } %>", "$1"); + script = script.replace("\\$", "$"); + script = script.replaceAll("DIRNAME=\\.\\\\[\r\n]", "DIRNAME=."); + script = script.replace("\\\\", "\\"); + script = script.replaceAll("\r\n|\r|\n", lineSeparator); + + return script; + } + + private static class WrapperPropertiesVisitor extends PropertiesVisitor { + + private static final String DISTRIBUTION_SHA_256_SUM_KEY = "distributionSha256Sum"; + private final GradleWrapper gradleWrapper; + + public WrapperPropertiesVisitor(GradleWrapper gradleWrapper) { + this.gradleWrapper = gradleWrapper; + } + + @Override + public Properties visitFile(Properties.File file, ExecutionContext ctx) { + Properties p = super.visitFile(file, ctx); + Set checksumKey = FindProperties.find(p, DISTRIBUTION_SHA_256_SUM_KEY, false); + if (checksumKey.isEmpty() && gradleWrapper.getDistributionChecksum() != null) { + Properties.Value propertyValue = new Properties.Value(Tree.randomId(), "", Markers.EMPTY, gradleWrapper.getDistributionChecksum().getHexValue()); + Properties.Entry entry = new Properties.Entry(Tree.randomId(), "\n", Markers.EMPTY, DISTRIBUTION_SHA_256_SUM_KEY, "", Properties.Entry.Delimiter.EQUALS, propertyValue); + List contentList = ListUtils.concat(((Properties.File) p).getContent(), entry); + p = ((Properties.File) p).withContent(contentList); + } else if (!checksumKey.isEmpty() && gradleWrapper.getDistributionChecksum() == null) { + List contentList = ListUtils.map(((Properties.File) p).getContent(), c -> { + if (c instanceof Properties.Entry && DISTRIBUTION_SHA_256_SUM_KEY.equals(((Properties.Entry) c).getKey())) { + return null; + } + return c; + }); + p = ((Properties.File) p).withContent(contentList); + } + return p; + } + + @Override + public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) { + if ("distributionUrl".equals(entry.getKey())) { + Properties.Value value = entry.getValue(); + return entry.withValue(value.withText(gradleWrapper.getPropertiesFormattedUrl())); + } + if (DISTRIBUTION_SHA_256_SUM_KEY.equals(entry.getKey()) && gradleWrapper.getDistributionChecksum() != null) { + return entry.withValue(entry.getValue().withText(gradleWrapper.getDistributionChecksum().getHexValue())); + } + return entry; + } + } +} diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java new file mode 100755 index 00000000000..8e7d880d32e --- /dev/null +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java @@ -0,0 +1,149 @@ +/* + * Copyright 2022 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.gradle.util.GradleWrapper; +import org.openrewrite.marker.BuildTool; +import org.openrewrite.semver.Semver; +import org.openrewrite.semver.VersionComparator; + +import java.time.Duration; +import java.util.Optional; + +import static java.util.Objects.requireNonNull; +import static org.openrewrite.internal.StringUtils.isBlank; + +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +@EqualsAndHashCode(callSuper = false) +public class UpdateGradleWrapperMarkers extends Recipe { + + @Override + public String getDisplayName() { + return "Update Gradle wrapper marker versions"; + } + + @Override + public String getDescription() { + return "Update the version of Gradle used in an existing Gradle wrapper. " + + "Queries services.gradle.org to determine the available releases, but prefers the artifact repository URL " + + "which already exists within the wrapper properties file. " + + "If your artifact repository does not contain the same Gradle distributions as services.gradle.org, " + + "then the recipe may suggest a version which is not available in your artifact repository."; + } + + @Getter + @Option(displayName = "New version", + description = "An exact version number or node-style semver selector used to select the version number. " + + "Defaults to the latest release available from services.gradle.org if not specified.", + example = "7.x", + required = false) + @Nullable + final String version; + + @Getter + @Option(displayName = "Distribution type", + description = "The distribution of Gradle to use. \"bin\" includes Gradle binaries. " + + "\"all\" includes Gradle binaries, source code, and documentation. " + + "Defaults to \"bin\".", + valid = {"bin", "all"}, + required = false + ) + @Nullable + final String distribution; + + @Getter + @Option(displayName = "Add if missing", + description = "Add a Gradle wrapper, if it's missing. Defaults to `true`.", + required = false) + @Nullable + final Boolean addIfMissing; + + @Getter + @Option(example = "https://services.gradle.org/distributions/gradle-${version}-${distribution}.zip", + displayName = "Wrapper URI", + description = "The URI of the Gradle wrapper distribution. " + + "Lookup of available versions still requires access to https://services.gradle.org " + + "When this is specified the exact literal values supplied for `version` and `distribution` " + + "will be interpolated into this string wherever `${version}` and `${distribution}` appear respectively. " + + "Defaults to https://services.gradle.org/distributions/gradle-${version}-${distribution}.zip.", + required = false) + @Nullable + final String wrapperUri; + + @Getter + @Option(example = "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda", + displayName = "SHA-256 checksum", + description = "The SHA-256 checksum of the Gradle distribution. " + + "If specified, the recipe will add the checksum along with the custom distribution URL.", + required = false) + @Nullable + final String distributionChecksum; + + @NonFinal + @Nullable + transient GradleWrapper gradleWrapper; + + private GradleWrapper getGradleWrapper(ExecutionContext ctx) { + gradleWrapper = UpdateGradleWrapper.getGradleWrapper(ctx, wrapperUri, distribution, version, gradleWrapper); + return gradleWrapper; + } + + /** + * This recipe only updates markers, so it does not correspond to human manual effort. + * + * @return Zero estimated time. + */ + @Override + public Duration getEstimatedEffortPerOccurrence() { + return Duration.ofMinutes(0); + } + + @Override + public TreeVisitor getVisitor() { + return new TreeVisitor() { + @Override + public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + Optional maybeCurrentMarker = tree.getMarkers().findFirst(BuildTool.class); + if (maybeCurrentMarker.isPresent()) { + BuildTool currentMarker = maybeCurrentMarker.get(); + if (currentMarker.getType() != BuildTool.Type.Gradle) { + return tree; + } + String gradleWrapperVersion = getGradleWrapper(ctx).getVersion(); + BuildTool buildTool1 = currentMarker.withVersion(gradleWrapperVersion); + VersionComparator versionComparator = requireNonNull(Semver.validate(isBlank(version) ? "latest.release" : version, null).getValue()); + int compare = versionComparator.compare(null, currentMarker.getVersion(), buildTool1.getVersion()); + if (compare < 0) { + return tree.withMarkers(tree.getMarkers().setByType(buildTool1)); + } else { + return tree; + } + } + + return tree; + } + }; + } +} \ No newline at end of file From 37e61168614985b9c135c24f657d5e9b7931d465 Mon Sep 17 00:00:00 2001 From: leanne Date: Mon, 6 Jan 2025 14:15:30 -0800 Subject: [PATCH 2/3] adding a test --- .../gradle/UpdateGradleWrapperTest.java | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java index 003144c4709..35c52874a31 100755 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java @@ -36,6 +36,7 @@ import java.nio.file.*; import java.time.Duration; import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,14 +44,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.openrewrite.gradle.Assertions.buildGradle; import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi; -import static org.openrewrite.gradle.util.GradleWrapper.WRAPPER_BATCH_LOCATION; -import static org.openrewrite.gradle.util.GradleWrapper.WRAPPER_JAR_LOCATION; -import static org.openrewrite.gradle.util.GradleWrapper.WRAPPER_PROPERTIES_LOCATION; -import static org.openrewrite.gradle.util.GradleWrapper.WRAPPER_SCRIPT_LOCATION; +import static org.openrewrite.gradle.util.GradleWrapper.*; import static org.openrewrite.properties.Assertions.properties; -import static org.openrewrite.test.SourceSpecs.dir; -import static org.openrewrite.test.SourceSpecs.other; -import static org.openrewrite.test.SourceSpecs.text; +import static org.openrewrite.test.SourceSpecs.*; @SuppressWarnings("UnusedProperty") class UpdateGradleWrapperTest implements RewriteTest { @@ -163,6 +159,47 @@ void updateWrapper() { ); } + @Test + @DocumentExample("Update existing Gradle wrapper") + void timeSaved() { + rewriteRun( + spec -> spec.allSources(source -> source.markers(new BuildTool(Tree.randomId(), BuildTool.Type.Gradle, "7.4"))) + .afterRecipe(run -> { + AtomicReference timeSaved = new AtomicReference<>(Duration.ofMinutes(0)); + run.getChangeset().getAllResults().stream().forEach( + c -> timeSaved.set(timeSaved.get().plus(c.getTimeSavings()))); + + assertThat(timeSaved.get()).isEqualTo(Duration.ofMinutes(20)); + }), + properties( + """ + distributionBase=GRADLE_USER_HOME + distributionPath=wrapper/dists + distributionUrl=https\\://services.gradle.org/distributions/gradle-7.4-bin.zip + zipStoreBase=GRADLE_USER_HOME + zipStorePath=wrapper/dists + """, + """ + distributionBase=GRADLE_USER_HOME + distributionPath=wrapper/dists + distributionUrl=https\\://services.gradle.org/distributions/gradle-7.4.2-bin.zip + zipStoreBase=GRADLE_USER_HOME + zipStorePath=wrapper/dists + distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda + """, + spec -> spec.path("gradle/wrapper/gradle-wrapper.properties") + .afterRecipe(gradleWrapperProperties -> + assertThat(gradleWrapperProperties.getMarkers().findFirst(BuildTool.class)).hasValueSatisfying(buildTool -> { + assertThat(buildTool.getType()).isEqualTo(BuildTool.Type.Gradle); + assertThat(buildTool.getVersion()).isEqualTo("7.4.2"); + })) + ), + gradlew, + gradlewBat, + gradleWrapperJarQuark + ); + } + @Test void updateVersionAndDistribution() { rewriteRun( From 6274b5478da2891b0c586ece5a50f632d8407a4f Mon Sep 17 00:00:00 2001 From: leanne Date: Mon, 6 Jan 2025 14:24:29 -0800 Subject: [PATCH 3/3] removing test because it doesn't make a lot of sense --- .../gradle/UpdateGradleWrapperMarkers.java | 8 ++-- .../gradle/UpdateGradleWrapperTest.java | 41 ------------------- 2 files changed, 4 insertions(+), 45 deletions(-) diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java index 8e7d880d32e..1690e05b120 100755 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapperMarkers.java @@ -117,7 +117,7 @@ private GradleWrapper getGradleWrapper(ExecutionContext ctx) { */ @Override public Duration getEstimatedEffortPerOccurrence() { - return Duration.ofMinutes(0); + return Duration.ofMinutes(10); } @Override @@ -132,11 +132,11 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { return tree; } String gradleWrapperVersion = getGradleWrapper(ctx).getVersion(); - BuildTool buildTool1 = currentMarker.withVersion(gradleWrapperVersion); + BuildTool currentBuildTool = currentMarker.withVersion(gradleWrapperVersion); VersionComparator versionComparator = requireNonNull(Semver.validate(isBlank(version) ? "latest.release" : version, null).getValue()); - int compare = versionComparator.compare(null, currentMarker.getVersion(), buildTool1.getVersion()); + int compare = versionComparator.compare(null, currentMarker.getVersion(), currentBuildTool.getVersion()); if (compare < 0) { - return tree.withMarkers(tree.getMarkers().setByType(buildTool1)); + return tree.withMarkers(tree.getMarkers().setByType(currentBuildTool)); } else { return tree; } diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java index 35c52874a31..7b9cfae0dbe 100755 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpdateGradleWrapperTest.java @@ -159,47 +159,6 @@ void updateWrapper() { ); } - @Test - @DocumentExample("Update existing Gradle wrapper") - void timeSaved() { - rewriteRun( - spec -> spec.allSources(source -> source.markers(new BuildTool(Tree.randomId(), BuildTool.Type.Gradle, "7.4"))) - .afterRecipe(run -> { - AtomicReference timeSaved = new AtomicReference<>(Duration.ofMinutes(0)); - run.getChangeset().getAllResults().stream().forEach( - c -> timeSaved.set(timeSaved.get().plus(c.getTimeSavings()))); - - assertThat(timeSaved.get()).isEqualTo(Duration.ofMinutes(20)); - }), - properties( - """ - distributionBase=GRADLE_USER_HOME - distributionPath=wrapper/dists - distributionUrl=https\\://services.gradle.org/distributions/gradle-7.4-bin.zip - zipStoreBase=GRADLE_USER_HOME - zipStorePath=wrapper/dists - """, - """ - distributionBase=GRADLE_USER_HOME - distributionPath=wrapper/dists - distributionUrl=https\\://services.gradle.org/distributions/gradle-7.4.2-bin.zip - zipStoreBase=GRADLE_USER_HOME - zipStorePath=wrapper/dists - distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda - """, - spec -> spec.path("gradle/wrapper/gradle-wrapper.properties") - .afterRecipe(gradleWrapperProperties -> - assertThat(gradleWrapperProperties.getMarkers().findFirst(BuildTool.class)).hasValueSatisfying(buildTool -> { - assertThat(buildTool.getType()).isEqualTo(BuildTool.Type.Gradle); - assertThat(buildTool.getVersion()).isEqualTo("7.4.2"); - })) - ), - gradlew, - gradlewBat, - gradleWrapperJarQuark - ); - } - @Test void updateVersionAndDistribution() { rewriteRun(