diff --git a/apps/jreleaser-tool-provider/gradle.properties b/apps/jreleaser-tool-provider/gradle.properties new file mode 100644 index 00000000..92ff0132 --- /dev/null +++ b/apps/jreleaser-tool-provider/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser Tool Provider \ No newline at end of file diff --git a/apps/jreleaser-tool-provider/jreleaser-tool-provider.gradle b/apps/jreleaser-tool-provider/jreleaser-tool-provider.gradle new file mode 100644 index 00000000..4a055e97 --- /dev/null +++ b/apps/jreleaser-tool-provider/jreleaser-tool-provider.gradle @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser') +} + +tasks.withType(JavaCompile) { JavaCompile c -> + c.sourceCompatibility = JavaVersion.VERSION_1_9 + c.targetCompatibility = JavaVersion.VERSION_1_9 +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(9) + } +} + diff --git a/apps/jreleaser-tool-provider/src/main/java/module-info.java b/apps/jreleaser-tool-provider/src/main/java/module-info.java new file mode 100644 index 00000000..e87660cf --- /dev/null +++ b/apps/jreleaser-tool-provider/src/main/java/module-info.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.tool { + exports org.kordamp.jreleaser.tool; + requires org.kordamp.jreleaser.app; + + provides java.util.spi.ToolProvider with + org.kordamp.jreleaser.tool.JReleaserToolProvider; +} \ No newline at end of file diff --git a/apps/jreleaser-tool-provider/src/main/java/org/kordamp/jreleaser/tool/JReleaserToolProvider.java b/apps/jreleaser-tool-provider/src/main/java/org/kordamp/jreleaser/tool/JReleaserToolProvider.java new file mode 100644 index 00000000..c4bc35fa --- /dev/null +++ b/apps/jreleaser-tool-provider/src/main/java/org/kordamp/jreleaser/tool/JReleaserToolProvider.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tool; + +import java.io.PrintWriter; +import java.util.spi.ToolProvider; +import org.kordamp.jreleaser.app.Main; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserToolProvider implements ToolProvider { + public String name() { + return "jreleaser"; + } + + public int run(PrintWriter out, PrintWriter err, String... args) { + return Main.run(out, err, args); + } +} diff --git a/apps/jreleaser/gradle.properties b/apps/jreleaser/gradle.properties new file mode 100644 index 00000000..46c8a9c2 --- /dev/null +++ b/apps/jreleaser/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser \ No newline at end of file diff --git a/apps/jreleaser/jreleaser.gradle b/apps/jreleaser/jreleaser.gradle new file mode 100644 index 00000000..821f0c29 --- /dev/null +++ b/apps/jreleaser/jreleaser.gradle @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id 'application' +} + +config { + info { + specification { enabled = true } + } +} + +dependencies { + api project(':jreleaser-tools') + api project(':jreleaser-templates') + api project(':jreleaser-config-yaml') + api('com.google.guava:guava:30.0-jre') { transitive = false } + + annotationProcessor "info.picocli:picocli-codegen:$picocliVersion" + api "info.picocli:picocli:$picocliVersion" + api "org.slf4j:slf4j-api:$slf4jVersion" + runtimeOnly "org.slf4j:slf4j-simple:$slf4jVersion" +} + +mainClassName = 'org.kordamp.jreleaser.app.Main' + +processResources { + inputs.property('version', project.version) + filesMatching(['**/*.properties']) { + expand( + 'version': project.version, + 'id': 'jrleaser', + 'name': 'jrleaser' + ) + } +} \ No newline at end of file diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractCommand.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractCommand.java new file mode 100644 index 00000000..82fa5aa1 --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractCommand.java @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import org.kordamp.jreleaser.app.internal.Colorizer; +import org.kordamp.jreleaser.app.internal.JReleaserLoggerAdapter; +import org.kordamp.jreleaser.util.Logger; +import picocli.CommandLine; + +import java.nio.file.Path; +import java.util.concurrent.Callable; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command +abstract class AbstractCommand implements Callable { + protected Logger logger; + + @CommandLine.Option(names = {"-d", "--debug"}, + description = "Set log level to debug.") + boolean debug; + + @CommandLine.Option(names = {"-i", "--info"}, + description = "Set log level to info.") + boolean info; + + @CommandLine.Option(names = {"-w", "--warn"}, + description = "Set log level to warn.") + boolean warn; + + @CommandLine.Option(names = {"-q", "--quiet"}, + description = "Log errors only.") + boolean quiet; + + @CommandLine.Option(names = {"--basedir"}, + description = "Base directory") + Path basedir; + + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + + protected abstract Main parent(); + + public Integer call() { + Banner.display(); + + JReleaserLoggerAdapter.Level level = JReleaserLoggerAdapter.Level.WARN; + if (debug) { + level = JReleaserLoggerAdapter.Level.DEBUG; + System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug"); + } else if (info) { + level = JReleaserLoggerAdapter.Level.INFO; + System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info"); + } else if (warn) { + level = JReleaserLoggerAdapter.Level.WARN; + System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "warn"); + } else if (quiet) { + level = JReleaserLoggerAdapter.Level.ERROR; + System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "error"); + } + + logger = new JReleaserLoggerAdapter(parent().out, level); + + try { + execute(); + } catch (HaltExecutionException e) { + return 1; + } catch (Exception e) { + e.printStackTrace(new Colorizer(parent().out)); + return 1; + } + + return 0; + } + + protected abstract void execute(); +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractModelCommand.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractModelCommand.java new file mode 100644 index 00000000..27f5a414 --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractModelCommand.java @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import org.kordamp.jreleaser.app.internal.JReleaserLoggerAdapter; +import org.kordamp.jreleaser.config.JReleaserConfigLoader; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.JReleaserModelValidator; +import org.kordamp.jreleaser.util.Logger; +import picocli.CommandLine; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command +public abstract class AbstractModelCommand extends AbstractCommand { + @CommandLine.Option(names = {"--config-file"}, + description = "The config file") + Path configFile; + + @CommandLine.ParentCommand + Main parent; + + Path actualConfigFile; + Path actualBasedir; + + @Override + protected Main parent() { + return parent; + } + + protected void execute() { + resolveConfigFile(); + resolveBasedir(); + consumeModel(resolveModel()); + } + + protected void resolveConfigFile() { + actualConfigFile = null != configFile ? configFile : Paths.get(".").normalize().resolve(".jreleaser.yml"); + if (!Files.exists(actualConfigFile)) { + spec.commandLine().getErr() + .println(spec.commandLine().getColorScheme().errorText("Missing required option: '--config-file='")); + spec.commandLine().usage(parent.out); + throw new HaltExecutionException(); + } + } + + private void resolveBasedir() { + actualBasedir = null != basedir ? basedir : actualConfigFile.toAbsolutePath().getParent(); + if (!Files.exists(actualBasedir)) { + spec.commandLine().getErr() + .println(spec.commandLine().getColorScheme().errorText("Missing required option: '--basedir='")); + spec.commandLine().usage(parent.out); + throw new HaltExecutionException(); + } + } + + protected abstract void consumeModel(JReleaserModel jreleaserModel); + + private JReleaserModel resolveModel() { + try { + JReleaserModel jreleaserModel = JReleaserConfigLoader.loadConfig(actualConfigFile); + List errors = JReleaserModelValidator.validate(logger, actualBasedir, jreleaserModel); + if (!errors.isEmpty()) { + Logger logger = new JReleaserLoggerAdapter(parent.out); + logger.error("== JReleaser =="); + errors.forEach(logger::error); + throw new JReleaserException("JReleaser with " + actualConfigFile.toAbsolutePath() + " has not been properly configured."); + } + + return jreleaserModel; + } catch (IllegalArgumentException e) { + throw new JReleaserException("Unexpected error when parsing configuration from " + actualConfigFile.toAbsolutePath(), e); + } + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractProcessorCommand.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractProcessorCommand.java new file mode 100644 index 00000000..f7e8e6ce --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/AbstractProcessorCommand.java @@ -0,0 +1,96 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.tools.DistributionProcessor; +import org.kordamp.jreleaser.tools.ToolProcessingException; +import picocli.CommandLine; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command +public abstract class AbstractProcessorCommand extends AbstractModelCommand { + @CommandLine.Option(names = {"--fail-fast"}, + description = "Fail fast") + boolean failFast = true; + + Path outputDirectory; + + @Override + protected void consumeModel(JReleaserModel jreleaserModel) { + outputDirectory = actualBasedir.resolve("out"); + + Path checksumDirectory = computeChecksums(jreleaserModel, outputDirectory); + + List exceptions = new ArrayList<>(); + for (Distribution distribution : jreleaserModel.getDistributions().values()) { + for (String toolName : Distribution.supportedTools()) { + try { + DistributionProcessor processor = createDistributionProcessor(jreleaserModel, + checksumDirectory, + outputDirectory, + distribution, + toolName); + + consumeProcessor(processor); + } catch (ToolProcessingException e) { + if (failFast) throw new IllegalStateException("Unexpected error", e); + exceptions.add(e); + logger.warn("Unexpected error", e); + } + } + } + + if (!exceptions.isEmpty()) { + throw new IllegalStateException("There were " + exceptions.size() + " failure(s)"); + } + } + + protected abstract void consumeProcessor(DistributionProcessor processor) throws ToolProcessingException; + + private DistributionProcessor createDistributionProcessor(JReleaserModel jreleaserModel, + Path checksumDirectory, + Path outputDirectory, + Distribution distribution, + String toolName) { + return DistributionProcessor.builder() + .logger(logger) + .model(jreleaserModel) + .distributionName(distribution.getName()) + .toolName(toolName) + .checksumDirectory(checksumDirectory) + .outputDirectory(outputDirectory + .resolve("jreleaser") + .resolve(distribution.getName()) + .resolve(toolName)) + .build(); + } + + protected Path computeChecksums(JReleaserModel jreleaserModel, Path outputDirectory) { + return outputDirectory.resolve("jreleaser") + .resolve("checksums"); + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Banner.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Banner.java new file mode 100644 index 00000000..bdb3949f --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Banner.java @@ -0,0 +1,102 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.text.MessageFormat; +import java.util.ResourceBundle; +import java.util.Scanner; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +final class Banner { + private static final Banner b = new Banner(); + private final ResourceBundle bundle = ResourceBundle.getBundle(Banner.class.getName()); + private final String productVersion = bundle.getString("product.version"); + private final String productId = bundle.getString("product.id"); + private final String productName = bundle.getString("product.name"); + private final String banner = MessageFormat.format(bundle.getString("product.banner"), productName, productVersion); + + private Banner() { + // nooop + } + + public static void display() { + try { + File parent = new File(System.getProperty("user.home"), "/.jreleaser/caches"); + File markerFile = getMarkerFile(parent, b); + if (!markerFile.exists()) { + System.out.println(b.banner); + markerFile.getParentFile().mkdirs(); + PrintStream out = new PrintStream(new FileOutputStream(markerFile)); + out.println("1"); + out.close(); + writeQuietly(markerFile, "1"); + } else { + try { + int count = Integer.parseInt(readQuietly(markerFile)); + if (count < 3) { + System.out.println(b.banner); + } + writeQuietly(markerFile, (count + 1) + ""); + } catch (NumberFormatException e) { + writeQuietly(markerFile, "1"); + System.out.println(b.banner); + } + } + } catch (IOException ignored) { + // noop + } + } + + private static void writeQuietly(File file, String text) { + try { + PrintStream out = new PrintStream(new FileOutputStream(file)); + out.println(text); + out.close(); + } catch (IOException ignored) { + // ignored + } + } + + private static String readQuietly(File file) { + try { + Scanner in = new Scanner(new FileInputStream(file)); + return in.next(); + } catch (Exception ignored) { + return ""; + } + } + + private static File getMarkerFile(File parent, Banner b) { + return new File(parent, + "kordamp" + + File.separator + + b.productId + + File.separator + + b.productVersion + + File.separator + + "marker.txt"); + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Config.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Config.java new file mode 100644 index 00000000..d2038bb1 --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Config.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import org.kordamp.jreleaser.app.internal.JReleaserModelPrinter; +import org.kordamp.jreleaser.model.JReleaserModel; +import picocli.CommandLine; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command(name = "config", + description = "Displays current configuration") +public class Config extends AbstractModelCommand { + @Override + protected void consumeModel(JReleaserModel jreleaserModel) { + new JReleaserModelPrinter(parent.out).print(jreleaserModel.asMap()); + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/HaltExecutionException.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/HaltExecutionException.java new file mode 100644 index 00000000..2d4dc5c4 --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/HaltExecutionException.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class HaltExecutionException extends RuntimeException { + public HaltExecutionException() { + super(); + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Init.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Init.java new file mode 100644 index 00000000..967ea238 --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Init.java @@ -0,0 +1,82 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import org.kordamp.jreleaser.templates.TemplateUtils; +import picocli.CommandLine; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Scanner; + +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.CREATE_NEW; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command(name = "init", + description = "Creates a jrelaser config file") +public class Init extends AbstractCommand { + @CommandLine.Option(names = {"--overwrite"}, + description = "Overwrite existing files") + boolean overwrite; + + @CommandLine.ParentCommand + Main parent; + + @Override + protected Main parent() { + return parent; + } + + protected void execute() { + try { + Path outputDirectory = null != basedir ? basedir : Paths.get(".").normalize(); + Path outputFile = outputDirectory.resolve(".jreleaser.yml"); + + Reader template = TemplateUtils.resolveTemplate(logger, Init.class, + "META-INF/jreleaser/templates/jreleaser.yml.tpl"); + + logger.info("Writing file " + outputFile.toAbsolutePath()); + try (Writer writer = Files.newBufferedWriter(outputFile, (overwrite ? CREATE : CREATE_NEW), WRITE, TRUNCATE_EXISTING); + Scanner scanner = new Scanner(template)) { + while (scanner.hasNextLine()) { + writer.write(scanner.nextLine() + System.lineSeparator()); + } + } catch (FileAlreadyExistsException e) { + logger.error("File {} already exists and overwrite was set to false.", outputFile.toAbsolutePath()); + return; + } + + if (!quiet) { + parent.out.println("JReleaser initialized at " + outputDirectory.toAbsolutePath()); + } + } catch (IllegalStateException | IOException e) { + throw new JReleaserException("Unexpected error", e); + } + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/JReleaserException.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/JReleaserException.java new file mode 100644 index 00000000..cea1d91b --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/JReleaserException.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserException extends RuntimeException { + public JReleaserException(String message) { + super(message); + } + + public JReleaserException(String message, Throwable cause) { + super(message, cause); + } + + public JReleaserException(Throwable cause) { + super(cause); + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Main.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Main.java new file mode 100644 index 00000000..bfea6efe --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Main.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import picocli.CommandLine; + +import java.io.PrintWriter; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command(name = "jreleaser", + description = "jreleaser", + mixinStandardHelpOptions = true, + versionProvider = Versions.class, + subcommands = {Init.class, Config.class, Template.class, Prepare.class, Package.class}) +public class Main implements Runnable { + PrintWriter out; + PrintWriter err; + + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + + public void run() { + Banner.display(); + + spec.commandLine().usage(out); + } + + public static void main(String[] args) { + System.exit(run(args)); + } + + public static int run(String... args) { + Main cmd = new Main(); + CommandLine commandLine = new CommandLine(cmd); + cmd.out = commandLine.getOut(); + cmd.err = commandLine.getErr(); + return commandLine.execute(args); + } + + public static int run(PrintWriter out, PrintWriter err, String... args) { + Main cmd = new Main(); + cmd.out = out; + cmd.err = err; + return new CommandLine(cmd).execute(args); + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Package.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Package.java new file mode 100644 index 00000000..1539ff2b --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Package.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import org.kordamp.jreleaser.tools.DistributionProcessor; +import org.kordamp.jreleaser.tools.ToolProcessingException; +import picocli.CommandLine; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command(name = "package", + description = "Packages all distributions") +public class Package extends AbstractProcessorCommand { + @Override + protected void consumeProcessor(DistributionProcessor processor) throws ToolProcessingException { + if (processor.packageDistribution() && !quiet) { + parent.out.println("Packaged " + processor.getDistributionName() + + " distribution with tool " + processor.getToolName()); + } + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Prepare.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Prepare.java new file mode 100644 index 00000000..1adfca02 --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Prepare.java @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import com.google.common.hash.HashCode; +import com.google.common.hash.Hashing; +import com.google.common.io.Files; +import org.kordamp.jreleaser.model.Artifact; +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.tools.DistributionProcessor; +import org.kordamp.jreleaser.tools.ToolProcessingException; +import picocli.CommandLine; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command(name = "prepare", + description = "Prepares all distributions") +public class Prepare extends AbstractProcessorCommand { + @Override + protected void consumeProcessor(DistributionProcessor processor) throws ToolProcessingException { + if (processor.prepareDistribution()) { + parent.out.println("Prepared " + processor.getDistributionName() + + " distribution with tool " + processor.getToolName()); + } + } + + @Override + protected Path computeChecksums(JReleaserModel jreleaserModel, Path outputDirectory) { + Path checksumDirectory = super.computeChecksums(jreleaserModel, outputDirectory); + + try { + java.nio.file.Files.createDirectories(checksumDirectory); + } catch (IOException e) { + throw new JReleaserException("Unexpected error creating checksum directory.", e); + } + + jreleaserModel.getDistributions().values() + .stream().flatMap((Function>) distribution -> distribution.getArtifacts() + .stream()).forEach(artifact -> { + Path inputFile = Paths.get(artifact.getPath()).toAbsolutePath(); + String fileName = inputFile.getFileName().toString(); + Path checksumFilePath = checksumDirectory.resolve(fileName + ".sha256"); + try { + HashCode hashCode = Files.asByteSource(inputFile.toFile()).hash(Hashing.sha256()); + Files.write(hashCode.toString().getBytes(), checksumFilePath.toFile()); + } catch (IOException e) { + throw new JReleaserException("Unexpected error creating checksum for " + inputFile, e); + } + }); + + return checksumDirectory; + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Template.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Template.java new file mode 100644 index 00000000..f3d3d00e --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Template.java @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.templates.TemplateGenerationException; +import org.kordamp.jreleaser.templates.TemplateGenerator; +import picocli.CommandLine; + +import java.nio.file.Path; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CommandLine.Command(name = "template", + description = "Generates a tool template") +public class Template extends AbstractCommand { + @CommandLine.Option(names = {"--distribution-name"}, + description = "The name of the distribution", + required = true) + String distributionName; + + @CommandLine.Option(names = {"--tool-name"}, + description = "The name of the tool", + required = true) + String toolName; + + @CommandLine.Option(names = {"--distribution-type"}, + description = "The type of the distribution", + required = true, + defaultValue = "BINARY") + Distribution.DistributionType distributionType; + + @CommandLine.Option(names = {"--overwrite"}, + description = "Overwrite existing files") + boolean overwrite; + + @CommandLine.ParentCommand + Main parent; + + @Override + protected Main parent() { + return parent; + } + + protected void execute() { + try { + if (null == basedir) { + spec.commandLine().getErr() + .println(spec.commandLine().getColorScheme().errorText("Missing required option: '--basedir='")); + spec.commandLine().usage(parent.out); + throw new HaltExecutionException(); + } + + Path outputDirectory = basedir + .resolve("src") + .resolve("distributions"); + + boolean result = TemplateGenerator.builder() + .logger(logger) + .distributionName(distributionName) + .distributionType(distributionType) + .toolName(toolName) + .outputDirectory(outputDirectory) + .overwrite(overwrite) + .build() + .generate(); + + if (result && !quiet) { + parent.out.println("Template generated at " + + outputDirectory.resolve(distributionName).resolve(toolName) + .normalize().toAbsolutePath()); + } + } catch (TemplateGenerationException e) { + throw new JReleaserException("Unexpected error", e); + } + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Versions.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Versions.java new file mode 100644 index 00000000..7adde4ca --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/Versions.java @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app; + +import picocli.CommandLine; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.ResourceBundle; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Versions implements CommandLine.IVersionProvider { + private static final ResourceBundle bundle = ResourceBundle.getBundle(Versions.class.getName()); + private static final String JRELEASER_VERSION = bundle.getString("jreleaser_version"); + + @Override + public String[] getVersion() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + banner(new PrintStream(baos)); + return baos.toString().split("\n"); + } + + public static void banner(PrintStream out) { + Manifest manifest = findMyManifest(); + if (null != manifest) { + String version = manifest.getMainAttributes().getValue(Attributes.Name.SPECIFICATION_VERSION); + String buildDate = manifest.getMainAttributes().getValue("Build-Date"); + String buildTime = manifest.getMainAttributes().getValue("Build-Time"); + String buildRevision = manifest.getMainAttributes().getValue("Build-Revision"); + boolean additionalInfo = isNotBlank(buildDate) || isNotBlank(buildTime) || isNotBlank(buildRevision); + + out.println("------------------------------------------------------------"); + out.println("jreleaser " + version); + out.println("------------------------------------------------------------"); + if (additionalInfo) { + if (isNotBlank(buildDate) && isNotBlank(buildTime)) { + out.println("Build time: " + buildDate + " " + buildTime); + } + if (isNotBlank(buildRevision)) out.println("Revision: " + buildRevision); + out.println("------------------------------------------------------------"); + } + } else { + out.println("jreleaser " + JRELEASER_VERSION); + } + } + + private static Manifest findMyManifest() { + try { + Enumeration urls = Versions.class.getClassLoader().getResources("META-INF/MANIFEST.MF"); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + Manifest manifest = new Manifest(url.openStream()); + if (manifest.getMainAttributes().containsKey(Attributes.Name.SPECIFICATION_TITLE)) { + String specificationTitle = manifest.getMainAttributes().getValue(Attributes.Name.SPECIFICATION_TITLE); + if ("jreleaser".equals(specificationTitle)) { + return manifest; + } + } + } + } catch (IOException e) { + // well, this sucks + } + + return null; + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/Colorizer.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/Colorizer.java new file mode 100644 index 00000000..d8f5ba6f --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/Colorizer.java @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app.internal; + +import picocli.CommandLine; + +import java.io.PrintWriter; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Colorizer extends PrintWriter { + public Colorizer(PrintWriter delegate) { + super(delegate, true); + } + + @Override + public void print(String s) { + super.print(CommandLine.Help.Ansi.AUTO.text("@|red " + s + "|@")); + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/JReleaserLoggerAdapter.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/JReleaserLoggerAdapter.java new file mode 100644 index 00000000..a56d5fef --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/JReleaserLoggerAdapter.java @@ -0,0 +1,162 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app.internal; + +import org.kordamp.jreleaser.util.Logger; +import org.slf4j.helpers.MessageFormatter; +import picocli.CommandLine; + +import java.io.PrintWriter; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserLoggerAdapter implements Logger { + private final PrintWriter out; + private final Level level; + + public JReleaserLoggerAdapter(PrintWriter out) { + this(out, Level.WARN); + } + + public JReleaserLoggerAdapter(PrintWriter out, Level level) { + this.out = out; + this.level = level; + } + + @Override + public void debug(String message) { + if (isLevelEnabled(Level.DEBUG)) { + out.println(Level.DEBUG + message); + } + } + + @Override + public void info(String message) { + if (isLevelEnabled(Level.INFO)) { + out.println(Level.INFO + message); + } + } + + @Override + public void warn(String message) { + if (isLevelEnabled(Level.WARN)) { + out.println(Level.WARN + message); + } + } + + @Override + public void error(String message) { + if (isLevelEnabled(Level.ERROR)) { + out.println(Level.ERROR + message); + } + } + + @Override + public void debug(String message, Object... args) { + if (isLevelEnabled(Level.DEBUG)) { + out.println(Level.DEBUG + MessageFormatter.arrayFormat(message, args).getMessage()); + } + } + + @Override + public void info(String message, Object... args) { + if (isLevelEnabled(Level.INFO)) { + out.println(Level.INFO + MessageFormatter.arrayFormat(message, args).getMessage()); + } + } + + @Override + public void warn(String message, Object... args) { + if (isLevelEnabled(Level.WARN)) { + out.println(Level.WARN + MessageFormatter.arrayFormat(message, args).getMessage()); + } + } + + @Override + public void error(String message, Object... args) { + if (isLevelEnabled(Level.ERROR)) { + out.println(Level.ERROR + MessageFormatter.arrayFormat(message, args).getMessage()); + } + } + + @Override + public void debug(String message, Throwable throwable) { + if (isLevelEnabled(Level.DEBUG)) { + out.println(Level.DEBUG + message); + printThrowable(throwable); + } + } + + @Override + public void info(String message, Throwable throwable) { + if (isLevelEnabled(Level.INFO)) { + out.println(Level.INFO + message); + printThrowable(throwable); + } + } + + @Override + public void warn(String message, Throwable throwable) { + if (isLevelEnabled(Level.WARN)) { + out.println(Level.WARN + message); + printThrowable(throwable); + } + } + + @Override + public void error(String message, Throwable throwable) { + if (isLevelEnabled(Level.ERROR)) { + out.println(Level.ERROR + message); + printThrowable(throwable); + } + } + + private void printThrowable(Throwable throwable) { + if (null != throwable) { + throwable.printStackTrace(new Colorizer(out)); + } + } + + private boolean isLevelEnabled(Level requested) { + return requested.ordinal() >= level.ordinal(); + } + + public enum Level { + DEBUG("cyan"), + INFO("blue"), + WARN("yellow"), + ERROR("red"); + + private final String color; + + Level(String color) { + this.color = color; + } + + @Override + public String toString() { + return "[" + colorize(name()) + "] "; + } + + private String colorize(String input) { + return CommandLine.Help.Ansi.AUTO.string("@|" + color + " " + input + "|@"); + } + } +} diff --git a/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/JReleaserModelPrinter.java b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/JReleaserModelPrinter.java new file mode 100644 index 00000000..beed8087 --- /dev/null +++ b/apps/jreleaser/src/main/java/org/kordamp/jreleaser/app/internal/JReleaserModelPrinter.java @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.app.internal; + +import picocli.CommandLine; + +import java.io.PrintWriter; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserModelPrinter extends org.kordamp.jreleaser.model.JReleaserModelPrinter { + public JReleaserModelPrinter(PrintWriter out) { + super(out); + } + + public JReleaserModelPrinter(PrintWriter out, boolean showSecrets) { + super(out, showSecrets); + } + + @Override + protected String color(String color, String input) { + return CommandLine.Help.Ansi.AUTO.string("@|" + color + " " + input + "|@"); + } +} diff --git a/apps/jreleaser/src/main/module/module-info.java b/apps/jreleaser/src/main/module/module-info.java new file mode 100644 index 00000000..62b16f5a --- /dev/null +++ b/apps/jreleaser/src/main/module/module-info.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.app { + exports org.kordamp.jreleaser.app; + requires org.kordamp.jreleaser.util; + requires org.kordamp.jreleaser.model; + requires org.kordamp.jreleaser.config; + requires org.kordamp.jreleaser.tools; + requires org.kordamp.jreleaser.templates; + requires info.picocli; + requires org.slf4j; + requires org.slf4j.simple; + + opens org.kordamp.jreleaser.app to info.picocli; +} \ No newline at end of file diff --git a/apps/jreleaser/src/main/resources/META-INF/jreleaser/templates/jreleaser.yml.tpl b/apps/jreleaser/src/main/resources/META-INF/jreleaser/templates/jreleaser.yml.tpl new file mode 100644 index 00000000..d78b80e4 --- /dev/null +++ b/apps/jreleaser/src/main/resources/META-INF/jreleaser/templates/jreleaser.yml.tpl @@ -0,0 +1,19 @@ +project: + name: awesomeApp + version: 0.0.0-SNAPSHOT + description: Awesome App + longDescription: Awesome App + website: https://acme.com/awesomeapp + authors: + - Joe Cool + license: Apache-2 + javaVersion: 8 + +release: + repoType: GITHUB + repoOwner: acme + +distributions: + awesomeApp: + artifacts: + - path: /path/to/app/awesomeApp-0.0.0-SNAPSHOT.zip \ No newline at end of file diff --git a/apps/jreleaser/src/main/resources/org/kordamp/jreleaser/app/Banner.properties b/apps/jreleaser/src/main/resources/org/kordamp/jreleaser/app/Banner.properties new file mode 100644 index 00000000..d841c0dc --- /dev/null +++ b/apps/jreleaser/src/main/resources/org/kordamp/jreleaser/app/Banner.properties @@ -0,0 +1,22 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +product.version=$version +product.id=$id +product.name=$name +product.banner={0} {1}. Consider becoming a patron at https://www.patreon.com/aalmiray \ No newline at end of file diff --git a/apps/jreleaser/src/main/resources/org/kordamp/jreleaser/app/Versions.properties b/apps/jreleaser/src/main/resources/org/kordamp/jreleaser/app/Versions.properties new file mode 100644 index 00000000..3c10a483 --- /dev/null +++ b/apps/jreleaser/src/main/resources/org/kordamp/jreleaser/app/Versions.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +jreleaser_version = ${version} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..33c49996 --- /dev/null +++ b/build.gradle @@ -0,0 +1,105 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +config { + info { + description = 'jreleaser' + inceptionYear = '2020' + tags = ['release'] + + specification { + enabled = true + } + + implementation { + enabled = true + } + } + + docs { + javadoc { + autoLinks { + enabled = false + } + } + } + + bintray { + enabled = false + } +} + +allprojects { + repositories { + gradlePluginPortal() + jcenter() + mavenLocal() + } + + tasks.withType(GenerateModuleMetadata) { + enabled = false + } +} + +subprojects { + if (project.name != 'guide') { + config { + info { + description = project.project_description + } + + bintray { + enabled = true + name = project.name + } + } + + tasks.withType(JavaCompile) { JavaCompile c -> + c.sourceCompatibility = JavaVersion.VERSION_1_8 + c.targetCompatibility = JavaVersion.VERSION_1_8 + } + tasks.withType(GroovyCompile) { GroovyCompile c -> + c.sourceCompatibility = JavaVersion.VERSION_1_8 + c.targetCompatibility = JavaVersion.VERSION_1_8 + } + + if (project.projectDir.parentFile.name != 'plugins' && + project.name != 'jreleaser-tool-provider') { + jar { + multiRelease = true + moduleInfoPath = 'src/main/module/module-info.java' + } + } + + license { + exclude('build/**') + exclude('**/*.tpl') + } + + dependencies { + testImplementation "org.junit.jupiter:junit-jupiter:$junitVersion" + testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion" + + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + } + + test { + useJUnitPlatform() + } + } +} diff --git a/core/jreleaser-config-yaml/gradle.properties b/core/jreleaser-config-yaml/gradle.properties new file mode 100644 index 00000000..aa48a345 --- /dev/null +++ b/core/jreleaser-config-yaml/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser YAML config support \ No newline at end of file diff --git a/core/jreleaser-config-yaml/jreleaser-config-yaml.gradle b/core/jreleaser-config-yaml/jreleaser-config-yaml.gradle new file mode 100644 index 00000000..111108db --- /dev/null +++ b/core/jreleaser-config-yaml/jreleaser-config-yaml.gradle @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-config') + api "org.yaml:snakeyaml:$snakeYamlVersion" + + compileOnly "org.kordamp.jipsy:jipsy:${jipsyVersion}" + annotationProcessor "org.kordamp.jipsy:jipsy:${jipsyVersion}" +} \ No newline at end of file diff --git a/core/jreleaser-config-yaml/src/main/java/org/kordamp/jreleaser/config/yaml/YamlJReleaserConfigParser.java b/core/jreleaser-config-yaml/src/main/java/org/kordamp/jreleaser/config/yaml/YamlJReleaserConfigParser.java new file mode 100644 index 00000000..b00092a3 --- /dev/null +++ b/core/jreleaser-config-yaml/src/main/java/org/kordamp/jreleaser/config/yaml/YamlJReleaserConfigParser.java @@ -0,0 +1,71 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.config.yaml; + +import org.kordamp.jipsy.ServiceProviderFor; +import org.kordamp.jreleaser.config.JReleaserConfigParser; +import org.kordamp.jreleaser.model.Artifact; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Plug; +import org.kordamp.jreleaser.model.Slot; +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.introspector.Property; +import org.yaml.snakeyaml.introspector.PropertyUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@ServiceProviderFor(JReleaserConfigParser.class) +public class YamlJReleaserConfigParser implements JReleaserConfigParser { + @Override + public boolean supports(Path configFile) { + String fileName = configFile.getFileName().toString(); + return fileName.endsWith(".yml") || fileName.endsWith(".yaml"); + } + + @Override + public JReleaserModel parse(InputStream inputStream) throws IOException { + Constructor c = new Constructor(JReleaserModel.class); + TypeDescription td = new TypeDescription(JReleaserModel.class); + td.addPropertyParameters("artifacts", Artifact.class); + td.addPropertyParameters("plugs", Plug.class); + td.addPropertyParameters("slots", Slot.class); + c.addTypeDescription(td); + + c.setPropertyUtils(new PropertyUtils() { + @Override + public Property getProperty(Class type, String name) { + if (name.equals("class")) { + name = "clazz"; + } + return super.getProperty(type, name); + } + }); + + Yaml yaml = new Yaml(c); + + return yaml.load(inputStream); + } +} diff --git a/core/jreleaser-config-yaml/src/main/module/module-info.java b/core/jreleaser-config-yaml/src/main/module/module-info.java new file mode 100644 index 00000000..0c52e0c6 --- /dev/null +++ b/core/jreleaser-config-yaml/src/main/module/module-info.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.config.yaml { + exports org.kordamp.jreleaser.config.yaml; + requires org.kordamp.jreleaser.config; + requires org.kordamp.jreleaser.model; + requires org.yaml.snakeyaml; + requires static org.kordamp.jipsy; + requires static org.kordamp.jipsy.annotations; + + provides org.kordamp.jreleaser.config.JReleaserConfigParser + with org.kordamp.jreleaser.config.yaml.YamlJReleaserConfigParser; +} \ No newline at end of file diff --git a/core/jreleaser-config/gradle.properties b/core/jreleaser-config/gradle.properties new file mode 100644 index 00000000..df3d7f5b --- /dev/null +++ b/core/jreleaser-config/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser config support \ No newline at end of file diff --git a/core/jreleaser-config/jreleaser-config.gradle b/core/jreleaser-config/jreleaser-config.gradle new file mode 100644 index 00000000..cc845253 --- /dev/null +++ b/core/jreleaser-config/jreleaser-config.gradle @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-model') +} \ No newline at end of file diff --git a/core/jreleaser-config/src/main/java/org/kordamp/jreleaser/config/JReleaserConfigLoader.java b/core/jreleaser-config/src/main/java/org/kordamp/jreleaser/config/JReleaserConfigLoader.java new file mode 100644 index 00000000..6cca5f3c --- /dev/null +++ b/core/jreleaser-config/src/main/java/org/kordamp/jreleaser/config/JReleaserConfigLoader.java @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.config; + +import org.kordamp.jreleaser.model.JReleaserModel; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.ServiceLoader; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserConfigLoader { + public static JReleaserModel loadConfig(Path configFile) { + ServiceLoader parsers = ServiceLoader.load(JReleaserConfigParser.class, JReleaserConfigParser.class.getClassLoader()); + + for (JReleaserConfigParser parser : parsers) { + if (parser.supports(configFile)) { + try (InputStream inputStream = configFile.toUri().toURL().openStream()) { + return parser.parse(inputStream); + } catch (IOException e) { + throw new IllegalArgumentException("Unexpected error parsing config file. " + configFile, e); + } + } + } + throw new IllegalArgumentException("Unsupported config format. " + configFile); + } +} diff --git a/core/jreleaser-config/src/main/java/org/kordamp/jreleaser/config/JReleaserConfigParser.java b/core/jreleaser-config/src/main/java/org/kordamp/jreleaser/config/JReleaserConfigParser.java new file mode 100644 index 00000000..26494ec7 --- /dev/null +++ b/core/jreleaser-config/src/main/java/org/kordamp/jreleaser/config/JReleaserConfigParser.java @@ -0,0 +1,50 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.config; + +import org.kordamp.jreleaser.model.JReleaserModel; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; + +/** + * Allows external configuration to be parsed with a custom format. + * + * @author Andres Almiray + * @since 0.1.0 + */ +public interface JReleaserConfigParser { + /** + * Whether the given config file format is supported or not.

+ * Implementors would typically look at the file extension. + * + * @param configFile the configuration file to inspect + * @return {@code true} if the given format is supported, {@code false} otherwise. + */ + boolean supports(Path configFile); + + /** + * Reads and parses external configuration into a {@code JReleaserModel} instance. + * + * @param inputStream the configuration's input source + * @return a configured {@code JReleaserModel} instance, should never return {@code null}. + * @throws IOException if an error occurs while reading from the {@code InputStream}. + */ + JReleaserModel parse(InputStream inputStream) throws IOException; +} diff --git a/core/jreleaser-config/src/main/module/module-info.java b/core/jreleaser-config/src/main/module/module-info.java new file mode 100644 index 00000000..835965ef --- /dev/null +++ b/core/jreleaser-config/src/main/module/module-info.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.config { + exports org.kordamp.jreleaser.config; + requires org.kordamp.jreleaser.model; + + uses org.kordamp.jreleaser.config.JReleaserConfigParser; +} \ No newline at end of file diff --git a/core/jreleaser-model/gradle.properties b/core/jreleaser-model/gradle.properties new file mode 100644 index 00000000..d6674ea8 --- /dev/null +++ b/core/jreleaser-model/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser Model \ No newline at end of file diff --git a/core/jreleaser-model/jreleaser-model.gradle b/core/jreleaser-model/jreleaser-model.gradle new file mode 100644 index 00000000..5b512d17 --- /dev/null +++ b/core/jreleaser-model/jreleaser-model.gradle @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-utils') +} \ No newline at end of file diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/AbstractDomain.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/AbstractDomain.java new file mode 100644 index 00000000..0c951015 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/AbstractDomain.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.io.Serializable; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractDomain implements Serializable { + public abstract Map asMap(); +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/AbstractTool.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/AbstractTool.java new file mode 100644 index 00000000..15a3be7c --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/AbstractTool.java @@ -0,0 +1,110 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractTool extends AbstractDomain implements Tool { + protected final String toolName; + protected final Map extraProperties = new LinkedHashMap<>(); + protected Boolean enabled; + protected boolean enabledSet; + protected Path templateDirectory; + + protected AbstractTool(String toolName) { + this.toolName = toolName; + } + + void setAll(AbstractTool tool) { + this.enabled = tool.enabled; + this.enabledSet = tool.enabledSet; + this.templateDirectory = tool.templateDirectory; + setExtraProperties(tool.extraProperties); + } + + @Override + public Boolean isEnabled() { + return enabled != null && enabled; + } + + @Override + public void setEnabled(Boolean enabled) { + this.enabledSet = true; + this.enabled = enabled; + } + + @Override + public boolean isEnabledSet() { + return enabledSet; + } + + @Override + public String getToolName() { + return toolName; + } + + @Override + public Path getTemplateDirectory() { + return templateDirectory; + } + + @Override + public void setTemplateDirectory(Path templateDirectory) { + this.templateDirectory = templateDirectory; + } + + @Override + public Map getExtraProperties() { + return extraProperties; + } + + @Override + public void setExtraProperties(Map extraProperties) { + this.extraProperties.clear(); + this.extraProperties.putAll(extraProperties); + } + + @Override + public void addExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + @Override + public final Map asMap() { + if (!isEnabled()) return Collections.emptyMap(); + + Map props = new LinkedHashMap<>(); + props.put("enabled", isEnabled()); + props.put("templateDirectory", templateDirectory); + asMap(props); + props.put("extraProperties", extraProperties); + + Map map = new LinkedHashMap<>(); + map.put(getToolName(), props); + return map; + } + + protected abstract void asMap(Map props); +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Artifact.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Artifact.java new file mode 100644 index 00000000..f5a94eb5 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Artifact.java @@ -0,0 +1,73 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Artifact extends AbstractDomain { + private String path; + private String hash; + private String osClassifier; + private String javaVersion; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getOsClassifier() { + return osClassifier; + } + + public void setOsClassifier(String osClassifier) { + this.osClassifier = osClassifier; + } + + public String getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("path", path); + map.put("hash", hash); + map.put("osClassifier", osClassifier); + map.put("javaVersion", javaVersion); + return map; + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Brew.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Brew.java new file mode 100644 index 00000000..ecee0437 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Brew.java @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Brew extends AbstractTool { + public static final String TOOL_NAME = "brew"; + + private final Map dependencies = new LinkedHashMap<>(); + + public Brew() { + super(TOOL_NAME); + } + + void setAll(Brew brew) { + super.setAll(brew); + setDependencies(brew.dependencies); + } + + public Map getDependencies() { + return dependencies; + } + + public void setDependencies(Map dependencies) { + this.dependencies.clear(); + this.dependencies.putAll(dependencies); + } + + public void addDependencies(Map dependencies) { + this.dependencies.putAll(dependencies); + } + + public void addDependency(String key, String value) { + dependencies.put(key, value); + } + + public void addDependency(String key) { + dependencies.put(key, ""); + } + + @Override + protected void asMap(Map props) { + props.put("dependencies", dependencies); + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Chocolatey.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Chocolatey.java new file mode 100644 index 00000000..f68c9c48 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Chocolatey.java @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Chocolatey extends AbstractTool { + public static final String TOOL_NAME = "chocolatey"; + + public Chocolatey() { + super(TOOL_NAME); + } + + @Override + protected void asMap(Map props) { + // empty + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Distribution.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Distribution.java new file mode 100644 index 00000000..f78759d8 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Distribution.java @@ -0,0 +1,218 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.kordamp.jreleaser.util.StringUtils.isBlank; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Distribution extends Packagers implements ExtraProperties { + private final List tags = new ArrayList<>(); + private final Map extraProperties = new LinkedHashMap<>(); + private final List artifacts = new ArrayList<>(); + private String name; + private DistributionType type = DistributionType.BINARY; + private String executable; + private String javaVersion; + + void setAll(Distribution distribution) { + super.setAll(distribution); + this.name = distribution.name; + this.type = distribution.type; + this.executable = distribution.executable; + this.javaVersion = distribution.javaVersion; + setTags(distribution.tags); + setExtraProperties(distribution.extraProperties); + setArtifacts(distribution.artifacts); + } + + public DistributionType getType() { + return type; + } + + public void setType(DistributionType type) { + this.type = type; + } + + public void setType(String type) { + this.type = DistributionType.valueOf(type.replaceAll(" ", "_") + .replaceAll("-", "_") + .toUpperCase()); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getExecutable() { + return executable; + } + + public void setExecutable(String executable) { + this.executable = executable; + } + + public String getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + public List getArtifacts() { + return artifacts; + } + + public void setArtifacts(List artifacts) { + this.artifacts.clear(); + this.artifacts.addAll(artifacts); + } + + public void addArtifacts(List artifacts) { + this.artifacts.addAll(artifacts); + } + + public void addArtifact(Artifact artifact) { + if (null != artifact) { + this.artifacts.add(artifact); + } + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags.clear(); + this.tags.addAll(tags); + } + + public void addTags(List tags) { + this.tags.addAll(tags); + } + + public void addTag(String tag) { + if (isNotBlank(tag)) { + this.tags.add(tag.trim()); + } + } + + public void removeTag(String tag) { + if (isNotBlank(tag)) { + this.tags.remove(tag.trim()); + } + } + + @Override + public Map getExtraProperties() { + return extraProperties; + } + + @Override + public void setExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + @Override + public void addExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + // --== TOOLs ==-- + + public T findTool(String name) { + if (isBlank(name)) { + throw new IllegalArgumentException("Tool name must not be blank"); + } + + return resolveTool(name); + } + + public T getTool(String name) { + T tool = findTool(name); + if (null != tool) { + return tool; + } + throw new IllegalArgumentException("Tool '" + name + "' has not been configured"); + } + + private T resolveTool(String name) { + switch (name.toLowerCase().trim()) { + case Brew.TOOL_NAME: + return (T) getBrew(); + case Chocolatey.TOOL_NAME: + return (T) getChocolatey(); + case Scoop.TOOL_NAME: + return (T) getScoop(); + case Snap.TOOL_NAME: + return (T) getSnap(); + default: + throw new IllegalArgumentException("Unsupported tool '" + name + "'"); + } + } + + @Override + public Map asMap() { + Map props = new LinkedHashMap<>(); + props.put("type", type); + props.put("executable", executable); + props.put("javaVersion", javaVersion); + props.put("artifacts", artifacts.stream() + .map(Artifact::asMap) + .collect(Collectors.toList())); + props.put("tags", tags); + props.put("extraProperties", extraProperties); + props.putAll(super.asMap()); + + Map map = new LinkedHashMap<>(); + map.put(name, props); + return map; + } + + public static Set supportedTools() { + Set set = new LinkedHashSet<>(); + set.add(Brew.TOOL_NAME); + set.add(Chocolatey.TOOL_NAME); + set.add(Scoop.TOOL_NAME); + set.add(Snap.TOOL_NAME); + return Collections.unmodifiableSet(set); + } + + public enum DistributionType { + BINARY, + SINGLE_JAR + // NATIVE_IMAGE, + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/ExtraProperties.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/ExtraProperties.java new file mode 100644 index 00000000..119b4b80 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/ExtraProperties.java @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.io.Serializable; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface ExtraProperties extends Serializable { + Map getExtraProperties(); + + void setExtraProperties(Map properties); + + void addExtraProperties(Map properties); +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModel.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModel.java new file mode 100644 index 00000000..70a20e17 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModel.java @@ -0,0 +1,104 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.kordamp.jreleaser.util.StringUtils.isBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserModel extends AbstractDomain { + private final Project project = new Project(); + private final Release release = new Release(); + private final Packagers packagers = new Packagers(); + private final Map distributions = new LinkedHashMap<>(); + + public Project getProject() { + return project; + } + + public void setProject(Project project) { + this.project.setAll(project); + } + + public Release getRelease() { + return release; + } + + public void setRelease(Release release) { + this.release.setAll(release); + } + + public Packagers getPackagers() { + return packagers; + } + + public void setPackagers(Packagers packagers) { + this.packagers.setAll(packagers); + } + + public Map getDistributions() { + return distributions; + } + + public void setDistributions(Map distributions) { + this.distributions.clear(); + this.distributions.putAll(distributions); + } + + public void addDistributions(Map distributions) { + this.distributions.putAll(distributions); + } + + public void addDistribution(Distribution distribution) { + this.distributions.put(distribution.getName(), distribution); + } + + public Distribution findDistribution(String name) { + if (isBlank(name)) { + throw new IllegalArgumentException("Distribution name must not be blank"); + } + + if (distributions.isEmpty()) { + throw new IllegalArgumentException("No distributions have been configured"); + } + + if (distributions.containsKey(name)) { + return distributions.get(name); + } + + throw new IllegalArgumentException("Distribution '" + name + "' not found"); + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("project", project.asMap()); + map.put("release", release.asMap()); + map.put("packagers", packagers.asMap()); + map.put("distributions", distributions.values() + .stream() + .map(Distribution::asMap) + .collect(Collectors.toList())); + return map; + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModelPrinter.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModelPrinter.java new file mode 100644 index 00000000..8ef1a146 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModelPrinter.java @@ -0,0 +1,298 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public abstract class JReleaserModelPrinter { + private static final String SECRET_KEYWORDS = "password,secret,credential,token,apikey,login"; + private static final String KEY_SECRET_KEYWORDS = "kordamp.secret.keywords"; + private final boolean showSecrets; + private final PrintWriter out; + + public JReleaserModelPrinter(PrintWriter out) { + this(out, false); + } + + public JReleaserModelPrinter(PrintWriter out, boolean showSecrets) { + this.out = out; + this.showSecrets = showSecrets; + } + + public void print(Object value) { + print(value, 0); + } + + public void print(Object value, int offset) { + if (value instanceof Map) { + doPrintMap((Map) value, offset); + } else if (value instanceof Collection) { + doPrintCollection((Collection) value, offset); + } else if (null != value) { + Class clazz = value.getClass(); + if (clazz.isArray()) { + doPrintArray((Object[]) value, offset); + } else { + doPrintElement(value, offset); + } + } + } + + private void print(String value, int offset) { + doPrintElement(value, offset); + } + + private void doPrintMap(Map map, final int offset) { + if (map != null) { + map.forEach((key, value) -> { + if (value instanceof Map) { + if (!((Map) value).isEmpty()) { + out.println(multiply(" ", offset) + key + ":"); + doPrintMap((Map) value, offset + 1); + } + } else if (value instanceof Collection) { + if (!((Collection) value).isEmpty()) { + out.println(multiply(" ", offset) + key + ":"); + doPrintCollection((Collection) value, offset + 1); + } + } else if (null != value && value.getClass().isArray()) { + if (((Object[]) value).length > 0) { + out.println(multiply(" ", offset) + key + ":"); + doPrintArray((Object[]) value, offset + 1); + } + } else if (isNotNullNorBlank(value)) { + doPrintMapEntry(key, value, offset); + } + + if (offset == 0) { + out.println(" "); + } + }); + } + } + + private void doPrintMapEntry(String key, Object value, int offset) { + if (value instanceof Map) { + doPrintMap(key, (Map) value, offset); + } else if (value instanceof Collection) { + doPrintCollection(key, (Collection) value, offset); + } else if (null != value) { + Class clazz = value.getClass(); + if (clazz.isArray()) { + doPrintArray(key, (Object[]) value, offset); + } else { + String result = formatValue(value, isSecret(key)); + if (isNotNullNorBlank(result)) { + out.println(multiply(" ", offset) + key + ": " + result); + } + } + } + } + + private void doPrintCollection(Collection collection, final int offset) { + if (collection != null) { + collection.forEach(value -> { + if (value instanceof Map) { + if (!((Map) value).isEmpty()) { + doPrintMap((Map) value, offset); + } + } else if (value instanceof Collection) { + if (!((Collection) value).isEmpty()) { + doPrintCollection((Collection) value, offset + 1); + } + } else if (null != value && value.getClass().isArray()) { + if (((Object[]) value).length > 0) { + doPrintArray((Object[]) value, offset + 1); + } + } else if (isNotNullNorBlank(value)) { + doPrintElement(value, offset); + } + }); + } + } + + private void doPrintArray(Object[] array, final int offset) { + if (array != null) { + Arrays.stream(array).forEach(value -> { + if (value instanceof Map) { + if (!((Map) value).isEmpty()) { + doPrintMap((Map) value, offset); + } + } else if (value instanceof Collection) { + if (!((Collection) value).isEmpty()) { + doPrintCollection((Collection) value, offset + 1); + } + } else if (null != value && value.getClass().isArray()) { + if (((Object[]) value).length > 0) { + doPrintArray((Object[]) value, offset + 1); + } + } else if (isNotNullNorBlank(value)) { + doPrintElement(value, offset); + } + }); + } + } + + private void doPrintMap(String key, Map map, int offset) { + if (map != null && !map.isEmpty()) { + out.println(multiply(" ", offset) + key + ':'); + doPrintMap(map, offset + 1); + } + } + + private void doPrintCollection(String key, Collection collection, int offset) { + if (collection != null && !collection.isEmpty()) { + out.println(multiply(" ", offset) + key + ':'); + doPrintCollection(collection, offset + 1); + } + } + + private void doPrintArray(String key, Object[] array, int offset) { + if (array != null && array.length > 0) { + out.println(multiply(" ", offset) + key + ':'); + doPrintArray(array, offset + 1); + } + } + + private void doPrintElement(Object value, int offset) { + String result = formatValue(value); + if (isNotNullNorBlank(result)) { + out.println(multiply(" ", offset) + result); + } + } + + private boolean isNotNullNorBlank(Object value) { + if (value instanceof CharSequence) { + return isNotBlank(String.valueOf(value)); + } + + return value != null; + } + + private String formatValue(Object value) { + return formatValue(value, false); + } + + private String formatValue(Object value, boolean secret) { + if (value instanceof Boolean) { + Boolean b = (Boolean) value; + return b ? green(String.valueOf(b)) : red(String.valueOf(b)); + } else if (value instanceof Number) { + return cyan(String.valueOf(value)); + } else if (value != null) { + String s = String.valueOf(value); + s = secret && !showSecrets ? multiply("*", 12) : s; + + String r = parseAsBoolean(s); + if (r != null) return r; + r = parseAsInteger(s); + if (r != null) return r; + r = parseAsDouble(s); + if (r != null) return r; + + return secret ? magenta(s) : yellow(s); + } + + return String.valueOf(value); + } + + private String parseAsBoolean(String s) { + if ("true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s)) { + boolean b = Boolean.valueOf(s); + return b ? green(String.valueOf(b)) : red(String.valueOf(b)); + } else { + return null; + } + } + + private String parseAsInteger(String s) { + try { + Integer.parseInt(s); + return cyan(s); + } catch (Exception e) { + return null; + } + } + + private String parseAsDouble(String s) { + try { + Double.parseDouble(s); + return cyan(s); + } catch (Exception e) { + return null; + } + } + + private boolean isSecret(String key) { + String lower = key.toLowerCase(); + + for (String keyword : System.getProperty(KEY_SECRET_KEYWORDS, SECRET_KEYWORDS).split(",")) { + if (lower.contains(keyword.trim().toLowerCase())) return true; + } + + return false; + } + + private String cyan(String s) { + return color("cyan", s); + } + + private String red(String s) { + return color("red", s); + } + + private String green(String s) { + return color("green", s); + } + + private String magenta(String s) { + return color("magenta", s); + } + + private String yellow(String s) { + return color("yellow", s); + } + + protected abstract String color(String color, String input); + + private static String multiply(CharSequence self, Number factor) { + int size = factor.intValue(); + if (size == 0) { + return ""; + } else if (size < 0) { + throw new IllegalArgumentException("multiply() should be called with a number of 0 or greater not: " + size); + } else { + StringBuilder answer = new StringBuilder(self); + + for (int i = 1; i < size; ++i) { + answer.append(self); + } + + return answer.toString(); + } + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModelValidator.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModelValidator.java new file mode 100644 index 00000000..e2c5f804 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/JReleaserModelValidator.java @@ -0,0 +1,352 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import org.kordamp.jreleaser.util.Logger; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.groupingBy; +import static org.kordamp.jreleaser.util.StringUtils.capitalize; +import static org.kordamp.jreleaser.util.StringUtils.getFilenameExtension; +import static org.kordamp.jreleaser.util.StringUtils.isBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public final class JReleaserModelValidator { + private JReleaserModelValidator() { + // noop + } + + public static List validate(Logger logger, Path basedir, JReleaserModel model) { + List errors = new ArrayList<>(); + validateModel(logger, basedir, model, errors); + return Collections.unmodifiableList(errors); + } + + private static void validateModel(Logger logger, Path basedir, JReleaserModel model, List errors) { + validateProject(logger, basedir, model.getProject(), errors); + validateRelease(logger, basedir, model.getProject(), model.getRelease(), errors); + validateDistributions(logger, basedir, model, model.getDistributions(), errors); + } + + private static void validateProject(Logger logger, Path basedir, Project project, List errors) { + if (isBlank(project.getName())) { + errors.add("project.name must not be blank"); + } + if (isBlank(project.getVersion())) { + errors.add("project.version must not be blank"); + } + if (isBlank(project.getDescription())) { + errors.add("project.description must not be blank"); + } + if (isBlank(project.getWebsite())) { + errors.add("project.website must not be blank"); + } + if (isBlank(project.getLicense())) { + errors.add("project.license must not be blank"); + } + if (isBlank(project.getLongDescription())) { + project.setLongDescription(project.getDescription()); + } + if (project.getAuthors().isEmpty()) { + errors.add("project.authors must not be empty"); + } + + adjustExtraProperties(project, "project"); + } + + private static void validateRelease(Logger logger, Path basedir, Project project, Release release, List errors) { + if (isBlank(release.getRepoOwner())) { + errors.add("release.repoOwner must not be blank"); + } + if (isBlank(release.getRepoName())) { + release.setRepoName(project.getName()); + } + if (null == release.getRepoType()) { + release.setRepoType(Release.RepoType.GITHUB); + } + + if (isBlank(release.getRepoHost())) { + release.setRepoHost(release.getRepoType().repoHost()); + } + if (isBlank(release.getDownloadUrlFormat())) { + release.setDownloadUrlFormat(release.getRepoType().downloadUrlFormat()); + } + if (isBlank(release.getReleaseNotesUrlFormat())) { + release.setReleaseNotesUrlFormat(release.getRepoType().releaseNotesUrlFormat()); + } + if (isBlank(release.getLatestReleaseUrlFormat())) { + release.setLatestReleaseUrlFormat(release.getRepoType().latestReleaseUrlFormat()); + } + if (isBlank(release.getIssueTrackerUrlFormat())) { + release.setIssueTrackerUrlFormat(release.getRepoType().issueTrackerUrlFormat()); + } + + if (isBlank(release.getAuthorization())) { + String tokenName = release.getRepoType().name() + "_TOKEN"; + logger.warn("release.auhorization is not explicitly defined. Checking environment for {}", tokenName); + if (isBlank(System.getenv(tokenName))) { + errors.add("release.authorization must not be blank. Alternatively define a " + tokenName + " environment variable."); + } + return; + } + if (isBlank(release.getTagName())) { + release.setTagName("v" + project.getVersion()); + } + if (isBlank(release.getTargetCommitish())) { + release.setTargetCommitish("main"); + } + } + + private static void validateDistributions(Logger logger, Path basedir, JReleaserModel model, Map distributions, List errors) { + if (distributions.isEmpty()) { + errors.add("Missing distributions configuration"); + return; + } + + if (distributions.size() == 1) { + distributions.values().stream() + .findFirst().ifPresent(distribution -> distribution.setName(model.getProject().getName())); + } + + for (Map.Entry e : distributions.entrySet()) { + Distribution distribution = e.getValue(); + if (isBlank(distribution.getName())) { + distribution.setName(e.getKey()); + } + validateDistribution(logger, basedir, model, distribution, errors); + } + } + + private static void validateDistribution(Logger logger, Path basedir, JReleaserModel model, Distribution distribution, List errors) { + if (isBlank(distribution.getName())) { + errors.add("distribution.name must not be blank"); + return; + } + if (null == distribution.getType()) { + errors.add("distribution." + distribution.getName() + ".type must not be null"); + return; + } + if (isBlank(distribution.getExecutable())) { + distribution.setExecutable(distribution.getName()); + } + if (isBlank(distribution.getJavaVersion())) { + distribution.setJavaVersion(model.getProject().getJavaVersion()); + } + if (null == distribution.getArtifacts() || distribution.getArtifacts().isEmpty()) { + errors.add("distribution." + distribution.getName() + ".artifacts is empty"); + return; + } + + List tags = new ArrayList<>(); + tags.addAll(model.getProject().getTags()); + tags.addAll(distribution.getTags()); + distribution.setTags(tags); + + for (int i = 0; i < distribution.getArtifacts().size(); i++) { + validateArtifact(logger, basedir, model, distribution, distribution.getArtifacts().get(i), i, errors); + } + // validate artifact.osClassifier is unique + Map> byClassifier = distribution.getArtifacts().stream() + .collect(groupingBy(artifact -> isBlank(artifact.getOsClassifier()) ? "" : artifact.getOsClassifier())); + // check classifiers by extension + byClassifier.entrySet().forEach(c -> { + String classifier = "".equals(c.getKey()) ? "no" : c.getKey(); + c.getValue().stream() + .collect(groupingBy(artifact -> getFilenameExtension(artifact.getPath()))) + .entrySet().forEach(e -> { + if (e.getValue().size() > 1) { + errors.add("distribution." + distribution.getName() + + " has more than one artifact with " + classifier + + " classifier for extension " + e.getValue()); + } + }); + }); + + adjustExtraProperties(distribution, "distribution"); + + validateBrew(logger, basedir, model, distribution, distribution.getBrew(), errors); + validateChocolatey(logger, basedir, model, distribution, distribution.getChocolatey(), errors); + validateScoop(logger, basedir, model, distribution, distribution.getScoop(), errors); + validateSnap(logger, basedir, model, distribution, distribution.getSnap(), errors); + } + + private static void validateArtifact(Logger logger, Path basedir, JReleaserModel model, Distribution distribution, Artifact artifact, int index, List errors) { + if (null == artifact) { + errors.add("distribution." + distribution.getName() + ".artifact[" + index + "] is null"); + return; + } + if (isBlank(artifact.getPath())) { + errors.add("distribution." + distribution.getName() + ".artifact[" + index + "].path must not be null"); + } + if (isBlank(artifact.getJavaVersion())) { + artifact.setJavaVersion(distribution.getJavaVersion()); + } + } + + private static void validateBrew(Logger logger, Path basedir, JReleaserModel model, Distribution distribution, Brew tool, List errors) { + if (!tool.isEnabledSet() && model.getPackagers().getBrew().isEnabledSet()) { + tool.setEnabled(model.getPackagers().getBrew().isEnabled()); + } + validateTemplate(logger, model, distribution, tool, tool.getToolName(), errors); + adjustExtraProperties(model.getPackagers().getBrew(), tool.getToolName()); + adjustExtraProperties(tool, tool.getToolName()); + mergeExtraProperties(tool, model.getPackagers().getBrew()); + + Map dependencies = new LinkedHashMap<>(model.getPackagers().getBrew().getDependencies()); + dependencies.putAll(tool.getDependencies()); + + tool.setDependencies(dependencies); + } + + private static void validateChocolatey(Logger logger, Path basedir, JReleaserModel model, Distribution distribution, Chocolatey tool, List errors) { + if (!tool.isEnabledSet() && model.getPackagers().getChocolatey().isEnabledSet()) { + tool.setEnabled(model.getPackagers().getChocolatey().isEnabled()); + } + validateTemplate(logger, model, distribution, tool, tool.getToolName(), errors); + adjustExtraProperties(model.getPackagers().getChocolatey(), tool.getToolName()); + adjustExtraProperties(tool, tool.getToolName()); + mergeExtraProperties(tool, model.getPackagers().getChocolatey()); + } + + private static void validateScoop(Logger logger, Path basedir, JReleaserModel model, Distribution distribution, Scoop tool, List errors) { + if (!tool.isEnabledSet() && model.getPackagers().getScoop().isEnabledSet()) { + tool.setEnabled(model.getPackagers().getScoop().isEnabled()); + } + validateTemplate(logger, model, distribution, tool, tool.getToolName(), errors); + Scoop commonScoop = model.getPackagers().getScoop(); + adjustExtraProperties(commonScoop, tool.getToolName()); + adjustExtraProperties(tool, tool.getToolName()); + mergeExtraProperties(tool, model.getPackagers().getScoop()); + + if (isBlank(tool.getCheckverUrl())) { + tool.setCheckverUrl(commonScoop.getCheckverUrl()); + if (isBlank(tool.getCheckverUrl())) { + tool.setCheckverUrl(model.getRelease().getLatestReleaseUrlFormat()); + } + } + if (isBlank(tool.getAutoupdateUrl())) { + tool.setAutoupdateUrl(commonScoop.getAutoupdateUrl()); + if (isBlank(tool.getAutoupdateUrl())) { + tool.setAutoupdateUrl(model.getRelease().getDownloadUrlFormat()); + } + } + } + + private static void validateSnap(Logger logger, Path basedir, JReleaserModel model, Distribution distribution, Snap tool, List errors) { + if (!tool.isEnabledSet() && model.getPackagers().getSnap().isEnabledSet()) { + tool.setEnabled(model.getPackagers().getSnap().isEnabled()); + } + validateTemplate(logger, model, distribution, tool, tool.getToolName(), errors); + Snap commonSnap = model.getPackagers().getSnap(); + adjustExtraProperties(commonSnap, tool.getToolName()); + adjustExtraProperties(tool, tool.getToolName()); + mergeExtraProperties(tool, model.getPackagers().getSnap()); + mergeSnapPlugs(tool, model.getPackagers().getSnap()); + mergeSnapSlots(tool, model.getPackagers().getSnap()); + + if (isBlank(tool.getBase())) { + tool.setBase(commonSnap.getBase()); + if (isBlank(tool.getBase())) { + errors.add("distribution." + distribution.getName() + ".snap.base must not be blank"); + } + } + if (isBlank(tool.getGrade())) { + tool.setGrade(commonSnap.getGrade()); + if (isBlank(tool.getGrade())) { + errors.add("distribution." + distribution.getName() + ".snap.grade must not be blank"); + } + } + if (isBlank(tool.getConfinement())) { + tool.setConfinement(commonSnap.getConfinement()); + if (isBlank(tool.getConfinement())) { + errors.add("distribution." + distribution.getName() + ".snap.confinement must not be blank"); + } + } + if (isBlank(tool.getExportedLogin())) { + tool.setExportedLogin(commonSnap.getExportedLogin()); + if (isBlank(tool.getExportedLogin())) { + errors.add("distribution." + distribution.getName() + ".snap.exportedLogin must not be empty"); + } else if (!basedir.resolve(tool.getExportedLogin()).toFile().exists()) { + errors.add("distribution." + distribution.getName() + ".snap.exportedLogin does not exist. " + basedir.resolve(tool.getExportedLogin())); + } + } + } + + private static void mergeExtraProperties(Tool tool, Tool common) { + Map extraProperties = new LinkedHashMap<>(common.getExtraProperties()); + extraProperties.putAll(tool.getExtraProperties()); + tool.setExtraProperties(extraProperties); + } + + private static void mergeSnapPlugs(Snap tool, Snap common) { + Map commonPlugs = common.getPlugs().stream() + .collect(Collectors.toMap(Plug::getName, Plug::copyOf)); + Map toolPlugs = tool.getPlugs().stream() + .collect(Collectors.toMap(Plug::getName, Plug::copyOf)); + commonPlugs.forEach((name, cp) -> { + Plug tp = toolPlugs.remove(name); + if (null != tp) { + cp.getAttributes().putAll(tp.getAttributes()); + } + }); + commonPlugs.putAll(toolPlugs); + tool.setPlugs(new ArrayList<>(commonPlugs.values())); + } + + private static void mergeSnapSlots(Snap tool, Snap common) { + Map commonSlots = common.getSlots().stream() + .collect(Collectors.toMap(Slot::getName, Slot::copyOf)); + Map toolSlots = tool.getSlots().stream() + .collect(Collectors.toMap(Slot::getName, Slot::copyOf)); + commonSlots.forEach((name, cp) -> { + Slot tp = toolSlots.remove(name); + if (null != tp) { + cp.getAttributes().putAll(tp.getAttributes()); + } + }); + commonSlots.putAll(toolSlots); + tool.setSlots(new ArrayList<>(commonSlots.values())); + } + + private static void validateTemplate(Logger logger, JReleaserModel model, Distribution distribution, Tool tool, String toolName, List errors) { + if (null != tool.getTemplateDirectory() && !tool.getTemplateDirectory().toFile().exists()) { + errors.add("distribution." + distribution.getName() + "." + toolName + ".template does not exist. " + tool.getTemplateDirectory()); + } + } + + private static void adjustExtraProperties(ExtraProperties extra, String prefix) { + if (extra.getExtraProperties().size() > 0) { + Map props = extra.getExtraProperties() + .entrySet().stream() + .collect(Collectors.toMap( + e -> prefix + capitalize(e.getKey()), + Map.Entry::getValue)); + extra.setExtraProperties(props); + } + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Packagers.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Packagers.java new file mode 100644 index 00000000..ae6d4556 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Packagers.java @@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Packagers extends AbstractDomain { + private final Brew brew = new Brew(); + private final Chocolatey chocolatey = new Chocolatey(); + private final Scoop scoop = new Scoop(); + private final Snap snap = new Snap(); + + void setAll(Packagers packagers) { + setBrew(packagers.brew); + setChocolatey(packagers.chocolatey); + setScoop(packagers.scoop); + setSnap(packagers.snap); + } + + public Brew getBrew() { + return brew; + } + + public void setBrew(Brew brew) { + this.brew.setAll(brew); + } + + public Chocolatey getChocolatey() { + return chocolatey; + } + + public void setChocolatey(Chocolatey chocolatey) { + this.chocolatey.setAll(chocolatey); + } + + public Scoop getScoop() { + return scoop; + } + + public void setScoop(Scoop scoop) { + this.scoop.setAll(scoop); + } + + public Snap getSnap() { + return snap; + } + + public void setSnap(Snap snap) { + this.snap.setAll(snap); + } + + @Override + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.putAll(brew.asMap()); + map.putAll(chocolatey.asMap()); + map.putAll(scoop.asMap()); + map.putAll(snap.asMap()); + return map; + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Plug.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Plug.java new file mode 100644 index 00000000..b314e7dc --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Plug.java @@ -0,0 +1,68 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Plug extends AbstractDomain { + private final Map attributes = new LinkedHashMap<>(); + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes.clear(); + this.attributes.putAll(attributes); + } + + public void addAttributes(Map attributes) { + this.attributes.putAll(attributes); + } + + public void addAttribute(String key, String value) { + attributes.put(key, value); + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put(name, attributes); + return map; + } + + public static Plug copyOf(Plug other) { + Plug copy = new Plug(); + copy.setName(other.getName()); + copy.setAttributes(other.getAttributes()); + return copy; + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Project.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Project.java new file mode 100644 index 00000000..ec7472d9 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Project.java @@ -0,0 +1,192 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Project extends AbstractDomain implements ExtraProperties { + private final List authors = new ArrayList<>(); + private final List tags = new ArrayList<>(); + private final Map extraProperties = new LinkedHashMap<>(); + private String name; + private String version; + private String description; + private String longDescription; + private String website; + private String license; + private String javaVersion; + + void setAll(Project project) { + this.name = project.name; + this.version = project.version; + this.description = project.description; + this.longDescription = project.longDescription; + this.website = project.website; + this.license = project.license; + this.javaVersion = project.javaVersion; + setAuthors(project.authors); + setTags(project.tags); + setExtraProperties(project.extraProperties); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLongDescription() { + return longDescription; + } + + public void setLongDescription(String longDescription) { + this.longDescription = longDescription; + } + + public String getWebsite() { + return website; + } + + public void setWebsite(String website) { + this.website = website; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + @Override + public Map getExtraProperties() { + return extraProperties; + } + + @Override + public void setExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + @Override + public void addExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + public List getAuthors() { + return authors; + } + + public void setAuthors(List authors) { + this.authors.clear(); + this.authors.addAll(authors); + } + + public void addAuthors(List authors) { + this.authors.addAll(authors); + } + + public void addAuthor(String author) { + if (isNotBlank(author)) { + this.authors.add(author.trim()); + } + } + + public void removeAuthor(String author) { + if (isNotBlank(author)) { + this.authors.remove(author.trim()); + } + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags.clear(); + this.tags.addAll(tags); + } + + public void addTags(List tags) { + this.tags.addAll(tags); + } + + public void addTag(String tag) { + if (isNotBlank(tag)) { + this.tags.add(tag.trim()); + } + } + + public void removeTag(String tag) { + if (isNotBlank(tag)) { + this.tags.remove(tag.trim()); + } + } + + @Override + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("name", name); + map.put("version", version); + map.put("description", description); + map.put("longDescription", longDescription); + map.put("website", website); + map.put("license", license); + if (isNotBlank(javaVersion)) map.put("javaVersion", javaVersion); + map.put("authors", authors); + map.put("tags", tags); + map.put("extraProperties", extraProperties); + return map; + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Release.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Release.java new file mode 100644 index 00000000..4e4c135b --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Release.java @@ -0,0 +1,296 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Release extends AbstractDomain { + private RepoType repoType; + private String repoHost; + private String repoOwner; + private String repoName; + private String downloadUrlFormat; + private String releaseNotesUrlFormat; + private String latestReleaseUrlFormat; + private String issueTrackerUrlFormat; + private String authorization; + private String tagName; + private String targetCommitish = "main"; + private String releaseName; + private String body = ""; + private boolean draft; + private boolean prerelease; + private boolean overwrite; + private boolean allowUploadToExisting; + private String apiEndpoint; + + void setAll(Release release) { + this.repoType = release.repoType; + this.repoHost = release.repoHost; + this.repoOwner = release.repoOwner; + this.repoName = release.repoName; + this.downloadUrlFormat = release.downloadUrlFormat; + this.releaseNotesUrlFormat = release.releaseNotesUrlFormat; + this.latestReleaseUrlFormat = release.latestReleaseUrlFormat; + this.issueTrackerUrlFormat = release.issueTrackerUrlFormat; + this.authorization = release.authorization; + this.tagName = release.tagName; + this.targetCommitish = release.targetCommitish; + this.releaseName = release.releaseName; + this.body = release.body; + this.draft = release.draft; + this.prerelease = release.prerelease; + this.overwrite = release.overwrite; + this.allowUploadToExisting = release.allowUploadToExisting; + this.apiEndpoint = release.apiEndpoint; + } + + public RepoType getRepoType() { + return repoType; + } + + public void setRepoType(RepoType repoType) { + this.repoType = repoType; + } + + public void setRepoType(String repoType) { + if (isNotBlank(repoType)) { + this.repoType = RepoType.valueOf(repoType.toUpperCase()); + } + } + + public String getRepoHost() { + return repoHost; + } + + public void setRepoHost(String repoHost) { + this.repoHost = repoHost; + } + + public String getRepoOwner() { + return repoOwner; + } + + public void setRepoOwner(String repoOwner) { + this.repoOwner = repoOwner; + } + + public String getRepoName() { + return repoName; + } + + public void setRepoName(String repoName) { + this.repoName = repoName; + } + + public String getDownloadUrlFormat() { + return downloadUrlFormat; + } + + public void setDownloadUrlFormat(String downloadUrlFormat) { + this.downloadUrlFormat = downloadUrlFormat; + } + + public String getReleaseNotesUrlFormat() { + return releaseNotesUrlFormat; + } + + public void setReleaseNotesUrlFormat(String releaseNotesUrlFormat) { + this.releaseNotesUrlFormat = releaseNotesUrlFormat; + } + + public String getLatestReleaseUrlFormat() { + return latestReleaseUrlFormat; + } + + public void setLatestReleaseUrlFormat(String latestReleaseUrlFormat) { + this.latestReleaseUrlFormat = latestReleaseUrlFormat; + } + + public String getIssueTrackerUrlFormat() { + return issueTrackerUrlFormat; + } + + public void setIssueTrackerUrlFormat(String issueTrackerUrlFormat) { + this.issueTrackerUrlFormat = issueTrackerUrlFormat; + } + + public String getAuthorization() { + return authorization; + } + + public void setAuthorization(String authorization) { + this.authorization = authorization; + } + + public String getTagName() { + return tagName; + } + + public void setTagName(String tagName) { + this.tagName = tagName; + } + + public String getTargetCommitish() { + return targetCommitish; + } + + public void setTargetCommitish(String targetCommitish) { + this.targetCommitish = targetCommitish; + } + + public String getReleaseName() { + return releaseName; + } + + public void setReleaseName(String releaseName) { + this.releaseName = releaseName; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public boolean isDraft() { + return draft; + } + + public void setDraft(boolean draft) { + this.draft = draft; + } + + public boolean isPrerelease() { + return prerelease; + } + + public void setPrerelease(boolean prerelease) { + this.prerelease = prerelease; + } + + public boolean isOverwrite() { + return overwrite; + } + + public void setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + } + + public boolean isAllowUploadToExisting() { + return allowUploadToExisting; + } + + public void setAllowUploadToExisting(boolean allowUploadToExisting) { + this.allowUploadToExisting = allowUploadToExisting; + } + + public String getApiEndpoint() { + return apiEndpoint; + } + + public void setApiEndpoint(String apiEndpoint) { + this.apiEndpoint = apiEndpoint; + } + + @Override + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("repoHost", repoHost); + map.put("repoType", repoType); + map.put("repoOwner", repoOwner); + map.put("repoName", repoName); + map.put("downloadUrlFormat", downloadUrlFormat); + map.put("releaseNotesUrlFormat", releaseNotesUrlFormat); + map.put("latestReleaseUrlFormat", latestReleaseUrlFormat); + map.put("issueTrackerUrlFormat", issueTrackerUrlFormat); + map.put("authorization", authorization); + map.put("tagName", tagName); + map.put("targetCommitish", targetCommitish); + map.put("releaseName", releaseName); + map.put("body ", isNotBlank(body)); + map.put("draft", draft); + map.put("prerelease", prerelease); + map.put("overwrite", overwrite); + map.put("allowUploadToExisting", allowUploadToExisting); + map.put("apiEndpoint", apiEndpoint); + return map; + } + + public enum RepoType { + GITHUB("github.com", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/download/v{{projectVersion}}/{{artifactFileName}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/tag/v{{projectVersion}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/latest", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/issues"); + /* + GITLAB("gitlab.com", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/archive/v{{projectVersion}}/{{artifactFileName}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/releases/v{{projectVersion}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/releases/v{{projectVersion}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/issues"); + */ + + private final String repoHost; + private final String downloadUrlFormat; + private final String releaseNotesUrlFormat; + private final String latestReleaseUrlFormat; + private final String issueTrackerUrlFormat; + + RepoType(String repoHost, + String downloadUrlFormat, + String releaseNotesUrlFormat, + String latestReleaseUrlFormat, + String issueTrackerUrlFormat) { + this.repoHost = repoHost; + this.downloadUrlFormat = downloadUrlFormat; + this.releaseNotesUrlFormat = releaseNotesUrlFormat; + this.latestReleaseUrlFormat = latestReleaseUrlFormat; + this.issueTrackerUrlFormat = issueTrackerUrlFormat; + } + + String repoHost() { + return this.repoHost; + } + + String downloadUrlFormat() { + return this.downloadUrlFormat; + } + + String releaseNotesUrlFormat() { + return this.releaseNotesUrlFormat; + } + + String latestReleaseUrlFormat() { + return this.latestReleaseUrlFormat; + } + + String issueTrackerUrlFormat() { + return this.issueTrackerUrlFormat; + } + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Scoop.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Scoop.java new file mode 100644 index 00000000..acea1cd7 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Scoop.java @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Scoop extends AbstractTool { + public static final String TOOL_NAME = "scoop"; + + private String checkverUrl; + private String autoupdateUrl; + + public Scoop() { + super(TOOL_NAME); + } + + void setAll(Scoop scoop) { + super.setAll(scoop); + this.checkverUrl = scoop.checkverUrl; + this.autoupdateUrl = scoop.autoupdateUrl; + } + + public String getCheckverUrl() { + return checkverUrl; + } + + public void setCheckverUrl(String checkverUrl) { + this.checkverUrl = checkverUrl; + } + + public String getAutoupdateUrl() { + return autoupdateUrl; + } + + public void setAutoupdateUrl(String autoupdateUrl) { + this.autoupdateUrl = autoupdateUrl; + } + + @Override + protected void asMap(Map props) { + props.put("checkverUrl", checkverUrl); + props.put("autoupdateUrl", autoupdateUrl); + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Slot.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Slot.java new file mode 100644 index 00000000..54e758f5 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Slot.java @@ -0,0 +1,136 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Slot extends AbstractDomain { + private final Map attributes = new LinkedHashMap<>(); + private final List reads = new ArrayList<>(); + private final List writes = new ArrayList<>(); + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes.clear(); + this.attributes.putAll(attributes); + } + + public void addAttributes(Map attributes) { + this.attributes.putAll(attributes); + } + + public void addAttribute(String key, String value) { + attributes.put(key, value); + } + + public List getReads() { + return reads; + } + + public void setReads(List reads) { + this.reads.clear(); + this.reads.addAll(reads); + } + + public void addReads(List read) { + this.reads.addAll(read); + } + + public void addRead(String read) { + if (isNotBlank(read)) { + this.reads.add(read.trim()); + } + } + + public void removeRead(String read) { + if (isNotBlank(read)) { + this.reads.remove(read.trim()); + } + } + + public List getWrites() { + return writes; + } + + public void setWrites(List writes) { + this.writes.clear(); + this.writes.addAll(writes); + } + + public void addWrites(List write) { + this.writes.addAll(write); + } + + public void addWrite(String write) { + if (isNotBlank(write)) { + this.writes.add(write.trim()); + } + } + + public void removeWrite(String write) { + if (isNotBlank(write)) { + this.writes.remove(write.trim()); + } + } + + public boolean getHasReads() { + return !reads.isEmpty(); + } + + public boolean getHasWrites() { + return !writes.isEmpty(); + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put(name, attributes); + map.put("read", reads); + map.put("write", writes); + return map; + } + + public static Slot copyOf(Slot other) { + Slot copy = new Slot(); + copy.setName(other.getName()); + copy.setAttributes(other.getAttributes()); + copy.setReads(other.getReads()); + copy.setWrites(other.getWrites()); + return copy; + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Snap.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Snap.java new file mode 100644 index 00000000..aea1a51e --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Snap.java @@ -0,0 +1,172 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Snap extends AbstractTool { + public static final String TOOL_NAME = "snap"; + + private final List localPlugs = new ArrayList<>(); + private final List plugs = new ArrayList<>(); + private final List slots = new ArrayList<>(); + private String base = "core18"; + private String grade = "stable"; + private String confinement = "strict"; + private String exportedLogin; + + public Snap() { + super(TOOL_NAME); + } + + void setAll(Snap snap) { + super.setAll(snap); + this.base = snap.base; + this.grade = snap.grade; + this.confinement = snap.confinement; + this.exportedLogin = snap.exportedLogin; + setLocalPlugs(localPlugs); + setPlugs(plugs); + setSlots(slots); + } + + public String getBase() { + return base; + } + + public void setBase(String base) { + this.base = base; + } + + public String getGrade() { + return grade; + } + + public void setGrade(String grade) { + this.grade = grade; + } + + public String getConfinement() { + return confinement; + } + + public void setConfinement(String confinement) { + this.confinement = confinement; + } + + public List getLocalPlugs() { + return localPlugs; + } + + public void setLocalPlugs(List localPlugs) { + this.localPlugs.clear(); + this.localPlugs.addAll(localPlugs); + } + + public void addLocalPlugs(List localPlugs) { + this.localPlugs.addAll(localPlugs); + } + + public void addLocalPlug(String localPlug) { + if (isNotBlank(localPlug)) { + this.localPlugs.add(localPlug.trim()); + } + } + + public void removeLocalPlug(String localPlug) { + if (isNotBlank(localPlug)) { + this.localPlugs.remove(localPlug.trim()); + } + } + + public List getPlugs() { + return plugs; + } + + public void setPlugs(List plugs) { + this.plugs.clear(); + this.plugs.addAll(plugs); + } + + public void addPlugs(List plugs) { + this.plugs.addAll(plugs); + } + + public void addPlug(Plug plug) { + if (null != plug) { + this.plugs.add(plug); + } + } + + public void removePlug(Plug plug) { + if (null != plug) { + this.plugs.remove(plug); + } + } + + public List getSlots() { + return slots; + } + + public void setSlots(List slots) { + this.slots.clear(); + this.slots.addAll(slots); + } + + public void addSlots(List slots) { + this.slots.addAll(slots); + } + + public void addSlot(Slot slot) { + if (null != slot) { + this.slots.add(slot); + } + } + + public void removeSlot(Slot slot) { + if (null != slot) { + this.slots.remove(slot); + } + } + public String getExportedLogin() { + return exportedLogin; + } + + public void setExportedLogin(String exportedLogin) { + this.exportedLogin = exportedLogin; + } + + @Override + protected void asMap(Map props) { + props.put("base", base); + props.put("grade", grade); + props.put("confinement", confinement); + props.put("exportedLogin", exportedLogin); + props.put("localPlugs", localPlugs); + props.put("plugs", plugs); + props.put("slots", slots); + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Tool.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Tool.java new file mode 100644 index 00000000..d7227568 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/Tool.java @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model; + +import java.io.Serializable; +import java.nio.file.Path; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface Tool extends Serializable, ExtraProperties { + boolean isEnabledSet(); + + Boolean isEnabled(); + + void setEnabled(Boolean enabled); + + String getToolName(); + + Path getTemplateDirectory(); + + void setTemplateDirectory(Path templateDirectory); +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/ReleaseException.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/ReleaseException.java new file mode 100644 index 00000000..a57f4b0d --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/ReleaseException.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model.releaser; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ReleaseException extends Exception { + public ReleaseException(String message) { + super(message); + } + + public ReleaseException(String message, Throwable cause) { + super(message, cause); + } + + public ReleaseException(Throwable cause) { + super(cause); + } +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/Releaser.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/Releaser.java new file mode 100644 index 00000000..301cd4c7 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/Releaser.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model.releaser; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface Releaser { + void release() throws ReleaseException; +} diff --git a/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/ReleaserBuilder.java b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/ReleaserBuilder.java new file mode 100644 index 00000000..d40aa757 --- /dev/null +++ b/core/jreleaser-model/src/main/java/org/kordamp/jreleaser/model/releaser/ReleaserBuilder.java @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.model.releaser; + +import org.kordamp.jreleaser.model.JReleaserModel; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface ReleaserBuilder { + R build(); + + R buildFromModel(JReleaserModel model); +} diff --git a/core/jreleaser-model/src/main/module/module-info.java b/core/jreleaser-model/src/main/module/module-info.java new file mode 100644 index 00000000..a7e335cb --- /dev/null +++ b/core/jreleaser-model/src/main/module/module-info.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.model { + exports org.kordamp.jreleaser.model; + requires org.kordamp.jreleaser.util; +} \ No newline at end of file diff --git a/core/jreleaser-releaser/gradle.properties b/core/jreleaser-releaser/gradle.properties new file mode 100644 index 00000000..46430532 --- /dev/null +++ b/core/jreleaser-releaser/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser Releaser \ No newline at end of file diff --git a/core/jreleaser-releaser/jreleaser-releaser.gradle b/core/jreleaser-releaser/jreleaser-releaser.gradle new file mode 100644 index 00000000..aaed5740 --- /dev/null +++ b/core/jreleaser-releaser/jreleaser-releaser.gradle @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-model') + api project(':jreleaser-templates') + api project(':github-java-sdk') +} \ No newline at end of file diff --git a/core/jreleaser-releaser/src/main/java/org/kordamp/jreleaser/releaser/Releasers.java b/core/jreleaser-releaser/src/main/java/org/kordamp/jreleaser/releaser/Releasers.java new file mode 100644 index 00000000..440f4e1e --- /dev/null +++ b/core/jreleaser-releaser/src/main/java/org/kordamp/jreleaser/releaser/Releasers.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.releaser; + +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.releaser.ReleaserBuilder; +import org.kordamp.jreleaser.sdk.github.GithubReleaser; +import org.kordamp.jreleaser.util.Logger; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Releasers { + public static RB findReleaser(Logger logger, JReleaserModel model) { + switch (model.getRelease().getRepoType()) { + case GITHUB: + return (RB) GithubReleaser.builder(); + default: + throw new IllegalArgumentException("Unsupported releaser " + model.getRelease().getRepoType()); + } + } +} diff --git a/core/jreleaser-releaser/src/main/module/module-info.java b/core/jreleaser-releaser/src/main/module/module-info.java new file mode 100644 index 00000000..d03f3d22 --- /dev/null +++ b/core/jreleaser-releaser/src/main/module/module-info.java @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.releaser { + exports org.kordamp.jreleaser.releaser; + requires org.kordamp.jreleaser.model; + requires org.kordamp.jreleaser.util; +} \ No newline at end of file diff --git a/core/jreleaser-templates/gradle.properties b/core/jreleaser-templates/gradle.properties new file mode 100644 index 00000000..8e4d16cb --- /dev/null +++ b/core/jreleaser-templates/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser tool templates \ No newline at end of file diff --git a/core/jreleaser-templates/jreleaser-templates.gradle b/core/jreleaser-templates/jreleaser-templates.gradle new file mode 100644 index 00000000..7f66fd10 --- /dev/null +++ b/core/jreleaser-templates/jreleaser-templates.gradle @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-model') + api "com.github.spullara.mustache.java:compiler:$mustacheVersion" +} \ No newline at end of file diff --git a/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateGenerationException.java b/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateGenerationException.java new file mode 100644 index 00000000..35d3905a --- /dev/null +++ b/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateGenerationException.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.templates; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class TemplateGenerationException extends Exception { + public TemplateGenerationException(String message) { + super(message); + } + + public TemplateGenerationException(String message, Throwable cause) { + super(message, cause); + } + + public TemplateGenerationException(Throwable cause) { + super(cause); + } +} diff --git a/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateGenerator.java b/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateGenerator.java new file mode 100644 index 00000000..641e3686 --- /dev/null +++ b/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateGenerator.java @@ -0,0 +1,179 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.templates; + +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.util.Logger; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.Scanner; + +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.CREATE_NEW; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; +import static java.util.Objects.requireNonNull; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class TemplateGenerator { + private final Logger logger; + private final String distributionName; + private final Distribution.DistributionType distributionType; + private final String toolName; + private final Path outputDirectory; + private final boolean overwrite; + + private TemplateGenerator(Logger logger, + String distributionName, + Distribution.DistributionType distributionType, + String toolName, + Path outputDirectory, + boolean overwrite) { + this.logger = logger; + this.distributionName = distributionName; + this.distributionType = distributionType; + this.toolName = toolName; + this.outputDirectory = outputDirectory; + this.overwrite = overwrite; + } + + public String getDistributionName() { + return distributionName; + } + + public Distribution.DistributionType getDistributionType() { + return distributionType; + } + + public String getToolName() { + return toolName; + } + + public Path getOutputDirectory() { + return outputDirectory; + } + + public boolean isOverwrite() { + return overwrite; + } + + public boolean generate() throws TemplateGenerationException { + if (!Distribution.supportedTools().contains(toolName)) { + logger.error("Tool {} is not supported", toolName); + return false; + } + + Path output = outputDirectory.resolve(distributionName) + .resolve(toolName); + + logger.info("Creating output directory {}", output.toAbsolutePath()); + try { + Files.createDirectories(output); + } catch (IOException e) { + throw fail(e); + } + + Map templates = TemplateUtils.resolveTemplates(logger, distributionType, toolName); + for (Map.Entry template : templates.entrySet()) { + Path outputFile = output.resolve(template.getKey()); + logger.info("Writing file " + outputFile.toAbsolutePath()); + try (Writer writer = Files.newBufferedWriter(outputFile, (overwrite ? CREATE : CREATE_NEW), WRITE, TRUNCATE_EXISTING); + Scanner scanner = new Scanner(template.getValue())) { + while (scanner.hasNextLine()) { + writer.write(scanner.nextLine() + System.lineSeparator()); + } + } catch (FileAlreadyExistsException e) { + logger.error("File {} already exists and overwrite was set to false.", outputFile.toAbsolutePath()); + return false; + } catch (Exception e) { + throw fail(e); + } + } + + return true; + } + + private TemplateGenerationException fail(Exception e) throws TemplateGenerationException { + throw new TemplateGenerationException("Unexpected error when generating template. " + + "distributionType=" + distributionType + + ", distributionName=" + distributionName + + ", toolName=" + toolName, e); + } + + public static TemplateGeneratorBuilder builder() { + return new TemplateGeneratorBuilder(); + } + + public static class TemplateGeneratorBuilder { + private Logger logger; + private String distributionName; + private Distribution.DistributionType distributionType = Distribution.DistributionType.BINARY; + private String toolName; + private Path outputDirectory; + private boolean overwrite; + + public TemplateGeneratorBuilder logger(Logger logger) { + this.logger = requireNonNull(logger, "'logger' must not be null"); + return this; + } + + public TemplateGeneratorBuilder distributionName(String distributionName) { + this.distributionName = requireNonBlank(distributionName, "'distributionName' must not be blank"); + return this; + } + + public TemplateGeneratorBuilder distributionType(Distribution.DistributionType distributionType) { + this.distributionType = requireNonNull(distributionType, "'distributionType' must not be null"); + return this; + } + + public TemplateGeneratorBuilder toolName(String toolName) { + this.toolName = requireNonBlank(toolName, "'toolName' must not be blank"); + return this; + } + + public TemplateGeneratorBuilder outputDirectory(Path outputDirectory) { + this.outputDirectory = requireNonNull(outputDirectory, "'outputDirectory' must not be null"); + return this; + } + + public TemplateGeneratorBuilder overwrite(boolean overwrite) { + this.overwrite = overwrite; + return this; + } + + public TemplateGenerator build() { + requireNonNull(logger, "'logger' must not be null"); + requireNonBlank(distributionName, "'distributionName' must not be blank"); + requireNonNull(distributionType, "'distributionType' must not be null"); + requireNonBlank(toolName, "'toolName' must not be blank"); + requireNonNull(outputDirectory, "'outputDirectory' must not be null"); + return new TemplateGenerator(logger, distributionName, distributionType, toolName, outputDirectory, overwrite); + } + } +} diff --git a/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateUtils.java b/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateUtils.java new file mode 100644 index 00000000..ac31e710 --- /dev/null +++ b/core/jreleaser-templates/src/main/java/org/kordamp/jreleaser/templates/TemplateUtils.java @@ -0,0 +1,189 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.templates; + +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.util.Logger; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public final class TemplateUtils { + private TemplateUtils() { + // noop + } + + public static String trimTplExtension(String str) { + if (str.endsWith(".tpl")) { + return str.substring(0, str.length() - 4); + } + return str; + } + + public static Map resolveAndMergeTemplates(Logger logger, Distribution.DistributionType distributionType, String toolName, Path templateDirectory) { + Map templates = resolveTemplates(logger, distributionType, toolName); + if (null != templateDirectory && templateDirectory.toFile().exists()) { + templates.putAll(resolveTemplates(logger, distributionType, toolName, templateDirectory)); + } + return templates; + } + + public static Map resolveTemplates(Logger logger, Distribution.DistributionType distributionType, String toolName, Path templateDirectory) { + Map templates = new LinkedHashMap<>(); + + try { + Files.walkFileTree(templateDirectory, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + templates.put(templateDirectory.relativize(file).toString(), + Files.newBufferedReader(file)); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + String distributionTypeName = distributionType.name().toLowerCase().replace('_', '-'); + throw new IllegalStateException("Unexpected error reading templates for distribution " + + distributionTypeName + "/" + toolName + " from " + templateDirectory.toAbsolutePath()); + } + + return templates; + } + + public static Map resolveTemplates(Logger logger, Distribution.DistributionType distributionType, String toolName) { + String distributionTypeName = distributionType.name().toLowerCase().replace('_', '-'); + String templatePrefix = "META-INF/jreleaser/templates/" + + distributionTypeName + "/" + toolName.toLowerCase(); + + Map templates = new LinkedHashMap<>(); + + logger.debug("Resolving templates from classpath"); + URL location = resolveLocation(TemplateUtils.class); + if (null == location) { + throw new IllegalStateException("Could not find location of classpath templates"); + } + + try { + if ("file".equals(location.getProtocol())) { + boolean templateFound = false; + JarFile jarFile = new JarFile(new File(location.toURI())); + logger.debug("Searching for templates matching {}/*", templatePrefix); + for (Enumeration e = jarFile.entries(); e.hasMoreElements(); ) { + JarEntry entry = e.nextElement(); + if (entry.isDirectory() || !entry.getName().startsWith(templatePrefix)) { + continue; + } + + String templateName = entry.getName().substring(templatePrefix.length() + 1); + templates.put(templateName, new InputStreamReader(jarFile.getInputStream(entry))); + logger.debug("Found template {}", templateName); + templateFound = true; + } + + if (!templateFound) { + logger.error("Templates for {}/{} were not found", distributionTypeName, toolName); + } + } else { + throw new IllegalStateException("Could not find location of classpath templates"); + } + } catch (URISyntaxException | IOException e) { + throw new IllegalStateException("Unexpected error reading templates for distribution " + + distributionTypeName + "/" + toolName + " from classpath."); + } + + return templates; + } + + public static Reader resolveTemplate(Logger logger, Class anchor, String templateKey) { + logger.debug("Resolving template from classpath for {}@{}", anchor.getName(), templateKey); + URL location = resolveLocation(anchor); + if (null == location) { + throw new IllegalStateException("Could not find location of classpath templates"); + } + + try { + if ("file".equals(location.getProtocol())) { + JarFile jarFile = new JarFile(new File(location.toURI())); + logger.debug("Searching for template matching {}", templateKey); + for (Enumeration e = jarFile.entries(); e.hasMoreElements(); ) { + JarEntry entry = e.nextElement(); + if (entry.isDirectory() || !entry.getName().equals(templateKey)) { + continue; + } + + logger.debug("Found template {}", templateKey); + return new InputStreamReader(jarFile.getInputStream(entry)); + } + throw new IllegalStateException("Template for " + + anchor.getName() + "@" + templateKey + " were not found"); + } else { + throw new IllegalStateException("Could not find location of classpath templates"); + } + } catch (URISyntaxException | IOException e) { + throw new IllegalStateException("Unexpected error reading template for " + + anchor.getName() + "@" + templateKey + " from classpath."); + } + } + + private static URL resolveLocation(Class klass) { + if (klass == null) return null; + + try { + URL codeSourceLocation = klass.getProtectionDomain() + .getCodeSource() + .getLocation(); + if (codeSourceLocation != null) return codeSourceLocation; + } catch (SecurityException | NullPointerException ignored) { + // noop + } + + URL classResource = klass.getResource(klass.getSimpleName() + ".class"); + if (classResource == null) return null; + + String url = classResource.toString(); + String suffix = klass.getCanonicalName().replace('.', '/') + ".class"; + if (!url.endsWith(suffix)) return null; + String path = url.substring(0, url.length() - suffix.length()); + + if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2); + + try { + return new URL(path); + } catch (MalformedURLException ignored) { + return null; + } + } +} diff --git a/core/jreleaser-templates/src/main/module/module-info.java b/core/jreleaser-templates/src/main/module/module-info.java new file mode 100644 index 00000000..10a48fd4 --- /dev/null +++ b/core/jreleaser-templates/src/main/module/module-info.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.templates { + exports org.kordamp.jreleaser.templates; + requires org.kordamp.jreleaser.model; + requires org.kordamp.jreleaser.util; + requires com.github.mustachejava; +} \ No newline at end of file diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/brew/formula.rb.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/brew/formula.rb.tpl new file mode 100644 index 00000000..cd18454a --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/brew/formula.rb.tpl @@ -0,0 +1,23 @@ +class {{projectNameCapitalized}} < Formula + desc "{{projectDescription}}" + homepage "{{projectWebsite}}" + url "{{distributionUrl}}" + sha256 "{{distributionSha256}}" + license "{{projectLicense}}" + + bottle :unneeded + + {{#brewDependencies}} + depends_on {{formattedDependency}} + {{/brewDependencies}} + + def install + libexec.install Dir["*"] + bin.install_symlink "#{libexec}/bin/{{distributionExecutable}}" + end + + test do + output = shell_output("#{bin}/{{distributionExecutable}} --version") + assert_match "{{projectVersion}}", output + end +end diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/binary.nuspec b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/binary.nuspec new file mode 100644 index 00000000..5a909c9e --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/binary.nuspec @@ -0,0 +1,22 @@ + + + + + + {{distributionName}} + {{projectVersion}} + {{projectAuthorsByComma}} + {{projectLongDescription}} + + {{projectName}} + {{projectWebsite}} + {{projectLicense}} + false + {{distributionTagsBySpace}} + {{projectDescription}} + {{distributionReleaseNotes}} + + + + + diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/tools/chocolateyinstall.ps1 b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/tools/chocolateyinstall.ps1 new file mode 100644 index 00000000..fb1a69c9 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/tools/chocolateyinstall.ps1 @@ -0,0 +1,13 @@ +$tools = Split-Path $MyInvocation.MyCommand.Definition +$package = Split-Path $tools +$app_home = Join-Path $package '{{projectName}}-{{projectVersion}}' +$app_bat = Join-Path $app_home 'bin/{{distributionExecutable}}.cmd' + +Install-ChocolateyZipPackage ` + -PackageName '{{distributionName}}' ` + -Url '{{distributionUrl}}' ` + -Checksum '{{distributionSha256}}' ` + -ChecksumType 'sha256' ` + -UnzipLocation $package + +Install-BinFile -Name '{{distributionExecutable}}' -Path $app_bat \ No newline at end of file diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/tools/chocolateyuninstall.ps1 b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/tools/chocolateyuninstall.ps1 new file mode 100644 index 00000000..67d06958 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/chocolatey/tools/chocolateyuninstall.ps1 @@ -0,0 +1,6 @@ +$tools = Split-Path $MyInvocation.MyCommand.Definition +$package = Split-Path $tools +$app_home = Join-Path $package '{{projectName}}-{{projectVersion}}' +$app_bat = Join-Path $app_home 'bin/{{distributionExecutable}}.cmd' + +Uninstall-BinFile -Name '{{distributionExecutable}}' -Path $app_bat diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/scoop/manifest.json.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/scoop/manifest.json.tpl new file mode 100644 index 00000000..8d5c2941 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/scoop/manifest.json.tpl @@ -0,0 +1,27 @@ +{ + "homepage": "{{projectWebsite}}", + "description": "{{projectDescription}}", + "version": "{{projectVersion}}", + "license": "{{projectLicense}}", + "url": "{{distributionUrl}}", + "hash": "sha256:{{distributionSha256}}", + "extract_dir": "{{projectName}}-{{projectVersion}}", + "env_add_path": "bin", + "suggest": { + "JDK": [ + "java/oraclejdk", + "java/openjdk" + ] + }, + "checkver": { + "url": "{{scoopCheckverUrl}}", + "re": "v([\\d.]+).zip" + }, + "autoupdate": { + "url": "{{scoopAutoupdateUrl}}", + "extract_dir": "{{projectName}}-$version", + "hash": { + "url": "$url.sha256" + } + } +} \ No newline at end of file diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/snap/snap/snapcraft.yaml.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/snap/snap/snapcraft.yaml.tpl new file mode 100644 index 00000000..7eb77b23 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/snap/snap/snapcraft.yaml.tpl @@ -0,0 +1,61 @@ +name: {{distributionName}} +base: {{snapBase}} +version: {{projectVersion}} +license: {{projectLicense}} +grade: {{snapGrade}} +type: app +confinement: {{snapConfinement}} +summary: {{projectDescription}} +description: {{projectLongDescription}} + +apps: + {{distributionExecutable}}: + command: bin/{{distributionExecutable}} + environment: + JAVA_HOME: $SNAP/usr/lib/jvm/java + +{{#snapHasPlugs}} +plugs: + {{#snapPlugs}} + {{name}}: + {{#attributes}} + {{key}}: {{value}} + {{/attributes}} + {{/snapPlugs}} +{{/snapHasPlugs}} +{{#snapHasSlots}} +slots: + {{#snapSlots}} + {{name}}: + {{#attributes}} + {{key}}: {{value}} + {{/attributes}} + {{#hasReads}} + reads: + {{#reads}} + - {{.}} + {{/reads}} + {{/hasReads}} + {{#hasWrites}} + writes: + {{#writes}} + - {{.}} + {{/writes}} + {{/hasWrites}} + {{/snapSlots }} +{{/snapHasSlots}} +parts: + {{distributionExecutable}}: + plugin: dump + source: {{distributionUrl}} + source-checksum: sha256/{{distributionSha256}} + stage-packages: + - openjdk-{{javaVersion}}-jdk + organize: + usr/lib/jvm/java-{{javaVersion}}-openjdk*: usr/lib/jvm/java + {{#snapHasLocalPlugs}} + plugs: + {{#snapLocalPlugs}} + - {{.}} + {{/snapLocalPlugs}} + {{/snapHasLocalPlugs}} \ No newline at end of file diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/scripts/executable.bat.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/scripts/executable.bat.tpl new file mode 100644 index 00000000..19176db9 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/scripts/executable.bat.tpl @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem {{distributionExecutable}} startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME%.. + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-jar {{artifactFileName}}" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH= + +@rem Execute {{distributionExecutable}} +"%JAVA_EXE%" %JAVA_OPTS% %DEFAULT_JVM_OPTS% %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable APP_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%APP_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/scripts/executable.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/scripts/executable.tpl new file mode 100755 index 00000000..44071fd0 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/scripts/executable.tpl @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## {{distributionExecutable}} start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/.." >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="{{distributionExecutable}}" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-jar {{artifactFileName}}"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH= + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $JAVA_OPTS $DEFAULT_JVM_OPTS "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/single-jar/snap/snap/snapcraft.yaml.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/single-jar/snap/snap/snapcraft.yaml.tpl new file mode 100644 index 00000000..a48b4a96 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/single-jar/snap/snap/snapcraft.yaml.tpl @@ -0,0 +1,62 @@ +name: {{distributionName}} +base: {{snapBase}} +version: {{projectVersion}} +license: {{projectLicense}} +grade: {{snapGrade}} +type: app +confinement: {{snapConfinement}} +summary: {{projectDescription}} +description: {{projectLongDescription}} + +apps: + {{distributionExecutable}}: + command: ${JAVA_HOME}/bin/java -jar $SNAP/{{distributionFileName}} + environment: + JAVA_HOME: $SNAP/usr/lib/jvm/java + +{{#snapHasPlugs}} +plugs: + {{#snapPlugs}} + {{name}}: + {{#attributes}} + {{key}}: {{value}} + {{/attributes}} + {{/snapPlugs}} +{{/snapHasPlugs}} +{{#snapHasSlots}} +slots: + {{#snapSlots}} + {{name}}: + {{#attributes}} + {{key}}: {{value}} + {{/attributes}} + {{#hasReads}} + reads: + {{#reads}} + - {{.}} + {{/reads}} + {{/hasReads}} + {{#hasWrites}} + writes: + {{#writes}} + - {{.}} + {{/writes}} + {{/hasWrites}} + {{/snapSlots }} +{{/snapHasSlots}} + +parts: + {{distributionExecutable}}: + plugin: nil + source: {{distributionUrl}} + source-checksum: sha256/{{distributionSha256}} + stage-packages: + - openjdk-{{javaVersion}}-jdk + organize: + usr/lib/jvm/java-{{javaVersion}}-openjdk*: usr/lib/jvm/java + {{#snapHasLocalPlugs}} + plugs: + {{#snapLocalPlugs}} + - {{.}} + {{/snapLocalPlugs}} + {{/snapHasLocalPlugs}} \ No newline at end of file diff --git a/core/jreleaser-tools/gradle.properties b/core/jreleaser-tools/gradle.properties new file mode 100644 index 00000000..6449a233 --- /dev/null +++ b/core/jreleaser-tools/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser Execution \ No newline at end of file diff --git a/core/jreleaser-tools/jreleaser-tools.gradle b/core/jreleaser-tools/jreleaser-tools.gradle new file mode 100644 index 00000000..80d4ac1b --- /dev/null +++ b/core/jreleaser-tools/jreleaser-tools.gradle @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-model') + api project(':jreleaser-templates') + api "com.github.spullara.mustache.java:compiler:$mustacheVersion" + api "org.zeroturnaround:zt-exec:$ztexecVersion" +} \ No newline at end of file diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/AbstractToolProcessor.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/AbstractToolProcessor.java new file mode 100644 index 00000000..4646d03c --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/AbstractToolProcessor.java @@ -0,0 +1,281 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Artifact; +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Project; +import org.kordamp.jreleaser.model.Release; +import org.kordamp.jreleaser.model.Tool; +import org.kordamp.jreleaser.util.Logger; +import org.zeroturnaround.exec.ProcessExecutor; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; +import static org.kordamp.jreleaser.templates.TemplateUtils.resolveAndMergeTemplates; +import static org.kordamp.jreleaser.tools.ProcessorUtils.applyTemplate; +import static org.kordamp.jreleaser.util.FileUtils.createDirectoriesWithFullAccess; +import static org.kordamp.jreleaser.util.FileUtils.grantFullAccess; +import static org.kordamp.jreleaser.util.StringUtils.capitalize; +import static org.kordamp.jreleaser.util.StringUtils.getClassNameForLowerCaseHyphenSeparatedName; +import static org.kordamp.jreleaser.util.StringUtils.isBlank; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractToolProcessor implements ToolProcessor { + private final Logger logger; + private final JReleaserModel model; + private final T tool; + + protected AbstractToolProcessor(Logger logger, JReleaserModel model, T tool) { + this.logger = logger; + this.model = model; + this.tool = tool; + } + + @Override + public T getTool() { + return tool; + } + + @Override + public String getToolName() { + return tool.getToolName(); + } + + @Override + public Logger getLogger() { + return logger; + } + + @Override + public JReleaserModel getModel() { + return model; + } + + @Override + public boolean prepareDistribution(Distribution distribution, Map context) throws ToolProcessingException { + Tool tool = distribution.getTool(getToolName()); + + try { + String distributionName = distribution.getName(); + getLogger().debug("Creating context for {}/{}", distributionName, getToolName()); + Map newContext = fillContext(distribution, context); + if (newContext.isEmpty()) { + logger.warn("Skipping {} tool for {} distribution", getToolName(), distributionName); + return false; + } + getLogger().debug("Resolving templates for {}/{}", distributionName, getToolName()); + Map templates = resolveAndMergeTemplates(logger, distribution.getType(), getToolName(), tool.getTemplateDirectory()); + for (Map.Entry entry : templates.entrySet()) { + getLogger().debug("Evaluating template {} for {}/{}", entry.getKey(), distributionName, getToolName()); + String content = applyTemplate(entry.getValue(), newContext); + getLogger().debug("Writing template {} for {}/{}", entry.getKey(), distributionName, getToolName()); + writeFile(model.getProject(), distribution, content, context, entry.getKey()); + } + } catch (IllegalArgumentException e) { + throw new ToolProcessingException(e); + } + + return true; + } + + @Override + public boolean packageDistribution(Distribution distribution, Map context) throws ToolProcessingException { + try { + String distributionName = distribution.getName(); + getLogger().debug("Creating context for {}/{}", distributionName, getToolName()); + Map newContext = fillContext(distribution, context); + if (newContext.isEmpty()) { + logger.warn("Skipping {} tool for {} distribution", getToolName(), distributionName); + return false; + } + return doPackageDistribution(distribution, newContext); + } catch (IllegalArgumentException e) { + throw new ToolProcessingException(e); + } + } + + protected abstract boolean doPackageDistribution(Distribution distribution, Map context) throws ToolProcessingException; + + protected abstract void writeFile(Project project, Distribution distribution, String content, Map context, String fileName) throws ToolProcessingException; + + protected void writeFile(String content, Path outputFile) throws ToolProcessingException { + try { + createDirectoriesWithFullAccess(outputFile.getParent()); + Files.write(outputFile, content.getBytes(), CREATE, WRITE, TRUNCATE_EXISTING); + grantFullAccess(outputFile); + } catch (IOException e) { + throw new ToolProcessingException("Unexpected error when writing to " + outputFile.toAbsolutePath(), e); + } + } + + protected Map fillContext(Distribution distribution, Map context) throws ToolProcessingException { + Map newContext = new LinkedHashMap<>(context); + getLogger().debug("Filling project properties into context"); + fillProjectProperties(newContext, model.getProject()); + getLogger().debug("Filling release properties into context"); + fillReleaseProperties(newContext, model.getRelease()); + getLogger().debug("Filling distribution properties into context"); + fillDistributionProperties(newContext, distribution, model.getRelease()); + getLogger().debug("Filling artifact properties into context"); + if (!verifyAndAddArtifacts(newContext, distribution)) { + // we can't continue with this tool + return Collections.emptyMap(); + } + getLogger().debug("Filling tool properties into context"); + fillToolProperties(newContext, distribution); + newContext.putAll(tool.getExtraProperties()); + return newContext; + } + + protected void fillProjectProperties(Map context, Project project) { + context.put(Constants.KEY_PROJECT_NAME, project.getName()); + context.put(Constants.KEY_PROJECT_NAME_CAPITALIZED, getClassNameForLowerCaseHyphenSeparatedName(project.getName())); + context.put(Constants.KEY_PROJECT_VERSION, project.getVersion()); + context.put(Constants.KEY_PROJECT_DESCRIPTION, project.getDescription()); + context.put(Constants.KEY_PROJECT_LONG_DESCRIPTION, project.getLongDescription()); + context.put(Constants.KEY_PROJECT_WEBSITE, project.getWebsite()); + context.put(Constants.KEY_PROJECT_LICENSE, project.getLicense()); + context.put(Constants.KEY_JAVA_VERSION, project.getJavaVersion()); + context.put(Constants.KEY_PROJECT_AUTHORS_BY_SPACE, String.join(" ", project.getAuthors())); + context.put(Constants.KEY_PROJECT_AUTHORS_BY_COMMA, String.join(",", project.getAuthors())); + context.put(Constants.KEY_PROJECT_TAGS_BY_SPACE, String.join(" ", project.getTags())); + context.put(Constants.KEY_PROJECT_TAGS_BY_COMMA, String.join(",", project.getTags())); + context.putAll(project.getExtraProperties()); + } + + protected void fillReleaseProperties(Map context, Release release) { + context.put(Constants.KEY_REPO_HOST, release.getRepoHost()); + context.put(Constants.KEY_REPO_OWNER, release.getRepoOwner()); + context.put(Constants.KEY_REPO_NAME, release.getRepoName()); + } + + protected void fillDistributionProperties(Map context, Distribution distribution, Release release) { + context.put(Constants.KEY_DISTRIBUTION_NAME, distribution.getName()); + context.put(Constants.KEY_DISTRIBUTION_EXECUTABLE, distribution.getExecutable()); + context.put(Constants.KEY_DISTRIBUTION_TAGS_BY_SPACE, String.join(" ", distribution.getTags())); + context.put(Constants.KEY_DISTRIBUTION_TAGS_BY_COMMA, String.join(",", distribution.getTags())); + context.put(Constants.KEY_DISTRIBUTION_RELEASE_NOTES, applyTemplate(new StringReader(release.getReleaseNotesUrlFormat()), context)); + context.put(Constants.KEY_DISTRIBUTION_ISSUE_TRACKER, applyTemplate(new StringReader(release.getIssueTrackerUrlFormat()), context)); + context.put(Constants.KEY_DISTRIBUTION_LATEST_RELEASE, applyTemplate(new StringReader(release.getLatestReleaseUrlFormat()), context)); + context.putAll(distribution.getExtraProperties()); + } + + protected abstract void fillToolProperties(Map context, Distribution distribution) throws ToolProcessingException; + + protected boolean executeCommand(List cmd) throws ToolProcessingException { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + + int exitValue = new ProcessExecutor(cmd) + .redirectOutput(out) + .redirectError(err) + .execute() + .getExitValue(); + + info(out); + error(err); + + if (exitValue == 0) return true; + throw new ToolProcessingException("Command execution error. exitValue = " + exitValue); + } catch (Exception e) { + if (e instanceof ToolProcessingException) { + throw (ToolProcessingException) e; + } + throw new ToolProcessingException("Unexpected error", e); + } + } + + private boolean verifyAndAddArtifacts(Map context, + Distribution distribution) throws ToolProcessingException { + Set fileExtensions = resolveByExtensionsFor(distribution.getType()); + List artifacts = distribution.getArtifacts().stream() + .filter(artifact -> fileExtensions.stream().anyMatch(ext -> artifact.getPath().endsWith(ext))) + .collect(Collectors.toList()); + + if (artifacts.size() == 0) { + // we can't proceed + logger.warn("No suitable artifacts found in distribution {} to be packaged with {}", + distribution.getName(), capitalize(tool.getToolName())); + return false; + } + + for (int i = 0; i < artifacts.size(); i++) { + Artifact artifact = artifacts.get(i); + String classifier = isNotBlank(artifact.getOsClassifier()) ? capitalize(artifact.getOsClassifier()) : ""; + String artifactFileName = Paths.get(artifact.getPath()).getFileName().toString(); + context.put("artifact" + classifier + "JavaVersion", artifact.getJavaVersion()); + context.put("artifact" + classifier + "FileName", artifactFileName); + context.put("artifact" + classifier + "Hash", artifact.getHash()); + Map newContext = new LinkedHashMap<>(context); + newContext.put("artifactFileName", artifactFileName); + String artifactUrl = applyTemplate(new StringReader(model.getRelease().getDownloadUrlFormat()), newContext, "downloadUrl"); + context.put("artifact" + classifier + "Url", artifactUrl); + + if (0 == i) { + context.put(Constants.KEY_DISTRIBUTION_URL, artifactUrl); + context.put(Constants.KEY_DISTRIBUTION_SHA_256, artifact.getHash()); + context.put(Constants.KEY_DISTRIBUTION_JAVA_VERSION, artifact.getJavaVersion()); + context.put(Constants.KEY_DISTRIBUTION_FILE_NAME, artifactFileName); + } + } + + return true; + } + + protected abstract Set resolveByExtensionsFor(Distribution.DistributionType type); + + protected void info(ByteArrayOutputStream out) { + log(out, logger::info); + } + + protected void error(ByteArrayOutputStream err) { + log(err, logger::error); + } + + private void log(ByteArrayOutputStream stream, Consumer consumer) { + String str = stream.toString(); + if (isBlank(str)) return; + + Arrays.stream(str.split(System.lineSeparator())) + .forEach(consumer); + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/BrewToolProcessor.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/BrewToolProcessor.java new file mode 100644 index 00000000..150f3c64 --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/BrewToolProcessor.java @@ -0,0 +1,108 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Brew; +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Project; +import org.kordamp.jreleaser.util.Logger; + +import java.nio.file.Path; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.kordamp.jreleaser.templates.TemplateUtils.trimTplExtension; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class BrewToolProcessor extends AbstractToolProcessor { + public BrewToolProcessor(Logger logger, JReleaserModel model, Brew brew) { + super(logger, model, brew); + } + + @Override + protected boolean doPackageDistribution(Distribution distribution, Map context) throws ToolProcessingException { + getLogger().debug("Tool {} does not require additional packaging", getToolName()); + return true; + } + + @Override + protected Set resolveByExtensionsFor(Distribution.DistributionType type) { + Set set = new LinkedHashSet<>(); + set.add(".zip"); + return set; + } + + @Override + protected void fillToolProperties(Map context, Distribution distribution) throws ToolProcessingException { + if (!getTool().getDependencies().containsKey(Constants.KEY_JAVA_VERSION)) { + getTool().getDependencies().put(":java", (String) context.get(Constants.KEY_DISTRIBUTION_JAVA_VERSION)); + } + + context.put(Constants.KEY_BREW_DEPENDENCIES, getTool().getDependencies() + .entrySet().stream() + .map(entry -> new Dependency(entry.getKey(), entry.getValue())) + .collect(Collectors.toList())); + } + + @Override + protected void writeFile(Project project, Distribution distribution, String content, Map context, String fileName) + throws ToolProcessingException { + fileName = trimTplExtension(fileName); + + Path outputDirectory = (Path) context.get(Constants.KEY_PREPARE_DIRECTORY); + Path outputFile = "formula.rb".equals(fileName) ? + outputDirectory.resolve("Formula").resolve(distribution.getExecutable().concat(".rb")) : + outputDirectory.resolve(fileName); + + writeFile(content, outputFile); + } + + public static class Dependency { + private final String key; + private final String value; + + public Dependency(String key, String value) { + this.key = key; + this.value = value; + } + + public String getFormattedDependency() { + StringBuilder formatted = new StringBuilder(); + if (key.startsWith(":")) { + formatted.append(key); + } else { + formatted.append("\"") + .append(key) + .append("\""); + } + if (isNotBlank(value)) { + formatted.append(" => \"") + .append(value) + .append("\""); + } + return "!!" + formatted.toString() + "!!"; + } + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ChocolateyToolProcessor.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ChocolateyToolProcessor.java new file mode 100644 index 00000000..d276d28b --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ChocolateyToolProcessor.java @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Chocolatey; +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Project; +import org.kordamp.jreleaser.util.Logger; +import org.kordamp.jreleaser.util.OsUtils; + +import java.nio.file.Path; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import static org.kordamp.jreleaser.templates.TemplateUtils.trimTplExtension; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ChocolateyToolProcessor extends AbstractToolProcessor { + public ChocolateyToolProcessor(Logger logger, JReleaserModel model, Chocolatey tool) { + super(logger, model, tool); + } + + @Override + protected boolean doPackageDistribution(Distribution distribution, Map context) throws ToolProcessingException { + if (!OsUtils.isWindows()) { + getLogger().debug("Tool {} must run on Windows", getToolName()); + return false; + } + + return true; + } + + @Override + protected Set resolveByExtensionsFor(Distribution.DistributionType type) { + Set set = new LinkedHashSet<>(); + set.add(".zip"); + return set; + } + + @Override + protected void fillToolProperties(Map context, Distribution distribution) throws ToolProcessingException { + // noop + } + + @Override + protected void writeFile(Project project, Distribution distribution, String content, Map context, String fileName) + throws ToolProcessingException { + fileName = trimTplExtension(fileName); + + Path outputDirectory = (Path) context.get(Constants.KEY_PREPARE_DIRECTORY); + Path outputFile = "binary.nuspec".equals(fileName) ? + outputDirectory.resolve(distribution.getExecutable().concat(".nuspec")) : + outputDirectory.resolve(fileName); + + writeFile(content, outputFile); + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/Constants.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/Constants.java new file mode 100644 index 00000000..ccc7d351 --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/Constants.java @@ -0,0 +1,85 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface Constants { + // General + String KEY_JAVA_VERSION = "javaVersion"; + + // Project + String KEY_PROJECT_NAME = "projectName"; + String KEY_PROJECT_NAME_CAPITALIZED = "projectNameCapitalized"; + String KEY_PROJECT_VERSION = "projectVersion"; + String KEY_PROJECT_DESCRIPTION = "projectDescription"; + String KEY_PROJECT_LONG_DESCRIPTION = "projectLongDescription"; + String KEY_PROJECT_WEBSITE = "projectWebsite"; + String KEY_PROJECT_LICENSE = "projectLicense"; + String KEY_PROJECT_AUTHORS_BY_SPACE = "projectAuthorsBySpace"; + String KEY_PROJECT_AUTHORS_BY_COMMA = "projectAuthorsByComma"; + String KEY_PROJECT_TAGS_BY_SPACE = "projectTagsBySpace"; + String KEY_PROJECT_TAGS_BY_COMMA = "projectTagsByComma"; + + // Release + String KEY_REPO_HOST = "repoHost"; + String KEY_REPO_OWNER = "repoOwner"; + String KEY_REPO_NAME = "repoName"; + + // Distribution + String KEY_DISTRIBUTION_NAME = "distributionName"; + String KEY_DISTRIBUTION_EXECUTABLE = "distributionExecutable"; + String KEY_DISTRIBUTION_TAGS_BY_SPACE = "distributionTagsBySpace"; + String KEY_DISTRIBUTION_TAGS_BY_COMMA = "distributionTagsByComma"; + String KEY_DISTRIBUTION_RELEASE_NOTES = "distributionReleaseNotes"; + String KEY_DISTRIBUTION_ISSUE_TRACKER = "distributionIssueTracker"; + String KEY_DISTRIBUTION_LATEST_RELEASE = "distributionLatestRelease"; + String KEY_DISTRIBUTION_JAVA_VERSION = "distributionJavaVersion"; + String KEY_DISTRIBUTION_URL = "distributionUrl"; + String KEY_DISTRIBUTION_SHA_256 = "distributionSha256"; + String KEY_DISTRIBUTION_FILE_NAME = "distributionFileName"; + + // Artifact + String KEY_ARTIFACT_FILE_NAME = "artifactFileName"; + + // Brew + String KEY_BREW_DEPENDENCIES = "brewDependencies"; + + // Scoop + String KEY_SCOOP_CHECKVER_URL = "scoopCheckverUrl"; + String KEY_SCOOP_AUTOUPDATE_URL = "scoopAutoupdateUrl"; + + // Snap + String KEY_SNAP_BASE = "snapBase"; + String KEY_SNAP_GRADE = "snapGrade"; + String KEY_SNAP_CONFINEMENT = "snapConfinement"; + String KEY_SNAP_HAS_PLUGS = "snapHasPlugs"; + String KEY_SNAP_PLUGS = "snapPlugs"; + String KEY_SNAP_HAS_SLOTS = "snapHasSlots"; + String KEY_SNAP_SLOTS = "snapSlots"; + String KEY_SNAP_HAS_LOCAL_PLUGS = "snapHasLocalPlugs"; + String KEY_SNAP_LOCAL_PLUGS = "snapLocalPlugs"; + + // ToolProcessor + String KEY_CHECKSUM_DIRECTORY = "__CHECKSUM_DIRECTORY__"; + String KEY_OUTPUT_DIRECTORY = "__OUTPUT_DIRECTORY__"; + String KEY_PREPARE_DIRECTORY = "__PREPARE_DIRECTORY__"; + String KEY_PACKAGE_DIRECTORY = "__PACKAGE_DIRECTORY__"; +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/DistributionProcessor.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/DistributionProcessor.java new file mode 100644 index 00000000..30165787 --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/DistributionProcessor.java @@ -0,0 +1,198 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Artifact; +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Tool; +import org.kordamp.jreleaser.util.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedHashMap; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class DistributionProcessor { + private final Logger logger; + private final JReleaserModel model; + private final String distributionName; + private final String toolName; + private final Path checksumDirectory; + private final Path outputDirectory; + + private DistributionProcessor(Logger logger, + JReleaserModel model, + String distributionName, + String toolName, + Path checksumDirectory, + Path outputDirectory) { + this.logger = logger; + this.model = model; + this.distributionName = distributionName; + this.toolName = toolName; + this.checksumDirectory = checksumDirectory; + this.outputDirectory = outputDirectory; + } + + public JReleaserModel getModel() { + return model; + } + + public String getDistributionName() { + return distributionName; + } + + public String getToolName() { + return toolName; + } + + public Path getChecksumDirectory() { + return checksumDirectory; + } + + public Path getOutputDirectory() { + return outputDirectory; + } + + public boolean prepareDistribution() throws ToolProcessingException { + Distribution distribution = model.findDistribution(distributionName); + Tool tool = distribution.getTool(toolName); + if (!tool.isEnabled()) { + logger.warn("Skipping {} tool for {} distribution", toolName, distributionName); + return false; + } + + logger.info("Preparing {} distribution with tool {}", distributionName, toolName); + + Map context = new LinkedHashMap<>(); + context.put(Constants.KEY_CHECKSUM_DIRECTORY, checksumDirectory); + context.put(Constants.KEY_OUTPUT_DIRECTORY, outputDirectory); + context.put(Constants.KEY_PREPARE_DIRECTORY, outputDirectory.resolve("prepare")); + + logger.debug("Reading checksums for {} distribution", distributionName); + for (int i = 0; i < distribution.getArtifacts().size(); i++) { + Artifact artifact = distribution.getArtifacts().get(i); + readHash(artifact, checksumDirectory); + } + + ToolProcessor toolProcessor = ToolProcessors.findProcessor(logger, model, tool); + return toolProcessor.prepareDistribution(distribution, context); + } + + public boolean packageDistribution() throws ToolProcessingException { + Distribution distribution = model.findDistribution(distributionName); + Tool tool = distribution.getTool(toolName); + if (!tool.isEnabled()) { + logger.warn("Skipping {} tool for {} distribution", toolName, distributionName); + return false; + } + + logger.info("Packaging {} distribution with tool {}", distributionName, toolName); + + Map context = new LinkedHashMap<>(); + context.put(Constants.KEY_OUTPUT_DIRECTORY, outputDirectory); + context.put(Constants.KEY_PREPARE_DIRECTORY, outputDirectory.resolve("prepare")); + context.put(Constants.KEY_PACKAGE_DIRECTORY, outputDirectory.resolve("package")); + + ToolProcessor toolProcessor = ToolProcessors.findProcessor(logger, model, tool); + return toolProcessor.packageDistribution(distribution, context); + } + + private void readHash(Artifact artifact, Path checksumDirectory) throws ToolProcessingException { + Path artifactPath = Paths.get(artifact.getPath()); + Path checksumPath = checksumDirectory.resolve(artifactPath.getFileName() + ".sha256"); + + if (!artifactPath.toFile().exists()) { + throw new ToolProcessingException("Artifact does not exist. " + artifactPath.toAbsolutePath()); + } + + if (!checksumPath.toFile().exists()) { + throw new ToolProcessingException("Artifact checksum does not exist. " + checksumPath.toAbsolutePath()); + } + + try { + logger.debug("Reading checksum for {} from {}", artifactPath.toAbsolutePath(), checksumPath.toAbsolutePath()); + artifact.setHash(new String(Files.readAllBytes(checksumPath))); + } catch (IOException e) { + throw new ToolProcessingException("Unexpected error when reading hash from " + checksumPath.toAbsolutePath(), e); + } + } + + public static DistributionProcessorBuilder builder() { + return new DistributionProcessorBuilder(); + } + + public static class DistributionProcessorBuilder { + private Logger logger; + private JReleaserModel model; + private String distributionName; + private String toolName; + private Path checksumDirectory; + private Path outputDirectory; + + public DistributionProcessorBuilder logger(Logger logger) { + this.logger = requireNonNull(logger, "'logger' must not be null"); + return this; + } + + public DistributionProcessorBuilder model(JReleaserModel model) { + this.model = requireNonNull(model, "'model' must not be null"); + return this; + } + + public DistributionProcessorBuilder distributionName(String distributionName) { + this.distributionName = requireNonBlank(distributionName, "'distributionName' must not be blank"); + return this; + } + + public DistributionProcessorBuilder toolName(String toolName) { + this.toolName = requireNonBlank(toolName, "'toolName' must not be blank"); + return this; + } + + public DistributionProcessorBuilder checksumDirectory(Path checksumDirectory) { + this.checksumDirectory = requireNonNull(checksumDirectory, "'checksumDirectory' must not be null"); + return this; + } + + public DistributionProcessorBuilder outputDirectory(Path outputDirectory) { + this.outputDirectory = requireNonNull(outputDirectory, "'outputDirectory' must not be null"); + return this; + } + + public DistributionProcessor build() { + requireNonNull(logger, "'logger' must not be null"); + requireNonNull(model, "'model' must not be null"); + requireNonBlank(distributionName, "'distributionName' must not be blank"); + requireNonBlank(toolName, "'toolName' must not be blank"); + requireNonNull(checksumDirectory, "'checksumDirectory' must not be null"); + requireNonNull(outputDirectory, "'outputDirectory' must not be null"); + return new DistributionProcessor(logger, model, distributionName, toolName, checksumDirectory, outputDirectory); + } + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ProcessorUtils.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ProcessorUtils.java new file mode 100644 index 00000000..222b592f --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ProcessorUtils.java @@ -0,0 +1,120 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import com.github.mustachejava.DefaultMustacheFactory; +import com.github.mustachejava.Mustache; +import com.github.mustachejava.MustacheException; +import com.github.mustachejava.MustacheFactory; +import org.kordamp.jreleaser.model.Artifact; +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Tool; +import org.kordamp.jreleaser.util.Logger; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.file.Paths; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.kordamp.jreleaser.util.StringUtils.capitalize; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +final class ProcessorUtils { + private ProcessorUtils() { + //noop + } + + static boolean verifyAndAddArtifacts(Logger logger, + Map context, + JReleaserModel model, + Distribution distribution, + String artifactExtension, + T tool) throws ToolProcessingException { + List artifacts = distribution.getArtifacts().stream() + .filter(artifact -> artifact.getPath().endsWith(artifactExtension)) + .collect(Collectors.toList()); + + if (artifacts.size() == 0) { + // we can't proceed + logger.warn("No suitable {} artifacts found in distribution {} to be packaged with ", + artifactExtension, distribution.getName(), capitalize(tool.getToolName())); + return false; + } + + for (int i = 0; i < artifacts.size(); i++) { + Artifact artifact = artifacts.get(i); + String classifier = isNotBlank(artifact.getOsClassifier()) ? capitalize(artifact.getOsClassifier()) : ""; + String artifactFileName = Paths.get(artifact.getPath()).getFileName().toString(); + context.put("artifact" + classifier + "JavaVersion", artifact.getJavaVersion()); + context.put("artifact" + classifier + "FileName", artifactFileName); + context.put("artifact" + classifier + "Hash", artifact.getHash()); + Map newContext = new LinkedHashMap<>(context); + newContext.put("artifactFileName", artifactFileName); + String artifactUrl = applyTemplate(new StringReader(model.getRelease().getDownloadUrlFormat()), newContext, "downloadUrl"); + context.put("artifact" + classifier + "Url", artifactUrl); + + if (0 == i) { + context.put("distributionUrl", artifactUrl); + context.put("distributionSha256", artifact.getHash()); + context.put("distributionJavaVersion", artifact.getJavaVersion()); + } + } + + return true; + } + + static String applyTemplate(Reader reader, Map context, String toolName) { + StringWriter input = new StringWriter(); + MustacheFactory mf = new MyMustacheFactory(); + Mustache mustache = mf.compile(reader, toolName); + mustache.execute(input, context); + input.flush(); + return input.toString(); + } + + static String applyTemplate(Reader reader, Map context) { + return applyTemplate(reader, context, UUID.randomUUID().toString()); + } + + private static class MyMustacheFactory extends DefaultMustacheFactory { + @Override + public void encode(String value, Writer writer) { + if (value.startsWith("!!") && value.endsWith("!!")) { + try { + writer.write(value.substring(2, value.length() - 2)); + } catch (IOException e) { + throw new MustacheException("Failed to write value: " + value, e); + } + } else { + super.encode(value, writer); + } + } + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ScoopToolProcessor.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ScoopToolProcessor.java new file mode 100644 index 00000000..5b94a152 --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ScoopToolProcessor.java @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Project; +import org.kordamp.jreleaser.model.Scoop; +import org.kordamp.jreleaser.util.Logger; + +import java.io.StringReader; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import static org.kordamp.jreleaser.templates.TemplateUtils.trimTplExtension; +import static org.kordamp.jreleaser.tools.ProcessorUtils.applyTemplate; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ScoopToolProcessor extends AbstractToolProcessor { + public ScoopToolProcessor(Logger logger, JReleaserModel model, Scoop scoop) { + super(logger, model, scoop); + } + + @Override + protected boolean doPackageDistribution(Distribution distribution, Map context) throws ToolProcessingException { + getLogger().debug("Tool {} does not require additional packaging", getToolName()); + return true; + } + + @Override + protected Set resolveByExtensionsFor(Distribution.DistributionType type) { + Set set = new LinkedHashSet<>(); + set.add(".zip"); + return set; + } + + @Override + protected void fillToolProperties(Map context, Distribution distribution) throws ToolProcessingException { + context.put(Constants.KEY_SCOOP_CHECKVER_URL, resolveCheckverUrl(context)); + context.put(Constants.KEY_SCOOP_AUTOUPDATE_URL, resolveAutoupdateUrl(context)); + } + + private Object resolveCheckverUrl(Map context) { + if (!getTool().getCheckverUrl().contains("{{")) { + return getTool().getCheckverUrl(); + } + return applyTemplate(new StringReader(getTool().getCheckverUrl()), context); + } + + private Object resolveAutoupdateUrl(Map context) { + if (!getTool().getAutoupdateUrl().contains("{{")) { + return getTool().getAutoupdateUrl(); + } + + Map copy = new LinkedHashMap<>(context); + copy.put(Constants.KEY_PROJECT_VERSION, "$version"); + copy.put(Constants.KEY_ARTIFACT_FILE_NAME, copy.get("projectName") + "-$version.zip"); + return applyTemplate(new StringReader(getTool().getAutoupdateUrl()), copy); + } + + @Override + protected void writeFile(Project project, Distribution distribution, String content, Map context, String fileName) + throws ToolProcessingException { + Path outputDirectory = (Path) context.get(Constants.KEY_PREPARE_DIRECTORY); + Path outputFile = outputDirectory.resolve(trimTplExtension(fileName)); + + writeFile(content, outputFile); + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/SnapToolProcessor.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/SnapToolProcessor.java new file mode 100644 index 00000000..e299468e --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/SnapToolProcessor.java @@ -0,0 +1,148 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Project; +import org.kordamp.jreleaser.model.Snap; +import org.kordamp.jreleaser.util.FileUtils; +import org.kordamp.jreleaser.util.Logger; +import org.kordamp.jreleaser.util.OsUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.kordamp.jreleaser.templates.TemplateUtils.trimTplExtension; +import static org.kordamp.jreleaser.util.FileUtils.createDirectoriesWithFullAccess; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class SnapToolProcessor extends AbstractToolProcessor { + public SnapToolProcessor(Logger logger, JReleaserModel model, Snap snap) { + super(logger, model, snap); + } + + @Override + protected boolean doPackageDistribution(Distribution distribution, Map context) throws ToolProcessingException { + if (OsUtils.isWindows()) { + getLogger().debug("Tool {} must not run on Windows", getToolName()); + return false; + } + + Path primeDirectory = createPackage(context); + + if (!login(distribution, context)) { + getLogger().error("Could not log into snapcraft store"); + return false; + } + + return createSnap(distribution, context, primeDirectory); + } + + @Override + protected Set resolveByExtensionsFor(Distribution.DistributionType type) { + Set set = new LinkedHashSet<>(); + if (type == Distribution.DistributionType.BINARY) { + set.add(".tar.gz"); + set.add(".tar"); + } else if (type == Distribution.DistributionType.SINGLE_JAR) { + set.add(".jar"); + } + return set; + } + + @Override + protected void fillToolProperties(Map context, Distribution distribution) throws ToolProcessingException { + context.put(Constants.KEY_SNAP_BASE, getTool().getBase()); + context.put(Constants.KEY_SNAP_GRADE, getTool().getGrade()); + context.put(Constants.KEY_SNAP_CONFINEMENT, getTool().getConfinement()); + context.put(Constants.KEY_SNAP_HAS_PLUGS, !getTool().getPlugs().isEmpty()); + context.put(Constants.KEY_SNAP_PLUGS, getTool().getPlugs()); + context.put(Constants.KEY_SNAP_HAS_SLOTS, !getTool().getSlots().isEmpty()); + context.put(Constants.KEY_SNAP_SLOTS, getTool().getSlots()); + context.put(Constants.KEY_SNAP_HAS_LOCAL_PLUGS, !getTool().getLocalPlugs().isEmpty()); + context.put(Constants.KEY_SNAP_LOCAL_PLUGS, getTool().getLocalPlugs()); + } + + @Override + protected void writeFile(Project project, Distribution distribution, String content, Map context, String fileName) + throws ToolProcessingException { + fileName = trimTplExtension(fileName); + + Path outputDirectory = (Path) context.get(Constants.KEY_PREPARE_DIRECTORY); + Path outputFile = outputDirectory.resolve(fileName); + + writeFile(content, outputFile); + } + + private Path createPackage(Map context) throws ToolProcessingException { + try { + Path prepareDirectory = (Path) context.get(Constants.KEY_PREPARE_DIRECTORY); + Path snapDirectory = prepareDirectory.resolve("snap"); + Path packageDirectory = (Path) context.get(Constants.KEY_PACKAGE_DIRECTORY); + Path primeDirectory = packageDirectory.resolve("prime"); + Path metaDirectory = primeDirectory.resolve("meta"); + createDirectoriesWithFullAccess(metaDirectory); + if (FileUtils.copyFiles(getLogger(), snapDirectory, metaDirectory)) { + Files.move(metaDirectory.resolve("snapcraft.yaml"), + metaDirectory.resolve("snap.yaml"), + REPLACE_EXISTING); + return primeDirectory; + } else { + throw new ToolProcessingException("Could not copy files from " + + prepareDirectory.toAbsolutePath().toString() + " to " + + metaDirectory.toAbsolutePath().toString()); + } + } catch (IOException e) { + throw new ToolProcessingException("Unexpected error when creating package", e); + } + } + + private boolean login(Distribution distribution, Map context) throws ToolProcessingException { + List cmd = new ArrayList<>(); + cmd.add("snapcraft"); + cmd.add("login"); + cmd.add("--with"); + cmd.add(distribution.getSnap().getExportedLogin()); + return executeCommand(cmd); + } + + private boolean createSnap(Distribution distribution, Map context, Path primeDirectory) throws ToolProcessingException { + Path packageDirectory = (Path) context.get(Constants.KEY_PACKAGE_DIRECTORY); + String version = (String) context.get(Constants.KEY_PROJECT_VERSION); + String snapName = distribution.getName() + "-" + version + ".snap"; + + List cmd = new ArrayList<>(); + cmd.add("snapcraft"); + cmd.add("snap"); + cmd.add(primeDirectory.toAbsolutePath().toString()); + cmd.add("--output"); + cmd.add(packageDirectory.resolve(snapName).toAbsolutePath().toString()); + return executeCommand(cmd); + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessingException.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessingException.java new file mode 100644 index 00000000..67a25fa0 --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessingException.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ToolProcessingException extends Exception { + public ToolProcessingException(String message) { + super(message); + } + + public ToolProcessingException(String message, Throwable cause) { + super(message, cause); + } + + public ToolProcessingException(Throwable cause) { + super(cause); + } +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessor.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessor.java new file mode 100644 index 00000000..4a9bc197 --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessor.java @@ -0,0 +1,43 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Tool; +import org.kordamp.jreleaser.util.Logger; + +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface ToolProcessor { + T getTool(); + + String getToolName(); + + Logger getLogger(); + + JReleaserModel getModel(); + + boolean prepareDistribution(Distribution distribution, Map context) throws ToolProcessingException; + + boolean packageDistribution(Distribution distribution, Map context) throws ToolProcessingException; +} diff --git a/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessors.java b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessors.java new file mode 100644 index 00000000..30660422 --- /dev/null +++ b/core/jreleaser-tools/src/main/java/org/kordamp/jreleaser/tools/ToolProcessors.java @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.tools; + +import org.kordamp.jreleaser.model.Brew; +import org.kordamp.jreleaser.model.Chocolatey; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Scoop; +import org.kordamp.jreleaser.model.Snap; +import org.kordamp.jreleaser.model.Tool; +import org.kordamp.jreleaser.util.Logger; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ToolProcessors { + public static ToolProcessor findProcessor(Logger logger, JReleaserModel model, T tool) { + if (tool instanceof Brew) { + return (ToolProcessor) new BrewToolProcessor(logger, model, (Brew) tool); + } else if (tool instanceof Chocolatey) { + return (ToolProcessor) new ChocolateyToolProcessor(logger, model, (Chocolatey) tool); + } else if (tool instanceof Scoop) { + return (ToolProcessor) new ScoopToolProcessor(logger, model, (Scoop) tool); + } else if (tool instanceof Snap) { + return (ToolProcessor) new SnapToolProcessor(logger, model, (Snap) tool); + } + + throw new IllegalArgumentException("Unsupported tool " + tool); + } +} diff --git a/core/jreleaser-tools/src/main/module/module-info.java b/core/jreleaser-tools/src/main/module/module-info.java new file mode 100644 index 00000000..45d46629 --- /dev/null +++ b/core/jreleaser-tools/src/main/module/module-info.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.tools { + exports org.kordamp.jreleaser.tools; + requires org.kordamp.jreleaser.model; + requires org.kordamp.jreleaser.util; + requires org.kordamp.jreleaser.templates; + requires com.github.mustachejava; + requires zt.exec; +} \ No newline at end of file diff --git a/core/jreleaser-utils/gradle.properties b/core/jreleaser-utils/gradle.properties new file mode 100644 index 00000000..3616b971 --- /dev/null +++ b/core/jreleaser-utils/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = JReleaser utility classes \ No newline at end of file diff --git a/core/jreleaser-utils/jreleaser-utils.gradle b/core/jreleaser-utils/jreleaser-utils.gradle new file mode 100644 index 00000000..57838687 --- /dev/null +++ b/core/jreleaser-utils/jreleaser-utils.gradle @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api('kr.motd.maven:os-maven-plugin:1.6.2') { transitive = false } +} \ No newline at end of file diff --git a/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/FileUtils.java b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/FileUtils.java new file mode 100644 index 00000000..c30c275d --- /dev/null +++ b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/FileUtils.java @@ -0,0 +1,142 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.util; + +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileSystemLoopException; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileTime; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Set; + +import static java.nio.file.FileVisitResult.CONTINUE; +import static java.nio.file.FileVisitResult.SKIP_SUBTREE; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public final class FileUtils { + private FileUtils() { + //noop + } + + public static void createDirectoriesWithFullAccess(Path path) throws IOException { + createDirectories(path, "rwxrwxrwx"); + } + + public static void createDirectories(Path path, String accessRights) throws IOException { + Set perms = PosixFilePermissions.fromString(accessRights); + FileAttribute> attr = PosixFilePermissions.asFileAttribute(perms); + Files.createDirectories(path, attr); + } + + public static void grantFullAccess(Path path) throws IOException { + grantAccess(path, "rwxrwxrwx"); + } + + public static void grantAccess(Path path, String accessRights) throws IOException { + Set perms = PosixFilePermissions.fromString(accessRights); + Files.setPosixFilePermissions(path, perms); + } + + public static boolean copyFiles(Logger logger, Path source, Path target) throws IOException { + FileTreeCopy copier = new FileTreeCopy(logger, source, target); + Files.walkFileTree(source, copier); + return copier.isSuccessful(); + } + + private static class FileTreeCopy implements FileVisitor { + private final Logger logger; + private final Path source; + private final Path target; + private boolean success = true; + + FileTreeCopy(Logger logger, Path source, Path target) { + this.logger = logger; + this.source = source; + this.target = target; + } + + public boolean isSuccessful() { + return success; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + Path newdir = target.resolve(source.relativize(dir)); + try { + Files.copy(dir, newdir); + FileUtils.grantFullAccess(newdir); + } catch (FileAlreadyExistsException ignored) { + // noop + } catch (IOException e) { + logger.error("Unable to create: {}", newdir, e); + success = false; + return SKIP_SUBTREE; + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + try { + Path newfile = target.resolve(source.relativize(file)); + Files.copy(file, newfile, REPLACE_EXISTING); + FileUtils.grantFullAccess(newfile); + } catch (IOException e) { + logger.error("Unable to copy: {}", source, e); + success = false; + } + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + if (exc == null) { + Path newdir = target.resolve(source.relativize(dir)); + try { + FileTime time = Files.getLastModifiedTime(dir); + Files.setLastModifiedTime(newdir, time); + } catch (IOException e) { + logger.warn("Unable to copy all attributes to: {}", newdir, e); + } + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException e) { + if (e instanceof FileSystemLoopException) { + logger.error("cycle detected: {}", file); + } else { + logger.error("Unable to copy: {}", file, e); + } + success = false; + return CONTINUE; + } + } +} diff --git a/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/Logger.java b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/Logger.java new file mode 100644 index 00000000..683a7c2a --- /dev/null +++ b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/Logger.java @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.util; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface Logger { + void debug(String message); + + void info(String message); + + void warn(String message); + + void error(String message); + + void debug(String message, Object... args); + + void info(String message, Object... args); + + void warn(String message, Object... args); + + void error(String message, Object... args); + + void debug(String message, Throwable throwable); + + void info(String message, Throwable throwable); + + void warn(String message, Throwable throwable); + + void error(String message, Throwable throwable); +} diff --git a/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/OsUtils.java b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/OsUtils.java new file mode 100644 index 00000000..5093e6cb --- /dev/null +++ b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/OsUtils.java @@ -0,0 +1,92 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.util; + +import kr.motd.maven.os.Detector; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public final class OsUtils { + private static final OsDetector OS_DETECTOR = new OsDetector(); + + private OsUtils() { + //noop + } + + public static boolean isWindows() { + return "windows".equals(OS_DETECTOR.get("os.detected.name")); + } + + public static boolean isMac() { + return "osx".equals(OS_DETECTOR.get("os.detected.name")); + } + + public static String getValue(String key) { + return OS_DETECTOR.get(key); + } + + public static Set keySet() { + return OS_DETECTOR.getProperties().keySet(); + } + + public static Collection values() { + return OS_DETECTOR.getProperties().values(); + } + + public static Set> entrySet() { + return OS_DETECTOR.getProperties().entrySet(); + } + + private static final class OsDetector extends Detector { + private final Map props = new LinkedHashMap<>(); + + private OsDetector() { + Properties p = new Properties(); + p.put("failOnUnknownOS", "false"); + detect(p, Collections.emptyList()); + p.stringPropertyNames().forEach(k -> props.put(k, p.getProperty(k))); + } + + private Map getProperties() { + return Collections.unmodifiableMap(props); + } + + private String get(String key) { + return props.get(key); + } + + @Override + protected void log(String message) { + // quiet + } + + @Override + protected void logProperty(String name, String value) { + // quiet + } + } +} diff --git a/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/StringUtils.java b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/StringUtils.java new file mode 100644 index 00000000..5127df1e --- /dev/null +++ b/core/jreleaser-utils/src/main/java/org/kordamp/jreleaser/util/StringUtils.java @@ -0,0 +1,514 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.util; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class StringUtils { + private static final String PROPERTY_SET_PREFIX = "set"; + private static final String PROPERTY_GET_PREFIX = "get"; + private static final Pattern GETTER_PATTERN_1 = Pattern.compile("^get[A-Z][\\w]*$"); + private static final Pattern GETTER_PATTERN_2 = Pattern.compile("^is[A-Z][\\w]*$"); + private static final Pattern SETTER_PATTERN = Pattern.compile("^set[A-Z][\\w]*$"); + private static final String ERROR_METHOD_NULL = "Argument 'method' must not be null"; + + /** + * Capitalizes a String (makes the first char uppercase) taking care + * of blank strings and single character strings. + * + * @param str The String to be capitalized + * @return Capitalized version of the target string if it is not blank + */ + public static String capitalize(String str) { + if (isBlank(str)) { + return str; + } + + if (str.length() == 1) { + return str.toUpperCase(); + } + + return ((String) (str.substring(0, 1).toUpperCase(Locale.ENGLISH) + str.substring(1))); + } + + public static String getFilenameExtension(String path) { + if (path == null) { + return null; + } + + int extIndex = path.lastIndexOf("."); + if (extIndex == -1) { + return null; + } + + int folderIndex = path.lastIndexOf(File.separator); + if (folderIndex > extIndex) { + return null; + } + + return path.substring(extIndex + 1); + } + + /** + * Retrieves the name of a setter for the specified property name + * + * @param propertyName The property name + * @return The setter equivalent + */ + public static String getSetterName(String propertyName) { + return ((String) (PROPERTY_SET_PREFIX + capitalize(propertyName))); + } + + /** + * Calculate the name for a getter method to retrieve the specified property + * + * @param propertyName The property name + * @return The name for the getter method for this property, if it were to exist, i.e. getConstraints + */ + public static String getGetterName(String propertyName) { + return ((String) (PROPERTY_GET_PREFIX + capitalize(propertyName))); + } + + /** + * Returns the class name for the given logical name and trailing name. For example "person" and "Controller" would evaluate to "PersonController" + * + * @param logicalName The logical name + * @param trailingName The trailing name + * @return The class name + */ + public static String getClassName(String logicalName, String trailingName) { + if (isBlank(logicalName)) { + throw new IllegalArgumentException("Argument [logicalName] must not be null or blank"); + } + + + String className = capitalize(logicalName); + if (trailingName != null) { + className = ((String) (className + trailingName)); + } + + return className; + } + + /** + * Returns the class name representation of the given name + * + * @param name The name to convert + * @return The property name representation + */ + public static String getClassNameRepresentation(String name) { + StringBuilder buf = new StringBuilder(); + if (name != null && name.length() > 0) { + String[] tokens = name.split("[^\\w\\d]"); + for (String token1 : tokens) { + String token = token1.trim(); + buf.append(capitalize(token)); + } + } + + return buf.toString(); + } + + /** + * Converts foo-bar into FooBar. Empty and null strings are returned + * as-is. + * + * @param name The lower case hyphen separated name + * @return The class name equivalent. + */ + public static String getClassNameForLowerCaseHyphenSeparatedName(String name) { + // Handle null and empty strings. + if (isBlank(name)) { + return name; + } + + if (name.contains("-")) { + StringBuilder buf = new StringBuilder(); + String[] tokens = name.split("-"); + for (String token : tokens) { + if (token == null || token.length() == 0) { + continue; + } + + buf.append(capitalize(token)); + } + + return buf.toString(); + } + + return capitalize(name); + } + + /** + * Retrieves the logical class name of a Griffon artifact given the Griffon class + * and a specified trailing name + * + * @param clazz The class + * @param trailingName The trailing name such as "Controller" or "TagLib" + * @return The logical class name + */ + public static String getLogicalName(Class clazz, String trailingName) { + return getLogicalName(clazz.getName(), trailingName); + } + + /** + * Retrieves the logical name of the class without the trailing name + * + * @param name The name of the class + * @param trailingName The trailing name + * @return The logical name + */ + public static String getLogicalName(String name, String trailingName) { + if (isNotBlank(name) && isNotBlank(trailingName)) { + String shortName = getShortName(name); + if (shortName.endsWith(trailingName)) { + return shortName.substring(0, shortName.length() - trailingName.length()); + } + } + + return name; + } + + public static String getLogicalPropertyName(String className, String trailingName) { + if (isNotBlank(className) && isNotBlank(trailingName) && className.length() == trailingName.length() + 1 && className.endsWith(trailingName)) { + return className.substring(0, 1).toLowerCase(); + } + + return getLogicalName(getPropertyName(className), trailingName); + } + + /** + * Shorter version of getPropertyNameRepresentation + * + * @param name The name to convert + * @return The property name version + */ + public static String getPropertyName(String name) { + return getPropertyNameRepresentation(name); + } + + /** + * Shorter version of getPropertyNameRepresentation + * + * @param clazz The clazz to convert + * @return The property name version + */ + public static String getPropertyName(Class clazz) { + return getPropertyNameRepresentation(clazz); + } + + /** + * Returns the property name representation of the given {@code Method} + * + * @param method The method to inspect + * @return The property name representation + * @since 3.0.0 + */ + public static String getPropertyName(Method method) { + Objects.requireNonNull(method, ERROR_METHOD_NULL); + String name = method.getName(); + if (GETTER_PATTERN_1.matcher(name).matches() || SETTER_PATTERN.matcher(name).matches()) { + return uncapitalize(name.substring(3)); + } else if (GETTER_PATTERN_2.matcher(name).matches()) { + return uncapitalize(name.substring(2)); + } + + return name; + } + + /** + * Returns the property name equivalent for the specified class + * + * @param targetClass The class to get the property name for + * @return A property name representation of the class name (eg. MyClass becomes myClass) + */ + public static String getPropertyNameRepresentation(Class targetClass) { + String shortName = getShortName(targetClass); + return getPropertyNameRepresentation(shortName); + } + + /** + * Returns the property name representation of the given name + * + * @param name The name to convert + * @return The property name representation + */ + public static String getPropertyNameRepresentation(String name) { + if (isBlank(name)) { + return name; + } + + // Strip any package from the name. + int pos = name.lastIndexOf("."); + if (pos != -1) { + name = name.substring(pos + 1); + } + + // Check whether the name begins with two upper case letters. + if (name.length() > 1 && Character.isUpperCase(name.charAt(0)) && Character.isUpperCase(name.charAt(1))) { + return name; + } + + String propertyName = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); + if (propertyName.contains(" ")) { + propertyName = propertyName.replaceAll("\\s", ""); + } + + return propertyName; + } + + /** + * Converts foo-bar into fooBar + * + * @param name The lower case hyphen separated name + * @return The property name equivalent + */ + public static String getPropertyNameForLowerCaseHyphenSeparatedName(String name) { + return getPropertyName(getClassNameForLowerCaseHyphenSeparatedName(name)); + } + + /** + * Returns the class name without the package prefix + * + * @param targetClass The class to get a short name for + * @return The short name of the class + */ + public static String getShortName(Class targetClass) { + String className = targetClass.getName(); + return getShortName(className); + } + + /** + * Returns the class name without the package prefix + * + * @param className The class name to get a short name for + * @return The short name of the class + */ + public static String getShortName(String className) { + if (isBlank(className)) { + return className; + } + + int i = className.lastIndexOf("."); + if (i > -1) { + className = className.substring(i + 1, className.length()); + } + + return className; + } + + /** + * Converts a property name into its natural language equivalent eg ('firstName' becomes 'First Name') + * + * @param name The property name to convert + * @return The converted property name + */ + public static String getNaturalName(String name) { + name = getShortName(name); + if (isBlank(name)) { + return name; + } + + List words = new ArrayList(); + int i = 0; + char[] chars = name.toCharArray(); + for (char c : chars) { + String w; + if (i >= words.size()) { + w = ""; + words.add(i, w); + } else { + w = words.get(i); + } + + if (Character.isLowerCase(c) || Character.isDigit(c)) { + if (Character.isLowerCase(c) && w.length() == 0) { + c = Character.toUpperCase(c); + } else if (w.length() > 1 && Character.isUpperCase(w.charAt(w.length() - 1))) { + w = ""; + words.add(++i, w); + } + + words.set(i, w + c); + } else if (Character.isUpperCase(c)) { + if ((i == 0 && w.length() == 0) || Character.isUpperCase(w.charAt(w.length() - 1))) { + words.set(i, w + c); + } else { + words.add(++i, String.valueOf(c)); + } + } + } + + StringBuilder buf = new StringBuilder(); + for (Iterator j = words.iterator(); j.hasNext(); ) { + String word = j.next(); + buf.append(word); + if (j.hasNext()) { + buf.append(" "); + } + } + + return buf.toString(); + } + + /** + *

Determines whether a given string is null, empty, + * or only contains whitespace. If it contains anything other than + * whitespace then the string is not considered to be blank and the + * method returns false.

+ * + * @param str The string to test. + * @return true if the string is null, or + * blank. + */ + public static boolean isBlank(String str) { + if (str == null || str.length() == 0) { + return true; + } + + for (char c : str.toCharArray()) { + if (!Character.isWhitespace(c)) { + return false; + } + } + + return true; + } + + /** + *

Determines whether a given string is not null, empty, + * or only contains whitespace. If it contains anything other than + * whitespace then the string is not considered to be blank and the + * method returns true.

+ * + * @param str The string to test. + * @return true if the string is not null, nor + * blank. + */ + public static boolean isNotBlank(String str) { + return ((boolean) (!isBlank(str))); + } + + /** + * Checks that the specified String is not {@code blank}. This + * method is designed primarily for doing parameter validation in methods + * and constructors, as demonstrated below: + *
+     *  Foo(String str) {*     this.str = GriffonNameUtils.requireNonBlank(str)
+     * }* 
+ * + * @param str the String to check for blank + * @return {@code str} if not {@code blank} + * @throws IllegalArgumentException if {@code str} is {@code blank} + */ + public static String requireNonBlank(String str) { + if (isBlank(str)) { + throw new IllegalArgumentException(); + } + + return str; + } + + /** + * Checks that the specified String is not {@code blank} and + * throws a customized {@link IllegalArgumentException} if it is. This method + * is designed primarily for doing parameter validation in methods and + * constructors with multiple parameters, as demonstrated below: + *
+     *  Foo(String str) {*     this.str = GriffonNameUtils.requireNonBlank(str, "str must not be null")
+     * }* 
+ * + * @param str the String to check for blank + * @param message detail message to be used in the event that a {@code + * IllegalArgumentException} is thrown + * @return {@code str} if not {@code blank} + * @throws IllegalArgumentException if {@code str} is {@code blank} + */ + public static String requireNonBlank(String str, String message) { + if (isBlank(str)) { + throw new IllegalArgumentException(message); + } + + return str; + } + + /** + * Retrieves the hyphenated name representation of the supplied class. For example + * MyFunkyGriffonThingy would be my-funky-griffon-thingy. + * + * @param clazz The class to convert + * @return The hyphenated name representation + */ + public static String getHyphenatedName(Class clazz) { + if (clazz == null) { + return null; + } + + return getHyphenatedName(clazz.getName()); + } + + /** + * Retrieves the hyphenated name representation of the given class name. + * For example MyFunkyGriffonThingy would be my-funky-griffon-thingy. + * + * @param name The class name to convert. + * @return The hyphenated name representation. + */ + public static String getHyphenatedName(String name) { + if (isBlank(name)) { + return name; + } + + if (name.endsWith(".groovy")) { + name = name.substring(0, name.length() - 7); + } + + String naturalName = getNaturalName(getShortName(name)); + return naturalName.replaceAll("\\s", "-").toLowerCase(); + } + + /** + * Uncapitalizes a String (makes the first char lowercase) taking care + * of blank strings and single character strings. + * + * @param str The String to be uncapitalized + * @return Uncapitalized version of the target string if it is not blank + */ + public static String uncapitalize(String str) { + if (isBlank(str)) { + return str; + } + + if (str.length() == 1) { + return String.valueOf(Character.toLowerCase(str.charAt(0))); + } + + return Character.toLowerCase(str.charAt(0)) + str.substring(1); + } +} diff --git a/core/jreleaser-utils/src/main/module/module-info.java b/core/jreleaser-utils/src/main/module/module-info.java new file mode 100644 index 00000000..24f59263 --- /dev/null +++ b/core/jreleaser-utils/src/main/module/module-info.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.util { + exports org.kordamp.jreleaser.util; + requires os.maven.plugin; +} \ No newline at end of file diff --git a/docs/guide/guide.gradle b/docs/guide/guide.gradle new file mode 100644 index 00000000..41b97125 --- /dev/null +++ b/docs/guide/guide.gradle @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +configurations { + asciidoctorExtensions +} + +dependencies { + asciidoctorExtensions 'com.bmuschko:asciidoctorj-tabbed-code-extension:0.3' +} + +asciidoctor { + configurations 'asciidoctorExtensions' + attributes = [ + 'gradle-version': project.gradle.gradleVersion, + 'source-highlighter': 'prettify' + ] +} diff --git a/docs/guide/src/docs/asciidoc/_links.adoc b/docs/guide/src/docs/asciidoc/_links.adoc new file mode 100644 index 00000000..e69de29b diff --git a/docs/guide/src/docs/asciidoc/index.adoc b/docs/guide/src/docs/asciidoc/index.adoc new file mode 100644 index 00000000..c1ef5dac --- /dev/null +++ b/docs/guide/src/docs/asciidoc/index.adoc @@ -0,0 +1,23 @@ +ifndef::imagesdir[] +:imagesdir: ../resources/images +endif::[] +ifndef::includedir[] +:includedir: . +endif::[] += {project-title} +:author: {project-author} +:revnumber: {project-version} +:toclevels: 4 +:docinfo1: + +include::{includedir}/_links.adoc[] + +:leveloffset: 1 +include::{includedir}/introduction.adoc[] +include::{includedir}/usage.adoc[] + += Links + +link:api/index.html[Javadoc, window="_blank"] + +link:api-html/index.html[Source, window="_blank"] \ No newline at end of file diff --git a/docs/guide/src/docs/asciidoc/introduction.adoc b/docs/guide/src/docs/asciidoc/introduction.adoc new file mode 100644 index 00000000..7534dc52 --- /dev/null +++ b/docs/guide/src/docs/asciidoc/introduction.adoc @@ -0,0 +1,5 @@ + +[[_introduction]] += Introduction + +Lorem ipsum dolor sit amet diff --git a/docs/guide/src/docs/asciidoc/usage.adoc b/docs/guide/src/docs/asciidoc/usage.adoc new file mode 100644 index 00000000..2b2d8709 --- /dev/null +++ b/docs/guide/src/docs/asciidoc/usage.adoc @@ -0,0 +1,5 @@ + +[[_usage]] += Usage + +Lorem ipsum dolor sit amet diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..38e3179d --- /dev/null +++ b/gradle.properties @@ -0,0 +1,49 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +group = org.kordamp.jreleaser +version = 0.1.0-SNAPSHOT +#sourceCompatibility = 1.8 +#targetCompatibility = 1.8 +javaCompatibility = 1.8 + +kordampPluginVersion = 0.42.0 +kordampBuildVersion = 2.1.0 +gitPluginVersion = 3.0.0 +checksumPluginVersion = 1.1.0 +beryxJarPluginVersion = 1.2.0 + +asmVersion = 8.0.1 +jacksonVersion = 2.11.3 +jipsyVersion = 0.6.0 +junitVersion = 5.7.0 +hamcrestVersion = 2.2 +mavenVersion = 3.6.0 +mustacheVersion = 0.9.7 +okhttpVersion = 3.14.9 +picocliVersion = 4.5.2 +plexusVersion = 3.1.0 +tikaVersion = 1.24.1 +wiremockVersion = 2.27.2 +slf4jVersion = 1.7.30 +snakeYamlVersion = 1.27 +ztexecVersion = 1.12 + +org.gradle.daemon = true +org.gradle.caching = true +org.gradle.parallel = false diff --git a/gradle/LICENSE_HEADER b/gradle/LICENSE_HEADER new file mode 100644 index 00000000..aa8903cb --- /dev/null +++ b/gradle/LICENSE_HEADER @@ -0,0 +1,15 @@ +SPDX-License-Identifier: Apache-2.0 + +Copyright ${copyrightYear} ${author}. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..be52383e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..4f906e0c --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/plugins/jreleaser-gradle-plugin/gradle.properties b/plugins/jreleaser-gradle-plugin/gradle.properties new file mode 100644 index 00000000..34906283 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/gradle.properties @@ -0,0 +1,24 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +pluginId = org.kordamp.jreleaser +pluginShortName = jreleaser +pluginDisplayName = JReleaser Gradle Plugin +pluginImplementationClass = org.kordamp.jreleaser.gradle.plugin.JReleaserPlugin +project_description = JReleaser Gradle Plugin \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/jreleaser-gradle-plugin.gradle b/plugins/jreleaser-gradle-plugin/jreleaser-gradle-plugin.gradle new file mode 100644 index 00000000..0bec90c2 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/jreleaser-gradle-plugin.gradle @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id 'groovy' + id 'org.kordamp.gradle.groovy-project' + id 'org.kordamp.gradle.plugin' +} + +config { + bintray { + enabled = true + } + + plugins { + plugin { + name = project.pluginShortName + id = project.pluginId + implementationClass = project.pluginImplementationClass + } + } +} + +dependencies { + compileOnly gradleApi() + + api project(':jreleaser-model') + api project(':jreleaser-tools') + api project(':jreleaser-templates') + api "org.kordamp.gradle:base-gradle-plugin:$kordampPluginVersion" + api "gradle.plugin.org.gradle.crypto:checksum:$checksumPluginVersion" +} + +processResources { + inputs.property('version', project.version) + filesMatching(['**/*.properties']) { + expand( + 'version': project.version, + 'id': 'jrleaser', + 'name': project.pluginDisplayName + ) + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/Banner.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/Banner.groovy new file mode 100644 index 00000000..ae46a0f7 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/Banner.groovy @@ -0,0 +1,89 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin + +import groovy.transform.CompileStatic +import org.gradle.BuildAdapter +import org.gradle.BuildResult +import org.gradle.api.Project + +import java.text.MessageFormat + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +final class Banner { + private final ResourceBundle bundle = ResourceBundle.getBundle(Banner.name) + private final String productVersion = bundle.getString('product.version') + private final String productId = bundle.getString('product.id') + private final String productName = bundle.getString('product.name') + private final String banner = MessageFormat.format(bundle.getString('product.banner'), productName, productVersion) + private final List visited = [] + + private static final Banner b = new Banner() + + private Banner() { + // nooop + } + + static void display(Project project) { + if (b.visited.contains(project.rootProject.name)) { + return + } + b.visited.add(project.rootProject.name) + project.gradle.addBuildListener(new BuildAdapter() { + @Override + void buildFinished(BuildResult result) { + b.visited.clear() + } + }) + + File parent = new File(project.gradle.gradleUserHomeDir, 'caches') + File markerFile = b.getMarkerFile(parent) + if (!markerFile.exists()) { + markerFile.parentFile.mkdirs() + markerFile.text = '1' + println(b.banner) + } else { + try { + int count = Integer.parseInt(markerFile.text) + if (count < 3) { + println(b.banner) + } + markerFile.text = (count + 1) + '' + } catch (NumberFormatException e) { + markerFile.text = '1' + println(b.banner) + } + } + } + + private File getMarkerFile(File parent) { + new File(parent, + 'kordamp' + + File.separator + + productId + + File.separator + + productVersion + + File.separator + + 'marker.txt') + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/JReleaserExtension.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/JReleaserExtension.groovy new file mode 100644 index 00000000..edfa7401 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/JReleaserExtension.groovy @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin + +import groovy.transform.CompileStatic +import org.gradle.api.Action +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.provider.Property +import org.kordamp.jreleaser.gradle.plugin.dsl.Distribution +import org.kordamp.jreleaser.gradle.plugin.dsl.Packagers +import org.kordamp.jreleaser.gradle.plugin.dsl.Project +import org.kordamp.jreleaser.gradle.plugin.dsl.Release + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface JReleaserExtension { + Property getEnabled() + + Project getProject() + + Release getRelease() + + Packagers getPackagers() + + NamedDomainObjectContainer getDistributions() + + void project(Action action) + + void release(Action action) + + void packagers(Action action) +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/JReleaserPlugin.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/JReleaserPlugin.groovy new file mode 100644 index 00000000..8322be99 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/JReleaserPlugin.groovy @@ -0,0 +1,86 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin + +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic +import org.gradle.api.Action +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.internal.JReleaserExtensionImpl +import org.kordamp.jreleaser.gradle.plugin.internal.JReleaserProjectConfigurer + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class JReleaserPlugin implements Plugin { + @Override + void apply(Project project) { + Banner.display(project) + + Provider nameProvider = project.provider({ -> project.name }) + Provider descriptionProvider = project.provider({ -> project.description }) + Provider versionProvider = project.provider({ -> String.valueOf(project.version) }) + Provider distributionsDirProvider = project.provider({ -> + project.layout.projectDirectory.dir('src/distributions') + }) + project.extensions.create(JReleaserExtension, 'jreleaser', JReleaserExtensionImpl, + project.objects, nameProvider, descriptionProvider, versionProvider, distributionsDirProvider) + + project.afterEvaluate(new Action() { + @Override + void execute(Project p) { + JReleaserExtension extension = project.extensions.findByType(JReleaserExtension) + if (!extension.enabled.get()) return + + if (hasKordampBasePluginApplied(p)) { + registerAllProjectsEvaluatedListener(p) + } else { + configureJReleaser(p) + } + } + }) + } + + private void configureJReleaser(Project project) { + JReleaserProjectConfigurer.configure(project) + } + + private boolean hasKordampBasePluginApplied(Project project) { + project.rootProject.plugins.findPlugin('org.kordamp.gradle.base') + } + + @CompileDynamic + private void registerAllProjectsEvaluatedListener(Project project) { + Class c = Class.forName('org.kordamp.jreleaser.gradle.plugin.internal.JReleaserAllProjectsEvaluatedListener') + def listener = c.getConstructor().newInstance() + listener.runnable = { -> + Class.forName('org.kordamp.jreleaser.gradle.plugin.internal.KordampJReleaserAdapter') + .adapt(project) + configureJReleaser(project) + } + + Class m = Class.forName('org.kordamp.gradle.listener.ProjectEvaluationListenerManager') + m.addAllProjectsEvaluatedListener(project, listener) + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Artifact.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Artifact.groovy new file mode 100644 index 00000000..c55333da --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Artifact.groovy @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Artifact { + RegularFileProperty getPath() + + Property getOsClassifier() +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Brew.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Brew.groovy new file mode 100644 index 00000000..953c3514 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Brew.groovy @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Brew extends BrewPackager, Tool { +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/BrewPackager.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/BrewPackager.groovy new file mode 100644 index 00000000..23df3c45 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/BrewPackager.groovy @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.provider.MapProperty + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface BrewPackager extends PackagerTool { + MapProperty getDependencies() + + void addDependency(String key, String value) + + void addDependency(String key) +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Chocolatey.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Chocolatey.groovy new file mode 100644 index 00000000..b3580d74 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Chocolatey.groovy @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Chocolatey extends ChocolateyPackager, Tool { +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ChocolateyPackager.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ChocolateyPackager.groovy new file mode 100644 index 00000000..1101e69d --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ChocolateyPackager.groovy @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface ChocolateyPackager extends PackagerTool { +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Distribution.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Distribution.groovy new file mode 100644 index 00000000..0d6a9b05 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Distribution.groovy @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.Action +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.kordamp.jreleaser.model.Distribution.DistributionType + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Distribution extends ExtraProperties { + Property getDistributionType() + + Property getExecutable() + + ListProperty getTags() + + void setDistributionType(String distributionType) + + void addTag(String tag) + + void artifact(Action action) + + Brew getBrew() + + Chocolatey getChocolatey() + + Scoop getScoop() + + Snap getSnap() + + void brew(Action action) + + void chocolatey(Action action) + + void scoop(Action action) + + void snap(Action action) +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ExtraProperties.java b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ExtraProperties.java new file mode 100644 index 00000000..dfdfa20b --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ExtraProperties.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl; + +import org.gradle.api.provider.MapProperty; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface ExtraProperties { + MapProperty getExtraProperties(); +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/PackagerTool.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/PackagerTool.groovy new file mode 100644 index 00000000..650b4a33 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/PackagerTool.groovy @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.provider.Property + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface PackagerTool extends ExtraProperties { + Property getEnabled() +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Packagers.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Packagers.groovy new file mode 100644 index 00000000..16321c3f --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Packagers.groovy @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.Action + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Packagers { + BrewPackager getBrew() + + ChocolateyPackager getChocolatey() + + ScoopPackager getScoop() + + SnapPackager getSnap() + + void brew(Action action) + + void chocolatey(Action action) + + void scoop(Action action) + + void snap(Action action) +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Plug.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Plug.groovy new file mode 100644 index 00000000..c33bec72 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Plug.groovy @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.provider.MapProperty + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Plug { + MapProperty getAttributes() + + void addAttribute(String key, String value) +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Project.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Project.groovy new file mode 100644 index 00000000..a82adb9a --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Project.groovy @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Project extends ExtraProperties { + Property getName() + + Property getVersion() + + Property getDescription() + + Property getWebsite() + + Property getLicense() + + ListProperty getAuthors() + + ListProperty getTags() + + void addAuthor(String name) + + void addTag(String tag) +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Release.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Release.groovy new file mode 100644 index 00000000..b527ef91 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Release.groovy @@ -0,0 +1,67 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.provider.Property + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Release { + Property getRepoType() + + Property getRepoHost() + + Property getRepoOwner() + + Property getRepoName() + + Property getDownloadUrlFormat() + + Property getReleaseNotesUrlFormat() + + Property getLatestReleaseUrlFormat() + + Property getIssueTrackerUrlFormat() + + void setRepoType(String repoType) + + Property getAuthorization() + + Property getTagName() + + Property getTargetCommitish() + + Property getReleaseName() + + Property getBody() + + Property getApiEndpoint() + + Property getDraft() + + Property getPrerelease() + + Property getOverwrite() + + Property getAllowUploadToExisting() +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Scoop.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Scoop.groovy new file mode 100644 index 00000000..4bdc56ff --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Scoop.groovy @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Scoop extends ScoopPackager, Tool { +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ScoopPackager.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ScoopPackager.groovy new file mode 100644 index 00000000..c9ceeab7 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/ScoopPackager.groovy @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.provider.Property + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface ScoopPackager extends PackagerTool { + Property getCheckverUrl() + + Property getAutoupdateUrl() +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Slot.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Slot.groovy new file mode 100644 index 00000000..afb59c6a --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Slot.groovy @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Slot { + MapProperty getAttributes() + + void addAttribute(String key, String value) + + ListProperty getReads() + + void addRead(String read) + + ListProperty getWrites() + + void addWrite(String write) +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Snap.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Snap.groovy new file mode 100644 index 00000000..5552576b --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Snap.groovy @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Snap extends SnapPackager, Tool { +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/SnapPackager.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/SnapPackager.groovy new file mode 100644 index 00000000..d9b7247b --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/SnapPackager.groovy @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface SnapPackager extends PackagerTool { + Property getBase() + + Property getGrade() + + Property getConfinement() + + RegularFileProperty getExportedLogin() + + ListProperty getLocalPlugs() + + NamedDomainObjectContainer getPlugs() + + NamedDomainObjectContainer getSlots() + + void addLocalPlug(String plug) +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Tool.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Tool.groovy new file mode 100644 index 00000000..2fb250e5 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/dsl/Tool.groovy @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.file.DirectoryProperty + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +interface Tool extends PackagerTool { + DirectoryProperty getTemplateDirectory() +} \ No newline at end of file diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserAllProjectsEvaluatedListener.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserAllProjectsEvaluatedListener.groovy new file mode 100644 index 00000000..12e8985c --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserAllProjectsEvaluatedListener.groovy @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal + +import groovy.transform.CompileStatic +import org.gradle.api.Project +import org.kordamp.gradle.annotations.DependsOn +import org.kordamp.gradle.listener.AllProjectsEvaluatedListener + +import javax.inject.Named + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +@DependsOn(['base','*']) +@Named('jreleaser') +class JReleaserAllProjectsEvaluatedListener implements AllProjectsEvaluatedListener { + Runnable runnable + + @Override + void allProjectsEvaluated(Project project) { + runnable?.run() + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserExtensionImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserExtensionImpl.groovy new file mode 100644 index 00000000..3fbe674a --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserExtensionImpl.groovy @@ -0,0 +1,103 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal + +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic +import org.gradle.api.Action +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.file.Directory +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.JReleaserExtension +import org.kordamp.jreleaser.gradle.plugin.dsl.Packagers +import org.kordamp.jreleaser.gradle.plugin.dsl.Project +import org.kordamp.jreleaser.gradle.plugin.dsl.Release +import org.kordamp.jreleaser.gradle.plugin.internal.dsl.DistributionImpl +import org.kordamp.jreleaser.gradle.plugin.internal.dsl.PackagersImpl +import org.kordamp.jreleaser.gradle.plugin.internal.dsl.ProjectImpl +import org.kordamp.jreleaser.gradle.plugin.internal.dsl.ReleaseImpl +import org.kordamp.jreleaser.model.Distribution +import org.kordamp.jreleaser.model.JReleaserModel + +import javax.inject.Inject +import java.util.stream.Collectors + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class JReleaserExtensionImpl implements JReleaserExtension { + final Property enabled + final ProjectImpl project + final ReleaseImpl release + final PackagersImpl packagers + final NamedDomainObjectContainer distributions + + @Inject + JReleaserExtensionImpl(ObjectFactory objects, + Provider nameProvider, + Provider descriptionProvider, + Provider versionProvider, + Provider distributionsDirProvider) { + enabled = objects.property(Boolean).convention(true) + project = objects.newInstance(ProjectImpl, objects, nameProvider, descriptionProvider, versionProvider) + release = objects.newInstance(ReleaseImpl, objects) + packagers = objects.newInstance(PackagersImpl, objects) + distributions = objects.domainObjectContainer(DistributionImpl, new NamedDomainObjectFactory() { + @Override + DistributionImpl create(String name) { + DistributionImpl distribution = objects.newInstance(DistributionImpl, objects, distributionsDirProvider, packagers) + distribution.name = name + return distribution + } + }) + } + + @Override + void project(Action action) { + action.execute(project) + } + + @Override + void release(Action action) { + action.execute(release) + } + + @Override + void packagers(Action action) { + action.execute(packagers) + } + + @CompileDynamic + JReleaserModel toModel() { + JReleaserModel jreleaser = new JReleaserModel() + jreleaser.project = project.toModel() + jreleaser.release = release.toModel() + jreleaser.packagers = packagers.toModel() + jreleaser.distributions = (distributions.toList().stream() + .collect(Collectors.toMap( + { DistributionImpl d -> d.name }, + { DistributionImpl d -> d.toModel() })) as Map) + jreleaser + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserLoggerAdapter.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserLoggerAdapter.groovy new file mode 100644 index 00000000..14b5ec3f --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserLoggerAdapter.groovy @@ -0,0 +1,92 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal + +import org.kordamp.jreleaser.util.Logger + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +class JReleaserLoggerAdapter implements Logger { + private final org.gradle.api.logging.Logger delegate + + JReleaserLoggerAdapter(org.gradle.api.logging.Logger delegate) { + this.delegate = delegate + } + + @Override + void debug(String message) { + delegate.debug(message) + } + + @Override + void info(String message) { + delegate.info(message) + } + + @Override + void warn(String message) { + delegate.warn(message) + } + + @Override + void error(String message) { + delegate.error(message) + } + + @Override + void debug(String message, Object... args) { + delegate.debug(message, args) + } + + @Override + void info(String message, Object... args) { + delegate.info(message, args) + } + + @Override + void warn(String message, Object... args) { + delegate.warn(message, args) + } + + @Override + void error(String message, Object... args) { + delegate.error(message, args) + } + + @Override + void debug(String message, Throwable throwable) { + delegate.debug(message, throwable) + } + + @Override + void info(String message, Throwable throwable) { + delegate.info(message, throwable) + } + + @Override + void warn(String message, Throwable throwable) { + delegate.warn(message, throwable) + } + + @Override + void error(String message, Throwable throwable) { + delegate.error(message, throwable) + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserProjectConfigurer.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserProjectConfigurer.groovy new file mode 100644 index 00000000..a51aec63 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/JReleaserProjectConfigurer.groovy @@ -0,0 +1,340 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal + +import groovy.transform.CompileStatic +import org.gradle.api.Action +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.JavaVersion +import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.bundling.Tar +import org.gradle.api.tasks.bundling.Zip +import org.gradle.crypto.checksum.Checksum +import org.kordamp.gradle.util.StringUtils +import org.kordamp.jreleaser.gradle.plugin.JReleaserExtension +import org.kordamp.jreleaser.gradle.plugin.dsl.Artifact +import org.kordamp.jreleaser.gradle.plugin.internal.dsl.DistributionImpl +import org.kordamp.jreleaser.gradle.plugin.tasks.JReleaserConfigTask +import org.kordamp.jreleaser.gradle.plugin.tasks.JReleaserTemplateGeneratorTask +import org.kordamp.jreleaser.gradle.plugin.tasks.JReleaserToolPackagerTask +import org.kordamp.jreleaser.gradle.plugin.tasks.JReleaserToolProcessorTask +import org.kordamp.jreleaser.model.Distribution +import org.kordamp.jreleaser.model.JReleaserModel +import org.kordamp.jreleaser.model.JReleaserModelValidator + +import static org.kordamp.gradle.util.StringUtils.isBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class JReleaserProjectConfigurer { + private static final String JRELEASER_GROUP = 'JReleaser' + + static void configure(Project project) { + JReleaserExtensionImpl extension = (JReleaserExtensionImpl) project.extensions.findByType(JReleaserExtension) + + boolean hasDistributionPlugin = configureDefaultDistribution(project, extension) + + String javaVersion = '' + if (project.hasProperty('targetCompatibility')) { + javaVersion = String.valueOf(project.findProperty('targetCompatibility')) + } + if (project.hasProperty('compilerRelease')) { + javaVersion = String.valueOf(project.findProperty('compilerRelease')) + } + if (isBlank(javaVersion)) { + javaVersion = JavaVersion.current().toString() + } + javaVersion += '+' + + JReleaserModel model = extension.toModel() + model.getProject().setJavaVersion(javaVersion) + JReleaserLoggerAdapter logger = new JReleaserLoggerAdapter(project.logger) + List errors = JReleaserModelValidator.validate(logger, project.projectDir.toPath(), model) + if (errors) { + project.logger.error('== JReleaser ==') + errors.each { project.logger.error(it) } + throw new GradleException("JReleaser for project ${project.name} has not been properly configured.") + } + + project.tasks.register('jreleaserConfig', JReleaserConfigTask, + new Action() { + @Override + void execute(JReleaserConfigTask t) { + t.group = JRELEASER_GROUP + t.description = 'Outputs current JReleaser configuration' + t.jreleaserModel.set(model) + } + }) + + project.tasks.register('generateJReleaserTemplate', JReleaserTemplateGeneratorTask, + new Action() { + @Override + void execute(JReleaserTemplateGeneratorTask t) { + t.group = JRELEASER_GROUP + t.description = 'Generates a tool file template' + t.outputDirectory.set(project.layout + .projectDirectory + .dir('src/distributions')) + } + }) + + Set> checksumTasks = new LinkedHashSet<>() + Set> prepareTasks = new LinkedHashSet<>() + Set> packageTasks = new LinkedHashSet<>() + model.distributions.values().each { distribution -> + List> tasks = configureDistribution(project, model, distribution) + if (tasks) { + checksumTasks << tasks[0] + prepareTasks << tasks[1] + packageTasks << tasks[2] + } + } + + if (checksumTasks) { + project.tasks.register('checksum', DefaultTask, + new Action() { + @Override + void execute(DefaultTask t) { + t.group = JRELEASER_GROUP + t.description = 'Generates checksums for all distributions' + t.dependsOn(checksumTasks) + } + }) + } + + Set> jreleaserDeps = new LinkedHashSet<>() + if (prepareTasks) { + jreleaserDeps << project.tasks.register('jreleaserPrepare', DefaultTask, + new Action() { + @Override + void execute(DefaultTask t) { + t.group = JRELEASER_GROUP + t.description = 'Prepares all distributions' + t.dependsOn(prepareTasks) + if (hasDistributionPlugin) { + t.dependsOn('assembleDist') + } + } + }) + } + + if (packageTasks) { + jreleaserDeps << project.tasks.register('jreleaserPackage', DefaultTask, + new Action() { + @Override + void execute(DefaultTask t) { + t.group = JRELEASER_GROUP + t.description = 'Packages all distributions' + t.dependsOn(packageTasks) + } + }) + } + + if (jreleaserDeps) { + project.tasks.register('jreleaser', DefaultTask, + new Action() { + @Override + void execute(DefaultTask t) { + t.group = JRELEASER_GROUP + t.description = 'Invokes JReleaser on all distributions' + t.dependsOn(jreleaserDeps) + } + }) + } + } + + private static boolean configureDefaultDistribution(Project project, JReleaserExtensionImpl extension) { + boolean hasDistributionPlugin = project.plugins.findPlugin('distribution') + + if (hasDistributionPlugin) { + Action configurer = new Action() { + @Override + void execute(DistributionImpl distribution) { + if (distribution.artifacts.size() > 0) return + distribution.artifact(new Action() { + @Override + void execute(Artifact artifact) { + artifact.path.set(project.tasks + .named('distZip', Zip) + .flatMap({ tr -> tr.archiveFile })) + } + }) + distribution.artifact(new Action() { + @Override + void execute(Artifact artifact) { + artifact.path.set(project.tasks + .named('distTar', Tar) + .flatMap({ tr -> tr.archiveFile })) + } + }) + } + } + + String distributionName = project.name + if (extension.distributions.findByName(distributionName)) { + extension.distributions.named(project.name, DistributionImpl, configurer) + } else { + extension.distributions.register(project.name, configurer) + } + } + + return hasDistributionPlugin + } + + private static List> configureDistribution(Project project, + JReleaserModel model, + Distribution distribution) { + Set> prepareTasks = new LinkedHashSet<>() + Set> packageTasks = new LinkedHashSet<>() + + String distributionName = distribution.name + String normalizedDistributionName = StringUtils.getPropertyNameForLowerCaseHyphenSeparatedName(distributionName) + String capitalizedDistributionName = normalizedDistributionName.capitalize() + + for (String toolName : Distribution.supportedTools()) { + if (distribution.findTool(toolName)?.enabled) { + String taskName = "prepare${toolName.capitalize()}${capitalizedDistributionName}".toString() + TaskProvider prt = createJReleaserToolProcessorTask(project, taskName, distributionName, toolName, model, distribution) + prepareTasks << prt + taskName = "package${toolName.capitalize()}${capitalizedDistributionName}".toString() + packageTasks << createJReleaserToolPackagerTask(project, taskName, distributionName, toolName, model, distribution, prt) + } + } + + if (prepareTasks) { + Provider checksumDirectory = project.layout + .buildDirectory + .dir('jreleaser/checksums/' + distributionName) + + TaskProvider checksumTask = project.tasks.register("checksum${capitalizedDistributionName}", Checksum, + new Action() { + @Override + void execute(Checksum t) { + t.group = JRELEASER_GROUP + t.description = "Generates checksums for the ${distributionName} distribution" + t.files = project.files(distribution.artifacts*.path) + t.algorithm = Checksum.Algorithm.SHA256 + t.outputDir = checksumDirectory.get().asFile + } + }) + prepareTasks.each { TaskProvider tp -> + tp.configure(new Action() { + @Override + void execute(JReleaserToolProcessorTask t) { + t.dependsOn(checksumTask) + t.checksumDirectory.set(checksumDirectory) + } + }) + } + packageTasks.each { TaskProvider tp -> + tp.configure(new Action() { + @Override + void execute(JReleaserToolPackagerTask t) { + t.dependsOn(checksumTask) + t.checksumDirectory.set(checksumDirectory) + } + }) + } + + TaskProvider prepareTask = project.tasks.register("prepare${capitalizedDistributionName}", DefaultTask, + new Action() { + @Override + void execute(DefaultTask t) { + t.group = JRELEASER_GROUP + t.description = "Prepares the ${distributionName} distribution" + t.dependsOn(prepareTasks) + } + }) + + TaskProvider packageTask = project.tasks.register("package${capitalizedDistributionName}", DefaultTask, + new Action() { + @Override + void execute(DefaultTask t) { + t.group = JRELEASER_GROUP + t.description = "Packages the ${distributionName} distribution" + t.dependsOn(packageTasks) + } + }) + + // pleasing the static compiler ... *grumble* + List> list = [] + list.add(checksumTask) + list.add(prepareTask) + list.add(packageTask) + return list + } + + return [] + } + + private static TaskProvider createJReleaserToolProcessorTask(Project project, + String taskName, + String distributionName, + String toolName, + JReleaserModel model, + Distribution distribution) { + project.tasks.register(taskName, JReleaserToolProcessorTask, + new Action() { + @Override + void execute(JReleaserToolProcessorTask t) { + t.group = JRELEASER_GROUP + t.description = "Prepares distribution ${distributionName} with ${toolName.capitalize()}".toString() + t.distributionName.set(distributionName) + t.toolName.set(toolName) + t.jreleaserModel.set(model) + t.artifacts.from(distribution.artifacts*.path) + t.outputDirectory.set(project.layout + .buildDirectory + .dir("jreleaser/${distributionName}/${toolName}".toString())) + } + }) + } + + private static TaskProvider createJReleaserToolPackagerTask(Project project, + String taskName, + String distributionName, + String toolName, + JReleaserModel model, + Distribution distribution, + TaskProvider prt) { + project.tasks.register(taskName, JReleaserToolPackagerTask, + new Action() { + @Override + void execute(JReleaserToolPackagerTask t) { + t.group = JRELEASER_GROUP + t.description = "Packages distribution ${distributionName} with ${toolName.capitalize()}".toString() + t.dependsOn(prt) + t.distributionName.set(distributionName) + t.toolName.set(toolName) + t.jreleaserModel.set(model) + t.artifacts.from(distribution.artifacts*.path) + t.outputDirectory.set(project.layout + .buildDirectory + .dir("jreleaser/${distributionName}/${toolName}".toString())) + } + }) + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/KordampJReleaserAdapter.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/KordampJReleaserAdapter.groovy new file mode 100644 index 00000000..99c7d1dc --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/KordampJReleaserAdapter.groovy @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal + +import groovy.transform.CompileStatic +import org.gradle.api.Project +import org.kordamp.gradle.plugin.base.ProjectConfigurationExtension +import org.kordamp.gradle.plugin.base.model.License +import org.kordamp.jreleaser.gradle.plugin.JReleaserExtension + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class KordampJReleaserAdapter { + static void adapt(Project project) { + JReleaserExtension jreleaser = project.extensions.findByType(JReleaserExtension) + ProjectConfigurationExtension config = project.extensions.findByType(ProjectConfigurationExtension) + + if (!jreleaser.project.description.present) { + jreleaser.project.description.set(config.info.description) + } + if (!jreleaser.project.website.present) { + jreleaser.project.website.set(config.info.links.website) + } + if (!jreleaser.project.authors.present) { + jreleaser.project.authors.set(config.info.authors) + } + if (!jreleaser.project.tags.present) { + jreleaser.project.tags.set(config.info.tags) + } + if (!jreleaser.project.license.present) { + List licenses = config.licensing.allLicenses() + if (licenses.size() > 0) { + License license = licenses.find { + it.primary + } ?: licenses[0] + jreleaser.project.license.set(license.name) + } + } + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/AbstractPackagerTool.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/AbstractPackagerTool.groovy new file mode 100644 index 00000000..c900b9c9 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/AbstractPackagerTool.groovy @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Internal +import org.kordamp.jreleaser.gradle.plugin.dsl.PackagerTool + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +abstract class AbstractPackagerTool implements PackagerTool { + final Property enabled + final MapProperty extraProperties + + @Inject + AbstractPackagerTool(ObjectFactory objects) { + enabled = objects.property(Boolean).convention(Providers.notDefined()) + extraProperties = objects.mapProperty(String, Object).convention(Providers.notDefined()) + } + + protected abstract String toolName() + + @Internal + boolean isSet() { + enabled.present || + extraProperties.present + } + + protected void fillToolProperties(T tool) { + if (enabled.present) tool.enabled = enabled.get() + if (extraProperties.present) tool.extraProperties.putAll(extraProperties.get()) + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/AbstractTool.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/AbstractTool.groovy new file mode 100644 index 00000000..eaf54fed --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/AbstractTool.groovy @@ -0,0 +1,93 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.Transformer +import org.gradle.api.file.Directory +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Internal +import org.kordamp.jreleaser.gradle.plugin.dsl.Tool + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +abstract class AbstractTool implements Tool { + final Property enabled + final DirectoryProperty templateDirectory + final MapProperty extraProperties + final Property distributionName + + private final Provider distributionsDirProvider + private final DirectoryProperty localTemplate + + @Inject + AbstractTool(ObjectFactory objects, Provider distributionsDirProvider) { + this.distributionsDirProvider = distributionsDirProvider + enabled = objects.property(Boolean).convention(Providers.notDefined()) + templateDirectory = objects.directoryProperty().convention(Providers.notDefined()) + localTemplate = objects.directoryProperty() + extraProperties = objects.mapProperty(String, Object).convention(Providers.notDefined()) + distributionName = objects.property(String).convention(Providers.notDefined()) + + // FIXME: there's probable a better way to do this + Provider dd = distributionsDirProvider.flatMap(new Transformer, Directory>() { + @Override + Provider transform(Directory tr) { + return tr.dir(distributionName) + } + }) + Provider td = dd.flatMap(new Transformer, Directory>() { + @Override + Provider transform(Directory tr) { + return tr.dir(objects.property(String).convention(toolName())) + } + }) + + localTemplate.set(td) + } + + protected abstract String toolName() + + protected void fillToolProperties(T tool) { + tool.enabled = enabled.getOrElse(isSet()) + if (templateDirectory.present) { + tool.templateDirectory = templateDirectory.get().asFile.toPath() + } else if (localTemplate.asFile.get().exists()) { + tool.templateDirectory = localTemplate.asFile.get().toPath() + } + if (extraProperties.present) tool.extraProperties.putAll(extraProperties.get()) + } + + @Internal + boolean isSet() { + enabled.present || + templateDirectory.present || + extraProperties.present + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ArtifactImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ArtifactImpl.groovy new file mode 100644 index 00000000..ec02547f --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ArtifactImpl.groovy @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.kordamp.jreleaser.gradle.plugin.dsl.Artifact + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class ArtifactImpl implements Artifact { + String name + final RegularFileProperty path + final Property osClassifier + + @Inject + ArtifactImpl(ObjectFactory objects) { + path = objects.fileProperty().convention(Providers.notDefined()) + osClassifier = objects.property(String).convention(Providers.notDefined()) + } + + org.kordamp.jreleaser.model.Artifact toModel() { + org.kordamp.jreleaser.model.Artifact artifact = new org.kordamp.jreleaser.model.Artifact() + artifact.path = path.asFile.get().absolutePath + artifact.osClassifier = osClassifier.orNull + artifact + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/BrewImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/BrewImpl.groovy new file mode 100644 index 00000000..688c1097 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/BrewImpl.groovy @@ -0,0 +1,75 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.file.Directory +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.dsl.Brew + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class BrewImpl extends AbstractTool implements Brew { + final MapProperty dependencies + + @Inject + BrewImpl(ObjectFactory objects, Provider distributionsDirProvider) { + super(objects, distributionsDirProvider) + dependencies = objects.mapProperty(String, String).convention(Providers.notDefined()) + } + + @Override + protected String toolName() { 'brew' } + + @Override + void addDependency(String key, String value) { + if (isNotBlank(key) && isNotBlank(value)) { + dependencies.put(key.trim(), value.trim()) + } + } + + @Override + void addDependency(String key) { + if (isNotBlank(key)) { + dependencies.put(key.trim(), '') + } + } + + @Override + boolean isSet() { + return super.isSet() || dependencies.present + } + + org.kordamp.jreleaser.model.Brew toModel() { + org.kordamp.jreleaser.model.Brew tool = new org.kordamp.jreleaser.model.Brew() + fillToolProperties(tool) + if (dependencies.present) tool.dependencies.putAll(dependencies.get()) + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/BrewPackagerImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/BrewPackagerImpl.groovy new file mode 100644 index 00000000..226857e7 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/BrewPackagerImpl.groovy @@ -0,0 +1,74 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty +import org.kordamp.jreleaser.gradle.plugin.dsl.BrewPackager +import org.kordamp.jreleaser.model.Brew + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class BrewPackagerImpl extends AbstractPackagerTool implements BrewPackager { + final MapProperty dependencies + + @Inject + BrewPackagerImpl(ObjectFactory objects) { + super(objects) + dependencies = objects.mapProperty(String, String).convention(Providers.notDefined()) + } + + @Override + protected String toolName() { 'brew' } + + @Override + void addDependency(String key, String value) { + if (isNotBlank(key) && isNotBlank(value)) { + dependencies.put(key.trim(), value.trim()) + } + } + + @Override + void addDependency(String key) { + if (isNotBlank(key)) { + dependencies.put(key.trim(), '') + } + } + + @Override + boolean isSet() { + return super.isSet() || dependencies.present + } + + Brew toModel() { + Brew tool = new Brew() + fillToolProperties(tool) + if (dependencies.present) tool.dependencies.putAll(dependencies.get()) + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ChocolateyImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ChocolateyImpl.groovy new file mode 100644 index 00000000..e66fefd4 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ChocolateyImpl.groovy @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.file.Directory +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.dsl.Chocolatey + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class ChocolateyImpl extends AbstractTool implements Chocolatey { + @Inject + ChocolateyImpl(ObjectFactory objects, Provider distributionsDirProvider) { + super(objects, distributionsDirProvider) + } + + @Override + protected String toolName() { 'chocolatey' } + + org.kordamp.jreleaser.model.Chocolatey toModel() { + org.kordamp.jreleaser.model.Chocolatey tool = new org.kordamp.jreleaser.model.Chocolatey() + fillToolProperties(tool) + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ChocolateyPackagerImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ChocolateyPackagerImpl.groovy new file mode 100644 index 00000000..d9b24d56 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ChocolateyPackagerImpl.groovy @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.model.ObjectFactory +import org.kordamp.jreleaser.gradle.plugin.dsl.ChocolateyPackager +import org.kordamp.jreleaser.model.Chocolatey + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class ChocolateyPackagerImpl extends AbstractPackagerTool implements ChocolateyPackager { + @Inject + ChocolateyPackagerImpl(ObjectFactory objects) { + super(objects) + } + + @Override + protected String toolName() { 'chocolatey' } + + Chocolatey toModel() { + Chocolatey tool = new Chocolatey() + fillToolProperties(tool) + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/DistributionImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/DistributionImpl.groovy new file mode 100644 index 00000000..dbb4b852 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/DistributionImpl.groovy @@ -0,0 +1,151 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.Action +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.file.Directory +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.dsl.Artifact +import org.kordamp.jreleaser.gradle.plugin.dsl.Brew +import org.kordamp.jreleaser.gradle.plugin.dsl.Chocolatey +import org.kordamp.jreleaser.gradle.plugin.dsl.Distribution +import org.kordamp.jreleaser.gradle.plugin.dsl.Scoop +import org.kordamp.jreleaser.gradle.plugin.dsl.Snap +import org.kordamp.jreleaser.model.Distribution.DistributionType + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class DistributionImpl implements Distribution { + String name + final Property executable + final Property distributionType + final ListProperty tags + final MapProperty extraProperties + final BrewImpl brew + final ChocolateyImpl chocolatey + final ScoopImpl scoop + final SnapImpl snap + + final NamedDomainObjectContainer artifacts + private final Property myName + private final PackagersImpl packagers + + @Inject + DistributionImpl(ObjectFactory objects, Provider distributionsDirProvider, PackagersImpl packagers) { + this.packagers = packagers + executable = objects.property(String).convention(Providers.notDefined()) + myName = objects.property(String).convention(Providers.notDefined()) + distributionType = objects.property(DistributionType).convention(DistributionType.BINARY) + tags = objects.listProperty(String).convention(Providers.notDefined()) + extraProperties = objects.mapProperty(String, Object).convention(Providers.notDefined()) + + artifacts = objects.domainObjectContainer(ArtifactImpl, new NamedDomainObjectFactory() { + @Override + ArtifactImpl create(String name) { + ArtifactImpl artifact = objects.newInstance(ArtifactImpl, objects) + artifact.name = name + artifact + } + }) + + brew = objects.newInstance(BrewImpl, objects, distributionsDirProvider) + brew.distributionName.set(myName) + chocolatey = objects.newInstance(ChocolateyImpl, objects, distributionsDirProvider) + chocolatey.distributionName.set(myName) + scoop = objects.newInstance(ScoopImpl, objects, distributionsDirProvider) + scoop.distributionName.set(myName) + snap = objects.newInstance(SnapImpl, objects, distributionsDirProvider) + snap.distributionName.set(myName) + } + + void setName(String name) { + this.name = name + this.myName.set(name) + } + + @Override + void setDistributionType(String distributionType) { + this.distributionType.set(DistributionType.valueOf(distributionType.toUpperCase())) + } + + @Override + void addTag(String tag) { + if (isNotBlank(tag)) { + tags.add(tag.trim()) + } + } + + @Override + void artifact(Action action) { + ArtifactImpl artifact = artifacts.maybeCreate("artifact-${artifacts.size()}".toString()) + action.execute(artifact) + } + + @Override + void brew(Action action) { + action.execute(brew) + } + + @Override + void chocolatey(Action action) { + action.execute(chocolatey) + } + + @Override + void scoop(Action action) { + action.execute(scoop) + } + + @Override + void snap(Action action) { + action.execute(snap) + } + + org.kordamp.jreleaser.model.Distribution toModel() { + org.kordamp.jreleaser.model.Distribution distribution = new org.kordamp.jreleaser.model.Distribution() + distribution.name = name + distribution.executable = executable.orNull + distribution.type = distributionType.get() + for (ArtifactImpl artifact : artifacts) { + distribution.artifacts.add(artifact.toModel()) + } + distribution.tags = (List) tags.getOrElse([]) + if (extraProperties.present) distribution.extraProperties.putAll(extraProperties.get()) + if (brew.set) distribution.brew = brew.toModel() + if (chocolatey.set) distribution.chocolatey = chocolatey.toModel() + if (scoop.set) distribution.scoop = scoop.toModel() + if (snap.set) distribution.snap = snap.toModel() + distribution + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/PackagersImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/PackagersImpl.groovy new file mode 100644 index 00000000..166b8207 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/PackagersImpl.groovy @@ -0,0 +1,79 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.Action +import org.gradle.api.model.ObjectFactory +import org.kordamp.jreleaser.gradle.plugin.dsl.BrewPackager +import org.kordamp.jreleaser.gradle.plugin.dsl.ChocolateyPackager +import org.kordamp.jreleaser.gradle.plugin.dsl.Packagers +import org.kordamp.jreleaser.gradle.plugin.dsl.ScoopPackager +import org.kordamp.jreleaser.gradle.plugin.dsl.SnapPackager + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class PackagersImpl implements Packagers { + final BrewPackagerImpl brew + final ChocolateyPackagerImpl chocolatey + final ScoopPackagerImpl scoop + final SnapPackagerImpl snap + + @Inject + PackagersImpl(ObjectFactory objects) { + brew = objects.newInstance(BrewPackagerImpl, objects) + chocolatey = objects.newInstance(ChocolateyPackagerImpl, objects) + scoop = objects.newInstance(ScoopPackagerImpl, objects) + snap = objects.newInstance(SnapPackagerImpl, objects) + } + + @Override + void brew(Action action) { + action.execute(brew) + } + + @Override + void chocolatey(Action action) { + action.execute(chocolatey) + } + + @Override + void scoop(Action action) { + action.execute(scoop) + } + + @Override + void snap(Action action) { + action.execute(snap) + } + + org.kordamp.jreleaser.model.Packagers toModel() { + org.kordamp.jreleaser.model.Packagers packagers = new org.kordamp.jreleaser.model.Packagers() + if (brew.set) packagers.brew = brew.toModel() + if (chocolatey.set) packagers.chocolatey = chocolatey.toModel() + if (scoop.set) packagers.scoop = scoop.toModel() + if (snap.set) packagers.snap = snap.toModel() + packagers + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/PlugImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/PlugImpl.groovy new file mode 100644 index 00000000..001efac7 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/PlugImpl.groovy @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty +import org.kordamp.jreleaser.gradle.plugin.dsl.Plug + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class PlugImpl implements Plug { + String name + final MapProperty attributes + + @Inject + PlugImpl(ObjectFactory objects) { + attributes = objects.mapProperty(String, String).convention([:]) + } + + void setName(String name) { + this.name = name + } + + @Override + void addAttribute(String key, String value) { + if (isNotBlank(key) && isNotBlank(value)) { + attributes.put(key.trim(), value.trim()) + } + } + + org.kordamp.jreleaser.model.Plug toModel() { + org.kordamp.jreleaser.model.Plug plug = new org.kordamp.jreleaser.model.Plug() + plug.name = name + plug.attributes.putAll(attributes.get()) + plug + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ProjectImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ProjectImpl.groovy new file mode 100644 index 00000000..b8f72cca --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ProjectImpl.groovy @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.dsl.Project + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class ProjectImpl implements Project { + final Property name + final Property version + final Property description + final Property website + final Property license + final ListProperty authors + final ListProperty tags + final MapProperty extraProperties + + @Inject + ProjectImpl(ObjectFactory objects, + Provider nameProvider, + Provider descriptionProvider, + Provider versionProvider) { + name = objects.property(String).convention(nameProvider) + version = objects.property(String).convention(versionProvider) + description = objects.property(String).convention(descriptionProvider) + website = objects.property(String).convention(Providers.notDefined()) + license = objects.property(String).convention(Providers.notDefined()) + authors = objects.listProperty(String).convention(Providers.notDefined()) + tags = objects.listProperty(String).convention(Providers.notDefined()) + extraProperties = objects.mapProperty(String, Object).convention(Providers.notDefined()) + } + + @Override + void addAuthor(String name) { + if (isNotBlank(name)) { + authors.add(name.trim()) + } + } + + @Override + void addTag(String tag) { + if (isNotBlank(tag)) { + tags.add(tag.trim()) + } + } + + org.kordamp.jreleaser.model.Project toModel() { + org.kordamp.jreleaser.model.Project project = new org.kordamp.jreleaser.model.Project() + project.name = name.get() + project.version = version.get() + project.description = description.orNull + project.website = website.orNull + project.license = license.orNull + project.authors = (List) authors.getOrElse([]) + project.tags = (List) tags.getOrElse([]) + if (extraProperties.present) project.extraProperties.putAll(extraProperties.get()) + project + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ReleaseImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ReleaseImpl.groovy new file mode 100644 index 00000000..d061a9e6 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ReleaseImpl.groovy @@ -0,0 +1,105 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.kordamp.jreleaser.gradle.plugin.dsl.Release + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class ReleaseImpl implements Release { + final Property repoHost + final Property repoOwner + final Property repoName + final Property downloadUrlFormat + final Property releaseNotesUrlFormat + final Property latestReleaseUrlFormat + final Property issueTrackerUrlFormat + final Property repoType + final Property authorization + final Property tagName + final Property targetCommitish + final Property releaseName + final Property body + final Property apiEndpoint + final Property draft + final Property prerelease + final Property overwrite + final Property allowUploadToExisting + + @Inject + ReleaseImpl(ObjectFactory objects) { + repoHost = objects.property(String).convention(Providers.notDefined()) + repoOwner = objects.property(String).convention(Providers.notDefined()) + repoName = objects.property(String).convention(Providers.notDefined()) + downloadUrlFormat = objects.property(String).convention(Providers.notDefined()) + releaseNotesUrlFormat = objects.property(String).convention(Providers.notDefined()) + latestReleaseUrlFormat = objects.property(String).convention(Providers.notDefined()) + issueTrackerUrlFormat = objects.property(String).convention(Providers.notDefined()) + repoType = objects.property(org.kordamp.jreleaser.model.Release.RepoType) + .convention(org.kordamp.jreleaser.model.Release.RepoType.GITHUB) + + authorization = objects.property(String).convention(Providers.notDefined()) + tagName = objects.property(String).convention(Providers.notDefined()) + targetCommitish = objects.property(String).convention(Providers.notDefined()) + releaseName = objects.property(String).convention(Providers.notDefined()) + body = objects.property(String).convention(Providers.notDefined()) + apiEndpoint = objects.property(String).convention(Providers.notDefined()) + draft = objects.property(Boolean).convention(false) + prerelease = objects.property(Boolean).convention(false) + overwrite = objects.property(Boolean).convention(false) + allowUploadToExisting = objects.property(Boolean).convention(false) + } + + @Override + void setRepoType(String repoType) { + this.repoType.set(org.kordamp.jreleaser.model.Release.RepoType.valueOf(repoType.toUpperCase())) + } + + org.kordamp.jreleaser.model.Release toModel() { + org.kordamp.jreleaser.model.Release release = new org.kordamp.jreleaser.model.Release() + release.repoHost = repoHost.orNull + release.repoOwner = repoOwner.orNull + release.repoName = repoName.orNull + release.downloadUrlFormat = downloadUrlFormat.orNull + release.releaseNotesUrlFormat = releaseNotesUrlFormat.orNull + release.latestReleaseUrlFormat = latestReleaseUrlFormat.orNull + release.issueTrackerUrlFormat = issueTrackerUrlFormat.orNull + release.repoType = repoType.get() + release.authorization = authorization.orNull + release.tagName = tagName.orNull + release.targetCommitish = targetCommitish.orNull + release.releaseName = releaseName.orNull + release.body = body.orNull + release.draft = draft.get() + release.prerelease = prerelease.get() + release.overwrite = overwrite.get() + release.allowUploadToExisting = allowUploadToExisting.get() + release.apiEndpoint = apiEndpoint.orNull + release + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ScoopImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ScoopImpl.groovy new file mode 100644 index 00000000..85235491 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ScoopImpl.groovy @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.file.Directory +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.dsl.Scoop + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class ScoopImpl extends AbstractTool implements Scoop { + final Property checkverUrl + final Property autoupdateUrl + + @Inject + ScoopImpl(ObjectFactory objects, Provider distributionsDirProvider) { + super(objects, distributionsDirProvider) + checkverUrl = objects.property(String).convention(Providers.notDefined()) + autoupdateUrl = objects.property(String).convention(Providers.notDefined()) + } + + @Override + protected String toolName() { 'scoop' } + + @Override + boolean isSet() { + return super.isSet() || + checkverUrl.present || + autoupdateUrl.present + } + + org.kordamp.jreleaser.model.Scoop toModel() { + org.kordamp.jreleaser.model.Scoop tool = new org.kordamp.jreleaser.model.Scoop() + fillToolProperties(tool) + tool.checkverUrl = checkverUrl.orNull + tool.autoupdateUrl = autoupdateUrl.orNull + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ScoopPackagerImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ScoopPackagerImpl.groovy new file mode 100644 index 00000000..2b148dcd --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/ScoopPackagerImpl.groovy @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.kordamp.jreleaser.gradle.plugin.dsl.ScoopPackager +import org.kordamp.jreleaser.model.Scoop + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class ScoopPackagerImpl extends AbstractPackagerTool implements ScoopPackager { + final Property checkverUrl + final Property autoupdateUrl + + @Inject + ScoopPackagerImpl(ObjectFactory objects) { + super(objects) + checkverUrl = objects.property(String).convention(Providers.notDefined()) + autoupdateUrl = objects.property(String).convention(Providers.notDefined()) + } + + @Override + protected String toolName() { 'scoop' } + + @Override + boolean isSet() { + return super.isSet() || + checkverUrl.present || + autoupdateUrl.present + } + + Scoop toModel() { + Scoop tool = new Scoop() + fillToolProperties(tool) + tool.checkverUrl = checkverUrl.orNull + tool.autoupdateUrl = autoupdateUrl.orNull + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SlotImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SlotImpl.groovy new file mode 100644 index 00000000..fb79c842 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SlotImpl.groovy @@ -0,0 +1,83 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty +import org.kordamp.jreleaser.gradle.plugin.dsl.Slot + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class SlotImpl implements Slot { + String name + final MapProperty attributes + final ListProperty reads + final ListProperty writes + + @Inject + SlotImpl(ObjectFactory objects) { + attributes = objects.mapProperty(String, String).convention([:]) + reads = objects.listProperty(String).convention(Providers.notDefined()) + writes = objects.listProperty(String).convention(Providers.notDefined()) + } + + void setName(String name) { + this.name = name + } + + @Override + void addAttribute(String key, String value) { + if (isNotBlank(key) && isNotBlank(value)) { + attributes.put(key.trim(), value.trim()) + } + } + + @Override + void addRead(String read) { + if (isNotBlank(read)) { + reads.add(read.trim()) + } + } + + @Override + void addWrite(String write) { + if (isNotBlank(write)) { + writes.add(write.trim()) + } + } + + org.kordamp.jreleaser.model.Slot toModel() { + org.kordamp.jreleaser.model.Slot slot = new org.kordamp.jreleaser.model.Slot() + slot.name = name + slot.attributes.putAll(attributes.get()) + slot.reads = (List) reads.getOrElse([]) + slot.writes = (List) writes.getOrElse([]) + slot + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SnapImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SnapImpl.groovy new file mode 100644 index 00000000..3f7e0fde --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SnapImpl.groovy @@ -0,0 +1,121 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.file.Directory +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.kordamp.jreleaser.gradle.plugin.dsl.Snap +import org.kordamp.jreleaser.model.Plug +import org.kordamp.jreleaser.model.Slot + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class SnapImpl extends AbstractTool implements Snap { + final Property base + final Property grade + final Property confinement + final RegularFileProperty exportedLogin + final ListProperty localPlugs + final NamedDomainObjectContainer plugs + final NamedDomainObjectContainer slots + + @Inject + SnapImpl(ObjectFactory objects, Provider distributionsDirProvider) { + super(objects, distributionsDirProvider) + base = objects.property(String).convention(Providers.notDefined()) + grade = objects.property(String).convention(Providers.notDefined()) + confinement = objects.property(String).convention(Providers.notDefined()) + exportedLogin = objects.fileProperty().convention(Providers.notDefined()) + localPlugs = objects.listProperty(String).convention(Providers.notDefined()) + + plugs = objects.domainObjectContainer(PlugImpl, new NamedDomainObjectFactory() { + @Override + PlugImpl create(String name) { + PlugImpl plug = objects.newInstance(PlugImpl, objects) + plug.name = name + return plug + } + }) + + slots = objects.domainObjectContainer(SlotImpl, new NamedDomainObjectFactory() { + @Override + SlotImpl create(String name) { + SlotImpl slot = objects.newInstance(SlotImpl, objects) + slot.name = name + return slot + } + }) + } + + @Override + protected String toolName() { 'snap' } + + @Override + void addLocalPlug(String plug) { + if (isNotBlank(plug)) { + localPlugs.add(plug.trim()) + } + } + + @Override + boolean isSet() { + return super.isSet() || + base.present || + grade.present || + confinement.present || + exportedLogin.present || + localPlugs.present || + plugs.size() || + slots.size() + } + + org.kordamp.jreleaser.model.Snap toModel() { + org.kordamp.jreleaser.model.Snap tool = new org.kordamp.jreleaser.model.Snap() + fillToolProperties(tool) + tool.base = base.orNull + tool.grade = grade.orNull + tool.confinement = confinement.orNull + if (exportedLogin.present) { + tool.exportedLogin = exportedLogin.get().asFile.absolutePath + } + tool.localPlugs = (List) localPlugs.getOrElse([]) + tool.plugs.addAll(plugs.collect([]) { PlugImpl plug -> + plug.toModel() + } as Set) + tool.slots.addAll(slots.collect([]) { SlotImpl slot -> + slot.toModel() + } as Set) + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SnapPackagerImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SnapPackagerImpl.groovy new file mode 100644 index 00000000..7f3cab9d --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/internal/dsl/SnapPackagerImpl.groovy @@ -0,0 +1,120 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.internal.dsl + +import groovy.transform.CompileStatic +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.internal.provider.Providers +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.kordamp.jreleaser.gradle.plugin.dsl.SnapPackager +import org.kordamp.jreleaser.model.Plug +import org.kordamp.jreleaser.model.Slot +import org.kordamp.jreleaser.model.Snap + +import javax.inject.Inject + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +class SnapPackagerImpl extends AbstractPackagerTool implements SnapPackager { + final Property base + final Property grade + final Property confinement + final RegularFileProperty exportedLogin + final ListProperty localPlugs + final NamedDomainObjectContainer plugs + final NamedDomainObjectContainer slots + + @Inject + SnapPackagerImpl(ObjectFactory objects) { + super(objects) + base = objects.property(String).convention(Providers.notDefined()) + grade = objects.property(String).convention(Providers.notDefined()) + confinement = objects.property(String).convention(Providers.notDefined()) + exportedLogin = objects.fileProperty().convention(Providers.notDefined()) + localPlugs = objects.listProperty(String).convention(Providers.notDefined()) + + plugs = objects.domainObjectContainer(PlugImpl, new NamedDomainObjectFactory() { + @Override + PlugImpl create(String name) { + PlugImpl plug = objects.newInstance(PlugImpl, objects) + plug.name = name + return plug + } + }) + + slots = objects.domainObjectContainer(SlotImpl, new NamedDomainObjectFactory() { + @Override + SlotImpl create(String name) { + SlotImpl slot = objects.newInstance(SlotImpl, objects) + slot.name = name + return slot + } + }) + } + + @Override + protected String toolName() { 'snap' } + + @Override + void addLocalPlug(String plug) { + if (isNotBlank(plug)) { + localPlugs.add(plug.trim()) + } + } + + @Override + boolean isSet() { + return super.isSet() || + base.present || + grade.present || + confinement.present || + exportedLogin.present || + localPlugs.present || + plugs.size() || + slots.size() + } + + Snap toModel() { + Snap tool = new Snap() + fillToolProperties(tool) + tool.base = base.orNull + tool.grade = grade.orNull + tool.confinement = confinement.orNull + if (exportedLogin.present) { + tool.exportedLogin = exportedLogin.get().asFile.absolutePath + } + tool.localPlugs = (List) localPlugs.getOrElse([]) + tool.plugs.addAll(plugs.collect([]) { PlugImpl plug -> + plug.toModel() + } as Set) + tool.slots.addAll(slots.collect([]) { SlotImpl slot -> + slot.toModel() + } as Set) + tool + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserConfigTask.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserConfigTask.groovy new file mode 100644 index 00000000..bf259eaa --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserConfigTask.groovy @@ -0,0 +1,50 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.tasks + +import groovy.transform.CompileStatic +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.TaskAction +import org.kordamp.gradle.plugin.base.tasks.AbstractSettingsTask +import org.kordamp.jreleaser.model.JReleaserModel + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +abstract class JReleaserConfigTask extends AbstractSettingsTask { + @Internal + final Property jreleaserModel + + @Inject + JReleaserConfigTask(ObjectFactory objects) { + jreleaserModel = objects.property(JReleaserModel) + } + + @TaskAction + void createOutput() { + println '== JReleaser ==' + doPrintMap(jreleaserModel.get().asMap(), 0) + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserTemplateGeneratorTask.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserTemplateGeneratorTask.groovy new file mode 100644 index 00000000..eaeb8793 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserTemplateGeneratorTask.groovy @@ -0,0 +1,113 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.tasks + +import groovy.transform.CompileStatic +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.options.Option +import org.gradle.api.tasks.options.OptionValues +import org.kordamp.jreleaser.gradle.plugin.internal.JReleaserLoggerAdapter +import org.kordamp.jreleaser.model.Distribution +import org.kordamp.jreleaser.templates.TemplateGenerator + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +abstract class JReleaserTemplateGeneratorTask extends DefaultTask { + @Internal + final Property distributionType + + @Input + final Property distributionName + + @Input + final Property toolName + + @OutputDirectory + final DirectoryProperty outputDirectory + + @Input + final Property overwrite + + @Inject + JReleaserTemplateGeneratorTask(ObjectFactory objects) { + distributionType = objects.property(Distribution.DistributionType).convention(Distribution.DistributionType.BINARY) + distributionName = objects.property(String) + toolName = objects.property(String) + overwrite = objects.property(Boolean).convention(false) + + outputDirectory = objects.directoryProperty() + } + + @Option(option = 'overwrite', description = 'Overwrite existing files (OPTIONAL).') + void setOverwrite(boolean overwrite) { + this.overwrite.set(overwrite) + } + + @Option(option = 'distribution-name', description = 'The name of the distribution (REQUIRED).') + void setDistributionName(String distributionName) { + this.distributionName.set(distributionName) + } + + @Option(option = 'tool-name', description = 'The name of the tool (REQUIRED).') + void setToolName(String toolName) { + this.toolName.set(toolName) + } + + @Option(option = 'distribution-type', description = 'The type of the distribution (REQUIRED).') + void setAction(Distribution.DistributionType distributionType) { + this.distributionType.set(distributionType) + } + + @OptionValues('distribution-type') + List getDistributionTypes() { + return new ArrayList(Arrays.asList(Distribution.DistributionType.values())) + } + + @TaskAction + void createOutput() { + boolean result = TemplateGenerator.builder() + .logger(new JReleaserLoggerAdapter(project.logger)) + .distributionName(distributionName.get()) + .distributionType(distributionType.get()) + .toolName(toolName.get()) + .outputDirectory(outputDirectory.get().asFile.toPath()) + .overwrite(overwrite.get()) + .build() + .generate() + + if (result) { + println('Template generated at ' + + outputDirectory.get().asFile.toPath() + .resolve(distributionName.get()) + .resolve(toolName.get())) + } + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserToolPackagerTask.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserToolPackagerTask.groovy new file mode 100644 index 00000000..d94f1fbe --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserToolPackagerTask.groovy @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.tasks + +import groovy.transform.CompileStatic +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.kordamp.jreleaser.gradle.plugin.internal.JReleaserLoggerAdapter +import org.kordamp.jreleaser.model.JReleaserModel +import org.kordamp.jreleaser.tools.DistributionProcessor + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +abstract class JReleaserToolPackagerTask extends DefaultTask { + @Internal + final Property jreleaserModel + + @Input + final Property distributionName + + @Input + final Property toolName + + @InputFiles + final ConfigurableFileCollection artifacts + + @InputDirectory + final DirectoryProperty checksumDirectory + + @OutputDirectory + final DirectoryProperty outputDirectory + + @Inject + JReleaserToolPackagerTask(ObjectFactory objects) { + jreleaserModel = objects.property(JReleaserModel) + distributionName = objects.property(String) + toolName = objects.property(String) + artifacts = objects.fileCollection() + checksumDirectory = objects.directoryProperty() + + outputDirectory = objects.directoryProperty() + } + + @TaskAction + void createOutput() { + boolean result = DistributionProcessor.builder() + .logger(new JReleaserLoggerAdapter(project.logger)) + .model(jreleaserModel.get()) + .distributionName(distributionName.get()) + .toolName(toolName.get()) + .checksumDirectory(checksumDirectory.get().asFile.toPath()) + .outputDirectory(outputDirectory.get().asFile.toPath()) + .build() + .packageDistribution() + + if (result) { + println("Packaged ${distributionName.get()} distribution with tool ${toolName.get()}") + } + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserToolProcessorTask.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserToolProcessorTask.groovy new file mode 100644 index 00000000..3850be35 --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/kordamp/jreleaser/gradle/plugin/tasks/JReleaserToolProcessorTask.groovy @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.gradle.plugin.tasks + +import groovy.transform.CompileStatic +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.kordamp.jreleaser.gradle.plugin.internal.JReleaserLoggerAdapter +import org.kordamp.jreleaser.model.JReleaserModel +import org.kordamp.jreleaser.tools.DistributionProcessor + +import javax.inject.Inject + +/** + * + * @author Andres Almiray + * @since 0.1.0 + */ +@CompileStatic +abstract class JReleaserToolProcessorTask extends DefaultTask { + @Internal + final Property jreleaserModel + + @Input + final Property distributionName + + @Input + final Property toolName + + @InputFiles + final ConfigurableFileCollection artifacts + + @InputDirectory + final DirectoryProperty checksumDirectory + + @OutputDirectory + final DirectoryProperty outputDirectory + + @Inject + JReleaserToolProcessorTask(ObjectFactory objects) { + jreleaserModel = objects.property(JReleaserModel) + distributionName = objects.property(String) + toolName = objects.property(String) + artifacts = objects.fileCollection() + checksumDirectory = objects.directoryProperty() + + outputDirectory = objects.directoryProperty() + } + + @TaskAction + void createOutput() { + boolean result = DistributionProcessor.builder() + .logger(new JReleaserLoggerAdapter(project.logger)) + .model(jreleaserModel.get()) + .distributionName(distributionName.get()) + .toolName(toolName.get()) + .checksumDirectory(checksumDirectory.get().asFile.toPath()) + .outputDirectory(outputDirectory.get().asFile.toPath()) + .build() + .prepareDistribution() + + if (result) { + println("Prepared ${distributionName.get()} distribution with tool ${toolName.get()}") + } + } +} diff --git a/plugins/jreleaser-gradle-plugin/src/main/resources/org/kordamp/jreleaser/gradle/plugin/Banner.properties b/plugins/jreleaser-gradle-plugin/src/main/resources/org/kordamp/jreleaser/gradle/plugin/Banner.properties new file mode 100644 index 00000000..d841c0dc --- /dev/null +++ b/plugins/jreleaser-gradle-plugin/src/main/resources/org/kordamp/jreleaser/gradle/plugin/Banner.properties @@ -0,0 +1,22 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +product.version=$version +product.id=$id +product.name=$name +product.banner={0} {1}. Consider becoming a patron at https://www.patreon.com/aalmiray \ No newline at end of file diff --git a/plugins/jreleaser-maven-plugin/gradle.properties b/plugins/jreleaser-maven-plugin/gradle.properties new file mode 100644 index 00000000..cc39f168 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/gradle.properties @@ -0,0 +1,21 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +project_description = JReleaser Maven Plugin +pluginDisplayName = JReleaser Maven Plugin \ No newline at end of file diff --git a/plugins/jreleaser-maven-plugin/jreleaser-maven-plugin.gradle b/plugins/jreleaser-maven-plugin/jreleaser-maven-plugin.gradle new file mode 100644 index 00000000..f5512dd7 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/jreleaser-maven-plugin.gradle @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id 'de.benediktritter.maven-plugin-development' version '0.3.1' +} + +config { + licensing { + exclude 'build/mavenPlugin/**' + } +} + +mavenPlugin { + helpMojoPackage = 'org.kordamp.jreleaser.maven.plugin' +} + +dependencies { + api project(':jreleaser-model') + api project(':jreleaser-tools') + api project(':jreleaser-templates') + api "org.slf4j:slf4j-api:$slf4jVersion" + + implementation "org.apache.maven:maven-plugin-api:$mavenVersion" + + compileOnly "org.apache.maven:maven-core:$mavenVersion" + compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:$mavenVersion" +} + +license { + exclude '**/build/**/pom.xml' + exclude '**/HelpMojo.java' +} + +processResources { + inputs.property('version', project.version) + filesMatching(['**/*.properties']) { + expand( + 'version': project.version, + 'id': 'jrleaser', + 'name': project.pluginDisplayName + ) + } +} \ No newline at end of file diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractDomain.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractDomain.java new file mode 100644 index 00000000..2bc541fd --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractDomain.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractDomain { + public abstract Map asMap(); +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractJReleaserMojo.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractJReleaserMojo.java new file mode 100644 index 00000000..a1464d9e --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractJReleaserMojo.java @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.kordamp.jreleaser.maven.plugin.internal.JReleaserLoggerAdapter; +import org.kordamp.jreleaser.util.Logger; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractJReleaserMojo extends AbstractMojo { + /** + * The project whose model will be checked. + */ + @Parameter(defaultValue = "${project}", readonly = true, required = true) + protected MavenProject project; + + protected Logger getLogger() { + return new JReleaserLoggerAdapter(getLog()); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractTool.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractTool.java new file mode 100644 index 00000000..c355aba5 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/AbstractTool.java @@ -0,0 +1,116 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractTool extends AbstractDomain implements Tool { + protected final String toolName; + protected final Map extraProperties = new LinkedHashMap<>(); + protected Boolean enabled; + protected boolean enabledSet; + protected Path templateDirectory; + + protected AbstractTool(String toolName) { + this.toolName = toolName; + } + + void setAll(AbstractTool tool) { + this.enabled = tool.enabled; + this.enabledSet = tool.enabledSet; + this.templateDirectory = tool.templateDirectory; + setExtraProperties(tool.extraProperties); + } + + @Override + public Boolean isEnabled() { + return enabled != null && enabled; + } + + @Override + public void setEnabled(Boolean enabled) { + this.enabledSet = true; + this.enabled = enabled; + } + + @Override + public boolean isEnabledSet() { + return enabledSet; + } + + @Override + public String getToolName() { + return toolName; + } + + @Override + public Path getTemplateDirectory() { + return templateDirectory; + } + + @Override + public void setTemplateDirectory(Path templateDirectory) { + this.templateDirectory = templateDirectory; + } + + @Override + public Map getExtraProperties() { + return extraProperties; + } + + @Override + public void setExtraProperties(Map extraProperties) { + this.extraProperties.clear(); + this.extraProperties.putAll(extraProperties); + } + + @Override + public void addExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + public boolean isSet() { + return enabledSet || + null != templateDirectory || + !extraProperties.isEmpty(); + } + + @Override + public final Map asMap() { + if (!isSet()) return Collections.emptyMap(); + + Map props = new LinkedHashMap<>(); + props.put("enabled", isEnabled()); + props.put("templateDirectory", templateDirectory); + asMap(props); + props.put("extraProperties", extraProperties); + + Map map = new LinkedHashMap<>(); + map.put(getToolName(), props); + return map; + } + + protected abstract void asMap(Map props); +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Artifact.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Artifact.java new file mode 100644 index 00000000..7a7d8fff --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Artifact.java @@ -0,0 +1,73 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Artifact extends AbstractDomain { + private String path; + private String hash; + private String osClassifier; + private String javaVersion; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getOsClassifier() { + return osClassifier; + } + + public void setOsClassifier(String osClassifier) { + this.osClassifier = osClassifier; + } + + public String getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("path", path); + map.put("hash", hash); + map.put("osClassifier", osClassifier); + map.put("javaVersion", javaVersion); + return map; + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Banner.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Banner.java new file mode 100644 index 00000000..9b1e3993 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Banner.java @@ -0,0 +1,122 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; +import java.util.Scanner; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +final class Banner { + private static final Banner b = new Banner(); + private final ResourceBundle bundle = ResourceBundle.getBundle(Banner.class.getName()); + private final String productVersion = bundle.getString("product.version"); + private final String productId = bundle.getString("product.id"); + private final String productName = bundle.getString("product.name"); + private final String banner = MessageFormat.format(bundle.getString("product.banner"), productName, productVersion); + private final List visited = new ArrayList<>(); + + private Banner() { + // nooop + } + + public static void display(MavenProject project, Log log) { + MavenProject element = project; + MavenProject root = project; + while (true) { + if (element.getParent() == null || element.getParent() == element) { + break; + } + root = element.getParent(); + } + if (b.visited.contains(root.getName())) { + return; + } + + b.visited.add(root.getName()); + + try { + File parent = new File(System.getProperty("user.home"), "/.m2/caches"); + File markerFile = getMarkerFile(parent, b); + if (!markerFile.exists()) { + System.out.println(b.banner); + markerFile.getParentFile().mkdirs(); + PrintStream out = new PrintStream(new FileOutputStream(markerFile)); + out.println("1"); + out.close(); + writeQuietly(markerFile, "1"); + } else { + try { + int count = Integer.parseInt(readQuietly(markerFile)); + if (count < 3) { + System.out.println(b.banner); + } + writeQuietly(markerFile, (count + 1) + ""); + } catch (NumberFormatException e) { + writeQuietly(markerFile, "1"); + System.out.println(b.banner); + } + } + } catch (IOException ignored) { + // noop + } + } + + private static void writeQuietly(File file, String text) { + try { + PrintStream out = new PrintStream(new FileOutputStream(file)); + out.println(text); + out.close(); + } catch (IOException ignored) { + // ignored + } + } + + private static String readQuietly(File file) { + try { + Scanner in = new Scanner(new FileInputStream(file)); + return in.next(); + } catch (Exception ignored) { + return ""; + } + } + + private static File getMarkerFile(File parent, Banner b) { + return new File(parent, + "kordamp" + + File.separator + + b.productId + + File.separator + + b.productVersion + + File.separator + + "marker.txt"); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Brew.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Brew.java new file mode 100644 index 00000000..205b2878 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Brew.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Brew extends AbstractTool { + public static final String TOOL_NAME = "brew"; + + private final Map dependencies = new LinkedHashMap<>(); + + public Brew() { + super(TOOL_NAME); + } + + void setAll(Brew brew) { + super.setAll(brew); + setDependencies(brew.dependencies); + } + + public Map getDependencies() { + return dependencies; + } + + public void setDependencies(Map dependencies) { + this.dependencies.clear(); + this.dependencies.putAll(dependencies); + } + + public void addDependencies(Map dependencies) { + this.dependencies.putAll(dependencies); + } + + public void addDependency(String key, String value) { + dependencies.put(key, value); + } + + public void addDependency(String key) { + dependencies.put(key, ""); + } + + @Override + public boolean isSet() { + return super.isSet() || + !dependencies.isEmpty(); + } + + @Override + protected void asMap(Map props) { + props.put("dependencies", dependencies); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Chocolatey.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Chocolatey.java new file mode 100644 index 00000000..48cbe9c4 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Chocolatey.java @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Chocolatey extends AbstractTool { + public static final String TOOL_NAME = "chocolatey"; + + public Chocolatey() { + super(TOOL_NAME); + } + + @Override + protected void asMap(Map props) { + // empty + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/ConfigMojo.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/ConfigMojo.java new file mode 100644 index 00000000..17103c70 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/ConfigMojo.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.kordamp.jreleaser.maven.plugin.internal.JReleaserModelConfigurer; +import org.kordamp.jreleaser.maven.plugin.internal.JReleaserModelConverter; +import org.kordamp.jreleaser.maven.plugin.internal.JReleaserModelPrinter; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.JReleaserModelValidator; + +import java.io.PrintWriter; +import java.util.List; + +@Mojo(name = "config") +public class ConfigMojo extends AbstractJReleaserMojo { + @Parameter(required = true) + private Jreleaser jreleaser; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + Banner.display(project, getLog()); + + JReleaserModel jreleaserModel = JReleaserModelConverter.convert(jreleaser); + JReleaserModelConfigurer.configure(jreleaserModel, project); + List errors = JReleaserModelValidator.validate(getLogger(), project.getBasedir().toPath(), jreleaserModel); + if (!errors.isEmpty()) { + getLog().error("== JReleaser =="); + errors.forEach(getLog()::error); + throw new MojoExecutionException("JReleaser for project " + project.getArtifactId() + " has not been properly configured."); + } + + new JReleaserModelPrinter(new PrintWriter(System.out, true)).print(jreleaserModel.asMap()); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Distribution.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Distribution.java new file mode 100644 index 00000000..2668e678 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Distribution.java @@ -0,0 +1,218 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.kordamp.jreleaser.util.StringUtils.isBlank; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Distribution extends Packagers implements ExtraProperties { + private final List tags = new ArrayList<>(); + private final Map extraProperties = new LinkedHashMap<>(); + private final List artifacts = new ArrayList<>(); + private String name; + private DistributionType type = DistributionType.BINARY; + private String executable; + private String javaVersion; + + void setAll(Distribution distribution) { + super.setAll(distribution); + this.name = distribution.name; + this.type = distribution.type; + this.executable = distribution.executable; + this.javaVersion = distribution.javaVersion; + setTags(distribution.tags); + setExtraProperties(distribution.extraProperties); + setArtifacts(distribution.artifacts); + } + + public DistributionType getType() { + return type; + } + + public void setType(DistributionType type) { + this.type = type; + } + + public void setType(String type) { + this.type = DistributionType.valueOf(type.replaceAll(" ", "_") + .replaceAll("-", "_") + .toUpperCase()); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getExecutable() { + return executable; + } + + public void setExecutable(String executable) { + this.executable = executable; + } + + public String getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + public List getArtifacts() { + return artifacts; + } + + public void setArtifacts(List artifacts) { + this.artifacts.clear(); + this.artifacts.addAll(artifacts); + } + + public void addArtifacts(List artifacts) { + this.artifacts.addAll(artifacts); + } + + public void addArtifact(Artifact artifact) { + if (null != artifact) { + this.artifacts.add(artifact); + } + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags.clear(); + this.tags.addAll(tags); + } + + public void addTags(List tags) { + this.tags.addAll(tags); + } + + public void addTag(String tag) { + if (isNotBlank(tag)) { + this.tags.add(tag.trim()); + } + } + + public void removeTag(String tag) { + if (isNotBlank(tag)) { + this.tags.remove(tag.trim()); + } + } + + @Override + public Map getExtraProperties() { + return extraProperties; + } + + @Override + public void setExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + @Override + public void addExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + // --== TOOLs ==-- + + public T findTool(String name) { + if (isBlank(name)) { + throw new IllegalArgumentException("Tool name must not be blank"); + } + + return resolveTool(name); + } + + public T getTool(String name) { + T tool = findTool(name); + if (null != tool) { + return tool; + } + throw new IllegalArgumentException("Tool '" + name + "' has not been configured"); + } + + private T resolveTool(String name) { + switch (name.toLowerCase().trim()) { + case Brew.TOOL_NAME: + return (T) getBrew(); + case Chocolatey.TOOL_NAME: + return (T) getChocolatey(); + case Scoop.TOOL_NAME: + return (T) getScoop(); + case Snap.TOOL_NAME: + return (T) getSnap(); + default: + throw new IllegalArgumentException("Unsupported tool '" + name + "'"); + } + } + + @Override + public Map asMap() { + Map props = new LinkedHashMap<>(); + props.put("type", type); + props.put("executable", executable); + props.put("javaVersion", javaVersion); + props.put("artifacts", artifacts.stream() + .map(Artifact::asMap) + .collect(Collectors.toList())); + props.put("tags", tags); + props.put("extraProperties", extraProperties); + props.putAll(super.asMap()); + + Map map = new LinkedHashMap<>(); + map.put(name, props); + return map; + } + + public static Set supportedTools() { + Set set = new LinkedHashSet<>(); + set.add(Brew.TOOL_NAME); + set.add(Chocolatey.TOOL_NAME); + set.add(Scoop.TOOL_NAME); + set.add(Snap.TOOL_NAME); + return Collections.unmodifiableSet(set); + } + + public enum DistributionType { + BINARY, + SINGLE_JAR + // NATIVE_IMAGE, + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/ExtraProperties.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/ExtraProperties.java new file mode 100644 index 00000000..7a0fdbc9 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/ExtraProperties.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface ExtraProperties { + Map getExtraProperties(); + + void setExtraProperties(Map properties); + + void addExtraProperties(Map properties); +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/GenerateTemplateMojo.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/GenerateTemplateMojo.java new file mode 100644 index 00000000..200e2c7a --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/GenerateTemplateMojo.java @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.kordamp.jreleaser.model.Distribution; +import org.kordamp.jreleaser.templates.TemplateGenerationException; +import org.kordamp.jreleaser.templates.TemplateGenerator; + +import java.nio.file.Path; +import java.nio.file.Paths; + +@Mojo(name = "generate-template") +public class GenerateTemplateMojo extends AbstractJReleaserMojo { + /** + * Skip execution. + */ + @Parameter(property = "jreleaser.generate.template.skip") + private boolean skip; + + /** + * The name of the distribution + */ + @Parameter(property = "jreleaser.generate.template.distributionName", required = true) + private String distributionName; + + /** + * The type of the distribution + */ + @Parameter(property = "jreleaser.generate.template.distributionType", defaultValue = "BINARY") + private Distribution.DistributionType distributionType = Distribution.DistributionType.BINARY; + + /** + * The name of the distribution + */ + @Parameter(property = "jreleaser.generate.template.toolName", required = true) + private String toolName; + + /** + * Overwrite existing files. + */ + @Parameter(property = "jreleaser.generate.template.overwrite") + private boolean overwrite; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + Banner.display(project, getLog()); + if (skip) return; + + try { + Path outputDirectory = Paths.get(project.getBasedir().getAbsolutePath()) + .resolve("src") + .resolve("distributions"); + + boolean result = TemplateGenerator.builder() + .logger(getLogger()) + .distributionName(distributionName) + .distributionType(distributionType) + .toolName(toolName) + .outputDirectory(outputDirectory) + .overwrite(overwrite) + .build() + .generate(); + + if (result) { + getLog().info("Template generated at " + + outputDirectory.resolve(distributionName).resolve(toolName)); + } + } catch (TemplateGenerationException e) { + throw new MojoExecutionException("Unexpected error", e); + } + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Jreleaser.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Jreleaser.java new file mode 100644 index 00000000..e2e26f5b --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Jreleaser.java @@ -0,0 +1,104 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static org.kordamp.jreleaser.util.StringUtils.isBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Jreleaser extends AbstractDomain { + private final Project project = new Project(); + private final Release release = new Release(); + private final Packagers packagers = new Packagers(); + private final List distributions = new ArrayList<>(); + + public Project getProject() { + return project; + } + + public void setProject(Project project) { + this.project.setAll(project); + } + + public Release getRelease() { + return release; + } + + public void setRelease(Release release) { + this.release.setAll(release); + } + + public Packagers getPackagers() { + return packagers; + } + + public void setPackagers(Packagers packagers) { + this.packagers.setAll(packagers); + } + + public List getDistributions() { + return distributions; + } + + public void setDistributions(Collection distributions) { + this.distributions.clear(); + this.distributions.addAll(distributions); + } + + public void addDistributions(Collection distributions) { + this.distributions.addAll(distributions); + } + + public Distribution findDistribution(String name) { + if (isBlank(name)) { + throw new IllegalArgumentException("Distribution name must not be blank"); + } + + if (distributions.isEmpty()) { + throw new IllegalArgumentException("No distributions have been configured"); + } + + return distributions.stream() + .filter(d -> name.equals(d.getName())) + .findFirst() + .orElseThrow((Supplier) () -> { + throw new IllegalArgumentException("Distribution '" + name + "' not found"); + }); + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("project", project.asMap()); + map.put("release", release.asMap()); + map.put("packagers", packagers.asMap()); + map.put("distributions", distributions.stream() + .map(Distribution::asMap) + .collect(Collectors.toList())); + return map; + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/PackageToolsMojo.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/PackageToolsMojo.java new file mode 100644 index 00000000..aa860d80 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/PackageToolsMojo.java @@ -0,0 +1,121 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.kordamp.jreleaser.maven.plugin.internal.JReleaserModelConfigurer; +import org.kordamp.jreleaser.maven.plugin.internal.JReleaserModelConverter; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.JReleaserModelValidator; +import org.kordamp.jreleaser.tools.DistributionProcessor; +import org.kordamp.jreleaser.tools.ToolProcessingException; +import org.kordamp.jreleaser.util.Logger; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +@Mojo(name = "package-tools", defaultPhase = LifecyclePhase.PACKAGE) +public class PackageToolsMojo extends AbstractJReleaserMojo { + /** + * Skip execution. + */ + @Parameter(property = "jreleaser.package.tools.skip") + private boolean skip; + + @Parameter(required = true) + private Jreleaser jreleaser; + + @Parameter(property = "jreleaser.package.output.directory", defaultValue = "${project.build.directory}") + private File outputDirectory; + + @Parameter(property = "jreleaser.package.checksum.directory", required = true) + private File checksumDirectory; + + @Parameter(property = "jreleaser.package.tools.failfast", defaultValue = "true") + private boolean failFast; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + Banner.display(project, getLog()); + if (skip) return; + + Logger logger = getLogger(); + JReleaserModel jreleaserModel = JReleaserModelConverter.convert(jreleaser); + JReleaserModelConfigurer.configure(jreleaserModel, project); + List errors = JReleaserModelValidator.validate(logger, project.getBasedir().toPath(), jreleaserModel); + if (!errors.isEmpty()) { + getLog().error("== JReleaser =="); + errors.forEach(getLog()::error); + throw new MojoExecutionException("JReleaser for project " + project.getArtifactId() + " has not been properly configured."); + } + + List exceptions = new ArrayList<>(); + for (org.kordamp.jreleaser.model.Distribution distribution : jreleaserModel.getDistributions().values()) { + for (String toolName : org.kordamp.jreleaser.model.Distribution.supportedTools()) { + try { + DistributionProcessor processor = createDistributionProcessor(jreleaserModel, + logger, + distribution, + toolName); + + if (!processor.prepareDistribution()) { + continue; + } + + getLog().info("Prepared " + distribution.getName() + " distribution with tool " + toolName); + + if (!processor.packageDistribution()) { + continue; + } + + getLog().info("Packaged " + distribution.getName() + " distribution with tool " + toolName); + } catch (ToolProcessingException e) { + if (failFast) throw new MojoExecutionException("Unexpected error", e); + exceptions.add(e); + getLog().warn(e); + } + } + } + + if (!exceptions.isEmpty()) { + throw new MojoExecutionException("There were " + exceptions.size() + " failure(s)"); + } + } + + private DistributionProcessor createDistributionProcessor(JReleaserModel jreleaserModel, + Logger logger, + org.kordamp.jreleaser.model.Distribution distribution, + String toolName) { + return DistributionProcessor.builder() + .logger(logger) + .model(jreleaserModel) + .distributionName(distribution.getName()) + .toolName(toolName) + .checksumDirectory(checksumDirectory.toPath()) + .outputDirectory(outputDirectory.toPath() + .resolve("jreleaser") + .resolve(distribution.getName()) + .resolve(toolName)) + .build(); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Packagers.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Packagers.java new file mode 100644 index 00000000..907d2857 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Packagers.java @@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Packagers extends AbstractDomain { + private final Brew brew = new Brew(); + private final Chocolatey chocolatey = new Chocolatey(); + private final Scoop scoop = new Scoop(); + private final Snap snap = new Snap(); + + void setAll(Packagers packagers) { + setBrew(packagers.brew); + setChocolatey(packagers.chocolatey); + setScoop(packagers.scoop); + setSnap(packagers.snap); + } + + public Brew getBrew() { + return brew; + } + + public void setBrew(Brew brew) { + this.brew.setAll(brew); + } + + public Chocolatey getChocolatey() { + return chocolatey; + } + + public void setChocolatey(Chocolatey chocolatey) { + this.chocolatey.setAll(chocolatey); + } + + public Scoop getScoop() { + return scoop; + } + + public void setScoop(Scoop scoop) { + this.scoop.setAll(scoop); + } + + public Snap getSnap() { + return snap; + } + + public void setSnap(Snap snap) { + this.snap.setAll(snap); + } + + @Override + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.putAll(brew.asMap()); + map.putAll(chocolatey.asMap()); + map.putAll(scoop.asMap()); + map.putAll(snap.asMap()); + return map; + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Plug.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Plug.java new file mode 100644 index 00000000..3b6b772e --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Plug.java @@ -0,0 +1,68 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Plug extends AbstractDomain { + private final Map attributes = new LinkedHashMap<>(); + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes.clear(); + this.attributes.putAll(attributes); + } + + public void addAttributes(Map attributes) { + this.attributes.putAll(attributes); + } + + public void addAttribute(String key, String value) { + attributes.put(key, value); + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put(name, attributes); + return map; + } + + public static Plug copyOf(Plug other) { + Plug copy = new Plug(); + copy.setName(other.getName()); + copy.setAttributes(other.getAttributes()); + return copy; + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Project.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Project.java new file mode 100644 index 00000000..84b782cd --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Project.java @@ -0,0 +1,192 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Project extends AbstractDomain implements ExtraProperties { + private final List authors = new ArrayList<>(); + private final List tags = new ArrayList<>(); + private final Map extraProperties = new LinkedHashMap<>(); + private String name; + private String version; + private String description; + private String longDescription; + private String website; + private String license; + private String javaVersion; + + void setAll(Project project) { + this.name = project.name; + this.version = project.version; + this.description = project.description; + this.longDescription = project.longDescription; + this.website = project.website; + this.license = project.license; + this.javaVersion = project.javaVersion; + setAuthors(project.authors); + setTags(project.tags); + setExtraProperties(project.extraProperties); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLongDescription() { + return longDescription; + } + + public void setLongDescription(String longDescription) { + this.longDescription = longDescription; + } + + public String getWebsite() { + return website; + } + + public void setWebsite(String website) { + this.website = website; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getJavaVersion() { + return javaVersion; + } + + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + @Override + public Map getExtraProperties() { + return extraProperties; + } + + @Override + public void setExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + @Override + public void addExtraProperties(Map extraProperties) { + this.extraProperties.putAll(extraProperties); + } + + public List getAuthors() { + return authors; + } + + public void setAuthors(List authors) { + this.authors.clear(); + this.authors.addAll(authors); + } + + public void addAuthors(List authors) { + this.authors.addAll(authors); + } + + public void addAuthor(String author) { + if (isNotBlank(author)) { + this.authors.add(author.trim()); + } + } + + public void removeAuthor(String author) { + if (isNotBlank(author)) { + this.authors.remove(author.trim()); + } + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags.clear(); + this.tags.addAll(tags); + } + + public void addTags(List tags) { + this.tags.addAll(tags); + } + + public void addTag(String tag) { + if (isNotBlank(tag)) { + this.tags.add(tag.trim()); + } + } + + public void removeTag(String tag) { + if (isNotBlank(tag)) { + this.tags.remove(tag.trim()); + } + } + + @Override + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("name", name); + map.put("version", version); + map.put("description", description); + map.put("longDescription", longDescription); + map.put("website", website); + map.put("license", license); + if (isNotBlank(javaVersion)) map.put("javaVersion", javaVersion); + map.put("authors", authors); + map.put("tags", tags); + map.put("extraProperties", extraProperties); + return map; + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Release.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Release.java new file mode 100644 index 00000000..cc4396f4 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Release.java @@ -0,0 +1,296 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Release extends AbstractDomain { + private RepoType repoType = RepoType.GITHUB; + private String repoHost; + private String repoOwner; + private String repoName; + private String downloadUrlFormat; + private String releaseNotesUrlFormat; + private String latestReleaseUrlFormat; + private String issueTrackerUrlFormat; + private String authorization; + private String tagName; + private String targetCommitish = "main"; + private String releaseName; + private String body = ""; + private boolean draft; + private boolean prerelease; + private boolean overwrite; + private boolean allowUploadToExisting; + private String apiEndpoint; + + void setAll(Release release) { + this.repoType = release.repoType; + this.repoHost = release.repoHost; + this.repoOwner = release.repoOwner; + this.repoName = release.repoName; + this.downloadUrlFormat = release.downloadUrlFormat; + this.releaseNotesUrlFormat = release.releaseNotesUrlFormat; + this.latestReleaseUrlFormat = release.latestReleaseUrlFormat; + this.issueTrackerUrlFormat = release.issueTrackerUrlFormat; + this.authorization = release.authorization; + this.tagName = release.tagName; + this.targetCommitish = release.targetCommitish; + this.releaseName = release.releaseName; + this.body = release.body; + this.draft = release.draft; + this.prerelease = release.prerelease; + this.overwrite = release.overwrite; + this.allowUploadToExisting = release.allowUploadToExisting; + this.apiEndpoint = release.apiEndpoint; + } + + public RepoType getRepoType() { + return repoType; + } + + public void setRepoType(RepoType repoType) { + this.repoType = repoType; + } + + public void setRepoType(String repoType) { + if (isNotBlank(repoType)) { + this.repoType = RepoType.valueOf(repoType.toUpperCase()); + } + } + + public String getRepoHost() { + return repoHost; + } + + public void setRepoHost(String repoHost) { + this.repoHost = repoHost; + } + + public String getRepoOwner() { + return repoOwner; + } + + public void setRepoOwner(String repoOwner) { + this.repoOwner = repoOwner; + } + + public String getRepoName() { + return repoName; + } + + public void setRepoName(String repoName) { + this.repoName = repoName; + } + + public String getDownloadUrlFormat() { + return downloadUrlFormat; + } + + public void setDownloadUrlFormat(String downloadUrlFormat) { + this.downloadUrlFormat = downloadUrlFormat; + } + + public String getReleaseNotesUrlFormat() { + return releaseNotesUrlFormat; + } + + public void setReleaseNotesUrlFormat(String releaseNotesUrlFormat) { + this.releaseNotesUrlFormat = releaseNotesUrlFormat; + } + + public String getLatestReleaseUrlFormat() { + return latestReleaseUrlFormat; + } + + public void setLatestReleaseUrlFormat(String latestReleaseUrlFormat) { + this.latestReleaseUrlFormat = latestReleaseUrlFormat; + } + + public String getIssueTrackerUrlFormat() { + return issueTrackerUrlFormat; + } + + public void setIssueTrackerUrlFormat(String issueTrackerUrlFormat) { + this.issueTrackerUrlFormat = issueTrackerUrlFormat; + } + + public String getAuthorization() { + return authorization; + } + + public void setAuthorization(String authorization) { + this.authorization = authorization; + } + + public String getTagName() { + return tagName; + } + + public void setTagName(String tagName) { + this.tagName = tagName; + } + + public String getTargetCommitish() { + return targetCommitish; + } + + public void setTargetCommitish(String targetCommitish) { + this.targetCommitish = targetCommitish; + } + + public String getReleaseName() { + return releaseName; + } + + public void setReleaseName(String releaseName) { + this.releaseName = releaseName; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public boolean isDraft() { + return draft; + } + + public void setDraft(boolean draft) { + this.draft = draft; + } + + public boolean isPrerelease() { + return prerelease; + } + + public void setPrerelease(boolean prerelease) { + this.prerelease = prerelease; + } + + public boolean isOverwrite() { + return overwrite; + } + + public void setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + } + + public boolean isAllowUploadToExisting() { + return allowUploadToExisting; + } + + public void setAllowUploadToExisting(boolean allowUploadToExisting) { + this.allowUploadToExisting = allowUploadToExisting; + } + + public String getApiEndpoint() { + return apiEndpoint; + } + + public void setApiEndpoint(String apiEndpoint) { + this.apiEndpoint = apiEndpoint; + } + + @Override + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put("repoHost", repoHost); + map.put("repoType", repoType); + map.put("repoOwner", repoOwner); + map.put("repoName", repoName); + map.put("downloadUrlFormat", downloadUrlFormat); + map.put("releaseNotesUrlFormat", releaseNotesUrlFormat); + map.put("latestReleaseUrlFormat", latestReleaseUrlFormat); + map.put("issueTrackerUrlFormat", issueTrackerUrlFormat); + map.put("authorization", authorization); + map.put("tagName", tagName); + map.put("targetCommitish", targetCommitish); + map.put("releaseName", releaseName); + map.put("body ", isNotBlank(body)); + map.put("draft", draft); + map.put("prerelease", prerelease); + map.put("overwrite", overwrite); + map.put("allowUploadToExisting", allowUploadToExisting); + map.put("apiEndpoint", apiEndpoint); + return map; + } + + public enum RepoType { + GITHUB("github.com", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/download/v{{projectVersion}}/{{artifactFileName}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/tag/v{{projectVersion}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/latest", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/issues"); + /* + GITLAB("gitlab.com", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/archive/v{{projectVersion}}/{{artifactFileName}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/releases/v{{projectVersion}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/releases/v{{projectVersion}}", + "https://{{repoHost}}/{{repoOwner}}/{{repoName}}/-/issues"); + */ + + private final String repoHost; + private final String downloadUrlFormat; + private final String releaseNotesUrlFormat; + private final String latestReleaseUrlFormat; + private final String issueTrackerUrlFormat; + + RepoType(String repoHost, + String downloadUrlFormat, + String releaseNotesUrlFormat, + String latestReleaseUrlFormat, + String issueTrackerUrlFormat) { + this.repoHost = repoHost; + this.downloadUrlFormat = downloadUrlFormat; + this.releaseNotesUrlFormat = releaseNotesUrlFormat; + this.latestReleaseUrlFormat = latestReleaseUrlFormat; + this.issueTrackerUrlFormat = issueTrackerUrlFormat; + } + + String repoHost() { + return this.repoHost; + } + + String downloadUrlFormat() { + return this.downloadUrlFormat; + } + + String releaseNotesUrlFormat() { + return this.releaseNotesUrlFormat; + } + + String latestReleaseUrlFormat() { + return this.latestReleaseUrlFormat; + } + + String issueTrackerUrlFormat() { + return this.issueTrackerUrlFormat; + } + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Scoop.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Scoop.java new file mode 100644 index 00000000..d564094e --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Scoop.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Scoop extends AbstractTool { + public static final String TOOL_NAME = "scoop"; + + private String checkverUrl; + private String autoupdateUrl; + + public Scoop() { + super(TOOL_NAME); + } + + void setAll(Scoop scoop) { + super.setAll(scoop); + this.checkverUrl = scoop.checkverUrl; + this.autoupdateUrl = scoop.autoupdateUrl; + } + + public String getCheckverUrl() { + return checkverUrl; + } + + public void setCheckverUrl(String checkverUrl) { + this.checkverUrl = checkverUrl; + } + + public String getAutoupdateUrl() { + return autoupdateUrl; + } + + public void setAutoupdateUrl(String autoupdateUrl) { + this.autoupdateUrl = autoupdateUrl; + } + + @Override + public boolean isSet() { + return super.isSet() || + isNotBlank(checkverUrl) || + isNotBlank(autoupdateUrl); + } + + @Override + protected void asMap(Map props) { + props.put("checkverUrl", checkverUrl); + props.put("autoupdateUrl", autoupdateUrl); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Slot.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Slot.java new file mode 100644 index 00000000..61742e1a --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Slot.java @@ -0,0 +1,119 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Slot extends AbstractDomain { + private final Map attributes = new LinkedHashMap<>(); + private final List reads = new ArrayList<>(); + private final List writes = new ArrayList<>(); + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes.clear(); + this.attributes.putAll(attributes); + } + + public void addAttributes(Map attributes) { + this.attributes.putAll(attributes); + } + + public void addAttribute(String key, String value) { + attributes.put(key, value); + } + + public List getReads() { + return reads; + } + + public void setReads(List reads) { + this.reads.clear(); + this.reads.addAll(reads); + } + + public void addReads(List read) { + this.reads.addAll(read); + } + + public void addRead(String read) { + if (isNotBlank(read)) { + this.reads.add(read.trim()); + } + } + + public void removeRead(String read) { + if (isNotBlank(read)) { + this.reads.remove(read.trim()); + } + } + + public List getWrites() { + return writes; + } + + public void setWrites(List writes) { + this.writes.clear(); + this.writes.addAll(writes); + } + + public void addWrites(List write) { + this.writes.addAll(write); + } + + public void addWrite(String write) { + if (isNotBlank(write)) { + this.writes.add(write.trim()); + } + } + + public void removeWrite(String write) { + if (isNotBlank(write)) { + this.writes.remove(write.trim()); + } + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put(name, attributes); + map.put("read", reads); + map.put("write", writes); + return map; + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Snap.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Snap.java new file mode 100644 index 00000000..2b0620e3 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Snap.java @@ -0,0 +1,186 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Snap extends AbstractTool { + public static final String TOOL_NAME = "snap"; + + private final List localPlugs = new ArrayList<>(); + private final List plugs = new ArrayList<>(); + private final List slots = new ArrayList<>(); + private String base; + private String grade; + private String confinement; + private File exportedLogin; + + public Snap() { + super(TOOL_NAME); + } + + void setAll(Snap snap) { + super.setAll(snap); + this.base = snap.base; + this.grade = snap.grade; + this.confinement = snap.confinement; + this.exportedLogin = snap.exportedLogin; + setLocalPlugs(localPlugs); + setPlugs(plugs); + setSlots(slots); + } + + public String getBase() { + return base; + } + + public void setBase(String base) { + this.base = base; + } + + public String getGrade() { + return grade; + } + + public void setGrade(String grade) { + this.grade = grade; + } + + public String getConfinement() { + return confinement; + } + + public void setConfinement(String confinement) { + this.confinement = confinement; + } + + public List getLocalPlugs() { + return localPlugs; + } + + public void setLocalPlugs(List localPlugs) { + this.localPlugs.clear(); + this.localPlugs.addAll(localPlugs); + } + + public void addLocalPlugs(List localPlugs) { + this.localPlugs.addAll(localPlugs); + } + + public void addLocalPlug(String localPlug) { + if (isNotBlank(localPlug)) { + this.localPlugs.add(localPlug.trim()); + } + } + + public void removeLocalPlug(String localPlug) { + if (isNotBlank(localPlug)) { + this.localPlugs.remove(localPlug.trim()); + } + } + + public List getPlugs() { + return plugs; + } + + public void setPlugs(List plugs) { + this.plugs.clear(); + this.plugs.addAll(plugs); + } + + public void addPlugs(List plugs) { + this.plugs.addAll(plugs); + } + + public void addPlug(Plug plug) { + if (null != plug) { + this.plugs.add(plug); + } + } + + public void removePlug(Plug plug) { + if (null != plug) { + this.plugs.remove(plug); + } + } + + public List getSlots() { + return slots; + } + + public void setSlots(List slots) { + this.slots.clear(); + this.slots.addAll(slots); + } + + public void addSlots(List slots) { + this.slots.addAll(slots); + } + + public void addSlot(Slot slot) { + if (null != slot) { + this.slots.add(slot); + } + } + + public void removeSlot(Slot slot) { + if (null != slot) { + this.slots.remove(slot); + } + } + + public File getExportedLogin() { + return exportedLogin; + } + + public void setExportedLogin(File exportedLogin) { + this.exportedLogin = exportedLogin; + } + + @Override + public boolean isSet() { + return super.isSet() || + isNotBlank(base) || + isNotBlank(grade) || + isNotBlank(confinement) || + null != exportedLogin || + !localPlugs.isEmpty() || + !plugs.isEmpty() || + !slots.isEmpty(); + } + + @Override + protected void asMap(Map props) { + props.put("base", base); + props.put("grade", grade); + props.put("confinement", confinement); + props.put("exportedLogin", exportedLogin); + props.put("localPlugs", localPlugs); + props.put("plugs", plugs); + props.put("slots", slots); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Tool.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Tool.java new file mode 100644 index 00000000..2cfed236 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/Tool.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin; + +import java.nio.file.Path; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface Tool extends ExtraProperties { + boolean isEnabledSet(); + + Boolean isEnabled(); + + void setEnabled(Boolean enabled); + + String getToolName(); + + Path getTemplateDirectory(); + + void setTemplateDirectory(Path templateDirectory); +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserLoggerAdapter.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserLoggerAdapter.java new file mode 100644 index 00000000..5e6bcb2d --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserLoggerAdapter.java @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin.internal; + +import org.apache.maven.plugin.logging.Log; +import org.kordamp.jreleaser.util.Logger; +import org.slf4j.helpers.MessageFormatter; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserLoggerAdapter implements Logger { + private final Log delegate; + + public JReleaserLoggerAdapter(Log delegate) { + this.delegate = delegate; + } + + @Override + public void debug(String message) { + delegate.debug(message); + } + + @Override + public void info(String message) { + delegate.info(message); + } + + @Override + public void warn(String message) { + delegate.warn(message); + } + + @Override + public void error(String message) { + delegate.error(message); + } + + @Override + public void debug(String message, Object... args) { + delegate.debug(MessageFormatter.arrayFormat(message, args).getMessage()); + } + + @Override + public void info(String message, Object... args) { + delegate.info(MessageFormatter.arrayFormat(message, args).getMessage()); + } + + @Override + public void warn(String message, Object... args) { + delegate.warn(MessageFormatter.arrayFormat(message, args).getMessage()); + } + + @Override + public void error(String message, Object... args) { + delegate.error(MessageFormatter.arrayFormat(message, args).getMessage()); + } + + @Override + public void debug(String message, Throwable throwable) { + delegate.debug(message, throwable); + } + + @Override + public void info(String message, Throwable throwable) { + delegate.info(message, throwable); + } + + @Override + public void warn(String message, Throwable throwable) { + delegate.warn(message, throwable); + } + + @Override + public void error(String message, Throwable throwable) { + delegate.error(message, throwable); + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelConfigurer.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelConfigurer.java new file mode 100644 index 00000000..b5d277d5 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelConfigurer.java @@ -0,0 +1,130 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin.internal; + +import org.apache.maven.model.Developer; +import org.apache.maven.model.License; +import org.apache.maven.project.MavenProject; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.Project; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import static org.kordamp.jreleaser.util.StringUtils.isBlank; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public final class JReleaserModelConfigurer { + private JReleaserModelConfigurer() { + // noop + } + + public static void configure(JReleaserModel model, MavenProject mavenProject) { + configureProject(model.getProject(), mavenProject); + } + + private static void configureProject(Project project, MavenProject mavenProject) { + if (isBlank(project.getName())) { + project.setName(mavenProject.getArtifactId()); + } + if (isBlank(project.getVersion())) { + project.setVersion(mavenProject.getVersion()); + } + if (isBlank(project.getDescription())) { + project.setDescription(mavenProject.getDescription()); + } + if (isBlank(project.getWebsite())) { + project.setWebsite(mavenProject.getUrl()); + } + if (project.getAuthors().isEmpty()) { + project.setAuthors(resolveAuthors(mavenProject.getDevelopers())); + } + if (isBlank(project.getLicense())) { + project.setLicense(resolveLicense(mavenProject.getLicenses())); + } + if (isBlank(project.getJavaVersion())) { + project.setJavaVersion(resolveJavaVersion(mavenProject)); + } + } + + private static List resolveAuthors(List developers) { + if (null == developers || developers.isEmpty()) return Collections.emptyList(); + + List authors = new ArrayList<>(); + // 1. find all with role="author" + for (Developer developer : developers) { + List roles = developer.getRoles(); + if (null != roles && roles.stream() + .anyMatch("author"::equalsIgnoreCase)) { + String name = developer.getName(); + if (isBlank(name)) name = developer.getId(); + if (isNotBlank(name)) authors.add(name); + } + } + // 2. add all if the authors list is empty + if (authors.isEmpty()) { + for (Developer developer : developers) { + String name = developer.getName(); + if (isBlank(name)) name = developer.getId(); + if (isNotBlank(name)) authors.add(name); + } + } + + return authors; + } + + private static String resolveLicense(List licenses) { + if (null == licenses || licenses.isEmpty()) return ""; + for (License license : licenses) { + if (isNotBlank(license.getName())) { + return license.getName(); + } + } + return ""; + } + + private static String resolveJavaVersion(MavenProject mavenProject) { + Properties properties = mavenProject.getProperties(); + if (null == properties || properties.isEmpty()) return ""; + + if (properties.containsKey("maven.compiler.release")) { + return properties.getProperty("maven.compiler.release"); + } + if (properties.containsKey("maven.compiler.target")) { + return properties.getProperty("maven.compiler.target"); + } + if (properties.containsKey("maven.compiler.source")) { + return properties.getProperty("maven.compiler.source"); + } + + return resolveJavaVersion(System.getProperty("java.version")); + } + + private static String resolveJavaVersion(String str) { + if (str.startsWith("1.")) { + return str.substring(0, 2); + } + return str.split("\\.")[0]; + } +} \ No newline at end of file diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelConverter.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelConverter.java new file mode 100644 index 00000000..2a0d40d7 --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelConverter.java @@ -0,0 +1,219 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin.internal; + +import org.kordamp.jreleaser.maven.plugin.Artifact; +import org.kordamp.jreleaser.maven.plugin.Brew; +import org.kordamp.jreleaser.maven.plugin.Chocolatey; +import org.kordamp.jreleaser.maven.plugin.Distribution; +import org.kordamp.jreleaser.maven.plugin.Jreleaser; +import org.kordamp.jreleaser.maven.plugin.Packagers; +import org.kordamp.jreleaser.maven.plugin.Plug; +import org.kordamp.jreleaser.maven.plugin.Project; +import org.kordamp.jreleaser.maven.plugin.Release; +import org.kordamp.jreleaser.maven.plugin.Scoop; +import org.kordamp.jreleaser.maven.plugin.Slot; +import org.kordamp.jreleaser.maven.plugin.Snap; +import org.kordamp.jreleaser.model.JReleaserModel; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public final class JReleaserModelConverter { + private JReleaserModelConverter() { + // noop + } + + public static JReleaserModel convert(Jreleaser jreleaser) { + JReleaserModel jReleaserModel = new JReleaserModel(); + jReleaserModel.setProject(convertProject(jreleaser.getProject())); + jReleaserModel.setRelease(convertRelease(jreleaser.getRelease())); + jReleaserModel.setPackagers(convertPackagers(jreleaser.getPackagers())); + jReleaserModel.setDistributions(convertDistributions(jReleaserModel, jreleaser.getDistributions())); + return jReleaserModel; + } + + private static org.kordamp.jreleaser.model.Project convertProject(Project project) { + org.kordamp.jreleaser.model.Project p = new org.kordamp.jreleaser.model.Project(); + p.setName(project.getName()); + p.setVersion(project.getVersion()); + p.setDescription(project.getDescription()); + p.setLongDescription(project.getLongDescription()); + p.setWebsite(project.getWebsite()); + p.setLicense(project.getLicense()); + p.setJavaVersion(project.getJavaVersion()); + p.setTags(project.getTags()); + p.setAuthors(project.getAuthors()); + p.setExtraProperties(project.getExtraProperties()); + return p; + } + + private static org.kordamp.jreleaser.model.Release convertRelease(Release release) { + org.kordamp.jreleaser.model.Release r = new org.kordamp.jreleaser.model.Release(); + if (null != release.getRepoType()) r.setRepoType(release.getRepoType().name()); + r.setRepoOwner(release.getRepoOwner()); + r.setRepoName(release.getReleaseNotesUrlFormat()); + r.setDownloadUrlFormat(release.getDownloadUrlFormat()); + r.setReleaseNotesUrlFormat(release.getReleaseNotesUrlFormat()); + r.setLatestReleaseUrlFormat(release.getLatestReleaseUrlFormat()); + r.setIssueTrackerUrlFormat(release.getIssueTrackerUrlFormat()); + r.setAuthorization(release.getAuthorization()); + r.setTagName(release.getTagName()); + r.setTargetCommitish(release.getTargetCommitish()); + r.setReleaseName(release.getReleaseName()); + r.setBody(release.getBody()); + r.setDraft(release.isDraft()); + r.setPrerelease(release.isPrerelease()); + r.setOverwrite(release.isOverwrite()); + r.setAllowUploadToExisting(release.isAllowUploadToExisting()); + r.setApiEndpoint(release.getApiEndpoint()); + return r; + } + + private static org.kordamp.jreleaser.model.Packagers convertPackagers(Packagers packagers) { + org.kordamp.jreleaser.model.Packagers p = new org.kordamp.jreleaser.model.Packagers(); + if (packagers.getBrew().isSet()) p.setBrew(convertBrew(packagers.getBrew())); + if (packagers.getChocolatey().isSet()) p.setChocolatey(convertChocolatey(packagers.getChocolatey())); + if (packagers.getScoop().isSet()) p.setScoop(convertScoop(packagers.getScoop())); + if (packagers.getSnap().isSet()) p.setSnap(convertSnap(packagers.getSnap())); + return p; + } + + private static Map convertDistributions(JReleaserModel model, List distributions) { + Map ds = new LinkedHashMap<>(); + for (Distribution distribution : distributions) { + ds.put(distribution.getName(), convertDistribution(model, distribution)); + } + return ds; + } + + private static org.kordamp.jreleaser.model.Distribution convertDistribution(JReleaserModel model, Distribution distribution) { + org.kordamp.jreleaser.model.Distribution d = new org.kordamp.jreleaser.model.Distribution(); + d.setName(distribution.getName()); + d.setType(distribution.getType().name()); + d.setExecutable(distribution.getExecutable()); + d.setJavaVersion(distribution.getJavaVersion()); + d.setTags(distribution.getTags()); + d.setExtraProperties(distribution.getExtraProperties()); + d.setArtifacts(convertArtifacts(distribution.getArtifacts())); + + if (distribution.getBrew().isSet()) d.setBrew(convertBrew(distribution.getBrew())); + if (distribution.getChocolatey().isSet()) d.setChocolatey(convertChocolatey(distribution.getChocolatey())); + if (distribution.getScoop().isSet()) d.setScoop(convertScoop(distribution.getScoop())); + if (distribution.getSnap().isSet()) d.setSnap(convertSnap(distribution.getSnap())); + + return d; + } + + private static List convertArtifacts(List artifacts) { + List as = new ArrayList<>(); + for (Artifact artifact : artifacts) { + as.add(convertPlug(artifact)); + } + return as; + } + + private static org.kordamp.jreleaser.model.Artifact convertPlug(Artifact artifact) { + org.kordamp.jreleaser.model.Artifact a = new org.kordamp.jreleaser.model.Artifact(); + a.setPath(artifact.getPath()); + a.setHash(artifact.getHash()); + a.setOsClassifier(artifact.getOsClassifier()); + a.setJavaVersion(artifact.getJavaVersion()); + return a; + } + + private static org.kordamp.jreleaser.model.Brew convertBrew(Brew brew) { + org.kordamp.jreleaser.model.Brew t = new org.kordamp.jreleaser.model.Brew(); + if (brew.isEnabledSet()) t.setEnabled(brew.isEnabled()); + t.setTemplateDirectory(brew.getTemplateDirectory()); + t.setExtraProperties(brew.getExtraProperties()); + t.setDependencies(brew.getDependencies()); + return t; + } + + private static org.kordamp.jreleaser.model.Chocolatey convertChocolatey(Chocolatey chocolatey) { + org.kordamp.jreleaser.model.Chocolatey t = new org.kordamp.jreleaser.model.Chocolatey(); + if (chocolatey.isEnabledSet()) t.setEnabled(chocolatey.isEnabled()); + t.setTemplateDirectory(chocolatey.getTemplateDirectory()); + t.setExtraProperties(chocolatey.getExtraProperties()); + return t; + } + + private static org.kordamp.jreleaser.model.Scoop convertScoop(Scoop scoop) { + org.kordamp.jreleaser.model.Scoop t = new org.kordamp.jreleaser.model.Scoop(); + if (scoop.isEnabledSet()) t.setEnabled(scoop.isEnabled()); + t.setTemplateDirectory(scoop.getTemplateDirectory()); + t.setExtraProperties(scoop.getExtraProperties()); + t.setCheckverUrl(scoop.getCheckverUrl()); + t.setAutoupdateUrl(scoop.getAutoupdateUrl()); + return t; + } + + private static org.kordamp.jreleaser.model.Snap convertSnap(Snap snap) { + org.kordamp.jreleaser.model.Snap t = new org.kordamp.jreleaser.model.Snap(); + if (snap.isEnabledSet()) t.setEnabled(snap.isEnabled()); + t.setTemplateDirectory(snap.getTemplateDirectory()); + t.setExtraProperties(snap.getExtraProperties()); + t.setBase(snap.getBase()); + t.setGrade(snap.getGrade()); + t.setConfinement(snap.getConfinement()); + t.setExportedLogin(snap.getExportedLogin().getAbsolutePath()); + t.setLocalPlugs(snap.getLocalPlugs()); + t.setPlugs(convertPlugs(snap.getPlugs())); + t.setSlots(convertSlots(snap.getSlots())); + return t; + } + + private static List convertPlugs(List plugs) { + List ps = new ArrayList<>(); + for (Plug plug : plugs) { + ps.add(convertPlug(plug)); + } + return ps; + } + + private static org.kordamp.jreleaser.model.Plug convertPlug(Plug plug) { + org.kordamp.jreleaser.model.Plug p = new org.kordamp.jreleaser.model.Plug(); + p.setName(plug.getName()); + p.setAttributes(plug.getAttributes()); + return p; + } + + private static List convertSlots(List slots) { + List ps = new ArrayList<>(); + for (Slot slot : slots) { + ps.add(convertSlot(slot)); + } + return ps; + } + + private static org.kordamp.jreleaser.model.Slot convertSlot(Slot slot) { + org.kordamp.jreleaser.model.Slot p = new org.kordamp.jreleaser.model.Slot(); + p.setName(slot.getName()); + p.setAttributes(slot.getAttributes()); + p.setReads(slot.getReads()); + p.setWrites(slot.getWrites()); + return p; + } +} \ No newline at end of file diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelPrinter.java b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelPrinter.java new file mode 100644 index 00000000..eb3314af --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/kordamp/jreleaser/maven/plugin/internal/JReleaserModelPrinter.java @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.maven.plugin.internal; + + +import java.io.PrintWriter; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class JReleaserModelPrinter extends org.kordamp.jreleaser.model.JReleaserModelPrinter { + public JReleaserModelPrinter(PrintWriter out) { + super(out); + } + + public JReleaserModelPrinter(PrintWriter out, boolean showSecrets) { + super(out, showSecrets); + } + + @Override + protected String color(String color, String input) { + return input; + } +} diff --git a/plugins/jreleaser-maven-plugin/src/main/resources/org/kordamp/jreleaser/maven/plugin/Banner.properties b/plugins/jreleaser-maven-plugin/src/main/resources/org/kordamp/jreleaser/maven/plugin/Banner.properties new file mode 100644 index 00000000..d841c0dc --- /dev/null +++ b/plugins/jreleaser-maven-plugin/src/main/resources/org/kordamp/jreleaser/maven/plugin/Banner.properties @@ -0,0 +1,22 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +product.version=$version +product.id=$id +product.name=$name +product.banner={0} {1}. Consider becoming a patron at https://www.patreon.com/aalmiray \ No newline at end of file diff --git a/sdks/github-java-sdk/github-java-sdk.gradle b/sdks/github-java-sdk/github-java-sdk.gradle new file mode 100644 index 00000000..817ec32b --- /dev/null +++ b/sdks/github-java-sdk/github-java-sdk.gradle @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-model') + + api "org.apache.tika:tika-core:$tikaVersion" + api "com.squareup.okhttp3:okhttp:$okhttpVersion" + + api 'org.kohsuke:github-api:1.116' +} \ No newline at end of file diff --git a/sdks/github-java-sdk/gradle.properties b/sdks/github-java-sdk/gradle.properties new file mode 100644 index 00000000..1ef8c39a --- /dev/null +++ b/sdks/github-java-sdk/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = Java SDK for Github diff --git a/sdks/github-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/github/Github.java b/sdks/github-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/github/Github.java new file mode 100644 index 00000000..ff1a55b2 --- /dev/null +++ b/sdks/github-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/github/Github.java @@ -0,0 +1,100 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.github; + +import okhttp3.Cache; +import okhttp3.OkHttpClient; +import org.apache.tika.Tika; +import org.apache.tika.mime.MediaType; +import org.kohsuke.github.GHAsset; +import org.kohsuke.github.GHRelease; +import org.kohsuke.github.GHReleaseBuilder; +import org.kohsuke.github.GitHub; +import org.kohsuke.github.GitHubBuilder; +import org.kohsuke.github.extras.okhttp3.OkHttpConnector; +import org.kordamp.jreleaser.model.releaser.ReleaseException; +import org.kordamp.jreleaser.util.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +class Github { + static final String ENDPOINT = "https://api.github.com"; + private final Tika tika = new Tika(); + + private final Logger logger; + private final GitHub github; + + Github(Logger logger, String authorization) throws ReleaseException { + this(logger, ENDPOINT, authorization); + } + + Github(Logger logger, String endpoint, String authorization) throws ReleaseException { + this.logger = logger; + + try { + Path githubCache = Paths.get(System.getProperty("user.home")) + .resolve(".jreleaser") + .resolve("caches") + .resolve("github"); + + github = new GitHubBuilder() + .withEndpoint(endpoint) + .withOAuthToken(authorization) + .withConnector(new OkHttpConnector(new OkHttpClient.Builder() + .cache(new Cache(Files.createDirectory(githubCache).toFile(), 10 * 1024 * 1024)) + .build())) + .build(); + } catch (IOException e) { + throw new ReleaseException("Unexpected error setting up GitHub endpoint", e); + } + } + + GHRelease findReleaseByTag(String repo, String tagName) throws IOException { + logger.debug("Fetching release on {} with tag {}", repo, tagName); + return github.getRepository(repo).getReleaseByTagName(tagName); + } + + GHReleaseBuilder createRelease(String repo, String tagName) throws IOException { + logger.debug("Creating release on {} with tag {}", repo, tagName); + return github.getRepository(repo) + .createRelease(tagName); + } + + void uploadAssets(GHRelease release, List assets) throws IOException { + for (Path asset : assets) { + if (0 == asset.toFile().length()) { + // do not upload empty files + continue; + } + + logger.debug("Uploading asset {}", asset.getFileName().toString()); + GHAsset ghasset = release.uploadAsset(asset.toFile(), MediaType.parse(tika.detect(asset)).toString()); + if (!"uploaded".equalsIgnoreCase(ghasset.getState())) { + logger.warn("Failed to upload " + asset.getFileName()); + } + } + } +} diff --git a/sdks/github-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/github/GithubReleaser.java b/sdks/github-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/github/GithubReleaser.java new file mode 100644 index 00000000..834e3331 --- /dev/null +++ b/sdks/github-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/github/GithubReleaser.java @@ -0,0 +1,228 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.github; + +import org.kohsuke.github.GHRelease; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.releaser.ReleaseException; +import org.kordamp.jreleaser.model.releaser.Releaser; +import org.kordamp.jreleaser.model.releaser.ReleaserBuilder; +import org.kordamp.jreleaser.util.Logger; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Objects.requireNonNull; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class GithubReleaser implements Releaser { + private final Logger logger; + private final String repo; + private final String authorization; + private final String tagName; + private final String targetCommitish; + private final String releaseName; + private final String body; + private final boolean draft; + private final boolean prerelease; + private final boolean overwrite; + private final boolean allowUploadToExisting; + private final String apiEndpoint; + private final List assets = new ArrayList<>(); + + public GithubReleaser(Logger logger, String repo, String authorization, + String tagName, String targetCommitish, String releaseName, + String body, boolean draft, boolean prerelease, boolean overwrite, + boolean allowUploadToExisting, String apiEndpoint, List assets) { + this.logger = logger; + this.repo = repo; + this.authorization = authorization; + this.tagName = tagName; + this.targetCommitish = targetCommitish; + this.releaseName = releaseName; + this.body = body; + this.draft = draft; + this.prerelease = prerelease; + this.overwrite = overwrite; + this.allowUploadToExisting = allowUploadToExisting; + this.apiEndpoint = apiEndpoint; + this.assets.addAll(assets); + } + + public void release() throws ReleaseException { + Github api = new Github(logger, apiEndpoint, authorization); + + try { + GHRelease release = api.findReleaseByTag(repo, tagName); + if (null != release) { + if (overwrite) { + release.delete(); + createRelease(api); + } else if (allowUploadToExisting) { + api.uploadAssets(release, assets); + } else { + throw new IllegalStateException("Github release failed because release " + + tagName + " already exists"); + } + } else { + createRelease(api); + } + } catch (IOException | IllegalStateException e) { + throw new ReleaseException(e); + } + } + + private void createRelease(Github api) throws IOException { + GHRelease release = api.createRelease(repo, tagName) + .commitish(targetCommitish) + .name(releaseName) + .draft(draft) + .prerelease(prerelease) + .body(body) + .create(); + api.uploadAssets(release, assets); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder implements ReleaserBuilder { + private final List assets = new ArrayList<>(); + private Logger logger; + private String repo; + private String authorization; + private String tagName; + private String targetCommitish = "main"; + private String releaseName; + private String body = ""; + private boolean draft; + private boolean prerelease; + private boolean overwrite; + private boolean allowUploadToExisting; + private String apiEndpoint = Github.ENDPOINT; + + public Builder logger(Logger logger) { + this.logger = requireNonNull(logger, "'logger' must not be null"); + return this; + } + + public Builder repo(String repo) { + this.repo = requireNonBlank(repo, "'repo' must not be blank"); + return this; + } + + public Builder authorization(String authorization) { + this.authorization = requireNonBlank(authorization, "'authorization' must not be blank"); + return this; + } + + public Builder tagName(String tagName) { + this.tagName = requireNonBlank(tagName, "'tagName' must not be blank"); + return this; + } + + public Builder targetCommitish(String targetCommitish) { + this.targetCommitish = requireNonBlank(targetCommitish, "'targetCommitish' must not be blank"); + return this; + } + + public Builder releaseName(String releaseName) { + this.releaseName = requireNonBlank(releaseName, "'releaseName' must not be blank"); + return this; + } + + public Builder body(String body) { + this.body = body; + return this; + } + + public Builder draft(boolean draft) { + this.draft = draft; + return this; + } + + public Builder prerelease(boolean prerelease) { + this.prerelease = prerelease; + return this; + } + + public Builder overwrite(boolean overwrite) { + this.overwrite = overwrite; + return this; + } + + public Builder allowUploadToExisting(boolean allowUploadToExisting) { + this.allowUploadToExisting = allowUploadToExisting; + return this; + } + + public Builder apiEndpoint(String apiEndpoint) { + this.apiEndpoint = isNotBlank(apiEndpoint) ? apiEndpoint : Github.ENDPOINT; + return this; + } + + public Builder setReleaseAssets(List assets) { + if (null != assets) { + this.assets.addAll(assets); + } + return this; + } + + @Override + public GithubReleaser build() { + requireNonNull(logger, "'logger' must not be null"); + requireNonBlank(repo, "'repo' must not be blank"); + requireNonBlank(authorization, "'authorization' must not be blank"); + requireNonBlank(tagName, "'tagName' must not be blank"); + requireNonBlank(targetCommitish, "'targetCommitish' must not be blank"); + requireNonBlank(releaseName, "'releaseName' must not be blank"); + if (assets.isEmpty()) { + throw new IllegalArgumentException("'assets must not be empty"); + } + + return new GithubReleaser(logger, repo, authorization, + tagName, targetCommitish, releaseName, + body, draft, prerelease, overwrite, + allowUploadToExisting, apiEndpoint, assets); + } + + @Override + public GithubReleaser buildFromModel(JReleaserModel model) { + repo(model.getRelease().getRepoName()); + authorization(model.getRelease().getAuthorization()); + tagName(model.getRelease().getTagName()); + targetCommitish(model.getRelease().getTargetCommitish()); + releaseName(model.getRelease().getRepoName()); + body(model.getRelease().getBody()); + draft(model.getRelease().isDraft()); + prerelease(model.getRelease().isPrerelease()); + overwrite(model.getRelease().isOverwrite()); + allowUploadToExisting(model.getRelease().isAllowUploadToExisting()); + apiEndpoint(model.getRelease().getApiEndpoint()); + return build(); + } + } +} diff --git a/sdks/github-java-sdk/src/main/module/module-info.java b/sdks/github-java-sdk/src/main/module/module-info.java new file mode 100644 index 00000000..dde7ba16 --- /dev/null +++ b/sdks/github-java-sdk/src/main/module/module-info.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.sdk.github { + exports org.kordamp.jreleaser.sdk.github; + requires org.kordamp.jreleaser.model; + requires org.kordamp.jreleaser.util; + requires github.api; + requires org.apache.tika.core; + requires okhttp3; +} \ No newline at end of file diff --git a/sdks/gitlab-java-sdk/gitlab-java-sdk.gradle b/sdks/gitlab-java-sdk/gitlab-java-sdk.gradle new file mode 100644 index 00000000..e3079623 --- /dev/null +++ b/sdks/gitlab-java-sdk/gitlab-java-sdk.gradle @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-model') + + api "org.apache.tika:tika-core:$tikaVersion" + + api 'org.gitlab4j:gitlab4j-api:4.15.7' +} \ No newline at end of file diff --git a/sdks/gitlab-java-sdk/gradle.properties b/sdks/gitlab-java-sdk/gradle.properties new file mode 100644 index 00000000..ce9a90ee --- /dev/null +++ b/sdks/gitlab-java-sdk/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = Java SDK for Gitlab diff --git a/sdks/gitlab-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/gitlab/Gitlab.java b/sdks/gitlab-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/gitlab/Gitlab.java new file mode 100644 index 00000000..3e53d6ea --- /dev/null +++ b/sdks/gitlab-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/gitlab/Gitlab.java @@ -0,0 +1,93 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.gitlab; + +import org.apache.tika.Tika; +import org.apache.tika.mime.MediaType; +import org.gitlab4j.api.GitLabApi; +import org.gitlab4j.api.GitLabApiException; +import org.gitlab4j.api.models.FileUpload; +import org.gitlab4j.api.models.Release; +import org.gitlab4j.api.models.ReleaseParams; +import org.kordamp.jreleaser.model.releaser.ReleaseException; +import org.kordamp.jreleaser.util.Logger; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.List; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class Gitlab { + static final String ENDPOINT = "https://gitlab.com/"; + private final Tika tika = new Tika(); + + private final Logger logger; + private final GitLabApi gitlab; + + Gitlab(Logger logger, String authorization) throws ReleaseException { + this(logger, ENDPOINT, authorization); + } + + Gitlab(Logger logger, String endpoint, String authorization) throws ReleaseException { + this.logger = logger; + + gitlab = new GitLabApi(endpoint, authorization); + } + + Release findReleaseByTag(String repo, String tagName) throws GitLabApiException, IOException { + logger.debug("Fetching release on {} with tag {}", repo, tagName); + return gitlab.getReleasesApi().getRelease(encode(repo), tagName); + } + + void deleteRelease(String repo, String tagName) throws GitLabApiException, IOException { + logger.debug("Deleting release on {} with tag {}", repo, tagName); + gitlab.getReleasesApi().deleteRelease(encode(repo), tagName); + } + + Release createRelease(String repo, ReleaseParams params) throws GitLabApiException, IOException { + logger.debug("Creating release on {} with tag {}", repo, params.getTagName()); + return gitlab.getReleasesApi().createRelease(encode(repo), params); + } + + void uploadAssets(String repo, Release release, List assets) throws GitLabApiException, IOException { + for (Path asset : assets) { + if (0 == asset.toFile().length()) { + // do not upload empty files + continue; + } + + logger.debug("Uploading asset {}", asset.getFileName().toString()); + try { + FileUpload upload = gitlab.getProjectApi() + .uploadFile(encode(repo), asset.toFile(), MediaType.parse(tika.detect(asset)).toString()); + // gitlab.getReleaseLinksApi().link(...) + } catch (Exception e) { + logger.warn("Failed to upload " + asset.getFileName(), e); + } + } + } + + private Object encode(String repo) throws IOException { + return URLEncoder.encode(repo, StandardCharsets.UTF_8.displayName()); + } +} diff --git a/sdks/gitlab-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/gitlab/GitlabReleaser.java b/sdks/gitlab-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/gitlab/GitlabReleaser.java new file mode 100644 index 00000000..c7548c91 --- /dev/null +++ b/sdks/gitlab-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/gitlab/GitlabReleaser.java @@ -0,0 +1,210 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.gitlab; + +import org.gitlab4j.api.GitLabApiException; +import org.gitlab4j.api.models.Release; +import org.gitlab4j.api.models.ReleaseParams; +import org.kordamp.jreleaser.model.JReleaserModel; +import org.kordamp.jreleaser.model.releaser.ReleaseException; +import org.kordamp.jreleaser.model.releaser.Releaser; +import org.kordamp.jreleaser.model.releaser.ReleaserBuilder; +import org.kordamp.jreleaser.util.Logger; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Objects.requireNonNull; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class GitlabReleaser implements Releaser { + private final Logger logger; + private final String repo; + private final String authorization; + private final String tagName; + private final String ref; + private final String body; + private final String releaseName; + private final boolean overwrite; + private final boolean allowUploadToExisting; + private final String apiEndpoint; + private final List assets = new ArrayList<>(); + + public GitlabReleaser(Logger logger, String repo, String authorization, + String tagName, String ref, String releaseName, + String body, boolean overwrite, + boolean allowUploadToExisting, String apiEndpoint, List assets) { + this.logger = logger; + this.repo = repo; + this.authorization = authorization; + this.tagName = tagName; + this.ref = ref; + this.releaseName = releaseName; + this.body = body; + this.overwrite = overwrite; + this.allowUploadToExisting = allowUploadToExisting; + this.apiEndpoint = apiEndpoint; + this.assets.addAll(assets); + } + + public void release() throws ReleaseException { + Gitlab api = new Gitlab(logger, apiEndpoint, authorization); + + try { + Release release = api.findReleaseByTag(repo, tagName); + if (null != release) { + if (overwrite) { + api.deleteRelease(repo, tagName); + createRelease(api); + } else if (allowUploadToExisting) { + api.uploadAssets(repo, release, assets); + } else { + throw new IllegalStateException("Gitlab release failed because release " + + tagName + " already exists"); + } + } else { + createRelease(api); + } + } catch (GitLabApiException | IOException | IllegalStateException e) { + throw new ReleaseException(e); + } + } + + private void createRelease(Gitlab api) throws GitLabApiException, IOException { + ReleaseParams params = new ReleaseParams(); + params.setName(releaseName); + params.setTagName(tagName); + params.setRef(ref); + Release release = api.createRelease(repo, params); + api.uploadAssets(repo, release, assets); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder implements ReleaserBuilder { + private final List assets = new ArrayList<>(); + private Logger logger; + private String repo; + private String authorization; + private String tagName; + private String ref = "main"; + private String releaseName; + private String body = ""; + private boolean overwrite; + private boolean allowUploadToExisting; + private String apiEndpoint = Gitlab.ENDPOINT; + + public Builder logger(Logger logger) { + this.logger = requireNonNull(logger, "'logger' must not be null"); + return this; + } + + public Builder repo(String repo) { + this.repo = requireNonBlank(repo, "'repo' must not be blank"); + return this; + } + + public Builder authorization(String authorization) { + this.authorization = requireNonBlank(authorization, "'authorization' must not be blank"); + return this; + } + + public Builder tagName(String tagName) { + this.tagName = requireNonBlank(tagName, "'tagName' must not be blank"); + return this; + } + + public Builder ref(String ref) { + this.ref = requireNonBlank(ref, "'ref' must not be blank"); + return this; + } + + public Builder releaseName(String releaseName) { + this.releaseName = requireNonBlank(releaseName, "'releaseName' must not be blank"); + return this; + } + + public Builder body(String body) { + this.body = body; + return this; + } + + public Builder overwrite(boolean overwrite) { + this.overwrite = overwrite; + return this; + } + + public Builder allowUploadToExisting(boolean allowUploadToExisting) { + this.allowUploadToExisting = allowUploadToExisting; + return this; + } + + public Builder apiEndpoint(String apiEndpoint) { + this.apiEndpoint = isNotBlank(apiEndpoint) ? apiEndpoint : Gitlab.ENDPOINT; + return this; + } + + public Builder setReleaseAssets(List assets) { + if (null != assets) { + this.assets.addAll(assets); + } + return this; + } + + @Override + public GitlabReleaser build() { + requireNonNull(logger, "'logger' must not be null"); + requireNonBlank(repo, "'repo' must not be blank"); + requireNonBlank(authorization, "'authorization' must not be blank"); + requireNonBlank(tagName, "'tagName' must not be blank"); + requireNonBlank(ref, "'ref' must not be blank"); + requireNonBlank(releaseName, "'releaseName' must not be blank"); + if (assets.isEmpty()) { + throw new IllegalArgumentException("'assets must not be empty"); + } + + return new GitlabReleaser(logger, repo, authorization, + tagName, ref, releaseName, + body, overwrite, + allowUploadToExisting, apiEndpoint, assets); + } + + @Override + public GitlabReleaser buildFromModel(JReleaserModel model) { + repo(model.getRelease().getRepoName()); + authorization(model.getRelease().getAuthorization()); + tagName(model.getRelease().getTagName()); + ref(model.getRelease().getTargetCommitish()); + releaseName(model.getRelease().getRepoName()); + body(model.getRelease().getBody()); + overwrite(model.getRelease().isOverwrite()); + allowUploadToExisting(model.getRelease().isAllowUploadToExisting()); + apiEndpoint(model.getRelease().getApiEndpoint()); + return build(); + } + } +} diff --git a/sdks/gitlab-java-sdk/src/main/module/module-info.java b/sdks/gitlab-java-sdk/src/main/module/module-info.java new file mode 100644 index 00000000..f3ae741c --- /dev/null +++ b/sdks/gitlab-java-sdk/src/main/module/module-info.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.sdk.gitlab { + exports org.kordamp.jreleaser.sdk.gitlab; + requires org.kordamp.jreleaser.model; + requires org.kordamp.jreleaser.util; + requires org.apache.tika.core; + requires gitlab4j.api; +} \ No newline at end of file diff --git a/sdks/sdkman-java-sdk/gradle.properties b/sdks/sdkman-java-sdk/gradle.properties new file mode 100644 index 00000000..16ab7bde --- /dev/null +++ b/sdks/sdkman-java-sdk/gradle.properties @@ -0,0 +1,19 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright 2020 Andres Almiray. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +project_description = Java SDK for SDKMAN diff --git a/sdks/sdkman-java-sdk/sdkman-java-sdk.gradle b/sdks/sdkman-java-sdk/sdkman-java-sdk.gradle new file mode 100644 index 00000000..ac153a60 --- /dev/null +++ b/sdks/sdkman-java-sdk/sdkman-java-sdk.gradle @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api project(':jreleaser-utils') + + api "com.fasterxml.jackson.core:jackson-core:$jacksonVersion" + api "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" + api "com.squareup.okhttp3:okhttp:$okhttpVersion" + + testImplementation "com.github.tomakehurst:wiremock-jre8:$wiremockVersion" +} \ No newline at end of file diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractMultiSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractMultiSdkmanCommand.java new file mode 100644 index 00000000..63a27eda --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractMultiSdkmanCommand.java @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import okhttp3.Response; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractMultiSdkmanCommand extends AbstractSdkmanCommand { + protected AbstractMultiSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https) { + super(consumerKey, + consumerToken, + candidate, + version, + apiHost, + https); + } + + protected Map getPayload() { + Map payload = new HashMap<>(); + payload.put("candidate", candidate); + payload.put("version", version); + return payload; + } + + protected abstract Response executeRequests() throws IOException; + + @Override + public void execute() throws SdkmanException { + try { + Response resp = executeRequests(); + int statusCode = resp.code(); + if (statusCode < 200 || statusCode >= 300) { + throw new IllegalStateException("Server returned error " + resp.message()); + } + } catch (Exception e) { + throw new SdkmanException("Sdk vendor operation failed", e); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractSdkmanCommand.java new file mode 100644 index 00000000..15b4fedc --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractSdkmanCommand.java @@ -0,0 +1,180 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractSdkmanCommand implements SdkmanCommand { + protected static final MediaType JSON = MediaType.get("application/json; charset=UTF-8"); + + protected final String consumerKey; + protected final String consumerToken; + protected final String candidate; + protected final String version; + protected final String apiHost; + protected final boolean https; + + protected AbstractSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https) { + this.consumerKey = consumerKey; + this.consumerToken = consumerToken; + this.candidate = candidate; + this.version = version; + this.apiHost = apiHost; + this.https = https; + } + + protected Map getPayload() { + Map payload = new HashMap<>(); + payload.put("candidate", candidate); + payload.put("version", version); + return payload; + } + + protected String toJson(Map payload) { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(payload); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Invalid JSON", e); + } + } + + protected Response execCall(Request req) throws IOException { + req = req.newBuilder() + .addHeader("Consumer-Key", consumerKey) + .addHeader("Consumer-Token", consumerToken) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + + OkHttpClient client = new OkHttpClient(); + try (Response response = client.newCall(req).execute()) { + return response; + } + } + + protected URL createURL(String endpoint) { + try { + return createURI(endpoint).toURL(); + } catch (MalformedURLException | URISyntaxException e) { + throw new IllegalArgumentException("Invalid URL", e); + } + } + + private URI createURI(String endpoint) throws URISyntaxException { + String host = apiHost; + int i = host.indexOf("://"); + if (i > -1) { + host = host.substring(i + 3); + } + + String[] parts = host.split(":"); + if (parts.length == 1) { + return new URI(https ? "https" : "http", host, endpoint, null); + } else if (parts.length == 2) { + return new URI(https ? "https" : "http", null, parts[0], Integer.parseInt(parts[1]), endpoint, null, null); + } else { + throw new URISyntaxException(apiHost, "Invalid"); + } + } + + static class Builder> { + protected String consumerKey; + protected String consumerToken; + protected String candidate; + protected String version; + protected String apiHost = "vendors.sdkman.io"; + protected boolean https = true; + + protected final S self() { + return (S) this; + } + + /** + * The SDK consumer key + */ + public S consumerKey(String consumerKey) { + this.consumerKey = requireNonBlank(consumerKey, "'consumerKey' must not be blank").trim(); + return self(); + } + + /** + * The SDK consumer token + */ + public S consumerToken(String consumerToken) { + this.consumerToken = requireNonBlank(consumerToken, "'consumerToken' must not be blank").trim(); + return self(); + } + + /** + * candidate identifier + */ + public S candidate(String candidate) { + this.candidate = requireNonBlank(candidate, "'candidate' must not be blank").trim(); + return self(); + } + + /** + * candidate version + */ + public S version(String version) { + this.version = requireNonBlank(version, "'version' must not be blank").trim(); + return self(); + } + + /** + * SDK service hostname + */ + public S apiHost(String apiHost) { + this.apiHost = requireNonBlank(apiHost, "'apiHost' must not be blank").trim(); + return self(); + } + + /** + * Use HTTPS + */ + public S https(boolean https) { + this.https = https; + return self(); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractSingleSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractSingleSdkmanCommand.java new file mode 100644 index 00000000..abbadeaa --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AbstractSingleSdkmanCommand.java @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import okhttp3.Request; +import okhttp3.Response; + +import java.util.Map; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +abstract class AbstractSingleSdkmanCommand extends AbstractSdkmanCommand { + protected AbstractSingleSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https) { + super(consumerKey, + consumerToken, + candidate, + version, + apiHost, + https); + } + + protected abstract Request createRequest(Map payload); + + @Override + public void execute() throws SdkmanException { + try { + Response resp = execCall(createRequest(getPayload())); + int statusCode = resp.code(); + if (statusCode < 200 || statusCode >= 300) { + throw new IllegalStateException("Server returned error " + resp.message()); + } + } catch (Exception e) { + throw new SdkmanException("Sdk vendor operation failed", e); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AnnounceSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AnnounceSdkmanCommand.java new file mode 100644 index 00000000..b7de1059 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/AnnounceSdkmanCommand.java @@ -0,0 +1,114 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import okhttp3.Request; +import okhttp3.RequestBody; + +import java.util.Map; + +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.ANNOUNCE_ENDPOINT; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class AnnounceSdkmanCommand extends AbstractSingleSdkmanCommand { + private final String hashtag; + private final String releaseNotesUrl; + + private AnnounceSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https, + String hashtag, + String releaseNotesUrl) { + super(consumerKey, + consumerToken, + candidate, + version, + apiHost, + https); + this.hashtag = hashtag; + this.releaseNotesUrl = releaseNotesUrl; + } + + @Override + protected Map getPayload() { + Map payload = super.getPayload(); + if (isNotBlank(hashtag)) payload.put("hashtag", hashtag.trim()); + if (isNotBlank(releaseNotesUrl)) payload.put("url", releaseNotesUrl.trim()); + return payload; + } + + @Override + protected Request createRequest(Map payload) { + RequestBody body = RequestBody.create(JSON, toJson(payload)); + return new Request.Builder() + .url(createURL(ANNOUNCE_ENDPOINT)) + .post(body) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AbstractSdkmanCommand.Builder { + private String hashtag; + private String releaseNotesUrl; + + /** + * The hashtag to use (legacy) + */ + public Builder hashtag(String hashtag) { + this.hashtag = hashtag; + return this; + } + + /** + * The URL where the release notes can be found + */ + public Builder releaseNotesUrl(String releaseNotesUrl) { + this.releaseNotesUrl = releaseNotesUrl; + return this; + } + + public AnnounceSdkmanCommand build() { + requireNonBlank(consumerKey, "'consumerKey' must not be blank"); + requireNonBlank(consumerToken, "'consumerToken' must not be blank"); + requireNonBlank(candidate, "'candidate' must not be blank"); + requireNonBlank(version, "'version' must not be blank"); + requireNonBlank(apiHost, "'apiHost' must not be blank"); + + return new AnnounceSdkmanCommand( + consumerKey, + consumerToken, + candidate, + version, + apiHost, + https, + hashtag, + releaseNotesUrl); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/ApiEndpoints.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/ApiEndpoints.java new file mode 100644 index 00000000..43d5eda0 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/ApiEndpoints.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ApiEndpoints { + public static final String ANNOUNCE_ENDPOINT = "/announce/struct"; + public static final String DEFAULT_ENDPOINT = "/default"; + public static final String RELEASE_ENDPOINT = "/release"; +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/DefaultSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/DefaultSdkmanCommand.java new file mode 100644 index 00000000..39f89591 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/DefaultSdkmanCommand.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import okhttp3.Request; +import okhttp3.RequestBody; + +import java.util.Map; + +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.DEFAULT_ENDPOINT; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class DefaultSdkmanCommand extends AbstractSingleSdkmanCommand { + private DefaultSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https) { + super(consumerKey, consumerToken, candidate, version, apiHost, https); + } + + @Override + protected Request createRequest(Map payload) { + RequestBody body = RequestBody.create(JSON, toJson(payload)); + return new Request.Builder() + .url(createURL(DEFAULT_ENDPOINT)) + .put(body) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AbstractSdkmanCommand.Builder { + public DefaultSdkmanCommand build() { + requireNonBlank(consumerKey, "'consumerKey' must not be blank"); + requireNonBlank(consumerToken, "'consumerToken' must not be blank"); + requireNonBlank(candidate, "'candidate' must not be blank"); + requireNonBlank(version, "'version' must not be blank"); + requireNonBlank(apiHost, "'apiHost' must not be blank"); + + return new DefaultSdkmanCommand( + consumerKey, + consumerToken, + candidate, + version, + apiHost, + https); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/MajorReleaseSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/MajorReleaseSdkmanCommand.java new file mode 100644 index 00000000..66bbe8d0 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/MajorReleaseSdkmanCommand.java @@ -0,0 +1,218 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.ANNOUNCE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.DEFAULT_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.RELEASE_ENDPOINT; +import static org.kordamp.jreleaser.util.StringUtils.isBlank; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class MajorReleaseSdkmanCommand extends AbstractMultiSdkmanCommand { + private final String hashtag; + private final String releaseNotesUrl; + private final String url; + private final Map platforms = new LinkedHashMap<>(); + + private MajorReleaseSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https, + String hashtag, + String releaseNotesUrl, + String url, + Map platforms) { + super(consumerKey, + consumerToken, + candidate, + version, + apiHost, + https); + this.hashtag = hashtag; + this.releaseNotesUrl = releaseNotesUrl; + this.url = url; + this.platforms.putAll(platforms); + } + + @Override + protected Response executeRequests() throws IOException { + List responses = new ArrayList<>(); + + if (platforms.isEmpty()) { + responses.add(execCall(createRequest(getReleasePayload()))); + } else { + for (Map.Entry platform : platforms.entrySet()) { + Map payload = super.getPayload(); + payload.put("platform", platform.getKey()); + payload.put("url", platform.getValue()); + responses.add(execCall(createRequest(payload))); + } + } + + responses.add(execCall(createAnnounceRequest())); + responses.add(execCall(createDefaultRequest())); + + return responses.stream() + .filter(resp -> { + int statusCode = resp.code(); + return statusCode < 200 || statusCode >= 300; + }) + .findFirst() + .orElse(responses.get(responses.size() - 1)); + } + + private Map getReleasePayload() { + Map payload = super.getPayload(); + payload.put("platform", "UNIVERSAL"); + payload.put("url", url); + return payload; + } + + private Request createRequest(Map payload) { + RequestBody body = RequestBody.create(JSON, toJson(payload)); + return new Request.Builder() + .url(createURL(RELEASE_ENDPOINT)) + .post(body) + .build(); + } + + private Request createAnnounceRequest() { + Map payload = super.getPayload(); + if (isNotBlank(hashtag)) payload.put("hashtag", hashtag.trim()); + if (isNotBlank(releaseNotesUrl)) payload.put("url", releaseNotesUrl.trim()); + + RequestBody body = RequestBody.create(JSON, toJson(payload)); + return new Request.Builder() + .url(createURL(ANNOUNCE_ENDPOINT)) + .post(body) + .build(); + } + + private Request createDefaultRequest() { + RequestBody body = RequestBody.create(JSON, toJson(super.getPayload())); + return new Request.Builder() + .url(createURL(DEFAULT_ENDPOINT)) + .put(body) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AbstractSdkmanCommand.Builder { + private final Map platforms = new LinkedHashMap<>(); + private String hashtag; + private String releaseNotesUrl; + private String url; + + /** + * The hashtag to use (legacy) + */ + public Builder hashtag(String hashtag) { + this.hashtag = hashtag; + return this; + } + + /** + * The URL where the release notes can be found + */ + public Builder releaseNotesUrl(String releaseNotesUrl) { + this.releaseNotesUrl = releaseNotesUrl; + return this; + } + + /** + * The URL from where the candidate version can be downloaded + */ + public Builder url(String url) { + this.url = url; + return this; + } + + /** + * Platform to downlodable URL mappings. + * Supported platforms are: + *
    + *
  • MAC_OSX
  • + *
  • WINDOWS_64
  • + *
  • LINUX_64
  • + *
  • LINUX_32
  • + *
+ * Example: + *
+         *     "MAC_OSX"   :"https://host/micronaut-x.y.z-macosx.zip"
+         *     "LINUX_64"  :"https://host/micronaut-x.y.z-linux64.zip"
+         *     "WINDOWS_64":"https://host/micronaut-x.y.z-win.zip"
+         * 
+ */ + public Builder platforms(Map platforms) { + this.platforms.putAll(platforms); + return this; + } + + public Builder platform(String platform, String url) { + this.platforms.put( + requireNonBlank(platform, "'platform' must not be blank").trim(), + requireNonBlank(url, "'url' must not be blank").trim()); + return this; + } + + public MajorReleaseSdkmanCommand build() { + requireNonBlank(consumerKey, "'consumerKey' must not be blank"); + requireNonBlank(consumerToken, "'consumerToken' must not be blank"); + requireNonBlank(candidate, "'candidate' must not be blank"); + requireNonBlank(version, "'version' must not be blank"); + requireNonBlank(apiHost, "'apiHost' must not be blank"); + + // url is required if platforms is empty + if ((platforms.isEmpty()) && isBlank(url)) { + throw new IllegalArgumentException("Missing url"); + } + + return new MajorReleaseSdkmanCommand( + consumerKey, + consumerToken, + candidate, + version, + apiHost, + https, + hashtag, + releaseNotesUrl, + url, + platforms); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/MinorReleaseSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/MinorReleaseSdkmanCommand.java new file mode 100644 index 00000000..ea2f87f8 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/MinorReleaseSdkmanCommand.java @@ -0,0 +1,208 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.ANNOUNCE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.RELEASE_ENDPOINT; +import static org.kordamp.jreleaser.util.StringUtils.isBlank; +import static org.kordamp.jreleaser.util.StringUtils.isNotBlank; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class MinorReleaseSdkmanCommand extends AbstractMultiSdkmanCommand { + private final String hashtag; + private final String releaseNotesUrl; + private final String url; + private final Map platforms = new LinkedHashMap<>(); + + private MinorReleaseSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https, + String hashtag, + String releaseNotesUrl, + String url, + Map platforms) { + super(consumerKey, + consumerToken, + candidate, + version, + apiHost, + https); + this.hashtag = hashtag; + this.releaseNotesUrl = releaseNotesUrl; + this.url = url; + this.platforms.putAll(platforms); + } + + @Override + protected Response executeRequests() throws IOException { + List responses = new ArrayList<>(); + + if (platforms.isEmpty()) { + responses.add(execCall(createRequest(getReleasePayload()))); + } else { + for (Map.Entry platform : platforms.entrySet()) { + Map payload = super.getPayload(); + payload.put("platform", platform.getKey()); + payload.put("url", platform.getValue()); + responses.add(execCall(createRequest(payload))); + } + } + + responses.add(execCall(createAnnounceRequest())); + + return responses.stream() + .filter(resp -> { + int statusCode = resp.code(); + return statusCode < 200 || statusCode >= 300; + }) + .findFirst() + .orElse(responses.get(responses.size() - 1)); + } + + private Map getReleasePayload() { + Map payload = super.getPayload(); + payload.put("platform", "UNIVERSAL"); + payload.put("url", url); + return payload; + } + + private Request createRequest(Map payload) { + RequestBody body = RequestBody.create(JSON, toJson(payload)); + return new Request.Builder() + .url(createURL(RELEASE_ENDPOINT)) + .post(body) + .build(); + } + + private Request createAnnounceRequest() { + Map payload = super.getPayload(); + if (isNotBlank(hashtag)) payload.put("hashtag", hashtag.trim()); + if (isNotBlank(releaseNotesUrl)) payload.put("url", releaseNotesUrl.trim()); + + RequestBody body = RequestBody.create(JSON, toJson(payload)); + return new Request.Builder() + .url(createURL(ANNOUNCE_ENDPOINT)) + .post(body) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AbstractSdkmanCommand.Builder { + private final Map platforms = new LinkedHashMap<>(); + private String hashtag; + private String releaseNotesUrl; + private String url; + + /** + * The hashtag to use (legacy) + */ + public Builder hashtag(String hashtag) { + this.hashtag = hashtag; + return this; + } + + /** + * The URL where the release notes can be found + */ + public Builder releaseNotesUrl(String releaseNotesUrl) { + this.releaseNotesUrl = releaseNotesUrl; + return this; + } + + /** + * The URL from where the candidate version can be downloaded + */ + public Builder url(String url) { + this.url = url; + return this; + } + + /** + * Platform to downlodable URL mappings. + * Supported platforms are: + *
    + *
  • MAC_OSX
  • + *
  • WINDOWS_64
  • + *
  • LINUX_64
  • + *
  • LINUX_32
  • + *
+ * Example: + *
+         *     "MAC_OSX"   :"https://host/micronaut-x.y.z-macosx.zip"
+         *     "LINUX_64"  :"https://host/micronaut-x.y.z-linux64.zip"
+         *     "WINDOWS_64":"https://host/micronaut-x.y.z-win.zip"
+         * 
+ */ + public Builder platforms(Map platforms) { + this.platforms.putAll(platforms); + return this; + } + + public Builder platform(String platform, String url) { + this.platforms.put( + requireNonBlank(platform, "'platform' must not be blank").trim(), + requireNonBlank(url, "'url' must not be blank").trim()); + return this; + } + + public MinorReleaseSdkmanCommand build() { + requireNonBlank(consumerKey, "'consumerKey' must not be blank"); + requireNonBlank(consumerToken, "'consumerToken' must not be blank"); + requireNonBlank(candidate, "'candidate' must not be blank"); + requireNonBlank(version, "'version' must not be blank"); + requireNonBlank(apiHost, "'apiHost' must not be blank"); + + // url is required if platforms is empty + if ((platforms.isEmpty()) && isBlank(url)) { + throw new IllegalArgumentException("Missing url"); + } + + return new MinorReleaseSdkmanCommand( + consumerKey, + consumerToken, + candidate, + version, + apiHost, + https, + hashtag, + releaseNotesUrl, + url, + platforms); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/ReleaseSdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/ReleaseSdkmanCommand.java new file mode 100644 index 00000000..1e307e1f --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/ReleaseSdkmanCommand.java @@ -0,0 +1,166 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.RELEASE_ENDPOINT; +import static org.kordamp.jreleaser.util.StringUtils.isBlank; +import static org.kordamp.jreleaser.util.StringUtils.requireNonBlank; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ReleaseSdkmanCommand extends AbstractMultiSdkmanCommand { + private final String url; + private final Map platforms = new LinkedHashMap<>(); + + private ReleaseSdkmanCommand(String consumerKey, + String consumerToken, + String candidate, + String version, + String apiHost, + boolean https, + String url, + Map platforms) { + super(consumerKey, + consumerToken, + candidate, + version, + apiHost, + https); + this.url = url; + this.platforms.putAll(platforms); + } + + @Override + protected Map getPayload() { + Map payload = super.getPayload(); + payload.put("platform", "UNIVERSAL"); + payload.put("url", url); + return payload; + } + + @Override + protected Response executeRequests() throws IOException { + if (platforms.isEmpty()) { + return execCall(createRequest(getPayload())); + } + + List responses = new ArrayList<>(); + for (Map.Entry platform : platforms.entrySet()) { + Map payload = super.getPayload(); + payload.put("platform", platform.getKey()); + payload.put("url", platform.getValue()); + responses.add(execCall(createRequest(payload))); + } + + return responses.stream() + .filter(resp -> { + int statusCode = resp.code(); + return statusCode < 200 || statusCode >= 300; + }) + .findFirst() + .orElse(responses.get(responses.size() - 1)); + } + + private Request createRequest(Map payload) { + RequestBody body = RequestBody.create(JSON, toJson(payload)); + return new Request.Builder() + .url(createURL(RELEASE_ENDPOINT)) + .post(body) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AbstractSdkmanCommand.Builder { + private final Map platforms = new LinkedHashMap<>(); + private String url; + + /** + * The URL from where the candidate version can be downloaded + */ + public Builder url(String url) { + this.url = url; + return this; + } + + /** + * Platform to downlodable URL mappings. + * Supported platforms are: + *
    + *
  • MAC_OSX
  • + *
  • WINDOWS_64
  • + *
  • LINUX_64
  • + *
  • LINUX_32
  • + *
+ * Example: + *
+         *     "MAC_OSX"   :"https://host/micronaut-x.y.z-macosx.zip"
+         *     "LINUX_64"  :"https://host/micronaut-x.y.z-linux64.zip"
+         *     "WINDOWS_64":"https://host/micronaut-x.y.z-win.zip"
+         * 
+ */ + public Builder platforms(Map platforms) { + this.platforms.putAll(platforms); + return this; + } + + public Builder platform(String platform, String url) { + this.platforms.put( + requireNonBlank(platform, "'platform' must not be blank").trim(), + requireNonBlank(url, "'url' must not be blank").trim()); + return this; + } + + public ReleaseSdkmanCommand build() { + requireNonBlank(consumerKey, "'consumerKey' must not be blank"); + requireNonBlank(consumerToken, "'consumerToken' must not be blank"); + requireNonBlank(candidate, "'candidate' must not be blank"); + requireNonBlank(version, "'version' must not be blank"); + requireNonBlank(apiHost, "'apiHost' must not be blank"); + + // url is required if platforms is empty + if ((platforms.isEmpty()) && isBlank(url)) { + throw new IllegalArgumentException("Missing url"); + } + + return new ReleaseSdkmanCommand( + consumerKey, + consumerToken, + candidate, + version, + apiHost, + https, + url, + platforms); + } + } +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/SdkmanCommand.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/SdkmanCommand.java new file mode 100644 index 00000000..1d7c5aaf --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/SdkmanCommand.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public interface SdkmanCommand { + void execute() throws SdkmanException; +} diff --git a/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/SdkmanException.java b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/SdkmanException.java new file mode 100644 index 00000000..67ddfad6 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/java/org/kordamp/jreleaser/sdk/sdkman/SdkmanException.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class SdkmanException extends Exception { + public SdkmanException(String message) { + super(message); + } + + public SdkmanException(String message, Throwable cause) { + super(message, cause); + } + + public SdkmanException(Throwable cause) { + super(cause); + } +} diff --git a/sdks/sdkman-java-sdk/src/main/module/module-info.java b/sdks/sdkman-java-sdk/src/main/module/module-info.java new file mode 100644 index 00000000..9c5d4fba --- /dev/null +++ b/sdks/sdkman-java-sdk/src/main/module/module-info.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module org.kordamp.jreleaser.sdk.sdkman { + exports org.kordamp.jreleaser.sdk.sdkman; + requires org.kordamp.jreleaser.util; + requires okhttp3; + requires com.fasterxml.jackson.databind; +} \ No newline at end of file diff --git a/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/AnnounceSdkmanCommandTest.java b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/AnnounceSdkmanCommandTest.java new file mode 100644 index 00000000..eb7ae2ab --- /dev/null +++ b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/AnnounceSdkmanCommandTest.java @@ -0,0 +1,84 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.ANNOUNCE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.Stubs.verifyPost; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class AnnounceSdkmanCommandTest { + @RegisterExtension + WireMockExtension api = new WireMockExtension(options().dynamicPort()); + + @Test + public void testStructuredAnnouncement() throws SdkmanException { + // given: + stubFor(post(urlEqualTo(ANNOUNCE_ENDPOINT)) + .willReturn(okJson("{\"status\": 202, \"message\":\"success\"}"))); + + AnnounceSdkmanCommand command = AnnounceSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .https(false) + .build(); + + // when: + command.execute(); + + // then: + verifyPost(ANNOUNCE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\"\n" + + "}"); + } + + @Test + public void testError() { + // given: + stubFor(post(urlEqualTo(ANNOUNCE_ENDPOINT)) + .willReturn(aResponse().withStatus(400))); + + AnnounceSdkmanCommand command = AnnounceSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .https(false) + .build(); + + // expected: + assertThrows(SdkmanException.class, command::execute); + } +} diff --git a/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/DefaultSdkmanCommandTest.java b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/DefaultSdkmanCommandTest.java new file mode 100644 index 00000000..b547e165 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/DefaultSdkmanCommandTest.java @@ -0,0 +1,85 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.put; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.DEFAULT_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.Stubs.verifyPut; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class DefaultSdkmanCommandTest { + @RegisterExtension + WireMockExtension api = new WireMockExtension(options().dynamicPort()); + + @Test + public void testStructuredAnnouncement() throws SdkmanException { + // given: + stubFor(put(urlEqualTo(DEFAULT_ENDPOINT)) + .willReturn(okJson("{\"status\": 202, \"message\":\"success\"}"))); + + DefaultSdkmanCommand command = DefaultSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .https(false) + .build(); + + // when: + command.execute(); + + // then: + verifyPut(DEFAULT_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\"\n" + + "}"); + } + + @Test + public void testError() { + // given: + stubFor(post(urlEqualTo(DEFAULT_ENDPOINT)) + .willReturn(aResponse().withStatus(400))); + + DefaultSdkmanCommand command = DefaultSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .https(false) + .build(); + + // expected: + assertThrows(SdkmanException.class, command::execute); + } +} diff --git a/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/MajorReleaseSdkmanCommandTest.java b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/MajorReleaseSdkmanCommandTest.java new file mode 100644 index 00000000..8ef0115a --- /dev/null +++ b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/MajorReleaseSdkmanCommandTest.java @@ -0,0 +1,104 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.put; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.ANNOUNCE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.DEFAULT_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.RELEASE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.Stubs.verifyPost; +import static org.kordamp.jreleaser.sdk.sdkman.Stubs.verifyPut; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class MajorReleaseSdkmanCommandTest { + @RegisterExtension + WireMockExtension api = new WireMockExtension(options().dynamicPort()); + + @Test + public void testMajorReleaseWithAnnouncement() throws SdkmanException { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + stubFor(post(urlEqualTo(ANNOUNCE_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + stubFor(put(urlEqualTo(DEFAULT_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + + MajorReleaseSdkmanCommand command = MajorReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .url("https://host/jreleaser-1.0.0.zip") + .https(false) + .build(); + + // when: + command.execute(); + + // then: + verifyPost(RELEASE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"platform\": \"UNIVERSAL\",\n" + + " \"url\": \"https://host/jreleaser-1.0.0.zip\"\n" + + "}"); + verifyPost(ANNOUNCE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\"\n" + + "}"); + verifyPut(DEFAULT_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\"\n" + + "}"); + } + + @Test + public void testError() { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(aResponse().withStatus(500))); + + MajorReleaseSdkmanCommand command = MajorReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .url("https://host/jreleaser-1.0.0.zip") + .https(false) + .build(); + + // expected: + assertThrows(SdkmanException.class, command::execute); + } +} diff --git a/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/MinorReleaseSdkmanCommandTest.java b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/MinorReleaseSdkmanCommandTest.java new file mode 100644 index 00000000..77e5925f --- /dev/null +++ b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/MinorReleaseSdkmanCommandTest.java @@ -0,0 +1,95 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.ANNOUNCE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.RELEASE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.Stubs.verifyPost; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class MinorReleaseSdkmanCommandTest { + @RegisterExtension + WireMockExtension api = new WireMockExtension(options().dynamicPort()); + + @Test + public void testMinorReleaseWithAnnouncement() throws SdkmanException { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + stubFor(post(urlEqualTo(ANNOUNCE_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + + MinorReleaseSdkmanCommand command = MinorReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .url("https://host/jreleaser-1.0.0.zip") + .https(false) + .build(); + + // when: + command.execute(); + + // then: + verifyPost(RELEASE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"platform\": \"UNIVERSAL\",\n" + + " \"url\": \"https://host/jreleaser-1.0.0.zip\"\n" + + "}"); + verifyPost(ANNOUNCE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\"\n" + + "}"); + } + + @Test + public void testError() { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(aResponse().withStatus(500))); + + MinorReleaseSdkmanCommand command = MinorReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .url("https://host/jreleaser-1.0.0.zip") + .https(false) + .build(); + + // expected: + assertThrows(SdkmanException.class, command::execute); + } +} diff --git a/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/ReleaseSdkmanCommandTest.java b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/ReleaseSdkmanCommandTest.java new file mode 100644 index 00000000..73820afb --- /dev/null +++ b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/ReleaseSdkmanCommandTest.java @@ -0,0 +1,158 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.kordamp.jreleaser.sdk.sdkman.ApiEndpoints.RELEASE_ENDPOINT; +import static org.kordamp.jreleaser.sdk.sdkman.Stubs.verifyPost; + +/** + * @author Andres Almiray + * @since 0.1.0 + */ +public class ReleaseSdkmanCommandTest { + @RegisterExtension + WireMockExtension api = new WireMockExtension(options().dynamicPort()); + + @Test + public void testSingleUniversalRelease() throws SdkmanException { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + + ReleaseSdkmanCommand command = ReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .url("https://host/jreleaser-1.0.0.zip") + .https(false) + .build(); + + // when: + command.execute(); + + // then: + verifyPost(RELEASE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"platform\": \"UNIVERSAL\",\n" + + " \"url\": \"https://host/jreleaser-1.0.0.zip\"\n" + + "}"); + } + + @Test + public void testSinglePlatformRelease() throws SdkmanException { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + + ReleaseSdkmanCommand command = ReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .platform("MAC_OSX", "https://host/jreleaser-1.0.0.zip") + .https(false) + .build(); + + // when: + command.execute(); + + // then: + verifyPost(RELEASE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"platform\": \"MAC_OSX\",\n" + + " \"url\": \"https://host/jreleaser-1.0.0.zip\"\n" + + "}"); + } + + @Test + public void testMultiPlatformRelease() throws SdkmanException { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(okJson("{\"status\": 201, \"message\":\"success\"}"))); + + ReleaseSdkmanCommand command = ReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .platform("MAC_OSX", "https://host/jreleaser-1.0.0-mac.zip") + .platform("WINDOWS_64", "https://host/jreleaser-1.0.0-win.zip") + .platform("LINUX_64", "https://host/jreleaser-1.0.0-linux.zip") + .https(false) + .build(); + + // when: + command.execute(); + + // then: + verifyPost(RELEASE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"platform\": \"MAC_OSX\",\n" + + " \"url\": \"https://host/jreleaser-1.0.0-mac.zip\"\n" + + "}"); + verifyPost(RELEASE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"platform\": \"WINDOWS_64\",\n" + + " \"url\": \"https://host/jreleaser-1.0.0-win.zip\"\n" + + "}"); + verifyPost(RELEASE_ENDPOINT, "{\n" + + " \"candidate\": \"jreleaser\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"platform\": \"LINUX_64\",\n" + + " \"url\": \"https://host/jreleaser-1.0.0-linux.zip\"\n" + + "}"); + } + + @Test + public void testError() { + // given: + stubFor(post(urlEqualTo(RELEASE_ENDPOINT)) + .willReturn(aResponse().withStatus(500))); + + ReleaseSdkmanCommand command = ReleaseSdkmanCommand.builder() + .apiHost(api.baseUrl()) + .consumerKey("CONSUMER_KEY") + .consumerToken("CONSUMER_TOKEN") + .candidate("jreleaser") + .version("1.0.0") + .url("https://host/jreleaser-1.0.0.zip") + .https(false) + .build(); + + // expected: + assertThrows(SdkmanException.class, command::execute); + } +} diff --git a/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/Stubs.java b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/Stubs.java new file mode 100644 index 00000000..61ebb75d --- /dev/null +++ b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/Stubs.java @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; + +class Stubs { + static void verifyPost(String endpoint, String json) { + verifyRequest(postRequestedFor(urlEqualTo(endpoint)), json); + } + + static void verifyPut(String endpoint, String json) { + verifyRequest(putRequestedFor(urlEqualTo(endpoint)), json); + } + + private static void verifyRequest(RequestPatternBuilder builder, String json) { + verify(builder.withHeader("Content-Type", equalTo("application/json; charset=UTF-8")) + .withHeader("Accept", equalTo("application/json")) + .withHeader("Consumer-Key", equalTo("CONSUMER_KEY")) + .withHeader("Consumer-Token", equalTo("CONSUMER_TOKEN")) + .withRequestBody(equalToJson(json))); + } +} diff --git a/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/WireMockExtension.java b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/WireMockExtension.java new file mode 100644 index 00000000..250f5936 --- /dev/null +++ b/sdks/sdkman-java-sdk/src/test/java/org/kordamp/jreleaser/sdk/sdkman/WireMockExtension.java @@ -0,0 +1,43 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kordamp.jreleaser.sdk.sdkman; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.core.Options; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +class WireMockExtension extends WireMockServer implements BeforeEachCallback, AfterEachCallback { + WireMockExtension(Options options) { + super(options); + } + + @Override + public void beforeEach(ExtensionContext context) { + this.start(); + WireMock.configureFor("localhost", port()); + } + + @Override + public void afterEach(ExtensionContext context) { + this.stop(); + this.resetAll(); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..afe9a7b3 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,83 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2020 Andres Almiray. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +buildscript { + repositories { + gradlePluginPortal() + jcenter() + mavenLocal() + } + dependencies { + classpath "gradle.plugin.org.beryx:badass-jar:$beryxJarPluginVersion" + classpath "org.ajoberstar:gradle-git-publish:$gitPluginVersion" + classpath "org.kordamp.gradle:java-project-gradle-plugin:$kordampPluginVersion" + classpath "org.kordamp.gradle:groovy-project-gradle-plugin:$kordampPluginVersion" + classpath "org.kordamp.gradle:bintray-gradle-plugin:$kordampPluginVersion" + classpath "org.kordamp.gradle:guide-gradle-plugin:$kordampPluginVersion" + classpath "org.kordamp.gradle:plugin-gradle-plugin:$kordampPluginVersion" + classpath "org.kordamp.gradle:kordamp-parentbuild:$kordampBuildVersion" + classpath "org.ow2.asm:asm:$asmVersion" + classpath "org.ow2.asm:asm-commons:$asmVersion" + classpath "org.ow2.asm:asm-analysis:$asmVersion" + classpath "org.ow2.asm:asm-tree:$asmVersion" + } +} +apply plugin: 'org.kordamp.gradle.kordamp-parentbuild' + +rootProject.name = 'jreleaser' + +projects { + directories = ['apps', 'docs', 'core', 'sdks', 'plugins'] + + plugins { + all { + id 'idea' + } + path(':') { + id 'org.kordamp.gradle.java-project' + id 'org.kordamp.gradle.bintray' + } + path(':guide') { + id 'org.kordamp.gradle.guide' + id 'org.ajoberstar.git-publish' + } + dirs(['apps', 'core', 'sdks', 'plugins']) { + id 'java-library' + id 'org.beryx.jar' + } + } +} + +enforce { + mergeStrategy = 'append' + + rule(enforcer.rules.ForceDependencies) { r -> + r.dependencies.addAll "org.apache.maven:maven-artifact:$mavenVersion", + "org.codehaus.plexus:plexus-utils:$plexusVersion", + "org.codehaus.plexus:plexus-component-annotations:1.7.1", + "com.fasterxml.jackson.core:jackson-core:$jacksonVersion", + "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion", + "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion", + "org.hamcrest:hamcrest-core:$hamcrestVersion", + "org.slf4j:slf4j-api:$slf4jVersion", + "org.apache.commons:commons-lang3:3.8.1", + "org.opentest4j:opentest4j:1.2.0", + "jakarta.activation:jakarta.activation-api:1.2.2", + "org.yaml:snakeyaml:$snakeYamlVersion", + "info.picocli:picocli:$picocliVersion" + } +}