Skip to content

Commit eb27313

Browse files
authored
Merge branch 'main' into timtebeek/fix-issue-6833
2 parents 53d4aa2 + 998e8c3 commit eb27313

13 files changed

Lines changed: 134 additions & 94 deletions

File tree

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
3+
distributionUrl=https\://downloads.gradle.org/distributions/gradle-9.3.1-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

rewrite-core/src/main/java/org/openrewrite/marketplace/RecipeMarketplaceReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private void readRecipe(@Nullable String[] row, RecipeMarketplace marketplace, L
159159
String value = row[i];
160160
if (value != null) {
161161
value = value.trim();
162-
if (StringUtils.isBlank(value)) {
162+
if (StringUtils.isBlank(value) || "null".equals(value)) {
163163
value = null;
164164
}
165165
}

rewrite-core/src/test/java/org/openrewrite/marketplace/RecipeMarketplaceReaderTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,44 @@ void recipeInMultipleCategoriesHasSeparateBundleInstances() {
350350
assertThat(rtJsListing.getBundle().getRequestedVersion()).isEqualTo(requestedVersion);
351351
}
352352

353+
@Test
354+
void nullLiteralVersionIsTreatedAsNull() {
355+
// When a CSV contains the literal string "null" for version/requestedVersion,
356+
// the reader should treat it as null (not the string "null")
357+
RecipeMarketplace marketplace = new RecipeMarketplaceReader().fromCsv("""
358+
name,displayName,description,category,ecosystem,packageName,requestedVersion,version
359+
org.openrewrite.java.cleanup.UnnecessaryParentheses,Remove Unnecessary Parentheses,Removes unnecessary parentheses,Java Cleanup,maven,org.openrewrite:rewrite-java,null,null
360+
""");
361+
362+
RecipeListing listing = marketplace.getAllRecipes().iterator().next();
363+
RecipeBundle bundle = listing.getBundle();
364+
assertThat(bundle.getRequestedVersion()).isNull();
365+
assertThat(bundle.getVersion()).isNull();
366+
}
367+
368+
@Test
369+
void roundTripPreservesNullVersions() {
370+
// Create a marketplace with null versions, write to CSV, read back,
371+
// and verify versions remain null (not the string "null")
372+
RecipeMarketplace marketplace = new RecipeMarketplaceReader().fromCsv("""
373+
name,displayName,description,category,ecosystem,packageName
374+
org.openrewrite.java.cleanup.UnnecessaryParentheses,Remove Unnecessary Parentheses,Removes unnecessary parentheses,Java Cleanup,maven,org.openrewrite:rewrite-java
375+
""");
376+
377+
// Verify initial state has null versions
378+
RecipeListing listing = marketplace.getAllRecipes().iterator().next();
379+
assertThat(listing.getBundle().getVersion()).isNull();
380+
assertThat(listing.getBundle().getRequestedVersion()).isNull();
381+
382+
// Round-trip through CSV
383+
@Language("csv") String csv = new RecipeMarketplaceWriter().toCsv(marketplace);
384+
RecipeMarketplace roundTripped = new RecipeMarketplaceReader().fromCsv(csv);
385+
386+
RecipeListing rtListing = roundTripped.getAllRecipes().iterator().next();
387+
assertThat(rtListing.getBundle().getVersion()).isNull();
388+
assertThat(rtListing.getBundle().getRequestedVersion()).isNull();
389+
}
390+
353391
private void setVersionRecursive(RecipeMarketplace.Category category, String packageName,
354392
String requestedVersion, String version) {
355393
for (RecipeListing recipe : category.getRecipes()) {

rewrite-core/src/test/resources/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
distributionBase=GRADLE_USER_HOME
1818
distributionPath=wrapper/dists
19-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
19+
distributionUrl=https\://downloads.gradle.org/distributions/gradle-7.6.1-bin.zip
2020
networkTimeout=10000
2121
zipStoreBase=GRADLE_USER_HOME
2222
zipStorePath=wrapper/dists

rewrite-gradle-tooling-model/model/src/test/java/org/openrewrite/gradle/toolingapi/AssertionsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ void customInitScript() {
9393
}
9494
9595
""";
96-
GradleWrapper gradleWrapper = GradleWrapper.create(URI.create("https://services.gradle.org/distributions/gradle-8.6-bin.zip"), null);
96+
GradleWrapper gradleWrapper = GradleWrapper.create(URI.create("https://downloads.gradle.org/distributions/gradle-8.6-bin.zip"), null);
9797
rewriteRun(
9898
spec -> spec.beforeRecipe(Assertions.withToolingApi(gradleWrapper, alternateInit)),
9999
//language=groovy

rewrite-gradle/src/main/java/org/openrewrite/gradle/UpdateGradleWrapper.java

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,28 @@
4646
import static org.openrewrite.gradle.util.GradleWrapper.*;
4747
import static org.openrewrite.internal.StringUtils.isBlank;
4848

49+
@Getter
4950
@RequiredArgsConstructor
50-
@FieldDefaults(level = AccessLevel.PRIVATE)
51+
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
5152
@EqualsAndHashCode(callSuper = false)
5253
public class UpdateGradleWrapper extends ScanningRecipe<UpdateGradleWrapper.GradleWrapperState> {
5354

54-
@Getter
55-
final String displayName = "Update Gradle wrapper";
55+
String displayName = "Update Gradle wrapper";
5656

57-
@Getter
58-
final String description = "Update the version of Gradle used in an existing Gradle wrapper. " +
59-
"Queries services.gradle.org to determine the available releases, but prefers the artifact repository URL " +
57+
String description = "Update the version of Gradle used in an existing Gradle wrapper. " +
58+
"Queries `downloads.gradle.org` to determine the available releases, but prefers the artifact repository URL " +
6059
"which already exists within the wrapper properties file. " +
61-
"If your artifact repository does not contain the same Gradle distributions as services.gradle.org, " +
60+
"If your artifact repository does not contain the same Gradle distributions as `downloads.gradle.org`, " +
6261
"then the recipe may suggest a version which is not available in your artifact repository.";
6362

64-
@Getter
6563
@Option(displayName = "New version",
6664
description = "An exact version number or node-style semver selector used to select the version number. " +
67-
"Defaults to the latest release available from services.gradle.org if not specified.",
65+
"Defaults to the latest release available from `downloads.gradle.org` if not specified.",
6866
example = "7.x",
6967
required = false)
7068
@Nullable
71-
final String version;
69+
String version;
7270

73-
@Getter
7471
@Option(displayName = "Distribution type",
7572
description = "The distribution of Gradle to use. \"bin\" includes Gradle binaries. " +
7673
"\"all\" includes Gradle binaries, source code, and documentation. " +
@@ -79,17 +76,15 @@ public class UpdateGradleWrapper extends ScanningRecipe<UpdateGradleWrapper.Grad
7976
required = false
8077
)
8178
@Nullable
82-
final String distribution;
79+
String distribution;
8380

84-
@Getter
8581
@Option(displayName = "Add if missing",
8682
description = "Add a Gradle wrapper, if it's missing. Defaults to `true`.",
8783
required = false)
8884
@Nullable
89-
final Boolean addIfMissing;
85+
Boolean addIfMissing;
9086

91-
@Getter
92-
@Option(example = "https://services.gradle.org/distributions/gradle-8.5-bin.zip",
87+
@Option(example = "https://downloads.gradle.org/distributions/gradle-8.5-bin.zip",
9388
displayName = "Wrapper URI",
9489
description = "The URI of the Gradle wrapper distribution.\n" +
9590
"Specifies a custom location from which to download the Gradle wrapper scripts (gradlew, gradlew.bat, etc.). This is useful for setting up the Gradle wrapper without relying on Gradle's official distribution services.\n\n" +
@@ -98,16 +93,15 @@ public class UpdateGradleWrapper extends ScanningRecipe<UpdateGradleWrapper.Grad
9893
"If the URI is inaccessible, the recipe will leave the existing wrapper files in the repository unchanged, as they are generally compatible with various Gradle versions.",
9994
required = false)
10095
@Nullable
101-
final String wrapperUri;
96+
String wrapperUri;
10297

103-
@Getter
10498
@Option(example = "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda",
10599
displayName = "SHA-256 checksum",
106100
description = "The SHA-256 checksum of the Gradle distribution. " +
107101
"If specified, the recipe will add the checksum along with the custom distribution URL.",
108102
required = false)
109103
@Nullable
110-
final String distributionChecksum;
104+
String distributionChecksum;
111105

112106
@Override
113107
public String getInstanceNameSuffix() {
@@ -202,7 +196,7 @@ public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) {
202196
return entry;
203197
}
204198

205-
// Typical example: https://services.gradle.org/distributions/gradle-7.4-all.zip or https://company.com/repo/gradle-8.2-bin.zip
199+
// Typical example: https://downloads.gradle.org/distributions/gradle-7.4-all.zip or https://company.com/repo/gradle-8.2-bin.zip
206200
String currentDistributionUrl = entry.getValue().getText();
207201
acc.currentDistributionUrl = currentDistributionUrl;
208202

rewrite-gradle/src/main/java/org/openrewrite/gradle/util/GradleWrapper.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@
5151

5252
@Value
5353
public class GradleWrapper {
54+
private static final String GRADLE_DOWNLOADS_URL = "https://downloads.gradle.org";
55+
private static final String GRADLE_DISTRIBUTIONS_URL = GRADLE_DOWNLOADS_URL + "/distributions";
5456
private static final String GRADLE_SERVICES_URL = "https://services.gradle.org";
55-
private static final String GRADLE_DISTRIBUTIONS_URL = GRADLE_SERVICES_URL + "/distributions";
5657
private static final String GRADLE_VERSIONS_ALL_URL = GRADLE_SERVICES_URL + "/versions/all";
5758
public static final String WRAPPER_JAR_LOCATION_RELATIVE_PATH = "gradle/wrapper/gradle-wrapper.jar";
5859
public static final String WRAPPER_PROPERTIES_LOCATION_RELATIVE_PATH = "gradle/wrapper/gradle-wrapper.properties";
@@ -69,7 +70,7 @@ public class GradleWrapper {
6970

7071
/**
7172
* Construct a Gradle wrapper from a distribution type and version.
72-
* Used in contexts where services.gradle.org is available.
73+
* Used in contexts where downloads.gradle.org is available.
7374
*/
7475
public static GradleWrapper create(@Nullable String distributionTypeName, @Nullable String version, ExecutionContext ctx) {
7576
return create(null, distributionTypeName, version, ctx);
@@ -96,15 +97,15 @@ public static GradleWrapper create(@Nullable String currentDistributionUrl, @Nul
9697

9798
private static GradleVersion determineGradleVersion(@Nullable String currentDistributionUrl, @Nullable String version, VersionComparator versionComparator,
9899
DistributionType distributionType, ExecutionContext ctx) {
99-
if (currentDistributionUrl == null || currentDistributionUrl.startsWith(GRADLE_SERVICES_URL)) {
100+
if (currentDistributionUrl == null || currentDistributionUrl.startsWith(GRADLE_DOWNLOADS_URL) || currentDistributionUrl.startsWith(GRADLE_SERVICES_URL)) {
100101
// Only list all versions via services endpoint if a wildcard notation was requested or null, e.g. 8.x
101102
if (!(versionComparator instanceof ExactVersion)) {
102103
List<GradleVersion> allVersions = listAllPublicVersions(ctx);
103104
return allVersions.stream()
104105
.filter(v -> versionComparator.isValid(null, v.version))
105106
.filter(v -> v.distributionType == distributionType)
106107
.max((v1, v2) -> versionComparator.compare(null, v1.version, v2.version))
107-
.orElseThrow(() -> new IllegalStateException(String.format("Expected to find at least one Gradle wrapper version to select from %s.", GRADLE_SERVICES_URL)));
108+
.orElseThrow(() -> new IllegalStateException(String.format("Expected to find at least one Gradle wrapper version to select from %s.", GRADLE_DOWNLOADS_URL)));
108109
}
109110

110111
return new GradleVersion(version,
@@ -150,19 +151,22 @@ public static List<GradleVersion> listAllPublicVersions(ExecutionContext ctx) {
150151
});
151152
List<GradleVersion> allGradleVersions = new ArrayList<>(gradleVersions.size() * 2);
152153
for (GradleVersion gradleVersion : gradleVersions) {
154+
String downloadUrl = migrateToDownloadsUrl(gradleVersion.downloadUrl);
155+
String checksumUrl = migrateToDownloadsUrl(gradleVersion.checksumUrl);
156+
String wrapperChecksumUrl = migrateToDownloadsUrl(gradleVersion.wrapperChecksumUrl);
153157
allGradleVersions.add(new GradleVersion(
154158
gradleVersion.version,
155-
gradleVersion.downloadUrl,
159+
downloadUrl,
156160
DistributionType.Bin,
157-
gradleVersion.checksumUrl,
158-
gradleVersion.wrapperChecksumUrl
161+
checksumUrl,
162+
wrapperChecksumUrl
159163
));
160164
allGradleVersions.add(new GradleVersion(
161165
gradleVersion.version,
162-
gradleVersion.downloadUrl.replace("-bin.zip", "-all.zip"),
166+
downloadUrl.replace("-bin.zip", "-all.zip"),
163167
DistributionType.All,
164-
gradleVersion.checksumUrl == null ? null : gradleVersion.checksumUrl.replace("-bin.zip", "-all.zip"),
165-
gradleVersion.wrapperChecksumUrl
168+
checksumUrl == null ? null : checksumUrl.replace("-bin.zip", "-all.zip"),
169+
wrapperChecksumUrl
166170
));
167171
}
168172
return allGradleVersions;
@@ -200,11 +204,15 @@ private static List<GradleVersion> listAllPrivateArtifactoryVersions(String arti
200204
}
201205
}
202206

207+
private static @Nullable String migrateToDownloadsUrl(@Nullable String url) {
208+
return url == null ? null : url.replace(GRADLE_SERVICES_URL, GRADLE_DOWNLOADS_URL);
209+
}
210+
203211
private static final Pattern GRADLE_VERSION_PATTERN = Pattern.compile("gradle-([0-9.]+)");
204212

205213
/**
206214
* Construct a Gradle wrapper from a URI.
207-
* Can be used in contexts where services.gradle.org, normally used for version lookups, is unavailable.
215+
* Can be used in contexts where downloads.gradle.org, normally used for version lookups, is unavailable.
208216
*/
209217
public static GradleWrapper create(URI fullDistributionUri, @SuppressWarnings("unused") ExecutionContext ctx) {
210218
String version = "";

rewrite-gradle/src/main/resources/META-INF/rewrite/examples.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -715,13 +715,13 @@ examples:
715715
- before: |
716716
distributionBase=GRADLE_USER_HOME
717717
distributionPath=wrapper/dists
718-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
718+
distributionUrl=https\://downloads.gradle.org/distributions/gradle-7.4-bin.zip
719719
zipStoreBase=GRADLE_USER_HOME
720720
zipStorePath=wrapper/dists
721721
after: |
722722
distributionBase=GRADLE_USER_HOME
723723
distributionPath=wrapper/dists
724-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
724+
distributionUrl=https\://downloads.gradle.org/distributions/gradle-7.4.2-bin.zip
725725
zipStoreBase=GRADLE_USER_HOME
726726
zipStorePath=wrapper/dists
727727
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
@@ -1281,13 +1281,13 @@ examples:
12811281
- before: |
12821282
distributionBase=GRADLE_USER_HOME
12831283
distributionPath=wrapper/dists
1284-
distributionUrl=https\\://services.gradle.org/distributions/gradle-7.4-all.zip
1284+
distributionUrl=https\\://downloads.gradle.org/distributions/gradle-7.4-all.zip
12851285
zipStoreBase=GRADLE_USER_HOME
12861286
zipStorePath=wrapper/dists
12871287
after: |
12881288
distributionBase=GRADLE_USER_HOME
12891289
distributionPath=wrapper/dists
1290-
~~>distributionUrl=https\\://services.gradle.org/distributions/gradle-7.4-all.zip
1290+
~~>distributionUrl=https\\://downloads.gradle.org/distributions/gradle-7.4-all.zip
12911291
zipStoreBase=GRADLE_USER_HOME
12921292
zipStorePath=wrapper/dists
12931293
path: gradle/wrapper/gradle-wrapper.properties

0 commit comments

Comments
 (0)