diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3047333 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI +on: push +jobs: + build: + strategy: + matrix: + distribution: ['temurin'] + java-version: ['11', '16', '17', '18', '19'] + include: + - distribution: 'adopt' + java-version: '12' + - distribution: 'adopt' + java-version: '13' + - distribution: 'adopt' + java-version: '14' + - distribution: 'adopt' + java-version: '15' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: ${{ matrix.distribution }} + java-version: ${{ matrix.java-version }} + cache: maven + - run: mvn --batch-mode package + - uses: codecov/codecov-action@v2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..108e0cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Eclipse +.classpath +.project +.settings/ + +# Intellij +.idea/ +*.iml +*.iws + +# Mac +.DS_Store + +# Maven +log/ +target/ \ No newline at end of file diff --git a/.mvnchk-ignore b/.mvnchk-ignore new file mode 100644 index 0000000..ad6384e --- /dev/null +++ b/.mvnchk-ignore @@ -0,0 +1,6 @@ +commons-cli:commons-cli:20040117.000000 + +# FIXME NoSuchMethodError with maven-core:3.8.6 +org.apache.maven.resolver:maven-resolver-connector-basic:1.?.? +org.apache.maven.resolver:maven-resolver-transport-file:1.?.? +org.apache.maven.resolver:maven-resolver-transport-http:1.?.? \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..323a46a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +## 1.1.0 _(in progress)_ +… + +## 1.0.0 _(2022-12-23)_ +Initial release \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..7e663cd --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Alexis Jehan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4df80a7 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ + + +# Maven Check +[![release](https://img.shields.io/github/v/release/AlexisJehan/MavenCheck?display_name=tag)](https://github.com/AlexisJehan/MavenCheck/releases/latest) +[![build](https://img.shields.io/github/actions/workflow/status/AlexisJehan/MavenCheck/ci.yml?branch=main)](https://github.com/AlexisJehan/MavenCheck/actions/workflows/ci.yml) +[![coverage](https://img.shields.io/codecov/c/github/AlexisJehan/MavenCheck)](https://codecov.io/gh/AlexisJehan/MavenCheck) +[![license](https://img.shields.io/github/license/AlexisJehan/MavenCheck)](LICENSE.txt) + +A _Java 11+_ command line tool to check for artifact updates of _Maven_ and _Gradle_ projects. + +## Introduction +**Maven Check** aims to help developers to keep their projects up-to-date by checking for last available dependency and +plugin versions. Unlike some existing _Maven_ plugins, _Maven Check_ uses an advanced filtering system to choose the +most relevant update version for an artifact. + +### Features +- Standalone and portable +- Recursive build files lookup +- Compact and comprehensible output +- Smart filtering to exclude non-release versions +- Smart filtering to select versions with the same qualifier (if any) +- Possibility to filter specific artifacts or update versions using ignore files +- Use any already installed _Maven_ configuration and repository +- Use any already installed _Gradle_ installation if available, or download a wrapper distribution + +## Getting started + +### Prerequisites +_Maven Check_ is running on most operating systems, it only requires _Java 11_ or higher to be installed. + +You can check that _Java_ is available in your environment and its version using the following command: +```console +java -version +``` + +### Installation +You can download binaries for the latest version of _Maven Check_ on the +[release](https://github.com/AlexisJehan/MavenCheck/releases/latest) page. + +#### Linux / Mac +Execute following commands in the folder where the downloaded archive file is +located: +```console +sudo tar -xvzf maven-check-1.0.0-bin.tar.gz --directory /opt +export PATH=$PATH:/opt/maven-check-1.0.0/bin +``` + +#### Windows +Extract the content of the downloaded archive file and move the extracted folder to `C:\maven-check-1.0.0`, then: +- Right-click on the _Windows_ icon and select "System" +- On the right, click on "Advanced system settings" +- In the new window, click on "Environment Variables..." +- Find the "Path" variable, choose "Edit", and add `;C:\maven-check-1.0.0\bin` at the end + +### Verify +If _Maven Check_ is correctly installed, this command should work as expected: +```console +mvnchk --version +``` + +## Usage +``` +usage: mvnchk [] [-h] [-i] [-s] [-v] + -h,--help Display help information + -i,--ignore-snapshots Ignore build file artifacts with a snapshot + version + -s,--short Only show build files with at least one artifact + update + -v,--version Display version information +``` + +## Ignore file +_Maven Check_ allows to ignore artifacts or update versions by having a `.mvnchk-ignore` file: +- globally in the user home +- specifically in a project directory. + +Here is an example of how to write it: +``` +# Ignore a specific artifact +com.google.guava:guava + +# Ignore a specific artifact update version +com.google.guava:guava:30.0-android + +# Ignore artifact update versions using the "any characters" wildcard +com.google.guava:guava:*-android + +# Ignore artifact update versions using the "any single character" wildcard +com.google.guava:guava:30.?-android +``` + +## Compatibility matrix +The table below shows which version of _Maven_ and _Gradle_ is used by each _Maven Check_ release. However, a higher +version of a build tool may still be compatible. + +| Maven Check | Maven version | Gradle version | +|:-----------:|:-------------:|:--------------:| +| 1.0.0 | 3.8.6 | 7.6 | + +Note: _Gradle_ is compatible starting with _Gradle 4.8_. + +## License +This project is licensed under the [MIT License](LICENSE.txt). \ No newline at end of file diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..297d396 Binary files /dev/null and b/logo.png differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a71d2d8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,385 @@ + + + 4.0.0 + + com.github.alexisjehan + maven-check + 1.1.0-SNAPSHOT + + Maven Check + A Java 11+ command line tool to check for artifact updates of Maven and Gradle projects. + https://github.com/AlexisJehan/MavenCheck + 2022 + + + MIT License + https://opensource.org/licenses/MIT + repo + + + + Alexis Jehan + https://github.com/AlexisJehan + + + + alexisjehan + Alexis Jehan + alexis.jehan@outlook.com + Alexis Jehan + https://github.com/AlexisJehan + + + + + scm:git:git@github.com:AlexisJehan/MavenCheck.git + scm:git:git@github.com:AlexisJehan/MavenCheck.git + https://github.com/AlexisJehan/MavenCheck + + + GitHub Issues + https://github.com/AlexisJehan/MavenCheck/issues + + + GitHub Actions + https://github.com/AlexisJehan/MavenCheck/actions + + + + 11 + 11 + 11 + true + true + false + false + UTF-8 + UTF-8 + + + + + gradle-releases + Gradle Releases + https://repo.gradle.org/gradle/libs-releases + + + + + + com.github.alexisjehan + javanilla + 1.8.0 + + + + org.apache.maven + maven-core + 3.8.6 + + + org.apache.maven.resolver + maven-resolver-connector-basic + 1.7.3 + + + org.apache.maven.resolver + maven-resolver-transport-file + 1.7.3 + + + org.apache.maven.resolver + maven-resolver-transport-http + 1.7.3 + + + org.gradle + gradle-tooling-api + 7.6 + + + commons-cli + commons-cli + 1.5.0 + + + org.fusesource.jansi + jansi + 2.4.0 + + + org.apache.logging.log4j + log4j-api + 2.19.0 + + + org.apache.logging.log4j + log4j-core + 2.19.0 + runtime + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.19.0 + runtime + + + + org.junit.jupiter + junit-jupiter + 5.9.1 + test + + + org.assertj + assertj-core + 3.23.1 + test + + + org.mockito + mockito-inline + 4.10.0 + test + + + org.mockito + mockito-junit-jupiter + 4.10.0 + test + + + + + + + src/main/resources + + + ${project.basedir} + + LICENSE.txt + + + + + + src/test/resources + + + ${project.basedir} + + LICENSE.txt + + + + + + com.mycila + license-maven-plugin + 4.1 + +
LICENSE.txt
+ + src/**/*.java + + + SLASHSTAR_STYLE + +
+ + + license-check + validate + + check + + + +
+ + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + + -Xlint:all + -Xlint:-processing + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.22.2 + + ${project.build.outputDirectory} + + + + failsafe-integration-test + + integration-test + + + + failsafe-verify + + verify + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + jacoco-prepare-agent + test-compile + + prepare-agent + + + + jacoco-report + test + + report + + + + jacoco-prepare-agent-integration + + prepare-agent-integration + + + + jacoco-report-integration + post-integration-test + + report-integration + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + true + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + source-jar + + jar-no-fork + test-jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.4.1 + + -html5 + + + + javadoc-jar + + jar + + + + + + org.codehaus.mojo + appassembler-maven-plugin + 2.1.0 + + + + mvnchk + com.github.alexisjehan.mavencheck.Application + LICENSE.txt + + + + unix + windows + + + .cmd + + conf + src/main/resources + true + lib + flat + true + + + + appassembler-assemble + + assemble + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.4.2 + + + src/main/assembly/bin.xml + + ${maven.build.timestamp} + + + + assembly-single + package + + single + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + gpg-sign + + sign + + + + +
+
+
\ No newline at end of file diff --git a/src/main/assembly/bin.xml b/src/main/assembly/bin.xml new file mode 100644 index 0000000..c0acf81 --- /dev/null +++ b/src/main/assembly/bin.xml @@ -0,0 +1,28 @@ + + + bin + + tar.gz + zip + + + + ${project.build.directory}/appassembler/bin + bin + 0755 + + + ${project.build.directory}/appassembler/conf + conf + + + ${project.build.directory}/appassembler/lib + lib + + + + LICENSE.txt + + + + \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/Application.java b/src/main/java/com/github/alexisjehan/mavencheck/Application.java new file mode 100644 index 0000000..06e76c5 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/Application.java @@ -0,0 +1,380 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck; + +import com.github.alexisjehan.javanilla.lang.Throwables; +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.mavencheck.core.Service; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.ArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.Build; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.build.resolver.BuildResolveException; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import com.github.alexisjehan.mavencheck.core.util.GradleUtils; +import com.github.alexisjehan.mavencheck.core.util.MavenUtils; +import internal.ExcludeFromJacocoGeneratedReport; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.AnsiConsole; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.lang.invoke.MethodHandles; +import java.nio.file.Path; + +/** + *

Class that describes the application.

+ * @since 1.0.0 + */ +public final class Application { + + /** + *

Name.

+ * @since 1.0.0 + */ + private static final String NAME = MethodHandles.lookup().lookupClass().getPackage().getImplementationTitle(); + + /** + *

Version.

+ * @since 1.0.0 + */ + private static final String VERSION = MethodHandles.lookup().lookupClass().getPackage().getImplementationVersion() + + " (built with Maven " + MavenUtils.getVersion() + " and Gradle " + GradleUtils.getVersion() + ")"; + + /** + *

Description.

+ * @since 1.0.0 + */ + private static final String DESCRIPTION = "Check for artifact updates of every " + + ToString.toString(BuildFileType.MAVEN.getFileName()) + ", " + + ToString.toString(BuildFileType.GRADLE_GROOVY.getFileName()) + " and " + + ToString.toString(BuildFileType.GRADLE_KOTLIN.getFileName()) + " build files in the given or current " + + "path recursively."; + + /** + *

Command name.

+ * @since 1.0.0 + */ + private static final String COMMAND_NAME = "mvnchk"; + + /** + *

Help option long name.

+ * @since 1.0.0 + */ + private static final String OPTION_HELP = "help"; + + /** + *

Ignore snapshots option long name.

+ * @since 1.0.0 + */ + private static final String OPTION_IGNORE_SNAPSHOTS = "ignore-snapshots"; + + /** + *

Short option long name.

+ * @since 1.0.0 + */ + private static final String OPTION_SHORT = "short"; + + /** + *

Version option long name.

+ * @since 1.0.0 + */ + private static final String OPTION_VERSION = "version"; + + /** + *

Default value depending on whether ANSI should be enabled or not.

+ * @since 1.0.0 + */ + private static final boolean DEFAULT_ANSI = false; + + /** + *

Default path, current directory.

+ * @since 1.0.0 + */ + private static final Path DEFAULT_PATH = Path.of("."); + + /** + *

Options.

+ * @since 1.0.0 + */ + private static final Options options = new Options(); + + static { + options.addOption( + "h", + OPTION_HELP, + false, + "Display help information" + ); + options.addOption( + "i", + OPTION_IGNORE_SNAPSHOTS, + false, + "Ignore build file artifacts with a snapshot version" + ); + options.addOption( + "s", + OPTION_SHORT, + false, + "Only show build files with at least one artifact update" + ); + options.addOption( + "v", + OPTION_VERSION, + false, + "Display version information" + ); + } + + /** + *

Standard output {@link PrintStream}.

+ * @since 1.0.0 + */ + private final PrintStream outputStream; + + /** + *

Error output {@link PrintStream}.

+ * @since 1.0.0 + */ + private final PrintStream errorStream; + + /** + *

Constructor with a single {@link PrintStream} for standard and error outputs.

+ * @param printStream a {@link PrintStream} + * @throws NullPointerException if the {@link PrintStream} is {@code null} + * @since 1.0.0 + */ + Application(final PrintStream printStream) { + this(printStream, printStream, DEFAULT_ANSI); + } + + /** + *

Constructor with distinct {@link PrintStream}s for standard and error outputs.

+ * @param outputStream a standard output {@link PrintStream} + * @param errorStream an error output {@link PrintStream} + * @param ansi {@code true} if ANSI should be enabled + * @throws NullPointerException if the standard output {@link PrintStream} or the error output {@link PrintStream} + * is {@code null} + * @since 1.0.0 + */ + Application(final PrintStream outputStream, final PrintStream errorStream, final boolean ansi) { + Ensure.notNull("outputStream", outputStream); + Ensure.notNull("errorStream", errorStream); + this.outputStream = outputStream; + this.errorStream = errorStream; + Ansi.setEnabled(ansi); + } + + /** + *

Run the command-line interface.

+ * @param args an array of arguments + * @throws NullPointerException if the array of arguments or any of them is {@code null} + * @since 1.0.0 + */ + void run(final String... args) { + Ensure.notNullAndNotNullElements("args", args); + try { + final var commandLine = new DefaultParser().parse(options, args, false); + if (commandLine.hasOption(OPTION_VERSION) || commandLine.hasOption(OPTION_HELP)) { + outputStream.println(NAME + " " + VERSION); + if (commandLine.hasOption(OPTION_HELP)) { + outputStream.println(); + outputStream.println(DESCRIPTION); + outputStream.println(); + try (final var writer = new PrintWriter(outputStream)) { + final var helpFormatter = new HelpFormatter(); + helpFormatter.printHelp( + writer, + helpFormatter.getWidth(), + COMMAND_NAME + " []", + null, + options, + helpFormatter.getLeftPadding(), + helpFormatter.getDescPadding(), + null, + true + ); + } + } + } else { + final var arguments = commandLine.getArgs(); + run( + 1 == arguments.length + ? Path.of(arguments[0]) + : DEFAULT_PATH, + commandLine.hasOption(OPTION_IGNORE_SNAPSHOTS), + commandLine.hasOption(OPTION_SHORT) + ); + } + } catch (final Exception e) { + errorStream.println(Ansi.ansi().fgBrightRed().a(toString(e)).reset()); + } + } + + /** + *

Run the program.

+ * @param path a path + * @param ignoreSnapshots {@code true} if build file artifacts with a snapshot version should be ignored + * @param short0 {@code true} if only build files with at least one artifact update should be shown + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the path is {@code null} + * @since 1.0.0 + */ + void run(final Path path, final boolean ignoreSnapshots, final boolean short0) throws IOException { + Ensure.notNull("path", path); + final var service = createService(); + final var buildFiles = service.findBuildFiles(path); + if (buildFiles.isEmpty()) { + outputStream.println("No build file found"); + return; + } + outputStream.println(buildFiles.size() + " build file(s) found, checking for artifact updates"); + outputStream.println(); + var buildsCount = 0; + var artifactsUpdatesCount = 0; + for (final var buildFile : buildFiles) { + final var file = buildFile.getFile(); + final Build build; + try { + build = service.findBuild(buildFile); + } catch (final BuildResolveException e) { + outputStream.println(Ansi.ansi().fgBrightRed().a(toString(file)).reset()); + outputStream.println(Ansi.ansi().fgBrightRed().a(toString(e)).reset()); + outputStream.println(); + continue; + } + final var artifactUpdateVersions = service.findArtifactUpdateVersions(build, ignoreSnapshots); + if (artifactUpdateVersions.isEmpty()) { + if (!short0) { + outputStream.println(Ansi.ansi().fgBrightGreen().a(toString(file)).reset()); + outputStream.println("No artifact update available"); + outputStream.println(); + } + } else { + outputStream.println(Ansi.ansi().fgBrightYellow().a(toString(file)).reset()); + for (final var artifactUpdateVersion : artifactUpdateVersions) { + final var artifact = artifactUpdateVersion.getArtifact(); + final var updateVersion = artifactUpdateVersion.getUpdateVersion(); + outputStream.println( + Ansi.ansi() + .a("[") + .fgBrightBlue().a(toString(artifact.getType())).reset() + .a("] ") + .a(toString(artifact.getIdentifier())) + .a(" ") + .fgBrightYellow().a(artifact.getOptionalVersion().orElseThrow()).reset() + .a(" -> ") + .fgBrightGreen().a(updateVersion).reset() + ); + ++artifactsUpdatesCount; + } + outputStream.println(artifactUpdateVersions.size() + " artifact update(s) available"); + outputStream.println(); + } + ++buildsCount; + } + outputStream.println( + buildsCount + "/" + buildFiles.size() + " build file(s) checked, " + ( + 0 == artifactsUpdatesCount + ? "no artifact update available" + : artifactsUpdatesCount + " artifact update(s) available" + ) + ); + } + + /** + *

Create a service.

+ * @return the service + * @throws IOException might occur with input/output operations + * @since 1.0.0 + */ + static Service createService() throws IOException { + return new Service(new MavenSession()); + } + + /** + *

Convert an {@link Exception} to a {@link String}.

+ * @param exception an {@link Exception} + * @return the {@link String} + * @throws NullPointerException if the {@link Exception} is {@code null} + * @since 1.0.0 + */ + static String toString(final Exception exception) { + Ensure.notNull("exception", exception); + return Throwables.getOptionalRootCause(exception).orElse(exception).getMessage().trim(); + } + + /** + *

Convert a file to a {@link String}.

+ * @param file a file + * @return the {@link String} + * @throws NullPointerException if the file is {@code null} + * @since 1.0.0 + */ + static String toString(final Path file) { + Ensure.notNull("file", file); + return file.normalize().toString(); + } + + /** + *

Convert an artifact type to a {@link String}.

+ * @param artifactType an artifact type + * @return the {@link String} + * @throws NullPointerException if the artifact type is {@code null} + * @since 1.0.0 + */ + static String toString(final ArtifactType artifactType) { + Ensure.notNull("artifactType", artifactType); + return artifactType.toString().replace('_', ' '); + } + + /** + *

Convert an artifact identifier to a {@link String}.

+ * @param artifactIdentifier an artifact identifier + * @return the {@link String} + * @throws NullPointerException if the artifact identifier is {@code null} + * @since 1.0.0 + */ + static String toString(final ArtifactIdentifier artifactIdentifier) { + Ensure.notNull("artifactIdentifier", artifactIdentifier); + return artifactIdentifier.getGroupId() + ":" + artifactIdentifier.getArtifactId(); + } + + /** + *

Main entrance.

+ * @param args an array of arguments + * @since 1.0.0 + */ + @ExcludeFromJacocoGeneratedReport + public static void main(final String... args) { + AnsiConsole.systemInstall(); + new Application(AnsiConsole.out(), AnsiConsole.err(), true).run(args); + AnsiConsole.systemUninstall(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/Service.java b/src/main/java/com/github/alexisjehan/mavencheck/core/Service.java new file mode 100644 index 0000000..ff3eda2 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/Service.java @@ -0,0 +1,259 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.util.Comparators; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactUpdateVersion; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver.ArtifactAvailableVersionsResolver; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver.MavenArtifactAvailableVersionsResolver; +import com.github.alexisjehan.mavencheck.core.component.build.Build; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.build.resolver.BuildResolver; +import com.github.alexisjehan.mavencheck.core.component.build.resolver.GradleBuildResolver; +import com.github.alexisjehan.mavencheck.core.component.build.resolver.MavenBuildResolver; +import com.github.alexisjehan.mavencheck.core.component.filter.artifact.ArtifactFilter; +import com.github.alexisjehan.mavencheck.core.component.filter.artifact.CompositeArtifactFilter; +import com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser.ArtifactFilterParser; +import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter; +import com.github.alexisjehan.mavencheck.core.component.filter.version.factory.CompositeVersionFilterFactory; +import com.github.alexisjehan.mavencheck.core.component.filter.version.factory.QualifierVersionFilterFactory; +import com.github.alexisjehan.mavencheck.core.component.filter.version.factory.ReleaseVersionFilterFactory; +import com.github.alexisjehan.mavencheck.core.component.filter.version.factory.VersionFilterFactory; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import com.github.alexisjehan.mavencheck.core.util.SystemUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

Class that describes the service.

+ * @since 1.0.0 + */ +public final class Service { + + /** + *

Ignore file name.

+ * @since 1.0.0 + */ + private static final String IGNORE_FILE_NAME = ".mvnchk-ignore"; + + /** + *

{@link Set} of build resolvers.

+ * @since 1.0.0 + */ + private final Set buildResolvers; + + /** + *

Artifact available versions resolver.

+ * @since 1.0.0 + */ + private final ArtifactAvailableVersionsResolver artifactAvailableVersionsResolver; + + /** + *

Version filter factory.

+ * @since 1.0.0 + */ + private final VersionFilterFactory versionFilterFactory = new CompositeVersionFilterFactory( + QualifierVersionFilterFactory.INSTANCE, + ReleaseVersionFilterFactory.INSTANCE + ); + + /** + *

User artifact filter.

+ * @since 1.0.0 + */ + private final ArtifactFilter userArtifactFilter; + + /** + *

Constructor with a Maven session.

+ * @param mavenSession a Maven session + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the Maven session is {@code null} + * @since 1.0.0 + */ + public Service(final MavenSession mavenSession) throws IOException { + this( + Set.of( + new MavenBuildResolver(Ensure.notNull("mavenSession", mavenSession)), + new GradleBuildResolver() + ), + new MavenArtifactAvailableVersionsResolver(mavenSession) + ); + } + + /** + *

Constructor with a {@link Set} of build resolvers and an artifact available versions resolver.

+ * @param buildResolvers a {@link Set} of build resolvers + * @param artifactAvailableVersionsResolver an artifact available versions resolver + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the {@link Set} of build resolvers, any of them or the artifact available + * versions resolver is {@code null} + * @since 1.0.0 + */ + Service( + final Set buildResolvers, + final ArtifactAvailableVersionsResolver artifactAvailableVersionsResolver + ) throws IOException { + Ensure.notNullAndNotNullElements("buildResolvers", buildResolvers); + Ensure.notNull("artifactAvailableVersionsResolver", artifactAvailableVersionsResolver); + this.buildResolvers = Set.copyOf(buildResolvers); + this.artifactAvailableVersionsResolver = artifactAvailableVersionsResolver; + userArtifactFilter = createUserArtifactFilter(); + } + + /** + *

Find a {@link List} of build files in the given path, recursively.

+ * @param path a path + * @return the {@link List} of build files + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the path is {@code null} + * @throws IllegalArgumentException if the path does not exist + * @since 1.0.0 + */ + public List findBuildFiles(final Path path) throws IOException { + Ensure.notNullAndExists("path", path); + try (final var stream = Files.walk(path)) { + return stream + .filter(Files::isRegularFile) + .map(file -> { + final var fileName = file.getFileName().toString(); + return BuildFileType.optionalValueOf(fileName).map(type -> new BuildFile(type, file)); + }) + .flatMap(Optional::stream) + .sorted( + Comparator + .comparing( + buildFile -> buildFile.getFile().getParent().toString(), + Comparators.NUMBER_AWARE + ) + .thenComparing( + buildFile -> buildFile.getFile().getFileName().toString(), + Comparators.NUMBER_AWARE + ) + ) + .collect(Collectors.toUnmodifiableList()); + } + } + + /** + *

Find the build for the given build file.

+ * @param buildFile a build file + * @return the build + * @throws NullPointerException if the build file is {@code null} + * @since 1.0.0 + */ + public Build findBuild(final BuildFile buildFile) { + Ensure.notNull("buildFile", buildFile); + return buildResolvers.stream() + .filter(buildResolver -> buildResolver.getFileTypes().contains(buildFile.getType())) + .findAny() + .map(buildResolver -> buildResolver.resolve(buildFile)) + .orElseThrow(); + } + + /** + *

Find a {@link List} of artifact update versions for the given build.

+ * @param build a build + * @param ignoreSnapshots {@code true} if build file artifacts with a snapshot version should be ignored + * @return the {@link List} of artifact update versions + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the build is {@code null} + * @since 1.0.0 + */ + public List findArtifactUpdateVersions( + final Build build, + final boolean ignoreSnapshots + ) throws IOException { + Ensure.notNull("build", build); + final var artifactFilter = new CompositeArtifactFilter( + userArtifactFilter, + createBuildArtifactFilter(build.getFile()) + ); + return build.getArtifacts() + .parallelStream() + .filter(artifactFilter::accept) + .filter( + artifact -> artifact.getOptionalVersion() + .filter(version -> !ignoreSnapshots || !VersionFilter.SNAPSHOT.accept(version)) + .isPresent() + ) + .map(artifact -> artifactAvailableVersionsResolver.resolve(artifact, build.getRepositories())) + .map(artifactAvailableVersions -> { + final var artifact = artifactAvailableVersions.getArtifact(); + final var artifactVersion = artifact.getOptionalVersion().orElseThrow(); + final var availableVersions = new ArrayList<>(artifactAvailableVersions.getAvailableVersions()); + if (availableVersions.isEmpty()) { + return Optional.empty(); + } + Collections.reverse(availableVersions); + return availableVersions.stream() + .filter(updateVersion -> artifactFilter.accept(artifact, updateVersion)) + .filter(versionFilterFactory.create(artifactVersion)::accept) + .findAny() + .filter(updateVersion -> !artifactVersion.equals(updateVersion)) + .map(updateVersion -> new ArtifactUpdateVersion(artifact, updateVersion)); + }) + .flatMap(Optional::stream) + .collect(Collectors.toUnmodifiableList()); + } + + /** + *

Create the user artifact filter.

+ * @return the user artifact filter + * @throws IOException might occur with input/output operations + * @since 1.0.0 + */ + static ArtifactFilter createUserArtifactFilter() throws IOException { + final var userIgnoreFile = SystemUtils.getUserHomeDirectory().resolve(IGNORE_FILE_NAME); + return Files.isRegularFile(userIgnoreFile) + ? ArtifactFilterParser.parse(userIgnoreFile) + : ArtifactFilter.NONE; + } + + /** + *

Create the build artifact filter for the given build file.

+ * @param buildFile a build file + * @return the build artifact filter + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the build file is {@code null} + * @since 1.0.0 + */ + static ArtifactFilter createBuildArtifactFilter(final BuildFile buildFile) throws IOException { + Ensure.notNull("buildFile", buildFile); + final var buildIgnoreFile = buildFile.getFile().getParent().resolve(IGNORE_FILE_NAME); + return Files.isRegularFile(buildIgnoreFile) + ? ArtifactFilterParser.parse(buildIgnoreFile) + : ArtifactFilter.NONE; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/Artifact.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/Artifact.java new file mode 100644 index 0000000..fcb2e96 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/Artifact.java @@ -0,0 +1,170 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.ArtifactType; + +import java.util.Optional; + +/** + *

Class that describes an artifact.

+ * @param the type + * @since 1.0.0 + */ +public final class Artifact { + + /** + *

Type.

+ * @since 1.0.0 + */ + private final T type; + + /** + *

Identifier.

+ * @since 1.0.0 + */ + private final ArtifactIdentifier identifier; + + /** + *

Version.

+ * @since 1.0.0 + */ + private final String version; + + /** + *

Constructor without a version.

+ * @param type a type + * @param identifier an identifier + * @throws NullPointerException if the type or the identifier is {@code null} + * @since 1.0.0 + */ + public Artifact(final T type, final ArtifactIdentifier identifier) { + this(type, identifier, null); + } + + /** + *

Constructor with a version.

+ * @param type a type + * @param identifier an identifier + * @param version a version or {@code null} + * @throws NullPointerException if the type or the identifier is {@code null} + * @since 1.0.0 + */ + public Artifact(final T type, final ArtifactIdentifier identifier, final String version) { + Ensure.notNull("type", type); + Ensure.notNull("identifier", identifier); + this.type = type; + this.identifier = identifier; + this.version = version; + } + + /** + *

Return a copy of the current artifact with the given type.

+ * @param type a type + * @return the copy of the current artifact + * @throws NullPointerException if the type is {@code null} + * @since 1.0.0 + */ + public Artifact with(final T type) { + Ensure.notNull("type", type); + return new Artifact<>(type, identifier, version); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof Artifact)) { + return false; + } + final var other = (Artifact) object; + return Equals.equals(type, other.type) + && Equals.equals(identifier, other.identifier) + && Equals.equals(version, other.version); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(type), + HashCode.hashCode(identifier), + HashCode.hashCode(version) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("type", ToString.toString(type)), + Pair.of("identifier", ToString.toString(identifier)), + Pair.of("version", ToString.toString(version)) + ); + } + + /** + *

Get the type.

+ * @return the type + * @since 1.0.0 + */ + public T getType() { + return type; + } + + /** + *

Get the identifier.

+ * @return the identifier + * @since 1.0.0 + */ + public ArtifactIdentifier getIdentifier() { + return identifier; + } + + /** + *

Get an {@link Optional} of the version.

+ * @return the {@link Optional} of the version + * @since 1.0.0 + */ + public Optional getOptionalVersion() { + return Optional.ofNullable(version); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifier.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifier.java new file mode 100644 index 0000000..b194796 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifier.java @@ -0,0 +1,124 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; + +/** + *

Class that describes an artifact identifier.

+ * @since 1.0.0 + */ +public final class ArtifactIdentifier { + + /** + *

Group identifier.

+ * @since 1.0.0 + */ + private final String groupId; + + /** + *

Artifact identifier.

+ * @since 1.0.0 + */ + private final String artifactId; + + /** + *

Constructor.

+ * @param groupId a group identifier + * @param artifactId an artifact identifier + * @throws NullPointerException if the group identifier or the artifact identifier is {@code null} + * @throws IllegalArgumentException if the group identifier or the artifact identifier is empty + * @since 1.0.0 + */ + public ArtifactIdentifier(final String groupId, final String artifactId) { + Ensure.notNullAndNotEmpty("groupId", groupId); + Ensure.notNullAndNotEmpty("artifactId", artifactId); + this.groupId = groupId; + this.artifactId = artifactId; + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof ArtifactIdentifier)) { + return false; + } + final var other = (ArtifactIdentifier) object; + return Equals.equals(groupId, other.groupId) + && Equals.equals(artifactId, other.artifactId); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(groupId), + HashCode.hashCode(artifactId) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("groupId", ToString.toString(groupId)), + Pair.of("artifactId", ToString.toString(artifactId)) + ); + } + + /** + *

Get the group identifier.

+ * @return the group identifier + * @since 1.0.0 + */ + public String getGroupId() { + return groupId; + } + + /** + *

Get the artifact identifier.

+ * @return the artifact identifier + * @since 1.0.0 + */ + public String getArtifactId() { + return artifactId; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/package-info.java new file mode 100644 index 0000000..caa51ac --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Artifact components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.artifact; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/ArtifactType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/ArtifactType.java new file mode 100644 index 0000000..eb09ca6 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/ArtifactType.java @@ -0,0 +1,42 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.type; + +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; + +/** + *

Interface that describes an artifact type.

+ * @since 1.0.0 + */ +public interface ArtifactType { + + /** + *

Get the repository type.

+ * @return the repository type + * @since 1.0.0 + */ + default RepositoryType getRepositoryType() { + return RepositoryType.NORMAL; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactType.java new file mode 100644 index 0000000..ee9134a --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactType.java @@ -0,0 +1,218 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.type; + +import com.github.alexisjehan.javanilla.misc.CaseStyle; + +import java.util.Set; + +/** + *

Enumeration of Gradle artifact types.

+ *

Note: Based on {@code org.gradle:gradle-tooling-api:7.6}.

+ * @see https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management + * @see https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph + * @since 1.0.0 + */ +public enum GradleArtifactType implements ArtifactType { + + /** + *

Annotation processors and their dependency artifacts.

+ *

Note: Added since Gradle 4.6.

+ * @since 1.0.0 + */ + ANNOTATION_PROCESSOR, + + /** + *

API dependency artifacts.

+ * @since 1.0.0 + */ + API, + + /** + *

Dependency artifacts.

+ *

Note: Deprecated since Gradle 4.7.

+ *

Note: Removed since Gradle 7.0 (Superseded by {@link IMPLEMENTATION}).

+ * @since 1.0.0 + */ + COMPILE(Property.DEPRECATED), + + /** + *

Compile classpath artifacts.

+ * @since 1.0.0 + */ + COMPILE_CLASSPATH(Property.CLASSPATH), + + /** + *

Compile only dependency artifacts.

+ * @since 1.0.0 + */ + COMPILE_ONLY, + + /** + *

Compile only API dependency artifacts.

+ *

Note: Added since Gradle 6.7.

+ * @since 1.0.0 + */ + COMPILE_ONLY_API, + + /** + *

Implementation only dependency artifacts.

+ * @since 1.0.0 + */ + IMPLEMENTATION, + + /** + *

Runtime dependency artifacts.

+ *

Note: Deprecated since Gradle 4.7.

+ *

Note: Removed since Gradle 7.0 (Superseded by {@link RUNTIME_ONLY}).

+ * @since 1.0.0 + */ + RUNTIME(Property.DEPRECATED), + + /** + *

Runtime classpath artifacts.

+ * @since 1.0.0 + */ + RUNTIME_CLASSPATH(Property.CLASSPATH), + + /** + *

Runtime only dependency artifacts.

+ * @since 1.0.0 + */ + RUNTIME_ONLY, + + /** + *

Test annotation processors and their dependency artifacts.

+ *

Note: Added since Gradle 4.6.

+ * @since 1.0.0 + */ + TEST_ANNOTATION_PROCESSOR, + + /** + *

Test dependency artifacts.

+ *

Note: Deprecated since Gradle 4.7.

+ *

Note: Removed since Gradle 7.0 (Superseded by {@link TEST_IMPLEMENTATION}).

+ * @since 1.0.0 + */ + TEST_COMPILE(Property.DEPRECATED), + + /** + *

Test compile classpath artifacts.

+ * @since 1.0.0 + */ + TEST_COMPILE_CLASSPATH(Property.CLASSPATH), + + /** + *

Test compile only dependency artifacts.

+ * @since 1.0.0 + */ + TEST_COMPILE_ONLY, + + /** + *

Test implementation only dependency artifacts.

+ * @since 1.0.0 + */ + TEST_IMPLEMENTATION, + + /** + *

Test runtime dependency artifacts.

+ *

Note: Deprecated since Gradle 4.7.

+ *

Note: Removed since Gradle 7.0 (Superseded by {@link TEST_RUNTIME_ONLY}).

+ * @since 1.0.0 + */ + TEST_RUNTIME(Property.DEPRECATED), + + /** + *

Test runtime classpath artifacts.

+ * @since 1.0.0 + */ + TEST_RUNTIME_CLASSPATH(Property.CLASSPATH), + + /** + *

Test runtime only dependency artifacts.

+ * @since 1.0.0 + */ + TEST_RUNTIME_ONLY; + + /** + *

Enumeration of properties.

+ * @since 1.0.0 + */ + private enum Property { + + /** + *

Flagged as a classpath artifact type.

+ * @since 1.0.0 + */ + CLASSPATH, + + /** + *

Flagged as a deprecated artifact type.

+ * @since 1.0.0 + */ + DEPRECATED + } + + /** + *

{@link Set} of properties.

+ * @since 1.0.0 + */ + private final Set properties; + + /** + *

Constructor.

+ * @param properties an array of properties + * @since 1.0.0 + */ + GradleArtifactType(final Property... properties) { + this.properties = Set.of(properties); + } + + /** + *

Return the name printed by the Gradle {@code :dependencies} task.

+ * @return the name + * @since 1.0.0 + */ + public final String dependenciesTaskName() { + return CaseStyle.CAMEL.of(name(), CaseStyle.MACRO); + } + + /** + *

Get if this is a classpath artifact type.

+ * @return {@code true} if this is a classpath artifact type + * @since 1.0.0 + */ + public final boolean isClasspath() { + return properties.contains(Property.CLASSPATH); + } + + /** + *

Get if this is a deprecated artifact type.

+ * @return {@code true} if this is a deprecated artifact type + * @since 1.0.0 + */ + public final boolean isDeprecated() { + return properties.contains(Property.DEPRECATED); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactType.java new file mode 100644 index 0000000..a79840f --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactType.java @@ -0,0 +1,171 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.type; + +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; + +/** + *

Enumeration of Maven artifact types.

+ *

Note: Based on {@code org.apache.maven:maven-core:3.8.6}.

+ * @see https://maven.apache.org/ref/current/maven-model/maven.html + * @since 1.0.0 + */ +public enum MavenArtifactType implements ArtifactType { + + /** + *

The parent artifact.

+ * @since 1.0.0 + */ + PARENT, + + /** + *

Dependency management dependency artifacts.

+ * @since 1.0.0 + */ + DEPENDENCY_MANAGEMENT_DEPENDENCY, + + /** + *

Dependency artifacts.

+ * @since 1.0.0 + */ + DEPENDENCY, + + /** + *

Build extension artifacts.

+ * @since 1.0.0 + */ + BUILD_EXTENSION, + + /** + *

Build plugin management plugin artifacts.

+ * @since 1.0.0 + */ + BUILD_PLUGIN_MANAGEMENT_PLUGIN(true), + + /** + *

Build plugin management plugin dependency artifacts.

+ * @since 1.0.0 + */ + BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY, + + /** + *

Build plugin artifacts.

+ * @since 1.0.0 + */ + BUILD_PLUGIN(true), + + /** + *

Build plugin dependency artifacts.

+ * @since 1.0.0 + */ + BUILD_PLUGIN_DEPENDENCY, + + /** + *

Reporting plugin artifacts.

+ * @since 1.0.0 + */ + REPORTING_PLUGIN(true), + + /** + *

Profile build plugin management plugin artifacts.

+ * @since 1.0.0 + */ + PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN(true), + + /** + *

Profile build plugin management plugin dependency artifacts.

+ * @since 1.0.0 + */ + PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY, + + /** + *

Profile build plugin artifacts.

+ * @since 1.0.0 + */ + PROFILE_BUILD_PLUGIN(true), + + /** + *

Profile build plugin dependency artifacts.

+ * @since 1.0.0 + */ + PROFILE_BUILD_PLUGIN_DEPENDENCY, + + /** + *

Profile dependency management dependency artifacts.

+ * @since 1.0.0 + */ + PROFILE_DEPENDENCY_MANAGEMENT_DEPENDENCY, + + /** + *

Profile dependency artifacts.

+ * @since 1.0.0 + */ + PROFILE_DEPENDENCY, + + /** + *

Profile reporting plugin artifacts.

+ * @since 1.0.0 + */ + PROFILE_REPORTING_PLUGIN(true); + + /** + *

Default value depending on whether any related artifact is a plugin or not.

+ * @since 1.0.0 + */ + private static final boolean DEFAULT_PLUGIN = false; + + /** + *

Repository type.

+ * @since 1.0.0 + */ + private final RepositoryType repositoryType; + + /** + *

Constructor by default.

+ * @since 1.0.0 + */ + MavenArtifactType() { + this(DEFAULT_PLUGIN); + } + + /** + *

Constructor depending on whether any related artifact is a plugin or not.

+ * @param plugin {@code true} if any related artifact is a plugin + * @since 1.0.0 + */ + MavenArtifactType(final boolean plugin) { + repositoryType = plugin + ? RepositoryType.PLUGIN + : RepositoryType.NORMAL; + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public final RepositoryType getRepositoryType() { + return repositoryType; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/package-info.java new file mode 100644 index 0000000..c599239 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Artifact type components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.type; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersions.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersions.java new file mode 100644 index 0000000..c49272b --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersions.java @@ -0,0 +1,127 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; + +import java.util.List; + +/** + *

Class that describes available versions for an artifact.

+ * @since 1.0.0 + */ +public final class ArtifactAvailableVersions { + + /** + *

Artifact.

+ * @since 1.0.0 + */ + private final Artifact artifact; + + /** + *

{@link List} of available versions.

+ * @since 1.0.0 + */ + private final List availableVersions; + + /** + *

Constructor.

+ * @param artifact an artifact + * @param availableVersions a {@link List} of available versions + * @throws NullPointerException if the artifact, the {@link List} of available versions or any of them is + * {@code null} + * @since 1.0.0 + */ + public ArtifactAvailableVersions(final Artifact artifact, final List availableVersions) { + Ensure.notNull("artifact", artifact); + Ensure.notNullAndNotNullElements("availableVersions", availableVersions); + this.artifact = artifact; + this.availableVersions = List.copyOf(availableVersions); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof ArtifactAvailableVersions)) { + return false; + } + final var other = (ArtifactAvailableVersions) object; + return Equals.equals(artifact, other.artifact) + && Equals.equals(availableVersions, other.availableVersions); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(artifact), + HashCode.hashCode(availableVersions) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("artifact", ToString.toString(artifact)), + Pair.of("availableVersions", ToString.toString(availableVersions)) + ); + } + + /** + *

Get the artifact.

+ * @return the artifact + * @since 1.0.0 + */ + public Artifact getArtifact() { + return artifact; + } + + /** + *

Get the {@link List} of available versions.

+ * @return the {@link List} of available versions + * @since 1.0.0 + */ + public List getAvailableVersions() { + return availableVersions; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersion.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersion.java new file mode 100644 index 0000000..da1aa40 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersion.java @@ -0,0 +1,125 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; + +/** + *

Class that describes an update version for an artifact.

+ * @since 1.0.0 + */ +public final class ArtifactUpdateVersion { + + /** + *

Artifact.

+ * @since 1.0.0 + */ + private final Artifact artifact; + + /** + *

Update version.

+ * @since 1.0.0 + */ + private final String updateVersion; + + /** + *

Constructor.

+ * @param artifact an artifact + * @param updateVersion an update version + * @throws NullPointerException if the artifact or the update version is {@code null} + * @throws IllegalArgumentException if the update version is empty + * @since 1.0.0 + */ + public ArtifactUpdateVersion(final Artifact artifact, final String updateVersion) { + Ensure.notNull("artifact", artifact); + Ensure.notNullAndNotEmpty("updateVersion", updateVersion); + this.artifact = artifact; + this.updateVersion = updateVersion; + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof ArtifactUpdateVersion)) { + return false; + } + final var other = (ArtifactUpdateVersion) object; + return Equals.equals(artifact, other.artifact) + && Equals.equals(updateVersion, other.updateVersion); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(artifact), + HashCode.hashCode(updateVersion) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("artifact", ToString.toString(artifact)), + Pair.of("updateVersion", ToString.toString(updateVersion)) + ); + } + + /** + *

Get the artifact.

+ * @return the artifact + * @since 1.0.0 + */ + public Artifact getArtifact() { + return artifact; + } + + /** + *

Get the update version.

+ * @return the update version + * @since 1.0.0 + */ + public String getUpdateVersion() { + return updateVersion; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/package-info.java new file mode 100644 index 0000000..25327bd --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Artifact version components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/ArtifactAvailableVersionsResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/ArtifactAvailableVersionsResolver.java new file mode 100644 index 0000000..31940c4 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/ArtifactAvailableVersionsResolver.java @@ -0,0 +1,47 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; + +import java.util.List; + +/** + *

Interface that describes a resolver of available versions for an artifact.

+ * @since 1.0.0 + */ +@FunctionalInterface +public interface ArtifactAvailableVersionsResolver { + + /** + *

Resolve available versions for an artifact.

+ * @param artifact an artifact + * @param repositories a {@link List} of repositories + * @return available versions + * @since 1.0.0 + */ + ArtifactAvailableVersions resolve(final Artifact artifact, final List repositories); +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolver.java new file mode 100644 index 0000000..297b916 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolver.java @@ -0,0 +1,128 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import com.github.alexisjehan.mavencheck.core.util.MavenUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.version.Version; + +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

Class that describes a Maven resolver of available versions for an artifact.

+ * @since 1.0.0 + */ +public final class MavenArtifactAvailableVersionsResolver implements ArtifactAvailableVersionsResolver { + + /** + *

Logger.

+ * @since 1.0.0 + */ + private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass()); + + /** + *

Maven session.

+ * @since 1.0.0 + */ + private final MavenSession session; + + /** + *

Constructor.

+ * @param session a Maven session + * @since 1.0.0 + */ + public MavenArtifactAvailableVersionsResolver(final MavenSession session) { + Ensure.notNull("session", session); + this.session = session; + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact, the {@link List} of repositories or any of them is {@code null} + * @since 1.0.0 + */ + @Override + public ArtifactAvailableVersions resolve(final Artifact artifact, final List repositories) { + Ensure.notNull("artifact", artifact); + Ensure.notNullAndNotNullElements("repositories", repositories); + logger.info("Resolving {} artifact available versions", () -> ToString.toString(artifact)); + final var artifactType = artifact.getType(); + final var artifactIdentifier = artifact.getIdentifier(); + final var request = new VersionRangeRequest() + .setArtifact( + new DefaultArtifact( + artifactIdentifier.getGroupId(), + artifactIdentifier.getArtifactId(), + null, + "(,]" + ) + ) + .setRepositories( + session.resolve( + repositories.stream() + .filter( + repository -> RepositoryType.PLUGIN == artifactType.getRepositoryType() + || RepositoryType.NORMAL == repository.getType() + ) + .map( + repository -> MavenUtils.createRemoteRepository( + repository.getId(), + repository.getUrl() + ) + ) + .collect(Collectors.toUnmodifiableList()) + ) + ); + final VersionRangeResult result; + try { + result = session.request(request); + } catch (final VersionRangeResolutionException e) { + throw new AssertionError(e); + } + for (final var exception : result.getExceptions()) { + logger.warn(exception::getMessage); + } + return new ArtifactAvailableVersions( + artifact, + result.getVersions() + .stream() + .map(Version::toString) + .collect(Collectors.toUnmodifiableList()) + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/package-info.java new file mode 100644 index 0000000..195428c --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Artifact version resolving components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/Build.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/Build.java new file mode 100644 index 0000000..48e5fc8 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/Build.java @@ -0,0 +1,154 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; + +import java.util.List; + +/** + *

Class that describes a build.

+ * @since 1.0.0 + */ +public final class Build { + + /** + *

File.

+ * @since 1.0.0 + */ + private final BuildFile file; + + /** + *

{@link List} of repositories.

+ * @since 1.0.0 + */ + private final List repositories; + + /** + *

{@link List} of artifacts.

+ * @since 1.0.0 + */ + private final List> artifacts; + + /** + *

Constructor.

+ * @param file a file + * @param repositories a {@link List} of repositories + * @param artifacts a {@link List} of artifacts + * @throws NullPointerException if the file, the {@link List} of repositories, any of them, the {@link List} of + * artifacts or any of them is {@code null} + * @since 1.0.0 + */ + public Build( + final BuildFile file, + final List repositories, + final List> artifacts + ) { + Ensure.notNull("file", file); + Ensure.notNullAndNotNullElements("repositories", repositories); + Ensure.notNullAndNotNullElements("artifacts", artifacts); + this.file = file; + this.repositories = List.copyOf(repositories); + this.artifacts = List.copyOf(artifacts); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof Build)) { + return false; + } + final var other = (Build) object; + return Equals.equals(file, other.file) + && Equals.equals(repositories, other.repositories) + && Equals.equals(artifacts, other.artifacts); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(file), + HashCode.hashCode(repositories), + HashCode.hashCode(artifacts) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("file", ToString.toString(file)), + Pair.of("repositories", ToString.toString(repositories)), + Pair.of("artifacts", ToString.toString(artifacts)) + ); + } + + /** + *

Get the file.

+ * @return the file + * @since 1.0.0 + */ + public BuildFile getFile() { + return file; + } + + /** + *

Get the {@link List} of repositories.

+ * @return the {@link List} of repositories + * @since 1.0.0 + */ + public List getRepositories() { + return repositories; + } + + /** + *

Get the {@link List} of artifacts.

+ * @return the {@link List} of artifacts + * @since 1.0.0 + */ + public List> getArtifacts() { + return artifacts; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFile.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFile.java new file mode 100644 index 0000000..fb8cd12 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFile.java @@ -0,0 +1,125 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.file; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; + +import java.nio.file.Path; + +/** + *

Class that describes a build file.

+ * @since 1.0.0 + */ +public final class BuildFile { + + /** + *

Type.

+ * @since 1.0.0 + */ + private final BuildFileType type; + + /** + *

File.

+ * @since 1.0.0 + */ + private final Path file; + + /** + *

Constructor.

+ * @param type a type + * @param file a file + * @throws NullPointerException if the type or the file is {@code null} + * @since 1.0.0 + */ + public BuildFile(final BuildFileType type, final Path file) { + Ensure.notNull("type", type); + Ensure.notNull("file", file); + this.type = type; + this.file = file; + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof BuildFile)) { + return false; + } + final var other = (BuildFile) object; + return Equals.equals(type, other.type) + && Equals.equals(file, other.file); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(type), + HashCode.hashCode(file) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("type", ToString.toString(type)), + Pair.of("file", ToString.toString(file)) + ); + } + + /** + *

Get the type.

+ * @return the type + * @since 1.0.0 + */ + public BuildFileType getType() { + return type; + } + + /** + *

Get the file.

+ * @return the file + * @since 1.0.0 + */ + public Path getFile() { + return file; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileType.java new file mode 100644 index 0000000..7a72a9b --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileType.java @@ -0,0 +1,93 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.file; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; + +import java.util.Arrays; +import java.util.Optional; + +/** + *

Enumeration of build file types.

+ * @since 1.0.0 + */ +public enum BuildFileType { + + /** + *

The Maven build file type.

+ * @since 1.0.0 + */ + MAVEN("pom.xml"), + + /** + *

The Gradle Groovy build file type.

+ * @since 1.0.0 + */ + GRADLE_GROOVY("build.gradle"), + + /** + *

The Gradle Kotlin build file type.

+ * @since 1.0.0 + */ + GRADLE_KOTLIN("build.gradle.kts"); + + /** + *

File name.

+ * @since 1.0.0 + */ + private final String fileName; + + /** + *

Constructor.

+ * @param fileName a file name + * @since 1.0.0 + */ + BuildFileType(final String fileName) { + this.fileName = fileName; + } + + /** + *

Get the file name.

+ * @return the file name + * @since 1.0.0 + */ + public final String getFileName() { + return fileName; + } + + /** + *

Return an {@link Optional} of the value for the given file name.

+ * @param fileName a file name + * @return the {@link Optional} of the value + * @throws NullPointerException if the file name is {@code null} + * @throws IllegalArgumentException if the file name is empty + * @since 1.0.0 + */ + public static Optional optionalValueOf(final String fileName) { + Ensure.notNullAndNotEmpty("fileName", fileName); + return Arrays.stream(values()) + .filter(value -> value.fileName.equals(fileName)) + .findAny(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/package-info.java new file mode 100644 index 0000000..7ae114f --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/file/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Build file components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.build.file; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/package-info.java new file mode 100644 index 0000000..af3c8aa --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Build components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.build; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveException.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveException.java new file mode 100644 index 0000000..3e40a77 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveException.java @@ -0,0 +1,60 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; + +/** + *

Unchecked {@link Exception} related to build resolving.

+ * @since 1.0.0 + */ +public final class BuildResolveException extends RuntimeException { + + /** + *

Serial version unique identifier.

+ * @since 1.0.0 + */ + private static final long serialVersionUID = 2259143999947820179L; + + /** + *

Constructor with a message.

+ * @param message a message + * @throws NullPointerException if the message is {@code null} + * @throws IllegalArgumentException if the message is empty + * @since 1.0.0 + */ + BuildResolveException(final String message) { + super(Ensure.notNullAndNotEmpty("message", message)); + } + + /** + *

Constructor with a cause.

+ * @param cause a cause + * @throws NullPointerException if the cause is {@code null} + * @since 1.0.0 + */ + BuildResolveException(final Throwable cause) { + super(Ensure.notNull("cause", cause)); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolver.java new file mode 100644 index 0000000..cf6ffa3 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolver.java @@ -0,0 +1,53 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.mavencheck.core.component.build.Build; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; + +import java.util.Set; + +/** + *

Interface that describes a resolver of the build for a file.

+ * @since 1.0.0 + */ +public interface BuildResolver { + + /** + *

Resolve the build for a file.

+ * @param file a file + * @return the build + * @throws BuildResolveException might occur while resolving the build + * @since 1.0.0 + */ + Build resolve(final BuildFile file) throws BuildResolveException; + + /** + *

Get the {@link Set} of file types.

+ * @return the {@link Set} of file types + * @since 1.0.0 + */ + Set getFileTypes(); +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolver.java new file mode 100644 index 0000000..89ee55b --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolver.java @@ -0,0 +1,355 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.javanilla.io.Readers; +import com.github.alexisjehan.javanilla.lang.Strings; +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.GradleArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.Build; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.util.GradleUtils; +import internal.ExcludeFromJacocoGeneratedReport; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.gradle.tooling.GradleConnectionException; +import org.gradle.tooling.GradleConnector; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.invoke.MethodHandles; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

Class that describes a Gradle resolver of the build for a file.

+ *

Note: Compatible starting with Gradle 4.8.

+ * @since 1.0.0 + */ +public final class GradleBuildResolver implements BuildResolver { + + /** + *

Initialisation file name.

+ * @since 1.0.0 + */ + private static final String INIT_FILE_NAME = "init.gradle"; + + /** + *

{@link Set} of file types.

+ * @since 1.0.0 + */ + private static final Set FILE_TYPES = Set.of( + BuildFileType.GRADLE_GROOVY, + BuildFileType.GRADLE_KOTLIN + ); + + /** + *

Logger.

+ * @since 1.0.0 + */ + private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass()); + + /** + *

Constructor by default.

+ * @since 1.0.0 + */ + public GradleBuildResolver() { + // By default + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the file is {@code null} + * @since 1.0.0 + */ + @Override + @ExcludeFromJacocoGeneratedReport + public Build resolve(final BuildFile file) { + Ensure.notNull("file", file); + try (final var outputStream = new ByteArrayOutputStream()) { + return resolve(file, outputStream); + } catch (final IOException e) { + throw new AssertionError(e); + } + } + + /** + *

Resolve the build for a file using an {@link OutputStream}.

+ * @param file a file + * @param outputStream an {@link OutputStream} + * @return the build + * @throws IOException might occur with input/output operations + * @throws BuildResolveException might occur while resolving the build + * @since 1.0.0 + */ + private Build resolve(final BuildFile file, final OutputStream outputStream) throws IOException { + logger.info("Resolving the {} build", () -> ToString.toString(file)); + final var connector = GradleConnector.newConnector() + .forProjectDirectory(file.getFile().getParent().toFile()); + GradleUtils.retrieveOptionalHome() + .map(Path::of) + .ifPresent(installation -> { + logger.debug("Using the {} installation", () -> ToString.toString(installation)); + connector.useInstallation(installation.toFile()); + }); + try (final var connection = connector.connect()) { + connection.newBuild() + .forTasks("repositories", "dependencies") + .withArguments("--init-script=" + getClass().getClassLoader().getResource(INIT_FILE_NAME)) + .setStandardOutput(outputStream) + .run(); + } catch (final GradleConnectionException e) { + throw new BuildResolveException(e); + } finally { + connector.disconnect(); + } + try (final var reader = Readers.buffered(Readers.of(outputStream.toString()))) { + logger.trace("Parsing repositories"); + final var repositories = parseRepositories(reader); + logger.debug("Parsed repositories:"); + repositories.forEach( + repository -> logger.debug("- {}", () -> ToString.toString(repository)) + ); + + logger.trace("Parsing artifacts"); + final var artifacts = parseArtifacts(reader); + logger.debug("Parsed artifacts:"); + artifacts.forEach( + artifact -> logger.debug("- {}", () -> ToString.toString(artifact)) + ); + + logger.trace("Filtering artifacts"); + final var filteredArtifacts = filter(artifacts); + logger.debug("Filtered artifacts:"); + filteredArtifacts.forEach( + filteredArtifact -> logger.debug("- {}", () -> ToString.toString(filteredArtifact)) + ); + + return new Build(file, repositories, filteredArtifacts); + } + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public Set getFileTypes() { + return FILE_TYPES; + } + + /** + *

Parse a {@link List} of repositories from a {@link BufferedReader} of the Gradle {@code :repositories} + * task.

+ * @param bufferedReader a {@link BufferedReader} + * @return the {@link List} of repositories + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the {@link BufferedReader} is {@code null} + * @throws BuildResolveException if the Gradle {@code :repositories} task output is unexpected + * @since 1.0.0 + */ + static List parseRepositories(final BufferedReader bufferedReader) throws IOException { + Ensure.notNull("bufferedReader", bufferedReader); + final var repositories = new ArrayList(); + String line; + while (null != (line = bufferedReader.readLine())) { + if ("> Task :repositories".equals(line)) { + while (null != (line = bufferedReader.readLine())) { + if (line.isEmpty()) { + break; + } + if (2 > Strings.frequency(line, ':')) { + throw new BuildResolveException("Unexpected Gradle \":repositories\" repository format"); + } + final var parts = Strings.split(':', line, 3); + final RepositoryType repositoryType; + try { + repositoryType = RepositoryType.valueOf(parts.get(0)); + } catch (final IllegalArgumentException e) { + throw new BuildResolveException("Unexpected Gradle \":repositories\" repository type format"); + } + repositories.add(new Repository(repositoryType, parts.get(1), parts.get(2))); + } + break; + } + } + return repositories; + } + + /** + *

Parse a {@link List} of artifacts from a {@link BufferedReader} of the Gradle {@code :dependencies} + * task.

+ * @param bufferedReader a {@link BufferedReader} + * @return the {@link List} of artifacts + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the {@link BufferedReader} is {@code null} + * @throws BuildResolveException if the Gradle {@code :dependencies} task output is unexpected + * @since 1.0.0 + */ + static List> parseArtifacts(final BufferedReader bufferedReader) throws IOException { + Ensure.notNull("bufferedReader", bufferedReader); + final var artifacts = new ArrayList>(); + String line; + while (null != (line = bufferedReader.readLine())) { + if ("> Task :dependencies".equals(line)) { + if (!Strings.EMPTY.equals(bufferedReader.readLine()) + || !"-".repeat(60).equals(bufferedReader.readLine()) + + // Until Gradle 6.7: "Root project" + // Since Gradle 6.8: "Root project 'foo'" + || !Strings.nullToEmpty(bufferedReader.readLine()).startsWith("Root project") + + || !"-".repeat(60).equals(bufferedReader.readLine()) + || !Strings.EMPTY.equals(bufferedReader.readLine())) { + throw new BuildResolveException("Unexpected Gradle \":dependencies\" header format"); + } + while (null != (line = bufferedReader.readLine())) { + if ("A web-based, searchable dependency report is available by adding the --scan option." + .equals(line)) { + break; + } + final var artifactTypeString = Strings.substringBefore(line, " - "); + final var optionalArtifactType = Arrays.stream(GradleArtifactType.values()) + .filter(artifactType -> artifactType.dependenciesTaskName().equals(artifactTypeString)) + .findAny(); + if (optionalArtifactType.isEmpty()) { + while (null != (line = bufferedReader.readLine())) { + if (line.isEmpty()) { + break; + } + } + } else { + final var artifactType = optionalArtifactType.orElseThrow(); + while (null != (line = bufferedReader.readLine())) { + if (line.isEmpty()) { + break; + } + if ("No dependencies".equals(line) + || line.startsWith("| ") + || line.startsWith(" ")) { + continue; + } + if (!line.startsWith("+--- ") && !line.startsWith("\\--- ")) { + throw new BuildResolveException("Unexpected Gradle \":dependencies\" artifact format"); + } + final var artifactString = Strings.substringBefore( + Strings.substringAfter( + line, + "--- " + ), + ' ' + ); + final var frequency = Strings.frequency(artifactString, ':'); + if (1 > frequency || 2 < frequency) { + throw new BuildResolveException("Unexpected Gradle \":dependencies\" artifact format"); + } + final var parts = Strings.split(':', artifactString); + artifacts.add( + new Artifact<>( + artifactType, + new ArtifactIdentifier(parts.get(0), parts.get(1)), + 3 == parts.size() + ? parts.get(2) + : null + ) + ); + } + } + } + break; + } + } + return artifacts; + } + + /** + *

Filter a modifiable {@link List} of artifacts, removing redundant duplicates.

+ * @param artifacts a modifiable {@link List} of artifacts + * @return the {@link List} of artifacts + * @throws NullPointerException if the {@link List} of artifacts or any of them is {@code null} + * @since 1.0.0 + */ + static List> filter(final List> artifacts) { + Ensure.notNullAndNotNullElements("artifacts", artifacts); + artifacts.stream() + .filter(artifact -> { + final var artifactType = artifact.getType(); + return !artifactType.isClasspath(); + }) + .collect(Collectors.toUnmodifiableList()) + .forEach(artifact -> { + artifacts.remove(artifact.with(GradleArtifactType.COMPILE_CLASSPATH)); + artifacts.remove(artifact.with(GradleArtifactType.RUNTIME_CLASSPATH)); + artifacts.remove(artifact.with(GradleArtifactType.TEST_COMPILE_CLASSPATH)); + artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH)); + }); + artifacts.stream() + .filter(artifact -> GradleArtifactType.COMPILE_CLASSPATH == artifact.getType()) + .collect(Collectors.toUnmodifiableList()) + .forEach(artifact -> { + artifacts.remove(artifact.with(GradleArtifactType.RUNTIME_CLASSPATH)); + artifacts.remove(artifact.with(GradleArtifactType.TEST_COMPILE_CLASSPATH)); + artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH)); + }); + artifacts.stream() + .filter(artifact -> GradleArtifactType.RUNTIME_CLASSPATH == artifact.getType()) + .collect(Collectors.toUnmodifiableList()) + .forEach(artifact -> { + artifacts.remove(artifact.with(GradleArtifactType.TEST_COMPILE_CLASSPATH)); + artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH)); + }); + artifacts.stream() + .filter(artifact -> GradleArtifactType.TEST_COMPILE_CLASSPATH == artifact.getType()) + .collect(Collectors.toUnmodifiableList()) + .forEach(artifact -> artifacts.remove(artifact.with(GradleArtifactType.TEST_RUNTIME_CLASSPATH))); + return artifacts.stream() + .map(artifact -> { + final var artifactType = artifact.getType(); + if (GradleArtifactType.COMPILE_CLASSPATH == artifactType) { + return artifact.with(GradleArtifactType.IMPLEMENTATION); + } else if (GradleArtifactType.RUNTIME_CLASSPATH == artifactType) { + return artifact.with(GradleArtifactType.RUNTIME_ONLY); + } else if (GradleArtifactType.TEST_COMPILE_CLASSPATH == artifactType) { + return artifact.with(GradleArtifactType.TEST_IMPLEMENTATION); + } else if (GradleArtifactType.TEST_RUNTIME_CLASSPATH == artifactType) { + return artifact.with(GradleArtifactType.TEST_RUNTIME_ONLY); + } else { + return artifact; + } + }) + .collect(Collectors.toUnmodifiableList()); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolver.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolver.java new file mode 100644 index 0000000..ae4fff6 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolver.java @@ -0,0 +1,385 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.Build; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Extension; +import org.apache.maven.model.Model; +import org.apache.maven.model.Parent; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.ReportPlugin; +import org.apache.maven.model.building.DefaultModelBuilderFactory; +import org.apache.maven.model.building.DefaultModelBuildingRequest; +import org.apache.maven.model.building.ModelBuildingException; +import org.apache.maven.model.building.ModelBuildingRequest; +import org.apache.maven.model.building.ModelBuildingResult; + +import java.lang.invoke.MethodHandles; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + *

Class that describes a Maven resolver of the build for a file.

+ * @since 1.0.0 + */ +public final class MavenBuildResolver implements BuildResolver { + + /** + *

{@link Set} of file types.

+ * @since 1.0.0 + */ + private static final Set FILE_TYPES = Set.of(BuildFileType.MAVEN); + + /** + *

Logger.

+ * @since 1.0.0 + */ + private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass()); + + /** + *

Maven session.

+ * @since 1.0.0 + */ + private final MavenSession session; + + /** + *

Constructor.

+ * @param session a Maven session + * @throws NullPointerException if the Maven session is {@code null} + * @since 1.0.0 + */ + public MavenBuildResolver(final MavenSession session) { + Ensure.notNull("session", session); + this.session = session; + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the file is {@code null} + * @since 1.0.0 + */ + @Override + public Build resolve(final BuildFile file) { + Ensure.notNull("file", file); + logger.info("Resolving the {} build", () -> ToString.toString(file)); + final var request = new DefaultModelBuildingRequest() + .setPomFile(file.getFile().toFile()) + .setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL) + .setProcessPlugins(false) + .setSystemProperties(System.getProperties()) + .setModelResolver(session.getModelResolver()) + .setModelCache(session.getModelCache()); + final ModelBuildingResult result; + try { + result = new DefaultModelBuilderFactory() + .newInstance() + .build(request); + } catch (final ModelBuildingException e) { + throw new BuildResolveException(e); + } + final var effectiveModel = result.getEffectiveModel(); + + logger.trace("Extracting repositories"); + final var repositories = extractRepositories(effectiveModel); + logger.debug("Extracted repositories:"); + repositories.forEach( + repository -> logger.debug("- {}", () -> ToString.toString(repository)) + ); + + logger.trace("Extracting effective artifacts"); + final var effectiveArtifacts = extractArtifacts(effectiveModel); + logger.debug("Extracted effective artifacts:"); + effectiveArtifacts.forEach( + effectiveArtifact -> logger.debug("- {}", () -> ToString.toString(effectiveArtifact)) + ); + + logger.trace("Extracting raw artifacts"); + final var rawArtifacts = extractArtifacts(result.getRawModel()); + logger.debug("Extracted raw artifacts:"); + rawArtifacts.forEach( + rawArtifact -> logger.debug("- {}", () -> ToString.toString(rawArtifact)) + ); + + logger.trace("Filtering artifacts"); + final var filteredArtifacts = filter(effectiveArtifacts, rawArtifacts); + logger.debug("Filtered artifacts:"); + filteredArtifacts.forEach( + filteredArtifact -> logger.debug("- {}", () -> ToString.toString(filteredArtifact)) + ); + + return new Build(file, repositories, filteredArtifacts); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public Set getFileTypes() { + return FILE_TYPES; + } + + /** + *

Extract a {@link List} of repositories from a Maven model.

+ * @param model a Maven model + * @return the {@link List} of repositories + * @since 1.0.0 + */ + private static List extractRepositories(final Model model) { + return Stream.concat( + model.getRepositories() + .stream() + .map(repository -> toRepository(RepositoryType.NORMAL, repository)), + model.getPluginRepositories() + .stream() + .map(pluginRepository -> toRepository(RepositoryType.PLUGIN, pluginRepository)) + ).collect(Collectors.toUnmodifiableList()); + } + + /** + *

Extract a {@link List} of artifacts from a Maven model.

+ * @param model a Maven model + * @return the {@link List} of artifacts + * @since 1.0.0 + */ + private static List> extractArtifacts(final Model model) { + final var artifacts = new ArrayList>(); + final var parent = model.getParent(); + if (null != parent) { + artifacts.add(toArtifact(parent)); + } + final var dependencyManagement = model.getDependencyManagement(); + if (null != dependencyManagement) { + for (final var dependency : dependencyManagement.getDependencies()) { + artifacts.add(toArtifact(MavenArtifactType.DEPENDENCY_MANAGEMENT_DEPENDENCY, dependency)); + } + } + for (final var dependency : model.getDependencies()) { + artifacts.add(toArtifact(MavenArtifactType.DEPENDENCY, dependency)); + } + final var build = model.getBuild(); + if (null != build) { + for (final var extension : build.getExtensions()) { + artifacts.add(toArtifact(extension)); + } + final var buildPluginManagement = build.getPluginManagement(); + if (null != buildPluginManagement) { + for (final var plugin : buildPluginManagement.getPlugins()) { + artifacts.add(toArtifact(MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN, plugin)); + for (final var dependency : plugin.getDependencies()) { + artifacts.add( + toArtifact( + MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY, + dependency + ) + ); + } + } + } + for (final var plugin : build.getPlugins()) { + artifacts.add(toArtifact(MavenArtifactType.BUILD_PLUGIN, plugin)); + for (final var dependency : plugin.getDependencies()) { + artifacts.add(toArtifact(MavenArtifactType.BUILD_PLUGIN_DEPENDENCY, dependency)); + } + } + } + final var reporting = model.getReporting(); + if (null != reporting) { + for (final var plugin : reporting.getPlugins()) { + artifacts.add(toArtifact(MavenArtifactType.REPORTING_PLUGIN, plugin)); + } + } + for (final var profile : model.getProfiles()) { + final var profileDependencyManagement = profile.getDependencyManagement(); + if (null != profileDependencyManagement) { + for (final var dependency : profileDependencyManagement.getDependencies()) { + artifacts.add(toArtifact(MavenArtifactType.PROFILE_DEPENDENCY_MANAGEMENT_DEPENDENCY, dependency)); + } + } + for (final var dependency : profile.getDependencies()) { + artifacts.add(toArtifact(MavenArtifactType.PROFILE_DEPENDENCY, dependency)); + } + final var profileBuild = profile.getBuild(); + if (null != profileBuild) { + final var profileBuildPluginManagement = profileBuild.getPluginManagement(); + if (null != profileBuildPluginManagement) { + for (final var plugin : profileBuildPluginManagement.getPlugins()) { + artifacts.add(toArtifact(MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN, plugin)); + for (final var dependency : plugin.getDependencies()) { + artifacts.add( + toArtifact( + MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY, + dependency + ) + ); + } + } + } + for (final var plugin : profileBuild.getPlugins()) { + artifacts.add(toArtifact(MavenArtifactType.PROFILE_BUILD_PLUGIN, plugin)); + for (final var dependency : plugin.getDependencies()) { + artifacts.add(toArtifact(MavenArtifactType.PROFILE_BUILD_PLUGIN_DEPENDENCY, dependency)); + } + } + } + final var profileReporting = profile.getReporting(); + if (null != profileReporting) { + for (final var plugin : profileReporting.getPlugins()) { + artifacts.add(toArtifact(MavenArtifactType.PROFILE_REPORTING_PLUGIN, plugin)); + } + } + } + return artifacts; + } + + /** + *

Filter a {@link List} of effective artifacts using a {@link List} of raw artifacts.

+ * @param effectiveArtifacts a {@link List} of effective artifacts + * @param rawArtifacts a {@link List} of raw artifacts + * @return the {@link List} of artifacts + * @since 1.0.0 + */ + private static List> filter( + final List> effectiveArtifacts, + final List> rawArtifacts + ) { + return effectiveArtifacts.stream() + .filter(effectiveArtifact -> { + final var effectiveArtifactType = effectiveArtifact.getType(); + final var effectiveArtifactIdentifier = effectiveArtifact.getIdentifier(); + return rawArtifacts.stream() + .anyMatch( + rawArtifact -> rawArtifact.getType() == effectiveArtifactType + && rawArtifact.getIdentifier().equals(effectiveArtifactIdentifier) + ); + }) + .collect(Collectors.toUnmodifiableList()); + } + + /** + *

Create a repository from a type and a Maven repository.

+ * @param type a type + * @param repository a Maven repository + * @return the repository + * @since 1.0.0 + */ + private static Repository toRepository( + final RepositoryType type, + final org.apache.maven.model.Repository repository + ) { + return new Repository(type, repository.getId(), repository.getUrl()); + } + + /** + *

Create an artifact from a Maven parent.

+ * @param parent a Maven parent + * @return the artifact + * @since 1.0.0 + */ + private static Artifact toArtifact(final Parent parent) { + return new Artifact<>( + MavenArtifactType.PARENT, + new ArtifactIdentifier(parent.getGroupId(), parent.getArtifactId()), + parent.getVersion() + ); + } + + /** + *

Create an artifact from a type and a Maven dependency.

+ * @param type a type + * @param dependency a Maven dependency + * @return the artifact + * @since 1.0.0 + */ + private static Artifact toArtifact(final MavenArtifactType type, final Dependency dependency) { + return new Artifact<>( + type, + new ArtifactIdentifier(dependency.getGroupId(), dependency.getArtifactId()), + dependency.getVersion() + ); + } + + /** + *

Create an artifact from a Maven extension.

+ * @param extension a Maven extension + * @return the artifact + * @since 1.0.0 + */ + private static Artifact toArtifact(final Extension extension) { + return new Artifact<>( + MavenArtifactType.BUILD_EXTENSION, + new ArtifactIdentifier(extension.getGroupId(), extension.getArtifactId()), + extension.getVersion() + ); + } + + /** + *

Create an artifact from a type and a Maven plugin.

+ * @param type a type + * @param plugin a Maven plugin + * @return the artifact + * @since 1.0.0 + */ + private static Artifact toArtifact(final MavenArtifactType type, final Plugin plugin) { + return new Artifact<>( + type, + new ArtifactIdentifier(plugin.getGroupId(), plugin.getArtifactId()), + plugin.getVersion() + ); + } + + /** + *

Create an artifact from a type and a Maven report plugin.

+ * @param type a type + * @param reportPlugin a Maven report plugin + * @return the artifact + * @since 1.0.0 + */ + private static Artifact toArtifact( + final MavenArtifactType type, + final ReportPlugin reportPlugin + ) { + return new Artifact<>( + type, + new ArtifactIdentifier(reportPlugin.getGroupId(), reportPlugin.getArtifactId()), + reportPlugin.getVersion() + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/package-info.java new file mode 100644 index 0000000..0013bc0 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Build resolving components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilter.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilter.java new file mode 100644 index 0000000..c5f7676 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilter.java @@ -0,0 +1,113 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; + +/** + *

Interface that describes an artifact filter.

+ * @since 1.0.0 + */ +public interface ArtifactFilter { + + /** + *

Artifact filter that reject all artifacts.

+ * @since 1.0.0 + */ + ArtifactFilter ALL = new ArtifactFilter() { + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact is {@code null} + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact) { + Ensure.notNull("artifact", artifact); + return false; + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact or the update version is {@code null} + * @throws IllegalArgumentException if the update version is empty + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact, final String updateVersion) { + Ensure.notNull("artifact", artifact); + Ensure.notNullAndNotEmpty("updateVersion", updateVersion); + return false; + } + }; + + /** + *

Artifact filter that accept all artifacts.

+ * @since 1.0.0 + */ + ArtifactFilter NONE = new ArtifactFilter() { + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact is {@code null} + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact) { + Ensure.notNull("artifact", artifact); + return true; + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact or the update version is {@code null} + * @throws IllegalArgumentException if the update version is empty + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact, final String updateVersion) { + Ensure.notNull("artifact", artifact); + Ensure.notNullAndNotEmpty("updateVersion", updateVersion); + return true; + } + }; + + /** + *

Test if an artifact is accepted.

+ * @param artifact an artifact + * @return {@code true} if the artifact is accepted + * @since 1.0.0 + */ + boolean accept(final Artifact artifact); + + /** + *

Test if an artifact and an update version are accepted.

+ * @param artifact an artifact + * @param updateVersion an update version + * @return {@code true} if the artifact and the update version are accepted + * @since 1.0.0 + */ + boolean accept(final Artifact artifact, final String updateVersion); +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilter.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilter.java new file mode 100644 index 0000000..ad59e4e --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilter.java @@ -0,0 +1,84 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

Class that describes a composite artifact filter.

+ * @since 1.0.0 + */ +public final class CompositeArtifactFilter implements ArtifactFilter { + + /** + *

{@link Set} of artifact filters.

+ * @since 1.0.0 + */ + private final Set filters; + + /** + *

Constructor.

+ * @param filters an array of artifact filters + * @throws NullPointerException if the array of artifacts or any of them is {@code null} + * @throws IllegalArgumentException if the array of artifacts is empty + * @since 1.0.0 + */ + public CompositeArtifactFilter(final ArtifactFilter... filters) { + Ensure.notNullAndNotEmpty("filters", filters); + Ensure.notNullAndNotNullElements("filters", filters); + this.filters = Arrays.stream(filters) + .collect(Collectors.toUnmodifiableSet()); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact is {@code null} + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact) { + Ensure.notNull("artifact", artifact); + return filters.stream() + .allMatch(filter -> filter.accept(artifact)); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact or the update version is {@code null} + * @throws IllegalArgumentException if the update version is empty + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact, final String updateVersion) { + Ensure.notNull("artifact", artifact); + Ensure.notNullAndNotEmpty("updateVersion", updateVersion); + return filters.stream() + .allMatch(filter -> filter.accept(artifact, updateVersion)); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/package-info.java new file mode 100644 index 0000000..f0fe206 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Artifact filtering components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseException.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseException.java new file mode 100644 index 0000000..065bf56 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseException.java @@ -0,0 +1,161 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.ToString; + +import java.nio.file.Path; +import java.util.Optional; + +/** + *

Unchecked {@link Exception} related to artifact filter parsing.

+ * @since 1.0.0 + */ +public final class ArtifactFilterParseException extends RuntimeException { + + /** + *

Serial version unique identifier.

+ * @since 1.0.0 + */ + private static final long serialVersionUID = 8647765091802310213L; + + /** + *

Reason.

+ * @since 1.0.0 + */ + private final String reason; + + /** + *

Line.

+ * @since 1.0.0 + */ + private final String line; + + /** + *

Line number.

+ * @since 1.0.0 + */ + private final long lineNumber; + + /** + *

File.

+ * @since 1.0.0 + */ + private final transient Path file; + + /** + *

Constructor without a file.

+ * @param reason a reason + * @param line a line + * @param lineNumber a line number + * @throws NullPointerException if the reason or the line is {@code null} + * @throws IllegalArgumentException if the reason or the line is empty or if the line number is lower than or equal + * to 0 + * @since 1.0.0 + */ + ArtifactFilterParseException(final String reason, final String line, final long lineNumber) { + this(reason, line, lineNumber, null); + } + + /** + *

Constructor with a file.

+ * @param reason a reason + * @param line a line + * @param lineNumber a line number + * @param file a file or {@code null} + * @throws NullPointerException if the reason or the line is {@code null} + * @throws IllegalArgumentException if the reason or the line is empty or if the line number is lower than or equal + * to 0 + * @since 1.0.0 + */ + private ArtifactFilterParseException( + final String reason, + final String line, + final long lineNumber, + final Path file + ) { + super( + Ensure.notNullAndNotEmpty("reason", reason) + + ": " + + ToString.toString(Ensure.notNullAndNotEmpty("line", line)) + + " (" + + "at line " + Ensure.greaterThan("lineNumber", lineNumber, 0) + + (null != file ? " of the " + ToString.toString(file) + " file" : "") + + ")" + ); + this.reason = reason; + this.line = line; + this.lineNumber = lineNumber; + this.file = file; + } + + /** + *

Return a copy of the current exception with the given file.

+ * @param file a file + * @return the copy of the current exception + * @throws NullPointerException if the file is {@code null} + * @since 1.0.0 + */ + public ArtifactFilterParseException with(final Path file) { + Ensure.notNull("file", file); + return new ArtifactFilterParseException(reason, line, lineNumber, file); + } + + /** + *

Get the reason.

+ * @return the reason + * @since 1.0.0 + */ + public String getReason() { + return reason; + } + + /** + *

Get the line.

+ * @return the line + * @since 1.0.0 + */ + public String getLine() { + return line; + } + + /** + *

Get the line number.

+ * @return the line number + * @since 1.0.0 + */ + public long getLineNumber() { + return lineNumber; + } + + /** + *

Get an {@link Optional} of the file.

+ * @return the {@link Optional} of the file + * @since 1.0.0 + */ + public Optional getOptionalFile() { + return Optional.ofNullable(file); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParser.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParser.java new file mode 100644 index 0000000..7b34d9f --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParser.java @@ -0,0 +1,202 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser; + +import com.github.alexisjehan.javanilla.io.Readers; +import com.github.alexisjehan.javanilla.lang.Strings; +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.filter.artifact.ArtifactFilter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.io.Reader; +import java.lang.invoke.MethodHandles; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + *

Class that describes an artifact filter parser.

+ * @since 1.0.0 + */ +public final class ArtifactFilterParser { + + /** + *

Start of a comment line.

+ * @since 1.0.0 + */ + private static final char COMMENT_START = '#'; + + /** + *

Separator.

+ * @since 1.0.0 + */ + private static final char SEPARATOR = ':'; + + /** + *

Single character wildcard.

+ * @since 1.0.0 + */ + private static final char WILDCARD_SINGLE = '?'; + + /** + *

Any characters wildcard.

+ * @since 1.0.0 + */ + private static final char WILDCARD_ANY = '*'; + + /** + *

Logger.

+ * @since 1.0.0 + */ + private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass()); + + /** + *

Constructor not available.

+ * @since 1.0.0 + */ + private ArtifactFilterParser() { + // Not available + } + + /** + *

Parse an artifact filter from the given ignore file.

+ * @param ignoreFile an ignore file + * @return the artifact filter + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the ignore file is {@code null} + * @throws IllegalArgumentException if the ignore file does not exist + * @throws ArtifactFilterParseException if the content is unexpected + * @since 1.0.0 + */ + public static ArtifactFilter parse(final Path ignoreFile) throws IOException { + Ensure.notNullAndFile("ignoreFile", ignoreFile); + logger.info("Parsing the {} ignore file", () -> ToString.toString(ignoreFile)); + try (final var reader = Readers.of(ignoreFile)) { + return parse(reader); + } catch (final ArtifactFilterParseException e) { + throw e.with(ignoreFile); + } + } + + /** + *

Parse an artifact filter from the given {@link Reader}.

+ * @param reader a {@link Reader} + * @return the artifact filter + * @throws IOException might occur with input/output operations + * @throws NullPointerException if the {@link Reader} is {@code null} + * @throws ArtifactFilterParseException if the content is unexpected + * @since 1.0.0 + */ + static ArtifactFilter parse(final Reader reader) throws IOException { + Ensure.notNull("reader", reader); + final var identifiers = new HashSet(); + final var identifiersVersions = new HashMap>(); + try (final var bufferedReader = Readers.buffered(reader)) { + String line; + long lineNumber = 1; + while (null != (line = bufferedReader.readLine())) { + line = Strings.substringBefore(line, COMMENT_START).trim(); + if (line.isEmpty()) { + continue; + } + final var frequency = Strings.frequency(line, SEPARATOR); + if (1 != frequency && 2 != frequency) { + throw new ArtifactFilterParseException("Unexpected format", line, lineNumber); + } + final var parts = Strings.split(SEPARATOR, line); + final var groupId = parts.get(0); + if (groupId.isEmpty()) { + throw new ArtifactFilterParseException("Unexpected format, empty groupId", line, lineNumber); + } + final var artifactId = parts.get(1); + if (artifactId.isEmpty()) { + throw new ArtifactFilterParseException("Unexpected format, empty artifactId", line, lineNumber); + } + final var identifier = new ArtifactIdentifier(groupId, artifactId); + if (2 == parts.size()) { + logger.debug("Ignoring the {} artifact identifier", () -> ToString.toString(identifier)); + identifiers.add(identifier); + } else { + final var versionExpression = parts.get(2); + if (versionExpression.isEmpty()) { + throw new ArtifactFilterParseException( + "Unexpected format, empty version expression", + line, + lineNumber + ); + } + logger.debug( + "Ignoring the {} artifact identifier with {} version expression", + () -> ToString.toString(identifier), + () -> ToString.toString(versionExpression) + ); + identifiersVersions.computeIfAbsent(identifier, key -> new HashSet<>()).add( + Pattern.compile( + "^" + Pattern.quote(versionExpression) + .replace(String.valueOf(WILDCARD_SINGLE), "\\E.\\Q") + .replace(String.valueOf(WILDCARD_ANY), "\\E.*\\Q") + "$", + Pattern.CASE_INSENSITIVE + ) + ); + } + ++lineNumber; + } + } + return new ArtifactFilter() { + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact is {@code null} + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact) { + Ensure.notNull("artifact", artifact); + return !identifiers.contains(artifact.getIdentifier()); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact or the update version is {@code null} + * @throws IllegalArgumentException if the update version is empty + * @since 1.0.0 + */ + @Override + public boolean accept(final Artifact artifact, final String updateVersion) { + Ensure.notNull("artifact", artifact); + Ensure.notNullAndNotEmpty("updateVersion", updateVersion); + final var identifierVersions = identifiersVersions.get(artifact.getIdentifier()); + return null == identifierVersions + || identifierVersions.stream().noneMatch(pattern -> pattern.matcher(updateVersion).matches()); + } + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/package-info.java new file mode 100644 index 0000000..fda8eaa --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Artifact filter parsing components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/package-info.java new file mode 100644 index 0000000..89784b3 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Filtering components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.filter; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilter.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilter.java new file mode 100644 index 0000000..e6a370f --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilter.java @@ -0,0 +1,51 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; + +/** + *

Interface that describes a version filter.

+ * @since 1.0.0 + */ +@FunctionalInterface +public interface VersionFilter { + + /** + *

Version filter that reject snapshots.

+ * @since 1.0.0 + */ + VersionFilter SNAPSHOT = version -> { + Ensure.notNullAndNotEmpty("version", version); + return version.endsWith("-SNAPSHOT"); + }; + + /** + *

Test if a version is accepted.

+ * @param version a version + * @return {@code true} if the version is accepted + * @since 1.0.0 + */ + boolean accept(final String version); +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactory.java new file mode 100644 index 0000000..a9b2a44 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactory.java @@ -0,0 +1,77 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

Class that describes a composite version filter factory.

+ * @since 1.0.0 + */ +public final class CompositeVersionFilterFactory implements VersionFilterFactory { + + /** + *

{@link Set} of version filter factories.

+ * @since 1.0.0 + */ + private final Set factories; + + /** + *

Constructor.

+ * @param factories an array of factories + * @throws NullPointerException if the array of factories or any of them is {@code null} + * @throws IllegalArgumentException if the array of factories is empty + * @since 1.0.0 + */ + public CompositeVersionFilterFactory(final VersionFilterFactory... factories) { + Ensure.notNullAndNotEmpty("factories", factories); + Ensure.notNullAndNotNullElements("factories", factories); + this.factories = Arrays.stream(factories) + .collect(Collectors.toUnmodifiableSet()); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact version is {@code null} + * @throws IllegalArgumentException if the artifact version is empty + * @since 1.0.0 + */ + @Override + public VersionFilter create(final String artifactVersion) { + Ensure.notNullAndNotEmpty("artifactVersion", artifactVersion); + final var filters = factories.stream() + .map(factory -> factory.create(artifactVersion)) + .collect(Collectors.toUnmodifiableSet()); + return version -> { + Ensure.notNullAndNotEmpty("version", version); + return filters.stream() + .allMatch(filter -> filter.accept(version)); + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactory.java new file mode 100644 index 0000000..db44895 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactory.java @@ -0,0 +1,83 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter; + +import java.util.regex.Pattern; + +/** + *

Enumeration of a singleton qualifier version filter factory.

+ * @since 1.0.0 + */ +public enum QualifierVersionFilterFactory implements VersionFilterFactory { + + /** + *

Singleton instance.

+ * @since 1.0.0 + */ + INSTANCE; + + /** + *

Pattern to extract the qualifier from a version.

+ * @since 1.0.0 + */ + private static final Pattern PATTERN = Pattern.compile( + "^.*[.\\-]?([a-z]+)[.\\-]?\\d*$", + Pattern.CASE_INSENSITIVE + ); + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact version is {@code null} + * @throws IllegalArgumentException if the artifact version is empty + * @since 1.0.0 + */ + @Override + public VersionFilter create(final String artifactVersion) { + Ensure.notNullAndNotEmpty("artifactVersion", artifactVersion); + final var artifactVersionQualifier = extractQualifier(artifactVersion); + return version -> { + Ensure.notNullAndNotEmpty("version", version); + final var versionQualifier = extractQualifier(version); + return null == versionQualifier + || null == artifactVersionQualifier + || versionQualifier.equalsIgnoreCase(artifactVersionQualifier); + }; + } + + /** + *

Extract the qualifier from a version.

+ * @param version a version + * @return the qualifier + * @since 1.0.0 + */ + private static String extractQualifier(final String version) { + final var matcher = PATTERN.matcher(version); + return matcher.matches() + ? matcher.group(1) + : null; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactory.java new file mode 100644 index 0000000..ba10f6e --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactory.java @@ -0,0 +1,66 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter; + +import java.util.regex.Pattern; + +/** + *

Enumeration of a singleton release version filter factory.

+ * @since 1.0.0 + */ +public enum ReleaseVersionFilterFactory implements VersionFilterFactory { + + /** + *

Singleton instance.

+ * @since 1.0.0 + */ + INSTANCE; + + /** + *

Pattern to match pre-release versions.

+ * @since 1.0.0 + */ + private static final Pattern PATTERN = Pattern.compile( + "^.*[.\\-]?(?:alpha|a|beta|b|milestone|m|rc|cr|snapshot)[.\\-]?\\d*$", + Pattern.CASE_INSENSITIVE + ); + + /** + * {@inheritDoc} + * @throws NullPointerException if the artifact version is {@code null} + * @throws IllegalArgumentException if the artifact version is empty + * @since 1.0.0 + */ + @Override + public VersionFilter create(final String artifactVersion) { + Ensure.notNullAndNotEmpty("artifactVersion", artifactVersion); + return version -> { + Ensure.notNullAndNotEmpty("version", version); + return !PATTERN.matcher(version).matches(); + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/VersionFilterFactory.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/VersionFilterFactory.java new file mode 100644 index 0000000..d700d9e --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/VersionFilterFactory.java @@ -0,0 +1,42 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; + +import com.github.alexisjehan.mavencheck.core.component.filter.version.VersionFilter; + +/** + *

Interface that describes a version filter factory.

+ * @since 1.0.0 + */ +@FunctionalInterface +public interface VersionFilterFactory { + + /** + *

Create a version filter for the given artifact version.

+ * @param artifactVersion an artifact version + * @return the version filter + * @since 1.0.0 + */ + VersionFilter create(final String artifactVersion); +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/package-info.java new file mode 100644 index 0000000..f825c87 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Version filtering factory components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/package-info.java new file mode 100644 index 0000000..29345e7 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/filter/version/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Version filtering components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/package-info.java new file mode 100644 index 0000000..b2d84a7 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/Repository.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/Repository.java new file mode 100644 index 0000000..9ac015a --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/Repository.java @@ -0,0 +1,145 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.repository; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; + +/** + *

Class that describes a repository.

+ * @since 1.0.0 + */ +public final class Repository { + + /** + *

Type.

+ * @since 1.0.0 + */ + private final RepositoryType type; + + /** + *

Identifier.

+ * @since 1.0.0 + */ + private final String id; + + /** + *

URL.

+ * @since 1.0.0 + */ + private final String url; + + /** + *

Constructor.

+ * @param type a type + * @param id an identifier + * @param url an URL + * @throws NullPointerException if the type, the identifier or the URL is {@code null} + * @throws IllegalArgumentException if the identifier or the URL is empty + * @since 1.0.0 + */ + public Repository(final RepositoryType type, final String id, final String url) { + Ensure.notNull("type", type); + Ensure.notNullAndNotEmpty("id", id); + Ensure.notNullAndNotEmpty("url", url); + this.type = type; + this.id = id; + this.url = url; + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof Repository)) { + return false; + } + final var other = (Repository) object; + return Equals.equals(type, other.type) + && Equals.equals(id, other.id) + && Equals.equals(url, other.url); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(type), + HashCode.hashCode(id), + HashCode.hashCode(url) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("type", ToString.toString(type)), + Pair.of("id", ToString.toString(id)), + Pair.of("url", ToString.toString(url)) + ); + } + + /** + *

Get the type.

+ * @return the type + * @since 1.0.0 + */ + public RepositoryType getType() { + return type; + } + + /** + *

Get the identifier.

+ * @return the identifier + * @since 1.0.0 + */ + public String getId() { + return id; + } + + /** + *

Get the URL.

+ * @return the URL + * @since 1.0.0 + */ + public String getUrl() { + return url; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryType.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryType.java new file mode 100644 index 0000000..a76459b --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryType.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.repository; + +/** + *

Enumeration of repository types.

+ * @since 1.0.0 + */ +public enum RepositoryType { + + /** + *

Normal repositories.

+ * @since 1.0.0 + */ + NORMAL, + + /** + *

Plugin repositories.

+ * @since 1.0.0 + */ + PLUGIN +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/package-info.java new file mode 100644 index 0000000..148a9b6 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/repository/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Repository components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.repository; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSession.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSession.java new file mode 100644 index 0000000..da63b4a --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSession.java @@ -0,0 +1,156 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.session; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.util.Lists; +import com.github.alexisjehan.mavencheck.core.util.MavenUtils; +import org.apache.maven.model.building.ModelCache; +import org.apache.maven.model.resolution.ModelResolver; +import org.apache.maven.project.ProjectBuildingRequest; +import org.apache.maven.project.ProjectModelResolver; +import org.apache.maven.project.PublicReactorModelCache; +import org.apache.maven.project.PublicReactorModelPool; +import org.apache.maven.settings.Settings; +import org.apache.maven.settings.building.SettingsBuildingException; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; + +import java.util.List; + +/** + *

Class that describes a Maven session.

+ * @since 1.0.0 + */ +public final class MavenSession { + + /** + *

Repository system.

+ * @since 1.0.0 + */ + private final RepositorySystem repositorySystem; + + /** + *

Repository system session.

+ * @since 1.0.0 + */ + private final RepositorySystemSession repositorySystemSession; + + /** + *

{@link List} of remote repositories.

+ * @since 1.0.0 + */ + private final List remoteRepositories; + + /** + *

Model resolver.

+ * @since 1.0.0 + */ + private final ModelResolver modelResolver; + + /** + *

Model cache.

+ * @since 1.0.0 + */ + private final ModelCache modelCache; + + /** + *

Constructor.

+ * @throws MavenSessionException might occur while resolving Maven settings + * @since 1.0.0 + */ + public MavenSession() { + final var serviceLocator = MavenUtils.makeServiceLocator(); + repositorySystem = MavenUtils.makeRepositorySystem(serviceLocator); + final Settings settings; + try { + settings = MavenUtils.makeSettings(); + } catch (final SettingsBuildingException e) { + throw new MavenSessionException(e); + } + final var decryptedSettings = MavenUtils.makeDecryptedSettings(settings); + repositorySystemSession = MavenUtils.makeRepositorySystemSession(settings, decryptedSettings, repositorySystem); + remoteRepositories = MavenUtils.makeRemoteRepositories(settings); + modelResolver = new ProjectModelResolver( + repositorySystemSession, + null, + repositorySystem, + MavenUtils.makeRemoteRepositoryManager(serviceLocator), + remoteRepositories, + ProjectBuildingRequest.RepositoryMerging.POM_DOMINANT, + new PublicReactorModelPool() + ); + modelCache = new PublicReactorModelCache(); + } + + /** + *

Resolve remote repositories using the repository system session.

+ * @param remoteRepositories a {@link List} of remote repositories + * @return the {@link List} of remote repositories + * @throws NullPointerException if the {@link List} of remote repositories or any of them is {@code null} + * @since 1.0.0 + */ + public List resolve(final List remoteRepositories) { + Ensure.notNullAndNotNullElements("remoteRepositories", remoteRepositories); + return repositorySystem.newResolutionRepositories( + repositorySystemSession, + Lists.concat(this.remoteRepositories, remoteRepositories) + ); + } + + /** + *

Request a version range using the repository system session.

+ * @param request a request + * @return the result + * @throws VersionRangeResolutionException might occur while requesting an invalid version range + * @throws NullPointerException if the request is {@code null} + * @since 1.0.0 + */ + public VersionRangeResult request(final VersionRangeRequest request) throws VersionRangeResolutionException { + Ensure.notNull("request", request); + return repositorySystem.resolveVersionRange(repositorySystemSession, request); + } + + /** + *

Get the model resolver.

+ * @return the model resolver + * @since 1.0.0 + */ + public ModelResolver getModelResolver() { + return modelResolver; + } + + /** + *

Get the model cache.

+ * @return the model cache + * @since 1.0.0 + */ + public ModelCache getModelCache() { + return modelCache; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionException.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionException.java new file mode 100644 index 0000000..a14d3db --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionException.java @@ -0,0 +1,49 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.session; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; + +/** + *

Unchecked {@link Exception} related to Maven sessions.

+ * @since 1.0.0 + */ +public final class MavenSessionException extends RuntimeException { + + /** + *

Serial version unique identifier.

+ * @since 1.0.0 + */ + private static final long serialVersionUID = -2024028478245530224L; + + /** + *

Constructor.

+ * @param cause a cause + * @throws NullPointerException if the cause is {@code null} + * @since 1.0.0 + */ + MavenSessionException(final Throwable cause) { + super(Ensure.notNull("cause", cause)); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/package-info.java new file mode 100644 index 0000000..e83b315 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/component/session/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Session components.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.component.session; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/package-info.java new file mode 100644 index 0000000..2745eba --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Core package.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListener.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListener.java new file mode 100644 index 0000000..0eeee9c --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListener.java @@ -0,0 +1,330 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryListener; + +import java.lang.invoke.MethodHandles; + +/** + *

Class that describes a Maven console repository listener.

+ * @since 1.0.0 + */ +final class ConsoleRepositoryListener implements RepositoryListener { + + /** + *

Logger.

+ * @since 1.0.0 + */ + private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass()); + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactDescriptorInvalid(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Invalid {} artifact descriptor: {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getException()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactDescriptorMissing(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Missing {} artifact descriptor", + () -> ToString.toString(event.getArtifact()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactResolving(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Resolving {} artifact from {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactResolved(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Resolved {} artifact from {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactDownloading(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Downloading {} artifact from {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactDownloaded(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Downloaded {} artifact from {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactInstalling(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Installing {} artifact to {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getFile()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactInstalled(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Installed {} artifact to {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getFile()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactDeploying(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Deploying {} artifact to {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void artifactDeployed(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Deployed {} artifact to {}", + () -> ToString.toString(event.getArtifact()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataInvalid(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Invalid {} metadata: {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getException()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataResolving(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Resolving {} metadata from {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataResolved(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Resolved {} metadata from {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataDownloading(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Downloading {} metadata from {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataDownloaded(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Downloaded {} metadata from {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataInstalling(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Installing {} metadata to {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getFile()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataInstalled(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Installed {} metadata to {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getFile()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataDeploying(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Deploying {} metadata to {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getRepository()) + ); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the event is {@code null} + * @since 1.0.0 + */ + @Override + public void metadataDeployed(final RepositoryEvent event) { + Ensure.notNull("event", event); + logger.debug( + "Deployed {} metadata to {}", + () -> ToString.toString(event.getMetadata()), + () -> ToString.toString(event.getRepository()) + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettings.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettings.java new file mode 100644 index 0000000..e6f9399 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettings.java @@ -0,0 +1,128 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import com.github.alexisjehan.javanilla.misc.quality.Equals; +import com.github.alexisjehan.javanilla.misc.quality.HashCode; +import com.github.alexisjehan.javanilla.misc.quality.ToString; +import com.github.alexisjehan.javanilla.misc.tuple.Pair; +import org.apache.maven.settings.Proxy; +import org.apache.maven.settings.Server; + +import java.util.List; + +/** + *

Class that describes Maven decrypted settings.

+ * @since 1.0.0 + */ +final class DecryptedSettings { + + /** + *

{@link List} of proxies.

+ * @since 1.0.0 + */ + private final List proxies; + + /** + *

{@link List} of servers.

+ * @since 1.0.0 + */ + private final List servers; + + /** + *

Constructor.

+ * @param proxies a {@link List} of proxies + * @param servers a {@link List} of servers + * @throws NullPointerException if the {@link List} of proxies, any of them, the {@link List} of servers or any of + * them is {@code null} + * @since 1.0.0 + */ + DecryptedSettings(final List proxies, final List servers) { + Ensure.notNullAndNotNullElements("proxies", proxies); + Ensure.notNullAndNotNullElements("servers", servers); + this.proxies = List.copyOf(proxies); + this.servers = List.copyOf(servers); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof DecryptedSettings)) { + return false; + } + final var other = (DecryptedSettings) object; + return Equals.equals(proxies, other.proxies) + && Equals.equals(servers, other.servers); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public int hashCode() { + return HashCode.of( + HashCode.hashCode(proxies), + HashCode.hashCode(servers) + ); + } + + /** + * {@inheritDoc} + * @since 1.0.0 + */ + @Override + public String toString() { + return ToString.of( + this, + Pair.of("proxies", ToString.toString(proxies)), + Pair.of("servers", ToString.toString(servers)) + ); + } + + /** + *

Get the {@link List} of proxies.

+ * @return the {@link List} of proxies + * @since 1.0.0 + */ + List getProxies() { + return proxies; + } + + /** + *

Get the {@link List} of servers.

+ * @return the {@link List} of servers + * @since 1.0.0 + */ + List getServers() { + return servers; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/GradleUtils.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/GradleUtils.java new file mode 100644 index 0000000..42460e5 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/GradleUtils.java @@ -0,0 +1,92 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.gradle.util.GradleVersion; + +import java.io.File; +import java.util.Optional; +import java.util.regex.Pattern; + +/** + *

Utility class that helps dealing with Gradle.

+ * @since 1.0.0 + */ +public final class GradleUtils { + + /** + *

Gradle version.

+ * @since 1.0.0 + */ + private static final String VERSION = GradleVersion.current().getVersion(); + + /** + *

Pattern to extract the Gradle home from the {@code PATH} environment variable.

+ * @since 1.0.0 + */ + private static final Pattern PATH_PATTERN = Pattern.compile( + "^(.*[/\\\\]+gradle-\\d+\\.\\d+(?:\\.\\d+)?)[/\\\\]+bin[/\\\\]*$" + ); + + /** + *

Constructor not available.

+ * @since 1.0.0 + */ + private GradleUtils() { + // Not available + } + + /** + *

Retrieve an {@link Optional} of the Gradle home.

+ * @return the {@link Optional} of the Gradle home + * @since 1.0.0 + */ + public static Optional retrieveOptionalHome() { + final var optionalGradleHome = SystemUtils.getEnvironmentVariable("GRADLE_HOME"); + if (optionalGradleHome.isPresent()) { + return optionalGradleHome; + } + return Strings.split(File.pathSeparatorChar, SystemUtils.getPathEnvironmentVariable()) + .stream() + .map(segment -> { + final var matcher = PATH_PATTERN.matcher(segment); + if (matcher.find()) { + return Optional.of(matcher.group(1)); + } + return Optional.empty(); + }) + .flatMap(Optional::stream) + .findAny(); + } + + /** + *

Get the Gradle version.

+ * @return the Gradle version + * @since 1.0.0 + */ + public static String getVersion() { + return VERSION; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/MavenUtils.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/MavenUtils.java new file mode 100644 index 0000000..fb53ff0 --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/MavenUtils.java @@ -0,0 +1,494 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import com.github.alexisjehan.javanilla.lang.Strings; +import com.github.alexisjehan.javanilla.misc.quality.Ensure; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.maven.Maven; +import org.apache.maven.repository.internal.MavenRepositorySystemUtils; +import org.apache.maven.settings.Repository; +import org.apache.maven.settings.Settings; +import org.apache.maven.settings.building.DefaultSettingsBuilderFactory; +import org.apache.maven.settings.building.DefaultSettingsBuildingRequest; +import org.apache.maven.settings.building.SettingsBuildingException; +import org.apache.maven.settings.crypto.DefaultSettingsDecrypter; +import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest; +import org.eclipse.aether.DefaultRepositoryCache; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; +import org.eclipse.aether.impl.RemoteRepositoryManager; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.MirrorSelector; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.transport.file.FileTransporterFactory; +import org.eclipse.aether.transport.http.HttpTransporterFactory; +import org.eclipse.aether.util.repository.AuthenticationBuilder; +import org.eclipse.aether.util.repository.ConservativeAuthenticationSelector; +import org.eclipse.aether.util.repository.ConservativeProxySelector; +import org.eclipse.aether.util.repository.DefaultAuthenticationSelector; +import org.eclipse.aether.util.repository.DefaultMirrorSelector; +import org.eclipse.aether.util.repository.DefaultProxySelector; +import org.sonatype.plexus.components.cipher.DefaultPlexusCipher; +import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; + +import java.io.File; +import java.lang.invoke.MethodHandles; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; + +/** + *

Utility class that helps dealing with Maven.

+ * @since 1.0.0 + */ +public final class MavenUtils { + + /** + *

Maven version.

+ * @since 1.0.0 + */ + private static final String VERSION = Maven.class.getPackage().getImplementationVersion(); + + /** + *

Pattern to extract the Maven home from the {@code PATH} environment variable.

+ * @since 1.0.0 + */ + private static final Pattern PATH_PATTERN = Pattern.compile( + "^(.*[/\\\\]+apache-maven-\\d+\\.\\d+\\.\\d+)[/\\\\]+bin[/\\\\]*$" + ); + + /** + *

User {@code repository} directory.

+ * @since 1.0.0 + */ + private static final Path USER_REPOSITORY_DIRECTORY = SystemUtils.getUserHomeDirectory().resolve( + Path.of(".m2", "repository") + ); + + /** + *

User {@code settings.xml} file.

+ * @since 1.0.0 + */ + private static final Path USER_SETTINGS_FILE = SystemUtils.getUserHomeDirectory().resolve( + Path.of(".m2", "settings.xml") + ); + + /** + *

User {@code settings-security.xml} file.

+ * @since 1.0.0 + */ + private static final Path USER_SETTINGS_SECURITY_FILE = SystemUtils.getUserHomeDirectory().resolve( + Path.of(".m2", "settings-security.xml") + ); + + /** + *

Logger.

+ * @since 1.0.0 + */ + private static final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass()); + + /** + *

Constructor not available.

+ * @since 1.0.0 + */ + private MavenUtils() { + // Not available + } + + /** + *

Retrieve an {@link Optional} of the Maven home.

+ * @return the {@link Optional} of the Maven home + * @since 1.0.0 + */ + public static Optional retrieveOptionalGlobalHome() { + return Strings.split(File.pathSeparatorChar, SystemUtils.getPathEnvironmentVariable()) + .stream() + .map(segment -> { + final var matcher = PATH_PATTERN.matcher(segment); + if (matcher.find()) { + return Optional.of(matcher.group(1)); + } + return Optional.empty(); + }) + .flatMap(Optional::stream) + .findAny(); + } + + /** + *

Retrieve an {@link Optional} of the global {@code settings.xml} file.

+ * @return the {@link Optional} of the global {@code settings.xml} file + * @since 1.0.0 + */ + public static Optional retrieveOptionalGlobalSettingsFile() { + return retrieveOptionalGlobalHome() + .map(globalHome -> Path.of(globalHome, "conf", "settings.xml")); + } + + /** + *

Create a remote repository from an identifier and an URL.

+ * @param id an identifier + * @param url an URL + * @return the remote repository + * @throws NullPointerException if the identifier or the URL is {@code null} + * @throws IllegalArgumentException if the identifier or the URL is empty + * @since 1.0.0 + */ + public static RemoteRepository createRemoteRepository(final String id, final String url) { + Ensure.notNullAndNotEmpty("id", id); + Ensure.notNullAndNotEmpty("url", url); + final var repository = new Repository(); + repository.setId(id); + repository.setUrl(url); + return toRemoteRepository(repository); + } + + /** + *

Convert a repository to a remote repository.

+ * @param repository a repository + * @return the remote repository + * @throws NullPointerException if the repository is {@code null} + * @since 1.0.0 + */ + static RemoteRepository toRemoteRepository(final Repository repository) { + Ensure.notNull("repository", repository); + final var builder = new RemoteRepository.Builder( + repository.getId(), + repository.getLayout(), + repository.getUrl() + ); + final var releasesPolicy = repository.getReleases(); + if (null != releasesPolicy) { + builder.setReleasePolicy( + new RepositoryPolicy( + releasesPolicy.isEnabled(), + releasesPolicy.getUpdatePolicy(), + releasesPolicy.getChecksumPolicy() + ) + ); + } + final var snapshotsPolicy = repository.getSnapshots(); + if (null != snapshotsPolicy) { + builder.setSnapshotPolicy( + new RepositoryPolicy( + snapshotsPolicy.isEnabled(), + snapshotsPolicy.getUpdatePolicy(), + snapshotsPolicy.getChecksumPolicy() + ) + ); + } + return builder.build(); + } + + /** + *

Make a service locator.

+ * @return the service locator + * @since 1.0.0 + */ + public static ServiceLocator makeServiceLocator() { + return MavenRepositorySystemUtils.newServiceLocator() + .addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class) + .addService(TransporterFactory.class, FileTransporterFactory.class) + .addService(TransporterFactory.class, HttpTransporterFactory.class); + } + + /** + *

Make a repository system.

+ * @param serviceLocator a service locator + * @return the repository system + * @throws NullPointerException if the service locator is {@code null} + * @since 1.0.0 + */ + public static RepositorySystem makeRepositorySystem(final ServiceLocator serviceLocator) { + Ensure.notNull("serviceLocator", serviceLocator); + return serviceLocator.getService(RepositorySystem.class); + } + + /** + *

Make a remote repository manager.

+ * @param serviceLocator a service locator + * @return the remote repository manager + * @throws NullPointerException if the service locator is {@code null} + * @since 1.0.0 + */ + public static RemoteRepositoryManager makeRemoteRepositoryManager(final ServiceLocator serviceLocator) { + Ensure.notNull("serviceLocator", serviceLocator); + return serviceLocator.getService(RemoteRepositoryManager.class); + } + + /** + *

Make settings using default global and user {@code settings.xml} files.

+ * @return settings + * @throws SettingsBuildingException might occur while resolving settings + * @since 1.0.0 + */ + public static Settings makeSettings() throws SettingsBuildingException { + return makeSettings(retrieveOptionalGlobalSettingsFile().orElse(null), USER_SETTINGS_FILE); + } + + /** + *

Make settings using custom global and user {@code settings.xml} files.

+ * @param globalSettingsFile a global {@code settings.xml} file or {@code null} + * @param userSettingsFile a user {@code settings.xml} file or {@code null} + * @return settings + * @throws SettingsBuildingException might occur while resolving settings + * @since 1.0.0 + */ + static Settings makeSettings( + final Path globalSettingsFile, + final Path userSettingsFile + ) throws SettingsBuildingException { + final var result = new DefaultSettingsBuilderFactory() + .newInstance() + .build( + new DefaultSettingsBuildingRequest() + .setGlobalSettingsFile( + null != globalSettingsFile + ? globalSettingsFile.toFile() + : null + ) + .setUserSettingsFile( + null != userSettingsFile + ? userSettingsFile.toFile() + : null + ) + .setSystemProperties(System.getProperties()) + ); + for (final var exception : result.getProblems()) { + logger.warn(exception::getMessage); + } + return result.getEffectiveSettings(); + } + + /** + *

Make decrypted settings using the default user {@code settings-security.xml} file.

+ * @param settings settings + * @return decrypted settings + * @throws NullPointerException if settings are {@code null} + * @since 1.0.0 + */ + public static DecryptedSettings makeDecryptedSettings(final Settings settings) { + return makeDecryptedSettings(settings, USER_SETTINGS_SECURITY_FILE); + } + + /** + *

Make decrypted settings using a custom user {@code settings-security.xml} file.

+ * @param settings settings + * @param userSettingsSecurityFile a user {@code settings-security.xml} file or {@code null} + * @return decrypted settings + * @throws NullPointerException if settings are {@code null} + * @since 1.0.0 + */ + static DecryptedSettings makeDecryptedSettings( + final Settings settings, + final Path userSettingsSecurityFile + ) { + Ensure.notNull("settings", settings); + final var result = new DefaultSettingsDecrypter( + new DefaultSecDispatcher( + new DefaultPlexusCipher(), + Map.of(), + null != userSettingsSecurityFile + ? userSettingsSecurityFile.toString() + : null + ) + ).decrypt(new DefaultSettingsDecryptionRequest(settings)); + for (final var exception : result.getProblems()) { + logger.warn(exception::getMessage); + } + return new DecryptedSettings(result.getProxies(), result.getServers()); + } + + /** + *

Make a local repository.

+ * @param settings settings + * @return the local repository + * @throws NullPointerException if settings are {@code null} + * @since 1.0.0 + */ + static LocalRepository makeLocalRepository(final Settings settings) { + Ensure.notNull("settings", settings); + final var settingsLocalRepository = settings.getLocalRepository(); + if (null != settingsLocalRepository) { + return new LocalRepository(settingsLocalRepository); + } + return new LocalRepository(USER_REPOSITORY_DIRECTORY.toFile()); + } + + /** + *

Make a proxy selector.

+ * @param decryptedSettings decrypted settings + * @return the proxy selector + * @throws NullPointerException if decrypted settings are {@code null} + * @since 1.0.0 + */ + static ProxySelector makeProxySelector(final DecryptedSettings decryptedSettings) { + Ensure.notNull("decryptedSettings", decryptedSettings); + final var proxySelector = new DefaultProxySelector(); + for (final var proxy : decryptedSettings.getProxies()) { + proxySelector.add( + new Proxy( + proxy.getProtocol(), + proxy.getHost(), + proxy.getPort(), + new AuthenticationBuilder() + .addUsername(proxy.getUsername()) + .addPassword(proxy.getPassword()) + .build() + ), + proxy.getNonProxyHosts() + ); + } + return new ConservativeProxySelector(proxySelector); + } + + /** + *

Make an authentication selector.

+ * @param decryptedSettings decrypted settings + * @return the authentication selector + * @throws NullPointerException if decrypted settings are {@code null} + * @since 1.0.0 + */ + static AuthenticationSelector makeAuthenticationSelector(final DecryptedSettings decryptedSettings) { + Ensure.notNull("decryptedSettings", decryptedSettings); + final var authenticationSelector = new DefaultAuthenticationSelector(); + for (final var server : decryptedSettings.getServers()) { + authenticationSelector.add( + server.getId(), + new AuthenticationBuilder() + .addUsername(server.getUsername()) + .addPassword(server.getPassword()) + .addPrivateKey(server.getPrivateKey(), server.getPassphrase()) + .build() + ); + } + return new ConservativeAuthenticationSelector(authenticationSelector); + } + + /** + *

Make a mirror selector.

+ * @param settings settings + * @return the mirror selector + * @throws NullPointerException if settings are {@code null} + * @since 1.0.0 + */ + static MirrorSelector makeMirrorSelector(final Settings settings) { + Ensure.notNull("settings", settings); + final var mirrorSelector = new DefaultMirrorSelector(); + for (final var mirror : settings.getMirrors()) { + mirrorSelector.add( + mirror.getId(), + mirror.getUrl(), + mirror.getLayout(), + false, + mirror.isBlocked(), + mirror.getMirrorOf(), + mirror.getMirrorOfLayouts() + ); + } + return mirrorSelector; + } + + /** + *

Make a repository system session.

+ * @param settings settings + * @param decryptedSettings decrypted settings + * @param repositorySystem a repository system + * @return the repository system session + * @throws NullPointerException if settings, decrypted settings or the repository system are {@code null} + * @since 1.0.0 + */ + public static RepositorySystemSession makeRepositorySystemSession( + final Settings settings, + final DecryptedSettings decryptedSettings, + final RepositorySystem repositorySystem + ) { + Ensure.notNull("settings", settings); + Ensure.notNull("decryptedSettings", decryptedSettings); + Ensure.notNull("repositorySystem", repositorySystem); + final var repositorySystemSession = MavenRepositorySystemUtils.newSession(); + return repositorySystemSession + .setOffline(settings.isOffline()) + .setLocalRepositoryManager( + repositorySystem.newLocalRepositoryManager( + repositorySystemSession, + makeLocalRepository(settings) + ) + ) + .setProxySelector(makeProxySelector(decryptedSettings)) + .setAuthenticationSelector(makeAuthenticationSelector(decryptedSettings)) + .setMirrorSelector(makeMirrorSelector(settings)) + .setRepositoryListener(new ConsoleRepositoryListener()) + .setCache(new DefaultRepositoryCache()) + .setSystemProperties(System.getProperties()); + } + + /** + *

Make a {@link List} of remote repositories.

+ * @param settings settings + * @return the {@link List} of remote repositories + * @throws NullPointerException if settings are {@code null} + * @since 1.0.0 + */ + public static List makeRemoteRepositories(final Settings settings) { + Ensure.notNull("settings", settings); + final var remoteRepositories = new ArrayList(); + final var activeProfileIds = settings.getActiveProfiles(); + for (final var entry : settings.getProfilesAsMap().entrySet()) { + final var id = entry.getKey(); + final var profile = entry.getValue(); + final var profileActivation = profile.getActivation(); + if (activeProfileIds.contains(id) || null != profileActivation && profileActivation.isActiveByDefault()) { + for (final var repository : profile.getRepositories()) { + remoteRepositories.add(toRemoteRepository(repository)); + } + for (final var pluginRepository : profile.getPluginRepositories()) { + remoteRepositories.add(toRemoteRepository(pluginRepository)); + } + } + } + return remoteRepositories; + } + + /** + *

Get the Maven version.

+ * @return the Maven version + * @since 1.0.0 + */ + public static String getVersion() { + return VERSION; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/SystemUtils.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/SystemUtils.java new file mode 100644 index 0000000..5ec127d --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/SystemUtils.java @@ -0,0 +1,87 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import com.github.alexisjehan.javanilla.misc.quality.Ensure; + +import java.nio.file.Path; +import java.util.Optional; + +/** + *

Utility class that helps dealing with the system.

+ * @since 1.0.0 + */ +public final class SystemUtils { + + /** + *

{@code PATH} environment variable.

+ * @since 1.0.0 + */ + private static final String PATH_ENVIRONMENT_VARIABLE = System.getenv("PATH"); + + /** + *

User home directory.

+ * @since 1.0.0 + */ + private static final Path USER_HOME_DIRECTORY = Path.of(System.getProperty("user.home")); + + /** + *

Constructor not available.

+ * @since 1.0.0 + */ + private SystemUtils() { + // Not available + } + + /** + *

Get an {@link Optional} environment variable for the given name.

+ * @param name a name + * @return the {@link Optional} environment variable + * @throws NullPointerException if the name is {@code null} + * @throws IllegalArgumentException if the name is empty + * @since 1.0.0 + */ + public static Optional getEnvironmentVariable(final String name) { + Ensure.notNullAndNotEmpty("name", name); + return Optional.ofNullable(System.getenv(name)); + } + + /** + *

Get the {@code PATH} environment variable.

+ * @return the {@code PATH} environment variable + * @since 1.0.0 + */ + public static String getPathEnvironmentVariable() { + return PATH_ENVIRONMENT_VARIABLE; + } + + /** + *

Get the user home directory.

+ * @return the user home directory + * @since 1.0.0 + */ + public static Path getUserHomeDirectory() { + return USER_HOME_DIRECTORY; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/core/util/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/core/util/package-info.java new file mode 100644 index 0000000..f65519b --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/core/util/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Utilities.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck.core.util; \ No newline at end of file diff --git a/src/main/java/com/github/alexisjehan/mavencheck/package-info.java b/src/main/java/com/github/alexisjehan/mavencheck/package-info.java new file mode 100644 index 0000000..8d553ef --- /dev/null +++ b/src/main/java/com/github/alexisjehan/mavencheck/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Main package.

+ * @since 1.0.0 + */ +package com.github.alexisjehan.mavencheck; \ No newline at end of file diff --git a/src/main/java/org/apache/maven/project/PublicReactorModelCache.java b/src/main/java/org/apache/maven/project/PublicReactorModelCache.java new file mode 100644 index 0000000..bebd94b --- /dev/null +++ b/src/main/java/org/apache/maven/project/PublicReactorModelCache.java @@ -0,0 +1,39 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.apache.maven.project; + +/** + *

Public access to the {@link ReactorModelCache} class.

+ * @since 1.0.0 + */ +public final class PublicReactorModelCache extends ReactorModelCache { + + /** + *

Constructor by default.

+ * @since 1.0.0 + */ + public PublicReactorModelCache() { + // By default + } +} \ No newline at end of file diff --git a/src/main/java/org/apache/maven/project/PublicReactorModelPool.java b/src/main/java/org/apache/maven/project/PublicReactorModelPool.java new file mode 100644 index 0000000..59a267d --- /dev/null +++ b/src/main/java/org/apache/maven/project/PublicReactorModelPool.java @@ -0,0 +1,39 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.apache.maven.project; + +/** + *

Public access to the {@link ReactorModelPool} class.

+ * @since 1.0.0 + */ +public final class PublicReactorModelPool extends ReactorModelPool { + + /** + *

Constructor by default.

+ * @since 1.0.0 + */ + public PublicReactorModelPool() { + // By default + } +} \ No newline at end of file diff --git a/src/main/java/org/apache/maven/project/package-info.java b/src/main/java/org/apache/maven/project/package-info.java new file mode 100644 index 0000000..a2569c6 --- /dev/null +++ b/src/main/java/org/apache/maven/project/package-info.java @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

{@link org.apache.maven.project} additional custom classes.

+ * @since 1.0.0 + */ +package org.apache.maven.project; \ No newline at end of file diff --git a/src/main/resources/init.gradle b/src/main/resources/init.gradle new file mode 100644 index 0000000..aa674fe --- /dev/null +++ b/src/main/resources/init.gradle @@ -0,0 +1,29 @@ +settingsEvaluated { + settings -> allprojects { + task repositories { + doLast { + [ + 'NORMAL': [ + '6.8' <= gradle.gradleVersion + ? settings.dependencyResolutionManagement.repositories // Since Gradle 6.8 + : [], + repositories + ], + 'PLUGIN': [ + settings.pluginManagement.repositories + ] + ].each { + repositoryType, repositories -> + repositories + .flatten() + .findAll { + repository -> repository instanceof MavenArtifactRepository + } + .each { + repository -> println "$repositoryType:${repository.name}:${repository.url}" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..def2504 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/ApplicationIT.java b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationIT.java new file mode 100644 index 0000000..4f02389 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationIT.java @@ -0,0 +1,115 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import static org.assertj.core.api.Assertions.assertThat; + +final class ApplicationIT { + + @Test + void testRun(@TempDir final Path tmpDirectory) throws IOException { + final var tmpMavenBuildFile = tmpDirectory.resolve("pom.xml"); + Files.copy( + Path.of("src", "test", "resources", "pom_it.xml"), + tmpMavenBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var tmpGroovyBuildDirectory = tmpDirectory.resolve("groovy"); + Files.createDirectory(tmpGroovyBuildDirectory); + final var tmpGroovyBuildFile = tmpGroovyBuildDirectory.resolve("build.gradle"); + Files.copy( + Path.of("src", "test", "resources", "build_it.gradle"), + tmpGroovyBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var tmpKotlinBuildDirectory = tmpDirectory.resolve("kotlin"); + Files.createDirectory(tmpKotlinBuildDirectory); + final var tmpKotlinBuildFile = tmpKotlinBuildDirectory.resolve("build.gradle.kts"); + Files.copy( + Path.of("src", "test", "resources", "build_it.gradle.kts"), + tmpKotlinBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + try (final var outputStream = new ByteArrayOutputStream()) { + try (final var printStream = new PrintStream(outputStream)) { + final var application = new Application(printStream); + application.run(tmpDirectory, false, false); + } + assertThat(outputStream.toString()).matches( + "^" + + "3 build file\\(s\\) found, checking for artifact updates\\R" + + "\\R" + + ".+[/\\\\]pom\\.xml\\R" + + "\\[DEPENDENCY] com\\.google\\.android\\.material:material 1\\.0\\.0 -> " + + "\\d+\\.\\d+\\.\\d+\\R" + + "\\[DEPENDENCY] com\\.google\\.guava:guava 10\\.0 -> \\d+\\.\\d+(?:\\.\\d+)?-jre\\R" + + "\\[DEPENDENCY] org\\.springframework:spring-core 3\\.0\\.0\\.RELEASE -> " + + "\\d+\\.\\d+\\.\\d+\\R" + + "\\[PROFILE DEPENDENCY] com\\.google\\.guava:guava 23\\.1-jre -> " + + "\\d+\\.\\d+(?:\\.\\d+)?-jre\\R" + + "\\[PROFILE DEPENDENCY] com\\.google\\.guava:guava 23\\.1-android -> " + + "\\d+\\.\\d+(?:\\.\\d+)?-android\\R" + + "5 artifact update\\(s\\) available\\R" + + "\\R" + + ".+[/\\\\]build\\.gradle\\R" + + "\\[IMPLEMENTATION] com\\.google\\.android\\.material:material 1\\.0\\.0 -> " + + "\\d+\\.\\d+\\.\\d+\\R" + + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 10\\.0 -> \\d+\\.\\d+(?:\\.\\d+)?-jre\\R" + + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-jre -> " + + "\\d+\\.\\d+(?:\\.\\d+)?-jre\\R" + + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-android -> " + + "\\d+\\.\\d+(?:\\.\\d+)?-android\\R" + + "\\[IMPLEMENTATION] org\\.springframework:spring-core 3\\.0\\.0\\.RELEASE -> " + + "\\d+\\.\\d+\\.\\d+\\R" + + "5 artifact update\\(s\\) available\\R" + + "\\R" + + ".+[/\\\\]build\\.gradle\\.kts\\R" + + "\\[IMPLEMENTATION] com\\.google\\.android\\.material:material 1\\.0\\.0 -> " + + "\\d+\\.\\d+\\.\\d+\\R" + + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 10\\.0 -> \\d+\\.\\d+(?:\\.\\d+)?-jre\\R" + + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-jre -> " + + "\\d+\\.\\d+(?:\\.\\d+)?-jre\\R" + + "\\[IMPLEMENTATION] com\\.google\\.guava:guava 23\\.1-android -> " + + "\\d+\\.\\d+(?:\\.\\d+)?-android\\R" + + "\\[IMPLEMENTATION] org\\.springframework:spring-core 3\\.0\\.0\\.RELEASE -> " + + "\\d+\\.\\d+\\.\\d+\\R" + + "5 artifact update\\(s\\) available\\R" + + "\\R" + + "3/3 build file\\(s\\) checked, 15 artifact update\\(s\\) available\\R" + + "\\R" + + "$" + ); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/ApplicationTest.java b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationTest.java new file mode 100644 index 0000000..0ac6f74 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/ApplicationTest.java @@ -0,0 +1,192 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck; + +import com.github.alexisjehan.mavencheck.core.Service; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.ArtifactType; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactUpdateVersion; +import com.github.alexisjehan.mavencheck.core.component.build.Build; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.build.resolver.BuildResolveException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +@ExtendWith(MockitoExtension.class) +final class ApplicationTest { + + @Mock + private Service mockedService; + + @Test + void testConstructorInvalid() { + try (final var printStream = new PrintStream(OutputStream.nullOutputStream())) { + assertThatNullPointerException() + .isThrownBy(() -> new Application(null, printStream, false)); + assertThatNullPointerException() + .isThrownBy(() -> new Application(printStream, null, false)); + } + } + + @Test + void testRun() throws IOException { + final var path1 = Path.of("path1"); + final var path2 = Path.of("path2"); + final var path3 = Path.of("path3"); + final var buildFile1 = new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml")); + final var buildFile2 = new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle")); + final var buildFile3 = new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts")); + final var artifact = new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id"), + "1.0.0" + ); + final var build1 = new Build( + buildFile1, + List.of(), + List.of(artifact) + ); + final var build2 = new Build( + buildFile2, + List.of(), + List.of(artifact) + ); + Mockito.when(mockedService.findBuildFiles(Mockito.argThat(path1::equals))) + .thenReturn(List.of()); + Mockito.when(mockedService.findBuildFiles(Mockito.argThat(path2::equals))) + .thenReturn(List.of(buildFile1)); + Mockito.when(mockedService.findBuildFiles(Mockito.argThat(path3::equals))) + .thenReturn(List.of(buildFile1, buildFile2, buildFile3)); + Mockito.when(mockedService.findBuild(Mockito.argThat(buildFile1::equals))) + .thenReturn(build1); + Mockito.when(mockedService.findBuild(Mockito.argThat(buildFile2::equals))) + .thenReturn(build2); + Mockito.when(mockedService.findBuild(Mockito.argThat(buildFile3::equals))) + .thenThrow(BuildResolveException.class); + Mockito.when(mockedService.findArtifactUpdateVersions(Mockito.argThat(build1::equals), Mockito.anyBoolean())) + .thenReturn(List.of()); + Mockito.when(mockedService.findArtifactUpdateVersions(Mockito.argThat(build2::equals), Mockito.anyBoolean())) + .thenReturn(List.of(new ArtifactUpdateVersion(artifact, "2.0.0"))); + try (final var mockedApplication = Mockito.mockStatic(Application.class)) { + mockedApplication.when(Application::createService) + .thenReturn(mockedService); + try (final var printStream = new PrintStream(OutputStream.nullOutputStream())) { + final var application = new Application(printStream); + assertThatNoException().isThrownBy(application::run); + assertThatNoException().isThrownBy(() -> application.run("-h")); + assertThatNoException().isThrownBy(() -> application.run("-i")); + assertThatNoException().isThrownBy(() -> application.run("-s")); + assertThatNoException().isThrownBy(() -> application.run("-v")); + assertThatNoException().isThrownBy(() -> application.run("directory_not-found")); + assertThatNoException().isThrownBy(() -> application.run(path1.toString())); + assertThatNoException().isThrownBy(() -> application.run(path2.toString())); + assertThatNoException().isThrownBy(() -> application.run(path3.toString())); + assertThatNoException().isThrownBy(() -> application.run(path1, false, true)); + assertThatNoException().isThrownBy(() -> application.run(path2, false, true)); + assertThatNoException().isThrownBy(() -> application.run(path3, false, true)); + } + } + } + + @Test + void testRunInvalid() { + try (final var printStream = new PrintStream(OutputStream.nullOutputStream())) { + final var application = new Application(printStream); + assertThatNullPointerException() + .isThrownBy(() -> application.run((String[]) null)); + assertThatNullPointerException() + .isThrownBy(() -> application.run((String) null)); + assertThatNullPointerException() + .isThrownBy(() -> application.run(null, false, false)); + } + } + + @Test + void testCreateService() { + assertThatNoException().isThrownBy(Application::createService); + } + + @Test + void testToStringException() { + assertThat(Application.toString(new Exception(" foo "))).isEqualTo("foo"); + assertThat(Application.toString(new Exception(" foo ", new Exception(" bar ")))).isEqualTo("bar"); + } + + @Test + void testToStringExceptionInvalid() { + assertThatNullPointerException().isThrownBy(() -> Application.toString((Exception) null)); + } + + @Test + void testToStringPath() { + assertThat(Application.toString(Path.of("." + File.separator + "pom.xml"))) + .isEqualTo("pom.xml"); + assertThat(Application.toString(Path.of("." + File.separator + "foo" + File.separator + "pom.xml"))) + .isEqualTo("foo" + File.separator + "pom.xml"); + } + + @Test + void testToStringPathInvalid() { + assertThatNullPointerException().isThrownBy(() -> Application.toString((Path) null)); + } + + @Test + void testToStringArtifactType() { + assertThat(Application.toString(MavenArtifactType.DEPENDENCY)).isEqualTo("DEPENDENCY"); + assertThat(Application.toString(MavenArtifactType.BUILD_PLUGIN)).isEqualTo("BUILD PLUGIN"); + } + + @Test + void testToStringArtifactTypeInvalid() { + assertThatNullPointerException().isThrownBy(() -> Application.toString((ArtifactType) null)); + } + + @Test + void testToStringArtifactIdentifier() { + assertThat(Application.toString(new ArtifactIdentifier("foo-group-id", "foo-artifact-id"))) + .isEqualTo("foo-group-id:foo-artifact-id"); + } + + @Test + void testToStringArtifactIdentifierInvalid() { + assertThatNullPointerException().isThrownBy(() -> Application.toString((ArtifactIdentifier) null)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/ServiceTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/ServiceTest.java new file mode 100644 index 0000000..da10bac --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/ServiceTest.java @@ -0,0 +1,357 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core; + +import com.github.alexisjehan.javanilla.util.function.ThrowableConsumer; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactUpdateVersion; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver.ArtifactAvailableVersionsResolver; +import com.github.alexisjehan.mavencheck.core.component.build.Build; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.build.resolver.GradleBuildResolver; +import com.github.alexisjehan.mavencheck.core.component.build.resolver.MavenBuildResolver; +import com.github.alexisjehan.mavencheck.core.component.filter.artifact.ArtifactFilter; +import com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser.ArtifactFilterParser; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import com.github.alexisjehan.mavencheck.core.util.SystemUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +@ExtendWith(MockitoExtension.class) +final class ServiceTest { + + @Mock + private MavenSession mockedMavenSession; + + @Mock + private MavenBuildResolver mockedMavenBuildResolver; + + @Mock + private GradleBuildResolver mockedGradleBuildResolver; + + @Mock + private ArtifactAvailableVersionsResolver mockedArtifactAvailableVersionsResolver; + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy( + () -> new Service( + null + ) + ); + assertThatNullPointerException().isThrownBy( + () -> new Service( + null, + mockedArtifactAvailableVersionsResolver + ) + ); + assertThatNullPointerException().isThrownBy( + () -> new Service( + Collections.singleton(null), + mockedArtifactAvailableVersionsResolver + ) + ); + assertThatNullPointerException().isThrownBy( + () -> new Service( + Set.of(mockedMavenBuildResolver, mockedGradleBuildResolver), + null + ) + ); + } + + @Test + void testFindBuildFiles(@TempDir final Path tmpDirectory) throws IOException { + final var service = new Service(mockedMavenSession); + final var rootMavenFile = tmpDirectory.resolve(Path.of("pom.xml")); + final var fooMavenFile = tmpDirectory.resolve(Path.of("foo", "pom.xml")); + final var fooGradleGroovyFile = tmpDirectory.resolve(Path.of("foo", "build.gradle")); + final var fooGradleKotlinFile = tmpDirectory.resolve(Path.of("foo", "build.gradle.kts")); + final var foo10MavenFile = tmpDirectory.resolve(Path.of("foo", "10", "pom.xml")); + final var foo1GradleGroovyFile = tmpDirectory.resolve(Path.of("foo", "1", "build.gradle")); + final var foo2GradleKotlinFile = tmpDirectory.resolve(Path.of("foo", "2", "build.gradle.kts")); + final var barMavenFile = tmpDirectory.resolve(Path.of("bar", "pom.xml")); + final var barGradleGroovyFile = tmpDirectory.resolve(Path.of("bar", "build.gradle")); + final var barGradleKotlinFile = tmpDirectory.resolve(Path.of("bar", "build.gradle.kts")); + final var bar10MavenFile = tmpDirectory.resolve(Path.of("bar", "10", "pom.xml")); + final var bar1GradleGroovyFile = tmpDirectory.resolve(Path.of("bar", "1", "build.gradle")); + final var bar2GradleKotlinFile = tmpDirectory.resolve(Path.of("bar", "2", "build.gradle.kts")); + Stream.of( + rootMavenFile, + fooMavenFile, + fooGradleGroovyFile, + fooGradleKotlinFile, + foo10MavenFile, + foo1GradleGroovyFile, + foo2GradleKotlinFile, + barMavenFile, + barGradleGroovyFile, + barGradleKotlinFile, + bar10MavenFile, + bar1GradleGroovyFile, + bar2GradleKotlinFile + ).forEach( + ThrowableConsumer.sneaky(file -> { + Files.createDirectories(file.getParent()); + Files.createFile(file); + }) + ); + assertThat(service.findBuildFiles(tmpDirectory)).containsExactly( + new BuildFile(BuildFileType.MAVEN, rootMavenFile), + new BuildFile(BuildFileType.GRADLE_GROOVY, barGradleGroovyFile), + new BuildFile(BuildFileType.GRADLE_KOTLIN, barGradleKotlinFile), + new BuildFile(BuildFileType.MAVEN, barMavenFile), + new BuildFile(BuildFileType.GRADLE_GROOVY, bar1GradleGroovyFile), + new BuildFile(BuildFileType.GRADLE_KOTLIN, bar2GradleKotlinFile), + new BuildFile(BuildFileType.MAVEN, bar10MavenFile), + new BuildFile(BuildFileType.GRADLE_GROOVY, fooGradleGroovyFile), + new BuildFile(BuildFileType.GRADLE_KOTLIN, fooGradleKotlinFile), + new BuildFile(BuildFileType.MAVEN, fooMavenFile), + new BuildFile(BuildFileType.GRADLE_GROOVY, foo1GradleGroovyFile), + new BuildFile(BuildFileType.GRADLE_KOTLIN, foo2GradleKotlinFile), + new BuildFile(BuildFileType.MAVEN, foo10MavenFile) + ); + } + + @Test + void testFindBuildFilesInvalid() throws IOException { + final var service = new Service(mockedMavenSession); + assertThatNullPointerException() + .isThrownBy(() -> service.findBuildFiles(null)); + assertThatIllegalArgumentException() + .isThrownBy(() -> service.findBuildFiles(Path.of("directory_not-found"))); + } + + @Test + void testFindBuild() throws IOException { + Mockito.when(mockedMavenBuildResolver.resolve(Mockito.notNull())) + .then(invocation -> new Build(invocation.getArgument(0), List.of(), List.of())); + Mockito.when(mockedMavenBuildResolver.getFileTypes()) + .thenCallRealMethod(); + Mockito.when(mockedGradleBuildResolver.resolve(Mockito.notNull())) + .then(invocation -> new Build(invocation.getArgument(0), List.of(), List.of())); + Mockito.when(mockedGradleBuildResolver.getFileTypes()) + .thenCallRealMethod(); + assertThat( + new Service( + Set.of(), + mockedArtifactAvailableVersionsResolver + ) + ).satisfies(service -> { + assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies( + buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy( + () -> service.findBuild(buildFile) + ) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies( + buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy( + () -> service.findBuild(buildFile) + ) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies( + buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy( + () -> service.findBuild(buildFile) + ) + ); + }); + assertThat( + new Service( + Set.of(mockedMavenBuildResolver), + mockedArtifactAvailableVersionsResolver + ) + ).satisfies(service -> { + assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies( + buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies( + buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy( + () -> service.findBuild(buildFile) + ) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies( + buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy( + () -> service.findBuild(buildFile) + ) + ); + }); + assertThat( + new Service( + Set.of(mockedGradleBuildResolver), + mockedArtifactAvailableVersionsResolver + ) + ).satisfies(service -> { + assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies( + buildFile -> assertThatExceptionOfType(NoSuchElementException.class).isThrownBy( + () -> service.findBuild(buildFile) + ) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies( + buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies( + buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile) + ); + }); + assertThat( + new Service( + Set.of(mockedMavenBuildResolver, mockedGradleBuildResolver), + mockedArtifactAvailableVersionsResolver + ) + ).satisfies(service -> { + assertThat(new BuildFile(BuildFileType.MAVEN, Path.of("pom.xml"))).satisfies( + buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("build.gradle"))).satisfies( + buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile) + ); + assertThat(new BuildFile(BuildFileType.GRADLE_KOTLIN, Path.of("build.gradle.kts"))).satisfies( + buildFile -> assertThat(service.findBuild(buildFile).getFile()).isSameAs(buildFile) + ); + }); + } + + @Test + void testFindBuildInvalid() throws IOException { + final var service = new Service(mockedMavenSession); + assertThatNullPointerException().isThrownBy(() -> service.findBuild(null)); + } + + @Test + void testFindArtifactUpdateVersions() throws IOException { + final var service = new Service( + Set.of(mockedMavenBuildResolver, mockedGradleBuildResolver), + mockedArtifactAvailableVersionsResolver + ); + final var fooIdentifier = new ArtifactIdentifier("foo-group-id", "foo-artifact-id"); + final var barIdentifier = new ArtifactIdentifier("bar-group-id", "bar-artifact-id"); + Mockito + .when( + mockedArtifactAvailableVersionsResolver.resolve( + Mockito.argThat( + artifact -> null != artifact && fooIdentifier.equals(artifact.getIdentifier()) + ), + Mockito.notNull() + ) + ) + .then( + invocation -> new ArtifactAvailableVersions( + invocation.getArgument(0), + List.of("1.0.0", "2.0.0") + ) + ); + Mockito + .when( + mockedArtifactAvailableVersionsResolver.resolve( + Mockito.argThat( + artifact -> null != artifact && barIdentifier.equals(artifact.getIdentifier()) + ), + Mockito.notNull() + ) + ) + .then( + invocation -> new ArtifactAvailableVersions( + invocation.getArgument(0), + List.of() + ) + ); + final var fooArtifact1 = new Artifact<>(MavenArtifactType.DEPENDENCY, fooIdentifier, "1.0.0"); + final var fooArtifact2 = new Artifact<>(MavenArtifactType.DEPENDENCY, fooIdentifier, "2.0.0-SNAPSHOT"); + final var fooArtifact3 = new Artifact<>(MavenArtifactType.DEPENDENCY, fooIdentifier, "2.0.0"); + final var barArtifact = new Artifact<>(MavenArtifactType.DEPENDENCY, barIdentifier, "1.1.0"); + final var build = new Build( + new BuildFile(BuildFileType.MAVEN, Path.of("src", "test", "resources", "pom.xml")), + List.of(), + List.of(fooArtifact1, fooArtifact2, fooArtifact3, barArtifact) + ); + assertThat(service.findArtifactUpdateVersions(build, false)).containsExactly( + new ArtifactUpdateVersion(fooArtifact1, "2.0.0"), + new ArtifactUpdateVersion(fooArtifact2, "2.0.0") + ); + assertThat(service.findArtifactUpdateVersions(build, true)).containsExactly( + new ArtifactUpdateVersion(fooArtifact1, "2.0.0") + ); + } + + @Test + void testFindArtifactUpdateVersionsInvalid() throws IOException { + final var service = new Service(mockedMavenSession); + assertThatNullPointerException() + .isThrownBy(() -> service.findArtifactUpdateVersions(null, false)); + } + + @Test + void testCreateUserArtifactFilter(@TempDir final Path tmpDirectory) throws IOException { + final var ignoreFile = tmpDirectory.resolve(Path.of(".mvnchk-ignore")); + try (final var mockedArtifactFilterParser = Mockito.mockStatic(ArtifactFilterParser.class)) { + mockedArtifactFilterParser.when(() -> ArtifactFilterParser.parse(Mockito.notNull())) + .thenReturn(ArtifactFilter.ALL); + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(SystemUtils::getUserHomeDirectory) + .thenReturn(tmpDirectory); + assertThat(Service.createUserArtifactFilter()).isSameAs(ArtifactFilter.NONE); + Files.createFile(ignoreFile); + assertThat(Service.createUserArtifactFilter()).isSameAs(ArtifactFilter.ALL); + } + } + } + + @Test + void testCreateBuildArtifactFilter(@TempDir final Path tmpDirectory) throws IOException { + final var ignoreFile = tmpDirectory.resolve(Path.of(".mvnchk-ignore")); + try (final var mockedArtifactFilterParser = Mockito.mockStatic(ArtifactFilterParser.class)) { + mockedArtifactFilterParser.when(() -> ArtifactFilterParser.parse(Mockito.notNull())) + .thenReturn(ArtifactFilter.ALL); + final var buildFile = new BuildFile(BuildFileType.MAVEN, tmpDirectory.resolve("pom.xml")); + assertThat(Service.createBuildArtifactFilter(buildFile)).isSameAs(ArtifactFilter.NONE); + Files.createFile(ignoreFile); + assertThat(Service.createBuildArtifactFilter(buildFile)).isSameAs(ArtifactFilter.ALL); + } + } + + @Test + void testCreateBuildArtifactFilterInvalid() { + assertThatNullPointerException().isThrownBy(() -> Service.createBuildArtifactFilter(null)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifierTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifierTest.java new file mode 100644 index 0000000..cbff3ab --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactIdentifierTest.java @@ -0,0 +1,83 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ArtifactIdentifierTest { + + private static final String GROUP_ID = "foo-group-id"; + private static final String ARTIFACT_ID = "foo-artifact-id"; + private static final String OTHER_GROUP_ID = "bar-group-id"; + private static final String OTHER_ARTIFACT_ID = "bar-artifact-id"; + + private final ArtifactIdentifier artifactIdentifier = new ArtifactIdentifier(GROUP_ID, ARTIFACT_ID); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new ArtifactIdentifier(null, ARTIFACT_ID)); + assertThatIllegalArgumentException().isThrownBy(() -> new ArtifactIdentifier(Strings.EMPTY, ARTIFACT_ID)); + assertThatNullPointerException().isThrownBy(() -> new ArtifactIdentifier(GROUP_ID, null)); + assertThatIllegalArgumentException().isThrownBy(() -> new ArtifactIdentifier(GROUP_ID, Strings.EMPTY)); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(artifactIdentifier.equals(artifactIdentifier)).isTrue(); + assertThat(artifactIdentifier).isNotEqualTo(new Object()); + assertThat(new ArtifactIdentifier(GROUP_ID, ARTIFACT_ID)).satisfies(otherArtifactIdentifier -> { + assertThat(artifactIdentifier).isNotSameAs(otherArtifactIdentifier); + assertThat(artifactIdentifier).isEqualTo(otherArtifactIdentifier); + assertThat(artifactIdentifier).hasSameHashCodeAs(otherArtifactIdentifier); + assertThat(artifactIdentifier).hasToString(otherArtifactIdentifier.toString()); + }); + assertThat(new ArtifactIdentifier(OTHER_GROUP_ID, ARTIFACT_ID)).satisfies(otherArtifactIdentifier -> { + assertThat(artifactIdentifier).isNotSameAs(otherArtifactIdentifier); + assertThat(artifactIdentifier).isNotEqualTo(otherArtifactIdentifier); + assertThat(artifactIdentifier).doesNotHaveSameHashCodeAs(otherArtifactIdentifier); + assertThat(artifactIdentifier).doesNotHaveToString(otherArtifactIdentifier.toString()); + }); + assertThat(new ArtifactIdentifier(GROUP_ID, OTHER_ARTIFACT_ID)).satisfies(otherArtifactIdentifier -> { + assertThat(artifactIdentifier).isNotSameAs(otherArtifactIdentifier); + assertThat(artifactIdentifier).isNotEqualTo(otherArtifactIdentifier); + assertThat(artifactIdentifier).doesNotHaveSameHashCodeAs(otherArtifactIdentifier); + assertThat(artifactIdentifier).doesNotHaveToString(otherArtifactIdentifier.toString()); + }); + } + + @Test + void testGetGroupId() { + assertThat(artifactIdentifier.getGroupId()).isEqualTo(GROUP_ID); + } + + @Test + void testGetArtifactId() { + assertThat(artifactIdentifier.getArtifactId()).isEqualTo(ARTIFACT_ID); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactTest.java new file mode 100644 index 0000000..da9c51e --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/ArtifactTest.java @@ -0,0 +1,112 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact; + +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ArtifactTest { + + private static final MavenArtifactType TYPE = MavenArtifactType.DEPENDENCY; + private static final ArtifactIdentifier IDENTIFIER = new ArtifactIdentifier( + "foo-group-id", + "foo-artifact-id" + ); + private static final String VERSION = "foo-version"; + private static final MavenArtifactType OTHER_TYPE = MavenArtifactType.BUILD_PLUGIN; + private static final ArtifactIdentifier OTHER_IDENTIFIER = new ArtifactIdentifier( + "bar-group-id", + "bar-artifact-id" + ); + + private final Artifact artifact = new Artifact<>(TYPE, IDENTIFIER, VERSION); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new Artifact<>(null, IDENTIFIER, VERSION)); + assertThatNullPointerException().isThrownBy(() -> new Artifact<>(TYPE, null, VERSION)); + } + + @Test + void testWith() { + assertThat(artifact.with(TYPE)).satisfies(otherArtifact -> { + assertThat(otherArtifact.getType()).isEqualTo(TYPE); + assertThat(artifact.getIdentifier()).isEqualTo(otherArtifact.getIdentifier()); + assertThat(artifact.getOptionalVersion()).isEqualTo(otherArtifact.getOptionalVersion()); + }); + assertThat(artifact.with(OTHER_TYPE)).satisfies(otherArtifact -> { + assertThat(otherArtifact.getType()).isEqualTo(OTHER_TYPE); + assertThat(artifact.getIdentifier()).isEqualTo(otherArtifact.getIdentifier()); + assertThat(artifact.getOptionalVersion()).isEqualTo(otherArtifact.getOptionalVersion()); + }); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(artifact.equals(artifact)).isTrue(); + assertThat(artifact).isNotEqualTo(new Object()); + assertThat(new Artifact<>(TYPE, IDENTIFIER, VERSION)).satisfies(otherArtifact -> { + assertThat(artifact).isNotSameAs(otherArtifact); + assertThat(artifact).isEqualTo(otherArtifact); + assertThat(artifact).hasSameHashCodeAs(otherArtifact); + assertThat(artifact).hasToString(otherArtifact.toString()); + }); + assertThat(new Artifact<>(OTHER_TYPE, IDENTIFIER, VERSION)).satisfies(otherArtifact -> { + assertThat(artifact).isNotSameAs(otherArtifact); + assertThat(artifact).isNotEqualTo(otherArtifact); + assertThat(artifact).doesNotHaveSameHashCodeAs(otherArtifact); + assertThat(artifact).doesNotHaveToString(otherArtifact.toString()); + }); + assertThat(new Artifact<>(TYPE, OTHER_IDENTIFIER, VERSION)).satisfies(otherArtifact -> { + assertThat(artifact).isNotSameAs(otherArtifact); + assertThat(artifact).isNotEqualTo(otherArtifact); + assertThat(artifact).doesNotHaveSameHashCodeAs(otherArtifact); + assertThat(artifact).doesNotHaveToString(otherArtifact.toString()); + }); + assertThat(new Artifact<>(TYPE, IDENTIFIER)).satisfies(otherArtifact -> { + assertThat(artifact).isNotSameAs(otherArtifact); + assertThat(artifact).isNotEqualTo(otherArtifact); + assertThat(artifact).doesNotHaveSameHashCodeAs(otherArtifact); + assertThat(artifact).doesNotHaveToString(otherArtifact.toString()); + }); + } + + @Test + void testGetType() { + assertThat(artifact.getType()).isEqualTo(TYPE); + } + + @Test + void testGetIdentifier() { + assertThat(artifact.getIdentifier()).isEqualTo(IDENTIFIER); + } + + @Test + void testGetOptionalVersion() { + assertThat(artifact.getOptionalVersion()).hasValue(VERSION); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactTypeTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactTypeTest.java new file mode 100644 index 0000000..eb4c964 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/GradleArtifactTypeTest.java @@ -0,0 +1,54 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.type; + +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +final class GradleArtifactTypeTest { + + @Test + void testDependenciesTaskName() { + assertThat(GradleArtifactType.COMPILE_ONLY.dependenciesTaskName()).isEqualTo("compileOnly"); + } + + @Test + void testIsClasspath() { + assertThat(GradleArtifactType.COMPILE_CLASSPATH.isClasspath()).isTrue(); + assertThat(GradleArtifactType.COMPILE_ONLY.isClasspath()).isFalse(); + } + + @Test + void testIsDeprecated() { + assertThat(GradleArtifactType.COMPILE.isDeprecated()).isTrue(); + assertThat(GradleArtifactType.COMPILE_ONLY.isDeprecated()).isFalse(); + } + + @Test + void testGetRepositoryType() { + assertThat(GradleArtifactType.COMPILE_ONLY.getRepositoryType()).isEqualTo(RepositoryType.NORMAL); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactTypeTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactTypeTest.java new file mode 100644 index 0000000..8a08899 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/type/MavenArtifactTypeTest.java @@ -0,0 +1,38 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.type; + +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +final class MavenArtifactTypeTest { + + @Test + void testGetRepositoryType() { + assertThat(MavenArtifactType.DEPENDENCY.getRepositoryType()).isEqualTo(RepositoryType.NORMAL); + assertThat(MavenArtifactType.BUILD_PLUGIN.getRepositoryType()).isEqualTo(RepositoryType.PLUGIN); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersionsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersionsTest.java new file mode 100644 index 0000000..2bc2413 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactAvailableVersionsTest.java @@ -0,0 +1,129 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ArtifactAvailableVersionsTest { + + private static final Artifact ARTIFACT = new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id") + ); + private static final List AVAILABLE_VERSIONS = List.of("foo-version"); + private static final Artifact OTHER_ARTIFACT = new Artifact<>( + MavenArtifactType.BUILD_PLUGIN, + new ArtifactIdentifier("bar-group-id", "bar-artifact-id") + ); + private static final List OTHER_AVAILABLE_VERSIONS = List.of(); + + private final ArtifactAvailableVersions artifactAvailableVersions = new ArtifactAvailableVersions( + ARTIFACT, + AVAILABLE_VERSIONS + ); + + @Test + void testConstructorImmutable() { + final var availableVersions = new ArrayList<>(AVAILABLE_VERSIONS); + final var artifactAvailableVersions = new ArtifactAvailableVersions(ARTIFACT, availableVersions); + availableVersions.clear(); + assertThat(artifactAvailableVersions.getAvailableVersions()).containsExactlyElementsOf(AVAILABLE_VERSIONS); + } + + @Test + void testConstructorInvalid() { + assertThatNullPointerException() + .isThrownBy(() -> new ArtifactAvailableVersions(null, AVAILABLE_VERSIONS)); + assertThatNullPointerException() + .isThrownBy(() -> new ArtifactAvailableVersions(ARTIFACT, null)); + assertThatNullPointerException() + .isThrownBy(() -> new ArtifactAvailableVersions(ARTIFACT, Collections.singletonList(null))); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(artifactAvailableVersions.equals(artifactAvailableVersions)).isTrue(); + assertThat(artifactAvailableVersions).isNotEqualTo(new Object()); + assertThat(new ArtifactAvailableVersions(ARTIFACT, AVAILABLE_VERSIONS)) + .satisfies(otherArtifactAvailableVersions -> { + assertThat(artifactAvailableVersions) + .isNotSameAs(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .isEqualTo(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .hasSameHashCodeAs(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .hasToString(otherArtifactAvailableVersions.toString()); + }); + assertThat(new ArtifactAvailableVersions(OTHER_ARTIFACT, AVAILABLE_VERSIONS)) + .satisfies(otherArtifactAvailableVersions -> { + assertThat(artifactAvailableVersions) + .isNotSameAs(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .isNotEqualTo(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .doesNotHaveSameHashCodeAs(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .doesNotHaveToString(otherArtifactAvailableVersions.toString()); + }); + assertThat(new ArtifactAvailableVersions(ARTIFACT, OTHER_AVAILABLE_VERSIONS)) + .satisfies(otherArtifactAvailableVersions -> { + assertThat(artifactAvailableVersions) + .isNotSameAs(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .isNotEqualTo(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .doesNotHaveSameHashCodeAs(otherArtifactAvailableVersions); + assertThat(artifactAvailableVersions) + .doesNotHaveToString(otherArtifactAvailableVersions.toString()); + }); + } + + @Test + void testGetArtifact() { + assertThat(artifactAvailableVersions.getArtifact()).isEqualTo(ARTIFACT); + } + + @Test + void testGetAvailableVersions() { + assertThat(artifactAvailableVersions.getAvailableVersions()).isEqualTo(AVAILABLE_VERSIONS); + } + + @Test + void testGetAvailableVersionsImmutable() { + final var availableVersions = artifactAvailableVersions.getAvailableVersions(); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(availableVersions::clear); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersionTest.java new file mode 100644 index 0000000..0d1c087 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/ArtifactUpdateVersionTest.java @@ -0,0 +1,91 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version; + +import com.github.alexisjehan.javanilla.lang.Strings; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ArtifactUpdateVersionTest { + + private static final Artifact ARTIFACT = new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id") + ); + private static final String UPDATE_VERSION = "foo-version"; + private static final Artifact OTHER_ARTIFACT = new Artifact<>( + MavenArtifactType.BUILD_PLUGIN, + new ArtifactIdentifier("bar-group-id", "bar-artifact-id") + ); + private static final String OTHER_UPDATE_VERSION = "bar-version"; + + private final ArtifactUpdateVersion artifactUpdateVersion = new ArtifactUpdateVersion(ARTIFACT, UPDATE_VERSION); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new ArtifactUpdateVersion(null, UPDATE_VERSION)); + assertThatNullPointerException().isThrownBy(() -> new ArtifactUpdateVersion(ARTIFACT, null)); + assertThatIllegalArgumentException().isThrownBy(() -> new ArtifactUpdateVersion(ARTIFACT, Strings.EMPTY)); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(artifactUpdateVersion.equals(artifactUpdateVersion)).isTrue(); + assertThat(artifactUpdateVersion).isNotEqualTo(new Object()); + assertThat(new ArtifactUpdateVersion(ARTIFACT, UPDATE_VERSION)).satisfies(otherArtifactUpdateVersion -> { + assertThat(artifactUpdateVersion).isNotSameAs(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).isEqualTo(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).hasSameHashCodeAs(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).hasToString(otherArtifactUpdateVersion.toString()); + }); + assertThat(new ArtifactUpdateVersion(OTHER_ARTIFACT, UPDATE_VERSION)).satisfies(otherArtifactUpdateVersion -> { + assertThat(artifactUpdateVersion).isNotSameAs(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).isNotEqualTo(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).doesNotHaveSameHashCodeAs(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).doesNotHaveToString(otherArtifactUpdateVersion.toString()); + }); + assertThat(new ArtifactUpdateVersion(ARTIFACT, OTHER_UPDATE_VERSION)).satisfies(otherArtifactUpdateVersion -> { + assertThat(artifactUpdateVersion).isNotSameAs(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).isNotEqualTo(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).doesNotHaveSameHashCodeAs(otherArtifactUpdateVersion); + assertThat(artifactUpdateVersion).doesNotHaveToString(otherArtifactUpdateVersion.toString()); + }); + } + + @Test + void testGetArtifact() { + assertThat(artifactUpdateVersion.getArtifact()).isEqualTo(ARTIFACT); + } + + @Test + void testGetUpdateVersion() { + assertThat(artifactUpdateVersion.getUpdateVersion()).isEqualTo(UPDATE_VERSION); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverIT.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverIT.java new file mode 100644 index 0000000..f1fd4e6 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverIT.java @@ -0,0 +1,120 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +final class MavenArtifactAvailableVersionsResolverIT { + + private final MavenArtifactAvailableVersionsResolver mavenArtifactAvailableVersionsResolver + = new MavenArtifactAvailableVersionsResolver(new MavenSession()); + + @Test + void testResolve() { + assertThat( + new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("org.apache.maven", "maven-core") + ) + ).satisfies(artifact -> { + assertThat( + mavenArtifactAvailableVersionsResolver.resolve( + artifact, + List.of() + ).getAvailableVersions() + ).isEmpty(); + assertThat( + mavenArtifactAvailableVersionsResolver.resolve( + artifact, + List.of( + new Repository( + RepositoryType.NORMAL, + "central", + "https://repo.maven.apache.org/maven2" + ) + ) + ).getAvailableVersions() + ).isNotEmpty(); + assertThat( + mavenArtifactAvailableVersionsResolver.resolve( + artifact, + List.of( + new Repository( + RepositoryType.PLUGIN, + "central", + "https://repo.maven.apache.org/maven2" + ) + ) + ).getAvailableVersions() + ).isEmpty(); + }); + assertThat( + new Artifact<>( + MavenArtifactType.BUILD_PLUGIN, + new ArtifactIdentifier("org.apache.maven.plugins", "maven-compiler-plugin") + ) + ).satisfies(artifact -> { + assertThat( + mavenArtifactAvailableVersionsResolver.resolve( + artifact, + List.of() + ).getAvailableVersions() + ).isEmpty(); + assertThat( + mavenArtifactAvailableVersionsResolver.resolve( + artifact, + List.of( + new Repository( + RepositoryType.NORMAL, + "central", + "https://repo.maven.apache.org/maven2" + ) + ) + ).getAvailableVersions() + ).isNotEmpty(); + assertThat( + mavenArtifactAvailableVersionsResolver.resolve( + artifact, + List.of( + new Repository( + RepositoryType.PLUGIN, + "central", + "https://repo.maven.apache.org/maven2" + ) + ) + ).getAvailableVersions() + ).isNotEmpty(); + }); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverTest.java new file mode 100644 index 0000000..42205a1 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/artifact/version/resolver/MavenArtifactAvailableVersionsResolverTest.java @@ -0,0 +1,160 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.artifact.version.resolver; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.artifact.version.ArtifactAvailableVersions; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.version.Version; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.AdditionalAnswers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +@ExtendWith(MockitoExtension.class) +final class MavenArtifactAvailableVersionsResolverTest { + + private static final class SimpleVersion implements Version { + + private final String string; + + private SimpleVersion(final String string) { + this.string = string; + } + + @Override + public int compareTo(final Version o) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return string; + } + } + + @Mock + private MavenSession mockedMavenSession; + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new MavenArtifactAvailableVersionsResolver(null)); + } + + @Test + void testResolve() throws VersionRangeResolutionException { + final var versionRangeResult = new VersionRangeResult(new VersionRangeRequest()); + versionRangeResult.setVersions( + List.of( + new SimpleVersion("foo-version1"), + new SimpleVersion("foo-version2") + ) + ); + versionRangeResult.addException(new RuntimeException()); + Mockito.when(mockedMavenSession.resolve(Mockito.notNull())) + .then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(mockedMavenSession.request(Mockito.notNull())) + .thenReturn(versionRangeResult); + final var mavenArtifactAvailableVersionsResolver = new MavenArtifactAvailableVersionsResolver( + mockedMavenSession + ); + final var repositories = List.of( + new Repository(RepositoryType.NORMAL, "foo-id", "https://foo-host"), + new Repository(RepositoryType.PLUGIN, "foo-plugin-id", "https://foo-plugin-host") + ); + assertThat( + new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id"), + "foo-version" + ) + ).satisfies( + artifact -> assertThat(mavenArtifactAvailableVersionsResolver.resolve(artifact, repositories)) + .isEqualTo(new ArtifactAvailableVersions(artifact, List.of("foo-version1", "foo-version2"))) + ); + assertThat( + new Artifact<>( + MavenArtifactType.BUILD_PLUGIN, + new ArtifactIdentifier("foo-plugin-group-id", "foo-plugin-artifact-id"), + "foo-plugin-version" + ) + ).satisfies( + artifact -> assertThat(mavenArtifactAvailableVersionsResolver.resolve(artifact, repositories)) + .isEqualTo(new ArtifactAvailableVersions(artifact, List.of("foo-version1", "foo-version2"))) + ); + } + + @Test + void testResolveInvalid() throws VersionRangeResolutionException { + Mockito.when(mockedMavenSession.resolve(Mockito.notNull())) + .then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(mockedMavenSession.request(Mockito.notNull())) + .thenThrow(VersionRangeResolutionException.class); + final var mavenArtifactAvailableVersionsResolver = new MavenArtifactAvailableVersionsResolver( + mockedMavenSession + ); + final var artifact = new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id"), + "foo-version" + ); + final var repositories = List.of( + new Repository(RepositoryType.NORMAL, "foo-id", "https://foo-host"), + new Repository(RepositoryType.PLUGIN, "foo-plugin-id", "https://foo-plugin-host") + ); + assertThatNullPointerException() + .isThrownBy( + () -> mavenArtifactAvailableVersionsResolver.resolve(null, repositories) + ); + assertThatNullPointerException() + .isThrownBy( + () -> mavenArtifactAvailableVersionsResolver.resolve(artifact, null) + ); + assertThatNullPointerException() + .isThrownBy( + () -> mavenArtifactAvailableVersionsResolver.resolve(artifact, Collections.singletonList(null)) + ); + assertThatExceptionOfType(AssertionError.class) + .isThrownBy( + () -> mavenArtifactAvailableVersionsResolver.resolve(artifact, repositories) + ) + .withCauseInstanceOf(VersionRangeResolutionException.class); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/BuildTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/BuildTest.java new file mode 100644 index 0000000..91b7b69 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/BuildTest.java @@ -0,0 +1,151 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class BuildTest { + + private static final BuildFile FILE = new BuildFile(BuildFileType.MAVEN, Path.of("foo-file")); + private static final List REPOSITORIES = List.of( + new Repository(RepositoryType.NORMAL, "foo-id", "https://foo-host") + ); + private static final List> ARTIFACTS = List.of( + new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id"), + "foo-version" + ) + ); + private static final BuildFile OTHER_FILE = new BuildFile(BuildFileType.GRADLE_GROOVY, Path.of("bar-file")); + private static final List OTHER_REPOSITORIES = List.of( + new Repository(RepositoryType.PLUGIN, "bar-id", "https://bar-host") + ); + private static final List> OTHER_ARTIFACTS = List.of( + new Artifact<>( + MavenArtifactType.BUILD_PLUGIN, + new ArtifactIdentifier("bar-group-id", "bar-artifact-id") + ) + ); + + private final Build build = new Build(FILE, REPOSITORIES, ARTIFACTS); + + @Test + void testConstructorImmutable() { + final var repositories = new ArrayList<>(REPOSITORIES); + final var artifacts = new ArrayList<>(ARTIFACTS); + final var build = new Build(FILE, repositories, artifacts); + repositories.clear(); + artifacts.clear(); + assertThat(build.getRepositories()).containsExactlyElementsOf(REPOSITORIES); + assertThat(build.getArtifacts()).containsExactlyElementsOf(ARTIFACTS); + } + + @Test + void testConstructorInvalid() { + assertThatNullPointerException() + .isThrownBy(() -> new Build(null, REPOSITORIES, ARTIFACTS)); + assertThatNullPointerException() + .isThrownBy(() -> new Build(FILE, null, ARTIFACTS)); + assertThatNullPointerException() + .isThrownBy(() -> new Build(FILE, Collections.singletonList(null), ARTIFACTS)); + assertThatNullPointerException() + .isThrownBy(() -> new Build(FILE, REPOSITORIES, null)); + assertThatNullPointerException() + .isThrownBy(() -> new Build(FILE, REPOSITORIES, Collections.singletonList(null))); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(build.equals(build)).isTrue(); + assertThat(build).isNotEqualTo(new Object()); + assertThat(new Build(FILE, REPOSITORIES, ARTIFACTS)).satisfies(otherBuild -> { + assertThat(build).isNotSameAs(otherBuild); + assertThat(build).isEqualTo(otherBuild); + assertThat(build).hasSameHashCodeAs(otherBuild); + assertThat(build).hasToString(otherBuild.toString()); + }); + assertThat(new Build(OTHER_FILE, REPOSITORIES, ARTIFACTS)).satisfies(otherBuild -> { + assertThat(build).isNotSameAs(otherBuild); + assertThat(build).isNotEqualTo(otherBuild); + assertThat(build).doesNotHaveSameHashCodeAs(otherBuild); + assertThat(build).doesNotHaveToString(otherBuild.toString()); + }); + assertThat(new Build(FILE, OTHER_REPOSITORIES, ARTIFACTS)).satisfies(otherBuild -> { + assertThat(build).isNotSameAs(otherBuild); + assertThat(build).isNotEqualTo(otherBuild); + assertThat(build).doesNotHaveSameHashCodeAs(otherBuild); + assertThat(build).doesNotHaveToString(otherBuild.toString()); + }); + assertThat(new Build(FILE, REPOSITORIES, OTHER_ARTIFACTS)).satisfies(otherBuild -> { + assertThat(build).isNotSameAs(otherBuild); + assertThat(build).isNotEqualTo(otherBuild); + assertThat(build).doesNotHaveSameHashCodeAs(otherBuild); + assertThat(build).doesNotHaveToString(otherBuild.toString()); + }); + } + + @Test + void testGetFile() { + assertThat(build.getFile()).isEqualTo(FILE); + } + + @Test + void testGetRepositories() { + assertThat(build.getRepositories()).isEqualTo(REPOSITORIES); + } + + @Test + void testGetRepositoriesImmutable() { + final var repositories = build.getRepositories(); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(repositories::clear); + } + + @Test + void testGetArtifacts() { + assertThat(build.getArtifacts()).isEqualTo(ARTIFACTS); + } + + @Test + void testGetArtifactsImmutable() { + final var artifacts = build.getArtifacts(); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(artifacts::clear); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTest.java new file mode 100644 index 0000000..7d7f1c7 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTest.java @@ -0,0 +1,81 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.file; + +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class BuildFileTest { + + private static final BuildFileType TYPE = BuildFileType.MAVEN; + private static final Path FILE = Path.of("foo-file"); + private static final BuildFileType OTHER_TYPE = BuildFileType.GRADLE_GROOVY; + private static final Path OTHER_FILE = Path.of("bar-file"); + + private final BuildFile buildFile = new BuildFile(TYPE, FILE); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new BuildFile(null, FILE)); + assertThatNullPointerException().isThrownBy(() -> new BuildFile(TYPE, null)); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(buildFile.equals(buildFile)).isTrue(); + assertThat(buildFile).isNotEqualTo(new Object()); + assertThat(new BuildFile(TYPE, FILE)).satisfies(otherBuildFile -> { + assertThat(buildFile).isNotSameAs(otherBuildFile); + assertThat(buildFile).isEqualTo(otherBuildFile); + assertThat(buildFile).hasSameHashCodeAs(otherBuildFile); + assertThat(buildFile).hasToString(otherBuildFile.toString()); + }); + assertThat(new BuildFile(OTHER_TYPE, FILE)).satisfies(otherBuildFile -> { + assertThat(buildFile).isNotSameAs(otherBuildFile); + assertThat(buildFile).isNotEqualTo(otherBuildFile); + assertThat(buildFile).doesNotHaveSameHashCodeAs(otherBuildFile); + assertThat(buildFile).doesNotHaveToString(otherBuildFile.toString()); + }); + assertThat(new BuildFile(TYPE, OTHER_FILE)).satisfies(otherBuildFile -> { + assertThat(buildFile).isNotSameAs(otherBuildFile); + assertThat(buildFile).isNotEqualTo(otherBuildFile); + assertThat(buildFile).doesNotHaveSameHashCodeAs(otherBuildFile); + assertThat(buildFile).doesNotHaveToString(otherBuildFile.toString()); + }); + } + + @Test + void testGetType() { + assertThat(buildFile.getType()).isEqualTo(TYPE); + } + + @Test + void testGetFile() { + assertThat(buildFile.getFile()).isEqualTo(FILE); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTypeTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTypeTest.java new file mode 100644 index 0000000..e9a316d --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/file/BuildFileTypeTest.java @@ -0,0 +1,51 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.file; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class BuildFileTypeTest { + + @Test + void testGetFileName() { + assertThat(BuildFileType.MAVEN.getFileName()).isEqualTo("pom.xml"); + } + + @Test + void testOptionalValueOf() { + assertThat(BuildFileType.optionalValueOf("pom.xml")).hasValue(BuildFileType.MAVEN); + assertThat(BuildFileType.optionalValueOf("unknown")).isEmpty(); + } + + @Test + void testOptionalValueOfInvalid() { + assertThatNullPointerException().isThrownBy(() -> BuildFileType.optionalValueOf(null)); + assertThatIllegalArgumentException().isThrownBy(() -> BuildFileType.optionalValueOf(Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveExceptionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveExceptionTest.java new file mode 100644 index 0000000..132df1e --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/BuildResolveExceptionTest.java @@ -0,0 +1,62 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.javanilla.io.Serializables; +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class BuildResolveExceptionTest { + + private static final String MESSAGE = "foo-message"; + private static final Exception CAUSE = new Exception("foo-cause"); + + private final BuildResolveException buildResolveException1 = new BuildResolveException(MESSAGE); + private final BuildResolveException buildResolveException2 = new BuildResolveException(CAUSE); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> { + throw new BuildResolveException((String) null); + }); + assertThatIllegalArgumentException().isThrownBy(() -> { + throw new BuildResolveException(Strings.EMPTY); + }); + assertThatNullPointerException().isThrownBy(() -> { + throw new BuildResolveException((Throwable) null); + }); + } + + @Test + void testSerializable() { + assertThat(Serializables.deserialize(Serializables.serialize(buildResolveException1))) + .hasSameClassAs(buildResolveException1); + assertThat(Serializables.deserialize(Serializables.serialize(buildResolveException2))) + .hasSameClassAs(buildResolveException2); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverIT.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverIT.java new file mode 100644 index 0000000..2587226 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverIT.java @@ -0,0 +1,392 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.GradleArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.util.GradleUtils; +import org.gradle.tooling.GradleConnector; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Mockito; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +final class GradleBuildResolverIT { + + private final GradleBuildResolver gradleBuildResolver = new GradleBuildResolver(); + + @Test + void testUpToDate() { + assertThat(GradleUtils.getVersion()).startsWith("7.6"); // Ensure tests are up-to-date after updating Gradle + } + + @ParameterizedTest + @EnabledForJreRange(max = JRE.JAVA_13) + @ValueSource(strings = {"4.8", "4.9", "4.10", "5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "6.0", "6.1", "6.2"}) + void testResolveUntilGradle67UntilJava13(final String gradleVersion, @TempDir final Path tmpDirectory) { + testResolveUntilGradle67(gradleVersion, tmpDirectory); + } + + @ParameterizedTest + @EnabledForJreRange(max = JRE.JAVA_17) + @ValueSource(strings = {"6.3", "6.4", "6.5", "6.6", "6.7"}) + void testResolveUntilGradle67UntilJava17(final String gradleVersion, @TempDir final Path tmpDirectory) { + testResolveUntilGradle67(gradleVersion, tmpDirectory); + } + + @ParameterizedTest + @EnabledForJreRange(max = JRE.JAVA_17) + @ValueSource(strings = {"6.8", "6.9", "7.0", "7.1", "7.2"}) + void testResolveSinceGradle68UntilJava17(final String gradleVersion, @TempDir final Path tmpDirectory) { + testResolveSinceGradle68(gradleVersion, tmpDirectory); + } + + @ParameterizedTest + @EnabledForJreRange(max = JRE.JAVA_18) + @ValueSource(strings = {"7.3", "7.4", "7.5"}) + void testResolveSinceGradle68UntilJava18(final String gradleVersion, @TempDir final Path tmpDirectory) { + testResolveSinceGradle68(gradleVersion, tmpDirectory); + } + + @ParameterizedTest + @ValueSource(strings = "7.6") + void testResolveSinceGradle68UntilJavaLatest(final String gradleVersion, @TempDir final Path tmpDirectory) { + testResolveSinceGradle68(gradleVersion, tmpDirectory); + } + + private void testResolveUntilGradle67(final String gradleVersion, final Path tmpDirectory) { + try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) { + mockedGradleUtils.when(GradleUtils::retrieveOptionalHome) + .thenReturn(Optional.empty()); + assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> { + final var connector = GradleConnector.newConnector() + .useGradleVersion(gradleVersion); + try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) { + mockedGradleConnector.when(GradleConnector::newConnector) + .thenReturn(connector); + final var tmpBuildDirectory = tmpDirectory.resolve("groovy"); + Files.createDirectory(tmpBuildDirectory); + final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle"); + final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle"); + Files.copy( + Path.of("src", "test", "resources", "build_it.gradle"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + Files.copy( + Path.of("src", "test", "resources", "settings_it_until-6.7.gradle"), + tmpSettingsFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + final var build = gradleBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "MavenRepo", + "https://repo.maven.apache.org/maven2/" + ), + new Repository( + RepositoryType.NORMAL, + "google", + "https://maven.google.com" + ), + new Repository( + RepositoryType.PLUGIN, + "maven", + "https://plugin-management.example.com" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.android.material", "material"), + "1.0.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "10.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-jre" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-android" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("org.springframework", "spring-core"), + "3.0.0.RELEASE" + ) + ); + } + }); + assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> { + final var connector = GradleConnector.newConnector() + .useGradleVersion(gradleVersion); + try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) { + mockedGradleConnector.when(GradleConnector::newConnector) + .thenReturn(connector); + final var tmpBuildDirectory = tmpDirectory.resolve("kotlin"); + Files.createDirectory(tmpBuildDirectory); + final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle.kts"); + final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle.kts"); + Files.copy( + Path.of("src", "test", "resources", "build_it.gradle.kts"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + Files.copy( + Path.of("src", "test", "resources", "settings_it_until-6.7.gradle.kts"), + tmpSettingsFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + final var build = gradleBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "MavenRepo", + "https://repo.maven.apache.org/maven2/" + ), + new Repository( + RepositoryType.NORMAL, + "google", + "https://maven.google.com" + ), + new Repository( + RepositoryType.PLUGIN, + "maven", + "https://plugin-management.example.com" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.android.material", "material"), + "1.0.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "10.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-jre" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-android" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("org.springframework", "spring-core"), + "3.0.0.RELEASE" + ) + ); + } + }); + } + } + + private void testResolveSinceGradle68(final String gradleVersion, final Path tmpDirectory) { + try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) { + mockedGradleUtils.when(GradleUtils::retrieveOptionalHome) + .thenReturn(Optional.empty()); + assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> { + final var connector = GradleConnector.newConnector() + .useGradleVersion(gradleVersion); + try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) { + mockedGradleConnector.when(GradleConnector::newConnector) + .thenReturn(connector); + final var tmpBuildDirectory = tmpDirectory.resolve("groovy"); + Files.createDirectory(tmpBuildDirectory); + final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle"); + final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle"); + Files.copy( + Path.of("src", "test", "resources", "build_it.gradle"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + Files.copy( + Path.of("src", "test", "resources", "settings_it_since-6.8.gradle"), + tmpSettingsFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + final var build = gradleBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "maven", + "https://dependency-resolution-management.example.com" + ), + new Repository( + RepositoryType.NORMAL, + "MavenRepo", + "https://repo.maven.apache.org/maven2/" + ), + new Repository( + RepositoryType.NORMAL, + "google", + "https://maven.google.com" + ), + new Repository( + RepositoryType.PLUGIN, + "maven", + "https://plugin-management.example.com" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.android.material", "material"), + "1.0.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "10.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-jre" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-android" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("org.springframework", "spring-core"), + "3.0.0.RELEASE" + ) + ); + } + }); + assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> { + final var connector = GradleConnector.newConnector() + .useGradleVersion(gradleVersion); + try (final var mockedGradleConnector = Mockito.mockStatic(GradleConnector.class)) { + mockedGradleConnector.when(GradleConnector::newConnector) + .thenReturn(connector); + final var tmpBuildDirectory = tmpDirectory.resolve("kotlin"); + Files.createDirectory(tmpBuildDirectory); + final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle.kts"); + final var tmpSettingsFile = tmpBuildDirectory.resolve("settings.gradle.kts"); + Files.copy( + Path.of("src", "test", "resources", "build_it.gradle.kts"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + Files.copy( + Path.of("src", "test", "resources", "settings_it_since-6.8.gradle.kts"), + tmpSettingsFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + final var build = gradleBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "maven", + "https://dependency-resolution-management.example.com" + ), + new Repository( + RepositoryType.NORMAL, + "MavenRepo", + "https://repo.maven.apache.org/maven2/" + ), + new Repository( + RepositoryType.NORMAL, + "google", + "https://maven.google.com" + ), + new Repository( + RepositoryType.PLUGIN, + "maven", + "https://plugin-management.example.com" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.android.material", "material"), + "1.0.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "10.0" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-jre" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-android" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier("org.springframework", "spring-core"), + "3.0.0.RELEASE" + ) + ); + } + }); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverTest.java new file mode 100644 index 0000000..d5b8e2a --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/GradleBuildResolverTest.java @@ -0,0 +1,1026 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.GradleArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.util.GradleUtils; +import org.gradle.tooling.GradleConnectionException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mockito; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Collections; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class GradleBuildResolverTest { + + private final GradleBuildResolver gradleBuildResolver = new GradleBuildResolver(); + + @Test + void testResolve(@TempDir final Path tmpDirectory) { + assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> { + final var tmpBuildDirectory = tmpDirectory.resolve("groovy"); + Files.createDirectory(tmpBuildDirectory); + final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle"); + Files.copy( + Path.of("src", "test", "resources", "build_foo.gradle"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + final var build = gradleBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "MavenRepo", + "https://repo.maven.apache.org/maven2/" + ), + new Repository( + RepositoryType.NORMAL, + "foo-repository-name", + "https://foo-repository-host" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + GradleArtifactType.ANNOTATION_PROCESSOR, + new ArtifactIdentifier( + "foo-annotation-processor-group-id", + "foo-annotation-processor-artifact-id" + ), + "foo-annotation-processor-version" + ), + new Artifact<>( + GradleArtifactType.API, + new ArtifactIdentifier( + "foo-api-group-id", + "foo-api-artifact-id" + ), + "foo-api-version" + ), + new Artifact<>( + GradleArtifactType.COMPILE_ONLY, + new ArtifactIdentifier( + "foo-compile-only-group-id", + "foo-compile-only-artifact-id" + ), + "foo-compile-only-version" + ), + new Artifact<>( + GradleArtifactType.COMPILE_ONLY_API, + new ArtifactIdentifier( + "foo-compile-only-api-group-id", + "foo-compile-only-api-artifact-id" + ), + "foo-compile-only-api-version" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier( + "foo-implementation-group-id", + "foo-implementation-artifact-id" + ), + "foo-implementation-version" + ), + new Artifact<>( + GradleArtifactType.RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-runtime-only-group-id", + "foo-runtime-only-artifact-id" + ), + "foo-runtime-only-version" + ), + new Artifact<>( + GradleArtifactType.TEST_ANNOTATION_PROCESSOR, + new ArtifactIdentifier( + "foo-test-annotation-processor-group-id", + "foo-test-annotation-processor-artifact-id" + ), + "foo-test-annotation-processor-version" + ), + new Artifact<>( + GradleArtifactType.TEST_COMPILE_ONLY, + new ArtifactIdentifier( + "foo-test-compile-only-group-id", + "foo-test-compile-only-artifact-id" + ), + "foo-test-compile-only-version" + ), + new Artifact<>( + GradleArtifactType.TEST_IMPLEMENTATION, + new ArtifactIdentifier( + "foo-test-implementation-group-id", + "foo-test-implementation-artifact-id" + ), + "foo-test-implementation-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-test-runtime-only-group-id", + "foo-test-runtime-only-artifact-id" + ), + "foo-test-runtime-only-version" + ) + ); + }); + assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> { + final var tmpBuildDirectory = tmpDirectory.resolve("kotlin"); + Files.createDirectory(tmpBuildDirectory); + final var tmpBuildFile = tmpBuildDirectory.resolve("build.gradle.kts"); + Files.copy( + Path.of("src", "test", "resources", "build_foo.gradle.kts"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + final var build = gradleBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "MavenRepo", + "https://repo.maven.apache.org/maven2/" + ), + new Repository( + RepositoryType.NORMAL, + "foo-repository-name", + "https://foo-repository-host" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + GradleArtifactType.ANNOTATION_PROCESSOR, + new ArtifactIdentifier( + "foo-annotation-processor-group-id", + "foo-annotation-processor-artifact-id" + ), + "foo-annotation-processor-version" + ), + new Artifact<>( + GradleArtifactType.API, + new ArtifactIdentifier( + "foo-api-group-id", + "foo-api-artifact-id" + ), + "foo-api-version" + ), + new Artifact<>( + GradleArtifactType.COMPILE_ONLY, + new ArtifactIdentifier( + "foo-compile-only-group-id", + "foo-compile-only-artifact-id" + ), + "foo-compile-only-version" + ), + new Artifact<>( + GradleArtifactType.COMPILE_ONLY_API, + new ArtifactIdentifier( + "foo-compile-only-api-group-id", + "foo-compile-only-api-artifact-id" + ), + "foo-compile-only-api-version" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier( + "foo-implementation-group-id", + "foo-implementation-artifact-id" + ), + "foo-implementation-version" + ), + new Artifact<>( + GradleArtifactType.RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-runtime-only-group-id", + "foo-runtime-only-artifact-id" + ), + "foo-runtime-only-version" + ), + new Artifact<>( + GradleArtifactType.TEST_ANNOTATION_PROCESSOR, + new ArtifactIdentifier( + "foo-test-annotation-processor-group-id", + "foo-test-annotation-processor-artifact-id" + ), + "foo-test-annotation-processor-version" + ), + new Artifact<>( + GradleArtifactType.TEST_COMPILE_ONLY, + new ArtifactIdentifier( + "foo-test-compile-only-group-id", + "foo-test-compile-only-artifact-id" + ), + "foo-test-compile-only-version" + ), + new Artifact<>( + GradleArtifactType.TEST_IMPLEMENTATION, + new ArtifactIdentifier( + "foo-test-implementation-group-id", + "foo-test-implementation-artifact-id" + ), + "foo-test-implementation-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-test-runtime-only-group-id", + "foo-test-runtime-only-artifact-id" + ), + "foo-test-runtime-only-version" + ) + ); + }); + } + + @Test + void testResolveInvalid(@TempDir final Path tmpDirectory) { + assertThatNullPointerException().isThrownBy(() -> gradleBuildResolver.resolve(null)); + assertThat(BuildFileType.GRADLE_GROOVY).satisfies(buildFileType -> { + final var tmpBuildDirectory = tmpDirectory.resolve("groovy"); + Files.createDirectory(tmpBuildDirectory); + assertThat(tmpBuildDirectory.resolve("build_not-found.gradle")).satisfies(tmpBuildFile -> { + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> gradleBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(GradleConnectionException.class); + }); + assertThat(tmpBuildDirectory.resolve("build.gradle")).satisfies(tmpBuildFile -> { + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + Files.copy( + Path.of("src", "test", "resources", "build_error.gradle"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> gradleBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(GradleConnectionException.class); + try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) { + mockedGradleUtils.when(GradleUtils::retrieveOptionalHome) + .thenReturn(Optional.of("directory_not-found")); + Files.copy( + Path.of("src", "test", "resources", "build_foo.gradle"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> gradleBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(GradleConnectionException.class); + } + }); + }); + assertThat(BuildFileType.GRADLE_KOTLIN).satisfies(buildFileType -> { + final var tmpBuildDirectory = tmpDirectory.resolve("kotlin"); + Files.createDirectory(tmpBuildDirectory); + assertThat(tmpBuildDirectory.resolve("build_not-found.gradle.kts")).satisfies(tmpBuildFile -> { + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> gradleBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(GradleConnectionException.class); + }); + assertThat(tmpBuildDirectory.resolve("build.gradle.kts")).satisfies(tmpBuildFile -> { + final var buildFile = new BuildFile(buildFileType, tmpBuildFile); + Files.copy( + Path.of("src", "test", "resources", "build_error.gradle.kts"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> gradleBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(GradleConnectionException.class); + try (final var mockedGradleUtils = Mockito.mockStatic(GradleUtils.class)) { + mockedGradleUtils.when(GradleUtils::retrieveOptionalHome) + .thenReturn(Optional.of("directory_not-found")); + Files.copy( + Path.of("src", "test", "resources", "build_foo.gradle.kts"), + tmpBuildFile, + StandardCopyOption.REPLACE_EXISTING + ); + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> gradleBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(GradleConnectionException.class); + } + }); + }); + } + + @Test + void testGetFileTypes() { + assertThat(gradleBuildResolver.getFileTypes()).contains( + BuildFileType.GRADLE_GROOVY, + BuildFileType.GRADLE_KOTLIN + ); + } + + @Test + void testParseRepositories() throws IOException { + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "\n" + ) + ) + ) { + assertThat(GradleBuildResolver.parseRepositories(bufferedReader)).isEmpty(); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :repositories\n" + + "NORMAL:foo-repository-name:https://foo-repository-host\n" + + "PLUGIN:foo-plugin-repository-name:https://foo-plugin-repository-host" + ) + ) + ) { + assertThat(GradleBuildResolver.parseRepositories(bufferedReader)).containsExactly( + new Repository( + RepositoryType.NORMAL, + "foo-repository-name", + "https://foo-repository-host" + ), + new Repository( + RepositoryType.PLUGIN, + "foo-plugin-repository-name", + "https://foo-plugin-repository-host" + ) + ); + } + } + + @Test + void testParseRepositoriesInvalid() throws IOException { + assertThatNullPointerException() + .isThrownBy(() -> GradleBuildResolver.parseRepositories(null)); + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :repositories\n" + + "NORMAL:foo-repository-name" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseRepositories(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :repositories\n" + + "UNKNOWN:foo-repository-name:https://foo-repository-host" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseRepositories(bufferedReader)); + } + } + + @Test + void testParseArtifacts() throws IOException { + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "\n" + ) + ) + ) { + assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty(); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project\n" // Until Gradle 6.7 + + "------------------------------------------------------------\n" + + "\n" + + "api - API dependencies for source set 'main'. (n)" + ) + ) + ) { + assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty(); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'\n" // Since Gradle 6.8 + + "------------------------------------------------------------\n" + + "\n" + + "api - API dependencies for source set 'main'. (n)" + ) + ) + ) { + assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty(); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project\n" // Until Gradle 6.7 + + "------------------------------------------------------------\n" + + "\n" + + "api - API dependencies for source set 'main'. (n)\n" + + "No dependencies\n" + + "\n" + + "apiElements - API elements for main. (n)" + ) + ) + ) { + assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty(); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'\n" // Since Gradle 6.8 + + "------------------------------------------------------------\n" + + "\n" + + "api - API dependencies for source set 'main'. (n)\n" + + "No dependencies\n" + + "\n" + + "apiElements - API elements for main. (n)" + ) + ) + ) { + assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).isEmpty(); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project\n" // Until Gradle 6.7 + + "------------------------------------------------------------\n" + + "\n" + + "api - API dependencies for source set 'main'. (n)\n" + + "No dependencies\n" + + "\n" + + "apiElements - API elements for main. (n)\n" + + "No dependencies\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:" + + "foo-compile-only-version (n)\n" + + "| \\--- sub-foo-compile-only-group-id:" + + "sub-foo-compile-only-artifact-id -> sub-foo-compile-only-version (n)\n" + + "\\--- bar-compile-only-group-id:bar-compile-only-artifact-id (n)\n" + + " \\--- sub-bar-compile-only-group-id:" + + "sub-bar-compile-only-artifact-id (n)\n" + + "\n" + + "A web-based, searchable dependency report is available by adding the --scan " + + "option." + ) + ) + ) { + assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).containsExactly( + new Artifact<>( + GradleArtifactType.COMPILE_ONLY, + new ArtifactIdentifier( + "foo-compile-only-group-id", + "foo-compile-only-artifact-id" + ), + "foo-compile-only-version" + ), + new Artifact<>( + GradleArtifactType.COMPILE_ONLY, + new ArtifactIdentifier( + "bar-compile-only-group-id", + "bar-compile-only-artifact-id" + ) + ) + ); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'\n" // Since Gradle 6.8 + + "------------------------------------------------------------\n" + + "\n" + + "api - API dependencies for source set 'main'. (n)\n" + + "No dependencies\n" + + "\n" + + "apiElements - API elements for main. (n)\n" + + "No dependencies\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:" + + "foo-compile-only-version (n)\n" + + "| \\--- sub-foo-compile-only-group-id:" + + "sub-foo-compile-only-artifact-id -> sub-foo-compile-only-version (n)\n" + + "\\--- bar-compile-only-group-id:bar-compile-only-artifact-id (n)\n" + + " \\--- sub-bar-compile-only-group-id:" + + "sub-bar-compile-only-artifact-id (n)\n" + + "\n" + + "A web-based, searchable dependency report is available by adding the --scan " + + "option." + ) + ) + ) { + assertThat(GradleBuildResolver.parseArtifacts(bufferedReader)).containsExactly( + new Artifact<>( + GradleArtifactType.COMPILE_ONLY, + new ArtifactIdentifier( + "foo-compile-only-group-id", + "foo-compile-only-artifact-id" + ), + "foo-compile-only-version" + ), + new Artifact<>( + GradleArtifactType.COMPILE_ONLY, + new ArtifactIdentifier( + "bar-compile-only-group-id", + "bar-compile-only-artifact-id" + ) + ) + ); + } + } + + @Test + void testParseArtifactsInvalid() throws IOException { + assertThatNullPointerException() + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(null)); + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project" // Until Gradle 6.7 + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'" // Since Gradle 6.8 + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project\n" // Until Gradle 6.7 + + "------------------------------------------------------------" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'\n" // Since Gradle 6.8 + + "------------------------------------------------------------" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project\n" // Until Gradle 6.7 + + "------------------------------------------------------------\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "???? foo-compile-only-group-id:foo-compile-only-artifact-id:" + + "foo-compile-only-version (n)" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'\n" // Since Gradle 6.8 + + "------------------------------------------------------------\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "???? foo-compile-only-group-id:foo-compile-only-artifact-id:" + + "foo-compile-only-version (n)" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project\n" // Until Gradle 6.7 + + "------------------------------------------------------------\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "+--- foo-compile-only-group-id (n)" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'\n" // Since Gradle 6.8 + + "------------------------------------------------------------\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "+--- foo-compile-only-group-id (n)" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project\n" // Until Gradle 6.7 + + "------------------------------------------------------------\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:" + + "foo-compile-only-version:foo (n)" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + try ( + final var bufferedReader = new BufferedReader( + new StringReader( + "> Task :dependencies\n" + + "\n" + + "------------------------------------------------------------\n" + + "Root project 'foo-project'\n" // Since Gradle 6.8 + + "------------------------------------------------------------\n" + + "\n" + + "compileOnly - Compile only dependencies for source set 'main'. (n)\n" + + "+--- foo-compile-only-group-id:foo-compile-only-artifact-id:" + + "foo-compile-only-version:foo (n)" + ) + ) + ) { + assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> GradleBuildResolver.parseArtifacts(bufferedReader)); + } + } + + @Test + void testFilter() { + final var list = Stream.of( + // Deprecated or classpath duplicates to be removed + new Artifact<>( + GradleArtifactType.COMPILE_CLASSPATH, + new ArtifactIdentifier( + "foo-implementation-group-id", + "foo-implementation-artifact-id" + ), + "foo-implementation-version" + ), + new Artifact<>( + GradleArtifactType.RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-runtime-only-group-id", + "foo-runtime-only-artifact-id" + ), + "foo-runtime-only-version" + ), + new Artifact<>( + GradleArtifactType.TEST_COMPILE_CLASSPATH, + new ArtifactIdentifier( + "foo-test-implementation-group-id", + "foo-test-implementation-artifact-id" + ), + "foo-test-implementation-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-test-runtime-only-group-id", + "foo-test-runtime-only-artifact-id" + ), + "foo-test-runtime-only-version" + ), + + // "COMPILE_CLASSPATH" duplicates to be removed + new Artifact<>( + GradleArtifactType.RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-compile-classpath-group-id", + "foo-compile-classpath-artifact-id" + ), + "foo-compile-classpath-version" + ), + new Artifact<>( + GradleArtifactType.TEST_COMPILE_CLASSPATH, + new ArtifactIdentifier( + "foo-compile-classpath-group-id", + "foo-compile-classpath-artifact-id" + ), + "foo-compile-classpath-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-compile-classpath-group-id", + "foo-compile-classpath-artifact-id" + ), + "foo-compile-classpath-version" + ), + + // "RUNTIME_CLASSPATH" duplicates to be removed + new Artifact<>( + GradleArtifactType.TEST_COMPILE_CLASSPATH, + new ArtifactIdentifier( + "foo-runtime-classpath-group-id", + "foo-runtime-classpath-artifact-id" + ), + "foo-runtime-classpath-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-runtime-classpath-group-id", + "foo-runtime-classpath-artifact-id" + ), + "foo-runtime-classpath-version" + ), + + // "TEST_COMPILE_CLASSPATH" duplicates to be removed + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-test-compile-classpath-group-id", + "foo-test-compile-classpath-artifact-id" + ), + "foo-test-compile-classpath-version" + ), + + // "COMPILE_CLASSPATH" to "IMPLEMENTATION" + new Artifact<>( + GradleArtifactType.COMPILE_CLASSPATH, + new ArtifactIdentifier( + "foo-compile-classpath-group-id", + "foo-compile-classpath-artifact-id" + ), + "foo-compile-classpath-version" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier( + "foo-implementation-group-id", + "foo-implementation-artifact-id" + ), + "foo-implementation-version" + ), + + // "RUNTIME_CLASSPATH" to "RUNTIME_ONLY" + new Artifact<>( + GradleArtifactType.RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-runtime-classpath-group-id", + "foo-runtime-classpath-artifact-id" + ), + "foo-runtime-classpath-version" + ), + new Artifact<>( + GradleArtifactType.RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-runtime-only-group-id", + "foo-runtime-only-artifact-id" + ), + "foo-runtime-only-version" + ), + + // "TEST_COMPILE_CLASSPATH" to "TEST_IMPLEMENTATION" + new Artifact<>( + GradleArtifactType.TEST_COMPILE_CLASSPATH, + new ArtifactIdentifier( + "foo-test-compile-classpath-group-id", + "foo-test-compile-classpath-artifact-id" + ), + "foo-test-compile-classpath-version" + ), + new Artifact<>( + GradleArtifactType.TEST_IMPLEMENTATION, + new ArtifactIdentifier( + "foo-test-implementation-group-id", + "foo-test-implementation-artifact-id" + ), + "foo-test-implementation-version" + ), + + // "TEST_RUNTIME_CLASSPATH" to "TEST_RUNTIME_ONLY" + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_CLASSPATH, + new ArtifactIdentifier( + "foo-test-runtime-classpath-group-id", + "foo-test-runtime-classpath-artifact-id" + ), + "foo-test-runtime-classpath-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-test-runtime-only-group-id", + "foo-test-runtime-only-artifact-id" + ), + "foo-test-runtime-only-version" + ) + ).collect(Collectors.toList()); + assertThat(GradleBuildResolver.filter(list)).containsExactly( + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier( + "foo-compile-classpath-group-id", + "foo-compile-classpath-artifact-id" + ), + "foo-compile-classpath-version" + ), + new Artifact<>( + GradleArtifactType.IMPLEMENTATION, + new ArtifactIdentifier( + "foo-implementation-group-id", + "foo-implementation-artifact-id" + ), + "foo-implementation-version" + ), + new Artifact<>( + GradleArtifactType.RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-runtime-classpath-group-id", + "foo-runtime-classpath-artifact-id" + ), + "foo-runtime-classpath-version" + ), + new Artifact<>( + GradleArtifactType.RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-runtime-only-group-id", + "foo-runtime-only-artifact-id" + ), + "foo-runtime-only-version" + ), + new Artifact<>( + GradleArtifactType.TEST_IMPLEMENTATION, + new ArtifactIdentifier( + "foo-test-compile-classpath-group-id", + "foo-test-compile-classpath-artifact-id" + ), + "foo-test-compile-classpath-version" + ), + new Artifact<>( + GradleArtifactType.TEST_IMPLEMENTATION, + new ArtifactIdentifier( + "foo-test-implementation-group-id", + "foo-test-implementation-artifact-id" + ), + "foo-test-implementation-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-test-runtime-classpath-group-id", + "foo-test-runtime-classpath-artifact-id" + ), + "foo-test-runtime-classpath-version" + ), + new Artifact<>( + GradleArtifactType.TEST_RUNTIME_ONLY, + new ArtifactIdentifier( + "foo-test-runtime-only-group-id", + "foo-test-runtime-only-artifact-id" + ), + "foo-test-runtime-only-version" + ) + ); + } + + @Test + void testFilterInvalid() { + assertThatNullPointerException().isThrownBy(() -> GradleBuildResolver.filter(null)); + assertThatNullPointerException().isThrownBy(() -> GradleBuildResolver.filter(Collections.singletonList(null))); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverIT.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverIT.java new file mode 100644 index 0000000..dbe646f --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverIT.java @@ -0,0 +1,97 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +final class MavenBuildResolverIT { + + private final MavenBuildResolver mavenBuildResolver = new MavenBuildResolver(new MavenSession()); + + @Test + void testResolve() { + final var buildFile = new BuildFile( + BuildFileType.MAVEN, + Path.of("src", "test", "resources", "pom_it.xml") + ); + final var build = mavenBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "google", + "https://maven.google.com" + ), + new Repository( + RepositoryType.NORMAL, + "central", + "https://repo.maven.apache.org/maven2" + ), + new Repository( + RepositoryType.PLUGIN, + "central", + "https://repo.maven.apache.org/maven2" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("com.google.android.material", "material"), + "1.0.0" + ), + new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("com.google.guava", "guava"), + "10.0" + ), + new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("org.springframework", "spring-core"), + "3.0.0.RELEASE" + ), + new Artifact<>( + MavenArtifactType.PROFILE_DEPENDENCY, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-jre" + ), + new Artifact<>( + MavenArtifactType.PROFILE_DEPENDENCY, + new ArtifactIdentifier("com.google.guava", "guava"), + "23.1-android" + ) + ); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverTest.java new file mode 100644 index 0000000..dba5ce5 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/build/resolver/MavenBuildResolverTest.java @@ -0,0 +1,298 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.build.resolver; + +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFile; +import com.github.alexisjehan.mavencheck.core.component.build.file.BuildFileType; +import com.github.alexisjehan.mavencheck.core.component.repository.Repository; +import com.github.alexisjehan.mavencheck.core.component.repository.RepositoryType; +import com.github.alexisjehan.mavencheck.core.component.session.MavenSession; +import org.apache.maven.model.building.ModelBuildingException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +@ExtendWith(MockitoExtension.class) +final class MavenBuildResolverTest { + + @Mock + private MavenSession mockedMavenSession; + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new MavenBuildResolver(null)); + } + + @Test + void testResolve() { + final var mavenBuildResolver = new MavenBuildResolver(mockedMavenSession); + assertThat( + new BuildFile( + BuildFileType.MAVEN, + Path.of("src", "test", "resources", "pom_empty.xml") + ) + ).satisfies(buildFile -> { + final var build = mavenBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "central", + "https://repo.maven.apache.org/maven2" + ), + new Repository( + RepositoryType.PLUGIN, + "central", + "https://repo.maven.apache.org/maven2" + ) + ); + assertThat(build.getArtifacts()).isEmpty(); + }); + assertThat( + new BuildFile( + BuildFileType.MAVEN, + Path.of("src", "test", "resources", "pom_foo_parent.xml") + ) + ).satisfies(buildFile -> { + final var build = mavenBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "central", + "https://repo.maven.apache.org/maven2" + ), + new Repository( + RepositoryType.PLUGIN, + "central", + "https://repo.maven.apache.org/maven2" + ) + ); + assertThat(build.getArtifacts()).isEmpty(); + }); + assertThat( + new BuildFile( + BuildFileType.MAVEN, + Path.of("src", "test", "resources", "pom_foo.xml") + ) + ).satisfies(buildFile -> { + final var build = mavenBuildResolver.resolve(buildFile); + assertThat(build.getFile()).isSameAs(buildFile); + assertThat(build.getRepositories()).containsExactly( + new Repository( + RepositoryType.NORMAL, + "foo-repository-id", + "https://foo-repository-host" + ), + new Repository( + RepositoryType.NORMAL, + "central", + "https://repo.maven.apache.org/maven2" + ), + new Repository( + RepositoryType.PLUGIN, + "foo-plugin-repository-id", + "https://foo-plugin-repository-host" + ), + new Repository( + RepositoryType.PLUGIN, + "central", + "https://repo.maven.apache.org/maven2" + ) + ); + assertThat(build.getArtifacts()).containsExactly( + new Artifact<>( + MavenArtifactType.PARENT, + new ArtifactIdentifier( + "foo-parent-group-id", + "foo-parent-artifact-id" + ), + "foo-parent-version" + ), + new Artifact<>( + MavenArtifactType.DEPENDENCY_MANAGEMENT_DEPENDENCY, + new ArtifactIdentifier( + "foo-dependency-management-dependency-group-id", + "foo-dependency-management-dependency-artifact-id" + ), + "foo-dependency-management-dependency-version" + ), + new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier( + "foo-dependency-group-id", + "foo-dependency-artifact-id" + ), + "foo-dependency-version" + ), + new Artifact<>( + MavenArtifactType.BUILD_EXTENSION, + new ArtifactIdentifier( + "foo-build-extension-group-id", + "foo-build-extension-artifact-id" + ), + "foo-build-extension-version" + ), + new Artifact<>( + MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN, + new ArtifactIdentifier( + "foo-build-plugin-management-plugin-group-id", + "foo-build-plugin-management-plugin-artifact-id" + ), + "foo-build-plugin-management-plugin-version" + ), + new Artifact<>( + MavenArtifactType.BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY, + new ArtifactIdentifier( + "foo-build-plugin-management-plugin-dependency-group-id", + "foo-build-plugin-management-plugin-dependency-artifact-id" + ), + "foo-build-plugin-management-plugin-dependency-version" + ), + new Artifact<>( + MavenArtifactType.BUILD_PLUGIN, + new ArtifactIdentifier( + "foo-build-plugin-group-id", + "foo-build-plugin-artifact-id" + ), + "foo-build-plugin-version" + ), + new Artifact<>( + MavenArtifactType.BUILD_PLUGIN_DEPENDENCY, + new ArtifactIdentifier( + "foo-build-plugin-dependency-group-id", + "foo-build-plugin-dependency-artifact-id" + ), + "foo-build-plugin-dependency-version" + ), + new Artifact<>( + MavenArtifactType.REPORTING_PLUGIN, + new ArtifactIdentifier( + "foo-reporting-plugin-group-id", + "foo-reporting-plugin-artifact-id" + ), + "foo-reporting-plugin-version" + ), + new Artifact<>( + MavenArtifactType.PROFILE_DEPENDENCY_MANAGEMENT_DEPENDENCY, + new ArtifactIdentifier( + "foo-profile-dependency-management-dependency-group-id", + "foo-profile-dependency-management-dependency-artifact-id" + ), + "foo-profile-dependency-management-dependency-version" + ), + new Artifact<>( + MavenArtifactType.PROFILE_DEPENDENCY, + new ArtifactIdentifier( + "foo-profile-dependency-group-id", + "foo-profile-dependency-artifact-id" + ), + "foo-profile-dependency-version" + ), + new Artifact<>( + MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN, + new ArtifactIdentifier( + "foo-profile-build-plugin-management-plugin-group-id", + "foo-profile-build-plugin-management-plugin-artifact-id" + ), + "foo-profile-build-plugin-management-plugin-version" + ), + new Artifact<>( + MavenArtifactType.PROFILE_BUILD_PLUGIN_MANAGEMENT_PLUGIN_DEPENDENCY, + new ArtifactIdentifier( + "foo-profile-build-plugin-management-plugin-dependency-group-id", + "foo-profile-build-plugin-management-plugin-dependency-artifact-id" + ), + "foo-profile-build-plugin-management-plugin-dependency-version" + ), + new Artifact<>( + MavenArtifactType.PROFILE_BUILD_PLUGIN, + new ArtifactIdentifier( + "foo-profile-build-plugin-group-id", + "foo-profile-build-plugin-artifact-id" + ), + "foo-profile-build-plugin-version" + ), + new Artifact<>( + MavenArtifactType.PROFILE_BUILD_PLUGIN_DEPENDENCY, + new ArtifactIdentifier( + "foo-profile-build-plugin-dependency-group-id", + "foo-profile-build-plugin-dependency-artifact-id" + ), + "foo-profile-build-plugin-dependency-version" + ), + new Artifact<>( + MavenArtifactType.PROFILE_REPORTING_PLUGIN, + new ArtifactIdentifier( + "foo-profile-reporting-plugin-group-id", + "foo-profile-reporting-plugin-artifact-id" + ), + "foo-profile-reporting-plugin-version" + ) + ); + }); + } + + @Test + void testResolveInvalid() { + final var mavenBuildResolver = new MavenBuildResolver(mockedMavenSession); + assertThatNullPointerException().isThrownBy(() -> mavenBuildResolver.resolve(null)); + assertThat( + new BuildFile( + BuildFileType.MAVEN, + Path.of("src", "test", "resources", "pom_not-found.xml") + ) + ).satisfies( + buildFile -> assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> mavenBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(ModelBuildingException.class) + ); + assertThat( + new BuildFile( + BuildFileType.MAVEN, + Path.of("src", "test", "resources", "pom_error.xml") + ) + ).satisfies( + buildFile -> assertThatExceptionOfType(BuildResolveException.class) + .isThrownBy(() -> mavenBuildResolver.resolve(buildFile)) + .withCauseInstanceOf(ModelBuildingException.class) + ); + } + + @Test + void testGetFileTypes() { + final var mavenBuildResolver = new MavenBuildResolver(mockedMavenSession); + assertThat(mavenBuildResolver.getFileTypes()).contains(BuildFileType.MAVEN); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilterTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilterTest.java new file mode 100644 index 0000000..5321104 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/ArtifactFilterTest.java @@ -0,0 +1,87 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact; + +import com.github.alexisjehan.javanilla.lang.Strings; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ArtifactFilterTest { + + private static final Artifact ARTIFACT = new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id") + ); + private static final String UPDATE_VERSION = "foo-version"; + + @Test + void testAllAccept() { + assertThat(ArtifactFilter.ALL.accept(ARTIFACT)).isFalse(); + } + + @Test + void testAllAcceptInvalid() { + assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.ALL.accept(null)); + } + + @Test + void testAllAcceptUpdateVersion() { + assertThat(ArtifactFilter.ALL.accept(ARTIFACT, UPDATE_VERSION)).isFalse(); + } + + @Test + void testAllAcceptUpdateVersionInvalid() { + assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.ALL.accept(null, UPDATE_VERSION)); + assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.ALL.accept(ARTIFACT, null)); + assertThatIllegalArgumentException().isThrownBy(() -> ArtifactFilter.ALL.accept(ARTIFACT, Strings.EMPTY)); + } + + @Test + void testNoneAccept() { + assertThat(ArtifactFilter.NONE.accept(ARTIFACT)).isTrue(); + } + + @Test + void testNoneAcceptInvalid() { + assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.NONE.accept(null)); + } + + @Test + void testNoneAcceptUpdateVersion() { + assertThat(ArtifactFilter.NONE.accept(ARTIFACT, UPDATE_VERSION)).isTrue(); + } + + @Test + void testNoneAcceptUpdateVersionInvalid() { + assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.NONE.accept(null, UPDATE_VERSION)); + assertThatNullPointerException().isThrownBy(() -> ArtifactFilter.NONE.accept(ARTIFACT, null)); + assertThatIllegalArgumentException().isThrownBy(() -> ArtifactFilter.NONE.accept(ARTIFACT, Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilterTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilterTest.java new file mode 100644 index 0000000..c8e3d23 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/CompositeArtifactFilterTest.java @@ -0,0 +1,92 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact; + +import com.github.alexisjehan.javanilla.lang.Strings; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class CompositeArtifactFilterTest { + + private static final Artifact ARTIFACT = new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id") + ); + private static final String UPDATE_VERSION = "foo-version"; + + private final CompositeArtifactFilter compositeArtifactFilter = new CompositeArtifactFilter(ArtifactFilter.ALL); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new CompositeArtifactFilter((ArtifactFilter[]) null)); + assertThatIllegalArgumentException().isThrownBy(CompositeArtifactFilter::new); + assertThatNullPointerException().isThrownBy(() -> new CompositeArtifactFilter((ArtifactFilter) null)); + } + + @Test + void testAccept() { + assertThat(new CompositeArtifactFilter(ArtifactFilter.ALL).accept(ARTIFACT)).isFalse(); + assertThat(new CompositeArtifactFilter(ArtifactFilter.NONE).accept(ARTIFACT)).isTrue(); + assertThat(new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.ALL).accept(ARTIFACT)).isFalse(); + assertThat(new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.NONE).accept(ARTIFACT)).isFalse(); + assertThat(new CompositeArtifactFilter(ArtifactFilter.NONE, ArtifactFilter.NONE).accept(ARTIFACT)).isTrue(); + } + + @Test + void testAcceptInvalid() { + assertThatNullPointerException().isThrownBy(() -> compositeArtifactFilter.accept(null)); + } + + @Test + void testAcceptUpdateVersion() { + assertThat( + new CompositeArtifactFilter(ArtifactFilter.ALL).accept(ARTIFACT, UPDATE_VERSION) + ).isFalse(); + assertThat( + new CompositeArtifactFilter(ArtifactFilter.NONE).accept(ARTIFACT, UPDATE_VERSION) + ).isTrue(); + assertThat( + new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.ALL).accept(ARTIFACT, UPDATE_VERSION) + ).isFalse(); + assertThat( + new CompositeArtifactFilter(ArtifactFilter.ALL, ArtifactFilter.NONE).accept(ARTIFACT, UPDATE_VERSION) + ).isFalse(); + assertThat( + new CompositeArtifactFilter(ArtifactFilter.NONE, ArtifactFilter.NONE).accept(ARTIFACT, UPDATE_VERSION) + ).isTrue(); + } + + @Test + void testAcceptUpdateVersionInvalid() { + assertThatNullPointerException().isThrownBy(() -> compositeArtifactFilter.accept(null, UPDATE_VERSION)); + assertThatNullPointerException().isThrownBy(() -> compositeArtifactFilter.accept(ARTIFACT, null)); + assertThatIllegalArgumentException().isThrownBy(() -> compositeArtifactFilter.accept(ARTIFACT, Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseExceptionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseExceptionTest.java new file mode 100644 index 0000000..3d221c3 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParseExceptionTest.java @@ -0,0 +1,124 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser; + +import com.github.alexisjehan.javanilla.io.Serializables; +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ArtifactFilterParseExceptionTest { + + private static final String REASON = "foo-reason"; + private static final String LINE = "foo-line"; + private static final long LINE_NUMBER = 1; + private static final Path FILE = Path.of("foo-file"); + + private final ArtifactFilterParseException artifactFilterParseException = new ArtifactFilterParseException( + REASON, + LINE, + LINE_NUMBER + ); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> { + throw new ArtifactFilterParseException(null, LINE, LINE_NUMBER); + }); + assertThatIllegalArgumentException().isThrownBy(() -> { + throw new ArtifactFilterParseException(Strings.EMPTY, LINE, LINE_NUMBER); + }); + assertThatNullPointerException().isThrownBy(() -> { + throw new ArtifactFilterParseException(REASON, null, LINE_NUMBER); + }); + assertThatIllegalArgumentException().isThrownBy(() -> { + throw new ArtifactFilterParseException(REASON, Strings.EMPTY, LINE_NUMBER); + }); + assertThatIllegalArgumentException().isThrownBy(() -> { + throw new ArtifactFilterParseException(REASON, LINE, 0); + }); + } + + @Test + void testWith() { + final var otherArtifactFilterParseException = artifactFilterParseException.with(FILE); + assertThat(otherArtifactFilterParseException.getOptionalFile()) + .hasValue(FILE); + assertThat(artifactFilterParseException.getReason()) + .isEqualTo(otherArtifactFilterParseException.getReason()); + assertThat(artifactFilterParseException.getLine()) + .isEqualTo(otherArtifactFilterParseException.getLine()); + assertThat(artifactFilterParseException.getLineNumber()) + .isEqualTo(otherArtifactFilterParseException.getLineNumber()); + } + + @Test + void testWithInvalid() { + assertThatNullPointerException().isThrownBy(() -> artifactFilterParseException.with(null)); + } + + @Test + void testGetMessage() { + assertThat(artifactFilterParseException.getMessage()).isEqualTo( + REASON + ": \"" + LINE + "\" (at line " + LINE_NUMBER + ")" + ); + assertThat(artifactFilterParseException.with(FILE).getMessage()).isEqualTo( + REASON + ": \"" + LINE + "\" (at line " + LINE_NUMBER + " of the " + FILE + " file)" + ); + } + + @Test + void testGetReason() { + assertThat(artifactFilterParseException.getReason()).isEqualTo(REASON); + } + + @Test + void testGetLine() { + assertThat(artifactFilterParseException.getLine()).isEqualTo(LINE); + } + + @Test + void testGetLineNumber() { + assertThat(artifactFilterParseException.getLineNumber()).isEqualTo(LINE_NUMBER); + } + + @Test + void testGetOptionalFile() { + assertThat(artifactFilterParseException.getOptionalFile()).isEmpty(); + } + + @Test + void testSerializable() { + assertThat( + Serializables.deserialize( + Serializables.serialize(artifactFilterParseException) + ) + ).hasSameClassAs(artifactFilterParseException); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParserTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParserTest.java new file mode 100644 index 0000000..ae4316f --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/artifact/parser/ArtifactFilterParserTest.java @@ -0,0 +1,163 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.artifact.parser; + +import com.github.alexisjehan.javanilla.lang.Strings; +import com.github.alexisjehan.mavencheck.core.component.artifact.Artifact; +import com.github.alexisjehan.mavencheck.core.component.artifact.ArtifactIdentifier; +import com.github.alexisjehan.mavencheck.core.component.artifact.type.MavenArtifactType; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ArtifactFilterParserTest { + + private static final Artifact ARTIFACT = new Artifact<>( + MavenArtifactType.DEPENDENCY, + new ArtifactIdentifier("foo-group-id", "foo-artifact-id") + ); + private static final String UPDATE_VERSION = "foo-version"; + + @Test + void testParsePath() { + assertThatNoException().isThrownBy( + () -> ArtifactFilterParser.parse(Path.of("src", "test", "resources", ".mvnchk-ignore_foo")) + ); + } + + @Test + void testParsePathInvalid() { + assertThatNullPointerException().isThrownBy(() -> ArtifactFilterParser.parse((Path) null)); + assertThat(Path.of("src", "test", "resources", ".mvnchk-ignore_not-found")).satisfies( + ignoreFile -> assertThatIllegalArgumentException() + .isThrownBy(() -> ArtifactFilterParser.parse(ignoreFile)) + ); + assertThat(Path.of("src", "test", "resources", ".mvnchk-ignore_error")).satisfies( + ignoreFile -> assertThatExceptionOfType(ArtifactFilterParseException.class) + .isThrownBy(() -> ArtifactFilterParser.parse(ignoreFile)) + ); + } + + @Test + void testParseReader() { + try (final var reader = new StringReader(Strings.EMPTY)) { + assertThatNoException().isThrownBy(() -> ArtifactFilterParser.parse(reader)); + } + } + + @Test + void testParseReaderInvalid() { + assertThatNullPointerException().isThrownBy(() -> ArtifactFilterParser.parse((Reader) null)); + try (final var reader = new StringReader("foo-group-id")) { + assertThatExceptionOfType(ArtifactFilterParseException.class) + .isThrownBy(() -> ArtifactFilterParser.parse(reader)); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version:foo")) { + assertThatExceptionOfType(ArtifactFilterParseException.class) + .isThrownBy(() -> ArtifactFilterParser.parse(reader)); + } + try (final var reader = new StringReader(":foo-artifact-id")) { + assertThatExceptionOfType(ArtifactFilterParseException.class) + .isThrownBy(() -> ArtifactFilterParser.parse(reader)); + } + try (final var reader = new StringReader("foo-group-id:")) { + assertThatExceptionOfType(ArtifactFilterParseException.class) + .isThrownBy(() -> ArtifactFilterParser.parse(reader)); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:")) { + assertThatExceptionOfType(ArtifactFilterParseException.class) + .isThrownBy(() -> ArtifactFilterParser.parse(reader)); + } + } + + @Test + void testParseReaderAccept() throws IOException { + try (final var reader = new StringReader("#foo-group-id:foo-artifact-id")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT)).isTrue(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT)).isFalse(); + } + try (final var reader = new StringReader("foo-group-id:bar-artifact-id")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT)).isTrue(); + } + } + + @Test + void testParseReaderAcceptInvalid() throws IOException { + final var artifactFilter = ArtifactFilterParser.parse(new StringReader(Strings.EMPTY)); + assertThatNullPointerException().isThrownBy(() -> artifactFilter.accept(null)); + } + + @Test + void testParseReaderAcceptUpdateVersion() throws IOException { + try (final var reader = new StringReader("#foo-group-id:foo-artifact-id:foo-version")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:bar-version")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:FOO-VERSION")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version?")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-?")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isTrue(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-???????")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-version*")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-*")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse(); + } + try (final var reader = new StringReader("foo-group-id:foo-artifact-id:foo-*******")) { + assertThat(ArtifactFilterParser.parse(reader).accept(ARTIFACT, UPDATE_VERSION)).isFalse(); + } + } + + @Test + void testParseReaderAcceptUpdateVersionInvalid() throws IOException { + final var artifactFilter = ArtifactFilterParser.parse(new StringReader(Strings.EMPTY)); + assertThatNullPointerException().isThrownBy(() -> artifactFilter.accept(null, UPDATE_VERSION)); + assertThatNullPointerException().isThrownBy(() -> artifactFilter.accept(ARTIFACT, null)); + assertThatIllegalArgumentException().isThrownBy(() -> artifactFilter.accept(ARTIFACT, Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilterTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilterTest.java new file mode 100644 index 0000000..9974741 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/VersionFilterTest.java @@ -0,0 +1,69 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class VersionFilterTest { + + @Test + void testSnapshotAccept() { + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot.123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3snapshot-123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT.123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3SNAPSHOT-123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot.123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.snapshot-123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT.123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3.SNAPSHOT-123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot.123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-snapshot-123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT")).isTrue(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT.123")).isFalse(); + assertThat(VersionFilter.SNAPSHOT.accept("1.2.3-SNAPSHOT-123")).isFalse(); + } + + @Test + void testSnapshotAcceptInvalid() { + assertThatNullPointerException().isThrownBy(() -> VersionFilter.SNAPSHOT.accept(null)); + assertThatIllegalArgumentException().isThrownBy(() -> VersionFilter.SNAPSHOT.accept(Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactoryTest.java new file mode 100644 index 0000000..9ac425b --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/CompositeVersionFilterFactoryTest.java @@ -0,0 +1,71 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class CompositeVersionFilterFactoryTest { + + private static final VersionFilterFactory ALL = artifactVersion -> version -> false; + private static final VersionFilterFactory NONE = artifactVersion -> version -> true; + + private final CompositeVersionFilterFactory compositeVersionFilterFactory = new CompositeVersionFilterFactory(ALL); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException() + .isThrownBy(() -> new CompositeVersionFilterFactory((VersionFilterFactory[]) null)); + assertThatIllegalArgumentException() + .isThrownBy(CompositeVersionFilterFactory::new); + assertThatNullPointerException() + .isThrownBy(() -> new CompositeVersionFilterFactory((VersionFilterFactory) null)); + } + + @Test + void testCreateInvalid() { + assertThatNullPointerException().isThrownBy(() -> compositeVersionFilterFactory.create(null)); + assertThatIllegalArgumentException().isThrownBy(() -> compositeVersionFilterFactory.create(Strings.EMPTY)); + } + + @Test + void testCreateAccept() { + assertThat(new CompositeVersionFilterFactory(ALL).create("1.0.0").accept("1.2.3")).isFalse(); + assertThat(new CompositeVersionFilterFactory(NONE).create("1.0.0").accept("1.2.3")).isTrue(); + assertThat(new CompositeVersionFilterFactory(ALL, ALL).create("1.0.0").accept("1.2.3")).isFalse(); + assertThat(new CompositeVersionFilterFactory(ALL, NONE).create("1.0.0").accept("1.2.3")).isFalse(); + assertThat(new CompositeVersionFilterFactory(NONE, NONE).create("1.0.0").accept("1.2.3")).isTrue(); + } + + @Test + void testCreateAcceptInvalid() { + final var versionFilter = compositeVersionFilterFactory.create("1.0.0"); + assertThatNullPointerException().isThrownBy(() -> versionFilter.accept(null)); + assertThatIllegalArgumentException().isThrownBy(() -> versionFilter.accept(Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactoryTest.java new file mode 100644 index 0000000..9fe302c --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/QualifierVersionFilterFactoryTest.java @@ -0,0 +1,139 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class QualifierVersionFilterFactoryTest { + + private final QualifierVersionFilterFactory qualifierVersionFilterFactory = QualifierVersionFilterFactory.INSTANCE; + + @Test + void testCreateInvalid() { + assertThatNullPointerException().isThrownBy(() -> qualifierVersionFilterFactory.create(null)); + assertThatIllegalArgumentException().isThrownBy(() -> qualifierVersionFilterFactory.create(Strings.EMPTY)); + } + + @Test + void testCreateAccept() { + // No qualifier + assertThat(qualifierVersionFilterFactory.create("1.0.0")).satisfies(versionFilter -> { + assertThat(versionFilter.accept("1.2.3")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO-123")).isTrue(); + }); + + // Same qualifier + assertThat(qualifierVersionFilterFactory.create("1.0.0-foo")).satisfies(versionFilter -> { + assertThat(versionFilter.accept("1.2.3")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO-123")).isTrue(); + }); + + // Not same qualifier + assertThat(qualifierVersionFilterFactory.create("1.0.0-bar")).satisfies(versionFilter -> { + assertThat(versionFilter.accept("1.2.3")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo")).isFalse(); + assertThat(versionFilter.accept("1.2.3foo123")).isFalse(); + assertThat(versionFilter.accept("1.2.3foo.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3foo-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3FOO")).isFalse(); + assertThat(versionFilter.accept("1.2.3FOO123")).isFalse(); + assertThat(versionFilter.accept("1.2.3FOO.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3FOO-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.foo")).isFalse(); + assertThat(versionFilter.accept("1.2.3.foo123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.foo.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.foo-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.FOO")).isFalse(); + assertThat(versionFilter.accept("1.2.3.FOO123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.FOO.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.FOO-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-foo")).isFalse(); + assertThat(versionFilter.accept("1.2.3-foo123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-foo.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-foo-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-FOO")).isFalse(); + assertThat(versionFilter.accept("1.2.3-FOO123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-FOO.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-FOO-123")).isFalse(); + }); + } + + @Test + void testCreateAcceptInvalid() { + final var versionFilter = qualifierVersionFilterFactory.create("1.0.0"); + assertThatNullPointerException().isThrownBy(() -> versionFilter.accept(null)); + assertThatIllegalArgumentException().isThrownBy(() -> versionFilter.accept(Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactoryTest.java new file mode 100644 index 0000000..d18a4c9 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/filter/version/factory/ReleaseVersionFilterFactoryTest.java @@ -0,0 +1,309 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.filter.version.factory; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ReleaseVersionFilterFactoryTest { + + private final ReleaseVersionFilterFactory releaseVersionFilterFactory = ReleaseVersionFilterFactory.INSTANCE; + + @Test + void testCreateInvalid() { + assertThatNullPointerException().isThrownBy(() -> releaseVersionFilterFactory.create(null)); + assertThatIllegalArgumentException().isThrownBy(() -> releaseVersionFilterFactory.create(Strings.EMPTY)); + } + + @Test + void testCreateAccept() { + final var versionFilter = releaseVersionFilterFactory.create("1.0.0"); + + // No qualifier + assertThat(versionFilter.accept("1.2.3")).isTrue(); + + // Any qualifier + assertThat(versionFilter.accept("1.2.3foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3FOO-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3.FOO-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-foo-123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO.123")).isTrue(); + assertThat(versionFilter.accept("1.2.3-FOO-123")).isTrue(); + + // Alpha qualifier + assertThat(versionFilter.accept("1.2.3alpha")).isFalse(); + assertThat(versionFilter.accept("1.2.3alpha123")).isFalse(); + assertThat(versionFilter.accept("1.2.3alpha.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3alpha-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3ALPHA")).isFalse(); + assertThat(versionFilter.accept("1.2.3ALPHA123")).isFalse(); + assertThat(versionFilter.accept("1.2.3ALPHA.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3ALPHA-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.alpha")).isFalse(); + assertThat(versionFilter.accept("1.2.3.alpha123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.alpha.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.alpha-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.ALPHA")).isFalse(); + assertThat(versionFilter.accept("1.2.3.ALPHA123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.ALPHA.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.ALPHA-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-alpha")).isFalse(); + assertThat(versionFilter.accept("1.2.3-alpha123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-alpha.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-alpha-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-ALPHA")).isFalse(); + assertThat(versionFilter.accept("1.2.3-ALPHA123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-ALPHA.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-ALPHA-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3a")).isFalse(); + assertThat(versionFilter.accept("1.2.3a123")).isFalse(); + assertThat(versionFilter.accept("1.2.3a.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3a-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3A")).isFalse(); + assertThat(versionFilter.accept("1.2.3A123")).isFalse(); + assertThat(versionFilter.accept("1.2.3A.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3A-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.a")).isFalse(); + assertThat(versionFilter.accept("1.2.3.a123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.a.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.a-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.A")).isFalse(); + assertThat(versionFilter.accept("1.2.3.A123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.A.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.A-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-a")).isFalse(); + assertThat(versionFilter.accept("1.2.3-a123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-a.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-a-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-A")).isFalse(); + assertThat(versionFilter.accept("1.2.3-A123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-A.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-A-123")).isFalse(); + + // Beta qualifier + assertThat(versionFilter.accept("1.2.3beta")).isFalse(); + assertThat(versionFilter.accept("1.2.3beta123")).isFalse(); + assertThat(versionFilter.accept("1.2.3beta.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3beta-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3BETA")).isFalse(); + assertThat(versionFilter.accept("1.2.3BETA123")).isFalse(); + assertThat(versionFilter.accept("1.2.3BETA.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3BETA-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.beta")).isFalse(); + assertThat(versionFilter.accept("1.2.3.beta123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.beta.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.beta-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.BETA")).isFalse(); + assertThat(versionFilter.accept("1.2.3.BETA123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.BETA.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.BETA-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-beta")).isFalse(); + assertThat(versionFilter.accept("1.2.3-beta123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-beta.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-beta-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-BETA")).isFalse(); + assertThat(versionFilter.accept("1.2.3-BETA123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-BETA.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-BETA-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3b")).isFalse(); + assertThat(versionFilter.accept("1.2.3b123")).isFalse(); + assertThat(versionFilter.accept("1.2.3b.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3b-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3B")).isFalse(); + assertThat(versionFilter.accept("1.2.3B123")).isFalse(); + assertThat(versionFilter.accept("1.2.3B.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3B-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.b")).isFalse(); + assertThat(versionFilter.accept("1.2.3.b123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.b.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.b-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.B")).isFalse(); + assertThat(versionFilter.accept("1.2.3.B123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.B.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.B-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-b")).isFalse(); + assertThat(versionFilter.accept("1.2.3-b123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-b.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-b-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-B")).isFalse(); + assertThat(versionFilter.accept("1.2.3-B123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-B.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-B-123")).isFalse(); + + // Milestone qualifier + assertThat(versionFilter.accept("1.2.3milestone")).isFalse(); + assertThat(versionFilter.accept("1.2.3milestone123")).isFalse(); + assertThat(versionFilter.accept("1.2.3milestone.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3milestone-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3MILESTONE")).isFalse(); + assertThat(versionFilter.accept("1.2.3MILESTONE123")).isFalse(); + assertThat(versionFilter.accept("1.2.3MILESTONE.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3MILESTONE-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.milestone")).isFalse(); + assertThat(versionFilter.accept("1.2.3.milestone123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.milestone.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.milestone-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.MILESTONE")).isFalse(); + assertThat(versionFilter.accept("1.2.3.MILESTONE123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.MILESTONE.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.MILESTONE-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-milestone")).isFalse(); + assertThat(versionFilter.accept("1.2.3-milestone123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-milestone.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-milestone-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-MILESTONE")).isFalse(); + assertThat(versionFilter.accept("1.2.3-MILESTONE123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-MILESTONE.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-MILESTONE-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3m")).isFalse(); + assertThat(versionFilter.accept("1.2.3m123")).isFalse(); + assertThat(versionFilter.accept("1.2.3m.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3m-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3M")).isFalse(); + assertThat(versionFilter.accept("1.2.3M123")).isFalse(); + assertThat(versionFilter.accept("1.2.3M.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3M-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.m")).isFalse(); + assertThat(versionFilter.accept("1.2.3.m123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.m.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.m-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.M")).isFalse(); + assertThat(versionFilter.accept("1.2.3.M123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.M.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.M-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-m")).isFalse(); + assertThat(versionFilter.accept("1.2.3-m123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-m.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-m-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-M")).isFalse(); + assertThat(versionFilter.accept("1.2.3-M123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-M.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-M-123")).isFalse(); + + // Release candidate qualifier + assertThat(versionFilter.accept("1.2.3rc")).isFalse(); + assertThat(versionFilter.accept("1.2.3rc123")).isFalse(); + assertThat(versionFilter.accept("1.2.3rc.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3rc-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3RC")).isFalse(); + assertThat(versionFilter.accept("1.2.3RC123")).isFalse(); + assertThat(versionFilter.accept("1.2.3RC.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3RC-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.rc")).isFalse(); + assertThat(versionFilter.accept("1.2.3.rc123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.rc.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.rc-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.RC")).isFalse(); + assertThat(versionFilter.accept("1.2.3.RC123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.RC.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.RC-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-rc")).isFalse(); + assertThat(versionFilter.accept("1.2.3-rc123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-rc.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-rc-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-RC")).isFalse(); + assertThat(versionFilter.accept("1.2.3-RC123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-RC.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-RC-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3cr")).isFalse(); + assertThat(versionFilter.accept("1.2.3cr123")).isFalse(); + assertThat(versionFilter.accept("1.2.3cr.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3cr-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3CR")).isFalse(); + assertThat(versionFilter.accept("1.2.3CR123")).isFalse(); + assertThat(versionFilter.accept("1.2.3CR.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3CR-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.cr")).isFalse(); + assertThat(versionFilter.accept("1.2.3.cr123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.cr.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.cr-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.CR")).isFalse(); + assertThat(versionFilter.accept("1.2.3.CR123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.CR.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.CR-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-cr")).isFalse(); + assertThat(versionFilter.accept("1.2.3-cr123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-cr.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-cr-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-CR")).isFalse(); + assertThat(versionFilter.accept("1.2.3-CR123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-CR.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-CR-123")).isFalse(); + + // Snapshot qualifier + assertThat(versionFilter.accept("1.2.3snapshot")).isFalse(); + assertThat(versionFilter.accept("1.2.3snapshot123")).isFalse(); + assertThat(versionFilter.accept("1.2.3snapshot.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3snapshot-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3SNAPSHOT")).isFalse(); + assertThat(versionFilter.accept("1.2.3SNAPSHOT123")).isFalse(); + assertThat(versionFilter.accept("1.2.3SNAPSHOT.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3SNAPSHOT-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.snapshot")).isFalse(); + assertThat(versionFilter.accept("1.2.3.snapshot123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.snapshot.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.snapshot-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.SNAPSHOT")).isFalse(); + assertThat(versionFilter.accept("1.2.3.SNAPSHOT123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.SNAPSHOT.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3.SNAPSHOT-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-snapshot")).isFalse(); + assertThat(versionFilter.accept("1.2.3-snapshot123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-snapshot.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-snapshot-123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-SNAPSHOT")).isFalse(); + assertThat(versionFilter.accept("1.2.3-SNAPSHOT123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-SNAPSHOT.123")).isFalse(); + assertThat(versionFilter.accept("1.2.3-SNAPSHOT-123")).isFalse(); + } + + @Test + void testCreateAcceptInvalid() { + final var versionFilter = releaseVersionFilterFactory.create("1.0.0"); + assertThatNullPointerException().isThrownBy(() -> versionFilter.accept(null)); + assertThatIllegalArgumentException().isThrownBy(() -> versionFilter.accept(Strings.EMPTY)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryTest.java new file mode 100644 index 0000000..5fb0d86 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/repository/RepositoryTest.java @@ -0,0 +1,97 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.repository; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class RepositoryTest { + + private static final RepositoryType TYPE = RepositoryType.NORMAL; + private static final String ID = "foo-id"; + private static final String URL = "https://foo-host"; + private static final RepositoryType OTHER_TYPE = RepositoryType.PLUGIN; + private static final String OTHER_ID = "bar-id"; + private static final String OTHER_URL = "https://bar-host"; + + private final Repository repository = new Repository(TYPE, ID, URL); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> new Repository(null, ID, URL)); + assertThatNullPointerException().isThrownBy(() -> new Repository(TYPE, null, URL)); + assertThatIllegalArgumentException().isThrownBy(() -> new Repository(TYPE, Strings.EMPTY, URL)); + assertThatNullPointerException().isThrownBy(() -> new Repository(TYPE, ID, null)); + assertThatIllegalArgumentException().isThrownBy(() -> new Repository(TYPE, ID, Strings.EMPTY)); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(repository.equals(repository)).isTrue(); + assertThat(repository).isNotEqualTo(new Object()); + assertThat(new Repository(TYPE, ID, URL)).satisfies(otherRepository -> { + assertThat(repository).isNotSameAs(otherRepository); + assertThat(repository).isEqualTo(otherRepository); + assertThat(repository).hasSameHashCodeAs(otherRepository); + assertThat(repository).hasToString(otherRepository.toString()); + }); + assertThat(new Repository(OTHER_TYPE, ID, URL)).satisfies(otherRepository -> { + assertThat(repository).isNotSameAs(otherRepository); + assertThat(repository).isNotEqualTo(otherRepository); + assertThat(repository).doesNotHaveSameHashCodeAs(otherRepository); + assertThat(repository).doesNotHaveToString(otherRepository.toString()); + }); + assertThat(new Repository(TYPE, OTHER_ID, URL)).satisfies(otherRepository -> { + assertThat(repository).isNotSameAs(otherRepository); + assertThat(repository).isNotEqualTo(otherRepository); + assertThat(repository).doesNotHaveSameHashCodeAs(otherRepository); + assertThat(repository).doesNotHaveToString(otherRepository.toString()); + }); + assertThat(new Repository(TYPE, ID, OTHER_URL)).satisfies(otherRepository -> { + assertThat(repository).isNotSameAs(otherRepository); + assertThat(repository).isNotEqualTo(otherRepository); + assertThat(repository).doesNotHaveSameHashCodeAs(otherRepository); + assertThat(repository).doesNotHaveToString(otherRepository.toString()); + }); + } + + @Test + void testGetType() { + assertThat(repository.getType()).isEqualTo(TYPE); + } + + @Test + void testGetId() { + assertThat(repository.getId()).isEqualTo(ID); + } + + @Test + void testGetUrl() { + assertThat(repository.getUrl()).isEqualTo(URL); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionExceptionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionExceptionTest.java new file mode 100644 index 0000000..09459e4 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionExceptionTest.java @@ -0,0 +1,50 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.session; + +import com.github.alexisjehan.javanilla.io.Serializables; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class MavenSessionExceptionTest { + + private static final Exception CAUSE = new Exception("foo-cause"); + + private final MavenSessionException mavenSessionException = new MavenSessionException(CAUSE); + + @Test + void testConstructorInvalid() { + assertThatNullPointerException().isThrownBy(() -> { + throw new MavenSessionException(null); + }); + } + + @Test + void testSerializable() { + assertThat(Serializables.deserialize(Serializables.serialize(mavenSessionException))) + .hasSameClassAs(mavenSessionException); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionTest.java new file mode 100644 index 0000000..852b2ee --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/component/session/MavenSessionTest.java @@ -0,0 +1,112 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.component.session; + +import com.github.alexisjehan.mavencheck.core.util.MavenUtils; +import org.apache.maven.settings.building.SettingsBuildingException; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +@ExtendWith(MockitoExtension.class) +final class MavenSessionTest { + + @Mock + private RepositorySystem mockedRepositorySystem; + + @Test + void testConstructorInvalid() { + try (final var mockedMavenUtils = Mockito.mockStatic(MavenUtils.class)) { + mockedMavenUtils.when(MavenUtils::makeSettings) + .thenThrow(SettingsBuildingException.class); + assertThatExceptionOfType(MavenSessionException.class) + .isThrownBy(MavenSession::new) + .withCauseInstanceOf(SettingsBuildingException.class); + } + } + + @Test + void testResolve() { + final var remoteRepositories = List.of(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")); + Mockito.when(mockedRepositorySystem.newResolutionRepositories(Mockito.any(), Mockito.any())) + .thenReturn(remoteRepositories); + try (final var mockedMavenUtils = Mockito.mockStatic(MavenUtils.class)) { + mockedMavenUtils.when(() -> MavenUtils.makeRepositorySystem(Mockito.any())) + .thenReturn(mockedRepositorySystem); + final var mavenSession = new MavenSession(); + assertThat(mavenSession.resolve(List.of())).isSameAs(remoteRepositories); + } + } + + @Test + void testResolveInvalid() { + final var mavenSession = new MavenSession(); + assertThatNullPointerException().isThrownBy(() -> mavenSession.resolve(null)); + assertThatNullPointerException().isThrownBy(() -> mavenSession.resolve(Collections.singletonList(null))); + } + + @Test + void testRequest() throws VersionRangeResolutionException { + final var versionRangeResult = new VersionRangeResult(new VersionRangeRequest()); + Mockito.when(mockedRepositorySystem.resolveVersionRange(Mockito.any(), Mockito.any())) + .thenReturn(versionRangeResult); + try (final var mockedMavenUtils = Mockito.mockStatic(MavenUtils.class)) { + mockedMavenUtils.when(() -> MavenUtils.makeRepositorySystem(Mockito.any())) + .thenReturn(mockedRepositorySystem); + final var mavenSession = new MavenSession(); + assertThat(mavenSession.request(new VersionRangeRequest())).isSameAs(versionRangeResult); + } + } + + @Test + void testRequestInvalid() { + final var mavenSession = new MavenSession(); + assertThatNullPointerException().isThrownBy(() -> mavenSession.request(null)); + } + + @Test + void testGetModelResolver() { + final var mavenSession = new MavenSession(); + assertThat(mavenSession.getModelResolver()).isNotNull(); + } + + @Test + void testGetModelCache() { + final var mavenSession = new MavenSession(); + assertThat(mavenSession.getModelCache()).isNotNull(); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListenerTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListenerTest.java new file mode 100644 index 0000000..7c99a23 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/ConsoleRepositoryListenerTest.java @@ -0,0 +1,517 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import org.apache.maven.settings.building.SettingsBuildingException; +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.metadata.DefaultMetadata; +import org.eclipse.aether.metadata.Metadata; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class ConsoleRepositoryListenerTest { + + private final ConsoleRepositoryListener consoleRepositoryListener = new ConsoleRepositoryListener(); + + @Test + void testArtifactDescriptorInvalid() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactDescriptorInvalid( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_DESCRIPTOR_INVALID + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setException(new RuntimeException()) + .build() + ) + ); + } + + @Test + void testArtifactDescriptorInvalidInvalid() { + assertThatNullPointerException() + .isThrownBy(() -> consoleRepositoryListener.artifactDescriptorInvalid(null)); + } + + @Test + void testArtifactDescriptorMissing() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactDescriptorMissing( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_DESCRIPTOR_MISSING + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .build() + ) + ); + } + + @Test + void testArtifactDescriptorMissingInvalid() { + assertThatNullPointerException() + .isThrownBy(() -> consoleRepositoryListener.artifactDescriptorMissing(null)); + } + + @Test + void testArtifactResolving() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactResolving( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_RESOLVING + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testArtifactResolvingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactResolving(null)); + } + + @Test + void testArtifactResolved() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactResolved( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_RESOLVED + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testArtifactResolvedInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactResolved(null)); + } + + @Test + void testArtifactDownloading() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactDownloading( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_DOWNLOADING + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testArtifactDownloadingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDownloading(null)); + } + + @Test + void testArtifactDownloaded() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactDownloaded( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_DOWNLOADED + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testArtifactDownloadedInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDownloaded(null)); + } + + @Test + void testArtifactInstalling() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactInstalling( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_INSTALLING + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setFile(new File("foo-file")) + .build() + ) + ); + } + + @Test + void testArtifactInstallingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactInstalling(null)); + } + + @Test + void testArtifactInstalled() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactInstalled( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_INSTALLED + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setFile(new File("foo-file")) + .build() + ) + ); + } + + @Test + void testArtifactInstalledInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactInstalled(null)); + } + + @Test + void testArtifactDeploying() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactDeploying( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_DEPLOYING + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testArtifactDeployingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDeploying(null)); + } + + @Test + void testArtifactDeployed() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.artifactDeployed( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.ARTIFACT_DEPLOYED + ) + .setArtifact(new DefaultArtifact("foo-group-id:foo-artifact-id:1.0.0")) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testArtifactDeployedInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.artifactDeployed(null)); + } + + @Test + void testMetadataInvalid() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataInvalid( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_INVALID + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setException(new RuntimeException()) + .build() + ) + ); + } + + @Test + void testMetadataInvalidInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataInvalid(null)); + } + + @Test + void testMetadataResolving() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataResolving( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_RESOLVING + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testMetadataResolvingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataResolving(null)); + } + + @Test + void testMetadataResolved() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataResolved( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_RESOLVED + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testMetadataResolvedInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataResolved(null)); + } + + @Test + void testMetadataDownloading() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataDownloading( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_DOWNLOADING + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testMetadataDownloadingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDownloading(null)); + } + + @Test + void testMetadataDownloaded() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataDownloaded( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_DOWNLOADED + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testMetadataDownloadedInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDownloaded(null)); + } + + @Test + void testMetadataInstalling() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataInstalling( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_INSTALLING + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setFile(new File("foo-file")) + .build() + ) + ); + } + + @Test + void testMetadataInstallingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataInstalling(null)); + } + + @Test + void testMetadataInstalled() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataInstalled( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_INSTALLED + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setFile(new File("foo-file")) + .build() + ) + ); + } + + @Test + void testMetadataInstalledInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataInstalled(null)); + } + + @Test + void testMetadataDeploying() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataDeploying( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_DEPLOYING + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testMetadataDeployingInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDeploying(null)); + } + + @Test + void testMetadataDeployed() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings(); + assertThatNoException().isThrownBy( + () -> consoleRepositoryListener.metadataDeployed( + new RepositoryEvent.Builder( + MavenUtils.makeRepositorySystemSession( + settings, + MavenUtils.makeDecryptedSettings(settings), + MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()) + ), + RepositoryEvent.EventType.METADATA_DEPLOYED + ) + .setMetadata(new DefaultMetadata("foo-metadata", Metadata.Nature.RELEASE)) + .setRepository(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")) + .build() + ) + ); + } + + @Test + void testMetadataDeployedInvalid() { + assertThatNullPointerException().isThrownBy(() -> consoleRepositoryListener.metadataDeployed(null)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettingsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettingsTest.java new file mode 100644 index 0000000..19066e9 --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/DecryptedSettingsTest.java @@ -0,0 +1,115 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import org.apache.maven.settings.Proxy; +import org.apache.maven.settings.Server; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class DecryptedSettingsTest { + + private static final List PROXIES = List.of(new Proxy()); + private static final List SERVERS = List.of(new Server()); + private static final List OTHER_PROXIES = List.of(); + private static final List OTHER_SERVERS = List.of(); + + private final DecryptedSettings decryptedSettings = new DecryptedSettings(PROXIES, SERVERS); + + @Test + void testConstructorImmutable() { + final var proxies = new ArrayList<>(PROXIES); + final var servers = new ArrayList<>(SERVERS); + final var decryptedSettings = new DecryptedSettings(proxies, servers); + proxies.clear(); + servers.clear(); + assertThat(decryptedSettings.getProxies()).containsExactlyElementsOf(PROXIES); + assertThat(decryptedSettings.getServers()).containsExactlyElementsOf(SERVERS); + } + + @Test + void testConstructorInvalid() { + assertThatNullPointerException() + .isThrownBy(() -> new DecryptedSettings(null, SERVERS)); + assertThatNullPointerException() + .isThrownBy(() -> new DecryptedSettings(Collections.singletonList(null), SERVERS)); + assertThatNullPointerException() + .isThrownBy(() -> new DecryptedSettings(PROXIES, null)); + assertThatNullPointerException() + .isThrownBy(() -> new DecryptedSettings(PROXIES, Collections.singletonList(null))); + } + + @Test + void testEqualsAndHashCodeAndToString() { + assertThat(decryptedSettings.equals(decryptedSettings)).isTrue(); + assertThat(decryptedSettings).isNotEqualTo(new Object()); + assertThat(new DecryptedSettings(PROXIES, SERVERS)).satisfies(otherDecryptedSettings -> { + assertThat(decryptedSettings).isNotSameAs(otherDecryptedSettings); + assertThat(decryptedSettings).isEqualTo(otherDecryptedSettings); + assertThat(decryptedSettings).hasSameHashCodeAs(otherDecryptedSettings); + assertThat(decryptedSettings).hasToString(otherDecryptedSettings.toString()); + }); + assertThat(new DecryptedSettings(OTHER_PROXIES, SERVERS)).satisfies(otherDecryptedSettings -> { + assertThat(decryptedSettings).isNotSameAs(otherDecryptedSettings); + assertThat(decryptedSettings).isNotEqualTo(otherDecryptedSettings); + assertThat(decryptedSettings).doesNotHaveSameHashCodeAs(otherDecryptedSettings); + assertThat(decryptedSettings).doesNotHaveToString(otherDecryptedSettings.toString()); + }); + assertThat(new DecryptedSettings(PROXIES, OTHER_SERVERS)).satisfies(otherDecryptedSettings -> { + assertThat(decryptedSettings).isNotSameAs(otherDecryptedSettings); + assertThat(decryptedSettings).isNotEqualTo(otherDecryptedSettings); + assertThat(decryptedSettings).doesNotHaveSameHashCodeAs(otherDecryptedSettings); + assertThat(decryptedSettings).doesNotHaveToString(otherDecryptedSettings.toString()); + }); + } + + @Test + void testGetProxies() { + assertThat(decryptedSettings.getProxies()).isEqualTo(PROXIES); + } + + @Test + void testGetProxiesImmutable() { + final var proxies = decryptedSettings.getProxies(); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(proxies::clear); + } + + @Test + void testGetServers() { + assertThat(decryptedSettings.getServers()).isEqualTo(SERVERS); + } + + @Test + void testGetServersImmutable() { + final var servers = decryptedSettings.getServers(); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(servers::clear); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/GradleUtilsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/GradleUtilsTest.java new file mode 100644 index 0000000..18f7e0c --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/GradleUtilsTest.java @@ -0,0 +1,98 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.io.File; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +final class GradleUtilsTest { + + @Test + void testRetrieveOptionalHome() { + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME")) + .thenReturn(Optional.empty()); + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + "bar" + ) + ); + assertThat(GradleUtils.retrieveOptionalHome()).isEmpty(); + } + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME")) + .thenReturn(Optional.empty()); + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + File.separator + "gradle-1.0" + File.separator + "bin", + "bar" + ) + ); + assertThat(GradleUtils.retrieveOptionalHome()).contains(File.separator + "gradle-1.0"); + } + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME")) + .thenReturn(Optional.of(File.separatorChar + "gradle-1.0")); + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + "bar" + ) + ); + assertThat(GradleUtils.retrieveOptionalHome()).contains(File.separator + "gradle-1.0"); + } + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(() -> SystemUtils.getEnvironmentVariable("GRADLE_HOME")) + .thenReturn(Optional.of(File.separatorChar + "gradle-1.0")); + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + File.separator + "gradle-1.0" + File.separator + "bin", + "bar" + ) + ); + assertThat(GradleUtils.retrieveOptionalHome()).contains(File.separator + "gradle-1.0"); + } + } + + @Test + void testGetVersion() { + assertThat(GradleUtils.getVersion()).matches("^\\d+\\.\\d+(?:\\.\\d+)?$"); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/MavenUtilsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/MavenUtilsTest.java new file mode 100644 index 0000000..dc3452f --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/MavenUtilsTest.java @@ -0,0 +1,501 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.apache.maven.settings.Repository; +import org.apache.maven.settings.RepositoryPolicy; +import org.apache.maven.settings.building.SettingsBuildingException; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.util.repository.AuthenticationBuilder; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.io.File; +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class MavenUtilsTest { + + @Test + void testRetrieveOptionalGlobalHome() { + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + "bar" + ) + ); + assertThat(MavenUtils.retrieveOptionalGlobalHome()).isEmpty(); + } + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + File.separator + "apache-maven-1.0.0" + File.separator + "bin", + "bar" + ) + ); + assertThat(MavenUtils.retrieveOptionalGlobalHome()).contains(File.separator + "apache-maven-1.0.0"); + } + } + + @Test + void testRetrieveOptionalGlobalSettingsFile() { + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + "bar" + ) + ); + assertThat(MavenUtils.retrieveOptionalGlobalSettingsFile()) + .isEmpty(); + } + try (final var mockedSystemUtils = Mockito.mockStatic(SystemUtils.class)) { + mockedSystemUtils.when(SystemUtils::getPathEnvironmentVariable) + .thenReturn( + String.join( + File.pathSeparator, + "foo", + File.separator + "apache-maven-1.0.0" + File.separator + "bin", + "bar" + ) + ); + assertThat(MavenUtils.retrieveOptionalGlobalSettingsFile()) + .contains( + Path.of( + File.separator + "apache-maven-1.0.0", + "conf", + "settings.xml" + ) + ); + } + } + + @Test + void testCreateRemoteRepository() { + final var remoteRepository = MavenUtils.createRemoteRepository("foo-id", "foo-url"); + assertThat(remoteRepository.getId()).isEqualTo("foo-id"); + assertThat(remoteRepository.getUrl()).isEqualTo("foo-url"); + } + + @Test + void testCreateRemoteRepositoryInvalid() { + assertThatNullPointerException() + .isThrownBy(() -> MavenUtils.createRemoteRepository(null, "https://foo-host")); + assertThatIllegalArgumentException() + .isThrownBy(() -> MavenUtils.createRemoteRepository(Strings.EMPTY, "https://foo-host")); + assertThatNullPointerException() + .isThrownBy(() -> MavenUtils.createRemoteRepository("foo-id", null)); + assertThatIllegalArgumentException() + .isThrownBy(() -> MavenUtils.createRemoteRepository("foo-id", Strings.EMPTY)); + } + + @Test + void testToRemoteRepository() { + final var repository = new Repository(); + repository.setId("foo-id"); + repository.setLayout("foo-layout"); + repository.setUrl("https://foo-host"); + final var releasesPolicy = new RepositoryPolicy(); + releasesPolicy.setEnabled(true); + releasesPolicy.setUpdatePolicy("foo-update-releases-policy"); + releasesPolicy.setChecksumPolicy("foo-checksum-releases-policy"); + repository.setReleases(releasesPolicy); + final var snapshotsPolicy = new RepositoryPolicy(); + snapshotsPolicy.setEnabled(false); + snapshotsPolicy.setUpdatePolicy("foo-update-snapshots-policy"); + snapshotsPolicy.setChecksumPolicy("foo-checksum-snapshots-policy"); + repository.setSnapshots(snapshotsPolicy); + final var remoteRepository = MavenUtils.toRemoteRepository(repository); + assertThat(remoteRepository.getId()) + .isEqualTo("foo-id"); + assertThat(remoteRepository.getContentType()) + .isEqualTo("foo-layout"); + assertThat(remoteRepository.getUrl()) + .isEqualTo("https://foo-host"); + assertThat(remoteRepository.getPolicy(false).isEnabled()) + .isTrue(); + assertThat(remoteRepository.getPolicy(false).getUpdatePolicy()) + .isEqualTo("foo-update-releases-policy"); + assertThat(remoteRepository.getPolicy(false).getChecksumPolicy()) + .isEqualTo("foo-checksum-releases-policy"); + assertThat(remoteRepository.getPolicy(true).isEnabled()) + .isFalse(); + assertThat(remoteRepository.getPolicy(true).getUpdatePolicy()) + .isEqualTo("foo-update-snapshots-policy"); + assertThat(remoteRepository.getPolicy(true).getChecksumPolicy()) + .isEqualTo("foo-checksum-snapshots-policy"); + } + + @Test + void testToRemoteRepositoryInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.toRemoteRepository(null)); + } + + @Test + void testMakeServiceLocator() { + assertThat(MavenUtils.makeServiceLocator()).isNotNull(); + } + + @Test + void testMakeRepositorySystem() { + assertThat(MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator())).isNotNull(); + } + + @Test + void testMakeRepositorySystemInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeRepositorySystem(null)); + } + + @Test + void testMakeRemoteRepositoryManager() { + assertThat(MavenUtils.makeRemoteRepositoryManager(MavenUtils.makeServiceLocator())).isNotNull(); + } + + @Test + void testMakeRemoteRepositoryManagerInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeRemoteRepositoryManager(null)); + } + + @Test + void testMakeSettings() throws SettingsBuildingException { + assertThat(MavenUtils.makeSettings()).isNotNull(); + assertThat(MavenUtils.makeSettings(null, null)).isNotNull(); + assertThat(Path.of("src", "test", "resources", "settings_foo.xml")).satisfies( + settingsFile -> assertThat(MavenUtils.makeSettings(settingsFile, settingsFile)).isNotNull() + ); + assertThat(Path.of("src", "test", "resources", "settings_warning.xml")).satisfies( + settingsFile -> assertThat(MavenUtils.makeSettings(settingsFile, settingsFile)).isNotNull() + ); + assertThat(Path.of("src", "test", "resources", "settings_not-found.xml")).satisfies( + settingsFile -> assertThat(MavenUtils.makeSettings(settingsFile, settingsFile)).isNotNull() + ); + } + + @Test + void testMakeSettingsInvalid() { + final var settingsFile = Path.of("src", "test", "resources", "settings_error.xml"); + assertThatExceptionOfType(SettingsBuildingException.class) + .isThrownBy(() -> MavenUtils.makeSettings(settingsFile, settingsFile)); + } + + @Test + void testMakeDecryptedSettings() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ); + assertThat( + MavenUtils.makeDecryptedSettings(settings) + ).satisfies(decryptedSettings -> { + assertThat(decryptedSettings.getProxies()) + .anySatisfy(proxy -> assertThat(proxy.getPassword()).isNotEqualTo("foo-password")); + assertThat(decryptedSettings.getServers()) + .anySatisfy(server -> assertThat(server.getPassword()).isNotEqualTo("foo-password")); + }); + assertThat( + MavenUtils.makeDecryptedSettings(settings, null) + ).satisfies(decryptedSettings -> { + assertThat(decryptedSettings.getProxies()) + .anySatisfy(proxy -> assertThat(proxy.getPassword()).isNotEqualTo("foo-password")); + assertThat(decryptedSettings.getServers()) + .anySatisfy(server -> assertThat(server.getPassword()).isNotEqualTo("foo-password")); + }); + assertThat( + MavenUtils.makeDecryptedSettings( + settings, + Path.of("src", "test", "resources", "settings-security.xml") + ) + ).satisfies(decryptedSettings -> { + assertThat(decryptedSettings.getProxies()) + .anySatisfy(proxy -> assertThat(proxy.getPassword()).isEqualTo("foo-password")); + assertThat(decryptedSettings.getServers()) + .anySatisfy(server -> assertThat(server.getPassword()).isEqualTo("foo-password")); + }); + assertThat( + MavenUtils.makeDecryptedSettings( + settings, + Path.of("src", "test", "resources", "settings-security_not-found.xml") + ) + ).satisfies(decryptedSettings -> { + assertThat(decryptedSettings.getProxies()) + .anySatisfy(proxy -> assertThat(proxy.getPassword()).isNotEqualTo("foo-password")); + assertThat(decryptedSettings.getServers()) + .anySatisfy(server -> assertThat(server.getPassword()).isNotEqualTo("foo-password")); + }); + } + + @Test + void testMakeDecryptedSettingsInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeDecryptedSettings(null)); + } + + @Test + void testMakeLocalRepository() throws SettingsBuildingException { + final var localRepository = new LocalRepository("foo-directory"); + assertThat( + MavenUtils.makeLocalRepository( + MavenUtils.makeSettings(null, null) + ) + ).isNotEqualTo(localRepository); + assertThat( + MavenUtils.makeLocalRepository( + MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ) + ) + ).isEqualTo(localRepository); + } + + @Test + void testMakeLocalRepositoryInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeLocalRepository(null)); + } + + @Test + void testMakeProxySelector() throws SettingsBuildingException { + final var proxy = new Proxy( + "http", + "foo-host", + 8080, + new AuthenticationBuilder() + .addUsername("foo-username") + .addPassword("foo-password") + .build() + ); + assertThat( + MavenUtils.makeProxySelector( + MavenUtils.makeDecryptedSettings( + MavenUtils.makeSettings(null, null), + null + ) + ) + ).satisfies(proxySelector -> { + assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))) + .isNull(); + assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("bar-id", "https://bar-host"))) + .isNull(); + }); + assertThat( + MavenUtils.makeProxySelector( + MavenUtils.makeDecryptedSettings( + MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ), + Path.of("src", "test", "resources", "settings-security.xml") + ) + ) + ).satisfies(proxySelector -> { + assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("foo-id", "https://foo-host"))) + .isEqualTo(proxy); + assertThat(proxySelector.getProxy(MavenUtils.createRemoteRepository("bar-id", "https://bar-host"))) + .isNull(); + }); + } + + @Test + void testMakeProxySelectorInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeProxySelector(null)); + } + + @Test + void testMakeAuthenticationSelector() throws SettingsBuildingException { + final var authentication = new AuthenticationBuilder() + .addUsername("foo-username") + .addPassword("foo-password") + .build(); + assertThat( + MavenUtils.makeAuthenticationSelector( + MavenUtils.makeDecryptedSettings( + MavenUtils.makeSettings(null, null), + null + ) + ) + ).satisfies(authenticationSelector -> { + assertThat( + authenticationSelector.getAuthentication( + MavenUtils.createRemoteRepository("foo-id", "https://foo-host") + ) + ).isNull(); + assertThat( + authenticationSelector.getAuthentication( + MavenUtils.createRemoteRepository("bar-id", "https://bar-host") + ) + ).isNull(); + }); + assertThat( + MavenUtils.makeAuthenticationSelector( + MavenUtils.makeDecryptedSettings( + MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ), + Path.of("src", "test", "resources", "settings-security.xml") + ) + ) + ).satisfies(authenticationSelector -> { + assertThat( + authenticationSelector.getAuthentication( + MavenUtils.createRemoteRepository("foo-id", "https://foo-host") + ) + ).isEqualTo(authentication); + assertThat( + authenticationSelector.getAuthentication( + MavenUtils.createRemoteRepository("bar-id", "https://bar-host") + ) + ).isNull(); + }); + } + + @Test + void testMakeAuthenticationSelectorInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeAuthenticationSelector(null)); + } + + @Test + void testMakeMirrorSelector() throws SettingsBuildingException { + final var remoteRepositoryBuilder = new RemoteRepository.Builder( + "default", + "default", + "https://foo-mirror-host" + ); + assertThat( + MavenUtils.makeMirrorSelector( + MavenUtils.makeSettings(null, null) + ) + ).satisfies(mirrorSelector -> { + assertThat(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")).satisfies( + remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isNull() + ); + assertThat(MavenUtils.createRemoteRepository("bar-id", "https://bar-host")).satisfies( + remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isNull() + ); + }); + assertThat( + MavenUtils.makeMirrorSelector( + MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ) + ) + ).satisfies(mirrorSelector -> { + assertThat(MavenUtils.createRemoteRepository("foo-id", "https://foo-host")).satisfies( + remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isEqualTo( + remoteRepositoryBuilder.setMirroredRepositories(List.of(remoteRepository)).build() + ) + ); + assertThat(MavenUtils.createRemoteRepository("bar-id", "https://bar-host")).satisfies( + remoteRepository -> assertThat(mirrorSelector.getMirror(remoteRepository)).isNull() + ); + }); + } + + @Test + void testMakeMirrorSelectorInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeMirrorSelector(null)); + } + + @Test + void testMakeRepositorySystemSession() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ); + final var decryptedSettings = MavenUtils.makeDecryptedSettings( + settings, + Path.of("src", "test", "resources", "settings-security.xml") + ); + final var repositorySystem = MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()); + assertThat(MavenUtils.makeRepositorySystemSession(settings, decryptedSettings, repositorySystem)).isNotNull(); + } + + @Test + void testMakeRepositorySystemSessionInvalid() throws SettingsBuildingException { + final var settings = MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ); + final var decryptedSettings = MavenUtils.makeDecryptedSettings( + settings, + Path.of("src", "test", "resources", "settings-security.xml") + ); + final var repositorySystem = MavenUtils.makeRepositorySystem(MavenUtils.makeServiceLocator()); + assertThatNullPointerException().isThrownBy( + () -> MavenUtils.makeRepositorySystemSession(null, decryptedSettings, repositorySystem) + ); + assertThatNullPointerException().isThrownBy( + () -> MavenUtils.makeRepositorySystemSession(settings, null, repositorySystem) + ); + assertThatNullPointerException().isThrownBy( + () -> MavenUtils.makeRepositorySystemSession(settings, decryptedSettings, null) + ); + } + + @Test + void testMakeRemoteRepositories() throws SettingsBuildingException { + assertThat( + MavenUtils.makeRemoteRepositories( + MavenUtils.makeSettings(null, null) + ) + ).isEmpty(); + assertThat( + MavenUtils.makeRemoteRepositories( + MavenUtils.makeSettings( + null, + Path.of("src", "test", "resources", "settings_foo.xml") + ) + ) + ).containsExactly( + MavenUtils.createRemoteRepository("foo-id", "https://foo-host"), + MavenUtils.createRemoteRepository("foo-plugin-id", "https://foo-plugin-host") + ); + } + + @Test + void testMakeRemoteRepositoriesInvalid() { + assertThatNullPointerException().isThrownBy(() -> MavenUtils.makeRemoteRepositories(null)); + } + + @Test + void testGetVersion() { + assertThat(MavenUtils.getVersion()).matches("^\\d+\\.\\d+\\.\\d+$"); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/alexisjehan/mavencheck/core/util/SystemUtilsTest.java b/src/test/java/com/github/alexisjehan/mavencheck/core/util/SystemUtilsTest.java new file mode 100644 index 0000000..4d013db --- /dev/null +++ b/src/test/java/com/github/alexisjehan/mavencheck/core/util/SystemUtilsTest.java @@ -0,0 +1,56 @@ +/* + * MIT License + * + * Copyright (c) 2022 Alexis Jehan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.alexisjehan.mavencheck.core.util; + +import com.github.alexisjehan.javanilla.lang.Strings; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +final class SystemUtilsTest { + + @Test + void testGetEnvironmentVariable() { + assertThat(SystemUtils.getEnvironmentVariable("PATH")).isPresent(); + assertThat(SystemUtils.getEnvironmentVariable("NOT_FOUND")).isEmpty(); + } + + @Test + void testGetEnvironmentVariableInvalid() { + assertThatNullPointerException().isThrownBy(() -> SystemUtils.getEnvironmentVariable(null)); + assertThatIllegalArgumentException().isThrownBy(() -> SystemUtils.getEnvironmentVariable(Strings.EMPTY)); + } + + @Test + void testGetPathEnvironmentVariable() { + assertThat(SystemUtils.getPathEnvironmentVariable()).isNotEmpty(); + } + + @Test + void testGetUserHomeDirectory() { + assertThat(SystemUtils.getUserHomeDirectory()).isDirectory(); + } +} \ No newline at end of file diff --git a/src/test/resources/.mvnchk-ignore_error b/src/test/resources/.mvnchk-ignore_error new file mode 100644 index 0000000..760589c --- /dev/null +++ b/src/test/resources/.mvnchk-ignore_error @@ -0,0 +1 @@ +error \ No newline at end of file diff --git a/src/test/resources/.mvnchk-ignore_foo b/src/test/resources/.mvnchk-ignore_foo new file mode 100644 index 0000000..1bac4f1 --- /dev/null +++ b/src/test/resources/.mvnchk-ignore_foo @@ -0,0 +1,10 @@ +# comment +foo-group-id:foo-artifact-id +foo-group-id:foo-artifact-id:foo-version +foo-group-id:foo-artifact-id:FOO-VERSION +foo-group-id:foo-artifact-id:foo-version? +foo-group-id:foo-artifact-id:foo-? +foo-group-id:foo-artifact-id:foo-??????? +foo-group-id:foo-artifact-id:foo-version* +foo-group-id:foo-artifact-id:foo-* +foo-group-id:foo-artifact-id:foo-******* \ No newline at end of file diff --git a/src/test/resources/build_error.gradle b/src/test/resources/build_error.gradle new file mode 100644 index 0000000..d97a38e --- /dev/null +++ b/src/test/resources/build_error.gradle @@ -0,0 +1,5 @@ +plugins { + id 'java-library' +} + +error \ No newline at end of file diff --git a/src/test/resources/build_error.gradle.kts b/src/test/resources/build_error.gradle.kts new file mode 100644 index 0000000..6aca9b6 --- /dev/null +++ b/src/test/resources/build_error.gradle.kts @@ -0,0 +1,5 @@ +plugins { + `java-library` +} + +error \ No newline at end of file diff --git a/src/test/resources/build_foo.gradle b/src/test/resources/build_foo.gradle new file mode 100644 index 0000000..c744adc --- /dev/null +++ b/src/test/resources/build_foo.gradle @@ -0,0 +1,28 @@ +plugins { + id 'java-library' +} + +repositories { + mavenCentral() + maven { + name 'foo-repository-name' + url 'https://foo-repository-host' + } + ivy { + name 'bar-repository-name' + url 'https://bar-repository-host' + } +} + +dependencies { + annotationProcessor 'foo-annotation-processor-group-id:foo-annotation-processor-artifact-id:foo-annotation-processor-version' + api 'foo-api-group-id:foo-api-artifact-id:foo-api-version' + compileOnly 'foo-compile-only-group-id:foo-compile-only-artifact-id:foo-compile-only-version' + compileOnlyApi 'foo-compile-only-api-group-id:foo-compile-only-api-artifact-id:foo-compile-only-api-version' + implementation 'foo-implementation-group-id:foo-implementation-artifact-id:foo-implementation-version' + runtimeOnly 'foo-runtime-only-group-id:foo-runtime-only-artifact-id:foo-runtime-only-version' + testAnnotationProcessor 'foo-test-annotation-processor-group-id:foo-test-annotation-processor-artifact-id:foo-test-annotation-processor-version' + testCompileOnly 'foo-test-compile-only-group-id:foo-test-compile-only-artifact-id:foo-test-compile-only-version' + testImplementation 'foo-test-implementation-group-id:foo-test-implementation-artifact-id:foo-test-implementation-version' + testRuntimeOnly 'foo-test-runtime-only-group-id:foo-test-runtime-only-artifact-id:foo-test-runtime-only-version' +} \ No newline at end of file diff --git a/src/test/resources/build_foo.gradle.kts b/src/test/resources/build_foo.gradle.kts new file mode 100644 index 0000000..f892aeb --- /dev/null +++ b/src/test/resources/build_foo.gradle.kts @@ -0,0 +1,28 @@ +plugins { + `java-library` +} + +repositories { + mavenCentral() + maven { + name = "foo-repository-name" + url = uri("https://foo-repository-host") + } + ivy { + name = "bar-repository-name" + url = uri("https://bar-repository-host") + } +} + +dependencies { + annotationProcessor("foo-annotation-processor-group-id:foo-annotation-processor-artifact-id:foo-annotation-processor-version") + api("foo-api-group-id:foo-api-artifact-id:foo-api-version") + compileOnly("foo-compile-only-group-id:foo-compile-only-artifact-id:foo-compile-only-version") + compileOnlyApi("foo-compile-only-api-group-id:foo-compile-only-api-artifact-id:foo-compile-only-api-version") + implementation("foo-implementation-group-id:foo-implementation-artifact-id:foo-implementation-version") + runtimeOnly("foo-runtime-only-group-id:foo-runtime-only-artifact-id:foo-runtime-only-version") + testAnnotationProcessor("foo-test-annotation-processor-group-id:foo-test-annotation-processor-artifact-id:foo-test-annotation-processor-version") + testCompileOnly("foo-test-compile-only-group-id:foo-test-compile-only-artifact-id:foo-test-compile-only-version") + testImplementation("foo-test-implementation-group-id:foo-test-implementation-artifact-id:foo-test-implementation-version") + testRuntimeOnly("foo-test-runtime-only-group-id:foo-test-runtime-only-artifact-id:foo-test-runtime-only-version") +} \ No newline at end of file diff --git a/src/test/resources/build_it.gradle b/src/test/resources/build_it.gradle new file mode 100644 index 0000000..f4ee7a9 --- /dev/null +++ b/src/test/resources/build_it.gradle @@ -0,0 +1,22 @@ +plugins { + id 'java-library' +} + +repositories { + mavenCentral() + maven { + name 'google' + url 'https://maven.google.com' + } + ivy { + url 'https://ivy.example.com' + } +} + +dependencies { + implementation 'com.google.android.material:material:1.0.0' + implementation 'com.google.guava:guava:10.0' + implementation 'com.google.guava:guava:23.1-jre' + implementation 'com.google.guava:guava:23.1-android' + implementation 'org.springframework:spring-core:3.0.0.RELEASE' +} \ No newline at end of file diff --git a/src/test/resources/build_it.gradle.kts b/src/test/resources/build_it.gradle.kts new file mode 100644 index 0000000..ebdcbee --- /dev/null +++ b/src/test/resources/build_it.gradle.kts @@ -0,0 +1,22 @@ +plugins { + `java-library` +} + +repositories { + mavenCentral() + maven { + name = "google" + url = uri("https://maven.google.com") + } + ivy { + url = uri("https://ivy.example.com") + } +} + +dependencies { + implementation("com.google.android.material:material:1.0.0") + implementation("com.google.guava:guava:10.0") + implementation("com.google.guava:guava:23.1-jre") + implementation("com.google.guava:guava:23.1-android") + implementation("org.springframework:spring-core:3.0.0.RELEASE") +} \ No newline at end of file diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml new file mode 100644 index 0000000..b36ad10 --- /dev/null +++ b/src/test/resources/log4j2.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/pom_empty.xml b/src/test/resources/pom_empty.xml new file mode 100644 index 0000000..03b8d61 --- /dev/null +++ b/src/test/resources/pom_empty.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + foo-group-id + foo-artifact-id + foo-version + + + + + + foo-profile-id + + + bar-profile-id + + + + \ No newline at end of file diff --git a/src/test/resources/pom_error.xml b/src/test/resources/pom_error.xml new file mode 100644 index 0000000..001a664 --- /dev/null +++ b/src/test/resources/pom_error.xml @@ -0,0 +1,6 @@ + + + 4.0.0 + + \ No newline at end of file diff --git a/src/test/resources/pom_foo.xml b/src/test/resources/pom_foo.xml new file mode 100644 index 0000000..82a32ee --- /dev/null +++ b/src/test/resources/pom_foo.xml @@ -0,0 +1,158 @@ + + + 4.0.0 + + + + foo-repository-id + https://foo-repository-host + + + + + + foo-plugin-repository-id + https://foo-plugin-repository-host + + + + + foo-parent-group-id + foo-parent-artifact-id + foo-parent-version + pom_foo_parent.xml + + + foo-artifact-id + + + + + foo-dependency-management-dependency-group-id + foo-dependency-management-dependency-artifact-id + foo-dependency-management-dependency-version + + + + + + + foo-dependency-group-id + foo-dependency-artifact-id + foo-dependency-version + + + + + + + foo-build-extension-group-id + foo-build-extension-artifact-id + foo-build-extension-version + + + + + + foo-build-plugin-management-plugin-group-id + foo-build-plugin-management-plugin-artifact-id + foo-build-plugin-management-plugin-version + + + foo-build-plugin-management-plugin-dependency-group-id + foo-build-plugin-management-plugin-dependency-artifact-id + foo-build-plugin-management-plugin-dependency-version + + + + + + + + foo-build-plugin-group-id + foo-build-plugin-artifact-id + foo-build-plugin-version + + + foo-build-plugin-dependency-group-id + foo-build-plugin-dependency-artifact-id + foo-build-plugin-dependency-version + + + + + + + + + + foo-reporting-plugin-group-id + foo-reporting-plugin-artifact-id + foo-reporting-plugin-version + + + + + + + foo-profile-id + + + + foo-profile-dependency-management-dependency-group-id + foo-profile-dependency-management-dependency-artifact-id + foo-profile-dependency-management-dependency-version + + + + + + foo-profile-dependency-group-id + foo-profile-dependency-artifact-id + foo-profile-dependency-version + + + + + + + foo-profile-build-plugin-management-plugin-group-id + foo-profile-build-plugin-management-plugin-artifact-id + foo-profile-build-plugin-management-plugin-version + + + foo-profile-build-plugin-management-plugin-dependency-group-id + foo-profile-build-plugin-management-plugin-dependency-artifact-id + foo-profile-build-plugin-management-plugin-dependency-version + + + + + + + + foo-profile-build-plugin-group-id + foo-profile-build-plugin-artifact-id + foo-profile-build-plugin-version + + + foo-profile-build-plugin-dependency-group-id + foo-profile-build-plugin-dependency-artifact-id + foo-profile-build-plugin-dependency-version + + + + + + + + + foo-profile-reporting-plugin-group-id + foo-profile-reporting-plugin-artifact-id + foo-profile-reporting-plugin-version + + + + + + \ No newline at end of file diff --git a/src/test/resources/pom_foo_parent.xml b/src/test/resources/pom_foo_parent.xml new file mode 100644 index 0000000..b5e336a --- /dev/null +++ b/src/test/resources/pom_foo_parent.xml @@ -0,0 +1,9 @@ + + + 4.0.0 + + foo-parent-group-id + foo-parent-artifact-id + foo-parent-version + pom + \ No newline at end of file diff --git a/src/test/resources/pom_it.xml b/src/test/resources/pom_it.xml new file mode 100644 index 0000000..0bb5fc3 --- /dev/null +++ b/src/test/resources/pom_it.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + repository-maven + repository-maven + 1.0.0-SNAPSHOT + + + + google + Google + https://maven.google.com + + + + + + com.google.android.material + material + 1.0.0 + + + com.google.guava + guava + 10.0 + + + org.springframework + spring-core + 3.0.0.RELEASE + + + + + + jre + + + com.google.guava + guava + 23.1-jre + + + + + android + + + com.google.guava + guava + 23.1-android + + + + + \ No newline at end of file diff --git a/src/test/resources/settings-security.xml b/src/test/resources/settings-security.xml new file mode 100644 index 0000000..f0872ff --- /dev/null +++ b/src/test/resources/settings-security.xml @@ -0,0 +1,4 @@ + + + {aYVAWydUmZUHOanaKCcasd0+ZXjD8EZotUV/cWLgW2I=} + \ No newline at end of file diff --git a/src/test/resources/settings_error.xml b/src/test/resources/settings_error.xml new file mode 100644 index 0000000..0d19cab --- /dev/null +++ b/src/test/resources/settings_error.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/src/test/resources/settings_foo.xml b/src/test/resources/settings_foo.xml new file mode 100644 index 0000000..0d2da19 --- /dev/null +++ b/src/test/resources/settings_foo.xml @@ -0,0 +1,72 @@ + + + foo-directory + + + foo-host + foo-username + {yEMdGzgwNvAHEqBqqJ0td2W8uGxr3mRr+BQayeeKfvs=} + bar-host + + + + + foo-id + foo-username + {yEMdGzgwNvAHEqBqqJ0td2W8uGxr3mRr+BQayeeKfvs=} + + + + + https://foo-mirror-host + foo-id + + + + + foo-id + + true + + + + foo-id + https://foo-host + + + + + foo-plugin-id + + + foo-plugin-id + https://foo-plugin-host + + + + + bar-id + + false + + + + bar-id + https://bar-host + + + + + bar-plugin-id + + + bar-plugin-id + https://bar-plugin-host + + + + + + foo-plugin-id + + \ No newline at end of file diff --git a/src/test/resources/settings_it_since-6.8.gradle b/src/test/resources/settings_it_since-6.8.gradle new file mode 100644 index 0000000..5e82d35 --- /dev/null +++ b/src/test/resources/settings_it_since-6.8.gradle @@ -0,0 +1,15 @@ +pluginManagement { + repositories { + maven { + url 'https://plugin-management.example.com' + } + } +} + +dependencyResolutionManagement { + repositories { + maven { + url 'https://dependency-resolution-management.example.com' + } + } +} \ No newline at end of file diff --git a/src/test/resources/settings_it_since-6.8.gradle.kts b/src/test/resources/settings_it_since-6.8.gradle.kts new file mode 100644 index 0000000..8dd18d5 --- /dev/null +++ b/src/test/resources/settings_it_since-6.8.gradle.kts @@ -0,0 +1,15 @@ +pluginManagement { + repositories { + maven { + url = uri("https://plugin-management.example.com") + } + } +} + +dependencyResolutionManagement { + repositories { + maven { + url = uri("https://dependency-resolution-management.example.com") + } + } +} \ No newline at end of file diff --git a/src/test/resources/settings_it_until-6.7.gradle b/src/test/resources/settings_it_until-6.7.gradle new file mode 100644 index 0000000..64d96e1 --- /dev/null +++ b/src/test/resources/settings_it_until-6.7.gradle @@ -0,0 +1,7 @@ +pluginManagement { + repositories { + maven { + url 'https://plugin-management.example.com' + } + } +} \ No newline at end of file diff --git a/src/test/resources/settings_it_until-6.7.gradle.kts b/src/test/resources/settings_it_until-6.7.gradle.kts new file mode 100644 index 0000000..de770ab --- /dev/null +++ b/src/test/resources/settings_it_until-6.7.gradle.kts @@ -0,0 +1,7 @@ +pluginManagement { + repositories { + maven { + url = uri("https://plugin-management.example.com") + } + } +} \ No newline at end of file diff --git a/src/test/resources/settings_warning.xml b/src/test/resources/settings_warning.xml new file mode 100644 index 0000000..ac88dcc --- /dev/null +++ b/src/test/resources/settings_warning.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file