diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..32bf1e5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Automatically normalize line endings for all text-based files +* text=auto + +# set scripts to lf +*.sh text eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9b7442 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Compiled source +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases +*.log +*.sqlite + +# OS generated files +.DS_Store +ehthumbs.db +Icon +Thumbs.db + +# Idea +.idea/* +*.iml +*.iws +*.ipr + +# Maven +target + +# Test resource +!asset-zip-example.zip diff --git a/.run/main-checkstyle[check].run.xml b/.run/main-checkstyle[check].run.xml new file mode 100644 index 0000000..5ee2e9d --- /dev/null +++ b/.run/main-checkstyle[check].run.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/main-pmd[check].run.xml b/.run/main-pmd[check].run.xml new file mode 100644 index 0000000..97d17c4 --- /dev/null +++ b/.run/main-pmd[check].run.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/main[deploy].run.xml b/.run/main[deploy].run.xml new file mode 100644 index 0000000..ae36bc7 --- /dev/null +++ b/.run/main[deploy].run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/main[install].run.xml b/.run/main[install].run.xml new file mode 100644 index 0000000..1a868f2 --- /dev/null +++ b/.run/main[install].run.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/main[test].run.xml b/.run/main[test].run.xml new file mode 100644 index 0000000..2c798c7 --- /dev/null +++ b/.run/main[test].run.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/main[verify].run.xml b/.run/main[verify].run.xml new file mode 100644 index 0000000..b26772a --- /dev/null +++ b/.run/main[verify].run.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/plugin-example[install].run.xml b/.run/plugin-example[install].run.xml new file mode 100644 index 0000000..9a31d39 --- /dev/null +++ b/.run/plugin-example[install].run.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/plugin-example[run].run.xml b/.run/plugin-example[run].run.xml new file mode 100644 index 0000000..7c9b72c --- /dev/null +++ b/.run/plugin-example[run].run.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/MIT.LICENSE b/MIT.LICENSE new file mode 100644 index 0000000..8883431 --- /dev/null +++ b/MIT.LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2022 Michael Wiesendanger + +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. diff --git a/README.md b/README.md index c139a65..43d8d44 100644 --- a/README.md +++ b/README.md @@ -1 +1,216 @@ # wago-release-maven-plugin + +> A maven plugin for creating Wago.io mods/addons releases + +[![Maven Central](https://img.shields.io/maven-central/v/com.ragedunicorn.tools.maven/wago-release-maven-plugin.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.ragedunicorn.tools.maven%22%20AND%20a:%wago-release-maven-plugin%22) + +## Usage + +Setup pom.xml in project + +```xml + + [...] + + + + com.ragedunicorn.tools.maven + wago-release-maven-plugin + [version] + + + default-cli + + [projectId] + + release description overwritten by release notes + src/main/resources/release-notes-example.md + [game-version] + [game-version] + [game-version] + stable + [path-to-packaged-addon] + [.m2/settings.xml server name] + + + + + + + [...] + +``` +| Parameter | Required | Default Value | Description | +| --------------------- | -------- | ------------- | --------------------------------------------------------------------------------------------------------------------------- | +| | +| projectId | true | <> | The project id of the wago.io project (can be found on the developer dashboard) | +| server | false | <> | References a server configuration in your .m2 settings.xml. This is the preferred way for using the generated wago.io token | +| authToken | false | <> | Alternative of using a server configuration. The authToken can directly be placed in the plugin configuration | +| label | false | addon | An optional label for the uploaded file | +| changelog | false | <> | A string containing the changelog | +| changelogFile | false | <> | Optional path to a changelog file - will override changelog | +| supportedRetailPatch | false | <> | A number representing the retail supported version | +| supportedBccPatch | false | <> | A number representing the burning crusade supported version | +| supportedClassicPatch | false | <> | A number representing the classic supported version | +| releaseType | false | release | One of "stable", "beta", "alpha" | +| file | true | <> | The path to the addon to upload | + +### Execute Plugin + +``` +mvn wago-release:wago-release +``` + + +## Setup Api Token + +Before the plugin can be used an API token has to be generated. + +See Wago.io [documentation](https://addons.wago.io/account/apikeys) + +Once the Api token is generated it can be stored inside the maven `.m2/settings.xml`. + + ```xml + + wago-token + token + +``` + +Make sure to use `passphrase` instead of `username`and `password` otherwise the plugin will not be able to recognize the token. + +It is also possible to set the token with the parameter `authToken` directly inside the plugin configuration. This is however not recommended because those pom files are usually getting commited into source control and potentially leaking the token. +However, using maven commandline this can be useful being able to overwrite this parameter with the `-D` option. + +```xml + + ... + ${wago.auth-token} + +``` + +Then invoking via the command line +``` +mvn wago-release:wago-release -D wago.auth-token=[token] +``` + +## Test + +Basic tests can be executed with: + +``` +mvn test +``` + +Tests are kept basic because for most of the functionality the Wago.io backend is required. + +## Development + +##### IntelliJ Run Configurations + +The project contains IntelliJ run configurations that can be used for most tasks. All configurations can be found in the `.run` folder. + +##### Build Project + +wago-release-maven-plugin + +``` +clean install +``` + +#### Create a Release + +In maven `settings.xml` configure the ossrh account + +``` + + ossrh + + + +``` + +#### Build and Release + +``` +mvn clean deploy -P deploy +``` + +#### Move Staging to Release + +If `autoReleaseAfterClose` is set to false in the `nexus-staging-maven-plugin` plugin an additional step is required to move the deployment from staging to release. + +``` +mvn nexus-staging:release +``` + +Or if the deployment didn't work out you can drop the artifact from the staging repository. + +``` +mvn nexus-staging:drop +``` + +**Note:** On MacOS the error `gpg: signing failed: Inappropriate ioctl for device` can be solved by setting the tty export variable for gpg. + +``` +export GPG_TTY=$(tty) +``` + +If you are using the IntelliJ console this might need to be set directly in that console. + +##### Run Example + +The example can be used for testing of the plugin during development. It requires some manual setup on GitHub before it can be run. + +* Setup wago token + +wago-release-maven-plugin/example + +``` +clean install +``` + +Executing the plugin from a different folder won't work without also fixing the path to the release notes and any additional assets configured. + +**Note:** The example module is deliberately not included as default module otherwise it would execute each time the project is built. +Instead, the module can be considered separate and independent. It is an example of how to use the plugin, and it is helpful in testing the plugin during development. + + +##### Checkstyle + +wago-release-maven-plugin/plugin + +``` +mvn checkstyle:checkstyle +``` + +##### PMD + +wago-release-maven-plugin/plugin + +``` +mvn pmd:pmd +``` + +## License + +Copyright (c) 2022 Michael Wiesendanger + +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. diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..586ee88 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,18 @@ +# Release + +> This document explains how a new release is created for wago-release-maven-plugin + +* Remove snapshot from version and commit +* Create a new git tag and push it + * `git tag vx.x.x` + * `git push origin --tags` +* Draft new GitHub release with description + * Title should be the version e.g. vx.x.x + * Short description of what changed +* Deploy release artifact to OSSRH + * mvn clean deploy -P deploy + * mvn nexus-staging:release when autoReleaseAfterClose is set to false + * Increase project version and add SNAPSHOT then commit (after a release the version should always be a snapshot version) + * Don't forget to update the example and the test pom with the same version + +**Note:** Snapshot versions can be deployed with the same command `mvn clean deploy -P deploy` diff --git a/example/pom.xml b/example/pom.xml new file mode 100644 index 0000000..4c7edff --- /dev/null +++ b/example/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + com.ragedunicorn.tools.maven + wago-release-example + jar + 1.1.0-SNAPSHOT + + ${project.groupId}:${project.artifactId} + Example project for Maven CurseForge release plugin + https://github.com/RagedUnicorn/github-wago-maven-plugin + + + + MIT License + http://opensource.org/licenses/MIT + repo + A short, permissive software license. Basically, you can do whatever you want as long as you include the + original copyright and license notice in any copy of the software/source. + + + + + + RagedUnicorn + http://ragedunicorn.com + + + + + mwiesendanger + Michael Wiesendanger + michael.wiesendanger@gmail.com + http://ragedunicorn.com + RagedUnicorn + http://ragedunicorn.com + + developer + + Switzerland/Zurich + + + + + UTF-8 + + + + + + com.ragedunicorn.tools.maven + wago-release-maven-plugin + 1.0.0-SNAPSHOT + + + default-cli + + LvNAj96o + + release description overwritten by release notes + src/main/resources/release-notes-example.md + 1.13.7 + stable + src/main/resources/asset-zip-example.zip + wago-token + + + + + + + + + + + diff --git a/example/src/main/resources/asset-zip-example.zip b/example/src/main/resources/asset-zip-example.zip new file mode 100644 index 0000000..57058b4 Binary files /dev/null and b/example/src/main/resources/asset-zip-example.zip differ diff --git a/example/src/main/resources/release-notes-example.md b/example/src/main/resources/release-notes-example.md new file mode 100644 index 0000000..a500fa8 --- /dev/null +++ b/example/src/main/resources/release-notes-example.md @@ -0,0 +1,7 @@ +# release notes example + +# release changes + +* change 1 +* change 2 +* ... \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5b1d66c --- /dev/null +++ b/pom.xml @@ -0,0 +1,286 @@ + + + 4.0.0 + com.ragedunicorn.tools.maven + wago-release-maven-plugin + 1.0.0-SNAPSHOT + maven-plugin + + ${project.groupId}:${project.artifactId} + Maven plugin for creating Wago.io releases + https://github.com/RagedUnicorn/wago-release-maven-plugin + + + + MIT License + http://opensource.org/licenses/MIT + repo + A short, permissive software license. Basically, you can do whatever you want as long as you include the + original copyright and license notice in any copy of the software/source. + + + + + + RagedUnicorn + http://ragedunicorn.com + + + + + mwiesendanger + Michael Wiesendanger + michael.wiesendanger@gmail.com + http://ragedunicorn.com + RagedUnicorn + http://ragedunicorn.com + + developer + + Switzerland/Zurich + + + + + scm:git:git://github.com/RagedUnicorn/wago-release-maven-plugin.git + scm:git:ssh://github.com:RagedUnicorn/wago-release-maven-plugin.git + https://github.com/RagedUnicorn/wago-release-maven-plugin/tree/master + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2 + + + + + UTF-8 + 488C9072D9E5426B + checkstyle.xml + LICENSE.txt + + + + + development + + true + + + true + true + true + + + + release + + true + true + true + + + + deploy + + false + false + false + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.5.2 + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + ${skip.sign.gpg} + ${gpg.keyname} + ${gpg.keyname} + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + ${skip.package.sources} + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + + + attach-javadocs + + jar + + + ${skip.package.javadoc} + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + ossrh + https://oss.sonatype.org/ + false + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.0 + + + com.ragedunicorn.tools.maven + maven-code-quality + 1.0.5 + + + com.puppycrawl.tools + checkstyle + 8.29 + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.10.0 + + + pmd-ruleset.xml + + true + + + + com.ragedunicorn.tools.maven + maven-code-quality + 1.0.5 + + + net.sourceforge.pmd + pmd-vm + 6.6.0 + + + net.sourceforge.pmd + pmd-xml + 6.6.0 + + + + + + + + + org.apache.maven + maven-plugin-api + 3.8.5 + + + org.apache.maven + maven-core + 3.8.5 + + + org.apache.maven + maven-compat + 3.8.5 + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.6.4 + + + org.slf4j + slf4j-simple + 1.7.36 + + + com.google.code.gson + gson + 2.9.0 + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + org.apache.httpcomponents + httpmime + 4.5.13 + + + javax.ws.rs + jsr311-api + 1.1.1 + + + + junit + junit + 4.13.2 + test + + + org.apache.maven.plugin-testing + maven-plugin-testing-harness + 3.3.0 + test + + + diff --git a/src/main/java/com/ragedunicorn/tools/maven/WagoClient.java b/src/main/java/com/ragedunicorn/tools/maven/WagoClient.java new file mode 100644 index 0000000..1096017 --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/WagoClient.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven; + +import com.google.common.collect.Lists; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import org.apache.http.Header; +import org.apache.http.HttpHeaders; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.LaxRedirectStrategy; +import org.apache.http.message.BasicHeader; +import org.apache.maven.plugin.MojoExecutionException; + +public class WagoClient { + private static final String USER_AGENT = "wago-release-plugin"; + + private String baseUri = "https://addons.wago.io/api/projects/:projectId/version"; + // targeted project + private String projectId; + // token + private String token; + + public String getBaseUri() { + return baseUri; + } + + public void setBaseUri(String baseUri) { + this.baseUri = baseUri; + } + + public String getProjectId() { + return projectId; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + /** + * Create an http client. + * + * @return The created http client + */ + public CloseableHttpClient getHttpClient() { + hasValidPreconditions(); + + return HttpClientBuilder + .create() + .useSystemProperties() + .setDefaultHeaders(getDefaultHeaders()) + .setRedirectStrategy(new LaxRedirectStrategy()) + .build(); + } + + private List
getDefaultHeaders() { + return Lists.newArrayList( + new BasicHeader(HttpHeaders.USER_AGENT, USER_AGENT), + new BasicHeader("Authorization", "Bearer " + token), + new BasicHeader(HttpHeaders.ACCEPT, "application/json") + + ); + } + + /** + * Prepare an endpoint url by replacing placeholders with real values. + * + * @param path The path to prepare + * @return The prepared URI + * @throws MojoExecutionException If failing to prepare the URI properly + */ + public URI prepareEndpointUri(final String path) throws MojoExecutionException { + hasValidPreconditions(); + String processedBaseUri = baseUri.replace(":projectId", projectId); + + try { + return new URI(processedBaseUri); + } catch (URISyntaxException e) { + throw new MojoExecutionException("Failed to prepare endpoint URI", e); + } + } + + /** + * Checks if all preconditions are fulfilled. + * + * @throws IllegalStateException If any of the preconditions is not fulfilled + */ + private void hasValidPreconditions() { + if (token == null || token.isEmpty() || projectId == null || projectId.isEmpty() + || baseUri == null || baseUri.isEmpty()) { + throw new IllegalStateException("Wago client is in invalid state. Make sure to set token, " + + "projectId, baseUri and the game"); + } + } +} diff --git a/src/main/java/com/ragedunicorn/tools/maven/WagoReleaseMojo.java b/src/main/java/com/ragedunicorn/tools/maven/WagoReleaseMojo.java new file mode 100644 index 0000000..7606640 --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/WagoReleaseMojo.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven; + +import com.ragedunicorn.tools.maven.model.Metadata; +import com.ragedunicorn.tools.maven.service.ReleaseService; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.settings.Server; +import org.apache.maven.settings.Settings; + + + + +@Mojo(name = "wago-release") +public class WagoReleaseMojo extends AbstractMojo { + + // The project id of the wago project (can be found on the projects page) + @Parameter(property = "projectId", required = true) + private String projectId; + + // A label for the uploaded file + @Parameter(property = "label", defaultValue = "addon") + private String label; + + // One of stable, beta, alpha + @Parameter(property = "stability", defaultValue = "stable") + private String stability; + + // A string containing the changelog + @Parameter(property = "changelog") + private String changelog; + + // Optional path to a changelog file - will override changelog + @Parameter(property = "changelogFile") + private String changelogFile; + + // At least one of retail, classic or bcc patch must be set (multiple values allowed) + + // The retail supported version number + @Parameter(property = "supportRetailPatch") + private String supportedRetailPatch; + + // The bcc supported version number + @Parameter(property = "supportBccPatch") + private String supportedBccPatch; + + // The classic supported version number + @Parameter(property = "supportClassicPatch") + private String supportedClassicPatch; + + // The path to the addon to upload + @Parameter(property = "file", required = true) + private String file; + + // Alternative of using a server configuration. The authToken can directly be placed in the + // plugin configuration + @Parameter(property = "authToken") + private String authToken; + + // References a server configuration in your .m2 settings.xml. This is the preferred way for + // using the generated wago token + @Parameter(property = "server") + private String server; + + @Parameter(defaultValue = "${settings}", readonly = true) + private Settings settings; + + /** + * Plugin execution callback. + * + * @throws MojoExecutionException If any exception happens during the execution of the plugin + */ + public void execute() throws MojoExecutionException { + validateRequiredInputParameters(); + + WagoClient wagoClient = createWagoClient(); + createRelease(wagoClient); + } + + /** + * Create a new release on Wago.io. + * + * @param wagoClient The Wago client + * @throws MojoExecutionException If any exception happens during the execution of the release + * service + */ + private void createRelease(WagoClient wagoClient) throws MojoExecutionException { + final ReleaseService releaseService = new ReleaseService(wagoClient); + Metadata metadata = new Metadata(); + + metadata.setLabel(label); + metadata.setStability(stability); + metadata.setChangelog(getChangelog()); + metadata.setSupportedRetailPatch(supportedRetailPatch); + metadata.setSupportedBccPatch(supportedBccPatch); + metadata.setSupportedClassicPatch(supportedClassicPatch); + + releaseService.createReleaseOperation(metadata, file); + } + + /** + * Retrieve the token for the Wago.io Api. + * + * @return A property object containing the Wago.io Api token + * @throws MojoExecutionException An exception occurring during the execution of a plugin + */ + private String getCredentials() throws MojoExecutionException { + // prefer settings parameter over direct configuration in pom + if (settings != null && server != null) { + final Server serverEntry = settings.getServer(server); + if (serverEntry != null) { + authToken = serverEntry.getPassphrase(); + + if (authToken == null || authToken.isEmpty()) { + throw new MojoExecutionException("Found server entry in settings.xml " + + "but authToken parameter was missing or is empty"); + } + } else { + getLog().warn("Unable to retrieve settings or server. Falling back to project settings"); + } + } + // fallback to plugin configuration if credentials cannot be retrieved from maven settings.xml + if (authToken == null) { + throw new MojoExecutionException("Unable to read authentication configuration make " + + "sure to set the authToken property"); + } + + return authToken; + } + + private String getChangelog() throws MojoExecutionException { + if (!changelogFile.isEmpty()) { + byte[] changelogContent; + + try { + Path changelogPath = Paths.get(changelogFile); + if (getLog().isDebugEnabled()) { + getLog().debug("Changelog path: " + changelogFile); + } + changelogContent = Files.readAllBytes(changelogPath); + + return new String(changelogContent, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new MojoExecutionException("Failed to read release notes", e); + } + } else if (!changelog.isEmpty()) { + return changelog; + } + + return ""; + } + + /** + * Validate required input parameters. + * + * @throws MojoExecutionException An exception occurring during the execution of a plugin + */ + private void validateRequiredInputParameters() throws MojoExecutionException { + if (projectId == null || projectId.isEmpty()) { + throw new MojoExecutionException("Missing required parameter projectId"); + } + + if (!hasValidSupportedVersion()) { + throw new MojoExecutionException("Missing required parameter supported patch. One of " + + "supportedRetailPatch, supportedBccPatch or supportedClassicPatch has to be set"); + } + + if (label == null || label.isEmpty()) { + throw new MojoExecutionException("Missing required parameter label"); + } + + if (stability == null || stability.isEmpty()) { + throw new MojoExecutionException("Missing required parameter stability"); + } + + if (file == null || file.isEmpty()) { + throw new MojoExecutionException("Missing required parameter file"); + } + } + + /** + * Check if at least on support patch version is set. + * + * @return Boolean + * true if at least one version is set + * false if none of the versions is set + */ + private Boolean hasValidSupportedVersion() { + if (supportedRetailPatch != null && !supportedRetailPatch.isEmpty()) { + return true; + } + + if (supportedBccPatch != null && !supportedBccPatch.isEmpty()) { + return true; + } + + if (supportedClassicPatch != null && !supportedClassicPatch.isEmpty()) { + return true; + } + + return false; + } + + /** + * Create a new Wago.io client and set its owner and the targeted repository. + * Additionally the token for authenticating against the Wago.io Api is set. + * + * @return The created Wago.io client + * @throws MojoExecutionException An exception occurring during the execution of a plugin + */ + private WagoClient createWagoClient() throws MojoExecutionException { + WagoClient wagoClient = new WagoClient(); + wagoClient.setToken(getCredentials()); + wagoClient.setProjectId(projectId); + + return wagoClient; + } +} diff --git a/src/main/java/com/ragedunicorn/tools/maven/log/DefaultLog.java b/src/main/java/com/ragedunicorn/tools/maven/log/DefaultLog.java new file mode 100644 index 0000000..75d2da0 --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/log/DefaultLog.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven.log; + +@SuppressWarnings("PMD") +public class DefaultLog implements WagoReleaseLogger { + /** + * Define default logLevel. + * logLevels: + * 1 - Error + * 2 - Info + * 3 - Warning + * 4 - Debug + */ + private int logLevel = 3; + + public static final int LOG_LEVEL_ERROR = 1; + public static final int LOG_LEVEL_WARNING = 2; + public static final int LOG_LEVEL_INFO = 3; + public static final int LOG_LEVEL_DEBUG = 4; + + public DefaultLog() { + // no op + } + + public DefaultLog(int logLevel) { + this.logLevel = logLevel; + } + + /** + * Log a debug message. + * + * @param content The content to log + */ + public void debug(String content) { + if (this.logLevel >= LOG_LEVEL_DEBUG) { + System.out.println("[DEBUG] " + content); + } + } + + /** + * Log a debug message. + * + * @param content The content to log + * @param error An error object + */ + public void debug(String content, Throwable error) { + if (this.logLevel >= LOG_LEVEL_DEBUG) { + System.out.println("[DEBUG] " + content); + error.printStackTrace(); + } + } + + /** + * Log a debug message. + * + * @param error An error object + */ + public void debug(Throwable error) { + if (this.logLevel >= LOG_LEVEL_DEBUG) { + error.printStackTrace(); + } + } + + /** + * Returns whether the debug logLevel is enabled or not. + * + * @return whether the logLevel is enabled or not + */ + public boolean isDebugEnabled() { + return this.logLevel >= LOG_LEVEL_DEBUG; + } + + /** + * Log a info message. + * + * @param content The content to log + */ + public void info(String content) { + if (this.logLevel >= LOG_LEVEL_INFO) { + System.out.println("[INFO] " + content); + } + } + + /** + * Log a info message. + * + * @param content The content to log + * @param error An error object + */ + public void info(String content, Throwable error) { + if (this.logLevel >= LOG_LEVEL_INFO) { + System.out.println("[INFO] " + content); + error.printStackTrace(); + } + } + + /** + * Log a info message. + * + * @param error An error object + */ + public void info(Throwable error) { + if (this.logLevel >= LOG_LEVEL_INFO) { + error.printStackTrace(); + } + } + + /** + * Returns whether the info logLevel is enabled or not. + * + * @return whether the logLevel is enabled or not + */ + public boolean isInfoEnabled() { + return this.logLevel >= LOG_LEVEL_INFO; + } + + /** + * Log a warn message. + * + * @param content The content to log + */ + public void warn(String content) { + if (this.logLevel >= LOG_LEVEL_WARNING) { + System.out.println("[WARNING] " + content); + } + } + + /** + * Log a warn message. + * + * @param content The content to log + * @param error An error object + */ + public void warn(String content, Throwable error) { + if (this.logLevel >= LOG_LEVEL_WARNING) { + System.out.println("[WARNING] " + content); + error.printStackTrace(); + } + } + + /** + * Log a warn message. + * + * @param error An error object + */ + public void warn(Throwable error) { + if (this.logLevel >= LOG_LEVEL_WARNING) { + error.printStackTrace(); + } + } + + /** + * Returns whether the warn logLevel is enabled or not. + * + * @return whether the logLevel is enabled or not + */ + public boolean isWarnEnabled() { + return this.logLevel >= LOG_LEVEL_WARNING; + } + + /** + * Log a error message. + * + * @param content The content to log + */ + public void error(String content) { + if (this.logLevel >= LOG_LEVEL_ERROR) { + System.out.println("[ERROR] " + content); + } + } + + /** + * Log a error message. + * + * @param content The content to log + * @param error An error object + */ + public void error(String content, Throwable error) { + if (this.logLevel >= LOG_LEVEL_ERROR) { + System.out.println("[ERROR] " + content); + error.printStackTrace(); + } + } + + /** + * Log a error message. + * + * @param error An error object + */ + public void error(Throwable error) { + if (this.logLevel >= LOG_LEVEL_ERROR) { + error.printStackTrace(); + } + } + + /** + * Returns whether the error logLevel is enabled or not. + * + * @return whether the logLevel is enabled or not + */ + public boolean isErrorEnabled() { + return this.logLevel >= LOG_LEVEL_ERROR; + } +} diff --git a/src/main/java/com/ragedunicorn/tools/maven/log/WagoReleaseLogger.java b/src/main/java/com/ragedunicorn/tools/maven/log/WagoReleaseLogger.java new file mode 100644 index 0000000..3c47ff8 --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/log/WagoReleaseLogger.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven.log; + +public interface WagoReleaseLogger { + void debug(String content); + + void debug(String content, Throwable error); + + void debug(Throwable error); + + void info(String content); + + void info(String content, Throwable error); + + void info(Throwable error); + + void warn(String content); + + void warn(String content, Throwable error); + + void warn(Throwable error); + + void error(String content); + + void error(String content, Throwable error); + + void error(Throwable error); +} diff --git a/src/main/java/com/ragedunicorn/tools/maven/model/Errors.java b/src/main/java/com/ragedunicorn/tools/maven/model/Errors.java new file mode 100644 index 0000000..03de2d6 --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/model/Errors.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven.model; + +import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Errors { + public List metadata = new ArrayList<>(); + public List file = new ArrayList<>(); + public List stability = new ArrayList<>(); + @SerializedName(value = "supported_retail_patch") + public List supportedRetailPatch = new ArrayList<>(); + @SerializedName(value = "supported_bc_patch") + public List supportedBccPatch = new ArrayList<>(); + @SerializedName(value = "supported_classic_patch") + public List supportedClassicPatch = new ArrayList<>(); + + public List getMetadata() { + return metadata; + } + + public void setMetadata(List metadata) { + this.metadata = metadata; + } + + public List getFile() { + return file; + } + + public void setFile(List file) { + this.file = file; + } + + public List getStability() { + return stability; + } + + public void setStability(List stability) { + this.stability = stability; + } + + public List getSupportedRetailPatch() { + return supportedRetailPatch; + } + + public void setSupportedRetailPatch(List supportedRetailPatch) { + this.supportedRetailPatch = supportedRetailPatch; + } + + public List getSupportedBccPatch() { + return supportedBccPatch; + } + + public void setSupportedBccPatch(List supportedBccPatch) { + this.supportedBccPatch = supportedBccPatch; + } + + public List getSupportedClassicPatch() { + return supportedClassicPatch; + } + + public void setSupportedClassicPatch(List supportedClassicPatch) { + this.supportedClassicPatch = supportedClassicPatch; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + Errors errors = (Errors) o; + return Objects.equals(metadata, errors.metadata) + && Objects.equals(file, errors.file) + && Objects.equals(stability, errors.stability) + && Objects.equals(supportedRetailPatch, errors.supportedRetailPatch) + && Objects.equals(supportedBccPatch, errors.supportedBccPatch) + && Objects.equals(supportedClassicPatch, errors.supportedClassicPatch); + } + + @Override + public int hashCode() { + return Objects.hash(metadata, file, stability, supportedRetailPatch, supportedBccPatch, supportedClassicPatch); + } + + @Override + public String toString() { + return "Errors{" + + "metadata=" + metadata + + ", file=" + file + + ", stability=" + stability + + ", supportedRetailPatch=" + supportedRetailPatch + + ", supportedBccPatch=" + supportedBccPatch + + ", supportedClassicPatch=" + supportedClassicPatch + + '}'; + } +} diff --git a/src/main/java/com/ragedunicorn/tools/maven/model/Metadata.java b/src/main/java/com/ragedunicorn/tools/maven/model/Metadata.java new file mode 100644 index 0000000..7bbcef0 --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/model/Metadata.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven.model; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import java.util.Objects; + +public class Metadata { + + @Expose + private String label; + + @Expose + private String stability; + + @Expose + private String changelog; + + @Expose + @SerializedName(value = "supported_retail_patch") + private String supportedRetailPatch; + + @Expose + @SerializedName(value = "supported_bc_patch") + private String supportedBccPatch; + + @Expose + @SerializedName(value = "supported_classic_patch") + private String supportedClassicPatch; + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getStability() { + return stability; + } + + public void setStability(String stability) { + this.stability = stability; + } + + public String getChangelog() { + return changelog; + } + + public void setChangelog(String changelog) { + this.changelog = changelog; + } + + public String getSupportedRetailPatch() { + return supportedRetailPatch; + } + + public void setSupportedRetailPatch(String supportedRetailPatch) { + this.supportedRetailPatch = supportedRetailPatch; + } + + public String getSupportedBccPatch() { + return supportedBccPatch; + } + + public void setSupportedBccPatch(String supportedBccPatch) { + this.supportedBccPatch = supportedBccPatch; + } + + public String getSupportedClassicPatch() { + return supportedClassicPatch; + } + + public void setSupportedClassicPatch(String supportedClassicPatch) { + this.supportedClassicPatch = supportedClassicPatch; + } + + @Override + public String toString() { + return "Metadata{" + + "label='" + label + '\'' + + ", stability='" + stability + '\'' + + ", changelog='" + changelog + '\'' + + ", supportedRetailPatch='" + supportedRetailPatch + '\'' + + ", supportedBccPatch='" + supportedBccPatch + '\'' + + ", supportedClassicPatch='" + supportedClassicPatch + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + Metadata metadata = (Metadata) o; + return Objects.equals(label, metadata.label) + && Objects.equals(stability, metadata.stability) + && Objects.equals(changelog, metadata.changelog) + && Objects.equals(supportedRetailPatch, metadata.supportedRetailPatch) + && Objects.equals(supportedBccPatch, metadata.supportedBccPatch) + && Objects.equals(supportedClassicPatch, metadata.supportedClassicPatch); + } + + @Override + public int hashCode() { + return Objects.hash(label, stability, changelog, supportedRetailPatch, supportedBccPatch, supportedClassicPatch); + } +} diff --git a/src/main/java/com/ragedunicorn/tools/maven/model/WagoApiClientError.java b/src/main/java/com/ragedunicorn/tools/maven/model/WagoApiClientError.java new file mode 100644 index 0000000..d7f3799 --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/model/WagoApiClientError.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven.model; + +import java.util.Objects; + +public class WagoApiClientError { + private String message; + + private Errors errors; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Errors getErrors() { + return errors; + } + + public void setErrors(Errors errors) { + this.errors = errors; + } + + @Override + public String toString() { + return "WagoApiClientError{" + + "message='" + message + '\'' + + ", errors=" + errors + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + WagoApiClientError that = (WagoApiClientError) o; + return Objects.equals(message, that.message) && Objects.equals(errors, that.errors); + } + + @Override + public int hashCode() { + return Objects.hash(message, errors); + } +} diff --git a/src/main/java/com/ragedunicorn/tools/maven/service/ReleaseService.java b/src/main/java/com/ragedunicorn/tools/maven/service/ReleaseService.java new file mode 100644 index 0000000..a6d255b --- /dev/null +++ b/src/main/java/com/ragedunicorn/tools/maven/service/ReleaseService.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2022 Michael Wiesendanger + * 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.ragedunicorn.tools.maven.service; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.ragedunicorn.tools.maven.WagoClient; +import com.ragedunicorn.tools.maven.log.DefaultLog; +import com.ragedunicorn.tools.maven.model.Metadata; +import com.ragedunicorn.tools.maven.model.WagoApiClientError; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.util.EntityUtils; +import org.apache.maven.plugin.MojoExecutionException; + +public class ReleaseService { + private static final String ENDPOINT = "/api/projects/:projectId/upload-file"; + private static final String SUCCESS_RESPONSE = "OK"; + + private final DefaultLog logger = new DefaultLog(); + + private final WagoClient wagoClient; + + public ReleaseService(WagoClient wagoClient) { + this.wagoClient = wagoClient; + } + + /** + * Create a new release. + * + * @param metadata All metadata related to the upload + * @param file Path to the file to upload + * @throws MojoExecutionException If the request to the Wago.io Api failed + */ + public void createReleaseOperation(Metadata metadata, String file) + throws MojoExecutionException { + final Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + + HttpEntity entity = MultipartEntityBuilder + .create() + .addTextBody("metadata", gson.toJson(metadata)) + .addBinaryBody("file", new File(file), ContentType.create("application/octet-stream"), + metadata.getLabel()) + .build(); + + CloseableHttpClient httpClient = wagoClient.getHttpClient(); + + HttpPost httpPost = new HttpPost(); + URI preparedEndpointUrl = wagoClient.prepareEndpointUri(ENDPOINT); + if (logger.isDebugEnabled()) { + logger.debug("Endpoint Uri: " + preparedEndpointUrl.getPath()); + } + httpPost.setURI(preparedEndpointUrl); + httpPost.setEntity(entity); + + try { + CloseableHttpResponse response = httpClient.execute(httpPost); + String responseString = responseHandler(response); + + if (logger.isInfoEnabled() && responseString.equals(SUCCESS_RESPONSE)) { + logger.info("Upload successful"); + } + } catch (IOException e) { + throw new MojoExecutionException("Upload to Wago.io failed", e); + } + + try { + httpClient.close(); + } catch (IOException e) { + throw new MojoExecutionException("Failed to close http client", e); + } + } + + /** + * Check if the release request was successful and handle both failure and success. + * + * @param response The response from the Wago.io Api + * @return The response from the Wago.io Api as POJO + * @throws IOException If entity cannot be converted to a string + * @throws MojoExecutionException If creation of release failed + */ + private String responseHandler(CloseableHttpResponse response) + throws IOException, MojoExecutionException { + final Gson gson = new Gson(); + final HttpEntity entity = response.getEntity(); + final String responseString = EntityUtils.toString(entity, StandardCharsets.UTF_8); + final int statusCode = response.getStatusLine().getStatusCode(); + + if (statusCode != HttpStatus.SC_CREATED) { + WagoApiClientError clientError = gson.fromJson(responseString, WagoApiClientError.class); + logger.error(clientError.toString()); + + throw new MojoExecutionException("Failed to create release - reason: " + + clientError); + } else { + return responseString; + } + } +} diff --git a/src/test/java/com/ragedunicorn/tools/maven/WagoReleaseMojoTest.java b/src/test/java/com/ragedunicorn/tools/maven/WagoReleaseMojoTest.java new file mode 100644 index 0000000..7f90878 --- /dev/null +++ b/src/test/java/com/ragedunicorn/tools/maven/WagoReleaseMojoTest.java @@ -0,0 +1,36 @@ +package com.ragedunicorn.tools.maven; + +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import java.io.File; + +public class WagoReleaseMojoTest extends AbstractMojoTestCase { + + public void setUp() throws Exception { + super.setUp(); + } + + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Tests the proper discovery and configuration of the mojo. + * + * @throws Exception If failing to extract plugin configuration + */ + public void testBasicPluginConfiguration() throws Exception { + + File testPom = new File("src/test/resources/plugin-config.xml" ); + assertNotNull(testPom); + assertTrue(testPom.exists()); + + WagoReleaseMojo mojo = new WagoReleaseMojo(); + mojo = (WagoReleaseMojo) configureMojo( + mojo, extractPluginConfiguration("wago-release-maven-plugin", testPom) + ); + + assertNotNull(mojo); + + // mojo.execute(); execution requires wago backend + } +} diff --git a/src/test/java/com/ragedunicorn/tools/maven/WagoReleaseWagoClientTest.java b/src/test/java/com/ragedunicorn/tools/maven/WagoReleaseWagoClientTest.java new file mode 100644 index 0000000..9e76037 --- /dev/null +++ b/src/test/java/com/ragedunicorn/tools/maven/WagoReleaseWagoClientTest.java @@ -0,0 +1,43 @@ +package com.ragedunicorn.tools.maven; + +import org.apache.maven.plugin.MojoExecutionException; +import org.junit.Assert; +import org.junit.Test; + +import java.net.URI; +import java.util.Arrays; + +public class WagoReleaseWagoClientTest { + @Test + public void testEndpointUriPreparation() { + final String ENDPOINT = "https://addons.wago.io/api/projects/:projectId/version"; + final String projectId = "111111"; + + WagoClient client = new WagoClient(); + client.setProjectId(projectId); + client.setToken("test-token"); + + try { + URI preparedUri = client.prepareEndpointUri(ENDPOINT); + Assert.assertEquals(preparedUri.toString(), "https://addons.wago.io/api/projects/" + projectId + "/version"); + } catch (MojoExecutionException e) { + Assert.fail("MojoExecutionException: " + Arrays.toString(e.getStackTrace())); + } + } + + @Test(expected = IllegalStateException.class) + public void testPrepareEndpointUriExpectedInvalidState() { + WagoClient client = new WagoClient(); + try { + client.prepareEndpointUri("/some/url"); + } catch (MojoExecutionException e) { + Assert.fail("MojoExecutionException: " + Arrays.toString(e.getStackTrace())); + } + } + + @Test(expected = IllegalStateException.class) + public void testGetClientUriExpectedInvalidState() { + WagoClient client = new WagoClient(); + client.getHttpClient(); + } +} diff --git a/src/test/resources/plugin-config.xml b/src/test/resources/plugin-config.xml new file mode 100644 index 0000000..6527579 --- /dev/null +++ b/src/test/resources/plugin-config.xml @@ -0,0 +1,28 @@ + + 4.0.0 + com.ragedunicorn.tools.maven + test + jar + 1.0.0 + + + + + com.ragedunicorn.tools.maven + wago-release-maven-plugin + 1.0.0-SNAPSHOT + + LvNAj96o + + release description overwritten by release notes + src/main/resources/release-notes-example.md + 1.13.7 + stable + src/main/resources/asset-zip-example.zip + wago-token + + + + +