Skip to content

Commit e14e5fc

Browse files
authored
[cli][docker] Better expose version/sha information of builds (#5736)
* [cli] Some CLI improvements… * Introduce --version * Introduce --help * Add --sha to version command for short SHA display * Output Version and SHA details * In new --version output, display repo and doc site Additional cleanup to suppress warnings and code quality. * [docker] Adds labels for metadata This adds image labels to store metadata on the online and cli docker images, using standard labels: * org.opencontainers.image.created * org.opencontainers.image.revision * org.opencontainers.image.title * org.opencontainers.image.version These can be inspected via 'docker inspect IMAGE_NAME' and may be useful in tooling/automation or bug reports submitted by users. For more details on these labels, see: https://github.com/opencontainers/image-spec/blob/master/annotations.md * Include version --full for equiv to --version
1 parent 4623ec8 commit e14e5fc

18 files changed

+297
-64
lines changed

.travis.yml

+26-2
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,33 @@ after_success:
178178
fi;
179179
fi;
180180
## docker: build and push openapi-generator-online to DockerHub
181-
- if [ $DOCKER_HUB_USERNAME ]; then echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin && docker build -t $DOCKER_GENERATOR_IMAGE_NAME ./modules/openapi-generator-online && if [ ! -z "$TRAVIS_TAG" ]; then docker tag $DOCKER_GENERATOR_IMAGE_NAME:latest $DOCKER_GENERATOR_IMAGE_NAME:$TRAVIS_TAG; fi && if [ ! -z "$TRAVIS_TAG" ] || [ "$TRAVIS_BRANCH" = "master" ]; then docker push $DOCKER_GENERATOR_IMAGE_NAME && echo "Pushed to $DOCKER_GENERATOR_IMAGE_NAME"; fi; fi
181+
- if [ $DOCKER_HUB_USERNAME ]; then
182+
echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin;
183+
export cli_version=$(\mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\[');
184+
export build_date=$(date -u +"%Y-%m-%dT%H:%M:%SZ");
185+
docker build --label=org.opencontainers.image.created=$build_date --label=org.opencontainers.image.title=openapi-generator-online --label=org.opencontainers.image.revision=$TRAVIS_COMMIT --label=org.opencontainers.image.version=$cli_version -t $DOCKER_GENERATOR_IMAGE_NAME ./modules/openapi-generator-online;
186+
if [ ! -z "$TRAVIS_TAG" ]; then
187+
docker tag $DOCKER_GENERATOR_IMAGE_NAME:latest $DOCKER_GENERATOR_IMAGE_NAME:$TRAVIS_TAG;
188+
fi;
189+
if [ ! -z "$TRAVIS_TAG" ] || [ "$TRAVIS_BRANCH" = "master" ]; then
190+
docker push $DOCKER_GENERATOR_IMAGE_NAME && echo "Pushed to $DOCKER_GENERATOR_IMAGE_NAME";
191+
fi;
192+
fi;
182193
## docker: build cli image and push to Docker Hub
183-
- if [ $DOCKER_HUB_USERNAME ]; then echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin && cp docker-entrypoint.sh ./modules/openapi-generator-cli && docker build -t $DOCKER_CODEGEN_CLI_IMAGE_NAME ./modules/openapi-generator-cli && if [ ! -z "$TRAVIS_TAG" ]; then docker tag $DOCKER_CODEGEN_CLI_IMAGE_NAME:latest $DOCKER_CODEGEN_CLI_IMAGE_NAME:$TRAVIS_TAG; fi && if [ ! -z "$TRAVIS_TAG" ] || [ "$TRAVIS_BRANCH" = "master" ]; then docker push $DOCKER_CODEGEN_CLI_IMAGE_NAME && echo "Pushed to $DOCKER_CODEGEN_CLI_IMAGE_NAME"; fi; fi
194+
- if [ $DOCKER_HUB_USERNAME ]; then
195+
echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin;
196+
cp docker-entrypoint.sh ./modules/openapi-generator-cli;
197+
export cli_version=$(\mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\[');
198+
export build_date=$(date -u +"%Y-%m-%dT%H:%M:%SZ");
199+
docker build --label=org.opencontainers.image.created=$build_date --label=org.opencontainers.image.title=openapi-generator-cli --label=org.opencontainers.image.revision=$TRAVIS_COMMIT --label=org.opencontainers.image.version=$cli_version -t $DOCKER_CODEGEN_CLI_IMAGE_NAME ./modules/openapi-generator-cli;
200+
if [ ! -z "$TRAVIS_TAG" ]; then
201+
docker tag $DOCKER_CODEGEN_CLI_IMAGE_NAME:latest $DOCKER_CODEGEN_CLI_IMAGE_NAME:$TRAVIS_TAG;
202+
fi;
203+
if [ ! -z "$TRAVIS_TAG" ] || [ "$TRAVIS_BRANCH" = "master" ]; then
204+
docker push $DOCKER_CODEGEN_CLI_IMAGE_NAME;
205+
echo "Pushed to $DOCKER_CODEGEN_CLI_IMAGE_NAME";
206+
fi;
207+
fi;
184208
## publish latest website, variables below are secure environment variables which are unavailable to PRs from forks.
185209
- if [ "$TRAVIS_BRANCH" = "master" ] && [ -z $TRAVIS_TAG ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
186210
cd website;

docs/usage.md

+16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ The most commonly used openapi-generator-cli commands are:
2525

2626
See 'openapi-generator-cli help <command>' for more information on a specific
2727
command.
28+
```
29+
30+
## version
31+
32+
The version command provides version information, returning either the semver version by default or the git sha when passed `--sha`.
33+
34+
```bash
35+
NAME
36+
openapi-generator-cli version - Show version information
37+
38+
SYNOPSIS
39+
openapi-generator-cli version [--sha]
40+
41+
OPTIONS
42+
--sha
43+
Git commit SHA version
2844

2945
```
3046

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.openapitools.codegen;
2+
3+
public class Constants {
4+
private Constants(){ }
5+
6+
public static final String CLI_NAME = "openapi-generator-cli";
7+
public static final String GIT_REPO = "https://github.com/openapitools/openapi-generator";
8+
public static final String SITE = "https://openapi-generator.tech/";
9+
}

modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/OpenAPIGenerator.java

+13-13
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,38 @@
1818
package org.openapitools.codegen;
1919

2020
import io.airlift.airline.Cli;
21-
import io.airlift.airline.Help;
2221
import io.airlift.airline.ParseArgumentsUnexpectedException;
2322
import io.airlift.airline.ParseOptionMissingException;
2423
import io.airlift.airline.ParseOptionMissingValueException;
2524
import org.openapitools.codegen.cmd.*;
2625

2726
import java.util.Locale;
2827

28+
import static org.openapitools.codegen.Constants.CLI_NAME;
29+
2930
/**
3031
* User: lanwen Date: 24.03.15 Time: 17:56
3132
* <p>
3233
* Command line interface for OpenAPI Generator use `openapi-generator-cli.jar help` for more info
33-
*
34-
* @since 2.1.3-M1
3534
*/
3635
public class OpenAPIGenerator {
3736

3837
public static void main(String[] args) {
39-
String version = Version.readVersionFromResources();
40-
Cli.CliBuilder<Runnable> builder =
41-
Cli.<Runnable>builder("openapi-generator-cli")
38+
BuildInfo buildInfo = new BuildInfo();
39+
Cli.CliBuilder<OpenApiGeneratorCommand> builder =
40+
Cli.<OpenApiGeneratorCommand>builder(CLI_NAME)
4241
.withDescription(
4342
String.format(
4443
Locale.ROOT,
45-
"OpenAPI generator CLI (version %s).",
46-
version))
47-
.withDefaultCommand(ListGenerators.class)
44+
"OpenAPI Generator CLI %s (%s).",
45+
buildInfo.getVersion(),
46+
buildInfo.getSha()))
47+
.withDefaultCommand(HelpCommand.class)
4848
.withCommands(
4949
ListGenerators.class,
5050
Generate.class,
5151
Meta.class,
52-
Help.class,
52+
HelpCommand.class,
5353
ConfigHelp.class,
5454
Validate.class,
5555
Version.class,
@@ -60,7 +60,7 @@ public static void main(String[] args) {
6060
try {
6161
builder.build().parse(args).run();
6262

63-
// If CLI is run without a command, consider this an error. This exists after initial parse/run
63+
// If CLI runs without a command, consider this an error. This exists after initial parse/run
6464
// so we can present the configured "default command".
6565
// We can check against empty args because unrecognized arguments/commands result in an exception.
6666
// This is useful to exit with status 1, for example, so that misconfigured scripts fail fast.
@@ -71,10 +71,10 @@ public static void main(String[] args) {
7171
System.exit(1);
7272
}
7373
} catch (ParseArgumentsUnexpectedException e) {
74-
System.err.printf(Locale.ROOT,"[error] %s%n%nSee 'openapi-generator help' for usage.%n", e.getMessage());
74+
System.err.printf(Locale.ROOT, "[error] %s%n%nSee '%s help' for usage.%n", e.getMessage(), CLI_NAME);
7575
System.exit(1);
7676
} catch (ParseOptionMissingException | ParseOptionMissingValueException e) {
77-
System.err.printf(Locale.ROOT,"[error] %s%n", e.getMessage());
77+
System.err.printf(Locale.ROOT, "[error] %s%n", e.getMessage());
7878
System.exit(1);
7979
}
8080
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package org.openapitools.codegen.cmd;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.time.OffsetDateTime;
6+
import java.time.format.DateTimeFormatter;
7+
import java.time.format.DateTimeParseException;
8+
import java.util.Locale;
9+
import java.util.Properties;
10+
11+
import static org.openapitools.codegen.Constants.*;
12+
13+
/**
14+
* Presents build-time information
15+
*/
16+
@SuppressWarnings({"java:S108"})
17+
public class BuildInfo {
18+
private static final String VERSION_PLACEHOLDER = "${project.version}";
19+
private static final String UNSET = "unset";
20+
private static final String UNKNOWN = "unknown";
21+
22+
private static final Properties properties = new Properties();
23+
24+
static {
25+
try (InputStream is = BuildInfo.class.getResourceAsStream("/version.properties")) {
26+
Properties versionProps = new Properties();
27+
versionProps.load(is);
28+
properties.putAll(versionProps);
29+
} catch (IOException ignored) {
30+
}
31+
try (InputStream is = BuildInfo.class.getResourceAsStream("/openapi-generator-git.properties")) {
32+
Properties gitProps = new Properties();
33+
gitProps.load(is);
34+
properties.putAll(gitProps);
35+
} catch (IOException ignored) {
36+
}
37+
}
38+
39+
/**
40+
* Gets the version of the toolset.
41+
*
42+
* @return A semver string
43+
*/
44+
public String getVersion() {
45+
String version = (String) properties.getOrDefault("version", UNKNOWN);
46+
if (VERSION_PLACEHOLDER.equals(version)) {
47+
return UNSET;
48+
} else {
49+
return version;
50+
}
51+
}
52+
53+
/**
54+
* Gets the git commit SHA1 hash. Useful for differentiating between SNAPSHOT builds.
55+
*
56+
* @return A short git SHA
57+
*/
58+
public String getSha() {
59+
return (String) properties.getOrDefault("git.commit.id.abbrev", UNKNOWN);
60+
}
61+
62+
/**
63+
* Gets the time when this tool was built.
64+
*
65+
* @return The time as {@link OffsetDateTime}, or {@link OffsetDateTime#MIN} if metadata cannot be parsed.
66+
*/
67+
public OffsetDateTime getBuildTime() {
68+
try {
69+
String time = (String) properties.getOrDefault("git.build.time", "");
70+
return OffsetDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ROOT));
71+
} catch (DateTimeParseException e) {
72+
return OffsetDateTime.MIN;
73+
}
74+
}
75+
76+
/**
77+
* Gets the full version display text, as one would expect from a '--version' CLI option
78+
*
79+
* @return Human-readable version display information
80+
*/
81+
public String versionDisplayText() {
82+
StringBuilder sb = new StringBuilder(CLI_NAME);
83+
sb.append(" ").append(this.getVersion()).append(System.lineSeparator());
84+
sb.append(" commit : ").append(this.getSha()).append(System.lineSeparator());
85+
sb.append(" built : ").append(this.getBuildTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)).append(System.lineSeparator());
86+
sb.append(" source : ").append(GIT_REPO).append(System.lineSeparator());
87+
sb.append(" docs : ").append(SITE).append(System.lineSeparator());
88+
return sb.toString();
89+
}
90+
}

modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/CompletionCommand.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@
3636
import static com.google.common.collect.Lists.newArrayList;
3737
import static io.airlift.airline.ParserUtil.createInstance;
3838

39+
@SuppressWarnings({"java:S106"})
3940
@Command(name = "completion", description = "Complete commands (for using in tooling such as Bash Completions).", hidden = true)
40-
public class CompletionCommand
41+
public class CompletionCommand extends OpenApiGeneratorCommand
4142
implements Runnable, Callable<Void> {
4243
private static final Map<Context, Class<? extends Suggester>> BUILTIN_SUGGESTERS = ImmutableMap.<Context, Class<? extends Suggester>>builder()
4344
.put(Context.GLOBAL, GlobalSuggester.class)
@@ -95,7 +96,7 @@ public Iterable<String> generateSuggestions() {
9596
}
9697

9798
@Override
98-
public void run() {
99+
void execute() {
99100
System.out.println(Joiner.on("\n").join(generateSuggestions()));
100101
}
101102
}

modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/ConfigHelp.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
4040
import static org.apache.commons.lang3.StringUtils.isEmpty;
4141

42-
@SuppressWarnings("unused")
42+
@SuppressWarnings({"unused","java:S106"})
4343
@Command(name = "config-help", description = "Config help for chosen lang")
44-
public class ConfigHelp implements Runnable {
44+
public class ConfigHelp extends OpenApiGeneratorCommand {
4545

4646
private static final Logger LOGGER = LoggerFactory.getLogger(Generate.class);
4747

@@ -91,7 +91,7 @@ public class ConfigHelp implements Runnable {
9191
private String newline = System.lineSeparator();
9292

9393
@Override
94-
public void run() {
94+
public void execute() {
9595
if (isEmpty(generatorName)) {
9696
LOGGER.error("[error] A generator name (--generator-name / -g) is required.");
9797
System.exit(1);
@@ -320,6 +320,7 @@ private void generateYamlSample(StringBuilder sb, CodegenConfig config) {
320320
}
321321
}
322322

323+
@SuppressWarnings({"java:S1117"})
323324
private void generatePlainTextHelp(StringBuilder sb, CodegenConfig config) {
324325
sb.append(newline).append("CONFIG OPTIONS");
325326
if (Boolean.TRUE.equals(namedHeader)) {
@@ -418,6 +419,7 @@ private void generatePlainTextHelp(StringBuilder sb, CodegenConfig config) {
418419
}
419420
}
420421

422+
@SuppressWarnings({"java:S1117"})
421423
private void writePlainTextFromMap(
422424
StringBuilder sb,
423425
Map<String, String> map,
@@ -449,6 +451,7 @@ private void writePlainTextFromMap(
449451
}
450452
}
451453

454+
@SuppressWarnings({"java:S1117"})
452455
private void writePlainTextFromArray(StringBuilder sb, String[] arr, String optIndent) {
453456
if (arr.length > 0) {
454457
// target a width of 20, then take the max up to 40.

modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@
3434
import org.slf4j.Logger;
3535
import org.slf4j.LoggerFactory;
3636

37+
@SuppressWarnings({"java:S106"})
3738
@Command(name = "generate", description = "Generate code with the specified generator.")
38-
public class Generate implements Runnable {
39+
public class Generate extends OpenApiGeneratorCommand {
3940

4041
CodegenConfigurator configurator;
4142
Generator generator;
@@ -244,7 +245,7 @@ public class Generate implements Runnable {
244245
private Boolean minimalUpdate;
245246

246247
@Override
247-
public void run() {
248+
public void execute() {
248249
if (logToStderr != null) {
249250
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
250251
Stream.of(Logger.ROOT_LOGGER_NAME, "io.swagger", "org.openapitools")

modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/GenerateBatch.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@
5050
import java.util.stream.Collectors;
5151
import java.util.stream.Stream;
5252

53-
@SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"})
53+
@SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection", "java:S106"})
5454
@Command(name = "batch", description = "Generate code in batch via external configs.", hidden = true)
55-
public class GenerateBatch implements Runnable {
55+
public class GenerateBatch extends OpenApiGeneratorCommand {
5656

5757
private static final Logger LOGGER = LoggerFactory.getLogger(GenerateBatch.class);
5858

@@ -89,7 +89,7 @@ public class GenerateBatch implements Runnable {
8989
* @see Thread#run()
9090
*/
9191
@Override
92-
public void run() {
92+
public void execute() {
9393
if (configs.size() < 1) {
9494
LOGGER.error("No configuration file inputs specified");
9595
System.exit(1);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.openapitools.codegen.cmd;
2+
3+
import io.airlift.airline.Option;
4+
5+
import static io.airlift.airline.OptionType.GLOBAL;
6+
7+
public class GlobalOptions {
8+
@Option(type = GLOBAL, name = "--version", description = "Display full version output", hidden = true)
9+
public boolean version;
10+
11+
@Option(type = GLOBAL, name = "--help", description = "Display help about the tool", hidden = true)
12+
public boolean help;
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.openapitools.codegen.cmd;
2+
3+
import io.airlift.airline.Command;
4+
import io.airlift.airline.Help;
5+
6+
import javax.inject.Inject;
7+
8+
@Command(name = "help", description = "Display help information about openapi-generator")
9+
public class HelpCommand extends OpenApiGeneratorCommand {
10+
11+
@Inject
12+
public Help help;
13+
14+
@Override
15+
public void execute() {
16+
help.call();
17+
}
18+
}

modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/ListGenerators.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
import java.util.stream.Collectors;
1717

1818
// NOTE: List can later have subcommands such as list languages, list types, list frameworks, etc.
19+
@SuppressWarnings({"java:S106"})
1920
@Command(name = "list", description = "Lists the available generators")
20-
public class ListGenerators implements Runnable {
21+
public class ListGenerators extends OpenApiGeneratorCommand {
2122

2223
@Option(name = {"-s", "--short" }, description = "shortened output (suitable for scripting)")
2324
private Boolean shortened = false;
@@ -34,7 +35,7 @@ public class ListGenerators implements Runnable {
3435
private String include = "stable,beta,experimental";
3536

3637
@Override
37-
public void run() {
38+
public void execute() {
3839
List<CodegenConfig> generators = new ArrayList<>();
3940
List<Stability> stabilities = Arrays.asList(Stability.values());
4041

0 commit comments

Comments
 (0)