blob: c0626d4bed003bfc7d4cf4d05377bfc4c504ea08 [file] [log] [blame] [view]
# Bazel cheatsheet
This cheatsheet provides quick tips on how to build and test code in our repository using Bazel.
Start [here](https://docs.bazel.build/versions/4.1.0/bazel-overview.html) if you're completely new
to Bazel.
The original design documents for our Bazel build can be found at the following Golinks:
- [go/skia-infra-bazel](http://go/skia-infra-bazel)
- [go/skia-infra-bazel-frontend](http://go/skia-infra-bazel-frontend)
- [go/skia-infra-bazel-backend](http://go/skia-infra-bazel-backend)
## Initial setup
This section includes steps every engineer should follow to get a consistent development
experience.
### Install Bazelisk
[Bazelisk](https://github.com/bazelbuild/bazelisk) is a wrapper for Bazel that downloads and runs
the version of Bazel specified in `//.bazelversion`. It serves a similar purpose as
[nvm](https://github.com/nvm-sh/nvm) does for NodeJS.
Bazelisk is recommended over plain Bazel because the `bazel` command on our gLinux workstations is
automatically updated every time a new version of Bazel is released.
To install Bazelisk, grab the latest binary for your platform from
[GitHub](https://github.com/bazelbuild/bazelisk/releases), then add it to your `PATH`.
Tips:
- Make a Bash alias with `alias bazel="bazelisk"` and add it to your `~/.bash_aliases` file.
- Set the full path to `bazel` to be the full path to `bazelisk` in your IDE of choice. This is
necessary for some extensions to work correctly, such as the
[Bazel plugin for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=BazelBuild.vscode-bazel).
### Set up RBE access
[Remote Build Execution](https://bazel.build/remote/rbe) (RBE) allows faster build and test
execution times by distributing build and test actions across multiple machines.
Run the following command to get access our RBE instance:
```
$ gcloud auth application-default login
```
This should enable you to utilize RBE by including the flag `--config=remote` in your Bazel
invocations. For more details on this flag, see below.
Then, create a `//bazel/user/bazelrc` file in your repository checkout with the following contents:
```
build:mayberemote --config=remote
```
This will enable RBE for any Bazel invocations in scripts, Make targets, etc.
**Warning:** Do not use `--config=mayberemote` in your manual Bazel invocations. The "mayberemote"
configuration is only intended to be used from scripted actions. For manual Bazel invocations, use
`--config=remote` instead, which will explicitly let you know if there are any problems with your
RBE setup. For more details on the `--config=mayberemote` flag and why it is necessary, see below.
## Gazelle
We use [Gazelle](https://github.com/bazelbuild/bazel-gazelle) to automatically generate
`BUILD.bazel` files for most of our Go and TypeScript code.
Note that we occasionally edit Gazelle-generated `BUILD.bazel` files by hand, e.g. to mark tests as
[flaky](#flaky-tests).
### Usage
Run `make gazelle` from the repository's root directory.
### TypeScript support
TypeScript support is provided via a custom Gazelle extension which can be found in
`//bazel/gazelle/frontend`.
Tip: See [here](#testing-typescript-code) for details on how this extension decides which rule to
generate for a given TypeScript file.
## Buildifier
[Buildifier](https://github.com/bazelbuild/buildtools/tree/master/buildifier) is a linter and
formatter for `BUILD.bazel` files and other Bazel files (`WORKSPACE`, `*.bzl`, etc.).
### Usage
Run `bazel run //:buildifier`.
## Bazel CI tasks
Our repository is built is tested on RBE with the following CI tasks:
- Infra-PerCommit-Build (roughly equivalent to `bazel build //... --config=remote`)
- Infra-PerCommit-Test (roughly equivalent to `bazel test //... --config=remote`)
We regard the above tasks as the source of truth for build and test correctness.
## Building and testing
Use commands `bazel build` and `bazel test` to build and test Bazel targets, respectively.
Examples:
```
# Single target.
$ bazel build //go/util:util
$ bazel test //go/util:util_test
# All targets under a directory and any subdirectoriews.
$ bazel build //go/...
$ bazel test //go/...
# All targets in the repository.
$ bazel build //...
$ bazel test //...
```
Any build artifacts produced by `bazel build` or `bazel test` will be found under `//_bazel_bin`.
Note that it's not necessary to `bazel build` a test target before `bazel test`-ing it.
`bazel test` will automatically build the test target if it wasn't built already (i.e. if it
wasn't found in the Bazel cache).
More on `bazel build`
[here](https://docs.bazel.build/versions/main/guide.html#building-programs-with-bazel).
More on `bazel test` [here](https://docs.bazel.build/versions/main/user-manual.html#test).
### Building and testing on RBE
By default, Bazel will build and test targets on the host system (aka a local build). To build on
RBE, invoke Bazel with flag `--config=remote`, e.g.:
```
$ bazel build //go/util:util --config=remote
$ bazel test //go/util:util_test --config=remote
```
This repository contains some scripted actions that shell out to Bazel, such as certain `make`
targets (e.g. `make gazelle`, `make buildifier`) and `go generate` actions. These actions use the
"mayberemote" configuration via the `--config=mayberemote` flag, e.g.:
```
# //Makefile
update-go-bazel-files:
$(BAZEL) run --config=mayberemote //:gazelle -- update ./
```
By default, the "mayberemote" configuration does nothing. This is to support users that might not
have RBE access, or when working offline (e.g. on a plane with no WiFi). To get the benefits of RBE
when running scripted actions, please create a `//bazel/user/bazelrc` file with the following
contents:
```
build:mayberemote --config=remote
```
To learn more about the `mayberemote` configuration:
- See comments in `//.bazelrc`
[here](https://skia.googlesource.com/buildbot/+/576558265598b54751233441814aa389f1e96d53/.bazelrc#142).
- See [`//bazel/user/README.md`](https://skia.googlesource.com/buildbot/+/576558265598b54751233441814aa389f1e96d53/bazel/user/README.md).
## Running Bazel-built binaries
Use command `bazel run` to run binary Bazel targets (such as `go_binary`, `sh_binary`, etc.), e.g.:
```
# Without command-line parameters.
$ bazel run //scripts/run_emulators:run_emulators
# With command-line parameters.
$ bazel run //scripts/run_emulators:run_emulators -- start
```
Alternatively, you can run the Bazel-built artifact directly, e.g.:
```
$ bazel build //scripts/run_emulators:run_emulators
$ _bazel_bin/scripts/run_emulators/run_emulators_/run_emulators start
```
The exact path of the binary under `//_bazel_bin` depends on the Bazel rule (`go_binary`,
`py_binary`, etc.). As you can see, said path can be non-obvious, so it's generally recommended to
use `bazel run`.
More on `bazel run` [here](https://docs.bazel.build/versions/main/user-manual.html#run).
## Back-end development in Go
Our Go codebase is built and tested using Bazel rules from the
[rules_go](https://github.com/bazelbuild/rules_go) repository. The `go_test` rule
[documentation](https://github.com/bazelbuild/rules_go/blob/master/go/core.rst#go_test) is a great
read to get started.
As mentioned in the [Gazelle](#gazelle) section, all Bazel targets for Go code are generated with
Gazelle.
Read [go/skia-infra-bazel-backend](http://go/skia-infra-bazel-backend) for the full details.
### Invoking "go", "gofmt" and other tools
On non-Bazel Go projects, developers typically use locally installed binaries such as `go` and
`gofmt` for code generation and code formatting tasks. However, our Bazel build aims to be as
[hermetic](https://bazel.build/basics/hermeticity) as possible. To this end, rather than requiring
the developer to install a Go SDK on their system, we provide convenience Bazel targets defined in
`//BUILD.bazel` to invoke binaries in the Bazel-downloaded Go SDK and other Bazel-downloaded tools.
Example invocations:
```
# Equivalent to "go generate ./..."
$ bazel run //:go -- generate ./...
# Equivalent to "gofmt -s -w ."
$ bazel run //:gofmt -- -s -w .
# Equivalent to "errcheck go.skia.org/infra/..."
$ bazel run //:errcheck -- go.skia.org/infra/...
# Equivalent to "protoc --go_out . myproto.proto"
$ bazel run //:protoc -- --go_out=. myproto.proto
```
Our CI tasks and Makefiles use these Bazel targets. This prevents diffs that might arise from
using locally installed binaries, which might differ from system to system. Developers should
always use Bazel-downloaded binaries for any tasks that produce changes in checked-in files.
Note that it might still be desirable to have a locally installed Go SDK. For example,
[Visual Studio Code](https://code.visualstudio.com/)'s
[Go extension](https://code.visualstudio.com/docs/languages/go) requires a locally installed Go SDK
to enable autocompletion and debugging. It is the developer's responsibility to ensure that their
locally installed Go SDK matches the version used by the Bazel build, which is defined in the
[`//WORKSPACE`](https://skia.googlesource.com/buildbot/+/d18bcaf0173de9c054dd5809fe5ccd459a1adec5/WORKSPACE#99)
file.
### Building Go code
Simply use `bazel build` (and optionally `bazel run`) as described
[earlier](#building-and-testing).
### Testing Go code
Tip: Start by reading the [General testing tips](#general-testing-tips) section.
Our setup differs slightly from typical Go + Bazel projects in that we use a wrapper macro around
`go_test` to handle manual tests. Gazelle is configured to use this macro via a `gazelle:map_kind`
directive in `//BUILD.bazel`. The macro is defined in `//bazel/go/go_test.bzl`. Read the macro's
docstring for the full details.
#### Manual Go tests
To mark specific Go test cases as manual, extract them out into a separate file ending with
`_manual_test.go` within the same directory.
The `go_test` macro in `//bazel/go/go_test.bzl` places files ending with `_manual_test.go` in a
separate `go_test` target, which is tagged as manual.
More on manual tests [here](#manual-tests).
#### Passing flags to Go tests
The `go test` command supports flags such as `-v` to print verbose outputs, `-run` to run a
specific test case, etc. Under Bazel, these flags can be passed to a `go_test` test target via
`--test_arg`, but they need to be prefixed with `-test.`, e.g.:
```
# Equivalent to "go test ./go/util -v".
$ bazel test //go/util:util_test --test_arg=-test.v
# Equivalent to "go test ./go/util -run=TestFoo"
$ bazel test //go/util:util_test --test_arg=-test.run=TestFoo
```
#### Example `bazel test` invocation for Go tests
The following example shows what a typical `bazel test` invocation might look like while debugging
a `go_test` target locally.
```
# Equivalent to "$ MY_ENV_VAR=foo go test ./go/my_pkg -v -logtostderr"
$ bazel test //go/my_pkg:my_pkg_test \
--test_output=streamed \
--nocache_test_results \
--test_arg=-test.v \
--test_arg=-logtostderr \
--test_env=MY_ENV_VAR=foo
```
### Go modules
Unlike normal Go projects, Bazel Go projects based on rules_go specify Go module dependencies via
Gazelle's
[`go_repository`](https://github.com/bazelbuild/bazel-gazelle/blob/master/repository.md#go_repository)
rule. In our repository, those rules are located in `//go_repositories.bzl`.
While a Bazel Go project does not need a `go.mod` file, absence of a `go.mod` file breaks common
tooling such as VSCode's code completion. For this reason, our repository contains a `//go.mod`
file which we treat as the source of truth for Go dependencies, and we automatically generate file
`//go_repositories.bzl` from `//go.mod` via Gazelle.
#### Adding or updating Go modules
The process is similar to non-Bazel Go projects, but instead of running e.g.
`go get example.com/foo@v0.1.2`, we use the `//:go` Bazel wrapper mentioned earlier. This avoids
potential differences in `//go.mod` and `//go.sum` that might be introduced by a local Go SDK whose
version differs from the hermetic Go SDK downloaded by Bazel.
First, update the `//go.mod` file:
```
$ bazel run //:go -- get example.com/foo@v0.1.2
```
Then run Gazelle, which will update `//go_repositories.bzl`:
```
$ make gazelle
```
#### Troubleshooting Go dependency changes
While the above steps work for most Go dependencies, we occasionally run into issues that require
manual work to resolve.
For example:
- Most Go modules do not include `BUILD` files, in which case the `go_repository` rule will
generate `BUILD` files automatically using Gazelle. However, some Go modules are distributed
with `BUILD` files, in which case the `go_repository` rule will not generate any `BUILD` files.
This behavior can be customized to some extent via the `go_repository` rule's
`build_file_generation` attribute
([example](https://skia-review.googlesource.com/c/buildbot/+/772355/6/go_repositories.bzl#205)).
- For those Go modules that include `BUILD` files, sometimes the target names in those files will
use the
[`go_default_library`](https://github.com/bazelbuild/rules_go#what-s-up-with-the-go-default-library-name)
naming convention. In such cases, we must explicitly tell the `go_repository` rule via the
`build_naming_convention` attribute
([example](https://skia.googlesource.com/buildbot/+/232683f4840a825514e931d8201940388b3997dc/go_repositories.bzl#204)).
- For Go modules that include `.proto` files, sometimes they also include pre-generated `.pb.go`
files, in which case we need to tell the `go_repository` rule not to generate
[`go_proto_library`](https://github.com/bazelbuild/rules_go/blob/master/proto/core.rst#go_proto_library)
targets
([example](https://skia.googlesource.com/buildbot/+/232683f4840a825514e931d8201940388b3997dc/go_repositories.bzl#3174)).
Another important aspect to keep in mind while debugging problematic Go modules is that the order
in which we import external Bazel repositories in the `//WORKSPACE` file matters greatly. This is
relevant to Go modules because the `//go_repositories.bzl` file is imported from `//WORKSPACE`.
As an example, on Q4 2023 we updated the `google.golang.org/grpc` Go module. This update was
particularly challenging because it required:
- Investigating and simplifying non-`go_repository` external Bazel repositories in `//WORKSPACE`.
- Updating both rules_go and Gazelle.
- Updating numerous transitive dependencies which required customizing the attributes of some
`go_repository` rules in `//go_repositories.bzl`
- Compatibility hacks for certain Go modules that assumed an older version of `rules_go`.
This [bug](https://g-issues.skia.org/issues/308044304) tracks all the work that went into this
update. We recommend reading through the CL descriptions; it might give you some ideas as to what
to try next if you get stuck during a tricky Go module update.
## Front-end development in TypeScript
Our front-end code is built and tested using a set of custom Bazel macros built on top of rules
provided by the [rules_js](https://github.com/aspect-build/rules_js) and
[rules_ts](https://github.com/aspect-build/rules_ts) rulesets. All such macros are either defined
in or re-exported from `//infra-sk/index.bzl`. This section uses the terms macro and rule
interchangeably when referring to the macros exported from said file.
As mentioned in the [Gazelle](#gazelle) section, most Bazel targets for front-end code are
generated with Gazelle.
Read [go/skia-infra-bazel-frontend](http://go/skia-infra-bazel-frontend) for the full details.
### Building TypeScript code
Simply use `bazel build` (and optionally `bazel run`) as described
[earlier](#building-and-testing).
### Working with demo pages
Demo pages are served via a Gazelle-generated `sk_demo_page_server` rule.
Use `bazel run` to serve a demo page via its `sk_demo_page_server` rule, e.g.:
```
$ bazel run //golden/modules/dots-sk:demo_page_server
```
#### Watching for changes
To rebuild the demo page automatically upon changes in the custom element's directory, use the
`demopage.sh` script found in the repository's root directory, e.g.:
```
$ ./demopage.sh golden/modules/dots-sk
```
This script uses [entr](https://eradman.com/entrproject/) to watch for file changes and re-execute
the `bazel run` command as needed. The above `demopage.sh` invocation is equivalent to:
```
$ ls golden/modules/dots-sk/* | entr -r bazel run //golden/modules/dots-sk:demo_page_server
```
Install `entr` on a gLinux workstation with `sudo apt-get install entr`.
In the future, we might replace this script with
[ibazel](https://github.com/bazelbuild/bazel-watcher), which requires changes to the
`sk_demo_page_server` rule.
### Testing TypeScript code
Tip: Start by reading the [General testing tips](#general-testing-tips) section.
Front-end code testing is done via three different Bazel rules:
- `karma_test` for in-browser tests based on the Karma test runner.
- `sk_element_puppeteer_test` for Puppeteer tests that require a running `sk_demo_page_server`.
- `nodejs_test` for any other server-side TypeScript tests (i.e. NodeJS tests).
Gazelle decides which rule to generate for a given `*_test.ts` file based the following patterns:
- `karma_test` is used for files matching `//<app>/modules/<element>/<element>_test.ts`.
- `sk_element_puppeteer_test` is used for files matching
`//<app>/modules/<element>/<element>_puppeteer_test.ts`.
- `nodejs_test` is used for files matching `*_nodejs_test.ts`.
#### Karma tests (`karma_test` rule)
Use `bazel test` to run a Karma test in headless mode:
```
$ bazel test //golden/modules/dots-sk:dots-sk_test
```
To run a Karma test in the browser during development, use `bazel run` instead:
```
$ bazel run //golden/modules/dots-sk:dots-sk_test
...
Karma v4.4.1 server started at http://<hostname>:9876/
```
##### Watching for changes
As an alternative to `bazel run` when debugging tests in the browser, consider using the
`karmatest.sh` script found in the repository's root directory. Similarly to the `demopage.sh`
script mentioned earlier, it watches for changes in the custom element's directory, and relaunches
the test runner when a file changes. Example usage:
```
$ ./karmatest.sh golden/modules/digest-details-sk
```
As with `demopage.sh`, this script depends on the `entr` command, which can be installed on a
gLinux workstation with `sudo apt-get install entr`.
#### Puppeteer tests (`sk_element_puppeteer_test` rule)
Use `bazel test` to run a Puppeteer test, e.g.:
```
$ bazel test //golden/modules/dots-sk:dots-sk_puppeteer_test
```
To view the screenshots captured by a Puppeteer test, use the `//:puppeteer_screenshot_server`
target:
```
$ bazel run //:puppeteer_screenshot_server
...
Serving Puppeteer screenshots viewer at: http://<hostname>:8000
```
To extract the screenshots captured by a Puppeteer test into a directory, use the
`//:extract_puppeteer_screenshots` target:
```
$ mkdir /tmp/screenshots
$ bazel run //:extract_puppeteer_screenshots -- --output_dir /tmp/screenshots
```
To step through a Puppeteer test with a debugger, run your test with `bazel run`, and append
`_debug` at the end of the target name, e.g.:
```
# Normal test execution (for reference).
$ bazel test //golden/modules/dots-sk:dots-sk_puppeteer_test
# Test execution in debug mode.
$ bazel run //golden/modules/dots-sk:dots-sk_puppeteer_test_debug
```
This will print a URL to stdout that you can use to attach a Node.js debugger (such as the VS Code
Node.js debugger, or Chrome DevTools). Your test will wait until a debugger is attached before
continuing.
Example debug session with Chrome DevTools:
1. Add one or more `debugger` statements in your test code to set breakpoints, e.g.:
```
// //golden/modules/dots-sk/dots-sk_puppeteer_test.ts
describe('dots-sk', () => {
it('should do something', () => {
debugger;
...
});
});
```
2. Run `bazel run //golden/modules/dots-sk:dots-sk_puppeteer_test_debugger`.
3. Launch Chrome **in the machine where the test is running**, otherwise Chrome won't see the
Node.js process associated to your test.
4. Enter `chrome://inspect` in the URL bar, then press return.
5. You should see an "inspect" link under the "Remote Target" heading.
6. Click that link to launch a Chrome DevTools window attached to your Node.js process.
7. Click the "Resume script execution" button (looks like a play/pause icon).
8. Test execution should start, and eventually pause at your `debugger` statement.
By default, Puppeteer starts a Chromium instance in headless mode. If you would like to run your
test in headful mode, invoke your test with `bazel run`, and append `_debug_headful` at the end of
the target name, e.g.:
```
$ bazel run //golden/modules/dots-sk:dots-sk_puppeteer_test_debug_headful
```
Run your test in headful mode to visually inspect how your test interacts with the demo page under
test as you step through your test code with the attached debugger.
#### NodeJS tests (`nodejs_test` rule)
Use `bazel test` to run a NodeJS test, e.g.:
```
$ bazel test //puppeteer-tests:util_nodejs_test
```
## General testing tips
The below tips apply to all Bazel test targets (e.g. `go_test`, `karma_test`, etc.).
### Test output
By default, Bazel omits the standard output of tests (e.g. `fmt.Println("Hello")`).
Use flag `--test_output=all` to see the full output of your tests:
```
$ bazel test //perf/... --test_output=all
```
Note that Bazel runs tests in parallel, so it will only print out their output once all tests have
finished running.
Flag `--test_output=errors` can be used to only print out the output of failing tests.
To see the tests' output in real time, use flag `--test_output=streamed`. Note however that this
forces serial execution of tests, so this can be significantly slower.
### Caching
Bazel caches successful test runs, and reports `(cached) PASSED` on subsequent `bazel test`
invocations, e.g.:
```
$ bazel test //go/util:util_test
...
//go/util:util_test PASSED in 0.1s
$ bazel test //go/util:util_test
...
//go/util:util_test (cached) PASSED in 0.1s
```
To disable caching, use flag `--nocache_test_results`, e.g.
```
$ bazel test //go/util:util_test
...
//go/util:util_test (cached) PASSED in 0.1s
$ bazel test //go/util:util_test --nocache_test_results
...
//go/util:util_test PASSED in 0.1s
```
### Flaky tests
Flaky tests can cause the CI to fail (see [Bazel CI tasks](#bazel-ci-tasks)).
Tests can be marked as flaky via the `flaky` argument, e.g.:
```
go_test(
name = "some_flaky_test",
srcs = ["some_flaky_test.go"],
flaky = True,
...
)
```
Bazel will execute tests marked as flaky up to three times, and report test failure only if the
three attempts fail.
Using `flaky` is generally discouraged, but can be useful until the root cause of the flake is
diagnosed (see [Debugging flaky tests](#debugging-flaky-tests)) and fixed.
As a last resort, consider marking your flaky test as manual (see [Manual tests](#manual-tests)).
More on the `flaky` attribute
[here](https://docs.bazel.build/versions/main/be/common-definitions.html#common-attributes-tests).
### Debugging flaky tests
While `--nocache_test_results` can be useful for debugging flaky tests, flag `--runs_per_test` was
specifically added for this purpose. Example:
```
$ bazel test //path/to:some_flaky_test --runs_per_test=10
...
//path/to:some_flaky_test FAILED in 4 out of 10 in 0.1s
```
### Manual tests
Manual tests are excluded from Bazel wildcards such as `bazel test //...`.
To mark a test target as manual, use the `manual` tag, e.g.:
```
nodejs_test(
name = "some_manual_nodejs_test",
src = "some_manual_nodejs_test.ts",
tags = ["manual"],
...
)
```
Note that the instructions to mark `go_test` targets as manual are different. See
[Manual Go tests](#manual-go-tests) for more.
Note that manual tests are excluded from the [Bazel CI tasks](#bazel-ci-tasks).
More on manual tests and Bazel tags
[here](https://docs.bazel.build/versions/main/be/common-definitions.html#common-attributes).
### Test timeouts
By default, Bazel will report `TIMEOUT` if the test does not finish within 5 minutes. This can be
overridden via the `--test_timeout` flag, e.g.
`$ bazel test //go/util:slow_test --test_timeout=20`
This can also be overridden via the `timeout` and `size` arguments of the test target, e.g.
```
go_test(
name = "my_test",
srcs = ["my_test.go"],
timeout = "long",
....
)
```
More on how to handle timeouts and slow tests
[here](https://docs.bazel.build/versions/master/be/common-definitions.html#test.timeout).
### Passing command-line flags to test binaries
Use flag `--test_arg` to pass flags to the binary produced by a test target.
For example, our `go_test` targets define custom command-line flags such as
`flag.Bool("logtostderr", ...)`. This flag can be enabled with `--test_arg`, e.g.:
```
$ bazel test //go/util:util_test --test_arg=-logtostderr
```
As an alternative, command-line flags can be specified via the `args` argument of the Bazel test
target, as follows:
```
go_test(
name = "my_test",
srcs = ["my_test.go],
args = ["-logtostderr"],
...
)
```
More on test arguments
[here](https://docs.bazel.build/versions/master/be/common-definitions.html#test.args).
### Overriding environment variables
By default, Bazel isolates test targets from the host system's environment variables, and sets the
environment with a number of variables with Bazel-specific information that some `*_test` rules
depend on (documented
[here](https://docs.bazel.build/versions/main/test-encyclopedia.html#initial-conditions)).
Use flag `--test_env` to specify any environment variables, e.g.
```
$ bazel test //path/to:my_cockroachdb_test --test_env=COCKROACHDB_EMULATOR_STORE_DIR=/tmp/crdb
```
To pipe through an environment variable from the host's system:
```
$ export COCKROACHDB_EMULATOR_STORE_DIR=/tmp/crdb
$ bazel test //path/to:my_cockroachdb_test --test_env=COCKROACHDB_EMULATOR_STORE_DIR
```
More on the `--test_env` flag
[here](https://docs.bazel.build/versions/main/command-line-reference.html#flag--test_env).
### Faster Sandboxing
By default, Bazel [sandboxes](https://docs.bazel.build/versions/main/sandboxing.html)
every build step. Effectively, it runs the compile command with only the given source files for a
particular rule and the specified dependencies visible, to force all dependencies to be
properly listed.
For steps that have a lot of files, this can have a bit of I/O overhead. To speed this up, one
can use tempfs (e.g. a RAM disk) for the sandbox by adding `--sandbox_base=/dev/shm` to the build
command. When compiling Skia, for example, this reduces compile time by 2-3x.
Sandboxing can make diagnosing failing rules a bit harder. To see what command got run and to be
able to view the sandbox after failure, add `--subcommands --sandbox_debug` to the command.
### BUILD.bazel file debugging
Bazel builds fast and correct by making use of cached outputs and reusing them when
the input file is identical. This can make it hard to debug a slow or non-deterministic
build.
To get a detailed log of all the actions your build is taking:
1. Add the following to your .bazelrc
```
# ensure there are no disk cache hits
build --disk_cache=/path/to/debugging/cache
# IMPORTANT Generate execution logs
build --experimental_execution_log_file=yourLogFile.log
```
2. Run `bazel clean --expunge`. We want all actions to get executed, so nothing cached.
3. Look at the yourLogFile.log, it will contain a record of every action bazel executed,
environment variables, command line, input files, and output files of every action.
### Querying
[Bazel has a query feature](https://bazel.build/query/quickstart) that lets one extract
information from the build graph.
There's a `query` and `cquery` variant that lets one query for the maximal set of information
or the information in one specific case, respectively.
For example:
```
# Show all possible build flags (e.g. defines, copts) and other information about a label
bazel query 'kind("rule", //:skia_public)' --output xml
# Show the build flags for this specific build configuration (release)
bazel cquery 'kind("rule", //:skia_public)' --output jsonproto --config=release
```
This type of [querying is used extensively to generate .gni and CMakefiles](https://github.com/google/skia/blob/cf1fad655769f3e1a47a7b6d876efb0d7c5e0efa/bazel/exporter/bazel_query_command.go#L76-L116).