Skip to content

Commit 5ec9c16

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

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(),
@@ -2051,12 +2072,10 @@ mod test {
20512072
assert!(found);
20522073
}
20532074

2054-
/// Tests a situation where we have identical aliases to the crate's name on
2055-
/// the package's deps, and the dep is itself a workspace member. Because
2056-
/// workspace-member deps have no spoke repo and no override_targets["lib"]
2057-
/// is set, no hub alias should be emitted at all.
2075+
/// Tests that when a workspace-member dep is aliased under its own crate name
2076+
/// and has no `override_targets` set, no hub alias is emitted.
20582077
#[test]
2059-
fn crate_with_ambiguous_rename() {
2078+
fn workspace_member_dep_with_alias_same_as_crate_name_and_no_override() {
20602079
let mut context = Context::default();
20612080
let crate_id = CrateId::new("mock_crate".to_owned(), VERSION_ZERO_ONE_ZERO);
20622081
context
@@ -2104,11 +2123,11 @@ mod test {
21042123
let build_file_content = output.get(&PathBuf::from("BUILD.bazel")).unwrap();
21052124

21062125
println!("{build_file_content}");
2107-
// mock_crate is a workspace member dep with no override_targets["lib"],
2126+
// mock_crate is a workspace member dep with no override_targets set,
21082127
// so no hub alias should be emitted to avoid dangling spoke-repo refs.
21092128
assert!(
21102129
!build_file_content.contains("alias("),
2111-
"no alias should be emitted for workspace member dep with ambiguous rename and no override:\n{build_file_content}"
2130+
"no alias should be emitted for workspace member dep with no override:\n{build_file_content}"
21122131
);
21132132
}
21142133

@@ -2593,4 +2612,170 @@ mod test {
25932612
"no alias should be emitted for workspace member dep without override:\n{build_file_content}"
25942613
);
25952614
}
2615+
2616+
/// When a workspace-member proc-macro dep has `override_targets["proc-macro"]` set,
2617+
/// the hub alias must use that label rather than a non-existent spoke repo.
2618+
/// This exercises the `Rule::ProcMacro` arm of the `find_map` that replaced
2619+
/// the `"lib"` hardcode.
2620+
#[test]
2621+
fn hub_alias_for_workspace_member_proc_macro_dep_uses_override_target() {
2622+
let mut context = Context::default();
2623+
2624+
let consumer_id = CrateId::new("consumer".to_owned(), VERSION_ZERO_ONE_ZERO);
2625+
context
2626+
.workspace_members
2627+
.insert(consumer_id.clone(), "consumer".into());
2628+
2629+
let dep_id = CrateId::new("dep_crate".to_owned(), VERSION_ZERO_ONE_ZERO);
2630+
context
2631+
.workspace_members
2632+
.insert(dep_id.clone(), "dep_crate".into());
2633+
context.crates.insert(
2634+
dep_id.clone(),
2635+
CrateContext {
2636+
name: dep_id.name.clone(),
2637+
version: dep_id.version.clone(),
2638+
package_url: None,
2639+
targets: BTreeSet::from([Rule::ProcMacro(TargetAttributes {
2640+
crate_name: "dep_crate".to_owned(),
2641+
crate_root: Some("src/lib.rs".to_owned()),
2642+
..TargetAttributes::default()
2643+
})]),
2644+
library_target_name: Some("dep_crate".to_owned()),
2645+
common_attrs: CommonAttributes::default(),
2646+
build_script_attrs: None,
2647+
repository: None,
2648+
license: None,
2649+
license_ids: BTreeSet::default(),
2650+
license_file: None,
2651+
additive_build_file_content: None,
2652+
disable_pipelining: false,
2653+
extra_aliased_targets: BTreeMap::default(),
2654+
alias_rule: None,
2655+
override_targets: BTreeMap::from([(
2656+
"proc-macro".to_owned(),
2657+
Label::from_str("//tools/dep_crate:dep_crate").unwrap(),
2658+
)]),
2659+
},
2660+
);
2661+
context.crates.insert(
2662+
consumer_id.clone(),
2663+
CrateContext {
2664+
name: consumer_id.name.clone(),
2665+
version: consumer_id.version.clone(),
2666+
package_url: None,
2667+
targets: BTreeSet::from([Rule::Library(mock_target_attributes())]),
2668+
library_target_name: Some("consumer".to_owned()),
2669+
common_attrs: CommonAttributes {
2670+
deps: Select::from_value(BTreeSet::from([CrateDependency {
2671+
id: dep_id.clone(),
2672+
target: "dep_crate".to_owned(),
2673+
alias: None,
2674+
local_path: None,
2675+
}])),
2676+
..Default::default()
2677+
},
2678+
build_script_attrs: None,
2679+
repository: None,
2680+
license: None,
2681+
license_ids: BTreeSet::default(),
2682+
license_file: None,
2683+
additive_build_file_content: None,
2684+
disable_pipelining: false,
2685+
extra_aliased_targets: BTreeMap::default(),
2686+
alias_rule: None,
2687+
override_targets: BTreeMap::default(),
2688+
},
2689+
);
2690+
2691+
let renderer = Renderer::new(mock_render_config(None), mock_supported_platform_triples());
2692+
let output = renderer.render(&context, None).unwrap();
2693+
let build_file_content = output.get(&PathBuf::from("BUILD.bazel")).unwrap();
2694+
2695+
assert!(
2696+
build_file_content.contains("//tools/dep_crate:dep_crate"),
2697+
"expected override label in hub alias:\n{build_file_content}"
2698+
);
2699+
assert!(
2700+
!build_file_content.contains("@test_rendering__dep_crate"),
2701+
"must not emit spoke-repo alias for workspace member proc-macro:\n{build_file_content}"
2702+
);
2703+
}
2704+
2705+
/// When a workspace-member dep has `extra_aliased_targets` set, those aliases
2706+
/// must be suppressed — spoke repos are not created for workspace members so
2707+
/// the generated labels would be dangling.
2708+
#[test]
2709+
fn extra_aliased_targets_omitted_for_workspace_member_dep() {
2710+
let mut context = Context::default();
2711+
2712+
let consumer_id = CrateId::new("consumer".to_owned(), VERSION_ZERO_ONE_ZERO);
2713+
context
2714+
.workspace_members
2715+
.insert(consumer_id.clone(), "consumer".into());
2716+
2717+
let dep_id = CrateId::new("dep_crate".to_owned(), VERSION_ZERO_ONE_ZERO);
2718+
context
2719+
.workspace_members
2720+
.insert(dep_id.clone(), "dep_crate".into());
2721+
context.crates.insert(
2722+
dep_id.clone(),
2723+
CrateContext {
2724+
name: dep_id.name.clone(),
2725+
version: dep_id.version.clone(),
2726+
package_url: None,
2727+
targets: BTreeSet::from([Rule::Library(mock_target_attributes())]),
2728+
library_target_name: Some("dep_crate".to_owned()),
2729+
common_attrs: CommonAttributes::default(),
2730+
build_script_attrs: None,
2731+
repository: None,
2732+
license: None,
2733+
license_ids: BTreeSet::default(),
2734+
license_file: None,
2735+
additive_build_file_content: None,
2736+
disable_pipelining: false,
2737+
extra_aliased_targets: BTreeMap::from([("foo".to_owned(), "foo_impl".to_owned())]),
2738+
alias_rule: None,
2739+
override_targets: BTreeMap::default(),
2740+
},
2741+
);
2742+
context.crates.insert(
2743+
consumer_id.clone(),
2744+
CrateContext {
2745+
name: consumer_id.name.clone(),
2746+
version: consumer_id.version.clone(),
2747+
package_url: None,
2748+
targets: BTreeSet::from([Rule::Library(mock_target_attributes())]),
2749+
library_target_name: Some("consumer".to_owned()),
2750+
common_attrs: CommonAttributes {
2751+
deps: Select::from_value(BTreeSet::from([CrateDependency {
2752+
id: dep_id.clone(),
2753+
target: "dep_crate".to_owned(),
2754+
alias: None,
2755+
local_path: None,
2756+
}])),
2757+
..Default::default()
2758+
},
2759+
build_script_attrs: None,
2760+
repository: None,
2761+
license: None,
2762+
license_ids: BTreeSet::default(),
2763+
license_file: None,
2764+
additive_build_file_content: None,
2765+
disable_pipelining: false,
2766+
extra_aliased_targets: BTreeMap::default(),
2767+
alias_rule: None,
2768+
override_targets: BTreeMap::default(),
2769+
},
2770+
);
2771+
2772+
let renderer = Renderer::new(mock_render_config(None), mock_supported_platform_triples());
2773+
let output = renderer.render(&context, None).unwrap();
2774+
let build_file_content = output.get(&PathBuf::from("BUILD.bazel")).unwrap();
2775+
2776+
assert!(
2777+
!build_file_content.contains("alias("),
2778+
"extra_aliased_targets must not emit aliases for workspace member dep:\n{build_file_content}"
2779+
);
2780+
}
25962781
}

0 commit comments

Comments
 (0)