Skip to content

Fix #326: filter //external:* labels from impacted-targets output on bzlmod#334

Merged
tinder-maxwellelliott merged 1 commit intomasterfrom
fix-326-external-targets-in-impacted-output
Apr 27, 2026
Merged

Fix #326: filter //external:* labels from impacted-targets output on bzlmod#334
tinder-maxwellelliott merged 1 commit intomasterfrom
fix-326-external-targets-in-impacted-output

Conversation

@tinder-maxwellelliott
Copy link
Copy Markdown
Collaborator

@tinder-maxwellelliott tinder-maxwellelliott commented Apr 27, 2026

Summary

Closes #326.

On Bazel 8.6.0+ in bzlmod-only mode (--enable_workspace=false), bazel-diff get-impacted-targets was emitting synthetic //external:<apparent_name> labels created by BazelClient.queryAllTargets()BazelQueryService.queryBzlmodRepos(). Feeding the output to downstream bazel build failed with no such package 'external': //external package is not available since the WORKSPACE file is disabled. The synthetic labels are required during generate-hashes to detect bzlmod dep version changes (#322), but they should never reach the user-facing impacted-targets output. The existing --excludeExternalTargets flag on generate-hashes only suppressed the legacy WORKSPACE-style //external:all-targets query — it did not affect the bzlmod synthetic targets, which is why both reporters in the issue thread had to fall back to grep -v //external.

This PR adds the same flag to get-impacted-targets, filters //external:* labels at the output stage, and auto-defaults the flag to true whenever BazelModService.isBzlmodEnabled returns true (matching the auto-default behavior already in generate-hashes). Users can opt back into the legacy behavior with --no-excludeExternalTargets.

Changes

  • GetImpactedTargetsCommand.kt: new --excludeExternalTargets (negatable) Picocli option with bzlmod auto-default resolved at runtime via Koin.
  • CalculateImpactedTargetsInteractor.kt: new excludeExternalTargets parameter on both execute() and executeWithDistances(); drops labels starting with //external: from output.
  • Tests: unit coverage in CalculateImpactedTargetsInteractorTest for both code paths, plus an e2e test gated on Bazel 8.6.0+ that uses the existing bzlmod-show-repo-test-{1,2} fixtures and asserts both default-on filtering and the --no-excludeExternalTargets opt-out.

Test plan

  • bazel test //cli:CalculateImpactedTargetsInteractorTest passes locally
  • All non-cquery //cli:E2ETest cases pass locally (cquery tests fail in my local sandbox due to a pre-existing JDK/coursier issue, unrelated)
  • CI green (will exercise the new e2e test on Bazel 8.x / 9.x runners)

🤖 Generated with Claude Code

…bzlmod

Synthetic //external:<apparent_name> targets created by `bazel mod show_repo`
are needed during generate-hashes (so dep changes are detected) but are not
buildable in bzlmod-only mode (Bazel 8.6.0+ with WORKSPACE disabled), causing
downstream `bazel build` of the impacted-targets file to fail with
"no such package 'external'".

Adds --excludeExternalTargets to get-impacted-targets (negatable, auto-defaults
to true when bzlmod is detected), filters those labels at the output stage,
and adds unit + e2e coverage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tinder-maxwellelliott tinder-maxwellelliott merged commit 2f6b341 into master Apr 27, 2026
15 checks passed
@tinder-maxwellelliott tinder-maxwellelliott deleted the fix-326-external-targets-in-impacted-output branch April 27, 2026 13:44
@Ahajha
Copy link
Copy Markdown
Contributor

Ahajha commented Apr 27, 2026

Thanks!

rdark added a commit to rdark/bazel-diff that referenced this pull request Apr 28, 2026
The per-repo rdeps query-failure fallback filtered out every `@@` label
on the assumption that the hash set was mostly workspace-local `//...`
targets. That assumption does not hold on bzlmod-only workspaces where
`generate-hashes` emits almost entirely `@@canonical` labels plus a
small number of `//external:<apparent>` bzlmod-synthetic bridges, with
zero workspace-local targets.

On such workspaces, a single failed `rdeps(//..., @@<repo>//...)` query
(for example, one caused by an unrelated loading error elsewhere in the
dep graph) left the filter with only the `//external:*` bridges, which
the downstream `excludeExternalTargets=true` default (Tinder#334) then strips
entirely — producing silently-empty impacted output on what should be a
"conservatively rebuild everything" signal.

Mirror the outer catch at line 401 and mark every hashed target as
impacted on per-repo query failure. Downstream filters (`targetTypes`,
`excludeExternalTargets`) remain the caller's responsibility, which is
the whole point of surfacing the full set upstream.

Add a regression test in CalculateImpactedTargetsInteractorModuleQueryTest
that constructs a bzlmod-shaped hash set (two `@@abseil-cpp+` targets +
one `//external:*` bridge, no workspace targets), stubs
`queryService.query` to throw, and asserts all three labels appear in
the output.
rdark added a commit to rdark/bazel-diff that referenced this pull request Apr 28, 2026
The unioned rdeps query-failure fallback filtered out every `@@` label
on the assumption that the hash set was mostly workspace-local `//...`
targets. That assumption does not hold on bzlmod-only workspaces where
`generate-hashes` emits almost entirely `@@canonical` labels plus a
small number of `//external:<apparent>` bzlmod-synthetic bridges, with
zero workspace-local targets.

On such workspaces, a query failure (for example, one caused by an
unrelated loading error elsewhere in the dep graph) left the filter
with only the `//external:*` bridges, which the downstream
`excludeExternalTargets=true` default (Tinder#334) then strips entirely —
producing silently-empty impacted output on what should be a
"conservatively rebuild everything" signal.

Mark every hashed target as impacted on query failure. Downstream
filters (`targetTypes`, `excludeExternalTargets`) remain the caller's
responsibility, which is the whole point of surfacing the full set
upstream.

Add a regression test that constructs a bzlmod-shaped hash set (two
`@@abseil-cpp+` targets + one `//external:*` bridge, no workspace
targets), stubs `queryService.query` to throw, and asserts all three
labels appear in the output.
rdark added a commit to rdark/bazel-diff that referenced this pull request Apr 28, 2026
The per-repo rdeps query-failure fallback filtered out every `@@` label
on the assumption that the hash set was mostly workspace-local `//...`
targets. That assumption does not hold on bzlmod-only workspaces where
`generate-hashes` emits almost entirely `@@canonical` labels plus a
small number of `//external:<apparent>` bzlmod-synthetic bridges, with
zero workspace-local targets.

On such workspaces, a single failed `rdeps(//..., @@<repo>//...)` query
(for example, one caused by an unrelated loading error elsewhere in the
dep graph) left the filter with only the `//external:*` bridges, which
the downstream `excludeExternalTargets=true` default (Tinder#334) then strips
entirely — producing silently-empty impacted output on what should be a
"conservatively rebuild everything" signal.

Replace the unconditional `!startsWith("@@")` filter with a shape-aware
fallback:

  - Compute a "buildable workspace" set that excludes BOTH `@@canonical`
    transitives AND `//external:<apparent>` bridges.
  - If that set is non-empty (mixed WORKSPACE + bzlmod, or WORKSPACE-only
    shapes), emit it — preserves pre-existing granularity, avoids leaking
    tens of thousands of `@@` transitives into the impacted set on a
    single flaky `bazel query`.
  - If it is empty (bzlmod-only shape), fall through to `allTargets.keys`
    so the downstream filter has something to keep — rebuild-everything
    signal rather than a directly-buildable label list.

Adds a mixed-shape regression test asserting that `@@` transitives and
`//external:*` bridges do NOT leak into the fallback when buildable
workspace labels are present, complementing the existing bzlmod-only
test. An unconditional `allTargets.keys` fallback fails the new test;
the pre-commit `!startsWith("@@")` filter fails the existing bzlmod-only
one. Only the shape-aware fallback passes both.
rdark added a commit to rdark/bazel-diff that referenced this pull request Apr 28, 2026
The per-repo rdeps query-failure fallback filtered out every `@@` label
on the assumption that the hash set was mostly workspace-local `//...`
targets. That assumption does not hold on bzlmod-only workspaces where
`generate-hashes` emits almost entirely `@@canonical` labels plus a
small number of `//external:<apparent>` bzlmod-synthetic bridges, with
zero workspace-local targets.

On such workspaces, a single failed `rdeps(//..., @@<repo>//...)` query
(for example, one caused by an unrelated loading error elsewhere in the
dep graph) left the filter with only the `//external:*` bridges, which
the downstream `excludeExternalTargets=true` default (Tinder#334) then strips
entirely — producing silently-empty impacted output on what should be a
"conservatively rebuild everything" signal.

Replace the unconditional `!startsWith("@@")` filter with a shape-aware
fallback:

  - Compute a "buildable workspace" set that excludes BOTH `@@canonical`
    transitives AND `//external:<apparent>` bridges.
  - If that set is non-empty (mixed WORKSPACE + bzlmod, or WORKSPACE-only
    shapes), emit it — preserves pre-existing granularity, avoids leaking
    tens of thousands of `@@` transitives into the impacted set on a
    single flaky `bazel query`.
  - If it is empty (bzlmod-only shape), fall through to `allTargets.keys`
    so the downstream filter has something to keep — rebuild-everything
    signal rather than a directly-buildable label list.

Adds a mixed-shape regression test asserting that `@@` transitives and
`//external:*` bridges do NOT leak into the fallback when buildable
workspace labels are present, complementing the existing bzlmod-only
test. An unconditional `allTargets.keys` fallback fails the new test;
the pre-commit `!startsWith("@@")` filter fails the existing bzlmod-only
one. Only the shape-aware fallback passes both.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v18.0.0 does not exclude //external targets in bazel 8.6.0

2 participants