buf: Protobuf 构建工具介绍
buf 工具使基于
模式驱动(schema-driven)、Protobuf 的应用程序接口(API)开发,对服务生产者和消费者来说既可靠又友好
介绍
-
Buf 的目标是用模式驱动取代当前以 REST/JSON 为中心的应用程序接口开发模式
- 与 REST/JSON 相比,使用
IDL(interface description language)定义 API 有很多好处,而 Protobuf 是迄今为止业界最稳定、应用最广泛的 IDL - 用户应该选择建立在这个广受信赖的基础之上,而不是从头开始创建一个新的 IDL
- 更多参考 What we’re building
- 与 REST/JSON 相比,使用
-
buf 提供在线的仓库,类似于 github, for proto buf,地址:https://buf.build/explore,提供
Buf Schema Registry(BSR)服务- BSR 是一个托管的 SaaS 平台,可作为您组织的 Protobuf API 的代码托管工具
- 支持的Remote plugins插件:https://buf.build/plugins
- Generated SDKs
-
buf CLI 是现代、快速、高效的 Protobuf 应用程序
接口(API)管理的终极工具,Buf 具有格式化、linting、破坏性更改检测和代码生成等功能,为 Protobuf 的开发和维护提供了全面的解决方案 -
bufCLI 功能- 检查、格式化和检测 Protobuf 文件中的破坏性更改
- 为多种语言生成代码 stubs
- 管理其他 Protobuf 文件的依赖关系
- 将 Protobuf 管理和维护与工作流程相结合
- 根据可配置模板调用插件的生成器
- 与
Buf Schema Registry(BSR)集成,包括完全的依赖性管理
安装 buf
# Mac
brew install bufbuild/buf/buf
# Go
go install github.com/bufbuild/buf/cmd/buf@v1.32.2
# Binary
BIN="/usr/local/bin" && \
VERSION="1.32.2" && \
curl -sSL \
"https://github.com/bufbuild/buf/releases/download/v${VERSION}/buf-$(uname -s)-$(uname -m)" \
-o "${BIN}/buf" && \
chmod +x "${BIN}/buf"
# Docker
docker run --volume "$(pwd):/workspace" --workdir /workspace bufbuild/buf lint本文适基于 1.32.0,buf.yaml 的 version: v2
help
常用命令
buf --version
buf breaking
buf build
buf generate
buf lint
buf format
buf registry (for using the BSR)相关配置文件
buf.yaml一般位于项目根目录,定义了要作为逻辑单元或模块处理的 Protobuf 文件目录列表,通常一个项目一个该配置文件,生成命令
buf config initbuf.gen.yaml配置代码生成,它控制 buf 生成命令如何在给定模块上执行 protoc 插件,以用它来配置每个 protoc 插件写入结果的位置,并为每个插件指定选项,示例
version: v2
managed:
# 启动托管模式,以下配置对工作区中所有文件生效
enabled: true
override:
- file_option: go_package_prefix
value: github.com/bufbuild/buf-tour/gen
# 指定的插件是托管在 BSR 的远程插件,使用这些插件,就无需在本地计算机上下载、维护或运行插件
plugins:
# 执行 protocolbuffers/go 插件,为 .proto 文件生成 Go 专用代码,并将其输出放到 gen 目录中
- remote: buf.build/protocolbuffers/go
out: gen
opt: paths=source_relative
# 执行 connectrpc/go 插件,在 gen 目录中生成 Connect-Go 的客户端和服务器存根
- remote: buf.build/connectrpc/go
out: gen
opt: paths=source_relative
# buf generate 命令可接受多种类型的输入,如本地目录、 Buf 模块、GitHub 资源库和 tarball/zip 压缩包
inputs:
- directory: protobuf.lock由buf dep update命令生成,与 golang 的 go.sum,npm 的 lock 文件功能相同buf.md说明文件,功能类似与 github repo 的 readme.md
示例
- 示例
- 参考
- 官方示例仓库 https://github.com/bufbuild/buf-tour
- finish/getting-started-with-buf-cli/
clone 代码
$ git clone https://github.com/bufbuild/buf-tour.git
$ cd buf-tour/start/getting-started-with-buf-cli
$ tree
.
└── proto
├── google
│ └── type
│ └── datetime.proto
└── pet
└── v1
└── pet.proto
6 directories, 2 filesConfigure the workspace
$ buf --version
1.32.2
$ buf config init
$ ls
buf.yaml proto
$ cat buf.yaml
version: v2
lint:
use:
- DEFAULT
breaking:
use:
- FILE- 修改
buf.yaml更新目录路径,明确定义包含.proto文件的目录路径
version: v2
modules:
- path: proto
lint:
use:
- DEFAULT
breaking:
use:
- FILE- 构建模块:验证所有设置是否正确,模块是否已构建
$ buf build
$ echo $?
0生成代码
- 创建
buf.gen.yaml文件
$ cat >> buf.gen.yaml << EOF
version: v2
managed:
enabled: true
override:
- file_option: go_package_prefix
value: github.com/bufbuild/buf-tour/gen
plugins:
- remote: buf.build/protocolbuffers/go
out: gen
opt: paths=source_relative
- remote: buf.build/connectrpc/go
out: gen
opt: paths=source_relative
inputs:
- directory: proto
EOF- 生成 Go and Connect RPC stubs
$ buf generate
$ echo $?
0- 生成后的目录
$ tree
.
├── buf.gen.yaml
├── buf.yaml
├── gen
│ ├── google
│ │ └── type
│ │ └── datetime.pb.go
│ └── pet
│ └── v1
│ ├── pet.pb.go
│ └── petv1connect
│ └── pet.connect.go
└── proto
├── google
│ └── type
│ └── datetime.proto
└── pet
└── v1
└── pet.proto
12 directories, 7 fileslint
静态检查有助于提高代码质量,提前发现错误
$ buf lint
proto/google/type/datetime.proto:17:1:Package name "google.type" should be suffixed with a correctly formed version, such as "google.type.v1".
proto/pet/v1/pet.proto:42:10:Field name "petID" should be lower_snake_case, such as "pet_id".
proto/pet/v1/pet.proto:47:9:Service name "PetStore" should be suffixed with "Service".
$ echo $?
100由于代码有错误,可以根据提示修复代码,如下:
$ git diff
--- a/start/getting-started-with-buf-cli/proto/pet/v1/pet.proto
+++ b/start/getting-started-with-buf-cli/proto/pet/v1/pet.proto
@@ -39,12 +39,12 @@ message PutPetResponse {
}
message DeletePetRequest {
- string petID = 1;
+ string pet_id = 1;
}
message DeletePetResponse {}
-service PetStore {
+service PetStoreService {- 修复后,重新执行
$ buf generate
$ buf lint
proto/google/type/datetime.proto:17:1:Package name "google.type" should be suffixed with a correctly formed version, such as "google.type.v1".
$ echo $?
100- 忽略失败的 lint,修改
buf.yaml
version: v2
modules:
- path: proto
lint:
use:
- DEFAULT
+ ignore:
+ - proto/google/type/datetime.proto
breaking:
use:
- FILE- 再次 lint 提示成功
$ buf lint
$ echo $?
0Break your API
Protobuf 比 JSON 更容易产生不兼容性,break 用来测试不兼容性的变更
- 修改
pet.proto如下
message Pet {
- PetType pet_type = 1;
+ string pet_type = 1;
string pet_id = 2;
string name = 3;
}- 在工作区运行
buf breaking,需要选择一个输入进行比较,验证这是否是一个突破性的变化
$ buf breaking --against "../../.git#subdir=start/getting-started-with-buf-cli/proto"
proto/pet/v1/pet.proto:1:1:Previously present service "PetStore" was deleted from file.
proto/pet/v1/pet.proto:18:3:Field "1" with name "pet_type" on message "Pet" changed type from "enum" to "string".
proto/pet/v1/pet.proto:42:3:Field "1" with name "pet_id" on message "DeletePetRequest" changed option "json_name" from "petID" to "petId".
proto/pet/v1/pet.proto:42:10:Field "1" on message "DeletePetRequest" changed name from "petID" to "pet_id".
$ echo $?
100登录 BSR
在 https://buf.build/settings/user 点击 Create New Token 创建 token
$ buf registry login
Log in with your Buf Schema Registry username. If you don't have a username, create one at https://buf.build.
Username: xiexianbin
Token: <YOUR TOKEN>推送
在 buf.yaml 中添加 name: buf.build/xiexianbin/petapis,并在 https://buf.build/ 创建名称为 petapis 的 Repositories
version: v2
modules:
- path: proto
+ name: buf.build/xiexianbin/petapis
lint:
use:
- DEFAULT
ignore:
- proto/google/type/datetime.proto
breaking:
use:
- FILE-
添加
touch proto/README.md,并写入需要的说明 -
推送
$ tree proto
├── google
│ └── type
│ └── datetime.proto
├── pet
│ └── v1
│ └── pet.proto
└── README.md
$ buf registry login buf.build --username 'xiexianbin'
Token:xx
Credentials saved to /Users/xiexianbin/.netrc.
$ buf push
buf.build/xiexianbin/petapis:4b28576bedf545cba5fa30ba741d1c6d添加依赖
-
删除
rm -r proto/google -
buf.yaml添加依赖
version: v2
modules:
- path: proto
name: buf.build/xiexianbin/petapis
lint:
use:
- DEFAULT
- ignore:
- - google/type/datetime.proto
breaking:
use:
- FILE
# 在 buf.yaml 文件中为工作区中的所有模块定义一次依赖关系,然后 BSR 就会解析依赖关系,将构建模块所需的导入包含在内
+deps:
+ - buf.build/googleapis/googleapis- 更新依赖,并生成
buf.lok文件
# 将所有部署更新到最新版本,他会到 deps 找到需要的依赖,并下载到本地
$ buf dep update
$ tree
.
├── buf.gen.yaml
├── buf.lock
├── buf.yaml
├── gen
│ ├── google
│ │ └── type
│ │ └── datetime.pb.go
│ └── pet
│ └── v1
│ ├── pet.pb.go
│ └── petv1connect
│ └── pet.connect.go
└── proto
└── pet
└── v1
└── pet.proto
10 directories, 7 files
$ cat buf.lock
# Generated by buf. DO NOT EDIT.
version: v2
deps:
- name: buf.build/googleapis/googleapis
commit: f0e53af8f2fc4556b94f482688b57223
digest: b5:24e758f963ee1bb3b5218eb452e0bdfb7a5449d9a77d174b8284b6368ccc1884213689381cdcd79e4231796c281c128ac1ae50825237b1774deb542bdc704b32说明:
- Buf CLI 发现 deps 中添加了一个新的依赖项
- 它解析了
buf.build/googleapis/googleapis模块的最新版本,并将其写入模块的buf.lock文件 - 再次运行
buf build时,它会将buf.build/googleapis/googleapis模块下载到本地模块缓存 - 一旦所有依赖项都在本地可用,它就会成功构建模块(因为
google/type/datetime.proto在本地模块缓存中)
其他
- 接口实现参考
- 调用接口
$ buf curl \
--schema . \
--data '{"pet_type": "PET_TYPE_SNAKE", "name": "Ekans"}' \
http://localhost:8080/pet.v1.PetStoreService/PutPet与其他工具集成
Makefile
- 代码参考
.PHONY: proto/all
proto/all: proto/vendor proto/format proto/lint proto/generate
.PHONY: proto/lint
proto/lint:
# docker run --volume ${PWD}:/workspace --workdir /workspace bufbuild/buf lint
buf lint
buf breaking -v --against '.git#branch=main,subdir=proto'
.PHONY: proto/format
proto/format:
# docker run --volume ${PWD}:/workspace --workdir /workspace bufbuild/buf format
buf format -w
.PHONY: proto/generate
proto/generate: proto/vendor
# Generate just the annotations and http protos.
buf generate buf.build/googleapis/googleapis --path google/api/annotations.proto --path google/api/http.proto
buf generate buf.build/grpc/grpc --path grpc/health/
# docker run --volume ${PWD}:/workspace --workdir /workspace bufbuild/buf generate
buf generate
rm -rf gen/proto/go/opentelemetry
buf generate --template otel-buf.gen.yaml --path proto/opentelemetry/proto/collector/profiles/v1/profiles_service.proto
buf generate --template otel-buf.gen.yaml --path proto/opentelemetry/proto/profiles/v1/alternatives/pprofextended/pprofextended.proto
buf generate --template otel-buf.gen.yaml --path proto/opentelemetry/proto/profiles/v1/profiles.proto
rm -rf gen/proto/go/opentelemetry/proto/common
rm -rf gen/proto/go/opentelemetry/proto/resource
.PHONY: proto/vendor
proto/vendor: proto/google/pprof/profile.proto
cd proto && buf dep update
proto/google/pprof/profile.proto:
mkdir -p proto/google/pprof
curl https://raw.githubusercontent.com/google/pprof/master/proto/profile.proto > proto/google/pprof/profile.protogithub actions
- 参考同上
- proto-pr.yaml pr 检查,包括:format、gen、lint、breaking
name: proto-pr
on:
pull_request:
merge_group:
branches:
- main
jobs:
build:
name: Proto PR Checks
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: bufbuild/buf-setup-action@v1.33.0
- name: version
run: buf --version
- name: Format
run: buf format --diff --exit-code
- name: Generate
run:
make proto/generate && git diff --exit-code # ':!ui/packages/app/web/public/keep.go'
- uses: bufbuild/buf-lint-action@06f9dd823d873146471cfaaf108a993fe00e5325 # v1.1.1
with:
input: 'proto'
- uses: bufbuild/buf-breaking-action@c57b3d842a5c3f3b454756ef65305a50a587c5ba # v1.1.4
with:
input: 'proto'
# The 'main' branch of the GitHub repository that defines the module.
against: 'https://github.com/${GITHUB_REPOSITORY}.git#branch=main,subdir=proto'- proto-push.yaml 推动到 bsr
name: proto-push
on:
push:
branches:
- main
- release-*
merge_group:
branches:
- main
jobs:
build:
name: Proto Push
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: bufbuild/buf-setup-action@v1.33.0
- name: version
run: buf --version
- name: Format
run: buf format --diff --exit-code
- uses: bufbuild/buf-lint-action@06f9dd823d873146471cfaaf108a993fe00e5325 # v1.1.1
with:
input: 'proto'
- uses: bufbuild/buf-breaking-action@c57b3d842a5c3f3b454756ef65305a50a587c5ba # v1.1.4
with:
input: 'proto'
# The 'main' branch of the GitHub repository that defines the module.
against: 'https://github.com/${GITHUB_REPOSITORY}.git#branch=main,ref=HEAD~1,subdir=proto'
- uses: bufbuild/buf-push-action@a654ff18effe4641ebea4a4ce242c49800728459 # v1.2.0
with:
input: 'proto'
buf_token: ${{ secrets.BUF_TOKEN }}