build/proto_docs: add proto documentation generator
This adds an HTML documentation generator for our Protobuf files.
It consists of a new Bazel rule `proto_docs` which wraps protoc-gen-doc.
protoc-gen-doc itself and go-proto-validator which it includes need
some light patching because of dumbness in the Go Proto ecosystem that
doesn't exist in our Bazel build.
This just hooks up everything, it does not yet do anything custom like
annotating our own authorization metadata or similar.
Change-Id: If6fd7c777210fea700e49242b5339cfafe7c030d
Reviewed-on: https://review.monogon.dev/c/monogon/+/452
Reviewed-by: Leopold Schabel <leo@nexantic.com>
diff --git a/WORKSPACE b/WORKSPACE
index 8e83327..b27e651 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -53,6 +53,19 @@
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "go_repository")
+# Here to override the dep in rules_go with one with our patch
+http_archive(
+ name = "com_github_mwitkow_go_proto_validators",
+ patch_args = ["-p1"],
+ patches = ["//third_party/go/patches:go-proto-validators-default-alias.patch"],
+ sha256 = "d8697f05a2f0eaeb65261b480e1e6035301892d9fc07ed945622f41b12a68142",
+ strip_prefix = "go-proto-validators-0.3.2",
+ urls = [
+ "https://mirror.bazel.build/github.com/mwitkow/go-proto-validators/archive/v0.3.2.zip",
+ "https://github.com/mwitkow/go-proto-validators/archive/v0.3.2.zip",
+ ],
+)
+
go_rules_dependencies()
go_register_toolchains(
diff --git a/build/analysis/nogo_config.json b/build/analysis/nogo_config.json
index d2c824d..e7f1f04 100644
--- a/build/analysis/nogo_config.json
+++ b/build/analysis/nogo_config.json
@@ -14,7 +14,8 @@
"external/org_golang_google_protobuf/": "third_party",
"external/com_github_armon_go_metrics/": "third_party",
"external/com_github_elazarl_goproxy/": "third_party",
- "external/com_github_googleapis_gnostic/": "third_party"
+ "external/com_github_googleapis_gnostic/": "third_party",
+ "external/com_github_pseudomuto_protoc_gen_doc": "third_party"
}
},
"lostcancel": {
@@ -36,7 +37,8 @@
"external/com_github_shirou_gopsutil/": "unreachable",
"external/io_k8s_apimachinery/": "third_party",
"external/com_github_hpcloud_tail": "third_party",
- "external/com_github_flynn_go_shlex": "third_party"
+ "external/com_github_flynn_go_shlex": "third_party",
+ "external/com_github_masterminds_sprig": "third_party"
}
},
"assign": {
diff --git a/build/fietsje/deps_monogon.go b/build/fietsje/deps_monogon.go
index 0abcd66..a584f19 100644
--- a/build/fietsje/deps_monogon.go
+++ b/build/fietsje/deps_monogon.go
@@ -124,6 +124,18 @@
// Used by metroctl to resolve XDG directories
p.collect("github.com/adrg/xdg", "v0.4.0")
+ // Used for generating proto docs in //build/proto_docs
+ p.collect("github.com/pseudomuto/protoc-gen-doc", "v1.5.0", patches("protoc-gen-doc-no-gogo.patch")).use(
+ "github.com/Masterminds/sprig",
+ "github.com/Masterminds/semver",
+ "github.com/aokoli/goutils",
+ "github.com/huandu/xstrings",
+ ).with(
+ disabledProtoBuild,
+ ).use(
+ "github.com/pseudomuto/protokit",
+ )
+
// First generate the repositories starlark rule into memory. This is because
// rendering will lock all unlocked dependencies, which might take a while. If a
// use were to interrupt it now, they would end up with an incomplete
diff --git a/build/proto_docs/BUILD.bazel b/build/proto_docs/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/proto_docs/BUILD.bazel
diff --git a/build/proto_docs/proto_docs.bzl b/build/proto_docs/proto_docs.bzl
new file mode 100644
index 0000000..98661a2
--- /dev/null
+++ b/build/proto_docs/proto_docs.bzl
@@ -0,0 +1,66 @@
+load("@rules_proto//proto:defs.bzl", "ProtoInfo")
+
+def _proto_docs(ctx):
+ protos = [proto[ProtoInfo] for proto in ctx.attr.protos]
+ transitive_sources = depset(transitive = [proto.transitive_sources for proto in protos])
+ transitive_proto_path = depset(transitive = [proto.transitive_proto_path for proto in protos])
+
+ out = ctx.actions.declare_file(ctx.label.name + ".html")
+
+ args = []
+ args.append("--plugin")
+ args.append(ctx.executable._protoc_gen_doc.path)
+ args.append("--doc_out")
+ args.append(out.dirname)
+ args.append("--doc_opt=html," + out.basename)
+
+ for include_path in transitive_proto_path.to_list():
+ args.append("-I")
+ args.append(include_path)
+
+ for src in transitive_sources.to_list():
+ # Due to the built-in import path for well-known types (see AddDefaultProtoPaths
+ # in @com_google_protobuf//src/google/protobuf/compiler:command_line_interface.cc)
+ # in protoc the Bazel-generated well-known protos are considered to contain
+ # "duplicate" types.
+ # Since generating documentation for well-known types is not that useful just
+ # skip them.
+ if src.path.find("/bin/external/com_google_protobuf/_virtual_imports/") != -1:
+ continue
+ args.append(src.path)
+
+ ctx.actions.run(
+ tools = [ctx.executable._protoc_gen_doc],
+ inputs = transitive_sources,
+ outputs = [out],
+ executable = ctx.executable._protoc,
+ arguments = args,
+ )
+ return [DefaultInfo(files = depset([out]))]
+
+proto_docs = rule(
+ implementation = _proto_docs,
+ doc = """
+ Generate a single HTML documentation file documenting all types and services from the transitive set of
+ Protobuf files referenced by all proto_libraries passed into `protos`.
+ """,
+ attrs = {
+ "protos": attr.label_list(
+ doc = "A list of protobuf libraries for which (and their dependencies) documentation should be generated for",
+ providers = [ProtoInfo],
+ default = [],
+ ),
+ "_protoc": attr.label(
+ default = Label("@com_google_protobuf//:protoc"),
+ cfg = "exec",
+ executable = True,
+ allow_files = True,
+ ),
+ "_protoc_gen_doc": attr.label(
+ default = Label("@com_github_pseudomuto_protoc_gen_doc//cmd/protoc-gen-doc"),
+ cfg = "exec",
+ executable = True,
+ allow_files = True,
+ ),
+ },
+)
diff --git a/metropolis/proto/BUILD b/metropolis/proto/BUILD
new file mode 100644
index 0000000..45aa830
--- /dev/null
+++ b/metropolis/proto/BUILD
@@ -0,0 +1,9 @@
+load("//build/proto_docs:proto_docs.bzl", "proto_docs")
+
+proto_docs(
+ name = "docs",
+ protos = [
+ "//metropolis/proto/api:api_proto",
+ "//metropolis/proto/common:common_proto",
+ ],
+)
diff --git a/third_party/go/patches/go-proto-validators-default-alias.patch b/third_party/go/patches/go-proto-validators-default-alias.patch
new file mode 100644
index 0000000..46f21a9
--- /dev/null
+++ b/third_party/go/patches/go-proto-validators-default-alias.patch
@@ -0,0 +1,29 @@
+From 49b5f957d01cd50e5303cfc0e6c7f350d7e1c24e Mon Sep 17 00:00:00 2001
+From: Lorenz Brun <lorenz@monogon.tech>
+Date: Tue, 30 Nov 2021 03:19:37 +0100
+Subject: [PATCH] Alias go_default_library in BUILD to make Gazelle work
+
+---
+ BUILD.bazel | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/BUILD.bazel b/BUILD.bazel
+index 9a1edd4..e5b8f96 100644
+--- a/BUILD.bazel
++++ b/BUILD.bazel
+@@ -14,6 +14,12 @@ gazelle(
+ # By default resolve the top-level package to the gogo variant as it's required for the plugin compilation.
+ # gazelle:resolve go github.com/mwitkow/go-proto-validators //:validators_gogo
+
++alias(
++ name = "go_default_library",
++ actual = "validators_golang",
++ visibility = ["//visibility:public"],
++)
++
+ go_proto_compiler(
+ name = "go_proto_validators",
+ options = ["gogoimport=false"],
+--
+2.25.1
+
diff --git a/third_party/go/patches/protoc-gen-doc-no-gogo.patch b/third_party/go/patches/protoc-gen-doc-no-gogo.patch
new file mode 100644
index 0000000..8f2650e
--- /dev/null
+++ b/third_party/go/patches/protoc-gen-doc-no-gogo.patch
@@ -0,0 +1,46 @@
+From 3ec1e2168d64d880231c7bc3b022ac6e6ef342ad Mon Sep 17 00:00:00 2001
+From: Lorenz Brun <lorenz@monogon.tech>
+Date: Tue, 30 Nov 2021 03:40:11 +0100
+Subject: [PATCH] Remove gogo compatibility hack
+
+We build the whole thing with Bazel so the protobuf generated code uses
+the correct runtime support library by definition.
+---
+ extensions/validator_field/validator_field.go | 17 -----------------
+ 1 file changed, 17 deletions(-)
+
+diff --git a/extensions/validator_field/validator_field.go b/extensions/validator_field/validator_field.go
+index 224e414..0e2d8fb 100644
+--- a/extensions/validator_field/validator_field.go
++++ b/extensions/validator_field/validator_field.go
+@@ -5,27 +5,10 @@ import (
+ "reflect"
+ "strings"
+
+- "github.com/golang/protobuf/proto"
+- "github.com/golang/protobuf/protoc-gen-go/descriptor"
+ validator "github.com/mwitkow/go-proto-validators"
+ "github.com/pseudomuto/protoc-gen-doc/extensions"
+ )
+
+-func init() {
+- // NOTE: mwitkow/go-proto-validators uses gogo/profobuf/proto and therefore
+- // only registers the extension under gogo. We need to register it under
+- // golang/protobuf/proto with the same properties, except using the
+- // golang/protobuf FieldOptions descriptor.
+- proto.RegisterExtension(&proto.ExtensionDesc{
+- ExtendedType: (*descriptor.FieldOptions)(nil),
+- ExtensionType: validator.E_Field.ExtensionType,
+- Field: validator.E_Field.Field,
+- Name: validator.E_Field.Name,
+- Tag: validator.E_Field.Tag,
+- Filename: validator.E_Field.Filename,
+- })
+-}
+-
+ // ValidatorRule represents a single validator rule from the (validator.field) method option extension.
+ type ValidatorRule struct {
+ Name string `json:"name"`
+--
+2.25.1
+
diff --git a/third_party/go/repositories.bzl b/third_party/go/repositories.bzl
index ef9f9c8..23d425b 100644
--- a/third_party/go/repositories.bzl
+++ b/third_party/go/repositories.bzl
@@ -42,6 +42,26 @@
],
)
go_repository(
+ name = "com_github_masterminds_semver",
+ importpath = "github.com/Masterminds/semver",
+ version = "v1.4.2",
+ sum = "h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=",
+ build_extra_args = [
+ "-go_naming_convention=go_default_library",
+ "-go_naming_convention_external=go_default_library",
+ ],
+ )
+ go_repository(
+ name = "com_github_masterminds_sprig",
+ importpath = "github.com/Masterminds/sprig",
+ version = "v2.15.0+incompatible",
+ sum = "h1:0gSxPGWS9PAr7U2NsQ2YQg6juRDINkUyuvbb4b2Xm8w=",
+ build_extra_args = [
+ "-go_naming_convention=go_default_library",
+ "-go_naming_convention_external=go_default_library",
+ ],
+ )
+ go_repository(
name = "com_github_microsoft_go_winio",
importpath = "github.com/Microsoft/go-winio",
version = "v0.4.14",
@@ -113,6 +133,16 @@
],
)
go_repository(
+ name = "com_github_aokoli_goutils",
+ importpath = "github.com/aokoli/goutils",
+ version = "v1.0.1",
+ sum = "h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg=",
+ build_extra_args = [
+ "-go_naming_convention=go_default_library",
+ "-go_naming_convention_external=go_default_library",
+ ],
+ )
+ go_repository(
name = "com_github_armon_circbuf",
importpath = "github.com/armon/circbuf",
version = "v0.0.0-20150827004946-bbbad097214e",
@@ -1213,6 +1243,16 @@
],
)
go_repository(
+ name = "com_github_huandu_xstrings",
+ importpath = "github.com/huandu/xstrings",
+ version = "v1.0.0",
+ sum = "h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk=",
+ build_extra_args = [
+ "-go_naming_convention=go_default_library",
+ "-go_naming_convention_external=go_default_library",
+ ],
+ )
+ go_repository(
name = "com_github_imdario_mergo",
importpath = "github.com/imdario/mergo",
version = "v0.3.7",
@@ -1826,6 +1866,31 @@
],
)
go_repository(
+ name = "com_github_pseudomuto_protoc_gen_doc",
+ importpath = "github.com/pseudomuto/protoc-gen-doc",
+ version = "v1.5.0",
+ sum = "h1:pHZp0MEiT68jrZV8js8BS7E9ZEnlSLegoQbbtXj5lfo=",
+ patches = [
+ "//third_party/go/patches:protoc-gen-doc-no-gogo.patch",
+ ],
+ patch_args = ["-p1"],
+ build_extra_args = [
+ "-go_naming_convention=go_default_library",
+ "-go_naming_convention_external=go_default_library",
+ ],
+ )
+ go_repository(
+ name = "com_github_pseudomuto_protokit",
+ importpath = "github.com/pseudomuto/protokit",
+ version = "v0.2.0",
+ sum = "h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM=",
+ build_file_proto_mode = "disable",
+ build_extra_args = [
+ "-go_naming_convention=go_default_library",
+ "-go_naming_convention_external=go_default_library",
+ ],
+ )
+ go_repository(
name = "com_github_rekby_gpt",
importpath = "github.com/rekby/gpt",
version = "v0.0.0-20200219180433-a930afbc6edc",
diff --git a/third_party/go/shelf.pb.text b/third_party/go/shelf.pb.text
index a2f816b..dc199ab 100644
--- a/third_party/go/shelf.pb.text
+++ b/third_party/go/shelf.pb.text
@@ -41,6 +41,20 @@
semver: "v0.0.0-20170808103936-bb23615498cd"
>
entry: <
+ import_path: "github.com/Masterminds/semver"
+ version: "v1.4.2"
+ bazel_name: "com_github_masterminds_semver"
+ sum: "h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc="
+ semver: "v1.4.2"
+>
+entry: <
+ import_path: "github.com/Masterminds/sprig"
+ version: "v2.15.0+incompatible"
+ bazel_name: "com_github_masterminds_sprig"
+ sum: "h1:0gSxPGWS9PAr7U2NsQ2YQg6juRDINkUyuvbb4b2Xm8w="
+ semver: "v2.15.0+incompatible"
+>
+entry: <
import_path: "github.com/Microsoft/go-winio"
version: "6c72808b55902eae4c5943626030429ff20f3b63"
bazel_name: "com_github_microsoft_go_winio"
@@ -125,6 +139,13 @@
semver: "v0.0.0-20171022225611-72bdc8eae2ae"
>
entry: <
+ import_path: "github.com/aokoli/goutils"
+ version: "v1.0.1"
+ bazel_name: "com_github_aokoli_goutils"
+ sum: "h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg="
+ semver: "v1.0.1"
+>
+entry: <
import_path: "github.com/armon/circbuf"
version: "v0.0.0-20150827004946-bbbad097214e"
bazel_name: "com_github_armon_circbuf"
@@ -1700,6 +1721,13 @@
semver: "v1.0.0"
>
entry: <
+ import_path: "github.com/huandu/xstrings"
+ version: "v1.0.0"
+ bazel_name: "com_github_huandu_xstrings"
+ sum: "h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk="
+ semver: "v1.0.0"
+>
+entry: <
import_path: "github.com/imdario/mergo"
version: "7c29201646fa3de8506f701213473dd407f19646"
bazel_name: "com_github_imdario_mergo"
@@ -2246,6 +2274,13 @@
semver: "v0.0.0-20191010083416-a7dc8b61c822"
>
entry: <
+ import_path: "github.com/mwitkow/go-proto-validators"
+ version: "v0.0.0-20180403085117-0950a7990007"
+ bazel_name: "com_github_mwitkow_go_proto_validators"
+ sum: "h1:28i1IjGcx8AofiB4N3q5Yls55VEaitzuEPkFJEVgGkA="
+ semver: "v0.0.0-20180403085117-0950a7990007"
+>
+entry: <
import_path: "github.com/mxk/go-flowrate"
version: "v0.0.0-20140419014527-cca7078d478f"
bazel_name: "com_github_mxk_go_flowrate"
@@ -2582,6 +2617,20 @@
semver: "v0.6.0"
>
entry: <
+ import_path: "github.com/pseudomuto/protoc-gen-doc"
+ version: "v1.5.0"
+ bazel_name: "com_github_pseudomuto_protoc_gen_doc"
+ sum: "h1:pHZp0MEiT68jrZV8js8BS7E9ZEnlSLegoQbbtXj5lfo="
+ semver: "v1.5.0"
+>
+entry: <
+ import_path: "github.com/pseudomuto/protokit"
+ version: "v0.2.0"
+ bazel_name: "com_github_pseudomuto_protokit"
+ sum: "h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM="
+ semver: "v0.2.0"
+>
+entry: <
import_path: "github.com/rekby/gpt"
version: "a930afbc6edcc89c83d39b79e52025698156178d"
bazel_name: "com_github_rekby_gpt"