diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4fba065..83eb33b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,6 +27,16 @@ env: GO_VERSION: 1.19.2 jobs: + rpc-check: + name: RPC check + runs-on: ubuntu-latest + steps: + - name: git checkout + uses: actions/checkout@v3 + + - name: Generate RPC stubs and check REST annotations + run: make rpc-check + ######################## # lint code ######################## diff --git a/Makefile b/Makefile index 29c7171..866b488 100644 --- a/Makefile +++ b/Makefile @@ -111,6 +111,19 @@ list: grep -v Makefile | \ sort +rpc: + @$(call print, "Compiling protos.") + cd ./pricesrpc; ./gen_protos_docker.sh + +rpc-format: + @$(call print, "Formatting protos.") + cd ./pricesrpc; find . -name "*.proto" | xargs clang-format --style=file -i + +rpc-check: rpc + @$(call print, "Verifying protos.") + cd ./pricesrpc; ../scripts/check-rest-annotations.sh + if test -n "$$(git status --porcelain)"; then echo "Protos not properly formatted or not compiled with correct version"; git status; git diff; exit 1; fi + clean: @$(call print, "Cleaning source.$(NC)") $(RM) ./aperture diff --git a/pricesrpc/Dockerfile b/pricesrpc/Dockerfile new file mode 100644 index 0000000..a66de08 --- /dev/null +++ b/pricesrpc/Dockerfile @@ -0,0 +1,32 @@ +FROM golang:1.20.4-buster + +RUN apt-get update && apt-get install -y \ + git \ + protobuf-compiler='3.6.1*' \ + clang-format='1:7.0*' + +# We don't want any default values for these variables to make sure they're +# explicitly provided by parsing the go.mod file. Otherwise we might forget to +# update them here if we bump the versions. +ARG PROTOBUF_VERSION +ARG GRPC_GATEWAY_VERSION + +ENV PROTOC_GEN_GO_GRPC_VERSION="v1.1.0" +ENV FALAFEL_VERSION="v0.9.1" +ENV GOCACHE=/tmp/build/.cache +ENV GOMODCACHE=/tmp/build/.modcache + +RUN cd /tmp \ + && mkdir -p /tmp/build/.cache \ + && mkdir -p /tmp/build/.modcache \ + && go install google.golang.org/protobuf/cmd/protoc-gen-go@${PROTOBUF_VERSION} \ + && go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@${PROTOC_GEN_GO_GRPC_VERSION} \ + && go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@${GRPC_GATEWAY_VERSION} \ + && go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@${GRPC_GATEWAY_VERSION} \ + && go install github.com/lightninglabs/falafel@${FALAFEL_VERSION} \ + && go install golang.org/x/tools/cmd/goimports@v0.1.7 \ + && chmod -R 777 /tmp/build/ + +WORKDIR /build + +CMD ["/bin/bash", "/build/pricesrpc/gen_protos.sh"] diff --git a/pricesrpc/gen_protos.sh b/pricesrpc/gen_protos.sh new file mode 100755 index 0000000..ff71894 --- /dev/null +++ b/pricesrpc/gen_protos.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +set -e + +# generate compiles the *.pb.go stubs from the *.proto files. +function generate() { + echo "Generating root gRPC server protos" + + PROTOS="rpc.proto" + + # For each of the sub-servers, we then generate their protos, but a restricted + # set as they don't yet require REST proxies, or swagger docs. + for file in $PROTOS; do + DIRECTORY=$(dirname "${file}") + echo "Generating protos from ${file}, into ${DIRECTORY}" + + # Generate the protos. + protoc -I/usr/local/include -I. \ + --go_out . --go_opt paths=source_relative \ + --go-grpc_out . --go-grpc_opt paths=source_relative \ + "${file}" + + # Generate the REST reverse proxy. + annotationsFile=${file//proto/yaml} + protoc -I/usr/local/include -I. \ + --grpc-gateway_out . \ + --grpc-gateway_opt logtostderr=true \ + --grpc-gateway_opt paths=source_relative \ + --grpc-gateway_opt grpc_api_configuration=${annotationsFile} \ + "${file}" + + # Generate the swagger file which describes the REST API in detail. + protoc -I/usr/local/include -I. \ + --openapiv2_out . \ + --openapiv2_opt logtostderr=true \ + --openapiv2_opt grpc_api_configuration=${annotationsFile} \ + --openapiv2_opt json_names_for_fields=false \ + "${file}" + done + + # Generate the JSON/WASM client stubs. + falafel=$(which falafel) + pkg="pricesrpc" + opts="package_name=$pkg,js_stubs=1,build_tags=// +build js" + protoc -I/usr/local/include -I. -I.. \ + --plugin=protoc-gen-custom=$falafel\ + --custom_out=. \ + --custom_opt="$opts" \ + rpc.proto + + PACKAGES="" + for package in $PACKAGES; do + + opts="package_name=$package,manual_import=$manual_import,js_stubs=1,build_tags=// +build js" + pushd $package + protoc -I/usr/local/include -I. -I.. \ + --plugin=protoc-gen-custom=$falafel\ + --custom_out=. \ + --custom_opt="$opts" \ + "$(find . -name '*.proto')" + popd + done +} + +# format formats the *.proto files with the clang-format utility. +function format() { + find . -name "*.proto" -print0 | xargs -0 clang-format --style=file -i +} + +# Compile and format the pricesrpc package. +pushd pricesrpc +format +generate +popd + +if [[ "$COMPILE_MOBILE" == "1" ]]; then + pushd mobile + ./gen_bindings.sh $FALAFEL_VERSION + popd +fi diff --git a/pricesrpc/gen_protos_docker.sh b/pricesrpc/gen_protos_docker.sh new file mode 100755 index 0000000..e6a43ab --- /dev/null +++ b/pricesrpc/gen_protos_docker.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +# Directory of the script file, independent of where it's called from. +DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" + +PROTOBUF_VERSION=$(go list -f '{{.Version}}' -m google.golang.org/protobuf) +GRPC_GATEWAY_VERSION=$(go list -f '{{.Version}}' -m github.com/grpc-ecosystem/grpc-gateway/v2) + +echo "Building protobuf compiler docker image..." +docker build -t aperture-protobuf-builder \ + --build-arg PROTOBUF_VERSION="$PROTOBUF_VERSION" \ + --build-arg GRPC_GATEWAY_VERSION="$GRPC_GATEWAY_VERSION" \ + . + +echo "Compiling and formatting *.proto files..." +docker run \ + --rm \ + --user "$UID:$(id -g)" \ + -e UID=$UID \ + -e COMPILE_MOBILE \ + -e SUBSERVER_PREFIX \ + -v "$DIR/../:/build" \ + aperture-protobuf-builder