facebook / buck2

Build system, successor to Buck
https://buck2.build/
Apache License 2.0
3.33k stars 194 forks source link

Excluding rules from certain platforms #601

Open gsoyka opened 2 months ago

gsoyka commented 2 months ago

Hello, I'm working through a use case where we have certain rules that we want to run locally, but exclude from running on CI systems. I found this example: https://github.com/facebook/buck2/blob/8a7f7c7fca54af4be1a6b32b2d100aa0f4bca5d2/examples/with_prelude/go/hello/BUCK which uses host_info() to exclude rules, but I'm not sure if it's possible to extend this logic with a custom boolean value, for example, is_ci.

I've also attempted to access context data to determine which platform is being invoked and use that to skip the rule, but I'm not finding a way to do that either. Reading the docs, it seems like constraints added to our platform should work, but I'm unclear on how to implement that. For this use case, what is the best approach to take?

zjturner commented 2 months ago

Try this:

In your .buckconfig file:

[gsoyka]
is_ci = false

In a BUCK file somewhere:

build_go_binary = not read_config("gsoyka", "is_ci", false)

go_binary(
    name = "hello",
    srcs = glob(["*.go"]),
    deps = [
        "//go/hello/greeting:greeting",
    ],
) if build_go_binary else None
gsoyka commented 2 months ago

Thanks, that's helpful, and I think that can be made to work for my use case. If I have a rule defined, eg. my_rule(), is it possible to generalize that logic to apply to all my_rule instances within a project when the config value is set to true?

zjturner commented 2 months ago

You could make a macro. From a bzl file somewhere:

build_go_binary = not read_config("gsoyka", "is_ci", false)

def my_rule_macro(name, srcs, deps):
    go_binary(
        name = "hello",
        srcs = glob(["*.go"]),
        deps = [
            "//go/hello/greeting:greeting",
        ],
    ) if build_go_binary else None

and have people call your macro instead of your rule.

gsoyka commented 2 months ago

That makes sense to me, when I tried the example I'm seeing the behavior I want, but am getting an error about a missing symbol. Is there something the macro can return that isn't None that still does nothing?

zjturner commented 2 months ago

Try:

if build_go_binary: go_binary(…)

hard to say without seeing your error

cjhopman commented 1 month ago

Reading the docs, it seems like constraints added to our platform should work

Yeah, marking it target incompatible will cause it to be skipped without error when resolved in a pattern like //... or //foo: (but error when used explicitly like //foo:xyz).

You could actually still use the config value to set things up if you wanted, somethign like this could work:

constraint_setting(
  name = "none",
)

my_rule(
  ...
  target_compatible_with = [] if read_config("foo", "is_ci", False) else [":none"]
)