diff --git a/.gitignore b/.gitignore index 6cb25c0..53c216c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ # Ignore Gradle build output directory build -*.log \ No newline at end of file +*.log diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/app/build.gradle b/app/build.gradle index 856e289..05c8da4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,9 +41,13 @@ test { useJUnitPlatform() } +// read the version from the `VERSION` file +version = new File(rootDir,'VERSION').text.trim() +group = 'io.seqera' + application { // Define the main class for the application. - mainClass = 'io.seqera.wavelit.app.App' + mainClass = 'io.seqera.wavelit.App' // Run the Graalvm agent to resolve dynamic proxyes configuration applicationDefaultJvmArgs = ["-agentlib:native-image-agent=config-merge-dir=conf/"] } @@ -52,7 +56,7 @@ graalvmNative { binaries { main { imageName = 'wavelit' - mainClass = 'io.seqera.wavelit.app.App' + mainClass = 'io.seqera.wavelit.App' configurationFileDirectories.from(file('conf')) javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(19) @@ -62,3 +66,22 @@ graalvmNative { toolchainDetection = true testSupport = false } + +task buildInfo { + doLast { + def version = rootProject.file('VERSION').text.trim() + def commitId = System.env.getOrDefault("GITHUB_SHA", "unknown").substring(0,7) + def info = """\ + name=${rootProject.name} + version=${version} + commitId=${commitId} + """.stripIndent().toString() + def f = file("src/main/resources/META-INF/build-info.properties") + f.parentFile.mkdirs() + f.text = info + } +} + +compileJava { + dependsOn buildInfo +} diff --git a/app/conf/jni-config.json b/app/conf/jni-config.json index 2e367c6..8cef6d6 100644 --- a/app/conf/jni-config.json +++ b/app/conf/jni-config.json @@ -1,6 +1,6 @@ [ { - "name":"io.seqera.wavelit.app.App", + "name":"io.seqera.wavelit.App", "methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }] }, { diff --git a/app/conf/reflect-config.json b/app/conf/reflect-config.json index 0ed4967..be33bde 100644 --- a/app/conf/reflect-config.json +++ b/app/conf/reflect-config.json @@ -159,23 +159,29 @@ "methods":[{"name":"","parameterTypes":[] }] }, { - "name":"io.seqera.wavelit.app.App", + "name":"io.seqera.wavelit.App", "allDeclaredFields":true, "queryAllDeclaredMethods":true }, { - "name":"io.seqera.wavelit.app.json.ByteArrayAdapter", + "name":"io.seqera.wavelit.json.ByteArrayAdapter", "queryAllDeclaredMethods":true }, { - "name":"io.seqera.wavelit.app.json.DateTimeAdapter", + "name":"io.seqera.wavelit.json.DateTimeAdapter", "queryAllDeclaredMethods":true, "methods":[{"name":"deserializeInstant","parameterTypes":["java.lang.String"] }] }, { - "name":"io.seqera.wavelit.app.json.PathAdapter", + "name":"io.seqera.wavelit.json.PathAdapter", "queryAllDeclaredMethods":true }, +{ + "name":"io.seqera.wavelit.util.CliVersionProvider", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "methods":[{"name":"","parameterTypes":[] }] +}, { "name":"java.io.FilePermission" }, diff --git a/app/conf/resource-config.json b/app/conf/resource-config.json index ef6dcfb..e4a0028 100644 --- a/app/conf/resource-config.json +++ b/app/conf/resource-config.json @@ -1,6 +1,9 @@ { "resources":{ "includes":[ + { + "pattern":"\\QMETA-INF/build-info.properties\\E" + }, { "pattern":"\\QMETA-INF/services/ch.qos.logback.classic.spi.Configurator\\E" }, diff --git a/app/src/main/java/io/seqera/wavelit/app/App.java b/app/src/main/java/io/seqera/wavelit/App.java similarity index 80% rename from app/src/main/java/io/seqera/wavelit/app/App.java rename to app/src/main/java/io/seqera/wavelit/App.java index 94f7e82..2cc8257 100644 --- a/app/src/main/java/io/seqera/wavelit/app/App.java +++ b/app/src/main/java/io/seqera/wavelit/App.java @@ -12,7 +12,7 @@ /* * This Java source file was generated by the Gradle 'init' task. */ -package io.seqera.wavelit.app; +package io.seqera.wavelit; import java.io.IOException; import java.net.URI; @@ -24,37 +24,39 @@ import io.seqera.wave.api.SubmitContainerTokenRequest; import io.seqera.wave.api.SubmitContainerTokenResponse; -import io.seqera.wavelit.app.exception.IllegalCliArgumentException; +import io.seqera.wavelit.exception.IllegalCliArgumentException; +import io.seqera.wavelit.util.CliVersionProvider; import picocli.CommandLine; import static org.apache.commons.lang3.StringUtils.isEmpty; +import static picocli.CommandLine.Command; +import static picocli.CommandLine.Option; /** * Wavelit entrypoint class */ -@CommandLine.Command(name = "wavelit", description = "Wave command line tool", mixinStandardHelpOptions = true) +@Command(name = "wavelit", description = "Wave command line tool", mixinStandardHelpOptions = true, versionProvider = CliVersionProvider.class) public class App implements Runnable { - @CommandLine.Option(names = {"-i", "--image"}, description = "Container image name to be provisioned") + @Option(names = {"-i", "--image"}, description = "Container image name to be provisioned") private String image; - @CommandLine.Option(names = {"-c", "--containerfile"}, description = "Container file (i.e. Dockerfile) to be used to build the image") + @Option(names = {"-c", "--containerfile"}, description = "Container file (i.e. Dockerfile) to be used to build the image") private String containerFile; private String towerToken; - @CommandLine.Option(names = {"--tower-endpoint"}, description = "Tower service endpoint") + @Option(names = {"--tower-endpoint"}, description = "Tower service endpoint") private String towerEndpoint; private Long towerWorkspaceId; - @CommandLine.Option(names = {"--build-repo"}, description = "The container repository where image build by Wave will stored") + @Option(names = {"--build-repo"}, description = "The container repository where image build by Wave will stored") private String buildRepository; - @CommandLine.Option(names = {"--cache-repo"}, description = "The container repository where image layer created by Wave will stored") + @Option(names = {"--cache-repo"}, description = "The container repository where image layer created by Wave will stored") private String cacheRepository; - - @CommandLine.Option(names = {"--wave-endpoint"}, description = "Wave service endpoint (default: ${DEFAULT-VALUE})") + @Option(names = {"--wave-endpoint"}, description = "Wave service endpoint (default: ${DEFAULT-VALUE})") private String waveEndpoint = Client.DEFAULT_ENDPOINT; public static void main(String[] args) { diff --git a/app/src/main/java/io/seqera/wavelit/app/Client.java b/app/src/main/java/io/seqera/wavelit/Client.java similarity index 97% rename from app/src/main/java/io/seqera/wavelit/app/Client.java rename to app/src/main/java/io/seqera/wavelit/Client.java index ed280d8..58a08ee 100644 --- a/app/src/main/java/io/seqera/wavelit/app/Client.java +++ b/app/src/main/java/io/seqera/wavelit/Client.java @@ -9,7 +9,7 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app; +package io.seqera.wavelit; import java.io.IOException; import java.net.URI; @@ -27,8 +27,8 @@ import dev.failsafe.function.CheckedSupplier; import io.seqera.wave.api.SubmitContainerTokenRequest; import io.seqera.wave.api.SubmitContainerTokenResponse; -import io.seqera.wavelit.app.config.RetryOpts; -import io.seqera.wavelit.app.json.JsonHelper; +import io.seqera.wavelit.config.RetryOpts; +import io.seqera.wavelit.json.JsonHelper; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/app/src/main/java/io/seqera/wavelit/app/config/RetryOpts.java b/app/src/main/java/io/seqera/wavelit/config/RetryOpts.java similarity index 94% rename from app/src/main/java/io/seqera/wavelit/app/config/RetryOpts.java rename to app/src/main/java/io/seqera/wavelit/config/RetryOpts.java index 6e6f465..0c987d7 100644 --- a/app/src/main/java/io/seqera/wavelit/app/config/RetryOpts.java +++ b/app/src/main/java/io/seqera/wavelit/config/RetryOpts.java @@ -9,7 +9,7 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app.config; +package io.seqera.wavelit.config; import java.time.Duration; diff --git a/app/src/main/java/io/seqera/wavelit/app/exception/IllegalCliArgumentException.java b/app/src/main/java/io/seqera/wavelit/exception/IllegalCliArgumentException.java similarity index 94% rename from app/src/main/java/io/seqera/wavelit/app/exception/IllegalCliArgumentException.java rename to app/src/main/java/io/seqera/wavelit/exception/IllegalCliArgumentException.java index 186e4cb..a2b891d 100644 --- a/app/src/main/java/io/seqera/wavelit/app/exception/IllegalCliArgumentException.java +++ b/app/src/main/java/io/seqera/wavelit/exception/IllegalCliArgumentException.java @@ -9,7 +9,7 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app.exception; +package io.seqera.wavelit.exception; /** * Exception thrown to report a CLI validation error diff --git a/app/src/main/java/io/seqera/wavelit/app/json/ByteArrayAdapter.java b/app/src/main/java/io/seqera/wavelit/json/ByteArrayAdapter.java similarity index 95% rename from app/src/main/java/io/seqera/wavelit/app/json/ByteArrayAdapter.java rename to app/src/main/java/io/seqera/wavelit/json/ByteArrayAdapter.java index 7dd6d8e..08271b4 100644 --- a/app/src/main/java/io/seqera/wavelit/app/json/ByteArrayAdapter.java +++ b/app/src/main/java/io/seqera/wavelit/json/ByteArrayAdapter.java @@ -9,7 +9,7 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app.json; +package io.seqera.wavelit.json; import java.util.Base64; diff --git a/app/src/main/java/io/seqera/wavelit/app/json/DateTimeAdapter.java b/app/src/main/java/io/seqera/wavelit/json/DateTimeAdapter.java similarity index 97% rename from app/src/main/java/io/seqera/wavelit/app/json/DateTimeAdapter.java rename to app/src/main/java/io/seqera/wavelit/json/DateTimeAdapter.java index 3c42c08..509a4cf 100644 --- a/app/src/main/java/io/seqera/wavelit/app/json/DateTimeAdapter.java +++ b/app/src/main/java/io/seqera/wavelit/json/DateTimeAdapter.java @@ -9,7 +9,7 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app.json; +package io.seqera.wavelit.json; import java.time.Duration; import java.time.Instant; diff --git a/app/src/main/java/io/seqera/wavelit/app/json/JsonHelper.java b/app/src/main/java/io/seqera/wavelit/json/JsonHelper.java similarity index 97% rename from app/src/main/java/io/seqera/wavelit/app/json/JsonHelper.java rename to app/src/main/java/io/seqera/wavelit/json/JsonHelper.java index 1fc5c63..5c5a7df 100644 --- a/app/src/main/java/io/seqera/wavelit/app/json/JsonHelper.java +++ b/app/src/main/java/io/seqera/wavelit/json/JsonHelper.java @@ -9,7 +9,7 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app.json; +package io.seqera.wavelit.json; import java.io.IOException; diff --git a/app/src/main/java/io/seqera/wavelit/app/json/PathAdapter.java b/app/src/main/java/io/seqera/wavelit/json/PathAdapter.java similarity index 96% rename from app/src/main/java/io/seqera/wavelit/app/json/PathAdapter.java rename to app/src/main/java/io/seqera/wavelit/json/PathAdapter.java index 9ee0c09..f553575 100644 --- a/app/src/main/java/io/seqera/wavelit/app/json/PathAdapter.java +++ b/app/src/main/java/io/seqera/wavelit/json/PathAdapter.java @@ -9,7 +9,7 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app.json; +package io.seqera.wavelit.json; import java.nio.file.Path; diff --git a/app/src/main/java/io/seqera/wavelit/util/BuildInfo.java b/app/src/main/java/io/seqera/wavelit/util/BuildInfo.java new file mode 100644 index 0000000..8f2fef1 --- /dev/null +++ b/app/src/main/java/io/seqera/wavelit/util/BuildInfo.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023, Seqera Labs. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +package io.seqera.wavelit.util; + +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Paolo Di Tommaso + */ +public class BuildInfo { + + private static final Logger log = LoggerFactory.getLogger(BuildInfo.class); + + private static Properties properties; + + static { + final String BUILD_INFO = "/META-INF/build-info.properties"; + properties = new Properties(); + try { + properties.load( BuildInfo.class.getResourceAsStream(BUILD_INFO) ); + } + catch( Exception e ) { + log.warn("Unable to parse $BUILD_INFO - Cause: " + e.getMessage()); + } + } + + static Properties getProperties() { return properties; } + + static public String getVersion() { return properties.getProperty("version"); } + + static public String getCommitId() { return properties.getProperty("commitId"); } + + static public String getName() { return properties.getProperty("name"); } + + static public String getFullVersion() { + return getVersion() + "_" + getCommitId(); + } + +} diff --git a/app/src/main/java/io/seqera/wavelit/util/CliVersionProvider.java b/app/src/main/java/io/seqera/wavelit/util/CliVersionProvider.java new file mode 100644 index 0000000..f57538e --- /dev/null +++ b/app/src/main/java/io/seqera/wavelit/util/CliVersionProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, Seqera Labs. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +package io.seqera.wavelit.util; + +import picocli.CommandLine; + +/** + * @author Paolo Di Tommaso + */ +public class CliVersionProvider implements CommandLine.IVersionProvider { + @Override + public String[] getVersion() throws Exception { + return new String[] { BuildInfo.getVersion() }; + } +} diff --git a/app/src/main/resources/META-INF/build-info.properties b/app/src/main/resources/META-INF/build-info.properties new file mode 100644 index 0000000..78a8122 --- /dev/null +++ b/app/src/main/resources/META-INF/build-info.properties @@ -0,0 +1,3 @@ +name=wavelit +version=0.1.0 +commitId=unknown diff --git a/app/src/test/groovy/io/seqera/wavelit/app/JsonHelperTest.groovy b/app/src/test/groovy/io/seqera/wavelit/JsonHelperTest.groovy similarity index 94% rename from app/src/test/groovy/io/seqera/wavelit/app/JsonHelperTest.groovy rename to app/src/test/groovy/io/seqera/wavelit/JsonHelperTest.groovy index a76d35e..a661408 100644 --- a/app/src/test/groovy/io/seqera/wavelit/app/JsonHelperTest.groovy +++ b/app/src/test/groovy/io/seqera/wavelit/JsonHelperTest.groovy @@ -9,10 +9,10 @@ * defined by the Mozilla Public License, v. 2.0. */ -package io.seqera.wavelit.app +package io.seqera.wavelit import io.seqera.wave.api.SubmitContainerTokenRequest -import io.seqera.wavelit.app.json.JsonHelper +import io.seqera.wavelit.json.JsonHelper import spock.lang.Specification; /** diff --git a/app/src/test/groovy/io/seqera/wavelit/util/BuildInfoTest.groovy b/app/src/test/groovy/io/seqera/wavelit/util/BuildInfoTest.groovy new file mode 100644 index 0000000..ba97384 --- /dev/null +++ b/app/src/test/groovy/io/seqera/wavelit/util/BuildInfoTest.groovy @@ -0,0 +1,16 @@ +package io.seqera.wavelit.util + +import spock.lang.Specification +/** + * + * @author Paolo Di Tommaso + */ +class BuildInfoTest extends Specification { + + def 'should load version and commit id' () { + expect: + BuildInfo.getName() == 'wavelit' + BuildInfo.getVersion() + BuildInfo.getCommitId() + } +}