From 8687b4b166256fb2fca16dc5e791c9faa60c0b6b 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/pom.xml | 135 ++++++++++++++++++ .../crd/generator/cli/CRDGeneratorCLI.java | 118 +++++++++++++++ .../cli/KubernetesClientVersionProvider.java | 26 ++++ .../generator/cli/CRDGeneratorCLITest.java | 84 +++++++++++ .../generator/cli/examples/basic/Basic.java | 27 ++++ .../cli/examples/basic/BasicSpec.java | 63 ++++++++ .../cli/examples/basic/BasicStatus.java | 28 ++++ crd-generator/pom.xml | 1 + 8 files changed, 482 insertions(+) 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/KubernetesClientVersionProvider.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/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/pom.xml b/crd-generator/cli/pom.xml new file mode 100644 index 00000000000..0b86b0a1037 --- /dev/null +++ b/crd-generator/cli/pom.xml @@ -0,0 +1,135 @@ + + + + + crd-generator-parent + io.fabric8 + 6.13-SNAPSHOT + + 4.0.0 + + crd-generator-cli + Fabric8 :: CRD generator :: CLI + + + + io.fabric8 + crd-generator-collector + ${project.version} + + + + info.picocli + picocli + + + + org.slf4j + slf4j-simple + + + + 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 + 3.5.2 + + + 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 + 2.1.1 + + -Xmx1G + java-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..034b4ee99d4 --- /dev/null +++ b/crd-generator/cli/src/main/java/io/fabric8/crd/generator/cli/CRDGeneratorCLI.java @@ -0,0 +1,118 @@ +/* + * 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.crdv2.generator.CustomResourceInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +@CommandLine.Command(name = "crd-gen", mixinStandardHelpOptions = true, helpCommand = true, versionProvider = KubernetesClientVersionProvider.class) +public class CRDGeneratorCLI implements Runnable { + + private static final Logger log = LoggerFactory.getLogger(CustomResourceCollector.class); + private static final CRDGenerationInfo EMPTY_INFO = new CRDGenerationInfo(); + + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + + @CommandLine.Option(names = { "-c", + "--classes" }, description = "Directories or JAR files to be used to scan for Custom Resource classes") + List classesToIndex; + + @CommandLine.Option(names = { "-cr", + "--custom-resource" }, description = "Custom Resource classes, which should be considered to generate the CRDs. If set, scanning is disabled.") + List customResourceClasses; + + @CommandLine.Option(names = { "-cp", "--classpath" }, description = "The classpath which be used during the CRD generation") + List classpaths = new ArrayList<>(); + + @CommandLine.Option(names = { "-o", "--output-dir" }, description = "The output directory for the generated CRDs") + File outputDirectory = new File("."); + + @CommandLine.Option(names = { "-f", + "--force-index" }, description = "If true, a Jandex index will be created even if the directory or JAR file contains an existing index.", defaultValue = "false") + Boolean forceIndex; + + @CommandLine.Option(names = { "-p", "--parallel" }, description = "Enable parallel generation", defaultValue = "true") + Boolean parallel; + + @CommandLine.Option(names = { + "--implicit-preserve-unknown-fields" }, description = "If enabled, all objects are implicitly marked with x-kubernetes-preserve-unknown-fields: true.", defaultValue = "false") + Boolean implicitPreserveUnknownFields; + + private CRDGenerationInfo crdGenerationInfo = EMPTY_INFO; + + @Override + public void run() { + CustomResourceCollector customResourceCollector = new CustomResourceCollector() + .withParentClassLoader(Thread.currentThread().getContextClassLoader()) + .withClasspaths(classpaths) + .withFilesToIndex(classesToIndex) + .withForceIndex(forceIndex) + // TODO: allow to exclude / include + /* + * .withIncludePackages(inclusions.getPackages()) + * .withIncludeGroups(inclusions.getGroups()) + * .withIncludeVersions(inclusions.getVersions()) + * .withExcludePackages(exclusions.getPackages()) + * .withExcludeGroups(exclusions.getGroups()) + * .withExcludeVersions(exclusions.getVersions()) + */ + .withCustomResourceClasses(customResourceClasses); + + CustomResourceInfo[] customResourceInfos = customResourceCollector.findCustomResources(); + + log.info("Found {} CustomResources", customResourceInfos.length); + + try { + Files.createDirectories(outputDirectory.toPath()); + } catch (IOException e) { + throw new RuntimeException("Could not create output directory: " + e.getMessage()); + } + + CRDGenerator crdGenerator = new CRDGenerator() + .customResources(customResourceInfos) + .withParallelGenerationEnabled(parallel) + .withImplicitPreserveUnknownFields(implicitPreserveUnknownFields) + .inOutputDir(outputDirectory); + + crdGenerationInfo = crdGenerator.detailedGenerate(); + crdGenerationInfo.getCRDDetailsPerNameAndVersion().forEach((crdName, versionToInfo) -> { + log.info("Generated CRD {}:", crdName); + versionToInfo.forEach( + (version, info) -> log.info(" {} -> {}", version, info.getFilePath())); + }); + } + + public CRDGenerationInfo getCrdGenerationInfo() { + return crdGenerationInfo; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new CRDGeneratorCLI()).execute(args); + System.exit(exitCode); + } +} 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..d0cf7d09f11 --- /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; + +public class KubernetesClientVersionProvider implements CommandLine.IVersionProvider { + @Override + public String[] getVersion() throws Exception { + return new String[] { Version.clientVersion() }; + } +} 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..d5995f0c042 --- /dev/null +++ b/crd-generator/cli/src/test/java/io/fabric8/crd/generator/cli/CRDGeneratorCLITest.java @@ -0,0 +1,84 @@ +/* + * 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; + +public class CRDGeneratorCLITest { + + @Test + public void givenNoInput_thenGenerateNoCRDs() { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = new CommandLine(cliApp); + int exitCode = cmd.execute(); + assertEquals(0, exitCode); + assertEquals(0, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + } + + @Test + public void givenSingleCRClassNameFromSameClasspath_thenGenerate(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = new CommandLine(cliApp); + String[] args = new String[] { + "-cr", "io.fabric8.crd.generator.cli.examples.basic.Basic", + "-o", tempDir.toString() + }; + int exitCode = cmd.execute(args); + assertEquals(0, exitCode); + assertEquals(1, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + assertTrue(Paths.get(tempDir.toString(), "basics.sample.fabric8.io-v1.yml").toFile().exists()); + } + + @Test + public void givenSingleCRClassNameFromExternalClasspath_thenGenerate(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = new CommandLine(cliApp); + String[] args = new String[] { + "-cp", "../api-v2/target/test-classes/", + "-cr", "io.fabric8.crdv2.example.basic.Basic", + "-o", tempDir.toString() + }; + + int exitCode = cmd.execute(args); + assertEquals(0, exitCode); + assertEquals(1, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + assertTrue(Paths.get(tempDir.toString(), "basics.sample.fabric8.io-v1.yml").toFile().exists()); + } + + @Test + public void givenClassesDirectory_thenScanAndGenerate(@TempDir Path tempDir) { + CRDGeneratorCLI cliApp = new CRDGeneratorCLI(); + CommandLine cmd = new CommandLine(cliApp); + String[] args = new String[] { + "-c", "target/test-classes/", + //"-k", "basics.sample.fabric8.io", + "-o", tempDir.toString() + }; + + int exitCode = cmd.execute(args); + assertEquals(0, exitCode); + assertEquals(1, cliApp.getCrdGenerationInfo().numberOfGeneratedCRDs()); + assertTrue(Paths.get(tempDir.toString(), "basics.sample.fabric8.io-v1.yml").toFile().exists()); + } +} 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 61d7693c403..8f4ece860d4 100644 --- a/crd-generator/pom.xml +++ b/crd-generator/pom.xml @@ -35,6 +35,7 @@ api api-v2 collector + cli maven-plugin test