From 443f8bdfd70ca7d9460e180fef14e225609ae785 Mon Sep 17 00:00:00 2001 From: Maxwell Elliott Date: Tue, 3 Nov 2026 14:25:08 -0500 Subject: [PATCH 1/2] Reproducer for #612: main-repository aliases dropped under cquery Adds the cquery_main_repo_alias fixture (a genrule whose only src is an alias of a filegroup in another package) and two e2e cases. The query-mode control passes; the cquery case fails on master because the compatible-target cquery names the alias by repr(target), which Bazel prints as the apparent label //:tool while the target is named @@//:tool, so the alias is filtered out as if it were platform-incompatible and //:wrapper loses its edge through it. Co-Authored-By: Claude Fable 5.1 --- tests/e2e/regressions.rs | 81 +++++++++++++++++++ .../cquery_main_repo_alias/BUILD.bazel | 14 ++++ .../cquery_main_repo_alias/MODULE.bazel | 4 + .../cquery_main_repo_alias/README.md | 25 ++++++ .../cquery_main_repo_alias/bar/BUILD.bazel | 5 ++ .../cquery_main_repo_alias/bar/baz.txt | 1 + tools/e2e/rust_e2e_cases.bzl | 8 ++ 7 files changed, 138 insertions(+) create mode 100644 tests/resources/workspaces/cquery_main_repo_alias/BUILD.bazel create mode 100644 tests/resources/workspaces/cquery_main_repo_alias/MODULE.bazel create mode 100644 tests/resources/workspaces/cquery_main_repo_alias/README.md create mode 100644 tests/resources/workspaces/cquery_main_repo_alias/bar/BUILD.bazel create mode 100644 tests/resources/workspaces/cquery_main_repo_alias/bar/baz.txt diff --git a/tests/e2e/regressions.rs b/tests/e2e/regressions.rs index 6da59472..dbe91f5f 100644 --- a/tests/e2e/regressions.rs +++ b/tests/e2e/regressions.rs @@ -1259,3 +1259,84 @@ fn serve_rejects_packages_the_revision_does_not_track() { assert!(labels.is_superset(&expected_after_deletion()), "{labels:?}"); } } + +/// Control for : in query mode a change +/// behind a main-repository `alias` reaches the target that uses the alias. +#[test] +fn main_repo_alias_change_reaches_consumer_query() { + let first = copy_workspace("cquery_main_repo_alias"); + let second = copy_workspace("cquery_main_repo_alias"); + fs::write(second.path().join("bar/baz.txt"), "after\n").unwrap(); + let impacted = diff_workspaces(first.path(), second.path(), &[]); + for name in ["//bar:baz.txt", "//bar:baz", "//:tool", "//:wrapper"] { + assert!( + impacted + .iter() + .any(|label| label == name || label.trim_start_matches("@@") == name), + "{name} should be impacted through the alias, got {impacted:?}" + ); + } +} + +/// Reproducer for : under `--useCquery` +/// the compatible-target cquery names a main-repository alias by `repr(target)`, which +/// Bazel prints with its apparent label (`//:tool`) even under `--consistent_labels`, +/// while the target itself is named canonically (`@@//:tool`). The two never match, so +/// the alias is filtered out as if it were platform-incompatible and takes its edges with +/// it: `//:wrapper` has no node for `//:tool` to depend on and is never impacted. +#[test] +fn main_repo_alias_change_reaches_consumer_cquery() { + let first = copy_workspace("cquery_main_repo_alias"); + let second = copy_workspace("cquery_main_repo_alias"); + fs::write(second.path().join("bar/baz.txt"), "after\n").unwrap(); + + let output = tempfile::tempdir().unwrap(); + let from = output.path().join("from.json"); + let to = output.path().join("to.json"); + let edges_file = output.path().join("edges.json"); + let result = output.path().join("impacted.txt"); + assert!(generate(first.path(), &from, &["--useCquery"]) + .status + .success()); + assert!(generate( + second.path(), + &to, + &[ + "--useCquery", + "--depEdgesFile", + edges_file.to_str().unwrap() + ], + ) + .status + .success()); + assert!(impacted(second.path(), &from, &to, &result, &[]) + .status + .success()); + + let hashes = hashes(&to); + assert!( + hashes.keys().any(|label| label.ends_with("//:tool")), + "the alias //:tool was dropped from the cquery hashes: {:?}", + hashes.keys().collect::>() + ); + let edges = dep_edges(&edges_file); + let wrapper_edges = edges + .iter() + .find(|(label, _)| label.ends_with("//:wrapper")) + .map(|(_, deps)| deps.clone()) + .expect("//:wrapper has dep edges"); + assert!( + wrapper_edges.iter().any(|dep| dep.ends_with("//:tool")), + "//:wrapper lost its edge to the alias //:tool: {wrapper_edges:?}" + ); + + let impacted = read_lines(&result); + for name in ["//bar:baz.txt", "//bar:baz", "//:tool", "//:wrapper"] { + assert!( + impacted + .iter() + .any(|label| label == name || label.trim_start_matches("@@") == name), + "{name} should be impacted through the alias under cquery, got {impacted:?}" + ); + } +} diff --git a/tests/resources/workspaces/cquery_main_repo_alias/BUILD.bazel b/tests/resources/workspaces/cquery_main_repo_alias/BUILD.bazel new file mode 100644 index 00000000..a03cb29a --- /dev/null +++ b/tests/resources/workspaces/cquery_main_repo_alias/BUILD.bazel @@ -0,0 +1,14 @@ +# A main-repository alias in front of the file that changes. `//:wrapper` +# reaches `bar/baz.txt` only through the alias, so it must be impacted when +# the file changes. +alias( + name = "tool", + actual = "//bar:baz", +) + +genrule( + name = "wrapper", + srcs = [":tool"], + outs = ["wrapper.txt"], + cmd = "cat $(SRCS) > $@", +) diff --git a/tests/resources/workspaces/cquery_main_repo_alias/MODULE.bazel b/tests/resources/workspaces/cquery_main_repo_alias/MODULE.bazel new file mode 100644 index 00000000..4e5587d4 --- /dev/null +++ b/tests/resources/workspaces/cquery_main_repo_alias/MODULE.bazel @@ -0,0 +1,4 @@ +module( + name = "cquery_main_repo_alias", + version = "0.0.0", +) diff --git a/tests/resources/workspaces/cquery_main_repo_alias/README.md b/tests/resources/workspaces/cquery_main_repo_alias/README.md new file mode 100644 index 00000000..11dc4456 --- /dev/null +++ b/tests/resources/workspaces/cquery_main_repo_alias/README.md @@ -0,0 +1,25 @@ +# Main-repository alias under cquery + +Reproduces [GitHub Issue #612](https://github.com/Tinder/bazel-diff/issues/612): +with `--useCquery`, a target that reaches its inputs through a main-repository +`alias` stops seeing changes to them. + +## The graph + +`//:wrapper` (a `genrule`) lists `//:tool` in its `srcs`. `//:tool` is an +`alias` of `//bar:baz`, a `filegroup` over `bar/baz.txt`. + +## Expected behaviour + +Changing `bar/baz.txt` impacts `//bar:baz.txt`, `//bar:baz`, `//:tool`, +`//:wrapper` and `//:wrapper.txt`, in query mode and in cquery mode alike. + +## Behaviour before the fix + +The compatible-target cquery that filters out `IncompatiblePlatformProvider` +targets names an alias by `repr(target)`, and Bazel prints a main-repository +alias with its apparent label (`//:tool`) even under `--consistent_labels`, +while every other target is canonical (`@@//:tool`). The two never match, so +the alias is dropped as if it were incompatible, and with it every edge from +`//:wrapper` through it. Under cquery only `@@//bar:baz` and `@@//bar:baz.txt` +are reported as impacted. diff --git a/tests/resources/workspaces/cquery_main_repo_alias/bar/BUILD.bazel b/tests/resources/workspaces/cquery_main_repo_alias/bar/BUILD.bazel new file mode 100644 index 00000000..e31cb197 --- /dev/null +++ b/tests/resources/workspaces/cquery_main_repo_alias/bar/BUILD.bazel @@ -0,0 +1,5 @@ +filegroup( + name = "baz", + srcs = ["baz.txt"], + visibility = ["//visibility:public"], +) diff --git a/tests/resources/workspaces/cquery_main_repo_alias/bar/baz.txt b/tests/resources/workspaces/cquery_main_repo_alias/bar/baz.txt new file mode 100644 index 00000000..90be1f30 --- /dev/null +++ b/tests/resources/workspaces/cquery_main_repo_alias/bar/baz.txt @@ -0,0 +1 @@ +before diff --git a/tools/e2e/rust_e2e_cases.bzl b/tools/e2e/rust_e2e_cases.bzl index 14ac6d94..c4daaa2c 100644 --- a/tools/e2e/rust_e2e_cases.bzl +++ b/tools/e2e/rust_e2e_cases.bzl @@ -223,6 +223,14 @@ RUST_E2E_SUITES = [ "name": "regressions::macro_bzl_change_impacts_callers", "timeout": "moderate", }, + { + "name": "regressions::main_repo_alias_change_reaches_consumer_cquery", + "timeout": "moderate", + }, + { + "name": "regressions::main_repo_alias_change_reaches_consumer_query", + "timeout": "moderate", + }, { "name": "regressions::module_comment_and_lock_reformat_are_noops", "timeout": "moderate", From d460390c031a63e4c56746f9c3a0a9ef742e9118 Mon Sep 17 00:00:00 2001 From: Maxwell Elliott Date: Tue, 3 Nov 2026 14:28:10 -0500 Subject: [PATCH 2/2] Fix #612: name main-repository aliases canonically in the compatible-target cquery The compatible-target cquery names an alias by repr(target), and Bazel prints a main-repository alias with its apparent label (//:tool) even under --consistent_labels, while every other target is canonical (@@//:tool). The compatible set therefore never contained the alias's canonical label and query_compatible_labels filtered it out as if it were platform-incompatible, dropping every edge through it. Prefix @@ to apparent main-repository labels so the alias matches. Co-Authored-By: Claude Fable 5.1 --- src/bazel.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bazel.rs b/src/bazel.rs index c5b1abc4..4691e2b4 100644 --- a/src/bazel.rs +++ b/src/bazel.rs @@ -1552,7 +1552,14 @@ impl BazelOptions { if "IncompatiblePlatformProvider" not in providers(target): target_repr = repr(target) if "