General CI/CD setup
If you're using GitHub Actions, you can skip this guide and refer to the GitHub Action guide instead.
Continuous Integration/Continuous Deployment (CI/CD) is a software development practice that automates building, testing, and deploying software.
If you are working with Protobuf, then buf
should be part of all three of these development stages.
This guide illustrates how to integrate buf
into general CI/CD solutions, such as CircleCI and TravisCI.
This guide is also supplemented by the buf-examples repository, which provides a functional example for integrating buf
into CircleCI, TravisCI, or GitHub Actions.
For a quick solution that uses a Makefile, see buf-examples.
Installation
For a functional example, see the buf-examples repository.
The first step is to get buf
running on your CI/CD worker.
To do so, you'll need an install script.
buf
can be downloaded from a release or built from source.
#!/bin/bash
PROJECT=<your-project-name>
# Use your desired buf version
BUF_VERSION=1.49.0
# buf is installed to ~/bin/your-project-name.
BIN_DIR=$HOME/bin/$PROJECT
curl -sSL \
"https://github.com/bufbuild/buf/releases/download/v$BUF_VERSION/buf-$(uname -s)-$(uname -m)" \
-o "$BIN_DIR/buf"
chmod +x "$BIN_DIR/buf"
This script sends a request to the buf
GitHub Releases using
curl
for the given BUF_VERSION
and operating system.
The binary is then given executable permission.
If you intend to buf
from source, this assumes that you have the Go toolchain available in your CI/CD.
If not, see the Go Documentation for more details.
Running lint and breaking change detection
For a functional example, see the buf-examples repository.
To run lint checks with your job, simply add buf lint
to it and you're good to go.
If your buf.yaml
is defined at the root of your repository, you can run the linter with this command:
If, on the other hand, your buf.yaml
is defined in a nested directory, such as the proto
directory, the command looks like this:
For buf breaking
, the process is similar, but be sure to set the full https
or ssh
remote as the target.
If your buf.yaml
is defined at the root of your repository, the command looks like this:
Also valid:
Again, if your buf.yaml
is defined in a nested directory, such as the proto
directory, the command looks like this (notice the subdir
parameter):
$ buf breaking proto --against "https://github.com/<your-org>/<your-repo>.git#branch=main,subdir=proto"
Also valid:
$ buf breaking proto --against "ssh://git@github.com/<your-org>/<your-repo>.git#branch=main,subdir=proto"
If you are on TravisCI or CircleCI they don't clone any branches outside of the one being tested, so this enables buf
to clone using the remote and run the breaking change detector.
Handling concurrent non-breaking changes
When multiple developers work on separate branches and each introduces non-breaking changes to a stable Protobuf package,
merging these branches sequentially can sometimes lead to false positives in breaking change detection.
This occurs because the buf breaking
command compares the current directory, which may not inlude the other developers' changes,
against the main
branch.
Scenario:
- Developer A creates the
feature1
branch frommain
and adds a new message. - Developer B creates the
feature2
branch frommain
and adds a different new message. - Developer A merges
feature1
intomain
. - Developer B, before merging
feature2
, runsbuf breaking --against "https://github.com/<your-org>/<your-repo>.git#branch=main"
.
In step 4, buf breaking
may incorrectly report a breaking change because it doesn't account for the new message added in feature1
that's now in main
.
Recommendation:
To avoid false positives during breaking change detection, developers should follow one of these approaches:
-
Merge the latest changes from
main
into the feature branch before runningbuf breaking
:This approach ensures that the$ git fetch origin $ git merge origin/main $ buf breaking --against "https://github.com/<your-org>/<your-repo>.git#branch=main"
buf breaking
command considers all changes inmain
before running the check. CI/CD pipelines typically use this approach. -
Temporarily merge the latest changes from
main
into the feature branch, then abort the merge:This approach ensures that the$ git fetch origin $ git merge --no-commit --no-ff origin/main $ buf breaking --against "https://github.com/<your-org>/<your-repo>.git#branch=main" $ git merge --abort
buf breaking
command considers all changes inmain
without altering the feature branch.
CI authentication (Optional)
If you wish to authenticate a CI/CD job to access the BSR (for example to push a module, create labels, etc.), we recommend you store your BUF_TOKEN
in your CI/CD provider's secret environment variable storage.
For example:
You can then access the token in your job using an environment variable, which enables you to create a .netrc
file for your job during setup.
Here's an example assuming you've stored your token as BUF_API_TOKEN
and your username as BUF_USER
:
For more details on authenticating to the BSR
, see Authentication.
CI caching
To enable caching of modules downloaded by the Buf CLI, you can either configure caching of the ~/.cache
directory, or set the BUF_CACHE_DIR
environment variable to a directory of your choice and cache that directory.
For more information about module caching, see the module cache docs.