Skip to content

Commit

Permalink
Feature --exclude-unpublished (#710)
Browse files Browse the repository at this point in the history
This PR adds a new command line flag `--exclude-unpublished`. If the
flag is set, the construction of the crate graph does not use explicitly
unpublished crates as roots. Workspace members are considered explicitly
unpublished if their manifest specifies `publish = false`. For
motivation please see the [associated
issue](#708).

This PR depends on EmbarkStudios/krates#94 to
fix the workspace filters mechanism of
https://github.com/EmbarkStudios/krates. Documentation for the flag will
follow as soon as I find the time.

---------

Co-authored-by: Jake Shadle <[email protected]>
  • Loading branch information
Tastaturtaste and Jake-Shadle authored Nov 14, 2024
1 parent c54dc46 commit 2182b47
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 73 deletions.
176 changes: 107 additions & 69 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/cargo-deny/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ pub(crate) fn cmd(
krate_ctx.all_features |= graph.all_features;
krate_ctx.no_default_features |= graph.no_default_features;
krate_ctx.exclude_dev |= graph.exclude_dev | args.exclude_dev;
krate_ctx.exclude_unpublished |= graph.exclude_unpublished;

// If not specified on the cmd line, fallback to the feature related config options
if krate_ctx.features.is_empty() {
Expand Down
10 changes: 9 additions & 1 deletion src/cargo-deny/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct KrateContext {
pub locked: bool,
pub offline: bool,
pub exclude_dev: bool,
pub exclude_unpublished: bool,
}

impl KrateContext {
Expand Down Expand Up @@ -169,7 +170,14 @@ impl KrateContext {
}),
);
}

if self.exclude_unpublished {
gb.include_workspace_crates(metadata.workspace_packages().iter().filter_map(
|package| match package.publish {
Some(ref registries) if registries.is_empty() => None,
_ => Some(package.manifest_path.as_std_path()),
},
));
}
// Attempt to open the crates.io index so that the feature sets for every
// crate in the graph are correct, however, don't consider it a hard failure
// if we can't for some reason, as the graph will _probably_ still be accurate
Expand Down
7 changes: 7 additions & 0 deletions src/cargo-deny/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ pub(crate) struct GraphContext {
#[arg(long)]
/// If set, excludes all dev-dependencies, not just ones for non-workspace crates
pub(crate) exclude_dev: bool,
#[arg(long)]
/// If set, exclude unpublished workspace members from graph roots.
/// Workspace members are considered unpublished if they they are explicitly marked with `publish = false` as such.
/// Note that the excluded workspace members are still used for the initial dependency resolution by cargo,
/// which might affect the exact version of used dependencies.
pub(crate) exclude_unpublished: bool,
}

/// Lints your project's crate graph
Expand Down Expand Up @@ -296,6 +302,7 @@ fn real_main() -> Result<(), Error> {
locked: args.ctx.locked,
offline: args.ctx.offline,
exclude_dev: args.ctx.exclude_dev,
exclude_unpublished: args.ctx.exclude_unpublished,
};

let log_ctx = crate::common::LogContext {
Expand Down
3 changes: 3 additions & 0 deletions src/root_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub struct GraphConfig {
pub no_default_features: bool,
/// By default, dev dependencies for workspace crates are not ignored
pub exclude_dev: bool,
pub exclude_unpublished: bool,
}

impl<'de> Deserialize<'de> for GraphConfig {
Expand All @@ -59,6 +60,7 @@ impl<'de> Deserialize<'de> for GraphConfig {
let all_features = th.optional("all-features").unwrap_or_default();
let no_default_features = th.optional("no-default-features").unwrap_or_default();
let exclude_dev = th.optional("exclude-dev").unwrap_or_default();
let exclude_unpublished = th.optional("exclude-unpublished").unwrap_or_default();
th.finalize(None)?;

Ok(Self {
Expand All @@ -68,6 +70,7 @@ impl<'de> Deserialize<'de> for GraphConfig {
all_features,
no_default_features,
exclude_dev,
exclude_unpublished,
})
}
}
Expand Down
34 changes: 34 additions & 0 deletions tests/bans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,40 @@ allow-wildcard-paths = true
insta::assert_json_snapshot!(diags);
}

/// Ensures that individual workspace crates can be ignored
#[test]
fn ignores_unpublished_crates() {
let project_dir = camino::Utf8PathBuf::from("./tests/test_data/workspace");

let mut cmd = krates::Cmd::new();
cmd.current_dir(project_dir.clone());

let mut kb = krates::Builder::new();
kb.ignore_kind(krates::DepKind::Build, krates::Scope::All);
kb.include_workspace_crates([project_dir.join("crates/member-two/Cargo.toml")]);
let krates = kb
.build(cmd, krates::NoneFilter)
.expect("failed to build crate graph");

let diags = gather_diagnostics::<cargo_deny::bans::cfg::Config, _, _>(
&krates,
func_name!(),
// If either the workspace `root` or `member-one` crates are pulled in,
// they will emit diagnostics that won't be emitted by just including member-two
r#"
multiple-versions = 'allow'
wildcards = 'deny'
allow-wildcard-paths = true
"#
.into(),
|ctx, tx| {
cargo_deny::bans::check(ctx, None, tx);
},
);

insta::assert_json_snapshot!(diags);
}

/// Ensures that dependencies with wildcard and git are allowed for private packages
#[test]
fn allow_git_wildcards_private_package() {
Expand Down
6 changes: 6 additions & 0 deletions tests/snapshots/bans__ignores_unpublished_crates.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: tests/bans.rs
expression: diags
snapshot_kind: text
---
[]
4 changes: 3 additions & 1 deletion tests/snapshots/cargo_deny__test__cargo_deny.snap
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ Options:
--exclude-dev
If set, excludes all dev-dependencies, not just ones for non-workspace crates

--exclude-unpublished
If set, exclude unpublished workspace members from graph roots. Workspace members are considered unpublished if they they are explicitly marked with `publish = false` as such. Note that the excluded workspace members are still used for the initial dependency resolution by cargo, which might affect the exact version of used dependencies

-h, --help
Print help (see a summary with '-h')

-V, --version
Print version

2 changes: 0 additions & 2 deletions tests/test_data/wildcards/allow-paths-private/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,5 @@ license = "MIT"

publish = false

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wildcards-test-allow-paths-dependency = { path = "../allow-paths-dependency" }

0 comments on commit 2182b47

Please sign in to comment.