Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tooling: generate JSON schemas from protobuf definitions #27640

Merged
merged 23 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
288cfa8
WIP: generate jsonschemas from proto files using bazelified protoc-ge…
norbjd May 25, 2023
3a3eb59
Remove unused load directive
norbjd May 25, 2023
354db8c
Fix: precheck format
norbjd May 25, 2023
f91eefe
Move dependencies to bazel/repository_locations.bzl
norbjd May 26, 2023
a408678
Move dependencies to api/bazel/repository_locations.bzl
norbjd May 26, 2023
6a55133
Extract code in generate.bzl
norbjd May 27, 2023
536b9c2
Replace hardcoded list of protos with a generated file using genquery…
norbjd May 27, 2023
8f93ad2
WIP: try to use aspects, inspired by protoxform
norbjd May 27, 2023
7094542
Merge branch 'main' into generate-json-schemas-from-proto
norbjd Jun 3, 2023
67cdb0c
Make changes to get the same behavior than before merging main
norbjd Jun 3, 2023
6cdafe8
Fix precheck format
norbjd Jun 10, 2023
861906c
Only generate JSON schemas for bootstrap protos (v2 + v3)
norbjd Jun 10, 2023
0e58608
Remove unused load directives
norbjd Jun 10, 2023
24c14fc
Fix aspect to generate schemas
norbjd Jun 10, 2023
90c647a
Simplify aspect code
norbjd Jun 10, 2023
2644bc9
Reuse api_proto_plugin_aspect
norbjd Jun 10, 2023
b98fd5c
Change api_proto_plugin_impl to be able to reuse it in protojsonschema
norbjd Jun 10, 2023
deee3b1
Simplify _protojsonschema_rule_impl (simplification could be controve…
norbjd Jun 10, 2023
8d0b58c
Clarify _protojsonschema_impl parameters
norbjd Jun 10, 2023
963ae65
Remove plugin options for //tools/protojsonschema
norbjd Jun 10, 2023
6eacd2c
Merge branch 'main' into generate-json-schemas-from-proto
norbjd Jun 10, 2023
f98bc62
Format
norbjd Jun 10, 2023
335eddb
Merge branch 'main' into generate-json-schemas-from-proto
norbjd Oct 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def api_dependencies():
external_http_archive(
name = "com_github_chrusty_protoc_gen_jsonschema",
)
external_http_archive(
name = "rules_proto_grpc",
)

external_http_archive(
name = "envoy_toolshed",
Expand Down
11 changes: 11 additions & 0 deletions api/bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@ REPOSITORY_LOCATIONS_SPEC = dict(
use_category = ["build"],
release_date = "2023-05-30",
),
rules_proto_grpc = dict(
project_name = "rules_proto_grpc",
project_desc = "Bazel rules for building Protobuf and gRPC code and libraries from proto_library targets ",
project_url = "https://github.com/rules-proto-grpc/rules_proto_grpc",
version = "4.4.0",
sha256 = "928e4205f701b7798ce32f3d2171c1918b363e9a600390a25c876f075f1efc0a",
strip_prefix = "rules_proto_grpc-{version}",
urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/{version}/rules_proto_grpc-{version}.tar.gz"],
use_category = ["build"],
release_date = "2023-05-03",
),
envoy_toolshed = dict(
project_name = "envoy_toolshed",
project_desc = "Tooling, libraries, runners and checkers for Envoy proxy's CI",
Expand Down
2 changes: 2 additions & 0 deletions bazel/dependency_imports.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ load("@com_github_aignas_rules_shellcheck//:deps.bzl", "shellcheck_dependencies"
load("@aspect_bazel_lib//lib:repositories.bzl", "register_jq_toolchains", "register_yq_toolchains")
load("@com_google_cel_cpp//bazel:deps.bzl", "parser_deps")
load("@com_github_chrusty_protoc_gen_jsonschema//:deps.bzl", protoc_gen_jsonschema_go_dependencies = "go_dependencies")
load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains")

# go version for rules_go
GO_VERSION = "1.18"
Expand Down Expand Up @@ -148,6 +149,7 @@ def envoy_dependency_imports(go_version = GO_VERSION, jq_version = JQ_VERSION, y
)

protoc_gen_jsonschema_go_dependencies()
rules_proto_grpc_toolchains()

def envoy_download_go_sdks(go_version):
go_download_sdk(
Expand Down
24 changes: 16 additions & 8 deletions tools/api_proto_plugin/plugin.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def _path_ignoring_repository(f):
def _input_arg(i):
return "%s=%s" % (i.basename, i.path)

def api_proto_plugin_impl(target, ctx, output_group, mnemonic, output_suffixes):
def api_proto_plugin_impl(target, ctx, output_group, mnemonic, output_suffixes, output_dir = ""):
# Compute output files from the current proto_library node's dependencies.
transitive_outputs = depset(transitive = [dep.output_groups[output_group] for dep in ctx.rule.attr.deps])

Expand Down Expand Up @@ -53,18 +53,26 @@ def api_proto_plugin_impl(target, ctx, output_group, mnemonic, output_suffixes):
for f in target[ProtoInfo].transitive_sources.to_list():
import_paths.append("{}={}".format(_path_ignoring_repository(f), f.path))

# The outputs live in the ctx.label's package root. We add some additional
# path information to match with protoc's notion of path relative locations.
outputs = []
for output_suffix in output_suffixes:
outputs += [ctx.actions.declare_file(ctx.label.name + "/" + _path_ignoring_repository(f) +
output_suffix) for f in proto_sources]
output_path = ""

if output_suffixes:
# The outputs live in the ctx.label's package root. We add some additional
# path information to match with protoc's notion of path relative locations.
outputs = []
for output_suffix in output_suffixes:
outputs += [ctx.actions.declare_file(ctx.label.name + "/" + _path_ignoring_repository(f) +
output_suffix) for f in proto_sources]

ctx_path = ctx.label.package + "/" + ctx.label.name
output_path = outputs[0].root.path + "/" + outputs[0].owner.workspace_root + "/" + ctx_path
elif output_dir:
outputs.append(ctx.actions.declare_directory(output_dir))
output_path = outputs[0].path

# Create the protoc command-line args.
inputs = [target[ProtoInfo].transitive_sources]

ctx_path = ctx.label.package + "/" + ctx.label.name
output_path = outputs[0].root.path + "/" + outputs[0].owner.workspace_root + "/" + ctx_path
args = ctx.actions.args()
args.add(ctx.label.workspace_root, format = "-I./%s")
args.add_all(import_paths, format_each = "-I%s")
Expand Down
22 changes: 22 additions & 0 deletions tools/protojsonschema/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
load("@rules_proto_grpc//:defs.bzl", "proto_plugin")
load(":generate.bzl", "jsonschema_compile")

licenses(["notice"]) # Apache 2

proto_plugin(
name = "protoc_gen_jsonschema_proto_plugin",
output_directory = True,
tool = "@com_github_chrusty_protoc_gen_jsonschema//cmd/protoc-gen-jsonschema",
)

[
jsonschema_compile(
# example: "@envoy_api//envoy/config/bootstrap/v3:pkg" => "envoy_config_bootstrap_v3"
name = proto.replace("@envoy_api//", "").replace("/", "_").replace(":pkg", ""),
protos = [proto],
)
for proto in [
"@envoy_api//envoy/config/bootstrap/v2:pkg",
"@envoy_api//envoy/config/bootstrap/v3:pkg",
]
]
22 changes: 22 additions & 0 deletions tools/protojsonschema/generate.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
load(
"@rules_proto_grpc//:defs.bzl",
"ProtoPluginInfo",
"proto_compile_attrs",
"proto_compile_impl",
)

# Create compile rule
jsonschema_compile = rule(
implementation = proto_compile_impl,
attrs = dict(
proto_compile_attrs,
_plugins = attr.label_list(
providers = [ProtoPluginInfo],
default = [
Label(":protoc_gen_jsonschema_proto_plugin"),
],
doc = "List of protoc plugins to apply",
),
),
toolchains = [str(Label("@rules_proto_grpc//protobuf:toolchain_type"))],
)
12 changes: 12 additions & 0 deletions tools/protojsonschema_with_aspects/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
load("//tools/protojsonschema_with_aspects:protojsonschema.bzl", "protojsonschema_rule")

licenses(["notice"]) # Apache 2

protojsonschema_rule(
name = "api_protojsonschema",
visibility = ["//visibility:public"],
deps = [
"@envoy_api//envoy/config/bootstrap/v2:pkg",
"@envoy_api//envoy/config/bootstrap/v3:pkg",
],
)
39 changes: 39 additions & 0 deletions tools/protojsonschema_with_aspects/protojsonschema.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
load("//tools/api_proto_plugin:plugin.bzl", "api_proto_plugin_aspect", "api_proto_plugin_impl")

def _protojsonschema_impl(target, ctx):
return api_proto_plugin_impl(
target = target,
ctx = ctx,
output_group = "proto",
mnemonic = "protojsonschema",
output_suffixes = [],
output_dir = "jsonschema",
)

protojsonschema_aspect = api_proto_plugin_aspect(
"@com_github_chrusty_protoc_gen_jsonschema//cmd/protoc-gen-jsonschema",
_protojsonschema_impl,
)

def _protojsonschema_rule_impl(ctx):
return [
DefaultInfo(
files = depset(
transitive = [
depset([
path
for dep in ctx.attr.deps
for path in dep[OutputGroupInfo].proto.to_list()
]),
],
),
),
]

protojsonschema_rule = rule(
implementation = _protojsonschema_rule_impl,
attrs = {
"deps": attr.label_list(aspects = [protojsonschema_aspect]),
},
)