diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index ff9696e1..b1077fbd 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index abdd7d0e..5064d4db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## v0.4.1 - Snapshot +* Added custom blossom injector dependency +* Updated dependencies +* Moved github update check util +* Added new update check utils +* Updated .idea files +* Removed simplecoreapi properties to use injected variables +* Added tests for every update checker (available at the moment) + ## v0.4.0 - Snapshot * Added Velocity Support * Now we use the ILogger util to allow the usage of slf4j and JUL diff --git a/build.gradle b/build.gradle index 0eea59bc..efe37929 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id 'org.jetbrains.dokka' version '1.7.10' } -def projectVersion = (System.getenv("VERSION") ?: '0.4.0-SNAPSHOT').replaceFirst("v", "").replace('/', '') +def projectVersion = (System.getenv("VERSION") ?: '0.4.1-SNAPSHOT').replaceFirst("v", "").replace('/', '') group 'xyz.theprogramsrc' version projectVersion diff --git a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/GitHubUpdateChecker.kt b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/GitHubUpdateChecker.kt index f3586387..9960dad7 100644 --- a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/GitHubUpdateChecker.kt +++ b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/GitHubUpdateChecker.kt @@ -10,15 +10,15 @@ import java.time.format.DateTimeFormatter /** * Representation of the GitHub Update Checker * @param logger The logger to use, it must be an instance of [ILogger] - * @param repo The repository to check + * @param repo The repository to check. The format should be /, for example TheProgramSrc/SimpleCoreAPI * @param currentVersion the current version (tag name) of the product + * @param latestReleaseTag The tag name of the latest release. (Defaults to "latest") */ -class GitHubUpdateChecker(val logger: ILogger, val repo: String, val currentVersion: String, val latestReleaseTag: String = "latest") { +class GitHubUpdateChecker(val logger: ILogger, val repo: String, val currentVersion: String, val latestReleaseTag: String = "latest"): UpdateChecker { private var lastCheck = 0L private var lastCheckResult = false - private var lastRequest = 0L - private var latestData = JsonObject() + private val requestedData = mutableMapOf>() private val current = if(currentVersion.startsWith("v")) currentVersion else "v$currentVersion" /** @@ -26,9 +26,9 @@ class GitHubUpdateChecker(val logger: ILogger, val repo: String, val currentVers * a message if there is one asking the end user to * update the product. */ - fun checkWithPrint() { - val latestData = getLatestReleaseData() - val latestVersion = latestData.get("tag_name").asString + override fun checkWithPrint() { + val latestData = getReleaseData() + val latestVersion = latestData.get("version").asString if(checkForUpdates()){ logger.info("Please update (from $current to $latestVersion)! Download it now from here: https://github.com/$repo/releases/tag/$latestVersion") } @@ -38,15 +38,13 @@ class GitHubUpdateChecker(val logger: ILogger, val repo: String, val currentVers * Checks if there is an update available * @return true if there is an update available, false otherwise */ - fun checkForUpdates(): Boolean { + override fun checkForUpdates(): Boolean { val difference = System.currentTimeMillis() - lastCheck if(difference > 60000 || lastCheck == 0L){ lastCheckResult = try { val parser = DateTimeFormatter.ISO_INSTANT - val currentData = JsonParser.parseString(URL("https://api.github.com/repos/$repo/releases/tags/$current").readText()).asJsonObject - val currentReleasedAt = Instant.from(parser.parse(currentData.get("published_at").asString)) - val latestData = getLatestReleaseData() - val latestReleasedAt = Instant.from(parser.parse(latestData.get("published_at").asString)) + val currentReleasedAt = Instant.from(parser.parse(getReleaseData(current).get("published_at").asString)) + val latestReleasedAt = Instant.from(parser.parse(getReleaseData(latestReleaseTag).get("published_at").asString)) Instant.from(currentReleasedAt).isBefore(latestReleasedAt) }catch (e: Exception){ e.printStackTrace() @@ -59,16 +57,33 @@ class GitHubUpdateChecker(val logger: ILogger, val repo: String, val currentVers } /** - * Gets the information of the latest release - * @return The information of the latest release + * Gets the information of a single release + * Object Sample: + * { "published_at": "2022-07-15T21:51:46.397962Z", "version": "v0.4.1-SNAPSHOT", "url": "https://github.com/TheProgramSrc/SimpleCoreAPI/releases/tag/v0.4.1-SNAPSHOT", "author_url": "https://github.com/Im-Fran" } + * - published_at: Is the date when the version was made public. This date must be able to be parsed by Instant#from + * - version: The version of the latest asset + * - url: The url to the version page (null if not available) + * - author_url: The url to the author profile (null if not available) + * + * @param id the name of the release. (If none specified the latest data is fetched. Defaults to "latest") + * @return The information of the given release name + * @since 0.4.1-SNAPSHOT */ - fun getLatestReleaseData(): JsonObject { - val difference = System.currentTimeMillis() - lastRequest - if(difference > 60000 || lastRequest == 0L){ - latestData = JsonParser.parseString(URL(if(latestReleaseTag != "latest") "https://api.github.com/repos/$repo/releases/tags/$latestReleaseTag" else "https://api.github.com/repos/$repo/releases/latest").readText()).asJsonObject - lastRequest = System.currentTimeMillis() + override fun getReleaseData(id: String): JsonObject { + var cached = requestedData.getOrDefault(id, Pair(JsonObject(), 0L)) + val difference = System.currentTimeMillis() - cached.second + if(difference > 60000 || cached.second == 0L){ + val json = JsonParser.parseString(URL(if(id != "latest") "https://api.github.com/repos/$repo/releases/tags/$id" else "https://api.github.com/repos/$repo/releases/latest").readText()).asJsonObject + cached = Pair(JsonObject().apply { + addProperty("published_at", json.get("published_at").asString) + addProperty("version", json.get("tag_name").asString) + addProperty("url", json.get("html_url").asString) + addProperty("author_url", json.get("author").asJsonObject.get("html_url").asString) + }, System.currentTimeMillis()) + requestedData[id] = cached } - return latestData + println(cached.first.toString() + " - $id") + return cached.first } } \ No newline at end of file diff --git a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SongodaUpdateChecker.kt b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SongodaUpdateChecker.kt new file mode 100644 index 00000000..fdd18c03 --- /dev/null +++ b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SongodaUpdateChecker.kt @@ -0,0 +1,92 @@ +package xyz.theprogramsrc.simplecoreapi.global.utils.update + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import xyz.theprogramsrc.simplecoreapi.global.utils.ILogger +import java.net.URL +import java.time.Instant +import java.time.format.DateTimeFormatter + +class SongodaUpdateChecker(val logger: ILogger, val productId: String, val currentVersion: String): UpdateChecker { + + private var lastCheck = 0L + private var lastCheckResult = false + private val requestedData = mutableMapOf>() + private val current = if(currentVersion.startsWith("v")) currentVersion else "v$currentVersion" + + /** + * Checks if there is an update available and prints + * a message if there is one asking the end user to + * update the product. + */ + override fun checkWithPrint() { + val latestData = getReleaseData() + val latestVersion = latestData.get("version").asString + if(checkForUpdates()){ + logger.info("Please update (from $current to $latestVersion)! Download it now from here: https://songoda.org/marketplace/product/$productId") + } + } + + /** + * Checks if there is an update available + * @return true if there is an update available, false otherwise + */ + override fun checkForUpdates(): Boolean { + val difference = System.currentTimeMillis() - lastCheck + if(difference > 60000 || lastCheck == 0L) { + lastCheckResult = try { + val parser = DateTimeFormatter.ISO_INSTANT + val currentReleasedAt = Instant.from(parser.parse(getReleaseData(currentVersion).get("published_at").asString)) + val latestReleasedAt = Instant.from(parser.parse(getReleaseData().get("published_at").asString)) + currentReleasedAt.isBefore(latestReleasedAt) + }catch (e: Exception) { + e.printStackTrace() + false + } + } + + return lastCheckResult + } + + /** + * Gets the information of a single release + * Object Sample: + * { "published_at": "2022-07-15T21:51:46.397962Z", "version": "v0.4.1-SNAPSHOT", "url": "https://github.com/TheProgramSrc/SimpleCoreAPI/releases/tag/v0.4.1-SNAPSHOT", "author_url": "https://github.com/Im-Fran" } + * - published_at: Is the date when the version was made public. This date must be able to be parsed by Instant#from + * - version: The version of the latest asset + * - url: The url to the version page (null if not available) + * - author_url: The url to the author profile (null if not available) + * + * @param id the name of the release. (If none specified the latest data is fetched. Defaults to "latest") + * @return The information of the given release name + * @since 0.4.1-SNAPSHOT + */ + override fun getReleaseData(id: String): JsonObject { + var cached = requestedData.getOrDefault(id, Pair(JsonObject(), 0L)) + val difference = System.currentTimeMillis() - cached.second + if(difference > 60000 || cached.second == 0L){ + val url = if(id == "latest"){ + "https://songoda.com/api/v2/products/id/$productId/versions?sort=-created_at&per_page=1" + } else { + "https://songoda.com/api/v2/products/id/$productId/versions?sort=-created_at&per_page=1&filter[version]=$id" + } + + val data = JsonParser.parseString(URL(url).readText()).asJsonObject.getAsJsonArray("data") + if(data.isEmpty){ + throw RuntimeException("We couldn't find any data for the product with id '$productId' and version '$id'. Please try again later.") + } + val json = data.get(0).asJsonObject + + cached = Pair(JsonObject().apply { + addProperty("published_at", DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochMilli(json.get("created_at").asLong * 1000L))) + addProperty("version", json.get("version").asString) + addProperty("url", json.get("url").asString) + addProperty("author_url", "https://songoda.com/profiles/${json.get("uploaded_by").asJsonObject.get("name").asString}") + }, System.currentTimeMillis()) + requestedData[id] = cached + } + return cached.first + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SpigotUpdateChecker.kt b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SpigotUpdateChecker.kt new file mode 100644 index 00000000..7c684529 --- /dev/null +++ b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SpigotUpdateChecker.kt @@ -0,0 +1,92 @@ +package xyz.theprogramsrc.simplecoreapi.global.utils.update + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import xyz.theprogramsrc.simplecoreapi.global.utils.ILogger +import java.net.URL +import java.time.Instant +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder + +class SpigotUpdateChecker(val logger: ILogger, val resourceId: String, val currentVersion: String): UpdateChecker { + + private var lastCheck = 0L + private var lastCheckResult = false + private val requestedData = mutableMapOf>() + private val current = if(currentVersion.startsWith("v")) currentVersion else "v$currentVersion" + + /** + * Checks if there is an update available and prints + * a message if there is one asking the end user to + * update the product. + */ + override fun checkWithPrint() { + val latestData = getReleaseData() + val latestVersion = latestData.get("version").asString + if(checkForUpdates()){ + logger.info("Please update (from $current to $latestVersion)! Download it now from here: https://spigotmc.org/resources/$resourceId") + } + } + + override fun checkForUpdates(): Boolean { + val difference = System.currentTimeMillis() - lastCheck + if(difference > 60000 || lastCheck == 0L) { + lastCheckResult = try { + val parser = DateTimeFormatter.ISO_INSTANT + val currentReleasedAt = Instant.from(parser.parse(getReleaseData(currentVersion).get("published_at").asString)) + val latestReleasedAt = Instant.from(parser.parse(getReleaseData().get("published_at").asString)) + currentReleasedAt.isBefore(latestReleasedAt) + }catch (e: Exception) { + e.printStackTrace() + false + } + } + + return lastCheckResult + } + + /** + * Gets the information of a single release + * Object Sample: + * { "published_at": "2022-07-15T21:51:46.397962Z", "version": "v0.4.1-SNAPSHOT", "url": "https://github.com/TheProgramSrc/SimpleCoreAPI/releases/tag/v0.4.1-SNAPSHOT", "author_url": "https://github.com/Im-Fran" } + * - published_at: Is the date when the version was made public. This date must be able to be parsed by Instant#from + * - version: The version of the latest asset + * - url: The url to the version page (null if not available) + * - author_url: The url to the author profile (null if not available) + * + * @param id the name of the release. (If none specified the latest data is fetched. Defaults to "latest") + * @return The information of the given release name + * @since 0.4.1-SNAPSHOT + */ + override fun getReleaseData(id: String): JsonObject { + var cached = requestedData.getOrDefault(id, Pair(JsonObject(), 0L)) + val difference = System.currentTimeMillis() - cached.second + if(difference > 60000 || cached.second == 0L){ + val json = if(id == "latest"){ + JsonParser.parseString(URL("https://api.spiget.org/v2/resources/$resourceId/versions/latest").readText()).asJsonObject + } else { + var page = 1 + var data: JsonObject? = null + while(data == null) { + val versions = JsonParser.parseString(URL("http://api.spiget.org/v2/resources/$resourceId/versions?size=50&page=$page").readText()).asJsonArray + if(versions.isEmpty) throw RuntimeException("Couldn't find any version for the given id: $id! Make sure you're using a valid version") + data = versions.firstOrNull { + it.asJsonObject.get("name").asString == id + }?.asJsonObject + page++ + } + data + } + + cached = Pair(JsonObject().apply { + addProperty("published_at", DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochMilli(json.get("releaseDate").asLong * 1000L))) + addProperty("version", json.get("name").asString) + }, System.currentTimeMillis()) + requestedData[id] = cached + } + return cached.first + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/UpdateChecker.kt b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/UpdateChecker.kt new file mode 100644 index 00000000..195a46f8 --- /dev/null +++ b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/UpdateChecker.kt @@ -0,0 +1,34 @@ +package xyz.theprogramsrc.simplecoreapi.global.utils.update + +import com.google.gson.JsonObject + +interface UpdateChecker { + + /** + * Checks if there is an update available and prints + * a message if there is one asking the end user to + * update the product. + */ + fun checkWithPrint() + + /** + * Checks if there is an update available + * @return true if there is an update available, false otherwise + */ + fun checkForUpdates(): Boolean + + /** + * Gets the information of a single release + * Object Sample: + * { "published_at": "2022-07-15T21:51:46.397962Z", "version": "v0.4.1-SNAPSHOT", "url": "https://github.com/TheProgramSrc/SimpleCoreAPI/releases/tag/v0.4.1-SNAPSHOT", "author_url": "https://github.com/Im-Fran" } + * - published_at: Is the date when the version was made public. This date must be able to be parsed by Instant#from + * - version: The version of the latest asset + * - url: The url to the version page (null if not available) + * - author_url: The url to the author profile (null if not available) + * + * @param id the name of the release. (If none specified the latest data is fetched. Defaults to "latest") + * @return The information of the given release name + * @since 0.4.1-SNAPSHOT + */ + fun getReleaseData(id: String = "latest"): JsonObject +} \ No newline at end of file diff --git a/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/GitHubUpdateCheckerTest.kt b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/GitHubUpdateCheckerTest.kt deleted file mode 100644 index edd6c60b..00000000 --- a/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/GitHubUpdateCheckerTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.theprogramsrc.simplecoreapi.global - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import xyz.theprogramsrc.simplecoreapi.global.utils.update.GitHubUpdateChecker -import xyz.theprogramsrc.simplecoreapi.global.utils.logger.JavaLogger -import xyz.theprogramsrc.simplecoreapi.global.utils.logger.SLF4JLogger -import java.util.logging.Logger - -internal class GitHubUpdateCheckerTest { - - private val check1 = GitHubUpdateChecker(JavaLogger(Logger.getLogger("GitHubUpdateCheckerTest - 1")), "TheProgramSrc/SimpleCoreAPI", "0.3.0-SNAPSHOT", "v0.3.0-SNAPSHOT") - private val check2 = GitHubUpdateChecker(SLF4JLogger(org.slf4j.LoggerFactory.getLogger("GitHubUpdateCheckerTest - 2")), "TheProgramSrc/SimpleCoreAPI", "0.3.0-SNAPSHOT") - - @Test - fun noUpdatesAvailableTest() { - assertEquals(false, check1.checkForUpdates()) - } - - @Test - fun updatesAvailableTest() { - assertEquals(true, check2.checkForUpdates()) - } -} diff --git a/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/GitHubUpdateCheckerTest.kt b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/GitHubUpdateCheckerTest.kt new file mode 100644 index 00000000..4e770b56 --- /dev/null +++ b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/GitHubUpdateCheckerTest.kt @@ -0,0 +1,28 @@ +package xyz.theprogramsrc.simplecoreapi.global.utils.update + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import xyz.theprogramsrc.simplecoreapi.global.utils.logger.* +import java.util.logging.Logger + +internal class GitHubUpdateCheckerTest { + + private val check1 = GitHubUpdateChecker(JavaLogger(Logger.getLogger("GitHubUpdateCheckerTest - 1")), "TheProgramSrc/SimpleCoreAPI", "0.4.0-SNAPSHOT", "v0.4.0-SNAPSHOT") + private val check2 = GitHubUpdateChecker(SLF4JLogger(org.slf4j.LoggerFactory.getLogger("GitHubUpdateCheckerTest - 2")), "TheProgramSrc/SimpleCoreAPI", "0.3.6-SNAPSHOT") + + @Test + fun getReleaseData() { + val data = check1.getReleaseData() + assertFalse(data.keySet().isEmpty()) + } + + @Test + fun noUpdatesAvailableTest() { + assertFalse(check1.checkForUpdates()) + } + + @Test + fun updatesAvailableTest() { + assertTrue(check2.checkForUpdates()) + } +} diff --git a/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SongodaUpdateCheckerTest.kt b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SongodaUpdateCheckerTest.kt new file mode 100644 index 00000000..bb64ffdf --- /dev/null +++ b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SongodaUpdateCheckerTest.kt @@ -0,0 +1,28 @@ +package xyz.theprogramsrc.simplecoreapi.global.utils.update + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import xyz.theprogramsrc.simplecoreapi.global.utils.logger.* +import java.util.logging.Logger + +internal class SongodaUpdateCheckerTest { + + private val check1 = SongodaUpdateChecker(JavaLogger(Logger.getLogger("SongodaUpdateCheckerTest - 1")), "255", "3.18.1") + private val check2 = SongodaUpdateChecker(SLF4JLogger(org.slf4j.LoggerFactory.getLogger("SongodaUpdateCheckerTest - 2")), "255", "3.18.0") + + @Test + fun getReleaseData() { + val data = check1.getReleaseData() + assertFalse(data.keySet().isEmpty()) + } + + @Test + fun noUpdatesAvailableTest() { + assertFalse(check1.checkForUpdates()) + } + + @Test + fun updatesAvailableTest() { + assertTrue(check2.checkForUpdates()) + } +} \ No newline at end of file diff --git a/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SpigotUpdateChecker.kt b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SpigotUpdateChecker.kt new file mode 100644 index 00000000..85d62a48 --- /dev/null +++ b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/utils/update/SpigotUpdateChecker.kt @@ -0,0 +1,28 @@ +package xyz.theprogramsrc.simplecoreapi.global.utils.update + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import xyz.theprogramsrc.simplecoreapi.global.utils.logger.* +import java.util.logging.Logger + +internal class SpigotUpdateCheckerTest { + + private val check1 = SpigotUpdateChecker(JavaLogger(Logger.getLogger("SpigotUpdateCheckerTest - 1")), "77825", "3.18.1") + private val check2 = SpigotUpdateChecker(SLF4JLogger(org.slf4j.LoggerFactory.getLogger("SpigotUpdateCheckerTest - 2")), "77825", "3.18.0") + + @Test + fun getReleaseData() { + val data = check1.getReleaseData() + assertFalse(data.keySet().isEmpty()) + } + + @Test + fun noUpdatesAvailableTest() { + assertFalse(check1.checkForUpdates()) + } + + @Test + fun updatesAvailableTest() { + assertTrue(check2.checkForUpdates()) + } +} \ No newline at end of file