Skip to content

Commit

Permalink
add possibility generate several specification files at once
Browse files Browse the repository at this point in the history
  • Loading branch information
nebulon42 committed Jul 22, 2024
1 parent 1607ff3 commit 968af58
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@

package org.openapitools.codegen.config;

import java.util.List;

/**
* The Context used for generation.
*
* @param <TSpecDocument> the type of the input spec document.
*/
public class Context<TSpecDocument> {
private TSpecDocument specDocument;
private List<TSpecDocument> additionalSpecDocuments;
private GeneratorSettings generatorSettings;
private WorkflowSettings workflowSettings;

Expand All @@ -33,8 +36,9 @@ public class Context<TSpecDocument> {
* @param generatorSettings the generator settings
* @param workflowSettings the workflow settings
*/
public Context(TSpecDocument specDocument, GeneratorSettings generatorSettings, WorkflowSettings workflowSettings) {
public Context(TSpecDocument specDocument, List<TSpecDocument> additionalSpecDocuments, GeneratorSettings generatorSettings, WorkflowSettings workflowSettings) {
this.specDocument = specDocument;
this.additionalSpecDocuments = additionalSpecDocuments;
this.generatorSettings = generatorSettings;
this.workflowSettings = workflowSettings;
}
Expand All @@ -57,6 +61,15 @@ public TSpecDocument getSpecDocument() {
return specDocument;
}

/**
* Gets the additional spec documents.
*
* @return the spec document
*/
public List<TSpecDocument> getAdditionalSpecDocuments() {
return additionalSpecDocuments;
}

/**
* Gets the workflow settings. These options are specific to "how" code gets generated (input, output directory, ignore files, template engine, etc).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class WorkflowSettings {
public static final Map<String, String> DEFAULT_GLOBAL_PROPERTIES = Collections.unmodifiableMap(new HashMap<>());

private String inputSpec;
private List<String> additionalSpecFiles = new ArrayList<>();
private String outputDir = DEFAULT_OUTPUT_DIR;
private boolean verbose = DEFAULT_VERBOSE;
private boolean skipOverwrite = DEFAULT_SKIP_OVERWRITE;
Expand All @@ -68,6 +69,7 @@ public class WorkflowSettings {

private WorkflowSettings(Builder builder) {
this.inputSpec = builder.inputSpec;
this.additionalSpecFiles = builder.additionalSpecFiles;
this.outputDir = builder.outputDir;
this.verbose = builder.verbose;
this.skipOverwrite = builder.skipOverwrite;
Expand Down Expand Up @@ -100,6 +102,7 @@ public static Builder newBuilder() {
public static Builder newBuilder(WorkflowSettings copy) {
Builder builder = newBuilder();
builder.inputSpec = copy.getInputSpec();
builder.additionalSpecFiles = copy.getAdditionalSpecFiles();
builder.outputDir = copy.getOutputDir();
builder.verbose = copy.isVerbose();
builder.skipOverwrite = copy.isSkipOverwrite();
Expand Down Expand Up @@ -132,6 +135,15 @@ public String getInputSpec() {
return inputSpec;
}

/**
* Gets additional input spec locations, as URL or file
*
* @return the additional input spec files
*/
public List<String> getAdditionalSpecFiles() {
return additionalSpecFiles;
}

/**
* Gets the output dir (where we write generated files). Defaults to the current directory.
*
Expand Down Expand Up @@ -298,6 +310,7 @@ public Map<String, String> getGlobalProperties() {
@SuppressWarnings("unused")
public static final class Builder {
private String inputSpec;
private List<String> additionalSpecFiles = new ArrayList<>();
private String outputDir = DEFAULT_OUTPUT_DIR;
private Boolean verbose = DEFAULT_VERBOSE;
private Boolean skipOverwrite = DEFAULT_SKIP_OVERWRITE;
Expand Down Expand Up @@ -333,6 +346,19 @@ public Builder withInputSpec(String inputSpec) {
return this;
}

/**
* Sets the {@code additionalSpecFiles} and returns a reference to this Builder so that the methods can be chained together.
*
* @param additionalSpecFiles the {@code additionalSpecFiles} to set
* @return a reference to this Builder
*/
public Builder withAdditionalSpecFiles(List<String> additionalSpecFiles) {
if (additionalSpecFiles != null) {
this.additionalSpecFiles = additionalSpecFiles;
}
return this;
}

/**
* Sets the {@code outputDir} and returns a reference to this Builder so that the methods can be chained together.
*
Expand Down Expand Up @@ -572,6 +598,7 @@ public WorkflowSettings build() {
public String toString() {
return "WorkflowSettings{" +
"inputSpec='" + inputSpec + '\'' +
", additionalSpecFiles='" + additionalSpecFiles + '\'' +
", outputDir='" + outputDir + '\'' +
", verbose=" + verbose +
", skipOverwrite=" + skipOverwrite +
Expand Down Expand Up @@ -616,6 +643,7 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(
getInputSpec(),
getAdditionalSpecFiles(),
getOutputDir(),
isVerbose(),
isSkipOverwrite(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,10 @@ open class CommonGenerateCheckTask : DefaultTask() {
resolvedInputSpec = value
}

if (additionalSpecFiles.isPresent) {
configurator.setAdditionalSpecFiles(additionalSpecFiles.get())
}

remoteInputSpec.ifNotEmpty { value ->
resolvedInputSpec = value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class ClientOptInput {
private CodegenConfig config;
private GeneratorSettings generatorSettings;
private OpenAPI openAPI;
private List<OpenAPI> additionalSpecs;
private List<AuthorizationValue> auths;
// not deprecated as this is added to match other functionality, we need to move to Context<?> instead of ClientOptInput.
@Getter private List<TemplateDefinition> userDefinedTemplates;
Expand All @@ -40,6 +41,11 @@ public ClientOptInput openAPI(OpenAPI openAPI) {
return this;
}

public ClientOptInput additionalSpecs(List<OpenAPI> additionalSpecs) {
this.setAdditionalSpecs(additionalSpecs);
return this;
}

public ClientOptInput generatorSettings(GeneratorSettings generatorSettings) {
this.setGeneratorSettings(generatorSettings);
return this;
Expand Down Expand Up @@ -129,4 +135,19 @@ public void setOpenAPI(OpenAPI openAPI) {
this.config.setOpenAPI(this.openAPI);
}
}

public List<OpenAPI> getAdditionalSpecs() {
return additionalSpecs;
}

/**
* Sets additional OpenAPI documents
*
* @deprecated use {@link #additionalSpecs} instead
* @param additionalSpecs the specifications
*/
@Deprecated
public void setAdditionalSpecs(List<OpenAPI> additionalSpecs) {
this.additionalSpecs = additionalSpecs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.openapitools.codegen.model.WebhooksMap;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -122,6 +123,12 @@ public interface CodegenConfig {

void setInputSpec(String inputSpec);

default List<String> getAdditionalSpecFiles() {
return Collections.emptyList();
}

default void setAdditionalSpecFiles(List<String> additionalSpecFiles) {}

String getOutputDir();

void setOutputDir(String dir);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@
public class DefaultGenerator implements Generator {
private static final String METADATA_DIR = ".openapi-generator";
protected final Logger LOGGER = LoggerFactory.getLogger(DefaultGenerator.class);
private final boolean dryRun;
protected final boolean dryRun;
protected CodegenConfig config;
protected ClientOptInput opts;
protected OpenAPI openAPI;
protected CodegenIgnoreProcessor ignoreProcessor;
private Boolean generateApis = null;
private Boolean generateModels = null;
private Boolean generateRecursiveDependentModels = null;
private Boolean generateSupportingFiles = null;
protected Boolean generateSupportingFiles = null;
private Boolean generateWebhooks = null;
private Boolean generateApiTests = null;
private Boolean generateApiDocumentation = null;
Expand Down Expand Up @@ -328,7 +328,7 @@ void configureGeneratorProperties() {
}
}

private void configureOpenAPIInfo() {
void configureOpenAPIInfo() {
Info info = this.openAPI.getInfo();
if (info == null) {
return;
Expand Down Expand Up @@ -1075,7 +1075,7 @@ private void generateOpenapiGeneratorIgnoreFile() {
}
}

private void generateSupportingFiles(List<File> files, Map<String, Object> bundle) {
void generateSupportingFiles(List<File> files, Map<String, Object> bundle) {
if (!generateSupportingFiles) {
// TODO: process these anyway and report via dryRun?
LOGGER.info("Skipping generation of supporting files.");
Expand Down Expand Up @@ -1389,7 +1389,7 @@ public void displayDryRunResults(Map<String, DryRunStatus> fileStatusMap) {
LOGGER.error(sb.toString());
}

private void processUserDefinedTemplates() {
void processUserDefinedTemplates() {
// TODO: initial behavior is "merge" user defined with built-in templates. consider offering user a "replace" option.
if (userDefinedTemplates != null && !userDefinedTemplates.isEmpty()) {
Map<String, SupportingFile> supportingFilesMap = config.supportingFiles().stream()
Expand Down Expand Up @@ -1993,7 +1993,7 @@ private Path absPath(File input) {
*
* @param files The list tracking generated files
*/
private void generateFilesMetadata(List<File> files) {
void generateFilesMetadata(List<File> files) {
if (generateMetadata) {
try {
StringBuilder sb = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class CodegenConfigurator {

private String generatorName;
private String inputSpec;
private List<String> additionalSpecFiles = new ArrayList<>();
private String templatingEngineName;
private Map<String, String> globalProperties = new HashMap<>();
private Map<String, String> instantiationTypes = new HashMap<>();
Expand Down Expand Up @@ -494,6 +495,12 @@ public CodegenConfigurator setInputSpec(String inputSpec) {
return this;
}

public CodegenConfigurator setAdditionalSpecFiles(List<String> additionalSpecFiles) {
this.additionalSpecFiles = additionalSpecFiles;
workflowSettingsBuilder.withAdditionalSpecFiles(additionalSpecFiles);
return this;
}

public CodegenConfigurator setInstantiationTypes(Map<String, String> instantiationTypes) {
this.instantiationTypes = instantiationTypes;
generatorSettingsBuilder.withInstantiationTypes(instantiationTypes);
Expand Down Expand Up @@ -639,7 +646,7 @@ public CodegenConfigurator setVerbose(boolean verbose) {
}

@SuppressWarnings("WeakerAccess")
public Context<?> toContext() {
public Context<OpenAPI> toContext() {
Validate.notEmpty(generatorName, "generator name must be specified");
Validate.notEmpty(inputSpec, "input spec must be specified");

Expand Down Expand Up @@ -693,6 +700,13 @@ public Context<?> toContext() {
// https://github.com/swagger-api/swagger-parser/pull/1374
//ModelUtils.getOpenApiVersion(specification, inputSpec, authorizationValues);

final List<OpenAPI> additionalSpecifications = new ArrayList<>();
for (final String additionalSpecFile : additionalSpecFiles) {
final SwaggerParseResult additionalResult = new OpenAPIParser().readLocation(additionalSpecFile, authorizationValues, options);
validationMessages.addAll(additionalResult.getMessages());
additionalSpecifications.add(additionalResult.getOpenAPI());
}

// NOTE: We will only expose errors+warnings if there are already errors in the spec.
if (validationMessages.size() > 0) {
Set<String> warnings = new HashSet<>();
Expand All @@ -711,6 +725,22 @@ public Context<?> toContext() {
}
}

int i = 0;
for (final OpenAPI additionalSpecification : additionalSpecifications) {
// Wrap the getUnusedSchemas() in try catch block so it catches the NPE
// when the input spec file is not correct
try {
List<String> unusedModels = ModelUtils.getUnusedSchemas(additionalSpecification);
if (unusedModels != null) {
unusedModels.forEach(name -> warnings.add("Unused model: " + name));
}
} catch (Exception e){
System.err.println("[error] There is an error with OpenAPI specification parsed from the input spec file: " + additionalSpecFiles.get(i));
System.err.println("[error] Please make sure the spec file has correct format and all required fields are populated with valid value.");
}
i++;
}

if (workflowSettings.isValidateSpec()) {
String sb = "There were issues with the specification. The option can be disabled via validateSpec (Maven/Gradle) or --skip-validate-spec (CLI)." +
System.lineSeparator();
Expand All @@ -737,11 +767,11 @@ public Context<?> toContext() {
}
}

return new Context<>(specification, generatorSettings, workflowSettings);
return new Context<>(specification, additionalSpecifications, generatorSettings, workflowSettings);
}

public ClientOptInput toClientOptInput() {
Context<?> context = toContext();
Context<OpenAPI> context = toContext();
WorkflowSettings workflowSettings = context.getWorkflowSettings();
GeneratorSettings generatorSettings = context.getGeneratorSettings();

Expand All @@ -755,6 +785,7 @@ public ClientOptInput toClientOptInput() {

// TODO: Work toward CodegenConfig having a "WorkflowSettings" property, or better a "Workflow" object which itself has a "WorkflowSettings" property.
config.setInputSpec(workflowSettings.getInputSpec());
config.setAdditionalSpecFiles(workflowSettings.getAdditionalSpecFiles());
config.setOutputDir(workflowSettings.getOutputDir());
config.setSkipOverwrite(workflowSettings.isSkipOverwrite());
config.setIgnoreFilePathOverride(workflowSettings.getIgnoreFileOverride());
Expand Down Expand Up @@ -808,6 +839,8 @@ public ClientOptInput toClientOptInput() {
.generatorSettings(generatorSettings)
.userDefinedTemplates(userDefinedTemplates);

input.additionalSpecs(context.getAdditionalSpecDocuments());

return input.openAPI((OpenAPI)context.getSpecDocument());
}
}

0 comments on commit 968af58

Please sign in to comment.