Skip to content

Commit

Permalink
Merge pull request #68 from gradle/atual/allow-prerelease
Browse files Browse the repository at this point in the history
Add allowPreRelease option to control latest Maven/Gradle version
  • Loading branch information
clayburn authored Oct 27, 2022
2 parents ca6458a + f7e975d commit 9db5424
Show file tree
Hide file tree
Showing 20 changed files with 5,006 additions and 42 deletions.
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Running `/gradlew upgradeGradleWrapperXXX` will:
- clone the project XXX in `build/git-clones`
- run in the cloned project `./gradlew wrapper --gradle-version=<latest_gradle_version>`
- run a second time `./gradlew wrapper --gradle-version=<latest_gradle_version>`
- If changes occured
- If changes occurred
- create a specific branch
- commit and push the branch
- create a pull request on Github, it requires a Github access token, passed with `WRAPPER_UPGRADE_GIT_TOKEN` environment variable.
Expand All @@ -83,13 +83,14 @@ wrapperUpgrade {
}
```

| Field | description |
| :------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | A name identifying the upgrade, it can be different from the project name, for example when you need to upgrade multiple gradle projects in the same git project |
| `repo` | The Github repository to clone, format 'organization/project` |
| `dir` | The directory inside the project base directory to run the gradle or maven upgrade in |
| `baseBranch` | The git branch to checkout and that the pull request will target |
| `options.gitCommitExtraArgs` | List of additional git commit arguments
| Field | description |
|:-----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | A name identifying the upgrade, it can be different from the project name, for example when you need to upgrade multiple gradle projects in the same git project |
| `repo` | The Github repository to clone, format 'organization/project` |
| `dir` | The directory inside the project base directory to run the gradle or maven upgrade in |
| `baseBranch` | The git branch to checkout and that the pull request will target |
| `options.gitCommitExtraArgs` | List of additional git commit arguments |
| `options.allowPreRelease` | Boolean: true will get the latest Maven/Gradle version even if it's a pre-release. Default is false. |

## License

Expand Down
1 change: 1 addition & 0 deletions release/changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- [NEW] - Add `options.allowPreRelease` to control whether to upgrade to pre-release versions
2 changes: 1 addition & 1 deletion release/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.10.3
0.11
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public interface BuildToolStrategy {

String buildToolName();

VersionInfo lookupLatestVersion() throws IOException;
VersionInfo lookupLatestVersion(boolean allowPreRelease) throws IOException;

VersionInfo extractCurrentVersion(Path rootProjectDir) throws IOException;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,39 @@
package org.gradle.wrapperupgrade;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.gradle.process.ExecOperations;

import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;

import static org.gradle.wrapperupgrade.BuildToolStrategy.extractBuildToolVersion;

public final class GradleBuildToolStrategy implements BuildToolStrategy {

private final GradleMetadataFetcher gradleMetadataFetcher = new GradleMetadataFetcher();

@Override
public String buildToolName() {
return "Gradle";
}

@Override
public VersionInfo lookupLatestVersion() throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode gradleMetadata = mapper.readTree(new URL("https://services.gradle.org/versions/current"));
JsonNode version = gradleMetadata.get("version");
if (version != null) {
JsonNode checksumUrl = gradleMetadata.get("checksumUrl");
if (checksumUrl != null) {
URL url = new URL(checksumUrl.asText());
String checksum = new Scanner(url.openStream()).useDelimiter("\\A").next();
return new VersionInfo(version.asText(), checksum);
} else {
return new VersionInfo(version.asText(), null);
}
public VersionInfo lookupLatestVersion(boolean allowPreRelease) throws IOException {
JsonNode latestVersion = gradleMetadataFetcher.fetchLatestVersion(allowPreRelease)
.orElseThrow(() -> new IllegalStateException("Could not determine latest Gradle version"));

JsonNode checksumUrl = latestVersion.get("checksumUrl");
if (checksumUrl != null) {
URL url = new URL(checksumUrl.asText());
String checksum = new Scanner(url.openStream()).useDelimiter("\\A").next(); //unhandled stream
return new VersionInfo(latestVersion.get("version").asText(), checksum);
} else {
throw new IllegalStateException("Could not determine latest Gradle version");
return new VersionInfo(latestVersion.get("version").asText(), null);
}
}

Expand Down
43 changes: 43 additions & 0 deletions src/main/java/org/gradle/wrapperupgrade/GradleMetadataFetcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.gradle.wrapperupgrade;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.gradle.util.internal.VersionNumber;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Comparator;
import java.util.Optional;
import java.util.stream.StreamSupport;

public class GradleMetadataFetcher {
private final URL gradleAllVersionsMetadata;
private final URL gradleCurrentVersionMetadata;

GradleMetadataFetcher(URL gradleAllVersionsMetadata, URL gradleCurrentVersionMetadata) {
this.gradleAllVersionsMetadata = gradleAllVersionsMetadata;
this.gradleCurrentVersionMetadata = gradleCurrentVersionMetadata;
}

GradleMetadataFetcher() {
try {
this.gradleAllVersionsMetadata = new URL("https://services.gradle.org/versions/all");
this.gradleCurrentVersionMetadata = new URL("https://services.gradle.org/versions/current");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}

Optional<JsonNode> fetchLatestVersion(boolean allowPreRelease) throws IOException {
ObjectMapper mapper = new ObjectMapper();
if (allowPreRelease) {
return StreamSupport.stream(mapper.readTree(gradleAllVersionsMetadata).spliterator(), false)
.max(Comparator.comparing(n -> VersionNumber.parse(n.path("version").asText())))
.flatMap(n -> n.path("version").isMissingNode() ? Optional.empty() : Optional.of(n));
} else {
JsonNode gradleMetadata = mapper.readTree(gradleCurrentVersionMetadata);
return gradleMetadata.path("version").isMissingNode() ? Optional.empty() : Optional.of(gradleMetadata);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
package org.gradle.wrapperupgrade;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.gradle.process.ExecOperations;
import org.gradle.util.internal.VersionNumber;

import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

import static org.gradle.wrapperupgrade.BuildToolStrategy.extractBuildToolVersion;

public final class MavenBuildToolStrategy implements BuildToolStrategy {

private final MavenMetadataFetcher mavenMetadataFetcher = new MavenMetadataFetcher();
@Override
public String buildToolName() {
return "Maven";
}

@Override
public VersionInfo lookupLatestVersion() throws IOException {
XmlMapper mapper = new XmlMapper();
JsonNode mavenMetadata = mapper.readTree(new URL("https://repo.maven.apache.org/maven2/org/apache/maven/maven-core/maven-metadata.xml"));
JsonNode version = mavenMetadata.get("versioning").get("release");
if (version != null) {
return new VersionInfo(version.asText(), null);
} else {
throw new IllegalStateException("Could not determine latest Maven version");
}
public VersionInfo lookupLatestVersion(boolean allowPreRelease) throws IOException {
return mavenMetadataFetcher.fetchLatestVersion(allowPreRelease)
.map(latestVersion -> new VersionInfo(latestVersion.toString(), null))
.orElseThrow(() -> new IllegalStateException("Could not determine latest Maven version"));
}

@Override
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/org/gradle/wrapperupgrade/MavenMetadataFetcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.gradle.wrapperupgrade;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.gradle.util.internal.VersionNumber;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Comparator;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.StreamSupport;

public class MavenMetadataFetcher {

private final URL mavenMetadataUrl;

MavenMetadataFetcher(URL mavenMetadataUrl) {
this.mavenMetadataUrl = mavenMetadataUrl;
}

MavenMetadataFetcher() {
try {
this.mavenMetadataUrl = new URL("https://repo.maven.apache.org/maven2/org/apache/maven/maven-core/maven-metadata.xml");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}

Optional<VersionNumber> fetchLatestVersion(boolean allowPreRelease) throws IOException {
XmlMapper mapper = new XmlMapper();
JsonNode mavenMetadata = mapper.readTree(mavenMetadataUrl).path("versioning").path("versions").path("version");
if (mavenMetadata.isMissingNode()) {
return Optional.empty();
}
Predicate<VersionNumber> isReleaseOrIdentity = allowPreRelease ? v -> true : v -> v.getQualifier() == null;
return StreamSupport.stream(mavenMetadata.spliterator(), false)
.map(n -> VersionNumber.parse(n.asText()))
.sorted(Comparator.reverseOrder())
.filter(isReleaseOrIdentity)
.findFirst();
}

}
3 changes: 2 additions & 1 deletion src/main/java/org/gradle/wrapperupgrade/UpgradeWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public UpgradeWrapper(WrapperUpgradeDomainObject upgrade, BuildToolStrategy buil
@TaskAction
void upgrade() throws IOException {
GitHub gitHub = createGitHub();
VersionInfo latestBuildToolVersion = buildToolStrategy.lookupLatestVersion();
boolean allowPreRelease = upgrade.getOptions().getAllowPreRelease().orElse(Boolean.FALSE).get();
VersionInfo latestBuildToolVersion = buildToolStrategy.lookupLatestVersion(allowPreRelease);
Params params = Params.create(upgrade, buildToolStrategy, latestBuildToolVersion, layout.getProjectDirectory(), layout.getBuildDirectory(), gitHub);

if (!prExists(params)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,21 @@ public void options(Action<Options> action) {
public static class Options {

This comment has been minimized.

Copy link
@runningcode

runningcode Oct 28, 2022

Contributor

I believe this extension class can be simplified by using an abstract class: https://docs.gradle.org/current/userguide/custom_plugins.html#sec:getting_input_from_the_build

This comment has been minimized.

Copy link
@etiennestuder

etiennestuder Oct 28, 2022

Member

Personally, I like the explicitness better. Also, in some cases there comes some logic with it, which is usually put in the constructor.


private final ListProperty<String> gitCommitExtraArgs;
private final Property<Boolean> allowPreRelease;

@Inject
public Options(ObjectFactory objects) {
this.gitCommitExtraArgs = objects.listProperty(String.class);
this.allowPreRelease = objects.property(Boolean.class);
}

public ListProperty<String> getGitCommitExtraArgs() {
return gitCommitExtraArgs;
}

public Property<Boolean> getAllowPreRelease() {
return allowPreRelease;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.gradle.wrapperupgrade

import spock.lang.Shared
import spock.lang.Specification

class GradleMetadataFetcherTest extends Specification {

@Shared
def gradleMetadataFetcher = new GradleMetadataFetcher(getClass().getResource('/gradle-metadata-all.json'),
getClass().getResource('/gradle-metadata-current.json'))

def "fetch latest version allowing pre-releases"() {
when:
def version = gradleMetadataFetcher.fetchLatestVersion(true)

then:
version.map(node -> node.get('version').asText()).orElse(null) == '8.0-milestone-2'
}

def "fetch latest version ignoring pre-releases"() {
when:
def version = gradleMetadataFetcher.fetchLatestVersion(false)

then:
version.map(node -> node.get('version').asText()).orElse(null) == '7.5.1'
}

def "fetch unknown latest version allowing pre-releases"() {
when:
def version = new GradleMetadataFetcher(getClass().getResource('/gradle-metadata-all-unknown.json'),
getClass().getResource('/gradle-metadata-current.json')).fetchLatestVersion(true)

then:
version == Optional.empty()
}

def "fetch unknown latest version ignoring pre-releases"() {
when:
def version = new GradleMetadataFetcher(getClass().getResource('/gradle-metadata-all.json'),
getClass().getResource('/gradle-metadata-current-unknown.json')).fetchLatestVersion(false)

then:
version == Optional.empty()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ class GradleWrapperUpgradePluginFuncTest extends Specification {
File settingsFile
File buildFile

static boolean allowPreRelease = false

def setupSpec() {
latestGradleVersion = BuildToolStrategy.GRADLE.lookupLatestVersion().version
latestGradleVersion = BuildToolStrategy.GRADLE.lookupLatestVersion(allowPreRelease).version
}

def setup() {
Expand All @@ -41,6 +43,9 @@ wrapperUpgrade {
repo = 'gradle/wrapper-upgrade-gradle-plugin'
baseBranch = 'func-test-do-not-delete'
dir = 'samples/gradle'
options {
allowPreRelease = ${allowPreRelease}
}
}
}
}
Expand Down Expand Up @@ -92,7 +97,7 @@ wrapperUpgrade {
output2.contains "+distributionUrl=https\\://services.gradle.org/distributions/gradle-${latestGradleVersion}-bin.zip"
}

@Requires({ determineGradleVersion().baseVersion >= GradleVersion.version('7.0') })
@Requires({ determineGradleVersion().baseVersion >= GradleVersion.version('7.1') })
def "upgrade wrapper on wrapper-upgrade-gradle-plugin with dry run and configuration cache"() {
when:
def result = GradleRunner.create()
Expand All @@ -114,7 +119,7 @@ wrapperUpgrade {
.withProjectDir(testProjectDir)
.withPluginClasspath()
.withGradleVersion(determineGradleVersion().version)
.withArguments('clean', 'upgradeGradleWrapperAll', '--configuration-cache', '-DwrapperUpgrade.dryRun', '-DwrapperUpgrade.unsignedCommits')
.withArguments('clean', 'upgradeGradleWrapperAll', '--configuration-cache', '-DwrapperUpgrade.dryRun', '-DwrapperUpgrade.unsignedCommits', '--stacktrace')
.build()

then:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.gradle.wrapperupgrade

import spock.lang.Shared
import spock.lang.Specification

class MavenMetadataFetcherTest extends Specification {

@Shared
def mavenMetadataFetcher = new MavenMetadataFetcher(getClass().getResource('/maven-metadata.xml'))

def "fetch latest version allowing pre-releases"() {
when:
def version = mavenMetadataFetcher.fetchLatestVersion(true)

then:
version.map(v -> v as String).orElse(null) == '4.0.0-alpha-2'
}

def "fetch latest version ignoring pre-releases"() {
when:
def version = mavenMetadataFetcher.fetchLatestVersion(false)

then:
version.map(v -> v as String).orElse(null) == '3.8.6'
}

def "fetch unknown latest version"() {
when:
def version = new MavenMetadataFetcher(getClass().getResource('/maven-metadata-none.xml')).fetchLatestVersion(false)

then:
version == Optional.empty()
}

}
Loading

0 comments on commit 9db5424

Please sign in to comment.