diff --git a/cli/src/main/java/de/jplag/cli/CLI.java b/cli/src/main/java/de/jplag/cli/CLI.java index a5be41742..c60dcf0ee 100644 --- a/cli/src/main/java/de/jplag/cli/CLI.java +++ b/cli/src/main/java/de/jplag/cli/CLI.java @@ -49,6 +49,7 @@ public CLI(String[] args) { */ public void executeCli() throws ExitException, IOException { logger.debug("Your version of JPlag is {}", JPlag.JPLAG_VERSION); + JPlagVersionChecker.printVersionNotification(); if (!this.inputHandler.parse()) { CollectedLogger.setLogLevel(this.inputHandler.getCliOptions().advanced.logLevel); diff --git a/cli/src/main/java/de/jplag/cli/JPlagVersionChecker.java b/cli/src/main/java/de/jplag/cli/JPlagVersionChecker.java new file mode 100644 index 000000000..2f8a3ce5c --- /dev/null +++ b/cli/src/main/java/de/jplag/cli/JPlagVersionChecker.java @@ -0,0 +1,91 @@ +package de.jplag.cli; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Optional; + +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonObject; +import javax.json.JsonReader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.jplag.JPlag; +import de.jplag.reporting.reportobject.model.Version; + +/** + * Handles the check for newer versions. + */ +public class JPlagVersionChecker { + private static final String API_URL = "https://api.github.com/repos/jplag/JPlag/releases"; + private static final Logger logger = LoggerFactory.getLogger(JPlagVersionChecker.class); + private static final String EXPECTED_VERSION_FORMAT = "v\\d\\.\\d\\.\\d+"; + private static final String WARNING_UNABLE_TO_FETCH = "Unable to fetch version information. New version notification will not work."; + private static final String NEWER_VERSION_AVAILABLE = "There is a newer version ({}) available. You can download the newest version here: https://github.com/jplag/JPlag/releases"; + private static final String UNEXPECTED_ERROR = "There was an unexpected error, when checking for new versions. Please report this on: https://github.com/jplag/JPlag/issues"; + + private JPlagVersionChecker() { + + } + + /** + * Prints a warning if a newer version is available on GitHub. + */ + public static void printVersionNotification() { + Optional newerVersion = checkForNewVersion(); + newerVersion.ifPresent(version -> logger.warn(NEWER_VERSION_AVAILABLE, version)); + } + + private static Optional checkForNewVersion() { + try { + JsonArray array = fetchApi(); + Version newest = getNewestVersion(array); + Version current = JPlag.JPLAG_VERSION; + + if (newest.compareTo(current) > 0) { + return Optional.of(newest); + } + } catch (IOException | URISyntaxException e) { + logger.info(WARNING_UNABLE_TO_FETCH); + } catch (Exception e) { + logger.warn(UNEXPECTED_ERROR, e); + } + + return Optional.empty(); + } + + private static JsonArray fetchApi() throws IOException, URISyntaxException { + URL url = new URI(API_URL).toURL(); + URLConnection connection = url.openConnection(); + + try (JsonReader reader = Json.createReader(connection.getInputStream())) { + return reader.readArray(); + } + } + + private static Version getNewestVersion(JsonArray apiResult) { + return apiResult.stream().map(JsonObject.class::cast).map(version -> version.getString("name")) + .filter(versionName -> versionName.matches(EXPECTED_VERSION_FORMAT)).limit(1).map(JPlagVersionChecker::parseVersion).findFirst() + .orElse(JPlag.JPLAG_VERSION); + } + + /** + * Parses the version name. + * @param versionName The version name. The expected format is: v[major].[minor].[patch] + * @return The parsed version + */ + private static Version parseVersion(String versionName) { + String withoutPrefix = versionName.substring(1); + String[] parts = withoutPrefix.split("\\."); + return parseVersionParts(parts); + } + + private static Version parseVersionParts(String[] parts) { + return new Version(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2])); + } +} diff --git a/core/src/main/java/de/jplag/reporting/reportobject/model/Version.java b/core/src/main/java/de/jplag/reporting/reportobject/model/Version.java index ddf0fe1a9..7442e310d 100644 --- a/core/src/main/java/de/jplag/reporting/reportobject/model/Version.java +++ b/core/src/main/java/de/jplag/reporting/reportobject/model/Version.java @@ -1,5 +1,7 @@ package de.jplag.reporting.reportobject.model; +import java.util.Comparator; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,7 +14,8 @@ * @param minor MINOR version when you add functionality in a backwards compatible manner * @param patch PATCH version when you make backwards compatible bug fixes */ -public record Version(@JsonProperty("major") int major, @JsonProperty("minor") int minor, @JsonProperty("patch") int patch) { +public record Version(@JsonProperty("major") int major, @JsonProperty("minor") int minor, @JsonProperty("patch") int patch) + implements Comparable { /** * The default version for development (0.0.0). @@ -42,4 +45,9 @@ public static Version parseVersion(String version) { public String toString() { return String.format("%d.%d.%d", major, minor, patch); } + + @Override + public int compareTo(Version other) { + return Comparator.comparing(Version::major).thenComparing(Version::minor).thenComparing(Version::patch).compare(this, other); + } }