xtask: Add command for checking packages conform to certain standards (#15236)
This PR adds a new `xtask` command for checking that packages conform to certain standards. Still a work-in-progress, but right now it checks: - If `[lints] workspace = true` is set - If packages are using non-workspace dependencies Release Notes: - N/A
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::Parser;
|
||||
|
||||
use crate::workspace::load_workspace;
|
||||
@@ -13,8 +13,11 @@ pub fn run_licenses(_args: LicensesArgs) -> Result<()> {
|
||||
|
||||
let workspace = load_workspace()?;
|
||||
|
||||
for member in workspace.members {
|
||||
let crate_dir = PathBuf::from(&member);
|
||||
for package in workspace.workspace_packages() {
|
||||
let crate_dir = package
|
||||
.manifest_path
|
||||
.parent()
|
||||
.ok_or_else(|| anyhow!("no crate directory for {}", package.name))?;
|
||||
|
||||
if let Some(license_file) = first_license_file(&crate_dir, &LICENSE_FILES) {
|
||||
if !license_file.is_symlink() {
|
||||
@@ -24,15 +27,15 @@ pub fn run_licenses(_args: LicensesArgs) -> Result<()> {
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Missing license: {member}");
|
||||
println!("Missing license: {}", package.name);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn first_license_file(path: &Path, license_files: &[&str]) -> Option<PathBuf> {
|
||||
fn first_license_file(path: impl AsRef<Path>, license_files: &[&str]) -> Option<PathBuf> {
|
||||
for license_file in license_files {
|
||||
let path_to_license = path.join(license_file);
|
||||
let path_to_license = path.as_ref().join(license_file);
|
||||
if path_to_license.exists() {
|
||||
return Some(path_to_license);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use cargo_toml::{Dependency, Manifest};
|
||||
use clap::Parser;
|
||||
|
||||
use crate::workspace::load_workspace;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct PackageConformityArgs {}
|
||||
|
||||
pub fn run_package_conformity(_args: PackageConformityArgs) -> Result<()> {
|
||||
let workspace = load_workspace()?;
|
||||
|
||||
let mut non_workspace_dependencies = BTreeMap::new();
|
||||
|
||||
for package in workspace.workspace_packages() {
|
||||
let is_extension = package
|
||||
.manifest_path
|
||||
.parent()
|
||||
.and_then(|parent| parent.parent())
|
||||
.map_or(false, |grandparent_dir| {
|
||||
grandparent_dir.ends_with("extensions")
|
||||
});
|
||||
|
||||
let cargo_toml = read_cargo_toml(&package.manifest_path)?;
|
||||
|
||||
let is_using_workspace_lints = cargo_toml.lints.map_or(false, |lints| lints.workspace);
|
||||
if !is_using_workspace_lints {
|
||||
eprintln!(
|
||||
"{package:?} is not using workspace lints",
|
||||
package = package.name
|
||||
);
|
||||
}
|
||||
|
||||
// Extensions should not use workspace dependencies.
|
||||
if is_extension {
|
||||
continue;
|
||||
}
|
||||
|
||||
for dependencies in [
|
||||
&cargo_toml.dependencies,
|
||||
&cargo_toml.dev_dependencies,
|
||||
&cargo_toml.build_dependencies,
|
||||
] {
|
||||
for (name, dependency) in dependencies {
|
||||
if let Dependency::Inherited(_) = dependency {
|
||||
continue;
|
||||
}
|
||||
|
||||
non_workspace_dependencies
|
||||
.entry(name.to_owned())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(package.name.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (dependency, packages) in non_workspace_dependencies {
|
||||
eprintln!(
|
||||
"{dependency} is being used as a non-workspace dependency: {}",
|
||||
packages.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the contents of the `Cargo.toml` file at the given path.
|
||||
fn read_cargo_toml(path: impl AsRef<Path>) -> Result<Manifest> {
|
||||
let path = path.as_ref();
|
||||
let cargo_toml_bytes = fs::read(&path)?;
|
||||
Manifest::from_slice(&cargo_toml_bytes)
|
||||
.with_context(|| anyhow!("failed to read Cargo.toml at {path:?}"))
|
||||
}
|
||||
Reference in New Issue
Block a user