From 0daccf26b2504149a53c4240c782425c8fabd757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Str=C3=A4hle?= Date: Fri, 3 May 2024 17:27:05 +0200 Subject: [PATCH] feat(crd-generator): Add CRD-Generator CLI --- crd-generator/cli/README.md | 98 ++++++ crd-generator/cli/pom.xml | 132 +++++++ .../crd/generator/cli/CRDGeneratorCLI.java | 327 ++++++++++++++++++ ...CRDGeneratorExecutionExceptionHandler.java | 67 ++++ .../generator/cli/CRDGeneratorExitCode.java | 31 ++ .../cli/KubernetesClientVersionProvider.java | 26 ++ .../generator/cli/LoggingConfiguration.java | 78 +++++ .../crd/generator/cli/SourceParameter.java | 49 +++ .../cli/SourceParameterTypeConverter.java | 56 +++ .../generator/cli/CRDGeneratorCLITest.java | 158 +++++++++ .../cli/LoggingConfigurationTest.java | 59 ++++ .../cli/SourceArgumentConverterTest.java | 76 ++++ .../generator/cli/examples/basic/Basic.java | 27 ++ .../cli/examples/basic/BasicSpec.java | 63 ++++ .../cli/examples/basic/BasicStatus.java | 28 ++ crd-generator/pom.xml | 1 + java-generator/cli/pom.xml | 2 - pom.xml | 17 + uberjar/pom.xml | 1 - 19 files changed, 1293 insertions(+), 3 deletions(-) create mode 100644 crd-generator/cli/README.md create mode 100644 crd-generator/cli/pom.xml create mode 100644 crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorCLI.java create mode 100644 crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExecutionExceptionHandler.java create mode 100644 crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExitCode.java create mode 100644 crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/KubernetesClientVersionProvider.java create mode 100644 crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/LoggingConfiguration.java create mode 100644 crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameter.java create mode 100644 crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameterTypeConverter.java create mode 100644 crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/CRDGeneratorCLITest.java create mode 100644 crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/LoggingConfigurationTest.java create mode 100644 crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/SourceArgumentConverterTest.java create mode 100644 crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/Basic.java create mode 100644 crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicSpec.java create mode 100644 crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicStatus.java diff --git a/crd-generator/cli/README.md b/crd-generator/cli/README.md new file mode 100644 index 00000000000..5a02ce6c15f --- /dev/null +++ b/crd-generator/cli/README.md @@ -0,0 +1,98 @@ +# CRD-Generator CLI + +Generate Custom Resource Definitions (CRD) for Kubernetes from Java classes. + +## Install + +The CRD-Generator CLI is available for download on Sonatype at the link: + +``` +https://oss.sonatype.org/content/repositories/releases/io/fabric8/crd-generator-cli//crd-generator-cli-.sh +``` + +Download the latest version with the following commands: + +```bash +export VERSION=$(wget -q -O - https://github.com/fabric8io/kubernetes-client/releases/latest --header "Accept: application/json" | jq -r '.tag_name' | cut -c 2-) +wget -O crd-gen https://oss.sonatype.org/content/repositories/releases/io/fabric8/crd-generator-cli/$VERSION/crd-generator-cli-$VERSION.sh +chmod a+x crd-gen +./crd-gen --version +``` + +Alternatively, if you already have [jbang](https://www.jbang.dev/) installed, you can run the CLI by using the following command: + +```bash +jbang io.fabric8:crd-generator-cli: +``` + +## Usage + +``` +crd-gen [-hVv] [--force-index] [--force-scan] [--implicit-preserve-unknown-fields] [--no-parallel] + [-o=] [-cp=]... [--exclude-package=]... + [--include-package=]... ... + +Description: + +Fabric8 CRD-Generator +Generate Custom Resource Definitions (CRD) for Kubernetes from Java classes. + +Parameters: + ... A directory or JAR file to scan for Custom Resource classes, or a full qualified Custom Resource + class name. + +Options: + -o, --output-dir= + The output directory where the CRDs are emitted. + Default: . + -cp, --classpath= + Additional classpath element, e.g. a dependency packaged as JAR file or a directory of class + files. + --force-index Create Jandex index even if the directory or JAR file contains an existing index. + --force-scan Scan directories and JAR files even if Custom Resource classes are given. + --no-parallel Disable parallel generation of CRDs. + --implicit-preserve-unknown-fields + `x-kubernetes-preserve-unknown-fields: true` will be added on objects which contain an any-setter + or any-getter. + --include-package= + Filter Custom Resource classes after scanning by package inclusions. + --exclude-package= + Filter Custom Resource classes after scanning by package exclusions. + -v Verbose mode. Helpful for troubleshooting. + Multiple -v options increase the verbosity. + -h, --help Show this help message and exit. + -V, --version Print version information and exit. + +Exit Codes: + 0 Successful execution + 1 Unexpected error + 2 Invalid input + 70 Custom Resource class loading failed + 80 No Custom Resource classes retained after filtering +``` + +### Examples + +**Generate CRDs for Custom Resource classes in a directory:** + +```bash +crd-gen target/classes/ +``` + +**Generate CRDs for Custom Resource classes in a JAR file:** + +```bash +crd-gen my-jar-with-custom-resources.jar +``` + +**Generate CRD by using a single class only:** + +```bash +crd-gen -cp target/classes/ com.example.MyCustomResource +``` + +**Generate CRD(s) by using multiple classes:** + +```bash +crd-gen -cp target/classes/ com.example.v1.MyCustomResource com.example.v2.MyCustomResource +``` diff --git a/crd-generator/cli/pom.xml b/crd-generator/cli/pom.xml new file mode 100644 index 00000000000..6f6cfa57c44 --- /dev/null +++ b/crd-generator/cli/pom.xml @@ -0,0 +1,132 @@ + + + + + crd-generator-parent + io.fabric8 + 7.0-SNAPSHOT + + 4.0.0 + + crd-generator-cli + Fabric8 :: CRD generator :: CLI + + + + io.fabric8 + crd-generator-collector + + + + info.picocli + picocli + + + + ch.qos.logback + logback-classic + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + info.picocli + picocli-codegen + ${picocli.version} + + + + -Aproject=${project.groupId}/${project.artifactId} + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + + + + io.fabric8.crd.generator.cli.CRDGeneratorCLI + + + false + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + org.skife.maven + really-executable-jar-maven-plugin + + -Xmx1G + crd-gen + true + + + + + package + + really-executable-jar + + + + + + + diff --git a/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorCLI.java b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorCLI.java new file mode 100644 index 00000000000..ddb14149b91 --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorCLI.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import io.fabric8.crd.generator.collector.CustomResourceCollector; +import io.fabric8.crdv2.generator.CRDGenerationInfo; +import io.fabric8.crdv2.generator.CRDGenerator; +import io.fabric8.kubernetes.api.model.HasMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * CRD-Generator Command Line Interface. + */ +// spotless:off +@CommandLine.Command( + name = "crd-gen", + description = "@|bold Fabric8 CRD-Generator|@%n" + + "Generate Custom Resource Definitions (CRD) for Kubernetes from Java classes.", + exitCodeList = { + " 0:Successful execution", + " 1:Unexpected error", + " 2:Invalid input", + "70:Custom Resource class loading failed", + "80:No Custom Resource classes retained after filtering" + }, + helpCommand = true, + mixinStandardHelpOptions = true, + usageHelpAutoWidth = true, + sortOptions = false, + versionProvider = KubernetesClientVersionProvider.class, + synopsisHeading = "%nUsage:%n%n", + descriptionHeading = "%nDescription:%n%n", + parameterListHeading = "%nParameters:%n", + optionListHeading = "%nOptions:%n", + exitCodeListHeading = "%nExit Codes:%n", + footerHeading = "%nExamples:%n", + footer = " Generate CRDs for Custom Resource classes in a directory:%n" + + " @|faint ${COMMAND-NAME} target/classes/|@%n" + + " Generate CRDs for Custom Resource classes in a JAR file:%n" + + " @|faint ${COMMAND-NAME} my-jar-with-custom-resources.jar|@%n" + + " Generate CRD by using a single class only:%n" + + " @|faint ${COMMAND-NAME} -cp target/classes/ com.example.MyCustomResource|@" +) +// spotless:on +public class CRDGeneratorCLI implements Runnable { + + private static final Logger log = LoggerFactory.getLogger(CRDGeneratorCLI.class); + + private static final CRDGenerationInfo EMPTY_INFO = new CRDGenerationInfo(); + + private CRDGenerationInfo crdGenerationInfo = EMPTY_INFO; + + private final Set customResourceClassNames = new HashSet<>(); + private final Set filesToScan = new HashSet<>(); + + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + + // spotless:off + @CommandLine.Option( + names = {"-o", "--output-dir"}, + description = "The output directory where the CRDs are emitted.", + showDefaultValue = CommandLine.Help.Visibility.ALWAYS + ) + // spotless:on + File outputDirectory = new File("."); + + // spotless:off + @CommandLine.Option( + names = {"-cp", "--classpath"}, + paramLabel = "", + description = "Additional classpath element, e.g. a dependency packaged as JAR file or a directory of class files." + ) + // spotless:on + List classpathElements = new ArrayList<>(); + + // spotless:off + @CommandLine.Option( + names = {"--force-index"}, + description = "Create Jandex index even if the directory or JAR file contains an existing index.", + defaultValue = "false" + ) + // spotless:on + Boolean forceIndex; + + // spotless:off + @CommandLine.Option( + names = {"--force-scan"}, + description = "Scan directories and JAR files even if Custom Resource classes are given.", + defaultValue = "false" + ) + // spotless:on + Boolean forceScan; + + // spotless:off + @CommandLine.Option( + names = {"--no-parallel"}, + description = "Disable parallel generation of CRDs.", + defaultValue = "false" + ) + // spotless:on + Boolean parallelDisabled; + + // spotless:off + @CommandLine.Option( + names = {"--implicit-preserve-unknown-fields"}, + description = "`x-kubernetes-preserve-unknown-fields: true` will be added on objects which contain an any-setter or any-getter.", + defaultValue = "false" + ) + // spotless:on + Boolean implicitPreserveUnknownFields; + + // spotless:off + @CommandLine.Option( + names = {"--include-package"}, + paramLabel = "", + description = "Filter Custom Resource classes after scanning by package inclusions." + ) + // spotless:on + List includedPackages = new LinkedList<>(); + + // spotless:off + @CommandLine.Option( + names = {"--exclude-package"}, + paramLabel = "", + description = "Filter Custom Resource classes after scanning by package exclusions." + ) + // spotless:on + List excludedPackages = new LinkedList<>(); + + // spotless:off + @CommandLine.Option( + names = {"-v"}, + description = "Verbose mode. Helpful for troubleshooting.\nMultiple -v options increase the verbosity." + ) + // spotless:on + List verbose = new LinkedList<>(); + + // spotless:off + @CommandLine.Parameters( + paramLabel = "", + arity = "1..*", + converter = SourceParameterTypeConverter.class, + description = "A directory or JAR file to scan for Custom Resource classes, or a full qualified Custom Resource class name." + ) + // spotless:on + void setParameters(List parameters) { + setCustomResourceClassNames(parameters); + setFilesToScan(parameters); + } + + @Override + public void run() { + LoggingConfiguration.configureLogger(verbose); + List allClasspathElements = getClasspathElements(); + + log.trace("Custom Resource Class Names: {}", customResourceClassNames); + log.trace("Files to scan: {}", filesToScan); + log.trace("Classpath: {}", allClasspathElements); + + CustomResourceCollector customResourceCollector = new CustomResourceCollector() + .withClasspathElements(allClasspathElements) + .withFilesToScan(filesToScan) + .withForceIndex(forceIndex) + .withForceScan(forceScan) + .withCustomResourceClasses(customResourceClassNames) + .withIncludePackages(includedPackages) + .withExcludePackages(excludedPackages); + + List> customResourceClasses = customResourceCollector.findCustomResourceClasses(); + + if (customResourceClasses.isEmpty()) { + throw new CustomResourceClassNotFoundException(); + } + + log.debug("Generating CRDs for {} Custom Resource classes", customResourceClasses.size()); + + File sanitizedOutputDirectory; + try { + sanitizedOutputDirectory = outputDirectory.getCanonicalFile(); + } catch (IOException e) { + throw new RuntimeException("Could not get canonical file for " + outputDirectory, e); + } + + try { + Files.createDirectories(sanitizedOutputDirectory.toPath()); + } catch (IOException e) { + throw new RuntimeException( + "Could not create output directory at " + sanitizedOutputDirectory, e); + } + + CRDGenerator crdGenerator = new CRDGenerator() + .customResourceClasses(customResourceClasses) + .withParallelGenerationEnabled(!parallelDisabled) + .withImplicitPreserveUnknownFields(implicitPreserveUnknownFields) + .inOutputDir(sanitizedOutputDirectory); + + crdGenerationInfo = crdGenerator.detailedGenerate(); + crdGenerationInfo.getCRDDetailsPerNameAndVersion().forEach((crdName, versionToInfo) -> { + getOut().printf("Generated CRD %s:%n", crdName); + versionToInfo.forEach( + (version, info) -> getOut().printf(" %s -> %s%n", version, info.getFilePath())); + }); + } + + CRDGenerationInfo getCrdGenerationInfo() { + return crdGenerationInfo; + } + + String getDiagText() { + StringBuilder sb = new StringBuilder(); + sb.append("\n"); + + if (!customResourceClassNames.isEmpty()) { + sb.append("Custom Resource class names:\n"); + customResourceClassNames.forEach(fqcn -> sb.append(" ").append(fqcn).append("\n")); + } + if (filesToScan.isEmpty()) { + sb.append("Scan Paths: []\n"); + } else { + sb.append("Scan Paths:\n"); + filesToScan.forEach(f -> sb.append(" ").append(f.getPath()).append("\n")); + } + + List classpathElements = getClasspathElements(); + if (classpathElements.isEmpty()) { + sb.append("Classpath: []\n"); + } else { + sb.append("\nClasspath:\n"); + classpathElements.forEach(cpe -> sb.append(" ").append(cpe).append("\n")); + } + sb.append("\n"); + return sb.toString(); + } + + private void setCustomResourceClassNames(List source) { + source.stream() + .filter(s -> s instanceof SourceParameter.CustomResourceClass) + .map(SourceParameter.CustomResourceClass.class::cast) + .map(SourceParameter.CustomResourceClass::getCustomResourceClass) + .forEach(customResourceClassNames::add); + } + + private void setFilesToScan(List source) { + source.stream() + .filter(s -> s instanceof SourceParameter.FileToScan) + .map(SourceParameter.FileToScan.class::cast) + .map(SourceParameter.FileToScan::getFileToScan) + .forEach(filesToScan::add); + } + + private List getClasspathElements() { + List allClasspathElements = new LinkedList<>(classpathElements); + // Add files to classpath elements to improve UX of the CLI: + // A scan target must be always in the classpath. + filesToScan.stream() + .map(File::getPath) + .forEach(allClasspathElements::add); + + return allClasspathElements; + } + + private PrintWriter getOut() { + return spec.commandLine().getOut(); + } + + public static void main(String[] args) { + System.exit(exec(args)); + } + + /** + * Entry point for the CLI, intended to be used if embedded in other applications. In comparison + * to {@link #main(String[])}, System.exit() won't be called. + * + * @param args arguments + * @return the exit code + */ + public static int exec(String[] args) { + return createCommandLine() + .execute(args); + } + + static CommandLine createCommandLine() { + return createCommandLine(new CRDGeneratorCLI()); + } + + static CommandLine createCommandLine(CRDGeneratorCLI crdGeneratorCLI) { + return new CommandLine(crdGeneratorCLI) + .setExecutionExceptionHandler(new CRDGeneratorExecutionExceptionHandler(crdGeneratorCLI)); + } + + /** + * Exception to indicate that no custom resource classes + * have been retained after scanning and filtering. + */ + static class CustomResourceClassNotFoundException extends RuntimeException { + CustomResourceClassNotFoundException() { + super("No Custom Resource class retained after filtering"); + } + } + +} diff --git a/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExecutionExceptionHandler.java b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExecutionExceptionHandler.java new file mode 100644 index 00000000000..4ad22fb53b1 --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExecutionExceptionHandler.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import io.fabric8.crd.generator.collector.CustomResourceClassLoaderException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine; + +class CRDGeneratorExecutionExceptionHandler implements CommandLine.IExecutionExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(CRDGeneratorExecutionExceptionHandler.class); + + private final CRDGeneratorCLI crdGeneratorCLI; + + CRDGeneratorExecutionExceptionHandler(CRDGeneratorCLI crdGeneratorCLI) { + this.crdGeneratorCLI = crdGeneratorCLI; + } + + @Override + public int handleExecutionException( + Exception ex, + CommandLine commandLine, + CommandLine.ParseResult fullParseResult) { + + commandLine.getErr().println(ex.getMessage()); + + if (ex instanceof CustomResourceClassLoaderException) { + commandLine.getErr().println(); + commandLine.getErr().println("The classloader could not load the Custom Resource class.\n" + + "Check the list of classpath elements and add further JAR archives " + + "or directories containing required classes " + + "e.g. with `-cp my-dep.jar` or `-cp target/classes/`."); + commandLine.getErr().print(crdGeneratorCLI.getDiagText()); + return CRDGeneratorExitCode.CR_CLASS_LOADING; + } + + if (ex instanceof CRDGeneratorCLI.CustomResourceClassNotFoundException) { + commandLine.getErr().println(); + commandLine.getErr().println("Check JAR files and directories considered to be scanned " + + "as well as your filters. At least one Custom Resource class " + + "must be retained after filtering."); + commandLine.getErr().print(crdGeneratorCLI.getDiagText()); + return CRDGeneratorExitCode.NO_CR_CLASSES_RETAINED; + } + + if (log.isDebugEnabled()) { + commandLine.getErr().println(crdGeneratorCLI.getDiagText()); + } + + log.trace(ex.getMessage(), ex); + return CRDGeneratorExitCode.SOFTWARE; + } +} diff --git a/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExitCode.java b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExitCode.java new file mode 100644 index 00000000000..4560a89f81f --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorExitCode.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import picocli.CommandLine; + +class CRDGeneratorExitCode { + + static final int OK = CommandLine.ExitCode.OK; + static final int SOFTWARE = CommandLine.ExitCode.SOFTWARE; + static final int USAGE = CommandLine.ExitCode.USAGE; + static final int CR_CLASS_LOADING = 70; + static final int NO_CR_CLASSES_RETAINED = 80; + + private CRDGeneratorExitCode() { + } + +} diff --git a/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/KubernetesClientVersionProvider.java b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/KubernetesClientVersionProvider.java new file mode 100644 index 00000000000..4200f750441 --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/KubernetesClientVersionProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import io.fabric8.kubernetes.client.Version; +import picocli.CommandLine; + +class KubernetesClientVersionProvider implements CommandLine.IVersionProvider { + @Override + public String[] getVersion() { + return new String[] { Version.clientVersion() }; + } +} diff --git a/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/LoggingConfiguration.java b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/LoggingConfiguration.java new file mode 100644 index 00000000000..b0d55ccd9a1 --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/LoggingConfiguration.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * Utility class to configure log levels of underlying components. + */ +class LoggingConfiguration { + + private LoggingConfiguration() { + } + + static void configureLogger(List verbose) { + configureLogger(getBaseLogLevel(verbose)); + } + + private static void configureLogger(LogLevel baseLogLevel) { + setLogLevel("io.fabric8.crd.generator.cli", baseLogLevel.toLogbackLevel()); + setLogLevel("io.fabric8.crd.generator.collector", baseLogLevel.toLogbackLevel()); + setLogLevel("io.fabric8.crdv2.generator", baseLogLevel.toLogbackLevel()); + } + + private static void setLogLevel(String packageName, Level level) { + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + ch.qos.logback.classic.Logger logger = loggerContext.getLogger(packageName); + logger.setLevel(level); + } + + /** + * Derive the base log level from a list of verbose options. + * + * @return the base log level. + */ + static LogLevel getBaseLogLevel(List verbose) { + switch (verbose.size()) { + case 1: + return LogLevel.INFO; + case 2: + return LogLevel.DEBUG; + default: + if (verbose.size() >= 3) { + return LogLevel.TRACE; + } else { + return LogLevel.WARN; + } + } + } + + enum LogLevel { + WARN, + INFO, + DEBUG, + TRACE; + + Level toLogbackLevel() { + return Level.toLevel(name()); + } + } +} diff --git a/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameter.java b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameter.java new file mode 100644 index 00000000000..ba4fb6905e0 --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameter.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import java.io.File; + +/** + * A positional parameter. + */ +interface SourceParameter { + + class FileToScan implements SourceParameter { + + private final File fileToScan; + + FileToScan(File fileToScan) { + this.fileToScan = fileToScan; + } + + public File getFileToScan() { + return fileToScan; + } + } + + class CustomResourceClass implements SourceParameter { + private final String customResourceClass; + + CustomResourceClass(String customResourceClass) { + this.customResourceClass = customResourceClass; + } + + public String getCustomResourceClass() { + return customResourceClass; + } + } +} diff --git a/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameterTypeConverter.java b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameterTypeConverter.java new file mode 100644 index 00000000000..ff12a631f6e --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/SourceParameterTypeConverter.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import picocli.CommandLine; + +import java.io.File; +import java.io.IOException; +import java.util.regex.Pattern; + +class SourceParameterTypeConverter + implements CommandLine.ITypeConverter { + + private static final Pattern VALID_JAVA_IDENTIFIER = Pattern.compile( + "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"); + + private static final Pattern FQCN_PATTERN = Pattern.compile( + "(" + VALID_JAVA_IDENTIFIER + "\\.)*" + VALID_JAVA_IDENTIFIER); + + static boolean isFQCN(String value) { + return FQCN_PATTERN.matcher(value).matches(); + } + + @Override + public SourceParameter convert(String value) { + File f = new File(value); + if (f.exists()) { + try { + return new SourceParameter.FileToScan(f.getCanonicalFile()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + if (isFQCN(value)) { + return new SourceParameter.CustomResourceClass(value); + } + + // fail fast if invalid input can be already detected here + throw new IllegalArgumentException( + "Not an existing file or a full qualified class name."); + } +} diff --git a/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/CRDGeneratorCLITest.java b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/CRDGeneratorCLITest.java new file mode 100644 index 00000000000..4ff35a57f54 --- /dev/null +++ b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/CRDGeneratorCLITest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import picocli.CommandLine; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CRDGeneratorCLITest { + + @Test + void givenVersion_thenOutputVersionAndGenerateNoCRDs() { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = new CommandLine(cliApp); + String[] args = new String[] { + "--version" + }; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.OK, exitCode); + assertEquals(0, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + } + + @Test + void givenSingleCRClassNameFromSameClasspath_thenGenerate(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = CRDGeneratorCLI.createCommandLine(cliApp); + String[] args = new String[] { + "-o", tempDir.toString(), + "io.fabric8.crd.generator.cli.examples.basic.Basic" + }; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.OK, exitCode); + assertEquals(1, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + assertTrue(Paths.get(tempDir.toString(), "basics.sample.fabric8.io-v1.yml").toFile().exists()); + } + + @Test + void givenSingleCRClassNameFromExternalClasspath_thenGenerate(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = CRDGeneratorCLI.createCommandLine(cliApp); + String[] args = new String[] { + "--classpath", "../api-v2/target/test-classes/", + "-o", tempDir.toString(), + "io.fabric8.crdv2.example.basic.Basic" + }; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.OK, exitCode); + assertEquals(1, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + assertTrue(Paths.get(tempDir.toString(), "basics.sample.fabric8.io-v1.yml").toFile().exists()); + } + + @Test + void givenClassesDirectory_thenScanAndGenerate(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = CRDGeneratorCLI.createCommandLine(cliApp); + String[] args = new String[] { + "-o", tempDir.toString(), + "target/test-classes/" + }; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.OK, exitCode); + assertEquals(1, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + assertTrue(Paths.get(tempDir.toString(), "basics.sample.fabric8.io-v1.yml").toFile().exists()); + } + + @Test + void givenNoInput_thenFailAndGenerateNoCRDs() { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = CRDGeneratorCLI.createCommandLine(cliApp); + String[] args = new String[] {}; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.USAGE, exitCode); + assertEquals(0, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + } + + @Test + void givenNotExistingCRClassName_thenFailAndGenerateNoCRDs() { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = CRDGeneratorCLI.createCommandLine(cliApp); + String[] args = new String[] { + // There is also no file named like that! + "com.example.NotExisting" + }; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.CR_CLASS_LOADING, exitCode); + assertEquals(0, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + } + + @Test + void givenClassesDirectoryButFilterByPackageInclusion_thenScanAndFail(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = CRDGeneratorCLI.createCommandLine(cliApp); + String[] args = new String[] { + "-o", tempDir.toString(), + "--include-package", "not.existingpackage", + "target/test-classes/" + }; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.NO_CR_CLASSES_RETAINED, exitCode); + assertEquals(0, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + } + + @Test + void givenClassesDirectoryButFilterByPackageExclusion_thenScanAndFail(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = CRDGeneratorCLI.createCommandLine(cliApp); + String[] args = new String[] { + "-o", tempDir.toString(), + // package contains a Custom Resource class + "--exclude-package", "io.fabric8.crd.generator.cli.examples", + "target/test-classes/" + }; + + int exitCode = cmd.execute(args); + + assertEquals(CRDGeneratorExitCode.NO_CR_CLASSES_RETAINED, exitCode); + assertEquals(0, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + } + + @Test + void givenHelp_whenExec_thenHelp() { + int exitCode = CRDGeneratorCLI.exec(new String[] { "--help" }); + assertEquals(CRDGeneratorExitCode.OK, exitCode); + } +} diff --git a/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/LoggingConfigurationTest.java b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/LoggingConfigurationTest.java new file mode 100644 index 00000000000..8709ccd40a7 --- /dev/null +++ b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/LoggingConfigurationTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class LoggingConfigurationTest { + + @Test + void givenNoVerbosity_thenLevelWarn() { + LoggingConfiguration.LogLevel level = LoggingConfiguration.getBaseLogLevel(Collections.emptyList()); + assertEquals(LoggingConfiguration.LogLevel.WARN, level); + } + + @Test + void given1Verbosity_thenLevelInfo() { + LoggingConfiguration.LogLevel level = LoggingConfiguration.getBaseLogLevel(Collections.singletonList(true)); + + assertEquals(LoggingConfiguration.LogLevel.INFO, level); + } + + @Test + void given2Verbosity_thenLevelDebug() { + LoggingConfiguration.LogLevel level = LoggingConfiguration.getBaseLogLevel(Arrays.asList(true, true)); + + assertEquals(LoggingConfiguration.LogLevel.DEBUG, level); + } + + @Test + void given3orMoreVerbosity_thenLevelTrace() { + LoggingConfiguration.LogLevel level = LoggingConfiguration.getBaseLogLevel(Arrays.asList(true, true, true)); + assertEquals(LoggingConfiguration.LogLevel.TRACE, level); + + level = LoggingConfiguration.getBaseLogLevel(Arrays.asList(true, true, true, true)); + assertEquals(LoggingConfiguration.LogLevel.TRACE, level); + + level = LoggingConfiguration.getBaseLogLevel(Arrays.asList(true, true, true, true, true)); + assertEquals(LoggingConfiguration.LogLevel.TRACE, level); + } + +} diff --git a/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/SourceArgumentConverterTest.java b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/SourceArgumentConverterTest.java new file mode 100644 index 00000000000..ee95e94aadb --- /dev/null +++ b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/SourceArgumentConverterTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class SourceArgumentConverterTest { + + @Test + void givenValidCustomResourceClassArgument_thenConvertToCustomResourceClassArgument() { + SourceParameterTypeConverter converter = new SourceParameterTypeConverter(); + SourceParameter sourceParameter = converter.convert("com.example.MyValidClassName"); + assertInstanceOf(SourceParameter.CustomResourceClass.class, sourceParameter); + SourceParameter.CustomResourceClass customResourceClassArg = (SourceParameter.CustomResourceClass) sourceParameter; + assertEquals("com.example.MyValidClassName", customResourceClassArg.getCustomResourceClass()); + } + + @Test + void givenExistingFile_thenConvertToFileToScanArgument(@TempDir File tempDir) throws IOException { + File exampleFile = new File(tempDir, "example-file.txt"); + Files.write(exampleFile.toPath(), Collections.singletonList("some-content")); + + SourceParameterTypeConverter converter = new SourceParameterTypeConverter(); + SourceParameter sourceParameter = converter.convert(exampleFile.getAbsolutePath()); + assertInstanceOf(SourceParameter.FileToScan.class, sourceParameter); + SourceParameter.FileToScan fileToScanArg = (SourceParameter.FileToScan) sourceParameter; + assertEquals(exampleFile, fileToScanArg.getFileToScan()); + } + + @Test + void givenNotExistingFileAndInvalidCustomResourceClass_thenFail() { + SourceParameterTypeConverter converter = new SourceParameterTypeConverter(); + + assertThrows(IllegalArgumentException.class, () -> { + converter.convert("Not-Existing.txt"); + }); + } + + @Test + void givenValidClassName_whenCheckFQCN_thenTrue() { + assertTrue(SourceParameterTypeConverter.isFQCN("MyClass")); + assertTrue(SourceParameterTypeConverter.isFQCN("com.MyClass")); + assertTrue(SourceParameterTypeConverter.isFQCN("com.example.MyClass")); + } + + @Test + void givenInvalidClassName_whenCheckFQCN_thenFalse() { + assertFalse(SourceParameterTypeConverter.isFQCN("com.my-example.MyClass")); + assertFalse(SourceParameterTypeConverter.isFQCN("com.example.My-Class")); + } +} diff --git a/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/Basic.java b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/Basic.java new file mode 100644 index 00000000000..afe48f34b79 --- /dev/null +++ b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/Basic.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli.examples.basic; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.fabric8.io") +@Version("v1alpha1") +public class Basic extends CustomResource implements Namespaced { + +} diff --git a/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicSpec.java b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicSpec.java new file mode 100644 index 00000000000..e39d64987a0 --- /dev/null +++ b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicSpec.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli.examples.basic; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class BasicSpec { + private int myInt; + + public int getMyInt() { + return myInt; + } + + public void setMyInt(int myInt) { + this.myInt = myInt; + } + + private long myLong; + + public long getMyLong() { + return myLong; + } + + public void setMyLong(long myLong) { + this.myLong = myLong; + } + + private double myDouble; + + public double getMyDouble() { + return myDouble; + } + + public void setMyDouble(long myDouble) { + this.myDouble = myDouble; + } + + private float myFloat; + + public float getMyFloat() { + return myFloat; + } + + public void setMyFloat(long myFloat) { + this.myFloat = myFloat; + } + + @JsonIgnore + public Class clazz; +} diff --git a/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicStatus.java b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicStatus.java new file mode 100644 index 00000000000..daebe4361fa --- /dev/null +++ b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/examples/basic/BasicStatus.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 io.fabric8.crd.generator.cli.examples.basic; + +public class BasicStatus { + private String message; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/crd-generator/pom.xml b/crd-generator/pom.xml index b67385ca6ea..04953b180c0 100644 --- a/crd-generator/pom.xml +++ b/crd-generator/pom.xml @@ -36,6 +36,7 @@ apt collector maven-plugin + cli test test-apt diff --git a/java-generator/cli/pom.xml b/java-generator/cli/pom.xml index 4e84580e994..3e87271dc11 100644 --- a/java-generator/cli/pom.xml +++ b/java-generator/cli/pom.xml @@ -80,7 +80,6 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 package @@ -114,7 +113,6 @@ org.skife.maven really-executable-jar-maven-plugin - 2.1.1 -Xmx1G java-gen diff --git a/pom.xml b/pom.xml index f027bde9a92..1ccbec7120f 100644 --- a/pom.xml +++ b/pom.xml @@ -124,6 +124,7 @@ ${jackson.version} 2.0.16 2.23.1 + 1.5.6 1.18.34 2.7 2.2 @@ -167,6 +168,7 @@ 4.0.0.4121 1.7.0 2.43.0 + 2.1.1 1.8 @@ -860,6 +862,11 @@ ${log4j.version} test + + ch.qos.logback + logback-classic + ${logback.version} + io.vertx vertx-core @@ -1065,6 +1072,10 @@ maven-resources-plugin ${maven.resources.plugin.version} + + maven-shade-plugin + ${maven.shade.plugin.version} + maven-install-plugin ${maven.install.plugin.version} @@ -1161,6 +1172,11 @@ ${gradle-api-maven-plugin.version} true + + org.skife.maven + really-executable-jar-maven-plugin + ${really-executable-jar-maven-plugin.version} + @@ -1222,6 +1238,7 @@ ide-config/eclipse.importorder + diff --git a/uberjar/pom.xml b/uberjar/pom.xml index 4755c3806f1..dd2176c8eec 100644 --- a/uberjar/pom.xml +++ b/uberjar/pom.xml @@ -250,7 +250,6 @@ org.apache.maven.plugins maven-shade-plugin - ${maven.shade.plugin.version} uberjar