diff --git a/bin/grpc-schema-petstore.sh b/bin/grpc-schema-petstore.sh new file mode 100755 index 00000000000..0de5086d8b8 --- /dev/null +++ b/bin/grpc-schema-petstore.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +SCRIPT="$0" +echo "# START SCRIPT: $SCRIPT" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn -B clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties $@" +ags="generate -t modules/openapi-generator/src/main/resources/grpc-schema -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g grpc-schema -o samples/config/petstore/grpc-schema --additional-properties packageName=petstore $@" + +java $JAVA_OPTS -jar $executable $ags diff --git a/bin/windows/grpc-schema-petstore.bat b/bin/windows/grpc-schema-petstore.bat new file mode 100755 index 00000000000..968632451ba --- /dev/null +++ b/bin/windows/grpc-schema-petstore.bat @@ -0,0 +1,10 @@ +set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M +set ags=generate -t modules\openapi-generator\src\main\resources\grpc-schema -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g grpc-schema -o samples\config\petstore\grpc-schema + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/docs/generators.md b/docs/generators.md index 7f26d8eb219..81653653bb2 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -132,6 +132,7 @@ The following generators are available: ## CONFIG generators * [apache2](generators/apache2) * [graphql-schema](generators/graphql-schema) +* [grpc-schema (beta)](generators/grpc-schema) diff --git a/docs/generators/grpc-schema.md b/docs/generators/grpc-schema.md new file mode 100644 index 00000000000..17a765fbbcf --- /dev/null +++ b/docs/generators/grpc-schema.md @@ -0,0 +1,9 @@ + +--- +id: generator-opts-config-grpc-schema +title: Config Options for grpc-schema +sidebar_label: grpc-schema +--- + +| Option | Description | Values | Default | +| ------ | ----------- | ------ | ------- | diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GrpcSchemaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GrpcSchemaCodegen.java new file mode 100644 index 00000000000..9e851d01a52 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GrpcSchemaCodegen.java @@ -0,0 +1,458 @@ +/* + * Copyright 2019 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * 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 org.openapitools.codegen.languages; + +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; + +import org.openapitools.codegen.CliOption; +import org.openapitools.codegen.CodegenConfig; +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.*; +import org.openapitools.codegen.meta.GeneratorMetadata; +import org.openapitools.codegen.meta.Stability; +import org.openapitools.codegen.utils.ProcessUtils; +import org.openapitools.codegen.utils.ModelUtils; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.*; +import java.util.regex.Pattern; + +import static org.openapitools.codegen.utils.StringUtils.camelize; +import static org.openapitools.codegen.utils.StringUtils.underscore; + +public class GrpcSchemaCodegen extends DefaultCodegen implements CodegenConfig { + + private static final Logger LOGGER = LoggerFactory.getLogger(GrpcSchemaCodegen.class); + + protected String packageName = "openapitools"; + + @Override + public CodegenType getTag() { + return CodegenType.CONFIG; + } + + public String getName() { + return "grpc-schema"; + } + + public String getHelp() { + return "Generates gRPC and Protbuf schema files (beta)"; + } + + public GrpcSchemaCodegen() { + super(); + + generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata) + .stability(Stability.BETA) + .build(); + + outputFolder = "generated-code/grpc-schema"; + modelTemplateFiles.put("model.mustache", ".proto"); + apiTemplateFiles.put("api.mustache", ".proto"); + embeddedTemplateDir = templateDir = "grpc-schema"; + hideGenerationTimestamp = Boolean.TRUE; + modelPackage = "messages"; + apiPackage = "services"; + + /*setReservedWordsLowerCase( + Arrays.asList( + // data type + "nil", "string", "boolean", "number", "userdata", "thread", + "table", + + // reserved words: http://www.lua.org/manual/5.1/manual.html#2.1 + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "if", + "in", "local", "nil", "not", "or", + "repeat", "return", "then", "true", "until", "while" + ) + );*/ + + defaultIncludes = new HashSet( + Arrays.asList( + "map", + "array") + ); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "map", + "array", + "bool", + "bytes", + "string", + "int32", + "int64", + "uint32", + "uint64", + "sint32", + "sint64", + "fixed32", + "fixed64", + "sfixed32", + "sfixed64", + "float", + "double") + ); + + instantiationTypes.clear(); + instantiationTypes.put("array", "repeat"); + //instantiationTypes.put("map", "map"); + + // ref: https://developers.google.com/protocol-buffers/docs/proto + typeMapping.clear(); + typeMapping.put("array", "array"); + typeMapping.put("map", "map"); + typeMapping.put("integer", "int32"); + typeMapping.put("long", "int64"); + typeMapping.put("number", "float"); + typeMapping.put("float", "float"); + typeMapping.put("double", "double"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "string"); + typeMapping.put("UUID", "string"); + typeMapping.put("URI", "string"); + typeMapping.put("date", "string"); + typeMapping.put("DateTime", "string"); + typeMapping.put("password", "string"); + // TODO fix file mapping + typeMapping.put("file", "string"); + typeMapping.put("binary", "string"); + typeMapping.put("ByteArray", "bytes"); + typeMapping.put("object", "TODO_OBJECT_MAPPING"); + + importMapping.clear(); + /* + importMapping = new HashMap(); + importMapping.put("time.Time", "time"); + importMapping.put("*os.File", "os"); + importMapping.put("os", "io/ioutil"); + */ + + modelDocTemplateFiles.put("model_doc.mustache", ".md"); + apiDocTemplateFiles.put("api_doc.mustache", ".md"); + + cliOptions.clear(); + /*cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "GraphQL package name (convention: lowercase).") + .defaultValue("openapi2graphql")); + cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION, "GraphQL package version.") + .defaultValue("1.0.0")); + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC) + .defaultValue(Boolean.TRUE.toString()));*/ + + } + + @Override + public void processOpts() { + super.processOpts(); + + //apiTestTemplateFiles.put("api_test.mustache", ".proto"); + //modelTestTemplateFiles.put("model_test.mustache", ".proto"); + + apiDocTemplateFiles.clear(); // TODO: add api doc template + modelDocTemplateFiles.clear(); // TODO: add model doc template + + modelPackage = "models"; + apiPackage = "services"; + + if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) { + setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME)); + } + + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + //supportingFiles.add(new SupportingFile("root.mustache", "", packageName + ".proto")); + //supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + //supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")) + //supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml")); + } + + @Override + public String toOperationId(String operationId) { + // throw exception if method name is empty (should not occur as an auto-generated method name will be used) + if (StringUtils.isEmpty(operationId)) { + throw new RuntimeException("Empty method name (operationId) not allowed"); + } + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId))); + operationId = "call_" + operationId; + } + + return camelize(sanitizeName(operationId)); + } + + @Override + public Map postProcessModels(Map objs) { + objs = postProcessModelsEnum(objs); + List models = (List) objs.get("models"); + // add x-index to properties + ProcessUtils.addIndexToProperties(models, 1); + + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + + for (CodegenProperty var : cm.vars) { + // add x-protobuf-type: repeated if it's an array + if (Boolean.TRUE.equals(var.isListContainer)) { + var.vendorExtensions.put("x-protobuf-type", "repeated"); + } + + // add x-protobuf-data-type + // ref: https://developers.google.com/protocol-buffers/docs/proto3 + if (!var.vendorExtensions.containsKey("x-protobuf-data-type")) { + if (var.isListContainer) { + var.vendorExtensions.put("x-protobuf-data-type", var.items.dataType); + } else { + var.vendorExtensions.put("x-protobuf-data-type", var.dataType); + } + } + + if (var.isEnum && var.allowableValues.containsKey("enumVars")) { + List> enumVars = (List>) var.allowableValues.get("enumVars"); + int enumIndex = 0; + for (Map enumVar : enumVars) { + enumVar.put("protobuf-enum-index", enumIndex); + enumIndex++; + } + } + } + } + return objs; + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input; + } + + @Override + public String escapeQuotationMark(String input) { + return input; + } + + /** + * Return the default value of the property + * + * @param p OpenAPI property object + * @return string presentation of the default value of the property + */ + @Override + public String toDefaultValue(Schema p) { + if (ModelUtils.isBooleanSchema(p)) { + if (p.getDefault() != null) { + if (Boolean.valueOf(p.getDefault().toString()) == false) + return "false"; + else + return "true"; + } + } else if (ModelUtils.isDateSchema(p)) { + // TODO + } else if (ModelUtils.isDateTimeSchema(p)) { + // TODO + } else if (ModelUtils.isNumberSchema(p)) { + if (p.getDefault() != null) { + return p.getDefault().toString(); + } + } else if (ModelUtils.isIntegerSchema(p)) { + if (p.getDefault() != null) { + return p.getDefault().toString(); + } + } else if (ModelUtils.isStringSchema(p)) { + if (p.getDefault() != null) { + if (Pattern.compile("\r\n|\r|\n").matcher((String) p.getDefault()).find()) + return "'''" + p.getDefault() + "'''"; + else + return "'" + p.getDefault() + "'"; + } + } else if (ModelUtils.isArraySchema(p)) { + if (p.getDefault() != null) { + return p.getDefault().toString(); + } + } + + return null; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separatorChar + apiPackage; + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separatorChar + modelPackage; + } + + @Override + public String toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // e.g. PhoneNumber => phone_number + return underscore(name) + "_service"; + } + + @Override + public String toApiName(String name) { + if (name.length() == 0) { + return "DefaultService"; + } + // e.g. phone_number => PhoneNumber + return camelize(name) + "Service"; + } + + @Override + public String toApiVarName(String name) { + if (name.length() == 0) { + return "default_service"; + } + return underscore(name) + "_service"; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + @Override + public String toModelFilename(String name) { + // underscore the model file name + // PhoneNumber => phone_number + return underscore(toModelName(name)); + } + + @Override + public String toModelName(String name) { + name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + // remove dollar sign + name = name.replaceAll("$", ""); + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name)); + name = "model_" + name; // e.g. return => ModelReturn (after camelize) + } + + // model name starts with number + if (name.matches("^\\d.*")) { + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name)); + name = "model_" + name; // e.g. 200Response => Model200Response (after camelize) + } + + if (!StringUtils.isEmpty(modelNamePrefix)) { + name = modelNamePrefix + "_" + name; + } + + if (!StringUtils.isEmpty(modelNameSuffix)) { + name = name + "_" + modelNameSuffix; + } + + // camelize the model name + // phone_number => PhoneNumber + return camelize(name); + } + + @Override + public String getSchemaType(Schema p) { + String schemaType = super.getSchemaType(p); + String type = null; + if (typeMapping.containsKey(schemaType)) { + type = typeMapping.get(schemaType); + if (languageSpecificPrimitives.contains(type)) { + return type; + } + } else { + type = toModelName(schemaType); + } + return type; + } + + @Override + public Map postProcessOperationsWithModels(Map objs, List allModels) { + Map operations = (Map) objs.get("operations"); + List operationList = (List) operations.get("operation"); + for (CodegenOperation op : operationList) { + int index = 1; + for (CodegenParameter p : op.allParams) { + // add x-protobuf-type: repeated if it's an array + if (Boolean.TRUE.equals(p.isListContainer)) { + p.vendorExtensions.put("x-protobuf-type", "repeated"); + } else if (Boolean.TRUE.equals(p.isMapContainer)) { + LOGGER.warn("Map parameter (name: {}, operation ID: {}) not yet supported", p.paramName, op.operationId); + } + + // add x-protobuf-data-type + // ref: https://developers.google.com/protocol-buffers/docs/proto3 + if (!p.vendorExtensions.containsKey("x-protobuf-data-type")) { + if (Boolean.TRUE.equals(p.isListContainer)) { + p.vendorExtensions.put("x-protobuf-data-type", p.items.dataType); + } else { + p.vendorExtensions.put("x-protobuf-data-type", p.dataType); + } + } + + p.vendorExtensions.put("x-index", index); + index++; + } + + if (StringUtils.isEmpty(op.returnType)) { + op.vendorExtensions.put("x-grpc-response", "google.protobuf.Empty"); + } else { + if (Boolean.FALSE.equals(op.returnTypeIsPrimitive) && StringUtils.isEmpty(op.returnContainer)) { + op.vendorExtensions.put("x-grpc-response", op.returnType); + } else { + if ("map".equals(op.returnContainer)) { + LOGGER.warn("Map response (operation ID: {}) not yet supported", op.operationId); + op.vendorExtensions.put("x-grpc-response-type", op.returnBaseType); + } else if ("array".equals(op.returnContainer)) { + op.vendorExtensions.put("x-grpc-response-type", "repeated " + op.returnBaseType); + } else { // primitive type + op.vendorExtensions.put("x-grpc-response-type", op.returnBaseType); + } + } + } + } + + return objs; + } + + @Override + public String toModelImport(String name) { + return underscore(name); + } + + @Override + public String getTypeDeclaration(Schema p) { + if (ModelUtils.isArraySchema(p)) { + ArraySchema ap = (ArraySchema) p; + Schema inner = ap.getItems(); + return getSchemaType(p) + "[" + getTypeDeclaration(inner) + "]"; + } else if (ModelUtils.isMapSchema(p)) { + Schema inner = ModelUtils.getAdditionalProperties(p); + return getSchemaType(p) + "[str, " + getTypeDeclaration(inner) + "]"; + } + return super.getTypeDeclaration(p); + } +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index f6ca902864d..03ba27260bb 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -34,6 +34,7 @@ org.openapitools.codegen.languages.GoServerCodegen org.openapitools.codegen.languages.GoGinServerCodegen org.openapitools.codegen.languages.GraphQLSchemaCodegen org.openapitools.codegen.languages.GraphQLNodeJSExpressServerCodegen +org.openapitools.codegen.languages.GrpcSchemaCodegen org.openapitools.codegen.languages.GroovyClientCodegen org.openapitools.codegen.languages.KotlinClientCodegen org.openapitools.codegen.languages.KotlinServerCodegen diff --git a/modules/openapi-generator/src/main/resources/grpc-schema/README.mustache b/modules/openapi-generator/src/main/resources/grpc-schema/README.mustache new file mode 100644 index 00000000000..a516dff1de9 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/grpc-schema/README.mustache @@ -0,0 +1,39 @@ +# gPRC for {{packageName}} + +{{#appDescription}} +{{{appDescription}}} +{{/appDescription}} + +## Overview +These files were generated by the [OpenAPI Generator](https://openapi-generator.tech) project. + +- API version: {{appVersion}} +- Package version: {{packageVersion}} +{{^hideGenerationTimestamp}} +- Build date: {{generatedDate}} +{{/hideGenerationTimestamp}} +- Build package: {{generatorClass}} +{{#infoUrl}} +For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + +## Usage + +Below are some usage examples for Go and Ruby. For other languages, please refer to https://grpc.io/docs/quickstart/. + +### Go +``` +# assuming `protoc-gen-go` has been installed with `go get -u github.com/golang/protobuf/protoc-gen-go` +mkdir /var/tmp/go/{{{pacakgeName}}} +protoc --go_out=/var/tmp/go/{{{pacakgeName}}} services/* +protoc --go_out=/var/tmp/go/{{{pacakgeName}}} models/* +``` + +### Ruby +``` +# assuming `grpc_tools_ruby_protoc` has been installed via `gem install grpc-tools` +RUBY_OUTPUT_DIR="/var/tmp/ruby/{{{packageName}}}" +mkdir $RUBY_OUTPUT_DIR +grpc_tools_ruby_protoc --ruby_out=$RUBY_OUTPUT_DIR --grpc_out=$RUBY_OUTPUT_DIR/lib services/* +grpc_tools_ruby_protoc --ruby_out=$RUBY_OUTPUT_DIR --grpc_out=$RUBY_OUTPUT_DIR/lib models/* +``` diff --git a/modules/openapi-generator/src/main/resources/grpc-schema/api.mustache b/modules/openapi-generator/src/main/resources/grpc-schema/api.mustache new file mode 100644 index 00000000000..3236d010ccd --- /dev/null +++ b/modules/openapi-generator/src/main/resources/grpc-schema/api.mustache @@ -0,0 +1,46 @@ +{{>partial_header}} +syntax = "proto3"; + +package {{{packageName}}}; + +import "google/protobuf/empty.proto"; +{{#imports}} +{{#import}} +import public "{{{modelPackage}}}/{{{.}}}.proto"; +{{/import}} +{{/imports}} + +service {{classname}} { +{{#operations}} +{{#operation}} + {{#description}} + // {{{.}}} + {{/description}} + rpc {{operationId}} ({{#hasParams}}{{operationId}}Request{{/hasParams}}{{^hasParams}}google.protobuf.Empty{{/hasParams}}) returns ({{#vendorExtensions.x-grpc-response}}{{.}}{{/vendorExtensions.x-grpc-response}}{{^vendorExtensions.x-grpc-response}}{{operationId}}Response{{/vendorExtensions.x-grpc-response}}); + +{{/operation}} +{{/operations}} +} + +{{#operations}} +{{#operation}} +{{#hasParams}} +message {{operationId}}Request { + {{#allParams}} + {{#description}} + // {{{.}}} + {{/description}} + {{#vendorExtensions.x-protobuf-type}}{{.}} {{/vendorExtensions.x-protobuf-type}}{{vendorExtensions.x-protobuf-data-type}} {{paramName}} = {{vendorExtensions.x-index}}; + {{/allParams}} + +} + +{{/hasParams}} +{{^vendorExtensions.x-grpc-response}} +message {{operationId}}Response { + {{{vendorExtensions.x-grpc-response-type}}} data = 1; +} + +{{/vendorExtensions.x-grpc-response}} +{{/operation}} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/grpc-schema/git_push.sh.mustache b/modules/openapi-generator/src/main/resources/grpc-schema/git_push.sh.mustache new file mode 100755 index 00000000000..c344020eab5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/grpc-schema/git_push.sh.mustache @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 openapi-pestore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="{{{gitUserId}}}" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="{{{gitRepoId}}}" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="{{{releaseNote}}}" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/modules/openapi-generator/src/main/resources/grpc-schema/gitignore.mustache b/modules/openapi-generator/src/main/resources/grpc-schema/gitignore.mustache new file mode 100644 index 00000000000..180988936c5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/grpc-schema/gitignore.mustache @@ -0,0 +1,40 @@ +# Compiled Lua sources +luac.out + +# luarocks build files +*.src.rock +*.zip +*.tar.gz + +# Object files +*.o +*.os +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo +*.def +*.exp + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex diff --git a/modules/openapi-generator/src/main/resources/grpc-schema/model.mustache b/modules/openapi-generator/src/main/resources/grpc-schema/model.mustache new file mode 100644 index 00000000000..5362485d3a5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/grpc-schema/model.mustache @@ -0,0 +1,36 @@ +{{>partial_header}} +syntax = "proto3"; + +package {{{packageName}}}; + +{{#imports}} +{{#import}} +import public "{{{modelPackage}}}/{{{import}}}.proto"; +{{/import}} +{{/imports}} + +{{#models}} +{{#model}} +message {{classname}} { + + {{#vars}} + {{#description}} + // {{{.}}} + {{/description}} + {{^isEnum}} + {{#vendorExtensions.x-protobuf-type}}{{.}} {{/vendorExtensions.x-protobuf-type}}{{vendorExtensions.x-protobuf-data-type}} {{name}} = {{vendorExtensions.x-index}}{{#vendorExtensions.x-protobuf-packed}} [packed=true]{{/vendorExtensions.x-protobuf-packed}}; + {{/isEnum}} + {{#isEnum}} + enum {{name}} { + {{#allowableValues}} + {{#enumVars}} + {{{name}}} = {{{protobuf-enum-index}}}; + {{/enumVars}} + {{/allowableValues}} + } + {{/isEnum}} + + {{/vars}} +} +{{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/main/resources/grpc-schema/partial_header.mustache b/modules/openapi-generator/src/main/resources/grpc-schema/partial_header.mustache new file mode 100644 index 00000000000..0ade1e5273e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/grpc-schema/partial_header.mustache @@ -0,0 +1,13 @@ +/* + {{#appName}} + {{{appName}}} + + {{/appName}} + {{#appDescription}} + {{{appDescription}}} + + {{/appDescription}} + {{#version}}The version of the OpenAPI document: {{{version}}}{{/version}} + {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ diff --git a/modules/openapi-generator/src/main/resources/grpc-schema/root.mustache b/modules/openapi-generator/src/main/resources/grpc-schema/root.mustache new file mode 100644 index 00000000000..091a8513113 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/grpc-schema/root.mustache @@ -0,0 +1,22 @@ +{{>partial_header}} +syntax = "proto3"; + +package {{{packageName}}}; + +{{#vendorExtensions.x-grpc-options}} +option {{{.}}}; +{{/vendorExtensions.x-grpc-options}} + +// Models +{{#models}} +{{#model}} +import public "{{modelPackage}}/{{classFilename}}.proto"; +{{/model}} +{{/models}} + +// APIs +{{#apiInfo}} +{{#apis}} +import public "{{apiPackage}}/{{classFilename}}.proto"; +{{/apis}} +{{/apiInfo}} diff --git a/samples/config/petstore/grpc-schema/.openapi-generator-ignore b/samples/config/petstore/grpc-schema/.openapi-generator-ignore new file mode 100644 index 00000000000..7484ee590a3 --- /dev/null +++ b/samples/config/petstore/grpc-schema/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/config/petstore/grpc-schema/.openapi-generator/VERSION b/samples/config/petstore/grpc-schema/.openapi-generator/VERSION new file mode 100644 index 00000000000..d1a8f58b388 --- /dev/null +++ b/samples/config/petstore/grpc-schema/.openapi-generator/VERSION @@ -0,0 +1 @@ +4.1.2-SNAPSHOT \ No newline at end of file diff --git a/samples/config/petstore/grpc-schema/README.md b/samples/config/petstore/grpc-schema/README.md new file mode 100644 index 00000000000..bc5a26a836d --- /dev/null +++ b/samples/config/petstore/grpc-schema/README.md @@ -0,0 +1,31 @@ +# gPRC for petstore + +This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + +## Overview +These files were generated by the [OpenAPI Generator](https://openapi-generator.tech) project. + +- API version: 1.0.0 +- Package version: +- Build package: org.openapitools.codegen.languages.GrpcSchemaCodegen + +## Usage + +Below are some usage examples for Go and Ruby. For other languages, please refer to https://grpc.io/docs/quickstart/. + +### Go +``` +# assuming `protoc-gen-go` has been installed with `go get -u github.com/golang/protobuf/protoc-gen-go` +mkdir /var/tmp/go/ +protoc --go_out=/var/tmp/go/ services/* +protoc --go_out=/var/tmp/go/ models/* +``` + +### Ruby +``` +# assuming `grpc_tools_ruby_protoc` has been installed via `gem install grpc-tools` +RUBY_OUTPUT_DIR="/var/tmp/ruby/petstore" +mkdir $RUBY_OUTPUT_DIR +grpc_tools_ruby_protoc --ruby_out=$RUBY_OUTPUT_DIR --grpc_out=$RUBY_OUTPUT_DIR/lib services/* +grpc_tools_ruby_protoc --ruby_out=$RUBY_OUTPUT_DIR --grpc_out=$RUBY_OUTPUT_DIR/lib models/* +``` diff --git a/samples/config/petstore/grpc-schema/models/api_response.proto b/samples/config/petstore/grpc-schema/models/api_response.proto new file mode 100644 index 00000000000..bb08ca19e49 --- /dev/null +++ b/samples/config/petstore/grpc-schema/models/api_response.proto @@ -0,0 +1,24 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + + +message ApiResponse { + + int32 code = 1; + + string type = 2; + + string message = 3; + +} diff --git a/samples/config/petstore/grpc-schema/models/category.proto b/samples/config/petstore/grpc-schema/models/category.proto new file mode 100644 index 00000000000..474cf59efb1 --- /dev/null +++ b/samples/config/petstore/grpc-schema/models/category.proto @@ -0,0 +1,22 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + + +message Category { + + int64 id = 1; + + string name = 2; + +} diff --git a/samples/config/petstore/grpc-schema/models/order.proto b/samples/config/petstore/grpc-schema/models/order.proto new file mode 100644 index 00000000000..58f1458c63a --- /dev/null +++ b/samples/config/petstore/grpc-schema/models/order.proto @@ -0,0 +1,35 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + + +message Order { + + int64 id = 1; + + int64 petId = 2; + + int32 quantity = 3; + + string shipDate = 4; + + // Order Status + enum status { + PLACED = 0; + APPROVED = 1; + DELIVERED = 2; + } + + bool complete = 6; + +} diff --git a/samples/config/petstore/grpc-schema/models/pet.proto b/samples/config/petstore/grpc-schema/models/pet.proto new file mode 100644 index 00000000000..8cff62e9f5a --- /dev/null +++ b/samples/config/petstore/grpc-schema/models/pet.proto @@ -0,0 +1,37 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + +import public "models/category.proto"; +import public "models/tag.proto"; + +message Pet { + + int64 id = 1; + + Category category = 2; + + string name = 3; + + repeated string photoUrls = 4; + + repeated Tag tags = 5; + + // pet status in the store + enum status { + AVAILABLE = 0; + PENDING = 1; + SOLD = 2; + } + +} diff --git a/samples/config/petstore/grpc-schema/models/tag.proto b/samples/config/petstore/grpc-schema/models/tag.proto new file mode 100644 index 00000000000..f9a80eac541 --- /dev/null +++ b/samples/config/petstore/grpc-schema/models/tag.proto @@ -0,0 +1,22 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + + +message Tag { + + int64 id = 1; + + string name = 2; + +} diff --git a/samples/config/petstore/grpc-schema/models/user.proto b/samples/config/petstore/grpc-schema/models/user.proto new file mode 100644 index 00000000000..1a30b008131 --- /dev/null +++ b/samples/config/petstore/grpc-schema/models/user.proto @@ -0,0 +1,35 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + + +message User { + + int64 id = 1; + + string username = 2; + + string firstName = 3; + + string lastName = 4; + + string email = 5; + + string password = 6; + + string phone = 7; + + // User Status + int32 userStatus = 8; + +} diff --git a/samples/config/petstore/grpc-schema/services/pet_service.proto b/samples/config/petstore/grpc-schema/services/pet_service.proto new file mode 100644 index 00000000000..2b7ae553ad4 --- /dev/null +++ b/samples/config/petstore/grpc-schema/services/pet_service.proto @@ -0,0 +1,102 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + +import "google/protobuf/empty.proto"; +import public "models/api_response.proto"; +import public "models/pet.proto"; + +service PetService { + rpc AddPet (AddPetRequest) returns (google.protobuf.Empty); + + rpc DeletePet (DeletePetRequest) returns (google.protobuf.Empty); + + rpc FindPetsByStatus (FindPetsByStatusRequest) returns (FindPetsByStatusResponse); + + rpc FindPetsByTags (FindPetsByTagsRequest) returns (FindPetsByTagsResponse); + + rpc GetPetById (GetPetByIdRequest) returns (Pet); + + rpc UpdatePet (UpdatePetRequest) returns (google.protobuf.Empty); + + rpc UpdatePetWithForm (UpdatePetWithFormRequest) returns (google.protobuf.Empty); + + rpc UploadFile (UploadFileRequest) returns (ApiResponse); + +} + +message AddPetRequest { + // Pet object that needs to be added to the store + Pet body = 1; + +} + +message DeletePetRequest { + // Pet id to delete + int64 petId = 1; + string apiKey = 2; + +} + +message FindPetsByStatusRequest { + // Status values that need to be considered for filter + repeated string status = 1; + +} + +message FindPetsByStatusResponse { + repeated Pet data = 1; +} + +message FindPetsByTagsRequest { + // Tags to filter by + repeated string tags = 1; + +} + +message FindPetsByTagsResponse { + repeated Pet data = 1; +} + +message GetPetByIdRequest { + // ID of pet to return + int64 petId = 1; + +} + +message UpdatePetRequest { + // Pet object that needs to be added to the store + Pet body = 1; + +} + +message UpdatePetWithFormRequest { + // ID of pet that needs to be updated + int64 petId = 1; + // Updated name of the pet + string name = 2; + // Updated status of the pet + string status = 3; + +} + +message UploadFileRequest { + // ID of pet to update + int64 petId = 1; + // Additional data to pass to server + string additionalMetadata = 2; + // file to upload + string file = 3; + +} + diff --git a/samples/config/petstore/grpc-schema/services/store_service.proto b/samples/config/petstore/grpc-schema/services/store_service.proto new file mode 100644 index 00000000000..8adea52f754 --- /dev/null +++ b/samples/config/petstore/grpc-schema/services/store_service.proto @@ -0,0 +1,50 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + +import "google/protobuf/empty.proto"; +import public "models/order.proto"; + +service StoreService { + rpc DeleteOrder (DeleteOrderRequest) returns (google.protobuf.Empty); + + rpc GetInventory (google.protobuf.Empty) returns (GetInventoryResponse); + + rpc GetOrderById (GetOrderByIdRequest) returns (Order); + + rpc PlaceOrder (PlaceOrderRequest) returns (Order); + +} + +message DeleteOrderRequest { + // ID of the order that needs to be deleted + string orderId = 1; + +} + +message GetInventoryResponse { + int32 data = 1; +} + +message GetOrderByIdRequest { + // ID of pet that needs to be fetched + int64 orderId = 1; + +} + +message PlaceOrderRequest { + // order placed for purchasing the pet + Order body = 1; + +} + diff --git a/samples/config/petstore/grpc-schema/services/user_service.proto b/samples/config/petstore/grpc-schema/services/user_service.proto new file mode 100644 index 00000000000..8f3f762bd4c --- /dev/null +++ b/samples/config/petstore/grpc-schema/services/user_service.proto @@ -0,0 +1,86 @@ +/* + OpenAPI Petstore + + This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + + The version of the OpenAPI document: 1.0.0 + + Generated by OpenAPI Generator: https://openapi-generator.tech +*/ + +syntax = "proto3"; + +package petstore; + +import "google/protobuf/empty.proto"; +import public "models/user.proto"; + +service UserService { + rpc CreateUser (CreateUserRequest) returns (google.protobuf.Empty); + + rpc CreateUsersWithArrayInput (CreateUsersWithArrayInputRequest) returns (google.protobuf.Empty); + + rpc CreateUsersWithListInput (CreateUsersWithListInputRequest) returns (google.protobuf.Empty); + + rpc DeleteUser (DeleteUserRequest) returns (google.protobuf.Empty); + + rpc GetUserByName (GetUserByNameRequest) returns (User); + + rpc LoginUser (LoginUserRequest) returns (LoginUserResponse); + + rpc LogoutUser (google.protobuf.Empty) returns (google.protobuf.Empty); + + rpc UpdateUser (UpdateUserRequest) returns (google.protobuf.Empty); + +} + +message CreateUserRequest { + // Created user object + User body = 1; + +} + +message CreateUsersWithArrayInputRequest { + // List of user object + repeated User body = 1; + +} + +message CreateUsersWithListInputRequest { + // List of user object + repeated User body = 1; + +} + +message DeleteUserRequest { + // The name that needs to be deleted + string username = 1; + +} + +message GetUserByNameRequest { + // The name that needs to be fetched. Use user1 for testing. + string username = 1; + +} + +message LoginUserRequest { + // The user name for login + string username = 1; + // The password for login in clear text + string password = 2; + +} + +message LoginUserResponse { + string data = 1; +} + +message UpdateUserRequest { + // name that need to be deleted + string username = 1; + // Updated user object + User body = 2; + +} +