Follow unconfigured `alias`es during options parsing
Fixes #20582
RELNOTES: Starlark command-line flags can now be referred to through `alias` targets.
Closes #22192.
PiperOrigin-RevId: 629865954
Change-Id: I6215c8484ddc08e75507191bfa1eb5bc709c5fc6
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java
index e36f782..3375361 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkOptionsParsingTest.java
@@ -567,4 +567,146 @@
.hasMessageThat()
.contains("//test:all: user-defined flags must reference exactly one target");
}
+
+ @Test
+ public void flagIsAlias() throws Exception {
+ scratch.file(
+ "test/build_setting.bzl",
+ """
+ string_flag = rule(
+ implementation = lambda ctx: [],
+ build_setting = config.string(flag = True),
+ )
+ """);
+ scratch.file(
+ "test/BUILD",
+ """
+ load("//test:build_setting.bzl", "string_flag")
+
+ alias(
+ name = "one",
+ actual = "//test/pkg:two",
+ )
+
+ string_flag(
+ name = "three",
+ build_setting_default = "",
+ )
+ """);
+ scratch.file(
+ "test/pkg/BUILD",
+ """
+ alias(
+ name = "two",
+ actual = "//test:three",
+ )
+ """);
+
+ OptionsParsingResult result = parseStarlarkOptions("--//test:one=one --//test/pkg:two=two");
+
+ assertThat(result.getStarlarkOptions()).containsExactly("//test:three", "two");
+ }
+
+ @Test
+ public void flagIsAlias_cycle() throws Exception {
+ scratch.file(
+ "test/BUILD",
+ """
+ alias(
+ name = "one",
+ actual = "//test/pkg:two",
+ )
+
+ alias(
+ name = "three",
+ actual = ":one",
+ )
+ """);
+ scratch.file(
+ "test/pkg/BUILD",
+ """
+ alias(
+ name = "two",
+ actual = "//test:three",
+ )
+ """);
+
+ OptionsParsingException e =
+ assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:one=one"));
+
+ assertThat(e)
+ .hasMessageThat()
+ .isEqualTo(
+ "Failed to load build setting '//test:one' due to a cycle in alias chain: //test:one"
+ + " -> //test/pkg:two -> //test:three -> //test:one");
+ }
+
+ @Test
+ public void flagIsAlias_usesSelect() throws Exception {
+ scratch.file(
+ "test/BUILD",
+ """
+ alias(
+ name = "one",
+ actual = "//test/pkg:two",
+ )
+
+ alias(
+ name = "three",
+ actual = ":one",
+ )
+ """);
+ scratch.file(
+ "test/pkg/BUILD",
+ """
+ alias(
+ name = "two",
+ actual = select({"//conditions:default": "//test:three"}),
+ )
+ """);
+
+ OptionsParsingException e =
+ assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:one=one"));
+
+ assertThat(e)
+ .hasMessageThat()
+ .isEqualTo(
+ "Failed to load build setting '//test:one' as it resolves to an alias with an actual"
+ + " value that uses select(): //test:one -> //test/pkg:two. This is not supported"
+ + " as build settings are needed to determine the configuration the select is"
+ + " evaluated in.");
+ }
+
+ @Test
+ public void flagIsAlias_resolvesToNonBuildSettingTarget() throws Exception {
+ scratch.file(
+ "test/BUILD",
+ """
+ alias(
+ name = "one",
+ actual = "//test/pkg:two",
+ )
+
+ genrule(
+ name = "three",
+ outs = ["out"],
+ cmd = "echo hello > $@",
+ )
+ """);
+ scratch.file(
+ "test/pkg/BUILD",
+ """
+ alias(
+ name = "two",
+ actual = "//test:three",
+ )
+ """);
+
+ OptionsParsingException e =
+ assertThrows(OptionsParsingException.class, () -> parseStarlarkOptions("--//test:one=one"));
+
+ assertThat(e)
+ .hasMessageThat()
+ .isEqualTo("Unrecognized option: //test:one -> //test/pkg:two -> //test:three");
+ }
}