See Bazel at Sourcegraph for general bazel info/setup. See Overview of the Bazel configuration for client for in-depth configuration overview.
The sourcegraph client projects are setup to compile, bundle and test with Bazel. The tools used within Bazel include:
- Esbuild for bundling
- Vitest, Mocha for testing
- Node tools such as graphql-codegen for generating graphql schema types
The Bazel rulesets used to support these include:
See Aspect rules docs for more information on the Bazel rulesets used.
The primary Bazel targets have been configured roughly aligning with the pnpm workspace projects, while often composed of many sub-targets. The primary targets for client/*
pnpm projects are generated using bazel configure
. The primary targets include:
:{name}_pkg
for the npm package representing the pnpm project:test
for the Vitest unit tests of the project:{name}_lib
for compiling non-test*.ts\[x\]
files:{name}_tests
for compiling unit test*.ts\[x\]
files
Other targets may be configured per project such as sass compilation, graphql schema generation etc. See client/*/BUILD.bazel
files for more details and examples.
The srcs
and deps
attributes of the prmiary targets are generated by bazel configure
and any manual changes to those attributes will normally be overriden. If manual files/deps must be specified they must end with a # keep
comment to ensure bazel configure
does not remove them. Currently typescript type-only imports are not supported by bazel configure
and must be manually added to the deps
attribute, see aspect-build/aspect-cli#404.
Additional BUILD.bazel
files may exist throughout subdirectories and is encouraged to create many smaller independently cacheable targets.
All client tests (of all types such as Vitest and mocha) can be invoked by bazel test //client/...
or individual tests can be specified such as bazel test //client/common:test
or bazel test //client/web/src/end-to-end:e2e
. Vitest tests can be debugged using bazel run --config=debug //client/common:test
.
The primary client/web
bundle target is //client/web:bundle
. See client/web/BUILD.bazel
.
Most rules used throughout client/*
are macros defined in dev/*.bzl
to provide a consistent configuration used throughout the repo.
I encountered "bazel configure" failures on CI, and I'm not sure how to debug and fix the issue. What steps should I follow to resolve this?
- Examine the Bazel output logs: Scroll through and parse the Bazel output logs to find any reported errors, particularly missing modules or type declarations.
- Compare local and CI environments: Run the same failing test locally (e.g.,
bazel test //client/web:web_lib_typecheck_test
) and compare the results with those on CI. This can help identify discrepancies between the two environments. - Check for missing types: If you see errors related to missing types or modules in the Bazel logs, it's possible that some required dependencies are missing from your Bazel build file. To fix this, manually add the missing dependencies to the
deps
attribute in your primary target and include a# keep
comment to preventbazel configure
from removing them. Be aware thatbazel configure
currently does not support TypeScript type-only imports, and these dependencies need to be added manually (see aspect-build/aspect-cli#404). - Update the Bazel configuration: Run
bazel configure
to update your Bazel build configuration. Note that thesrcs
anddeps
attributes of the primary targets are generated bybazel configure
, and any manual changes to those attributes without the # keep comment will be overridden. - Leverage additional BUILD.bazel files: You can create additional
BUILD.bazel
files in subdirectories to break down your project into smaller, independently cacheable targets. This can help improve build performance and simplify your build configuration.
Lets say I want to execute a js binary called rawr
. rules_js
generates Starlark APIs for all dependencies defined in package
.json, so to import the generated api for rawr
we can do:
load("@npm//:rawr/package_json.bzl", my_alias = "bin")
With the above statement rules_js
generated the following targets for rawr
:
rawr
for use withbazel build
(js_binary + js_run_binary internally)rawr_binary
for use withbazel run
(js_binary internally)rawr_test
for use withbazel test
(js_test internally)
See the generated macro implementation here for more details.
Cool? I mean we technically have rawr
now available but HTF do we use this? To create a build target using rawr
we can now do:
my_alias.rawr (
# js_binary attributes
name = "rawr_event"
srcs = ["earth.js],
args = ["-event", "asteroid"],
)
To create a test target using rawr we can do (note the _test suffix):
my_alias.rawr_test (
# js_test attributes
name = "rawr_event_test"
srcs = ["earth.js],
args = ["-event", "asteroid", "-test"],
)
So now we have two targets that will execute the rawr
js binary with different arguments:
bazel build //:rawr_event
bazel test //:rawr_event_test
An example of a js binary being executed as a bazel test target is graphql-schema-linter
, whose definition can be found in cmd/frontend/graphqlbackend/BUILD.bazel
.
Using Bazel, you can build or test specific targets across all client packages. This can be done by leveraging Bazel's query
and test
commands.
The test
command is used to build and run all test targets. However, with the help of query
, we can filter out the specific targets we want to build and test.
For example, to check all Typescript types across all client packages locally, use:
bazel test `bazel query 'attr("name", ".*_typecheck_test", //...)'`
bazel test
: Commands Bazel to build and run specified test targets.bazel query 'attr("name", ".*_typecheck_test", //...)'
: Sub-command that specifies the targets for test. It queries for all targets whose name ends with_typecheck_test
in all packages (//...
).
If you want to run tests for a specific package, replace //...
with the package path like //client/vscode...
.
bazel test `bazel query 'attr("name", ".*_typecheck_test", //client/vscode...)'`
Similar to the above, we can use bazel query to find all target names ending with _eslint
and test them:
bazel test `bazel query 'attr("name", ".*_eslint$", //client/wildcard/...)'`