diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/InMemoryLargeSourceSet.java b/rewrite-core/src/main/java/org/openrewrite/internal/InMemoryLargeSourceSet.java index 07dea5eee39..1e3d53db3a9 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/InMemoryLargeSourceSet.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/InMemoryLargeSourceSet.java @@ -44,8 +44,8 @@ public InMemoryLargeSourceSet(List ls) { } protected InMemoryLargeSourceSet(@Nullable InMemoryLargeSourceSet initialState, - @Nullable Map> deletions, - List ls) { + @Nullable Map> deletions, + List ls) { this.initialState = initialState; this.ls = ls; this.deletions = deletions; diff --git a/rewrite-core/src/main/java/org/openrewrite/scheduling/RecipeRunCycle.java b/rewrite-core/src/main/java/org/openrewrite/scheduling/RecipeRunCycle.java index d08b85bb17d..6160d74344c 100644 --- a/rewrite-core/src/main/java/org/openrewrite/scheduling/RecipeRunCycle.java +++ b/rewrite-core/src/main/java/org/openrewrite/scheduling/RecipeRunCycle.java @@ -36,7 +36,7 @@ import java.util.function.BiFunction; import java.util.function.UnaryOperator; -import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableSet; import static java.util.Objects.requireNonNull; import static org.openrewrite.Recipe.PANIC; @@ -105,12 +105,12 @@ public LSS scanSources(LSS sourceSet) { } public LSS generateSources(LSS sourceSet) { - List generatedInThisCycle = allRecipeStack.reduce(sourceSet, recipe, ctx, (acc, recipeStack) -> { + Set generatedInThisCycle = allRecipeStack.reduce(sourceSet, recipe, ctx, (acc, recipeStack) -> { Recipe recipe = recipeStack.peek(); if (recipe instanceof ScanningRecipe) { //noinspection unchecked ScanningRecipe scanningRecipe = (ScanningRecipe) recipe; - List generated = new ArrayList<>(scanningRecipe.generate(scanningRecipe.getAccumulator(rootCursor, ctx), unmodifiableList(acc), ctx)); + List generated = new ArrayList<>(scanningRecipe.generate(scanningRecipe.getAccumulator(rootCursor, ctx), unmodifiableSet(acc), ctx)); generated.replaceAll(source -> addRecipesThatMadeChanges(recipeStack, source)); acc.addAll(generated); if (!generated.isEmpty()) { @@ -118,10 +118,10 @@ public LSS generateSources(LSS sourceSet) { } } return acc; - }, new ArrayList<>()); + }, new TreeSet<>(Comparator.comparing(SourceFile::getSourcePath))); // noinspection unchecked - return (LSS) sourceSet.generate(generatedInThisCycle); + return (LSS) sourceSet.generate(new ArrayList<>(generatedInThisCycle)); } public LSS editSources(LSS sourceSet) { @@ -238,7 +238,7 @@ private void recordSourceFileResult(@Nullable String beforePath, @Nullable Strin } private @Nullable SourceFile handleError(Recipe recipe, SourceFile sourceFile, @Nullable SourceFile after, - Throwable t) { + Throwable t) { ctx.getOnError().accept(t); if (t instanceof RecipeRunException) { diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java b/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java index 8995bab9a14..804a77fae79 100755 --- a/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java @@ -45,16 +45,16 @@ public static Validated build(String pattern) { } String versionOnly; int hyphenIndex = pattern.indexOf('-'); - if(hyphenIndex == -1) { + if (hyphenIndex == -1) { versionOnly = pattern; } else { versionOnly = pattern.substring(0, hyphenIndex); } - if(versionOnly.startsWith("latest") || - versionOnly.contains("x") || - versionOnly.contains("^") || - versionOnly.contains("~") || - versionOnly.contains(" ")) { + if (versionOnly.startsWith("latest") || + versionOnly.contains("x") || + versionOnly.contains("^") || + versionOnly.contains("~") || + versionOnly.contains(" ")) { return Validated.invalid("exactVersion", pattern, "not an exact version number"); } return Validated.valid("exactVersion", new ExactVersion(pattern)); diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersionWithPattern.java b/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersionWithPattern.java new file mode 100644 index 00000000000..0b4bcae3235 --- /dev/null +++ b/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersionWithPattern.java @@ -0,0 +1,45 @@ +/* + * Copyright 2024 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.semver; + +import org.openrewrite.Validated; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.internal.lang.Nullable; + +public class ExactVersionWithPattern extends LatestRelease { + private final String version; + + public ExactVersionWithPattern(String version, String metadataPattern) { + super(metadataPattern); + this.version = version; + } + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + return super.isValid(currentVersion, version) && + super.compare(currentVersion, version, this.version) == 0; + } + + public static Validated build(String toVersion, @Nullable String metadataPattern) { + if (StringUtils.isBlank(metadataPattern)) { + return Validated.invalid("exactVersionWithPattern", metadataPattern, "metadataPattern is null or empty"); + } + if (ExactVersion.build(toVersion).isInvalid()) { + return Validated.invalid("exactVersionWithPattern", toVersion, "not an exact version number"); + } + return Validated.valid("exactVersionWithPattern", new ExactVersionWithPattern(toVersion, metadataPattern)); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java b/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java index 09a63a0de0d..619c82d2b88 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java @@ -53,6 +53,7 @@ public static Validated validate(String toVersion, @Nullable .or(TildeRange.build(toVersion, metadataPattern)) .or(CaretRange.build(toVersion, metadataPattern)) .or(SetRange.build(toVersion, metadataPattern)) + .or(ExactVersionWithPattern.build(toVersion, metadataPattern)) .or(ExactVersion.build(toVersion)) ); } diff --git a/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java b/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java index 46a675afecf..9718096f17c 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java @@ -86,7 +86,7 @@ public TreeVisitor getVisitor(AtomicBoolean created) { @Override public SourceFile visit(@Nullable Tree tree, ExecutionContext ctx) { SourceFile sourceFile = (SourceFile) requireNonNull(tree); - if ((created.get() || Boolean.TRUE.equals(overwriteExisting)) && path.equals(sourceFile.getSourcePath())) { + if (Boolean.TRUE.equals(overwriteExisting) && path.equals(sourceFile.getSourcePath())) { if (sourceFile instanceof PlainText) { return ((PlainText) sourceFile).withText(fileContents); } diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java index c204d609383..c7aaf02f417 100644 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java @@ -922,4 +922,76 @@ void isAcceptable(){ sourceFile = PropertiesParser.builder().build().parse("guavaVersion=29.0-jre").findFirst().orElseThrow(); assertThat(visitor.isAcceptable(sourceFile, new InMemoryExecutionContext())).isTrue(); } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4333") + void exactVersionWithExactPattern() { + rewriteRun( + spec -> spec.recipe(new UpgradeDependencyVersion("com.google.guava", "guava", "32.1.1", "-jre")), + buildGradle( + """ + plugins { + id 'java-library' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation('com.google.guava:guava:29.0-jre') + } + """, + """ + plugins { + id 'java-library' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation('com.google.guava:guava:32.1.1-jre') + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4333") + void exactVersionWithRegexPattern() { + rewriteRun( + spec -> spec.recipe(new UpgradeDependencyVersion("com.google.guava", "guava", "32.1.1", ".*droid")), + buildGradle( + """ + plugins { + id 'java-library' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation('com.google.guava:guava:29.0-android') + } + """, + """ + plugins { + id 'java-library' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation('com.google.guava:guava:32.1.1-android') + } + """ + ) + ); + } } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeDependencyVersionTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeDependencyVersionTest.java index e01b34844f4..fdb24cd8ccd 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeDependencyVersionTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/UpgradeDependencyVersionTest.java @@ -1833,4 +1833,42 @@ void multipleRetainVersions() { ); } } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4333") + void exactVersionWithPattern() { + rewriteRun( + spec -> spec.recipe(new UpgradeDependencyVersion("com.google.guava", "guava", "29.0", "-jre", null, null)), + pomXml( + """ + + com.mycompany.app + my-app + 1 + + + com.google.guava + guava + 25.0-jre + + + + """, + """ + + com.mycompany.app + my-app + 1 + + + com.google.guava + guava + 29.0-jre + + + + """ + ) + ); + } } diff --git a/rewrite-test/src/test/java/org/openrewrite/text/CreateTextFileTest.java b/rewrite-test/src/test/java/org/openrewrite/text/CreateTextFileTest.java index fc1c8fac98b..d707cbb95d2 100644 --- a/rewrite-test/src/test/java/org/openrewrite/text/CreateTextFileTest.java +++ b/rewrite-test/src/test/java/org/openrewrite/text/CreateTextFileTest.java @@ -21,6 +21,8 @@ import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; +import java.nio.file.Path; + import static org.openrewrite.groovy.Assertions.groovy; import static org.openrewrite.test.SourceSpecs.text; @@ -128,4 +130,29 @@ void shouldOverrideDifferentSourceFileType() { ) ); } + + @Test + void shouldNotOverrideIfCreatedInSameRun() { + rewriteRun( + spec -> spec.recipeFromYaml(""" + --- + type: specs.openrewrite.org/v1beta/recipe + name: org.openrewrite.test.CreateTextFileDuplication + displayName: Create Text File test recipe + description: Create Text File test recipe. + recipeList: + - org.openrewrite.text.CreateTextFile: + relativeFileName: duplicate.txt + overwriteExisting: false + fileContents: | + hi + - org.openrewrite.text.CreateTextFile: + relativeFileName: duplicate.txt + overwriteExisting: false + fileContents: | + hello + """, "org.openrewrite.test.CreateTextFileDuplication"), + text(null, "hi", spec -> spec.path(Path.of("duplicate.txt"))) + ); + } }