Skip to content

Commit 0787340

Browse files
committed
chore(proto): tighten breaking detection and gate AIP lint in CI
The "my festival" API is HTTP/JSON-only (no gRPC server), so a JSON field-name change breaks real clients even when the wire format is unchanged. Switch buf breaking detection from WIRE to WIRE_JSON so those changes are caught now rather than deferred to v1. Add the AIP design linter (api-linter) to the CI proto job with --set-exit-status so design-level regressions buf's STANDARD ruleset doesn't cover actually gate merges; mirror the flag in the proto:api-lint mise task. Pin buf (1.70.0) and api-linter (2.3.1) in dev and CI so local and CI results agree. Fix the stale buf.yaml lint comment (Delete returns the DrinkEntry tombstone per AIP-164, not google.protobuf.Empty) and drop the now-dead empty.proto breaking-ignore entry.
1 parent abbba9c commit 0787340

3 files changed

Lines changed: 46 additions & 21 deletions

File tree

.github/workflows/ci.yml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,10 @@ jobs:
9999
mapfile -t SH_FILES < <(find . -name '*.sh' -not -path './.git/*' -not -path './.mise/*' -not -path '*/node_modules/*' | sort)
100100
[[ ${#SH_FILES[@]} -gt 0 ]] && shfmt -d -i 0 -ci "${SH_FILES[@]}"
101101
102-
# Lint proto files and check for breaking changes against main.
103-
# buf breaking runs on PRs only (bufbuild/buf-action skips it on push to main
104-
# where the change is already merged). FILE stability level (configured in
105-
# proto/buf.yaml) is appropriate for v1alpha; switch to WIRE_JSON_COMPATIBLE
106-
# when the API graduates to v1.
102+
# Lint proto files, check for breaking changes against main, and run the
103+
# AIP design linter. buf breaking runs on PRs only (bufbuild/buf-action skips
104+
# it on push to main where the change is already merged). buf.yaml uses
105+
# WIRE_JSON breaking detection because the transport is HTTP/JSON.
107106
proto:
108107
needs: changes
109108
runs-on: ubuntu-latest
@@ -118,11 +117,34 @@ jobs:
118117

119118
- uses: bufbuild/buf-action@v1
120119
with:
120+
version: 1.70.0
121121
input: proto
122122
push: false
123123
pr_comment: false
124124
breaking_against: "https://github.com/${{ github.repository }}.git#branch=main,subdir=proto"
125125

126+
# AIP design lint (googleapis/api-linter) — the design-level rules buf's
127+
# STANDARD ruleset doesn't cover. Mirrors the proto:api-lint mise task.
128+
- name: Set up Go
129+
uses: actions/setup-go@v5
130+
with:
131+
go-version: stable
132+
133+
- name: Install api-linter
134+
run: go install github.com/googleapis/api-linter/v2/cmd/api-linter@v2.3.1
135+
136+
- name: AIP design lint
137+
working-directory: proto
138+
run: |
139+
buf build -o /tmp/cambeerfestival.pb
140+
api-linter \
141+
--config .api-linter.yaml \
142+
--descriptor-set-in=/tmp/cambeerfestival.pb \
143+
--set-exit-status \
144+
cambeerfestival/myfestival/v1alpha/my_festival_service.proto \
145+
cambeerfestival/myfestival/v1alpha/drink_entry.proto \
146+
cambeerfestival/myfestival/v1alpha/drink_summary.proto
147+
126148
# Analyze code in parallel with tests so builds can start sooner
127149
analyze:
128150
needs: changes

mise.dev.toml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616

1717
[tools]
1818
watchexec = "2.5.1"
19-
buf = "latest"
19+
buf = "1.70.0"
2020

2121
# --- Protobuf / OpenAPI (API contract is proto-first; see proto/README.md) ---
22-
# buf and api-linter live here (dev-only) while the API design is still in flux.
23-
# Move both to base mise.toml when the API stabilises and proto tasks enter CI.
24-
# Move it to base mise.toml once the resource shapes and method signatures
25-
# have stabilised and the linter output is expected to stay clean in CI.
26-
"github:googleapis/api-linter" = "latest"
22+
# buf and api-linter live here for local dev. CI runs the equivalent checks in
23+
# the `proto` job (buf-action + api-linter via go install), so these versions
24+
# are pinned to match CI. Move both to base mise.toml if the toolchain is ever
25+
# needed by base (non-dev) tasks.
26+
"github:googleapis/api-linter" = "2.3.1"
2727

2828
[tasks."proto:lint"]
2929
description = "Lint the protobuf API contract (buf STANDARD ruleset)"
@@ -86,6 +86,7 @@ buf build -o /tmp/cambeerfestival.pb
8686
api-linter \
8787
--config .api-linter.yaml \
8888
--descriptor-set-in=/tmp/cambeerfestival.pb \
89+
--set-exit-status \
8990
cambeerfestival/myfestival/v1alpha/my_festival_service.proto \
9091
cambeerfestival/myfestival/v1alpha/drink_entry.proto \
9192
cambeerfestival/myfestival/v1alpha/drink_summary.proto

proto/buf.yaml

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ lint:
77
use:
88
- STANDARD
99
except:
10-
# AIP-131/134: Get and Update return the resource itself, and Delete
11-
# returns google.protobuf.Empty — both intentionally diverge from buf's
12-
# "<Method>Response" / unique-response defaults. Google's own APIs do the same.
10+
# AIP-131/134/164: Get, Update, and Delete all return the DrinkEntry
11+
# resource itself (Delete is a soft delete that returns the tombstone), so
12+
# one response message is shared across methods and none match buf's
13+
# "<Method>Response" naming default. Google's own APIs do the same.
1314
- RPC_RESPONSE_STANDARD_NAME
1415
- RPC_REQUEST_RESPONSE_UNIQUE
1516
breaking:
1617
use:
1718
- FILE
18-
- WIRE
19-
# WIRE catches field-number renumbering and field-type changes on the wire.
19+
- WIRE_JSON
20+
# WIRE_JSON is a superset of WIRE: it catches field-number renumbering and
21+
# field-type changes (WIRE) AND JSON field-name changes. The transport is
22+
# HTTP/JSON (we run no gRPC server), so renaming a field is breaking for real
23+
# clients even when the wire format is unchanged — WIRE alone would miss it.
2024
# FILE catches deleted files and moved definitions.
2125
#
2226
# Promotion path:
@@ -25,8 +29,6 @@ breaking:
2529
# No buf.yaml changes needed — ignore_unstable_packages stays absent so
2630
# beta breaking changes are caught from day one.
2731
# v1beta1 → v1: copy package to cambeerfestival.myfestival.v1 and delete
28-
# beta. Switch breaking.use to WIRE_JSON_COMPATIBLE here (superset of
29-
# WIRE; also checks JSON field name stability). Add ignore_unstable_packages:
30-
# true only if a new v2alpha package coexists with stable v1.
31-
ignore:
32-
- google/protobuf/empty.proto
32+
# beta. No breaking-config change needed (already WIRE_JSON). Add
33+
# ignore_unstable_packages: true only if a new v2alpha package coexists
34+
# with stable v1.

0 commit comments

Comments
 (0)