You can create different environments (e.g., testing, prod, mobile, rainforest) with Bazel, then use them to make sure that targets only build with the right environment. This is a cool feature that’s undocumented (because it’s still in development, shhhhh, don’t tell anyone I told you about it).
Let’s say you have a prod SSH key that you don’t want used in development or test builds. You could restrict it to only be used in prod builds by defining the following:
environment(name = "dev")
environment(name = "prod")
environment(name = "testing")
environment_group(
name = "buildenv",
defaults = ["dev"],
environments = [
"dev",
"prod",
"testing",
],
)
filegroup(
name = "ssh-key",
restricted_to = [":prod"],
srcs = ["key"],
)
Now whenever we use :ssh-key
, it has to be in a prod
-environment rule. For example, this works:
cc_binary(
name = "prod-job",
srcs = ["job.cc"],
restricted_to = [":prod"],
data = ["ssh-key"],
)
This doesn’t:
cc_test(
name = "job-test",
srcs = ["job_test.cc"],
data = [":ssh-key"],
)
Building the second one gives:
$ bazel build :job-test
ERROR: /Users/kchodorow/test/a/BUILD:34:1: in cc_test rule //:job-test: dependency //:ssh-key doesn't support expected environment: //:dev.
ERROR: Analysis of target '//:job-test' failed; build aborted.
INFO: Elapsed time: 0.167s
Hopefully, if someone tried to add restricted_to = [":prod"]
to a test, it’d “look wrong” and be easier to catch.
Note that you must set your defaults sanely: when I first tried this, I made the environment_group
‘s defaults = ["prod"]
and then was confused that I wasn’t getting any errors. Everything is built for the default environments unless specified otherwise!
This lets us say: “If a
depends on b
and b
is restricted to a certain environment, then a
must be restricted to the environment.” However, there is another direction to look at this from: if a
is restricted to an environment, b
must be compatible with that environment. To express this, you can use “compatible_with
“:
filegroup(
name = "dev-key",
srcs = ["key.dev"],
compatible_with = [
":dev",
":testing"
],
)
Now anything that’s restricted to “:dev” or “:testing” environments can depend on “:dev-key”. For example, these work:
cc_binary(
name = "dev-job",
srcs = ["job.cc"],
data = [":dev-key"],
)
cc_test(
name = "job-test",
srcs = ["job_test.cc"],
restricted_to = [":testing"],
data = [":dev-key"],
)
This does not:
cc_binary(
name = "prod-job",
srcs = ["job.cc"],
restricted_to = [":prod"],
data = [":dev-key"],
)
The full matrix (assuming env
is an environment) is:
|
b |
b restricted to env |
b compatible with env |
a |
✓ |
✗ |
✓ |
a restricted to env |
✗ |
✓ |
✓ |
a compatible with env |
✗ |
✗ |
✓ |
Remember that environments are targets themselves, so avoid proliferating environments that aren’t global to the global scope (don’t make them publicly visible and keep them as private as possible).