mirror of
https://github.com/tiennm99/noitu.git
synced 2026-10-11 03:13:45 +00:00
feat(proto): add protobuf wire contract and cross-language codegen
proto/noitu/v1/game.proto is the single source of truth for every WebSocket message. buf generates Go types into server/gen and JavaScript types into web/src/lib/proto; both trees are committed so building needs no codegen toolchain. The Go suite emits binary fixtures into proto/testdata and the JavaScript suite decodes the same bytes, so the two generated clients are checked against one artifact rather than against each other's assumptions. CI lints the schema, rejects breaking changes against main, and fails when the committed generated trees drift from the schema. game.NumRejectReasons and game.NumEndReasons let the mapping tests prove every engine reason has a wire value without guessing where the enum ends.
This commit is contained in:
1 parent
ca01145d06
commit
48b3b3c8ac
42 files changed
+6102
-31
No files matched your search
@@ -0,0 +1,84 @@
|
||||
# Guards the WebSocket wire contract.
|
||||
#
|
||||
# Nothing here downloads the 179 MB upstream dictionary: the wire types and
|
||||
# their fixtures are independent of the wordlist, so this workflow stays fast
|
||||
# and runs on every push.
|
||||
name: proto
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
contract:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# buf breaking compares against main, which needs real history.
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: bufbuild/buf-setup-action@v1
|
||||
with:
|
||||
version: 1.69.0
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: server/go.mod
|
||||
cache-dependency-path: server/go.sum
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: web/package-lock.json
|
||||
|
||||
- run: npm ci
|
||||
working-directory: web
|
||||
|
||||
- name: Lint the schema
|
||||
run: buf lint
|
||||
|
||||
# Skipped only until this contract first lands on main; after that the
|
||||
# baseline always exists and the check is unconditional.
|
||||
- name: Look for a breaking-change baseline on main
|
||||
id: baseline
|
||||
run: |
|
||||
if git cat-file -e origin/main:proto/noitu/v1/game.proto 2>/dev/null; then
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::no schema on main yet, skipping the breaking-change check"
|
||||
fi
|
||||
|
||||
# ref=origin/main, not branch=main: a pull_request checkout is a detached
|
||||
# HEAD with no local main, and branch=main fails there with a git clone
|
||||
# error rather than a breaking-change report.
|
||||
- name: Reject breaking changes
|
||||
if: steps.baseline.outputs.exists == 'true'
|
||||
run: buf breaking --against '.git#ref=origin/main'
|
||||
|
||||
# A committed generated tree that no longer matches the schema is worse
|
||||
# than no generated tree at all: it compiles, and it is wrong.
|
||||
# --intent-to-add first: git diff ignores untracked files, so without it
|
||||
# a plugin that starts emitting a new file passes this check while the
|
||||
# committed tree is incomplete.
|
||||
- name: Verify the committed generated code is in sync
|
||||
run: |
|
||||
buf generate
|
||||
git add --intent-to-add -- server/gen web/src/lib/proto
|
||||
git diff --exit-code -- server/gen web/src/lib/proto
|
||||
|
||||
# Both suites read the same fixtures in proto/testdata, so this is what
|
||||
# actually proves Go and JavaScript agree on the bytes.
|
||||
- name: Go wire tests
|
||||
run: go test ./internal/wsapi/... -race
|
||||
working-directory: server
|
||||
|
||||
- name: JavaScript wire tests
|
||||
run: npm test
|
||||
working-directory: web
|
||||
Reference in new issue
Block a user