Skip to content

Commit 6e1c897

Browse files
authored
[feat] Intro GeneratorMetadata (stability index) (#2816)
* [feat] Intro GeneratorMetadata (stability index) GeneratorMetadata offers an immutable object created via Builder pattern which allows generators to explicitly define their stability (stable, beta, experimental, deprecated) as well as a message to be shown during generation. This is a step toward: * Fleshing out the "Core" artifact (#845) * Providing a place to encapsulate feature-oriented metadata (#840) * Providing a means to communicate end of life scheduling (#116) This new structure, specifically the Stability property, allows us to offer future enhancements such as allowing users to filter down to only "Stable" generators via CLI, and eventually any compat table (see #503). * Mark deprecated generators as deprecated in-code * Re-export docs/generators.md
1 parent 26d0487 commit 6e1c897

File tree

11 files changed

+225
-5
lines changed

11 files changed

+225
-5
lines changed

docs/generators.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The following generators are available:
1616
- [cpp-restsdk](generators/cpp-restsdk.md)
1717
- [cpp-tizen](generators/cpp-tizen.md)
1818
- [csharp](generators/csharp.md)
19-
- [csharp-dotnet2](generators/csharp-dotnet2.md)
19+
- [csharp-dotnet2](generators/csharp-dotnet2.md) (deprecated)
2020
- [csharp-netcore](generators/csharp-netcore.md)
2121
- [dart](generators/dart.md)
2222
- [dart-jaguar](generators/dart-jaguar.md)
@@ -47,10 +47,10 @@ The following generators are available:
4747
- [rust](generators/rust.md)
4848
- [scala-akka](generators/scala-akka.md)
4949
- [scala-gatling](generators/scala-gatling.md)
50-
- [scala-httpclient-deprecated](generators/scala-httpclient-deprecated.md)
50+
- [scala-httpclient-deprecated](generators/scala-httpclient-deprecated.md) (deprecated)
5151
- [scalaz](generators/scalaz.md)
52-
- [swift2-deprecated](generators/swift2-deprecated.md)
53-
- [swift3-deprecated](generators/swift3-deprecated.md)
52+
- [swift2-deprecated](generators/swift2-deprecated.md) (deprecated)
53+
- [swift3-deprecated](generators/swift3-deprecated.md) (deprecated)
5454
- [swift4](generators/swift4.md)
5555
- [typescript-angular](generators/typescript-angular.md)
5656
- [typescript-angularjs](generators/typescript-angularjs.md)

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import org.openapitools.codegen.CodegenConfig;
99
import org.openapitools.codegen.CodegenConfigLoader;
1010
import org.openapitools.codegen.CodegenType;
11+
import org.openapitools.codegen.meta.GeneratorMetadata;
12+
import org.openapitools.codegen.meta.Stability;
1113

1214
import java.util.Comparator;
1315
import java.util.List;
@@ -70,16 +72,27 @@ private void appendForType(StringBuilder sb, CodegenType type, String typeName,
7072
sb.append(System.lineSeparator());
7173

7274
list.forEach(generator -> {
75+
GeneratorMetadata meta = generator.getGeneratorMetadata();
7376
if (docusaurus) {
7477
sb.append("* ");
7578
String id = "generators/" + generator.getName();
76-
sb.append("[").append(generator.getName()).append("](").append(id).append(")");
79+
sb.append("[").append(generator.getName());
80+
81+
if (meta != null && meta.getStability() != null && meta.getStability() != Stability.STABLE) {
82+
sb.append(" (").append(meta.getStability().value()).append(")");
83+
}
84+
85+
sb.append("](").append(id).append(")");
7786

7887
// trailing space is important for markdown list formatting
7988
sb.append(" ");
8089
} else {
8190
sb.append(" - ");
8291
sb.append(generator.getName());
92+
93+
if (meta != null && meta.getStability() != null && meta.getStability() != Stability.STABLE) {
94+
sb.append(" (").append(meta.getStability().value()).append(")");
95+
}
8396
}
8497
sb.append(System.lineSeparator());
8598
});
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package org.openapitools.codegen.meta;
2+
3+
/**
4+
* Represents metadata about a generator.
5+
*/
6+
public class GeneratorMetadata {
7+
private Stability stability;
8+
private String generationMessage;
9+
10+
private GeneratorMetadata(Builder builder) {
11+
stability = builder.stability;
12+
generationMessage = builder.generationMessage;
13+
}
14+
15+
/**
16+
* Creates a new builder object for {@link GeneratorMetadata}.
17+
*
18+
* @return A new builder instance.
19+
*/
20+
public static Builder newBuilder() {
21+
return new Builder();
22+
}
23+
24+
/**
25+
* Creates a new builder object for {@link GeneratorMetadata}, accepting another instance from which to copy properties.
26+
*
27+
* @param copy An existing instance to copy defaults from
28+
*
29+
* @return A new builder instance, with values preset to those of 'copy'.
30+
*/
31+
public static Builder newBuilder(GeneratorMetadata copy) {
32+
Builder builder = new Builder();
33+
if (copy != null) {
34+
builder.stability = copy.getStability();
35+
builder.generationMessage = copy.getGenerationMessage();
36+
}
37+
return builder;
38+
}
39+
40+
/**
41+
* Returns a message which can be displayed during generation.
42+
*
43+
* @return A message, if defined.
44+
*/
45+
public String getGenerationMessage() {
46+
return generationMessage;
47+
}
48+
49+
/**
50+
* Returns an enum describing the stability index of the generator.
51+
*
52+
* @return The defined stability index.
53+
*/
54+
public Stability getStability() {
55+
return stability;
56+
}
57+
58+
/**
59+
* {@code GeneratorMetadata} builder static inner class.
60+
*/
61+
public static final class Builder {
62+
private Stability stability;
63+
private String generationMessage;
64+
65+
private Builder() {
66+
}
67+
68+
/**
69+
* Sets the {@code stability} and returns a reference to this Builder so that the methods can be chained together.
70+
*
71+
* @param stability the {@code stability} to set
72+
* @return a reference to this Builder
73+
*/
74+
public Builder stability(Stability stability) {
75+
this.stability = stability;
76+
return this;
77+
}
78+
79+
/**
80+
* Sets the {@code generationMessage} and returns a reference to this Builder so that the methods can be chained together.
81+
*
82+
* @param generationMessage the {@code generationMessage} to set
83+
* @return a reference to this Builder
84+
*/
85+
public Builder generationMessage(String generationMessage) {
86+
this.generationMessage = generationMessage;
87+
return this;
88+
}
89+
90+
/**
91+
* Returns a {@code GeneratorMetadata} built from the parameters previously set.
92+
*
93+
* @return a {@code GeneratorMetadata} built with parameters of this {@code GeneratorMetadata.Builder}
94+
*/
95+
public GeneratorMetadata build() {
96+
return new GeneratorMetadata(this);
97+
}
98+
}
99+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.openapitools.codegen.meta;
2+
3+
/**
4+
* Represents the "stability index" of a generator or feature, based on the stability indexes defined in the node.js ecosystem.
5+
*/
6+
public enum Stability {
7+
/**
8+
* The feature or features are considered complete and "production-ready".
9+
*/
10+
STABLE("stable"),
11+
/**
12+
* The feature may be partially incomplete, but breaking changes will be avoided between major releases.
13+
*/
14+
BETA("beta"),
15+
/**
16+
* The feature is still under active development and subject to non-backward compatible changes or removal in any
17+
* future version. Use of the feature is not recommended in production environments.
18+
*/
19+
EXPERIMENTAL("experimental"),
20+
/**
21+
* The feature may emit warnings. Backward compatibility is not guaranteed. Removal is likely to occur in a subsequent major release.
22+
*/
23+
DEPRECATED("deprecated");
24+
25+
private String description;
26+
27+
Stability(String description) {
28+
this.description = description;
29+
}
30+
31+
/**
32+
* Returns a value for this stability index.
33+
*
34+
* @return The descriptive value of this enum.
35+
*/
36+
public String value() { return description; }
37+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@
2525
import io.swagger.v3.oas.models.servers.Server;
2626
import io.swagger.v3.oas.models.servers.ServerVariable;
2727
import org.openapitools.codegen.api.TemplatingEngineAdapter;
28+
import org.openapitools.codegen.meta.GeneratorMetadata;
2829

2930
import java.io.File;
3031
import java.util.List;
3132
import java.util.Map;
3233
import java.util.Set;
3334

3435
public interface CodegenConfig {
36+
GeneratorMetadata getGeneratorMetadata();
37+
3538
CodegenType getTag();
3639

3740
String getName();

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import org.openapitools.codegen.api.TemplatingEngineAdapter;
4545
import org.openapitools.codegen.config.GeneratorProperties;
4646
import org.openapitools.codegen.examples.ExampleGenerator;
47+
import org.openapitools.codegen.meta.GeneratorMetadata;
48+
import org.openapitools.codegen.meta.Stability;
4749
import org.openapitools.codegen.serializer.SerializerUtils;
4850
import org.openapitools.codegen.templating.MustacheEngineAdapter;
4951
import org.openapitools.codegen.utils.ModelUtils;
@@ -63,6 +65,7 @@
6365
public class DefaultCodegen implements CodegenConfig {
6466
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class);
6567

68+
protected GeneratorMetadata generatorMetadata;
6669
protected String inputSpec;
6770
protected String outputFolder = "";
6871
protected Set<String> defaultIncludes = new HashSet<String>();
@@ -816,6 +819,16 @@ public String toModelDocFilename(String name) {
816819
return camelize(name);
817820
}
818821

822+
/**
823+
* Returns metadata about the generator.
824+
*
825+
* @return A provided {@link GeneratorMetadata} instance
826+
*/
827+
@Override
828+
public GeneratorMetadata getGeneratorMetadata() {
829+
return generatorMetadata;
830+
}
831+
819832
/**
820833
* Return the operation ID (method name)
821834
*
@@ -932,6 +945,15 @@ public String toApiImport(String name) {
932945
* returns string presentation of the example path (it's a constructor)
933946
*/
934947
public DefaultCodegen() {
948+
CodegenType codegenType = getTag();
949+
if (codegenType == null) {
950+
codegenType = CodegenType.OTHER;
951+
}
952+
generatorMetadata = GeneratorMetadata.newBuilder()
953+
.stability(Stability.STABLE)
954+
.generationMessage(String.format(Locale.ROOT, "OpenAPI Generator: %s (%s)", getName(), codegenType.toValue()))
955+
.build();
956+
935957
defaultIncludes = new HashSet<String>(
936958
Arrays.asList("double",
937959
"int",

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import org.openapitools.codegen.config.GeneratorProperties;
3636
import org.openapitools.codegen.api.TemplatingEngineAdapter;
3737
import org.openapitools.codegen.ignore.CodegenIgnoreProcessor;
38+
import org.openapitools.codegen.meta.GeneratorMetadata;
39+
import org.openapitools.codegen.meta.Stability;
3840
import org.openapitools.codegen.templating.MustacheEngineAdapter;
3941
import org.openapitools.codegen.config.GeneratorProperties;
4042
import org.openapitools.codegen.utils.ImplementationVersion;
@@ -883,6 +885,23 @@ public List<File> generate() {
883885
throw new RuntimeException("missing config!");
884886
}
885887

888+
if (config.getGeneratorMetadata() == null) {
889+
LOGGER.warn(String.format(Locale.ROOT, "Generator '%s' is missing generator metadata!", config.getName()));
890+
} else {
891+
GeneratorMetadata generatorMetadata = config.getGeneratorMetadata();
892+
if (StringUtils.isNotEmpty(generatorMetadata.getGenerationMessage())) {
893+
LOGGER.info(generatorMetadata.getGenerationMessage());
894+
}
895+
896+
Stability stability = generatorMetadata.getStability();
897+
String stabilityMessage = String.format(Locale.ROOT, "Generator '%s' is considered %s.", config.getName(), stability.value());
898+
if (stability == Stability.DEPRECATED) {
899+
LOGGER.warn(stabilityMessage);
900+
} else {
901+
LOGGER.info(stabilityMessage);
902+
}
903+
}
904+
886905
// resolve inline models
887906
InlineModelResolver inlineModelResolver = new InlineModelResolver();
888907
inlineModelResolver.flatten(openAPI);

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpDotNet2ClientCodegen.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.openapitools.codegen.CodegenType;
2323
import org.openapitools.codegen.SupportingFile;
2424

25+
import org.openapitools.codegen.meta.GeneratorMetadata;
26+
import org.openapitools.codegen.meta.Stability;
2527
import org.slf4j.Logger;
2628
import org.slf4j.LoggerFactory;
2729

@@ -38,6 +40,10 @@ public class CSharpDotNet2ClientCodegen extends AbstractCSharpCodegen {
3840
public CSharpDotNet2ClientCodegen() {
3941
super();
4042

43+
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
44+
.stability(Stability.DEPRECATED)
45+
.build();
46+
4147
// clear import mapping (from default generator) as C# (2.0) does not use it
4248
// at the moment
4349
importMapping.clear();

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaHttpClientCodegen.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import org.apache.commons.lang3.StringUtils;
2121
import org.openapitools.codegen.*;
22+
import org.openapitools.codegen.meta.GeneratorMetadata;
23+
import org.openapitools.codegen.meta.Stability;
2224
import org.slf4j.Logger;
2325
import org.slf4j.LoggerFactory;
2426

@@ -46,6 +48,11 @@ public class ScalaHttpClientCodegen extends AbstractScalaCodegen implements Code
4648

4749
public ScalaHttpClientCodegen() {
4850
super();
51+
52+
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
53+
.stability(Stability.DEPRECATED)
54+
.build();
55+
4956
outputFolder = "generated-code/scala-http-client";
5057
modelTemplateFiles.put("model.mustache", ".scala");
5158
apiTemplateFiles.put("api.mustache", ".scala");

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift3Codegen.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.apache.commons.lang3.StringUtils;
2525
import org.apache.commons.lang3.text.WordUtils;
2626
import org.openapitools.codegen.*;
27+
import org.openapitools.codegen.meta.GeneratorMetadata;
28+
import org.openapitools.codegen.meta.Stability;
2729
import org.openapitools.codegen.utils.ModelUtils;
2830
import org.slf4j.Logger;
2931
import org.slf4j.LoggerFactory;
@@ -68,6 +70,11 @@ public class Swift3Codegen extends DefaultCodegen implements CodegenConfig {
6870

6971
public Swift3Codegen() {
7072
super();
73+
74+
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
75+
.stability(Stability.DEPRECATED)
76+
.build();
77+
7178
outputFolder = "generated-code" + File.separator + "swift";
7279
modelTemplateFiles.put("model.mustache", ".swift");
7380
apiTemplateFiles.put("api.mustache", ".swift");

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SwiftClientCodegen.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import org.apache.commons.lang3.StringUtils;
2626
import org.apache.commons.lang3.text.WordUtils;
2727
import org.openapitools.codegen.*;
28+
import org.openapitools.codegen.meta.GeneratorMetadata;
29+
import org.openapitools.codegen.meta.Stability;
2830
import org.openapitools.codegen.utils.ModelUtils;
2931
import org.slf4j.Logger;
3032
import org.slf4j.LoggerFactory;
@@ -87,6 +89,11 @@ public String getHelp() {
8789

8890
public SwiftClientCodegen() {
8991
super();
92+
93+
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
94+
.stability(Stability.DEPRECATED)
95+
.build();
96+
9097
outputFolder = "generated-code" + File.separator + "swift";
9198
modelTemplateFiles.put("model.mustache", ".swift");
9299
apiTemplateFiles.put("api.mustache", ".swift");

0 commit comments

Comments
 (0)