Skip to content

Commit 83b88e2

Browse files
committed
Warn for silent alias skips. Ensure all cases covered in test
Signed-off-by: Thomas Lam <thomaslam@canva.com>
1 parent ca46b02 commit 83b88e2

1 file changed

Lines changed: 192 additions & 7 deletions

File tree

crate_universe/src/rendering.rs

Lines changed: 192 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,17 @@ impl Renderer {
233233
))
234234
};
235235

236+
if context.workspace_members.contains_key(&dep.id) && maybe_actual.is_none() {
237+
tracing::warn!(
238+
"Skipping hub alias for workspace-member dep `{}-{}`: \
239+
no override_targets entry found. Add \
240+
`crate.annotation(override_target_lib = \"...\")` in MODULE.bazel \
241+
to emit a hub alias.",
242+
krate.name,
243+
krate.version,
244+
);
245+
}
246+
236247
if let Some(actual) = maybe_actual {
237248
// Avoid adding the <crate_name>-<version> alias if there are
238249
// more than 1 dependency referencing the same crate at the
@@ -286,6 +297,16 @@ impl Renderer {
286297
}
287298

288299
for (alias, target) in &krate.extra_aliased_targets {
300+
if context.workspace_members.contains_key(&dep.id) {
301+
tracing::warn!(
302+
"Skipping extra_aliased_targets alias `{alias}` for \
303+
workspace-member dep `{}-{}`: spoke repos are not \
304+
created for workspace members.",
305+
krate.name,
306+
krate.version,
307+
);
308+
continue;
309+
}
289310
dependencies.push(Alias {
290311
rule: alias_rule.rule(),
291312
name: alias.clone(),
@@ -2044,12 +2065,10 @@ mod test {
20442065
assert!(found);
20452066
}
20462067

2047-
/// Tests a situation where we have identical aliases to the crate's name on
2048-
/// the package's deps, and the dep is itself a workspace member. Because
2049-
/// workspace-member deps have no spoke repo and no override_targets["lib"]
2050-
/// is set, no hub alias should be emitted at all.
2068+
/// Tests that when a workspace-member dep is aliased under its own crate name
2069+
/// and has no `override_targets` set, no hub alias is emitted.
20512070
#[test]
2052-
fn crate_with_ambiguous_rename() {
2071+
fn workspace_member_dep_with_alias_same_as_crate_name_and_no_override() {
20532072
let mut context = Context::default();
20542073
let crate_id = CrateId::new("mock_crate".to_owned(), VERSION_ZERO_ONE_ZERO);
20552074
context
@@ -2097,11 +2116,11 @@ mod test {
20972116
let build_file_content = output.get(&PathBuf::from("BUILD.bazel")).unwrap();
20982117

20992118
println!("{build_file_content}");
2100-
// mock_crate is a workspace member dep with no override_targets["lib"],
2119+
// mock_crate is a workspace member dep with no override_targets set,
21012120
// so no hub alias should be emitted to avoid dangling spoke-repo refs.
21022121
assert!(
21032122
!build_file_content.contains("alias("),
2104-
"no alias should be emitted for workspace member dep with ambiguous rename and no override:\n{build_file_content}"
2123+
"no alias should be emitted for workspace member dep with no override:\n{build_file_content}"
21052124
);
21062125
}
21072126

@@ -2519,4 +2538,170 @@ mod test {
25192538
"no alias should be emitted for workspace member dep without override:\n{build_file_content}"
25202539
);
25212540
}
2541+
2542+
/// When a workspace-member proc-macro dep has `override_targets["proc-macro"]` set,
2543+
/// the hub alias must use that label rather than a non-existent spoke repo.
2544+
/// This exercises the `Rule::ProcMacro` arm of the `find_map` that replaced
2545+
/// the `"lib"` hardcode.
2546+
#[test]
2547+
fn hub_alias_for_workspace_member_proc_macro_dep_uses_override_target() {
2548+
let mut context = Context::default();
2549+
2550+
let consumer_id = CrateId::new("consumer".to_owned(), VERSION_ZERO_ONE_ZERO);
2551+
context
2552+
.workspace_members
2553+
.insert(consumer_id.clone(), "consumer".into());
2554+
2555+
let dep_id = CrateId::new("dep_crate".to_owned(), VERSION_ZERO_ONE_ZERO);
2556+
context
2557+
.workspace_members
2558+
.insert(dep_id.clone(), "dep_crate".into());
2559+
context.crates.insert(
2560+
dep_id.clone(),
2561+
CrateContext {
2562+
name: dep_id.name.clone(),
2563+
version: dep_id.version.clone(),
2564+
package_url: None,
2565+
targets: BTreeSet::from([Rule::ProcMacro(TargetAttributes {
2566+
crate_name: "dep_crate".to_owned(),
2567+
crate_root: Some("src/lib.rs".to_owned()),
2568+
..TargetAttributes::default()
2569+
})]),
2570+
library_target_name: Some("dep_crate".to_owned()),
2571+
common_attrs: CommonAttributes::default(),
2572+
build_script_attrs: None,
2573+
repository: None,
2574+
license: None,
2575+
license_ids: BTreeSet::default(),
2576+
license_file: None,
2577+
additive_build_file_content: None,
2578+
disable_pipelining: false,
2579+
extra_aliased_targets: BTreeMap::default(),
2580+
alias_rule: None,
2581+
override_targets: BTreeMap::from([(
2582+
"proc-macro".to_owned(),
2583+
Label::from_str("//tools/dep_crate:dep_crate").unwrap(),
2584+
)]),
2585+
},
2586+
);
2587+
context.crates.insert(
2588+
consumer_id.clone(),
2589+
CrateContext {
2590+
name: consumer_id.name.clone(),
2591+
version: consumer_id.version.clone(),
2592+
package_url: None,
2593+
targets: BTreeSet::from([Rule::Library(mock_target_attributes())]),
2594+
library_target_name: Some("consumer".to_owned()),
2595+
common_attrs: CommonAttributes {
2596+
deps: Select::from_value(BTreeSet::from([CrateDependency {
2597+
id: dep_id.clone(),
2598+
target: "dep_crate".to_owned(),
2599+
alias: None,
2600+
local_path: None,
2601+
}])),
2602+
..Default::default()
2603+
},
2604+
build_script_attrs: None,
2605+
repository: None,
2606+
license: None,
2607+
license_ids: BTreeSet::default(),
2608+
license_file: None,
2609+
additive_build_file_content: None,
2610+
disable_pipelining: false,
2611+
extra_aliased_targets: BTreeMap::default(),
2612+
alias_rule: None,
2613+
override_targets: BTreeMap::default(),
2614+
},
2615+
);
2616+
2617+
let renderer = Renderer::new(mock_render_config(None), mock_supported_platform_triples());
2618+
let output = renderer.render(&context, None).unwrap();
2619+
let build_file_content = output.get(&PathBuf::from("BUILD.bazel")).unwrap();
2620+
2621+
assert!(
2622+
build_file_content.contains("//tools/dep_crate:dep_crate"),
2623+
"expected override label in hub alias:\n{build_file_content}"
2624+
);
2625+
assert!(
2626+
!build_file_content.contains("@test_rendering__dep_crate"),
2627+
"must not emit spoke-repo alias for workspace member proc-macro:\n{build_file_content}"
2628+
);
2629+
}
2630+
2631+
/// When a workspace-member dep has `extra_aliased_targets` set, those aliases
2632+
/// must be suppressed — spoke repos are not created for workspace members so
2633+
/// the generated labels would be dangling.
2634+
#[test]
2635+
fn extra_aliased_targets_omitted_for_workspace_member_dep() {
2636+
let mut context = Context::default();
2637+
2638+
let consumer_id = CrateId::new("consumer".to_owned(), VERSION_ZERO_ONE_ZERO);
2639+
context
2640+
.workspace_members
2641+
.insert(consumer_id.clone(), "consumer".into());
2642+
2643+
let dep_id = CrateId::new("dep_crate".to_owned(), VERSION_ZERO_ONE_ZERO);
2644+
context
2645+
.workspace_members
2646+
.insert(dep_id.clone(), "dep_crate".into());
2647+
context.crates.insert(
2648+
dep_id.clone(),
2649+
CrateContext {
2650+
name: dep_id.name.clone(),
2651+
version: dep_id.version.clone(),
2652+
package_url: None,
2653+
targets: BTreeSet::from([Rule::Library(mock_target_attributes())]),
2654+
library_target_name: Some("dep_crate".to_owned()),
2655+
common_attrs: CommonAttributes::default(),
2656+
build_script_attrs: None,
2657+
repository: None,
2658+
license: None,
2659+
license_ids: BTreeSet::default(),
2660+
license_file: None,
2661+
additive_build_file_content: None,
2662+
disable_pipelining: false,
2663+
extra_aliased_targets: BTreeMap::from([("foo".to_owned(), "foo_impl".to_owned())]),
2664+
alias_rule: None,
2665+
override_targets: BTreeMap::default(),
2666+
},
2667+
);
2668+
context.crates.insert(
2669+
consumer_id.clone(),
2670+
CrateContext {
2671+
name: consumer_id.name.clone(),
2672+
version: consumer_id.version.clone(),
2673+
package_url: None,
2674+
targets: BTreeSet::from([Rule::Library(mock_target_attributes())]),
2675+
library_target_name: Some("consumer".to_owned()),
2676+
common_attrs: CommonAttributes {
2677+
deps: Select::from_value(BTreeSet::from([CrateDependency {
2678+
id: dep_id.clone(),
2679+
target: "dep_crate".to_owned(),
2680+
alias: None,
2681+
local_path: None,
2682+
}])),
2683+
..Default::default()
2684+
},
2685+
build_script_attrs: None,
2686+
repository: None,
2687+
license: None,
2688+
license_ids: BTreeSet::default(),
2689+
license_file: None,
2690+
additive_build_file_content: None,
2691+
disable_pipelining: false,
2692+
extra_aliased_targets: BTreeMap::default(),
2693+
alias_rule: None,
2694+
override_targets: BTreeMap::default(),
2695+
},
2696+
);
2697+
2698+
let renderer = Renderer::new(mock_render_config(None), mock_supported_platform_triples());
2699+
let output = renderer.render(&context, None).unwrap();
2700+
let build_file_content = output.get(&PathBuf::from("BUILD.bazel")).unwrap();
2701+
2702+
assert!(
2703+
!build_file_content.contains("alias("),
2704+
"extra_aliased_targets must not emit aliases for workspace member dep:\n{build_file_content}"
2705+
);
2706+
}
25222707
}

0 commit comments

Comments
 (0)