Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
60 changes: 60 additions & 0 deletions .github/workflows/proto.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
on:
push:
paths:
- 'proto/**'
- '.github/workflows/proto.yml'
pull_request:
paths:
- 'proto/**'
- '.github/workflows/proto.yml'

name: Proto
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
proto:
runs-on: ubuntu-latest
env:
BUF_VERSION: 1.55.1
PROTOC_GEN_GO_VERSION: v1.36.11
PROTOC_GEN_GO_GRPC_VERSION: v1.6.1
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Fetch main for breaking baseline
if: github.ref != 'refs/heads/main'
run: git fetch --no-tags --prune origin +refs/heads/main:refs/remotes/origin/main
- uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
- name: Install buf
run: go install github.com/bufbuild/buf/cmd/buf@v${{ env.BUF_VERSION }}
- name: Install protoc-gen-go
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@${{ env.PROTOC_GEN_GO_VERSION }}
- name: Install protoc-gen-go-grpc
run: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@${{ env.PROTOC_GEN_GO_GRPC_VERSION }}
- name: buf breaking (against main)
if: github.ref != 'refs/heads/main'
working-directory: proto
run: buf breaking --against '../.git#subdir=proto,ref=refs/remotes/origin/main'
- name: buf generate
working-directory: proto
run: buf generate
- name: Fail on regenerated diff
run: |
# intent-to-add surfaces newly generated .pb.go that would
# otherwise be invisible to `git diff` (adding a .proto without
# committing its generated .pb.go must fail this gate).
git add -N proto/
if ! git diff --exit-code -- proto/; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Detect untracked generated files in proto drift check

The Fail on regenerated diff step can miss missing generated artifacts because git diff --exit-code -- proto/ only compares tracked changes (index/worktree) and returns success when buf generate creates new untracked *.pb.go files. In that case CI can pass even though generation output is not fully committed (e.g., adding a new .proto file and forgetting to git add the new generated file), so this gate does not reliably enforce the intended “committed output matches generated output” invariant.

Useful? React with 👍 / 👎.

echo "::error::Generated proto files differ from committed output. Run 'make -C proto gen' and commit the result."
exit 1
fi
- name: go build
run: go build ./...
78 changes: 51 additions & 27 deletions proto/Makefile
Original file line number Diff line number Diff line change
@@ -1,39 +1,63 @@
PROTOC_VERSION := libprotoc 29.3
PROTOC_GEN_GO_VERSION := protoc-gen-go v1.36.11
PROTOC_GEN_GO_GRPC_VERSION := protoc-gen-go-grpc 1.6.1
BUF_VERSION := 1.55.1
PROTOC_GEN_GO_VERSION := 1.36.11
PROTOC_GEN_GO_GRPC_VERSION := 1.6.1

.PHONY: all gen check-tools
BUF ?= buf
# BREAKING_AGAINST lets callers override the auto-detected baseline.
BREAKING_AGAINST ?=

.PHONY: all gen check-tools breaking

all: gen

check-tools:
@if [ "$$(protoc --version)" != "$(PROTOC_VERSION)" ]; then \
echo "expected $(PROTOC_VERSION), got $$(protoc --version)"; \
@command -v $(BUF) >/dev/null 2>&1 || { \
echo "buf not found; install with:"; \
echo " go install github.com/bufbuild/buf/cmd/buf@v$(BUF_VERSION)"; \
exit 1; \
}
@installed=$$($(BUF) --version 2>/dev/null); \
if [ "$$installed" != "$(BUF_VERSION)" ]; then \
echo "buf version mismatch: expected $(BUF_VERSION), got $$installed"; \
echo "install with: go install github.com/bufbuild/buf/cmd/buf@v$(BUF_VERSION)"; \
exit 1; \
fi
@if [ "$$(protoc-gen-go --version)" != "$(PROTOC_GEN_GO_VERSION)" ]; then \
echo "expected $(PROTOC_GEN_GO_VERSION), got $$(protoc-gen-go --version)"; \
@command -v protoc-gen-go >/dev/null 2>&1 || { \
echo "protoc-gen-go not found; install with:"; \
echo " go install google.golang.org/protobuf/cmd/protoc-gen-go@v$(PROTOC_GEN_GO_VERSION)"; \
exit 1; \
}
@installed=$$(protoc-gen-go --version 2>/dev/null); \
if [ "$$installed" != "protoc-gen-go v$(PROTOC_GEN_GO_VERSION)" ]; then \
echo "protoc-gen-go version mismatch: expected v$(PROTOC_GEN_GO_VERSION), got $$installed"; \
echo "install with: go install google.golang.org/protobuf/cmd/protoc-gen-go@v$(PROTOC_GEN_GO_VERSION)"; \
exit 1; \
fi
@if [ "$$(protoc-gen-go-grpc --version)" != "$(PROTOC_GEN_GO_GRPC_VERSION)" ]; then \
echo "expected $(PROTOC_GEN_GO_GRPC_VERSION), got $$(protoc-gen-go-grpc --version)"; \
@command -v protoc-gen-go-grpc >/dev/null 2>&1 || { \
echo "protoc-gen-go-grpc not found; install with:"; \
echo " go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v$(PROTOC_GEN_GO_GRPC_VERSION)"; \
exit 1; \
}
@installed=$$(protoc-gen-go-grpc --version 2>/dev/null); \
if [ "$$installed" != "protoc-gen-go-grpc $(PROTOC_GEN_GO_GRPC_VERSION)" ]; then \
echo "protoc-gen-go-grpc version mismatch: expected $(PROTOC_GEN_GO_GRPC_VERSION), got $$installed"; \
echo "install with: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v$(PROTOC_GEN_GO_GRPC_VERSION)"; \
exit 1; \
fi

gen: check-tools
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
service.proto
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
internal.proto
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
distribution.proto
protoc --go_out=. --go_opt=paths=source_relative \
dynamodb_internal.proto
protoc --go_out=. --go_opt=paths=source_relative \
redis_internal.proto
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
etcd_raft.proto
breaking: check-tools
@baseline=''; \
if git -C .. rev-parse --verify main >/dev/null 2>&1; then \
baseline='../.git#subdir=proto,branch=main'; \
elif git -C .. rev-parse --verify origin/main >/dev/null 2>&1; then \
baseline='../.git#subdir=proto,ref=refs/remotes/origin/main'; \
Comment on lines +50 to +53
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prefer origin/main when selecting breaking baseline

The baseline selection in breaking prefers local main before origin/main, which can silently compare against a stale branch on developer machines. If local main lags remote, local make gen may miss breaking changes that CI later rejects (CI uses refs/remotes/origin/main in .github/workflows/proto.yml), making the gate inconsistent across environments.

Useful? React with 👍 / 👎.

else \
echo "no breaking baseline found: neither 'main' nor 'origin/main' is reachable"; \
echo "fetch main first (git fetch origin main) or override with BREAKING_AGAINST=..."; \
exit 1; \
fi; \
if [ -n "$(BREAKING_AGAINST)" ]; then baseline='$(BREAKING_AGAINST)'; fi; \
Comment on lines +55 to +59
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor BREAKING_AGAINST before baseline auto-detection

BREAKING_AGAINST is documented as an override, but the breaking recipe exits in the else branch before that override is applied. In environments without reachable main/origin/main refs (for example shallow or single-branch clones), make gen BREAKING_AGAINST=... still fails with “no breaking baseline found,” so the advertised override path is unusable.

Useful? React with 👍 / 👎.

$(BUF) breaking --against "$$baseline"

gen: check-tools breaking
$(BUF) generate
8 changes: 8 additions & 0 deletions proto/buf.gen.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: v2
plugins:
- local: protoc-gen-go
out: .
opt: paths=source_relative
- local: protoc-gen-go-grpc
out: .
opt: paths=source_relative
6 changes: 6 additions & 0 deletions proto/buf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: v2
modules:
- path: .
breaking:
use:
- WIRE
2 changes: 1 addition & 1 deletion proto/distribution.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/distribution_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/dynamodb_internal.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/etcd_raft.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/etcd_raft_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading