Skip to content

Commit

Permalink
Avoid including non-excluded members in parent workspaces (#6735)
Browse files Browse the repository at this point in the history
## Summary

If you're in a directory, and there's workspace above it, we check if
the directory is excluded from the workspace members... But not if it's
_included_ in the first place.

Closes #6732.
  • Loading branch information
charliermarsh committed Aug 28, 2024
1 parent 56cc0c9 commit 485e0d2
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
26 changes: 25 additions & 1 deletion crates/uv-workspace/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,14 @@ async fn find_workspace(
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.workspace.as_ref())
{
if !is_included_in_workspace(project_root, workspace_root, workspace)? {
debug!(
"Found workspace root `{}`, but project is not included",
workspace_root.simplified_display()
);
return Ok(None);
}

if is_excluded_from_workspace(project_root, workspace_root, workspace)? {
debug!(
"Found workspace root `{}`, but project is excluded",
Expand Down Expand Up @@ -1101,6 +1109,21 @@ pub fn check_nested_workspaces(inner_workspace_root: &Path, options: &DiscoveryO
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.workspace.as_ref())
{
let is_included = match is_included_in_workspace(
inner_workspace_root,
outer_workspace_root,
workspace,
) {
Ok(contents) => contents,
Err(err) => {
warn!(
"Invalid pyproject.toml `{}`: {err}",
pyproject_toml_path.simplified_display()
);
return;
}
};

let is_excluded = match is_excluded_from_workspace(
inner_workspace_root,
outer_workspace_root,
Expand All @@ -1115,7 +1138,8 @@ pub fn check_nested_workspaces(inner_workspace_root: &Path, options: &DiscoveryO
return;
}
};
if !is_excluded {

if is_included && !is_excluded {
warn_user!(
"Nested workspaces are not supported, but outer workspace (`{}`) includes `{}`",
outer_workspace_root.simplified_display().cyan(),
Expand Down
60 changes: 60 additions & 0 deletions crates/uv/tests/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,66 @@ fn workspace_hidden_member() -> Result<()> {
Ok(())
}

/// Ensure that workspace discovery accepts valid hidden directories.
#[test]
fn workspace_non_included_member() -> Result<()> {
let context = TestContext::new("3.12");

// Build the main workspace ...
let workspace = context.temp_dir.child("workspace");
workspace.child("pyproject.toml").write_str(indoc! {r#"
[tool.uv.workspace]
members = ["packages/*"]
"#})?;

// ... with a ...
let deps = indoc! {r#"
dependencies = ["b"]
[tool.uv.sources]
b = { workspace = true }
"#};
make_project(&workspace.join("packages").join("a"), "a", deps)?;

// ... and b.
let deps = indoc! {r"
dependencies = []
"};
make_project(&workspace.join("packages").join("b"), "b", deps)?;

// ... and c, which is _not_ a member, but also isn't explicitly excluded.
let deps = indoc! {r"
dependencies = []
"};
make_project(&workspace.join("c"), "c", deps)?;

// Locking from `c` should not include any workspace members.
uv_snapshot!(context.filters(), context.lock().current_dir(workspace.join("c")), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
Resolved 1 package in [TIME]
"###
);

let lock: SourceLock = toml::from_str(&fs_err::read_to_string(
workspace.join("c").join("uv.lock"),
)?)?;

assert_json_snapshot!(lock.sources(), @r###"
{
"c": {
"editable": "."
}
}
"###);

Ok(())
}

/// Ensure workspace members inherit sources from the root, if not specified in the member.
///
/// In such cases, relative paths should be resolved relative to the workspace root, rather than
Expand Down

0 comments on commit 485e0d2

Please sign in to comment.