From dbdf4c8e3185daf6db2b370c1eb39820e750b719 Mon Sep 17 00:00:00 2001 From: mrmeku <mrmeku@gmail.com> Date: Fri, 26 Jul 2019 14:02:25 -0600 Subject: [PATCH] feat: Enable bazel generation --- .bazelrc | 0 .gitignore | 1 + BUILD.bazel | 9 ++ WORKSPACE | 5 + defs.bzl | 9 ++ .../openapi-generator-bazel/src/BUILD.bazel | 1 + modules/openapi-generator-bazel/src/defs.bzl | 147 ++++++++++++++++++ .../openapi-generator-bazel/src/test/BUILD | 41 +++++ .../src/test/petstore.yaml | 101 ++++++++++++ openapi/BUILD | 0 10 files changed, 314 insertions(+) create mode 100644 .bazelrc create mode 100644 BUILD.bazel create mode 100644 WORKSPACE create mode 100644 defs.bzl create mode 100644 modules/openapi-generator-bazel/src/BUILD.bazel create mode 100644 modules/openapi-generator-bazel/src/defs.bzl create mode 100644 modules/openapi-generator-bazel/src/test/BUILD create mode 100644 modules/openapi-generator-bazel/src/test/petstore.yaml create mode 100644 openapi/BUILD diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.gitignore b/.gitignore index 18d2a7a1027..f77f474fe58 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ modules/openapi-generator-gradle-plugin/bin/ .classpath lib/* build/* +bazel-* generated-files/* generated-sources/* generated-code/* diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 00000000000..8cfb7fb8a19 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,9 @@ +load( + "//modules/openapi-generator-bazel/src:defs.bzl", + _openapi_generator = "openapi_generator", + _openapi_generator_repositories = "openapi_generator_repositories", +) + +openapi_generator_repositories = _openapi_generator_repositories + +openapi_generator = _openapi_generator diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 00000000000..90b02304d1d --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,5 @@ +workspace(name = "io_bazel_rules_openapi_generator") + +load("//:defs.bzl", "openapi_generator_repositories") + +openapi_generator_repositories() diff --git a/defs.bzl b/defs.bzl new file mode 100644 index 00000000000..b95c342544b --- /dev/null +++ b/defs.bzl @@ -0,0 +1,9 @@ +load( + "//modules/openapi-generator-bazel/src:defs.bzl", + _openapi_generator = "openapi_generator", + _openapi_generator_repositories = "openapi_generator_repositories", +) + +openapi_generator = _openapi_generator + +openapi_generator_repositories = _openapi_generator_repositories diff --git a/modules/openapi-generator-bazel/src/BUILD.bazel b/modules/openapi-generator-bazel/src/BUILD.bazel new file mode 100644 index 00000000000..5a203b3ab13 --- /dev/null +++ b/modules/openapi-generator-bazel/src/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["defs.bzl"]) diff --git a/modules/openapi-generator-bazel/src/defs.bzl b/modules/openapi-generator-bazel/src/defs.bzl new file mode 100644 index 00000000000..b9368068b32 --- /dev/null +++ b/modules/openapi-generator-bazel/src/defs.bzl @@ -0,0 +1,147 @@ +def openapi_generator_repositories(openapi_generator_cli_version = "4.1.0", prefix = "io_bazel_rules_openapi_generator"): + native.maven_jar( + name = prefix + "_cli", + artifact = "org.openapitools:openapi-generator-cli:" + openapi_generator_cli_version, + ) + native.bind( + name = prefix + "/dependency/openapi-generator-cli", + actual = "@" + prefix + "_cli//jar", + ) + +def _comma_separated_pairs(pairs): + return ",".join([ + "{}={}".format(k, v) + for k, v in pairs.items() + ]) + +def _new_generator_command(ctx, declared_dir, rjars): + java_path = ctx.attr._jdk[java_common.JavaRuntimeInfo].java_executable_exec_path + gen_cmd = str(java_path) + + gen_cmd += " -cp {cli_jar}:{jars} org.openapitools.codegen.OpenAPIGenerator generate -i {spec} -g {generator} -o {output}".format( + java = java_path, + cli_jar = ctx.file.openapi_generator_cli.path, + jars = ":".join([j.path for j in rjars.to_list()]), + spec = ctx.file.spec.path, + generator = ctx.attr.generator, + output = declared_dir.path, + ) + + gen_cmd += ' -p "{properties}"'.format( + properties = _comma_separated_pairs(ctx.attr.system_properties), + ) + + additional_properties = dict(ctx.attr.additional_properties) + + # This is needed to ensure reproducible Java output + if ctx.attr.generator == "java" and \ + "hideGenerationTimestamp" not in ctx.attr.additional_properties: + additional_properties["hideGenerationTimestamp"] = "true" + + gen_cmd += ' --additional-properties "{properties}"'.format( + properties = _comma_separated_pairs(additional_properties), + ) + + gen_cmd += ' --type-mappings "{mappings}"'.format( + mappings = _comma_separated_pairs(ctx.attr.type_mappings), + ) + + if ctx.attr.api_package: + gen_cmd += " --api-package {package}".format( + package = ctx.attr.api_package, + ) + if ctx.attr.invoker_package: + gen_cmd += " --invoker-package {package}".format( + package = ctx.attr.invoker_package, + ) + if ctx.attr.model_package: + gen_cmd += " --model-package {package}".format( + package = ctx.attr.model_package, + ) + + # fixme: by default, openapi-generator is rather verbose. this helps with that but can also mask useful error messages + # when it fails. look into log configuration options. it's a java app so perhaps just a log4j.properties or something + gen_cmd += " 1>/dev/null" + return gen_cmd + +def _impl(ctx): + jars = _collect_jars(ctx.attr.deps) + (cjars, rjars) = (jars.compiletime, jars.runtime) + + declared_dir = ctx.actions.declare_directory("%s" % (ctx.attr.name)) + + inputs = [ + ctx.file.openapi_generator_cli, + ctx.file.spec, + ] + cjars.to_list() + rjars.to_list() + + # TODO: Convert to run + ctx.actions.run_shell( + inputs = inputs, + command = "mkdir -p {gen_dir}".format( + gen_dir = declared_dir.path, + ) + " && " + _new_generator_command(ctx, declared_dir, rjars), + outputs = [declared_dir], + tools = ctx.files._jdk, + ) + + srcs = declared_dir.path + + return DefaultInfo(files = depset([ + declared_dir, + ])) + +def _collect_jars(targets): + """Compute the runtime and compile-time dependencies from the given targets""" # noqa + compile_jars = depset() + runtime_jars = depset() + for target in targets: + found = False + if hasattr(target, "scala"): + if hasattr(target.scala.outputs, "ijar"): + compile_jars = depset(transitive = [compile_jars, [target.scala.outputs.ijar]]) + compile_jars = depset(transitive = [compile_jars, target.scala.transitive_compile_exports]) + runtime_jars = depset(transitive = [runtime_jars, target.scala.transitive_runtime_deps]) + runtime_jars = depset(transitive = [runtime_jars, target.scala.transitive_runtime_exports]) + found = True + if hasattr(target, "java"): + compile_jars = depset(transitive = [compile_jars, target.java.transitive_deps]) + runtime_jars = depset(transitive = [runtime_jars, target.java.transitive_runtime_deps]) + found = True + if not found: + runtime_jars = depset(transitive = [runtime_jars, target.files]) + compile_jars = depset(transitive = [compile_jars, target.files]) + + return struct(compiletime = compile_jars, runtime = runtime_jars) + +openapi_generator = rule( + attrs = { + # downstream dependencies + "deps": attr.label_list(), + # openapi spec file + "spec": attr.label( + mandatory = True, + allow_single_file = [ + ".json", + ".yaml", + ], + ), + "generator": attr.string(mandatory = True), + "api_package": attr.string(), + "invoker_package": attr.string(), + "model_package": attr.string(), + "additional_properties": attr.string_dict(), + "system_properties": attr.string_dict(), + "type_mappings": attr.string_dict(), + "_jdk": attr.label( + default = Label("@bazel_tools//tools/jdk:current_java_runtime"), + providers = [java_common.JavaRuntimeInfo], + ), + "openapi_generator_cli": attr.label( + cfg = "host", + default = Label("//external:io_bazel_rules_openapi_generator/dependency/openapi-generator-cli"), + allow_single_file = True, + ), + }, + implementation = _impl, +) diff --git a/modules/openapi-generator-bazel/src/test/BUILD b/modules/openapi-generator-bazel/src/test/BUILD new file mode 100644 index 00000000000..5fd5e818428 --- /dev/null +++ b/modules/openapi-generator-bazel/src/test/BUILD @@ -0,0 +1,41 @@ +load("//:defs.bzl", "openapi_generator") + +openapi_generator( + name = "petstore", + generator = "go", + spec = "petstore.yaml", +) + +openapi_generator( + name = "petstore_java", + generator = "java", + spec = "petstore.yaml", +) + +openapi_generator( + name = "petstore_java_feign", + additional_properties = { + "library": "feign", + }, + generator = "java", + spec = "petstore.yaml", +) + +openapi_generator( + name = "petstore_java_no_tests", + generator = "java", + spec = "petstore.yaml", + system_properties = { + "apiTests": "false", + "modelTests": "false", + }, +) + +openapi_generator( + name = "petstore_java_bigdecimal", + generator = "java", + spec = "petstore.yaml", + type_mappings = { + "Integer": "java.math.BigDecimal", + }, +) diff --git a/modules/openapi-generator-bazel/src/test/petstore.yaml b/modules/openapi-generator-bazel/src/test/petstore.yaml new file mode 100644 index 00000000000..790948cb93d --- /dev/null +++ b/modules/openapi-generator-bazel/src/test/petstore.yaml @@ -0,0 +1,101 @@ +swagger: "2.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +host: petstore.swagger.io +basePath: /v1 +schemes: + - http +consumes: + - application/json +produces: + - application/json +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + type: integer + format: int32 + responses: + "200": + description: An paged array of pets + headers: + x-next: + type: string + description: A link to the next page of responses + schema: + $ref: '#/definitions/Pets' + default: + description: unexpected error + schema: + $ref: '#/definitions/Error' + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + "201": + description: Null response + default: + description: unexpected error + schema: + $ref: '#/definitions/Error' + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + type: string + responses: + "200": + description: Expected response to a valid request + schema: + $ref: '#/definitions/Pets' + default: + description: unexpected error + schema: + $ref: '#/definitions/Error' +definitions: + Pet: + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + items: + $ref: '#/definitions/Pet' + Error: + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string diff --git a/openapi/BUILD b/openapi/BUILD new file mode 100644 index 00000000000..e69de29bb2d -- GitLab