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).