From 74c5d35fde5c3cc499c232c9af5cfe05ae14e3c4 Mon Sep 17 00:00:00 2001 From: Rollczi Date: Wed, 18 Jan 2023 00:05:23 +0100 Subject: [PATCH] Change name of project to gitcheck. Bump java version to 9. Add git domain. Add unit tests for all classes. Add option to implement git release provider. Add github release provider. Exclude junit from json simple dependency. Change name of license.txt to LICENSE. Reduce jar size from 3.1MB to 65KB (-99,97%). --- .github/CONTRIBUTING.md | 16 +++ .github/workflows/build.yml | 34 +++++ .github/workflows/buildAndPush.yml | 28 ----- .github/workflows/publish.yml | 29 +++++ license.txt => LICENSE | 0 README.md | 119 +++++++++--------- build.gradle.kts | 30 +++-- settings.gradle.kts | 2 +- .../com/eternalcode/gitcheck/GitCheck.java | 70 +++++++++++ .../eternalcode/gitcheck/GitCheckResult.java | 57 +++++++++ .../gitcheck/git/GitException.java | 13 ++ .../eternalcode/gitcheck/git/GitRelease.java | 106 ++++++++++++++++ .../gitcheck/git/GitReleaseProvider.java | 7 ++ .../gitcheck/git/GitRepository.java | 80 ++++++++++++ .../com/eternalcode/gitcheck/git/GitTag.java | 74 +++++++++++ .../github/GitHubReleaseProvider.java | 85 +++++++++++++ .../eternalcode/gitcheck/github/JSONUtil.java | 44 +++++++ .../gitcheck/shared/Preconditions.java | 21 ++++ .../com/eternalcode/updater/PluginData.java | 56 --------- .../java/com/eternalcode/updater/Updater.java | 47 ------- .../eternalcode/updater/http/HttpClient.java | 46 ------- .../updater/http/RemoteInformation.java | 55 -------- .../gitcheck/GitCheckResultTest.java | 44 +++++++ .../eternalcode/gitcheck/GitCheckTest.java | 51 ++++++++ .../gitcheck/git/GitExceptionTest.java | 25 ++++ .../gitcheck/git/GitReleaseTest.java | 93 ++++++++++++++ .../gitcheck/git/GitRepositoryTest.java | 38 ++++++ .../eternalcode/gitcheck/git/GitTagTest.java | 29 +++++ .../github/GitHubVersionProviderTest.java | 47 +++++++ .../gitcheck/github/JSONUtilTest.java | 48 +++++++ .../gitcheck/mock/MockGitReleaseProvider.java | 23 ++++ .../gitcheck/shared/PreconditionsTest.java | 36 ++++++ 32 files changed, 1150 insertions(+), 303 deletions(-) create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/buildAndPush.yml create mode 100644 .github/workflows/publish.yml rename license.txt => LICENSE (100%) create mode 100644 src/main/java/com/eternalcode/gitcheck/GitCheck.java create mode 100644 src/main/java/com/eternalcode/gitcheck/GitCheckResult.java create mode 100644 src/main/java/com/eternalcode/gitcheck/git/GitException.java create mode 100644 src/main/java/com/eternalcode/gitcheck/git/GitRelease.java create mode 100644 src/main/java/com/eternalcode/gitcheck/git/GitReleaseProvider.java create mode 100644 src/main/java/com/eternalcode/gitcheck/git/GitRepository.java create mode 100644 src/main/java/com/eternalcode/gitcheck/git/GitTag.java create mode 100644 src/main/java/com/eternalcode/gitcheck/github/GitHubReleaseProvider.java create mode 100644 src/main/java/com/eternalcode/gitcheck/github/JSONUtil.java create mode 100644 src/main/java/com/eternalcode/gitcheck/shared/Preconditions.java delete mode 100644 src/main/java/com/eternalcode/updater/PluginData.java delete mode 100644 src/main/java/com/eternalcode/updater/Updater.java delete mode 100644 src/main/java/com/eternalcode/updater/http/HttpClient.java delete mode 100644 src/main/java/com/eternalcode/updater/http/RemoteInformation.java create mode 100644 src/test/java/com/eternalcode/gitcheck/GitCheckResultTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/GitCheckTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/git/GitExceptionTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/git/GitReleaseTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/git/GitRepositoryTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/git/GitTagTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/github/GitHubVersionProviderTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/github/JSONUtilTest.java create mode 100644 src/test/java/com/eternalcode/gitcheck/mock/MockGitReleaseProvider.java create mode 100644 src/test/java/com/eternalcode/gitcheck/shared/PreconditionsTest.java diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..cfc8744 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,16 @@ +# Contributing to GitCheck +We welcome contributions to GitCheck! Here are some guidelines to follow: + +## Submitting Issues +If you find a bug or have a feature request, please submit an issue on GitHub. Be sure to include as much information as possible, such as the version of GitCheck you are using, and steps to reproduce the issue. + +## Pull Requests +We welcome pull requests! +If you would like to make changes to the code, please fork the repository, create a new branch, and submit a pull request. +Be sure to include a detailed description of the changes you have made, and include any relevant test cases. +Make sure to follow the code style of the project. :) + +## License +By contributing to GitCheck, you agree that your contributions will be licensed under the [MIT License](../LICENSE). + +Thank you for your interest in contributing to GitCheck! We look forward to reviewing your pull requests and issues. \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..0dd1021 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,34 @@ +name: Java CI and Test with Gradle + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + name: "Build with JDK${{ matrix.jdk }}" + runs-on: ubuntu-latest + strategy: + matrix: + jdk: [ 9, 11, 17 ] + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up JDK ${{ matrix.jdk }} + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.jdk }} + distribution: 'adopt' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x ./gradlew + + - name: Build with Gradle + run: ./gradlew clean build + + - name: Test with Gradle + run: ./gradlew clean test diff --git a/.github/workflows/buildAndPush.yml b/.github/workflows/buildAndPush.yml deleted file mode 100644 index 2984644..0000000 --- a/.github/workflows/buildAndPush.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Publish package to EternalCode Repository -on: - release: - types: [published] -jobs: - publish: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'adopt' - - name: Run chmod to make gradlew executable - run: chmod +x ./gradlew - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b - - name: Publish package - uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 - with: - arguments: publish - env: - E_REPO_USERNAME: ${{ secrets.E_REPO_USERNAME }} - E_REPO_PASS: ${{ secrets.E_REPO_PASS }} - E_VERSION: ${{ github.ref_name }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..e1e720e --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,29 @@ +name: Publish package to Maven Repository + +on: + release: + types: [ published ] + +jobs: + publish: + name: "Publish to Maven Repository" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: 17 + cache: 'gradle' + + - name: Grant execute permission for gradlew + run: chmod +x ./gradlew + + - name: Publish with Gradle + run: ./gradlew clean build publish + env: + ETERNALCODE_REPO_USERNAME: ${{ secrets.ETERNALCODE_REPO_USERNAME }} + ETERNALCODE_REPO_PASSWORD: ${{ secrets.ETERNALCODE_REPO_PASSWORD }} \ No newline at end of file diff --git a/license.txt b/LICENSE similarity index 100% rename from license.txt rename to LICENSE diff --git a/README.md b/README.md index a2f0d3d..e55dbf6 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,80 @@ -# Updater +# GitCheck +GitCheck is a Java library that makes it easy to check for updates to a GitHub repository. +It utilizes the GitHub API to retrieve information about the latest release and compares it to the current version of your application. +With GitCheck, you can ensure that your users are always running the latest version of your software. -#### Updater is a library for checking for updates for your plugin on GitHub. It uses the GitHub API to get information about the latest release of your plugin and compare it to the current version of your plugin. +## Features +- Simple and easy-to-use API +- Lightweight and efficient +- Supports Java 9 and above +- Utilizes the GitHub API for retrieving release information +- You can add your own implementation for another platform -### Usage -First, you need to create an instance of the `Updater` class by passing the plugin name, current version, and Github repository name as arguments. Then, you can call the `checkUpdates()` method to check for updates and get the `RemoteInformation` object. +## Installation -The `RemoteInformation` object contains information about the update, such as the availability of a new version, the current version, and the download URI. +To use GitCheck in your project, if you are using Gradle, add the following to your `build.gradle` file: -```java -if (remoteInformation.isAvailableNewVersion()) { - System.out.println("A new version is available: " + remoteInformation.getCurrentVersion()); - System.out.println("Download URI: " + remoteInformation.getDownloadUri()); -} else { - System.out.println("You are already running the latest version."); -} +```kotlin +maven { url = uri("https://repo.eternalcode.pl/releases") } ``` -### Example -Here's an example of how to can use the Updater in `Spigot` plugin - -```java - -import com.eternalcode.updater.Updater; -import com.eternalcode.updater.http.RemoteInformation; - -public class MyPlugin { +```kotlin +implementation("com.eternalcode:gitcheck:1.0.0") +``` - private Updater updater; +Or, if you are using Maven, add the following to your `pom.xml` file: - public void onEnable() { - updater = new Updater("MyPlugin", "1.0", "MyGithubUsername/MyPlugin"); - checkForUpdates(); - } +```xml + + eternalcode-releases + https://repo.eternalcode.pl/releases + +``` - private void checkForUpdates() { - RemoteInformation remoteInformation = updater.checkUpdates(); - if (remoteInformation.isAvailableNewVersion()) { - System.out.println("A new version is available: " + remoteInformation.getCurrentVersion()); - System.out.println("Download URI: " + remoteInformation.getDownloadUri()); - } else { - System.out.println("You are already running the latest version."); - } - } -} +```xml + + com.eternalcode + gitcheck + 1.0.0 + ``` -### Maven/Gradle -Get the latest version from [EternalCode Repository](https://repo.eternalcode.pl/#/releases/com/eternalcode/updater) +## API Usage -#### gradle groovy -```groovy -maven { url "https://repo.eternalcode.pl/releases" } +To use GitCheck, you need to create an instance of the `GitCheck` class. +Create `GitRepository` and `GitTag` objects to specify the repository and the current version of your application. +Then, call the `checkRelease` method to check for updates. -implementation "com.eternalcode:updater:{VERSION}" -``` +```java +public class MyApplication { -```kotlin -maven { url = uri("https://repo.eternalcode.pl/releases") } + public static void main(String[] args) { + GitCheck gitCheck = new GitCheck(); + GitRepository repository = GitRepository.of("Owner", "Project"); -implementation("com.eternalcode:updater:{VERSION}") -``` + GitCheckResult result = gitCheck.checkRelease(repository, GitTag.of("v1.0.0")); -```xml - - eternalcode-reposilite-releases - EternalCode Repository - https://repo.eternalcode.pl/releases - + if (!result.isUpToDate()) { + GitRelease release = result.getLatestRelease(); + GitTag tag = release.getTag(); - -com.eternalcode -updater -{VERSION} - -``` + System.out.println("A new version is available: " + tag.getTag()); + System.out.println("See release page: " + release.getPageUrl()); + System.out.println("Release date: " + release.getPublishedAt()); + } + + // ... + } +} +``` +In this example, `GitCheck` is used to check for updates to the repository `Owner/Project` with the current version `v1.0.0`. +If a new version is available, the details of the release are printed to the console. +## Contributing +We welcome contributions to GitCheck! +If you have an idea for a new feature or have found a bug that needs to be fixed, you can [open an issue](https://github.com/EternalCodeTeam/GitCheck/issues/new) or [submit a pull request](https://github.com/EternalCodeTeam/GitCheck/compare) with your changes.
+See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for more information. +## License +GitCheck is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index c2e9383..5363606 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,19 @@ plugins { `java-library` `maven-publish` + id("com.github.johnrengelman.shadow") version "7.1.2" } group = "com.eternalcode" -version = System.getenv("E_VERSION") +version = "1.0.0" +val artifactId = "gitcheck" java { withJavadocJar() withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_1_9 + targetCompatibility = JavaVersion.VERSION_1_9 } repositories { @@ -17,21 +22,23 @@ repositories { dependencies { // https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple - implementation("com.googlecode.json-simple:json-simple:1.1.1") + api("com.googlecode.json-simple:json-simple:1.1.1") { + exclude(group = "junit") + } - // OkHTTP - implementation("com.squareup.okhttp3:okhttp:4.10.0") + api("org.jetbrains:annotations:23.1.0") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") + testImplementation("nl.jqno.equalsverifier:equalsverifier:3.12.3") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") } publishing { publications { create("maven") { - groupId = "com.eternalcode" - artifactId = "updater" - version = System.getenv("E_VERSION") + groupId = "$group" + artifactId = artifactId + version = "${project.version}" from(components["java"]) } @@ -40,9 +47,10 @@ publishing { maven { name = "eternalcode-repository" url = uri("https://repo.eternalcode.pl/releases") + credentials { - username = System.getenv("E_REPO_USERNAME") - password = System.getenv("E_REPO_PASS") + username = System.getenv("ETERNALCODE_REPO_USERNAME") + password = System.getenv("ETERNALCODE_REPO_PASSWORD") } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index b93cf4b..768abdf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1,2 @@ -rootProject.name = "eternalupdater" +rootProject.name = "gitcheck" diff --git a/src/main/java/com/eternalcode/gitcheck/GitCheck.java b/src/main/java/com/eternalcode/gitcheck/GitCheck.java new file mode 100644 index 0000000..baa2d04 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/GitCheck.java @@ -0,0 +1,70 @@ +package com.eternalcode.gitcheck; + +import com.eternalcode.gitcheck.git.GitRelease; +import com.eternalcode.gitcheck.git.GitReleaseProvider; +import com.eternalcode.gitcheck.git.GitRepository; +import com.eternalcode.gitcheck.git.GitTag; +import com.eternalcode.gitcheck.github.GitHubReleaseProvider; +import com.eternalcode.gitcheck.shared.Preconditions; +import org.jetbrains.annotations.NotNull; + +/** + * Service for checking if the latest release is up to date. + *

+ * This service uses {@link GitReleaseProvider} to get the latest release and compares it with the current tag. + * The current tag is provided by {@link GitTag#of(String)} + *
+ */ +public class GitCheck { + + private final GitReleaseProvider versionProvider; + + /** + * Creates a new instance of {@link GitCheck} with the default {@link GitHubReleaseProvider}. + */ + public GitCheck() { + this(new GitHubReleaseProvider()); + } + + /** + * Creates a new instance of {@link GitCheck} with the given {@link GitReleaseProvider}. + * + * @param versionProvider the version provider + */ + public GitCheck(@NotNull GitReleaseProvider versionProvider) { + Preconditions.notNull(versionProvider, "release provider"); + this.versionProvider = versionProvider; + } + + /** + * Gets the latest release for the given repository. + * + * @param repository the repository + * @return the latest release + */ + @NotNull + public GitRelease getLatestRelease(@NotNull GitRepository repository) { + Preconditions.notNull(repository, "repository"); + + return this.versionProvider.getLatestRelease(repository); + } + + /** + * Creates a new instance of {@link GitCheckResult} for the given repository and tag. + * Result contains the latest release and the current tag. + * Use {@link GitCheckResult#isUpToDate()} to check if the latest release is up to date. + * + * @param repository the repository + * @param currentTag the current tag + * @return the result + */ + @NotNull + public GitCheckResult checkRelease(@NotNull GitRepository repository, @NotNull GitTag currentTag) { + Preconditions.notNull(repository, "repository"); + Preconditions.notNull(currentTag, "current tag"); + + GitRelease latestRelease = this.getLatestRelease(repository); + return new GitCheckResult(latestRelease, currentTag); + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/GitCheckResult.java b/src/main/java/com/eternalcode/gitcheck/GitCheckResult.java new file mode 100644 index 0000000..86c19c7 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/GitCheckResult.java @@ -0,0 +1,57 @@ +package com.eternalcode.gitcheck; + +import com.eternalcode.gitcheck.git.GitRelease; +import com.eternalcode.gitcheck.git.GitTag; +import com.eternalcode.gitcheck.shared.Preconditions; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +/** + * Represents the result of a git check. + */ +public class GitCheckResult { + + private final GitRelease latestRelease; + private final GitTag currentTag; + + @ApiStatus.Internal + GitCheckResult(@NotNull GitRelease latestRelease, @NotNull GitTag currentTag) { + Preconditions.notNull(latestRelease, "latest release"); + Preconditions.notNull(currentTag, "current tag"); + + this.latestRelease = latestRelease; + this.currentTag = currentTag; + } + + /** + * Gets the latest release. + * + * @return the latest release + */ + @NotNull + public GitRelease getLatestRelease() { + return this.latestRelease; + } + + /** + * Gets the current tag. + * + * @return the current tag + */ + @NotNull + public GitTag getCurrentTag() { + return this.currentTag; + } + + /** + * Checks if the latest release is up to date. + * + * @return {@code true} if the latest release is up to date, {@code false} otherwise + */ + @Contract(pure = true) + public boolean isUpToDate() { + return this.latestRelease.getTag().equals(this.currentTag); + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/git/GitException.java b/src/main/java/com/eternalcode/gitcheck/git/GitException.java new file mode 100644 index 0000000..67a2165 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/git/GitException.java @@ -0,0 +1,13 @@ +package com.eternalcode.gitcheck.git; + +public class GitException extends RuntimeException { + + public GitException(String message) { + super(message); + } + + public GitException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/git/GitRelease.java b/src/main/java/com/eternalcode/gitcheck/git/GitRelease.java new file mode 100644 index 0000000..6858706 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/git/GitRelease.java @@ -0,0 +1,106 @@ +package com.eternalcode.gitcheck.git; + +import com.eternalcode.gitcheck.shared.Preconditions; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.time.Instant; + +public final class GitRelease { + + private final String name; + private final String branch; + private final GitTag tag; + private final String pageUrl; + private final Instant publishedAt; + + private GitRelease(@NotNull String name, @NotNull String branch, @NotNull GitTag tag, @NotNull String pageUrl, @NotNull Instant publishedAt) { + this.name = name; + this.branch = branch; + this.tag = tag; + this.pageUrl = pageUrl; + this.publishedAt = publishedAt; + } + + @NotNull + public String getName() { + return this.name; + } + + @NotNull + public String getBranch() { + return this.branch; + } + + @NotNull + public GitTag getTag() { + return this.tag; + } + + @NotNull + public String getPageUrl() { + return this.pageUrl; + } + + @NotNull + public Instant getPublishedAt() { + return this.publishedAt; + } + + @NotNull + @Contract("-> new") + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String name; + private String branch; + private GitTag tag; + private String pageUrl; + private Instant publishedAt; + + public Builder name(@NotNull String name) { + Preconditions.notNull(name, "name"); + this.name = name; + return this; + } + + public Builder branch(@NotNull String branch) { + Preconditions.notNull(branch, "branch"); + this.branch = branch; + return this; + } + + public Builder tag(@NotNull GitTag tag) { + Preconditions.notNull(tag, "tag"); + this.tag = tag; + return this; + } + + public Builder pageUrl(@NotNull String pageUrl) { + Preconditions.notNull(pageUrl, "page url"); + this.pageUrl = pageUrl; + return this; + } + + public Builder publishedAt(@NotNull Instant publishedAt) { + Preconditions.notNull(publishedAt, "published at"); + this.publishedAt = publishedAt; + return this; + } + + public GitRelease build() { + Preconditions.notNull(this.name, "name"); + Preconditions.notNull(this.branch, "branch"); + Preconditions.notNull(this.tag, "tag"); + Preconditions.notNull(this.pageUrl, "page url"); + Preconditions.notNull(this.publishedAt, "publishedAt"); + + return new GitRelease(this.name, this.branch, this.tag, this.pageUrl, this.publishedAt); + } + + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/git/GitReleaseProvider.java b/src/main/java/com/eternalcode/gitcheck/git/GitReleaseProvider.java new file mode 100644 index 0000000..450f757 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/git/GitReleaseProvider.java @@ -0,0 +1,7 @@ +package com.eternalcode.gitcheck.git; + +public interface GitReleaseProvider { + + GitRelease getLatestRelease(GitRepository repository); + +} diff --git a/src/main/java/com/eternalcode/gitcheck/git/GitRepository.java b/src/main/java/com/eternalcode/gitcheck/git/GitRepository.java new file mode 100644 index 0000000..8874462 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/git/GitRepository.java @@ -0,0 +1,80 @@ +package com.eternalcode.gitcheck.git; + +import com.eternalcode.gitcheck.shared.Preconditions; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +/** + * Represents a git repository. + */ +public final class GitRepository { + + private static final String FULL_NAME_FORMAT = "%s/%s"; + + private final String owner; + private final String name; + + /** + * Creates a new instance of {@link GitRepository} with the given owner and name. + * + * @see #of(String, String) + * @param owner the owner of the repository + * @param name the name of the repository + */ + private GitRepository(@NotNull String owner, @NotNull String name) { + Preconditions.notNull(owner, "owner"); + Preconditions.notNull(name, "name"); + Preconditions.notEmpty(owner, "owner"); + Preconditions.notEmpty(name, "name"); + + this.owner = owner; + this.name = name; + } + + @NotNull + public String getOwner() { + return this.owner; + } + + @NotNull + public String getName() { + return this.name; + } + + @NotNull + public String getFullName() { + return String.format(FULL_NAME_FORMAT, this.owner, this.name); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + + if (!(object instanceof GitRepository)) { + return false; + } + + GitRepository that = (GitRepository) object; + return this.owner.equals(that.owner) && this.name.equals(that.name); + } + + @Override + public int hashCode() { + return Objects.hash(this.owner, this.name); + } + + /** + * Creates a new instance of {@link GitRepository} with the given owner and name. + * + * @param owner the owner of the repository + * @param name the name of the repository + * @return repository of the given owner and name + */ + public static GitRepository of(@NotNull String owner, @NotNull String name) { + return new GitRepository(owner, name); + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/git/GitTag.java b/src/main/java/com/eternalcode/gitcheck/git/GitTag.java new file mode 100644 index 0000000..21bf430 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/git/GitTag.java @@ -0,0 +1,74 @@ +package com.eternalcode.gitcheck.git; + +import com.eternalcode.gitcheck.shared.Preconditions; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +/** + * Represents a git tag. + */ +public final class GitTag { + + private final String tag; + + /** + * Creates a new instance of {@link GitTag} with the given tag. + * + * @see #of(String) + * @param tag the tag + */ + private GitTag(@NotNull String tag) { + Preconditions.notNull(tag, "tag"); + this.tag = tag; + } + + @NotNull + public String getTag() { + return this.tag; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + + if (!(object instanceof GitTag)) { + return false; + } + + GitTag gitTag = (GitTag) object; + return this.tag.equals(gitTag.tag); + } + + @Override + public int hashCode() { + return Objects.hash(this.tag); + } + + @Override + public String toString() { + return this.tag; + } + + /** + * Creates a new instance of {@link GitTag} with the given tag. + *

+ * Tag should be in the format of {@code v1.0.0}, but it can be anything. + *
+ * This method does not validate the tag. + *
+ *

+ * + * @throws IllegalArgumentException if the tag is null + * @param tag the tag + * @return the git tag + */ + @Contract("_ -> new") + public static GitTag of(@NotNull String tag) { + return new GitTag(tag); + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/github/GitHubReleaseProvider.java b/src/main/java/com/eternalcode/gitcheck/github/GitHubReleaseProvider.java new file mode 100644 index 0000000..0d67221 --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/github/GitHubReleaseProvider.java @@ -0,0 +1,85 @@ +package com.eternalcode.gitcheck.github; + +import com.eternalcode.gitcheck.git.GitException; +import com.eternalcode.gitcheck.git.GitRelease; +import com.eternalcode.gitcheck.git.GitReleaseProvider; +import com.eternalcode.gitcheck.git.GitRepository; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.stream.Collectors; + +public class GitHubReleaseProvider implements GitReleaseProvider { + + private static final String USER_AGENT = "Mozilla/5.0"; + private static final String GET_LATEST_RELEASE = "https://api.github.com/repos/%s/releases/latest"; + + @Override + public GitRelease getLatestRelease(GitRepository repository) { + JSONObject json = this.requestLastRelease(repository); + + return GitRelease.builder() + .name(JSONUtil.asString(json, "name")) + .branch(JSONUtil.asString(json, "target_commitish")) + .tag(JSONUtil.asGitTag(json, "tag_name")) + .pageUrl(JSONUtil.asString(json, "html_url")) + .publishedAt(JSONUtil.asInstant(json, "published_at")) + .build(); + } + + private JSONObject requestLastRelease(GitRepository repository) { + String getUrl = String.format(GET_LATEST_RELEASE, repository.getFullName()); + + try { + URL url = new URL(getUrl); + URLConnection urlConnection = url.openConnection(); + + if (!(urlConnection instanceof HttpURLConnection)) { + throw new GitException("The URL is not an HTTP URL"); + } + + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + + httpURLConnection.setRequestProperty("User-Agent", USER_AGENT); + httpURLConnection.connect(); + + if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { + throw new GitException("The release of the repository " + repository.getFullName() + " was not found"); + } + + if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { + throw new GitException("The response code is not 200"); + } + + String response = this.readResponse(httpURLConnection); + + JSONParser parser = new JSONParser(); + Object parsed = parser.parse(response); + + if (!(parsed instanceof JSONObject)) { + throw new GitException("The response is not a JSON object"); + } + + return (JSONObject) parsed; + } catch (IOException exception) { + throw new GitException("Invalid URL", exception); + } catch (ParseException exception) { + throw new GitException("Invalid JSON response", exception); + } + } + + private String readResponse(HttpURLConnection connection) throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + return reader.lines() + .collect(Collectors.joining()); + } + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/github/JSONUtil.java b/src/main/java/com/eternalcode/gitcheck/github/JSONUtil.java new file mode 100644 index 0000000..c9e89ab --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/github/JSONUtil.java @@ -0,0 +1,44 @@ +package com.eternalcode.gitcheck.github; + +import com.eternalcode.gitcheck.git.GitTag; +import org.json.simple.JSONObject; + +import java.time.Instant; +import java.util.NoSuchElementException; + +final class JSONUtil { + + private JSONUtil() { + } + + static String asString(JSONObject jsonObject, String key) { + return as(jsonObject, key, String.class); + } + + static GitTag asGitTag(JSONObject jsonObject, String key) { + String rawTag = as(jsonObject, key, String.class); + + return GitTag.of(rawTag); + } + + static Instant asInstant(JSONObject jsonObject, String key) { + String rawDateTime = as(jsonObject, key, String.class); + + return Instant.parse(rawDateTime); + } + + private static T as(JSONObject jsonObject, String key, Class clazz) { + Object obj = jsonObject.get(key); + + if (obj == null) { + throw new NoSuchElementException("No value for key " + key); + } + + if (!clazz.isInstance(obj)) { + throw new IllegalArgumentException("Value for key " + key + " is not of type " + clazz.getSimpleName()); + } + + return clazz.cast(obj); + } + +} diff --git a/src/main/java/com/eternalcode/gitcheck/shared/Preconditions.java b/src/main/java/com/eternalcode/gitcheck/shared/Preconditions.java new file mode 100644 index 0000000..b15febf --- /dev/null +++ b/src/main/java/com/eternalcode/gitcheck/shared/Preconditions.java @@ -0,0 +1,21 @@ +package com.eternalcode.gitcheck.shared; + +public final class Preconditions { + + private Preconditions() { + throw new UnsupportedOperationException("Cannot create instance of class Validation"); + } + + public static void notNull(Object object, String name) { + if (object == null) { + throw new IllegalArgumentException(name + " cannot be null"); + } + } + + public static void notEmpty(String owner, String name) { + if (owner.isEmpty()) { + throw new IllegalArgumentException(name + " cannot be empty"); + } + } + +} diff --git a/src/main/java/com/eternalcode/updater/PluginData.java b/src/main/java/com/eternalcode/updater/PluginData.java deleted file mode 100644 index 5ad0736..0000000 --- a/src/main/java/com/eternalcode/updater/PluginData.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.eternalcode.updater; - -import org.jetbrains.annotations.Contract; - -/** - * The PluginData class is used to store information about a plugin. - */ -public class PluginData { - - private final String githubRepository; - private final String pluginVersion; - private final String pluginName; - - /** - * Creates a new instance of PluginData with the GitHub repository name, plugin version, and plugin name. - * - * @param githubRepository The GitHub repository name - * @param pluginVersion The version of the plugin - * @param pluginName The name of the plugin - */ - public PluginData(String githubRepository, String pluginVersion, String pluginName) { - this.githubRepository = githubRepository; - this.pluginVersion = pluginVersion; - this.pluginName = pluginName; - } - - /** - * Returns the GitHub repository name - * - * @return The GitHub repository name - */ - @Contract(pure = true) - public String getGithubRepository() { - return this.githubRepository; - } - - /** - * Returns the version of the plugin - * - * @return The version of the plugin - */ - @Contract(pure = true) - public String getPluginVersion() { - return this.pluginVersion; - } - - /** - * Returns the name of the plugin - * - * @return The name of the plugin - */ - @Contract(pure = true) - public String getPluginName() { - return this.pluginName; - } -} diff --git a/src/main/java/com/eternalcode/updater/Updater.java b/src/main/java/com/eternalcode/updater/Updater.java deleted file mode 100644 index 0744932..0000000 --- a/src/main/java/com/eternalcode/updater/Updater.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.eternalcode.updater; - -import com.eternalcode.updater.http.RemoteInformation; -import com.eternalcode.updater.http.HttpClient; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.json.simple.JSONObject; - -/** - * The Updater class is used to check for updates for a plugin. - */ -public class Updater { - - private final PluginData pluginData; - - /** - * Creates a new instance of Updater with the plugin name, plugin version, and GitHub remote repository name. - * - * @param pluginName The name of the plugin - * @param pluginVersion The current version of the plugin - * @param githubRepository The name of the GitHub remote repository (e.g. eternalcodeteam/eternalcore) - */ - public Updater(@NotNull String pluginName, @NotNull String pluginVersion, @NotNull String githubRepository) { - this.pluginData = new PluginData(githubRepository, pluginVersion, pluginName); - } - - /** - * Checks for updates for the plugin. - * - * @return Remote plugin information - * @throws RuntimeException If there is a connection problem or the remote repository is not found - */ - @Contract(pure = true) - public RemoteInformation checkUpdates() { - JSONObject response = HttpClient.doRequest("repos/" + this.pluginData.getGithubRepository() + "/releases/latest"); - boolean newVersionAvailable = !this.pluginData.getPluginVersion().equals(response.get("tag_name")); - String latestTag = (String) response.get("tag_name"); - String newDownloadUri = (String) response.get("zipball_url"); - - return new RemoteInformation( - newVersionAvailable, - latestTag, - newDownloadUri - ); - } - -} diff --git a/src/main/java/com/eternalcode/updater/http/HttpClient.java b/src/main/java/com/eternalcode/updater/http/HttpClient.java deleted file mode 100644 index 310ad57..0000000 --- a/src/main/java/com/eternalcode/updater/http/HttpClient.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.eternalcode.updater.http; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.jetbrains.annotations.Contract; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; - -/** - * The HttpClient class is used to send HTTP requests to the GitHub server. - */ -public class HttpClient { - - private final static String baseUri = "https://api.github.com/"; - private final static OkHttpClient client = new OkHttpClient(); - - /** - * Sends an HTTP request to the GitHub server and returns the response as a JSON object. - * - * @param url The URL of the request - * @return The server's response in JSON format - * @throws RuntimeException If there is a connection problem or the provided repository is not found - */ - @Contract(pure = true) - public static JSONObject doRequest(String url) { - Request request = new Request - .Builder() - .url(baseUri + "" + url) - .build(); - - try (Response response = client.newCall(request).execute()) { - JSONObject jsonResponse = (JSONObject) new JSONParser().parse(response.body().string()); - - if (jsonResponse.containsKey("message")) { - throw new Exception("[EternalUpdater] Provided repository was not found"); - } - else { - return jsonResponse; - } - } - catch (Exception exception) { - throw new RuntimeException(exception); - } - } -} diff --git a/src/main/java/com/eternalcode/updater/http/RemoteInformation.java b/src/main/java/com/eternalcode/updater/http/RemoteInformation.java deleted file mode 100644 index ab94a05..0000000 --- a/src/main/java/com/eternalcode/updater/http/RemoteInformation.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.eternalcode.updater.http; - -import org.jetbrains.annotations.Contract; - -/** - * The RemoteInformation class is used to store information about a plugin update. - */ -public class RemoteInformation { - private final boolean isAvailableNewVersion; - private final String currentVersion; - private final String downloadUri; - - /** - * Creates a new instance of RemoteInformation with the update availability, current version, and download URI. - * - * @param isAvailableNewVersion True if a new version is available, false otherwise - * @param currentVersion The current version of the plugin - * @param downloadUri The URI to download the update - */ - public RemoteInformation(boolean isAvailableNewVersion, String currentVersion, String downloadUri) { - this.isAvailableNewVersion = isAvailableNewVersion; - this.currentVersion = currentVersion; - this.downloadUri = downloadUri; - } - - /** - * Returns the URI to download the update - * - * @return The URI to download the update - */ - @Contract(pure = true) - public String getDownloadUri() { - return this.downloadUri; - } - - /** - * Indicates if a new version is available - * - * @return True if a new version is available, false otherwise - */ - @Contract(pure = true) - public boolean isAvailableNewVersion() { - return this.isAvailableNewVersion; - } - - /** - * Returns the current version of the plugin - * - * @return The current version of the plugin - */ - @Contract(pure = true) - public String getCurrentVersion() { - return this.currentVersion; - } -} diff --git a/src/test/java/com/eternalcode/gitcheck/GitCheckResultTest.java b/src/test/java/com/eternalcode/gitcheck/GitCheckResultTest.java new file mode 100644 index 0000000..873e0ff --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/GitCheckResultTest.java @@ -0,0 +1,44 @@ +package com.eternalcode.gitcheck; + +import com.eternalcode.gitcheck.git.GitRelease; +import com.eternalcode.gitcheck.git.GitTag; +import org.junit.jupiter.api.Test; + +import java.time.Instant; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GitCheckResultTest { + + private final GitRelease release = GitRelease.builder() + .name("test") + .branch("master") + .tag(GitTag.of("v2.0.0")) + .pageUrl("https://repo.eternalcode.pl/releases") + .publishedAt(Instant.parse("2020-01-01T00:00:00Z")) + .build(); + + private final GitCheckResult noActualResult = new GitCheckResult(this.release, GitTag.of("v1.0.0")); + private final GitCheckResult actualResult = new GitCheckResult(this.release, GitTag.of("v2.0.0")); + + @Test + void testIsUpToDate() { + assertFalse(this.noActualResult.isUpToDate()); + assertTrue(this.actualResult.isUpToDate()); + } + + @Test + void testGetRelease() { + assertEquals(this.release, this.noActualResult.getLatestRelease()); + assertEquals(this.release, this.actualResult.getLatestRelease()); + } + + @Test + void testGetActualTag() { + assertEquals(GitTag.of("v1.0.0"), this.noActualResult.getCurrentTag()); + assertEquals(GitTag.of("v2.0.0"), this.actualResult.getCurrentTag()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/GitCheckTest.java b/src/test/java/com/eternalcode/gitcheck/GitCheckTest.java new file mode 100644 index 0000000..88925ee --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/GitCheckTest.java @@ -0,0 +1,51 @@ +package com.eternalcode.gitcheck; + +import com.eternalcode.gitcheck.git.GitRelease; +import com.eternalcode.gitcheck.git.GitRepository; +import com.eternalcode.gitcheck.git.GitTag; +import com.eternalcode.gitcheck.mock.MockGitReleaseProvider; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class GitCheckTest { + + @Test + void testDefaultConstructor() { + assertDoesNotThrow(() -> new GitCheck()); + } + + @Test + void testGetLatestRelease() { + GitCheck gitCheck = new GitCheck(new MockGitReleaseProvider()); + GitRepository repository = GitRepository.of("EternalCodeTeam", "ChatFormatter"); + + GitRelease release = gitCheck.getLatestRelease(repository); + + assertNotNull(release); + } + + @Test + void testGetLatestReleaseWithNullRepository() { + GitCheck gitCheck = new GitCheck(new MockGitReleaseProvider()); + + assertThrows(IllegalArgumentException.class, () -> gitCheck.getLatestRelease(null)); + } + + @Test + void testCheckRelease() { + GitCheck gitCheck = new GitCheck(new MockGitReleaseProvider()); + GitRepository repository = GitRepository.of("EternalCodeTeam", "ChatFormatter"); + GitTag tag = GitTag.of("v1.0.0"); + + GitCheckResult result = gitCheck.checkRelease(repository, tag); + + assertNotNull(result); + assertNotNull(result.getLatestRelease()); + assertEquals(tag, result.getCurrentTag()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/git/GitExceptionTest.java b/src/test/java/com/eternalcode/gitcheck/git/GitExceptionTest.java new file mode 100644 index 0000000..d4a0abc --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/git/GitExceptionTest.java @@ -0,0 +1,25 @@ +package com.eternalcode.gitcheck.git; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class GitExceptionTest { + + @Test + void testMessage() { + GitException exception = new GitException("message"); + + assertEquals("message", exception.getMessage()); + } + + @Test + void testMessageAndCause() { + RuntimeException runtimeException = new RuntimeException(); + GitException exception = new GitException("message", runtimeException); + + assertEquals("message", exception.getMessage()); + assertEquals(runtimeException, exception.getCause()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/git/GitReleaseTest.java b/src/test/java/com/eternalcode/gitcheck/git/GitReleaseTest.java new file mode 100644 index 0000000..41d25e6 --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/git/GitReleaseTest.java @@ -0,0 +1,93 @@ +package com.eternalcode.gitcheck.git; + +import org.junit.jupiter.api.Test; + +import java.time.Instant; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class GitReleaseTest { + + private final String name = "GitCheck 1.0."; + private final String branch = "master"; + private final GitTag tag = GitTag.of("v1.0.0"); + private final String pageUrl = "https://github.com/EternalCodeTeam/EternalCore/releases/tag/v1.0.0"; + private final Instant time = Instant.now(); + + @Test + void testSuccessfulBuilder() { + GitRelease release = GitRelease.builder() + .name(this.name) + .branch(this.branch) + .tag(this.tag) + .pageUrl(this.pageUrl) + .publishedAt(this.time) + .build(); + + assertEquals(this.name, release.getName()); + assertEquals(this.branch, release.getBranch()); + assertEquals(this.tag, release.getTag()); + assertEquals(this.pageUrl, release.getPageUrl()); + assertEquals(this.time, release.getPublishedAt()); + } + + @Test + void testNotFinishedBuilder() { + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder().build()); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .branch(this.branch) + .tag(this.tag) + .pageUrl(this.pageUrl) + .publishedAt(this.time) + .build()); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .name(this.name) + .tag(this.tag) + .pageUrl(this.pageUrl) + .publishedAt(this.time) + .build()); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .name(this.name) + .branch(this.branch) + .pageUrl(this.pageUrl) + .publishedAt(this.time) + .build()); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .name(this.name) + .branch(this.branch) + .tag(this.tag) + .publishedAt(this.time) + .build()); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .name(this.name) + .branch(this.branch) + .tag(this.tag) + .pageUrl(this.pageUrl) + .build()); + } + + @Test + void testNullBuilder() { + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .name(null)); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .branch(null)); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .tag(null)); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .pageUrl(null)); + + assertThrows(IllegalArgumentException.class, () -> GitRelease.builder() + .publishedAt(null)); + } + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/git/GitRepositoryTest.java b/src/test/java/com/eternalcode/gitcheck/git/GitRepositoryTest.java new file mode 100644 index 0000000..51391ec --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/git/GitRepositoryTest.java @@ -0,0 +1,38 @@ +package com.eternalcode.gitcheck.git; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class GitRepositoryTest { + + @Test + void testSuccessful() { + GitRepository repository = GitRepository.of("EternalCodeTeam", "GitCheck"); + + assertEquals("EternalCodeTeam", repository.getOwner()); + assertEquals("GitCheck", repository.getName()); + assertEquals("EternalCodeTeam/GitCheck", repository.getFullName()); + } + + @Test + void testNullOwner() { + assertThrows(IllegalArgumentException.class, () -> GitRepository.of(null, "GitCheck")); + } + + @Test + void testNullName() { + assertThrows(IllegalArgumentException.class, () -> GitRepository.of("EternalCodeTeam", null)); + } + + @Test + void testHashcodeAndEquals() { + EqualsVerifier.forClass(GitRepository.class) + .withNonnullFields("owner", "name") + .verify(); + } + + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/git/GitTagTest.java b/src/test/java/com/eternalcode/gitcheck/git/GitTagTest.java new file mode 100644 index 0000000..2d3954d --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/git/GitTagTest.java @@ -0,0 +1,29 @@ +package com.eternalcode.gitcheck.git; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class GitTagTest { + + @Test + void testSuccessfulTag() { + GitTag tag = GitTag.of("v1.0.0"); + assertEquals("v1.0.0", tag.getTag()); + } + + @Test + void testHashcodeAndEquals() { + EqualsVerifier.forClass(GitTag.class) + .withNonnullFields("tag") + .verify(); + } + + @Test + void testNullTag() { + assertThrows(IllegalArgumentException.class, () -> GitTag.of(null)); + } + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/github/GitHubVersionProviderTest.java b/src/test/java/com/eternalcode/gitcheck/github/GitHubVersionProviderTest.java new file mode 100644 index 0000000..c69ebf1 --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/github/GitHubVersionProviderTest.java @@ -0,0 +1,47 @@ +package com.eternalcode.gitcheck.github; + +import com.eternalcode.gitcheck.git.GitException; +import com.eternalcode.gitcheck.git.GitRelease; +import com.eternalcode.gitcheck.git.GitRepository; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class GitHubVersionProviderTest { + + @Test + void testGetLatestRelease() { + GitHubReleaseProvider provider = new GitHubReleaseProvider(); + GitRelease release = provider.getLatestRelease(GitRepository.of("EternalCodeTeam", "ChatFormatter")); + + assertNotNull(release); + assertNotNull(release.getName()); + assertNotNull(release.getBranch()); + assertNotNull(release.getTag()); + assertNotNull(release.getPageUrl()); + assertNotNull(release.getPublishedAt()); + } + + @Test + void testGetLatestReleaseWithNonExistingRepository() { + this.assertThrowsReleaseFor(GitRepository.of("EternalCodeTeam", "-")); + } + + @Test + void testGetLatestReleaseWithNotReleasedRepository() { + this.assertThrowsReleaseFor(GitRepository.of("EternalCodeTeam", "EternalCore")); + } + + @Test + void testGetLatestReleaseWithInvalidRepository() { + this.assertThrowsReleaseFor(GitRepository.of(".", ".")); + } + + private void assertThrowsReleaseFor(GitRepository repository) { + GitHubReleaseProvider provider = new GitHubReleaseProvider(); + + assertThrows(GitException.class, () -> provider.getLatestRelease(repository)); + } + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/github/JSONUtilTest.java b/src/test/java/com/eternalcode/gitcheck/github/JSONUtilTest.java new file mode 100644 index 0000000..0003f31 --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/github/JSONUtilTest.java @@ -0,0 +1,48 @@ +package com.eternalcode.gitcheck.github; + +import com.eternalcode.gitcheck.git.GitTag; +import org.json.simple.JSONObject; +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.util.NoSuchElementException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class JSONUtilTest { + + @Test + @SuppressWarnings("unchecked") + void testAsString() { + JSONObject jsonObject = new JSONObject(); + + jsonObject.put("text", "test"); + jsonObject.put("time", "2020-01-01T00:00:00Z"); + jsonObject.put("tag", "v1.0.0"); + + assertEquals("test", JSONUtil.asString(jsonObject, "text")); + assertEquals(Instant.parse("2020-01-01T00:00:00Z"), JSONUtil.asInstant(jsonObject, "time")); + assertEquals(GitTag.of("v1.0.0"), JSONUtil.asGitTag(jsonObject, "tag")); + } + + @Test + @SuppressWarnings("unchecked") + void testAsStringWithInvalidKey() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("text", "test"); + + assertThrows(NoSuchElementException.class, () -> JSONUtil.asString(jsonObject, "time")); + } + + @Test + @SuppressWarnings("unchecked") + void testAsStringWithInvalidType() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("text", 0); + + assertThrows(IllegalArgumentException.class, () -> JSONUtil.asString(jsonObject, "text")); + } + + +} \ No newline at end of file diff --git a/src/test/java/com/eternalcode/gitcheck/mock/MockGitReleaseProvider.java b/src/test/java/com/eternalcode/gitcheck/mock/MockGitReleaseProvider.java new file mode 100644 index 0000000..f411df6 --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/mock/MockGitReleaseProvider.java @@ -0,0 +1,23 @@ +package com.eternalcode.gitcheck.mock; + +import com.eternalcode.gitcheck.git.GitRelease; +import com.eternalcode.gitcheck.git.GitReleaseProvider; +import com.eternalcode.gitcheck.git.GitRepository; +import com.eternalcode.gitcheck.git.GitTag; + +import java.time.Instant; + +public class MockGitReleaseProvider implements GitReleaseProvider { + + @Override + public GitRelease getLatestRelease(GitRepository repository) { + return GitRelease.builder() + .name("GitCheck 1.0.0") + .branch("master") + .tag(GitTag.of("v1.0.0")) + .pageUrl("https://repo.eternalcode.pl/releases") + .publishedAt(Instant.parse("2020-01-01T00:00:00Z")) + .build(); + } + +} diff --git a/src/test/java/com/eternalcode/gitcheck/shared/PreconditionsTest.java b/src/test/java/com/eternalcode/gitcheck/shared/PreconditionsTest.java new file mode 100644 index 0000000..ab49e78 --- /dev/null +++ b/src/test/java/com/eternalcode/gitcheck/shared/PreconditionsTest.java @@ -0,0 +1,36 @@ +package com.eternalcode.gitcheck.shared; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PreconditionsTest { + + @Test + void testConstructor() throws NoSuchMethodException { + Constructor constructor = Preconditions.class.getDeclaredConstructor(); + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, constructor::newInstance); + } + + @Test + void testNotNull() { + assertDoesNotThrow(() -> Preconditions.notNull(new Object(), "test")); + assertThrows(IllegalArgumentException.class, () -> Preconditions.notNull(null, "test")); + } + + @Test + void testNotEmpty() { + assertDoesNotThrow(() -> Preconditions.notEmpty("test", "test")); + assertThrows(IllegalArgumentException.class, () -> Preconditions.notEmpty("", "test")); + } + +} \ No newline at end of file