Add GH workflow

This commit is contained in:
Andres Almiray
2020-11-28 15:36:44 +01:00
parent f9bfc18c0b
commit c534f8b854
221 changed files with 16844 additions and 0 deletions

View File

@@ -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

View File

@@ -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)
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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'
)
}
}

View File

@@ -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<Integer> {
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();
}

View File

@@ -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=<configFile>'"));
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=<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<String> 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);
}
}
}

View File

@@ -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<ToolProcessingException> 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");
}
}

View File

@@ -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");
}
}

View File

@@ -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());
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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, Stream<Artifact>>) 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;
}
}

View File

@@ -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=<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);
}
}
}

View File

@@ -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<URL> 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;
}
}

View File

@@ -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 + "|@"));
}
}

View File

@@ -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 + "|@");
}
}
}

View File

@@ -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 + "|@");
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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}

105
build.gradle Normal file
View File

@@ -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()
}
}
}

View File

@@ -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

View File

@@ -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}"
}

View File

@@ -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<? extends Object> type, String name) {
if (name.equals("class")) {
name = "clazz";
}
return super.getProperty(type, name);
}
});
Yaml yaml = new Yaml(c);
return yaml.load(inputStream);
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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')
}

View File

@@ -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<JReleaserConfigParser> 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);
}
}

View File

@@ -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.</p>
* 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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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')
}

View File

@@ -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<String, Object> asMap();
}

View File

@@ -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<String, Object> 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<String, Object> getExtraProperties() {
return extraProperties;
}
@Override
public void setExtraProperties(Map<String, Object> extraProperties) {
this.extraProperties.clear();
this.extraProperties.putAll(extraProperties);
}
@Override
public void addExtraProperties(Map<String, Object> extraProperties) {
this.extraProperties.putAll(extraProperties);
}
@Override
public final Map<String, Object> asMap() {
if (!isEnabled()) return Collections.emptyMap();
Map<String, Object> props = new LinkedHashMap<>();
props.put("enabled", isEnabled());
props.put("templateDirectory", templateDirectory);
asMap(props);
props.put("extraProperties", extraProperties);
Map<String, Object> map = new LinkedHashMap<>();
map.put(getToolName(), props);
return map;
}
protected abstract void asMap(Map<String, Object> props);
}

View File

@@ -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<String, Object> asMap() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("path", path);
map.put("hash", hash);
map.put("osClassifier", osClassifier);
map.put("javaVersion", javaVersion);
return map;
}
}

View File

@@ -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<String, String> dependencies = new LinkedHashMap<>();
public Brew() {
super(TOOL_NAME);
}
void setAll(Brew brew) {
super.setAll(brew);
setDependencies(brew.dependencies);
}
public Map<String, String> getDependencies() {
return dependencies;
}
public void setDependencies(Map<String, String> dependencies) {
this.dependencies.clear();
this.dependencies.putAll(dependencies);
}
public void addDependencies(Map<String, String> 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<String, Object> props) {
props.put("dependencies", dependencies);
}
}

View File

@@ -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<String, Object> props) {
// empty
}
}

View File

@@ -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<String> tags = new ArrayList<>();
private final Map<String, Object> extraProperties = new LinkedHashMap<>();
private final List<Artifact> 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<Artifact> getArtifacts() {
return artifacts;
}
public void setArtifacts(List<Artifact> artifacts) {
this.artifacts.clear();
this.artifacts.addAll(artifacts);
}
public void addArtifacts(List<Artifact> artifacts) {
this.artifacts.addAll(artifacts);
}
public void addArtifact(Artifact artifact) {
if (null != artifact) {
this.artifacts.add(artifact);
}
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags.clear();
this.tags.addAll(tags);
}
public void addTags(List<String> 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<String, Object> getExtraProperties() {
return extraProperties;
}
@Override
public void setExtraProperties(Map<String, Object> extraProperties) {
this.extraProperties.putAll(extraProperties);
}
@Override
public void addExtraProperties(Map<String, Object> extraProperties) {
this.extraProperties.putAll(extraProperties);
}
// --== TOOLs ==--
public <T extends Tool> T findTool(String name) {
if (isBlank(name)) {
throw new IllegalArgumentException("Tool name must not be blank");
}
return resolveTool(name);
}
public <T extends Tool> T getTool(String name) {
T tool = findTool(name);
if (null != tool) {
return tool;
}
throw new IllegalArgumentException("Tool '" + name + "' has not been configured");
}
private <T extends Tool> 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<String, Object> asMap() {
Map<String, Object> 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<String, Object> map = new LinkedHashMap<>();
map.put(name, props);
return map;
}
public static Set<String> supportedTools() {
Set<String> 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,
}
}

View File

@@ -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<String, Object> getExtraProperties();
void setExtraProperties(Map<String, Object> properties);
void addExtraProperties(Map<String, Object> properties);
}

View File

@@ -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<String, Distribution> 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<String, Distribution> getDistributions() {
return distributions;
}
public void setDistributions(Map<String, Distribution> distributions) {
this.distributions.clear();
this.distributions.putAll(distributions);
}
public void addDistributions(Map<String, Distribution> 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<String, Object> asMap() {
Map<String, Object> 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;
}
}

View File

@@ -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<String, ?>) 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<String, ?> 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<String, ?> 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();
}
}
}

View File

@@ -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<String> validate(Logger logger, Path basedir, JReleaserModel model) {
List<String> errors = new ArrayList<>();
validateModel(logger, basedir, model, errors);
return Collections.unmodifiableList(errors);
}
private static void validateModel(Logger logger, Path basedir, JReleaserModel model, List<String> 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<String> 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<String> 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<String, Distribution> distributions, List<String> 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<String, Distribution> 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<String> 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<String> 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<String, List<Artifact>> byClassifier = distribution.getArtifacts().stream()
.collect(groupingBy(artifact -> isBlank(artifact.getOsClassifier()) ? "<nil>" : artifact.getOsClassifier()));
// check classifiers by extension
byClassifier.entrySet().forEach(c -> {
String classifier = "<nil>".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<String> 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<String> 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<String, String> 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<String> 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<String> 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<String> 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<String, Object> extraProperties = new LinkedHashMap<>(common.getExtraProperties());
extraProperties.putAll(tool.getExtraProperties());
tool.setExtraProperties(extraProperties);
}
private static void mergeSnapPlugs(Snap tool, Snap common) {
Map<String, Plug> commonPlugs = common.getPlugs().stream()
.collect(Collectors.toMap(Plug::getName, Plug::copyOf));
Map<String, Plug> 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<String, Slot> commonSlots = common.getSlots().stream()
.collect(Collectors.toMap(Slot::getName, Slot::copyOf));
Map<String, Slot> 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<String> 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<String, Object> props = extra.getExtraProperties()
.entrySet().stream()
.collect(Collectors.toMap(
e -> prefix + capitalize(e.getKey()),
Map.Entry::getValue));
extra.setExtraProperties(props);
}
}
}

View File

@@ -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<String, Object> asMap() {
Map<String, Object> map = new LinkedHashMap<>();
map.putAll(brew.asMap());
map.putAll(chocolatey.asMap());
map.putAll(scoop.asMap());
map.putAll(snap.asMap());
return map;
}
}

View File

@@ -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<String, String> attributes = new LinkedHashMap<>();
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes.clear();
this.attributes.putAll(attributes);
}
public void addAttributes(Map<String, String> attributes) {
this.attributes.putAll(attributes);
}
public void addAttribute(String key, String value) {
attributes.put(key, value);
}
public Map<String, Object> asMap() {
Map<String, Object> 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;
}
}

View File

@@ -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<String> authors = new ArrayList<>();
private final List<String> tags = new ArrayList<>();
private final Map<String, Object> 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<String, Object> getExtraProperties() {
return extraProperties;
}
@Override
public void setExtraProperties(Map<String, Object> extraProperties) {
this.extraProperties.putAll(extraProperties);
}
@Override
public void addExtraProperties(Map<String, Object> extraProperties) {
this.extraProperties.putAll(extraProperties);
}
public List<String> getAuthors() {
return authors;
}
public void setAuthors(List<String> authors) {
this.authors.clear();
this.authors.addAll(authors);
}
public void addAuthors(List<String> 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<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags.clear();
this.tags.addAll(tags);
}
public void addTags(List<String> 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<String, Object> asMap() {
Map<String, Object> 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;
}
}

View File

@@ -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<String, Object> asMap() {
Map<String, Object> 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;
}
}
}

View File

@@ -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<String, Object> props) {
props.put("checkverUrl", checkverUrl);
props.put("autoupdateUrl", autoupdateUrl);
}
}

View File

@@ -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<String, String> attributes = new LinkedHashMap<>();
private final List<String> reads = new ArrayList<>();
private final List<String> writes = new ArrayList<>();
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes.clear();
this.attributes.putAll(attributes);
}
public void addAttributes(Map<String, String> attributes) {
this.attributes.putAll(attributes);
}
public void addAttribute(String key, String value) {
attributes.put(key, value);
}
public List<String> getReads() {
return reads;
}
public void setReads(List<String> reads) {
this.reads.clear();
this.reads.addAll(reads);
}
public void addReads(List<String> 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<String> getWrites() {
return writes;
}
public void setWrites(List<String> writes) {
this.writes.clear();
this.writes.addAll(writes);
}
public void addWrites(List<String> 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<String, Object> asMap() {
Map<String, Object> 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;
}
}

View File

@@ -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<String> localPlugs = new ArrayList<>();
private final List<Plug> plugs = new ArrayList<>();
private final List<Slot> 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<String> getLocalPlugs() {
return localPlugs;
}
public void setLocalPlugs(List<String> localPlugs) {
this.localPlugs.clear();
this.localPlugs.addAll(localPlugs);
}
public void addLocalPlugs(List<String> 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<Plug> getPlugs() {
return plugs;
}
public void setPlugs(List<Plug> plugs) {
this.plugs.clear();
this.plugs.addAll(plugs);
}
public void addPlugs(List<Plug> 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<Slot> getSlots() {
return slots;
}
public void setSlots(List<Slot> slots) {
this.slots.clear();
this.slots.addAll(slots);
}
public void addSlots(List<Slot> 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<String, Object> 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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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 extends Releaser> {
R build();
R buildFromModel(JReleaserModel model);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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')
}

View File

@@ -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 extends ReleaserBuilder> 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());
}
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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);
}
}

View File

@@ -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<String, Reader> templates = TemplateUtils.resolveTemplates(logger, distributionType, toolName);
for (Map.Entry<String, Reader> 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);
}
}
}

View File

@@ -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<String, Reader> resolveAndMergeTemplates(Logger logger, Distribution.DistributionType distributionType, String toolName, Path templateDirectory) {
Map<String, Reader> templates = resolveTemplates(logger, distributionType, toolName);
if (null != templateDirectory && templateDirectory.toFile().exists()) {
templates.putAll(resolveTemplates(logger, distributionType, toolName, templateDirectory));
}
return templates;
}
public static Map<String, Reader> resolveTemplates(Logger logger, Distribution.DistributionType distributionType, String toolName, Path templateDirectory) {
Map<String, Reader> templates = new LinkedHashMap<>();
try {
Files.walkFileTree(templateDirectory, new SimpleFileVisitor<Path>() {
@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<String, Reader> resolveTemplates(Logger logger, Distribution.DistributionType distributionType, String toolName) {
String distributionTypeName = distributionType.name().toLowerCase().replace('_', '-');
String templatePrefix = "META-INF/jreleaser/templates/" +
distributionTypeName + "/" + toolName.toLowerCase();
Map<String, Reader> 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<JarEntry> 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<JarEntry> 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;
}
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Do not remove this test for UTF-8: if “Ω” doesnt appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. -->
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
<metadata>
<!-- required -->
<id>{{distributionName}}</id>
<version>{{projectVersion}}</version>
<authors>{{projectAuthorsByComma}}</authors>
<description>{{projectLongDescription}}</description>
<!-- optional -->
<title>{{projectName}}</title>
<projectUrl>{{projectWebsite}}</projectUrl>
<license type="expression">{{projectLicense}}</license>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<tags>{{distributionTagsBySpace}}</tags>
<summary>{{projectDescription}}</summary>
<releaseNotes>{{distributionReleaseNotes}}</releaseNotes>
</metadata>
<files>
<file src="tools\**" target="tools" />
</files>
</package>

View File

@@ -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

View File

@@ -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

View File

@@ -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"
}
}
}

View File

@@ -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}}

View File

@@ -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

View File

@@ -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" "$@"

View File

@@ -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}}

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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<T extends Tool> implements ToolProcessor<T> {
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<String, Object> context) throws ToolProcessingException {
Tool tool = distribution.getTool(getToolName());
try {
String distributionName = distribution.getName();
getLogger().debug("Creating context for {}/{}", distributionName, getToolName());
Map<String, Object> 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<String, Reader> templates = resolveAndMergeTemplates(logger, distribution.getType(), getToolName(), tool.getTemplateDirectory());
for (Map.Entry<String, Reader> 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<String, Object> context) throws ToolProcessingException {
try {
String distributionName = distribution.getName();
getLogger().debug("Creating context for {}/{}", distributionName, getToolName());
Map<String, Object> 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<String, Object> context) throws ToolProcessingException;
protected abstract void writeFile(Project project, Distribution distribution, String content, Map<String, Object> 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<String, Object> fillContext(Distribution distribution, Map<String, Object> context) throws ToolProcessingException {
Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> context, Distribution distribution) throws ToolProcessingException;
protected boolean executeCommand(List<String> 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<String, Object> context,
Distribution distribution) throws ToolProcessingException {
Set<String> fileExtensions = resolveByExtensionsFor(distribution.getType());
List<Artifact> 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<String, Object> 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<String> 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<? super String> consumer) {
String str = stream.toString();
if (isBlank(str)) return;
Arrays.stream(str.split(System.lineSeparator()))
.forEach(consumer);
}
}

View File

@@ -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<Brew> {
public BrewToolProcessor(Logger logger, JReleaserModel model, Brew brew) {
super(logger, model, brew);
}
@Override
protected boolean doPackageDistribution(Distribution distribution, Map<String, Object> context) throws ToolProcessingException {
getLogger().debug("Tool {} does not require additional packaging", getToolName());
return true;
}
@Override
protected Set<String> resolveByExtensionsFor(Distribution.DistributionType type) {
Set<String> set = new LinkedHashSet<>();
set.add(".zip");
return set;
}
@Override
protected void fillToolProperties(Map<String, Object> 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<String, Object> 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() + "!!";
}
}
}

View File

@@ -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<Chocolatey> {
public ChocolateyToolProcessor(Logger logger, JReleaserModel model, Chocolatey tool) {
super(logger, model, tool);
}
@Override
protected boolean doPackageDistribution(Distribution distribution, Map<String, Object> context) throws ToolProcessingException {
if (!OsUtils.isWindows()) {
getLogger().debug("Tool {} must run on Windows", getToolName());
return false;
}
return true;
}
@Override
protected Set<String> resolveByExtensionsFor(Distribution.DistributionType type) {
Set<String> set = new LinkedHashSet<>();
set.add(".zip");
return set;
}
@Override
protected void fillToolProperties(Map<String, Object> context, Distribution distribution) throws ToolProcessingException {
// noop
}
@Override
protected void writeFile(Project project, Distribution distribution, String content, Map<String, Object> 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);
}
}

View File

@@ -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__";
}

View File

@@ -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<String, Object> 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<String, Object> 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);
}
}
}

View File

@@ -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 <T extends Tool> boolean verifyAndAddArtifacts(Logger logger,
Map<String, Object> context,
JReleaserModel model,
Distribution distribution,
String artifactExtension,
T tool) throws ToolProcessingException {
List<Artifact> 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<String, Object> 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<String, Object> 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<String, Object> 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);
}
}
}
}

View File

@@ -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<Scoop> {
public ScoopToolProcessor(Logger logger, JReleaserModel model, Scoop scoop) {
super(logger, model, scoop);
}
@Override
protected boolean doPackageDistribution(Distribution distribution, Map<String, Object> context) throws ToolProcessingException {
getLogger().debug("Tool {} does not require additional packaging", getToolName());
return true;
}
@Override
protected Set<String> resolveByExtensionsFor(Distribution.DistributionType type) {
Set<String> set = new LinkedHashSet<>();
set.add(".zip");
return set;
}
@Override
protected void fillToolProperties(Map<String, Object> 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<String, Object> context) {
if (!getTool().getCheckverUrl().contains("{{")) {
return getTool().getCheckverUrl();
}
return applyTemplate(new StringReader(getTool().getCheckverUrl()), context);
}
private Object resolveAutoupdateUrl(Map<String, Object> context) {
if (!getTool().getAutoupdateUrl().contains("{{")) {
return getTool().getAutoupdateUrl();
}
Map<String, Object> 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<String, Object> context, String fileName)
throws ToolProcessingException {
Path outputDirectory = (Path) context.get(Constants.KEY_PREPARE_DIRECTORY);
Path outputFile = outputDirectory.resolve(trimTplExtension(fileName));
writeFile(content, outputFile);
}
}

View File

@@ -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<Snap> {
public SnapToolProcessor(Logger logger, JReleaserModel model, Snap snap) {
super(logger, model, snap);
}
@Override
protected boolean doPackageDistribution(Distribution distribution, Map<String, Object> 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<String> resolveByExtensionsFor(Distribution.DistributionType type) {
Set<String> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> context) throws ToolProcessingException {
List<String> 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<String, Object> 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<String> 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 extends Tool> {
T getTool();
String getToolName();
Logger getLogger();
JReleaserModel getModel();
boolean prepareDistribution(Distribution distribution, Map<String, Object> context) throws ToolProcessingException;
boolean packageDistribution(Distribution distribution, Map<String, Object> context) throws ToolProcessingException;
}

View File

@@ -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 <T extends Tool> ToolProcessor<T> findProcessor(Logger logger, JReleaserModel model, T tool) {
if (tool instanceof Brew) {
return (ToolProcessor<T>) new BrewToolProcessor(logger, model, (Brew) tool);
} else if (tool instanceof Chocolatey) {
return (ToolProcessor<T>) new ChocolateyToolProcessor(logger, model, (Chocolatey) tool);
} else if (tool instanceof Scoop) {
return (ToolProcessor<T>) new ScoopToolProcessor(logger, model, (Scoop) tool);
} else if (tool instanceof Snap) {
return (ToolProcessor<T>) new SnapToolProcessor(logger, model, (Snap) tool);
}
throw new IllegalArgumentException("Unsupported tool " + tool);
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 }
}

View File

@@ -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<PosixFilePermission> perms = PosixFilePermissions.fromString(accessRights);
FileAttribute<Set<PosixFilePermission>> 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<PosixFilePermission> 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<Path> {
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;
}
}
}

View File

@@ -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);
}

View File

@@ -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<String> keySet() {
return OS_DETECTOR.getProperties().keySet();
}
public static Collection<String> values() {
return OS_DETECTOR.getProperties().values();
}
public static Set<Map.Entry<String, String>> entrySet() {
return OS_DETECTOR.getProperties().entrySet();
}
private static final class OsDetector extends Detector {
private final Map<String, String> 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<String, String> 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
}
}
}

View File

@@ -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<String> words = new ArrayList<String>();
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<String> j = words.iterator(); j.hasNext(); ) {
String word = j.next();
buf.append(word);
if (j.hasNext()) {
buf.append(" ");
}
}
return buf.toString();
}
/**
* <p>Determines whether a given string is <code>null</code>, 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 <code>false</code>.</p>
*
* @param str The string to test.
* @return <code> true</code> if the string is <code>null</code>, 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;
}
/**
* <p>Determines whether a given string is not <code>null</code>, 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 <code>true</code>.</p>
*
* @param str The string to test.
* @return <code> true</code> if the string is not <code>null</code>, 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:
* <blockquote><pre>
* Foo(String str) {* this.str = GriffonNameUtils.requireNonBlank(str)
* }* </pre></blockquote>
*
* @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:
* <blockquote><pre>
* Foo(String str) {* this.str = GriffonNameUtils.requireNonBlank(str, "str must not be null")
* }* </pre></blockquote>
*
* @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);
}
}

View File

@@ -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;
}

Some files were not shown because too many files have changed in this diff Show More