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

Cannot generate combined swagger from gateway_openapiv2_compile #382

Open
johngun3 opened this issue Nov 14, 2024 · 1 comment
Open

Cannot generate combined swagger from gateway_openapiv2_compile #382

johngun3 opened this issue Nov 14, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@johngun3
Copy link

Issue Description

It seems that it is not possible to generate a single, combined swagger.json file when using gateway_openapiv2_compile with multiple proto file inputs.

The openapiv2 protoc plugin has allow_merge=true and merge_file_name={name}.json options that allow for the creation of a single, combined swagger.json file. When attempting to use those options with gateway_openapiv2_compile the build fails because the expected outputs are not generated.

gateway_openapiv2_compile(
    name = "gen_swagger_merged",
    protos = [":a_proto", ":b_proto"],
    options = {
        "@rules_proto_grpc//grpc-gateway:openapiv2_plugin": [
            "allow_merge=true",
            "merge_file_name=merged_swagger.json",
        ]
    },
)

merged_swagger.json DOES get generated but the expected a.swagger.json and b.swagger.json are not generated which causes the build to fail. This is due to this block of code in modules/core/internal/compile.bzl that specifies the plugin_outputs without an option to override:

    for proto_info in proto_infos:
            for proto in proto_info.direct_sources:
                # Check for exclusion
                if any([
                    proto.dirname.endswith(exclusion) or proto.path.endswith(exclusion)
                    for exclusion in plugin.exclusions
                ]) or proto in protos:
                    # When using import_prefix, the ProtoInfo.direct_sources list appears to contain
                    # duplicate records, the final check 'proto in protos' removes these. See
                    # https://github.com/bazelbuild/bazel/issues/9127
                    continue

                # Proto not excluded
                protos.append(proto)

                # Add per-proto outputs
                for pattern in plugin.outputs:
                    plugin_outputs.append(ctx.actions.declare_file("{}/{}".format(
                        rel_premerge_root,
                        get_output_filename(proto, pattern, proto_info),
                    )))

                # Get proto path for protoc
                proto_paths.append(descriptor_proto_path(proto, proto_info))

As seen in this issue comment a possible remedy for this is to create a new plugin that sets output_directory=True instead of outputs = ["{protopath}.swagger.json"] which allows the build to succeed.

From reading over the code I'm not quite sure what the right remedy is. The fundamental issue with gateway_openapiv2_compile seems to be that options can be passed to protoc which change its outputs and the implementation of this rule does not support that functionality. I seems that perhaps outputs = ["{protopath}.swagger.json"] should not be hardcoded into the proto_plugin definition because it's not always the case that we want a separate swagger.json file per proto but again, I'm not sure how best to change the code to account for this case.

I think that I may go the route of defining my own, slightly modified proto_plugin and associated rule or perhaps just use a genrule to generate combined swagger the file that I want. I'm curious what others have done when they've encountered this problem.

If there's an obvious solution that I've missed or I've misread the code and it is indeed possible to generate a single, combined swagger file I'd love to know that as well. Cheers!

Log Output

No response

rules_proto_grpc Version

4.1.1, 5.0.0

Bazel Version

6.4.0

OS

Ubuntu

Link to Demo Repo

No response

MODULE.bazel or WORKSPACE Content

No response

BUILD Content

No response

Proto Content

No response

Any Other Content

No response

@johngun3 johngun3 added the bug Something isn't working label Nov 14, 2024
@johngun3
Copy link
Author

I was able to solve this by defining my own rule and proto_plugin:

load("@rules_proto_grpc//:defs.bzl", "proto_plugin")

proto_plugin(
    name = "openapiv2_plugin_custom",
    exclusions = [
        "google/api",
        "google/protobuf",
    ],
    output_directory = True,
    quirks = [
        "QUIRK_DIRECT_MODE",
    ],
    tool = "@grpc_ecosystem_grpc_gateway//protoc-gen-openapiv2",
    visibility = ["//visibility:public"],
)

The only different between the stock proto plugin and this one is that I swapped outputs for output_directory

And my rule definition:

load(
    "@rules_proto_grpc//:defs.bzl",
    "ProtoPluginInfo",
    "proto_compile_attrs",
    "proto_compile_impl",
)

gateway_openapiv2_compile_combined_swagger = rule(
    implementation = proto_compile_impl,
    attrs = dict(
        proto_compile_attrs,
        _plugins = attr.label_list(
            providers = [ProtoPluginInfo],
            default = [
                Label("//path/to/my/plugin:openapiv2_plugin_custom"),
            ],
            doc = "List of protoc plugins to apply",
        ),
    ),
    toolchains = [str(Label("@rules_proto_grpc//protobuf:toolchain_type"))],
)

I was able to use the rule like this:

gateway_openapiv2_compile_combined_swagger(
    name = "gateway_swagger",
    options = {
        # the leading @ is important so the Label function does not prepend @rules_proto_grpc to this string
        "@//path/to/my/plugin:openapiv2_plugin_custom": [
            "allow_merge=true",
            "merge_file_name=combined",
        ],
    },
    protos = [....],
)

I hope this helps anyone else that runs into this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant