Skip to content
This repository has been archived by the owner on Jul 28, 2024. It is now read-only.

Commit

Permalink
Add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Aug 15, 2023
1 parent e7a9efc commit 530e840
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 33 deletions.
29 changes: 26 additions & 3 deletions crates/cli/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
use clap::{Args, Parser, Subcommand};
use jpm_common::{EsTarget, PackageName};
use jpm_workspace::SelectQuery;

pub const BIN_NAME: &str = if cfg!(windows) { "jpm.exe" } else { "jpm" };

static HEADING_FILTER: &str = "Package filtering";

#[derive(Clone, Debug, Args)]
pub struct GlobalArgs {
pub package: Option<Vec<PackageName>>,
pub filters: Option<Vec<String>>,
pub packages: Option<Vec<PackageName>>,
pub workspace: bool,
}

impl GlobalArgs {
pub fn to_package_select_query(&self) -> SelectQuery {
SelectQuery {
all: self.workspace,
filters: self.filters.as_ref(),
names: self.packages.as_ref(),
}
}
}

#[derive(Clone, Debug, Args)]
pub struct BuildArgs {
#[arg(
Expand Down Expand Up @@ -59,11 +71,21 @@ pub struct CLI {
#[command(subcommand)]
pub command: Commands,

#[arg(
short = 'f',
long,
global = true,
help = "Select packages by name using a filter glob. Can be specified multiple times.",
help_heading = HEADING_FILTER,
group = "package-filter"
)]
pub filter: Option<Vec<String>>,

#[arg(
short = 'p',
long,
global = true,
help = "Select a specific package. Can be specified multiple times.",
help = "Select a specific package by name. Can be specified multiple times.",
help_heading = HEADING_FILTER,
group = "package-filter"
)]
Expand All @@ -83,7 +105,8 @@ pub struct CLI {
impl CLI {
pub fn global_args(&self) -> GlobalArgs {
GlobalArgs {
package: self.package.clone(),
filters: self.filter.clone(),
packages: self.package.clone(),
workspace: self.workspace,
}
}
Expand Down
3 changes: 1 addition & 2 deletions crates/cli/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ pub async fn build(
args: &BuildArgs,
global_args: &GlobalArgs,
) -> SystemResult {
let packages =
workspace.select_packages(global_args.workspace, global_args.package.as_ref())?;
let packages = workspace.select_packages(global_args.to_package_select_query())?;
let last_index = packages.len() - 1;

for (index, package) in packages.iter().enumerate() {
Expand Down
3 changes: 0 additions & 3 deletions crates/cli/src/commands/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,5 @@ pub async fn debug(workspace: &Workspace) -> SystemResult {
dbg!("LOAD PACKAGES");
dbg!(workspace.load_packages()?);

dbg!("QUERY PACKAGES");
dbg!(workspace.select_packages(true, None)?);

Ok(())
}
37 changes: 23 additions & 14 deletions crates/workspace/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ use std::fmt;
use std::path::{Path, PathBuf};
use tracing::debug;

#[derive(Default)]
pub struct SelectQuery<'app> {
pub all: bool,
pub filters: Option<&'app Vec<String>>,
pub names: Option<&'app Vec<PackageName>>,
}

#[derive(Resource)]
pub struct Workspace {
pub manifest: Manifest,
Expand Down Expand Up @@ -109,20 +116,26 @@ impl Workspace {
})
}

pub fn select_packages(
&self,
select_all: bool,
select_by_names: Option<&Vec<PackageName>>,
) -> miette::Result<Vec<&Package>> {
pub fn select_packages(&self, query: SelectQuery) -> miette::Result<Vec<&Package>> {
let packages = self.load_packages()?;
let mut selected_names = HashSet::new();

// Select packages by name
if let Some(select_by) = select_by_names {
if select_all {
return Err(WorkspaceError::EitherPackageOrWorkspaceArg)?;
// If a polyrepo, always use the root package
if let Manifest::Package(root_package) = &self.manifest {
selected_names.insert(&root_package.package.name);

// Select packages with filters
} else if let Some(filters) = query.filters {
let globset = glob::GlobSet::new(filters)?;

for package_name in packages.keys() {
if globset.matches(package_name.as_str()) {
selected_names.insert(package_name);
}
}

// Select packages by name
} else if let Some(select_by) = query.names {
for name in select_by {
if !packages.contains_key(name) {
return Err(WorkspaceError::UnknownPackage {
Expand All @@ -134,12 +147,8 @@ impl Workspace {
}

// Select all packages
} else if select_all {
} else if query.all {
selected_names.extend(packages.keys());

// If a polyrepo, always use the root package if no filters provided
} else if let Manifest::Package(root_package) = &self.manifest {
selected_names.insert(&root_package.package.name);
}

if selected_names.is_empty() {
Expand Down
11 changes: 2 additions & 9 deletions crates/workspace/src/workspace_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,12 @@ use thiserror::Error;

#[derive(Debug, Diagnostic, Error)]
pub enum WorkspaceError {
#[diagnostic(code(workspace::package_graph::either_filters))]
#[error(
"The {} and {} arguments cannot be used together. Use one or the other.",
"--workspace".style(Style::Label),
"--package".style(Style::Label),
)]
EitherPackageOrWorkspaceArg,

#[diagnostic(code(workspace::package_graph::none_selected))]
#[error(
"No packages have been selected. Pass {} to select all packages in the workspace, or {} for each package to select.",
"No packages have been selected. Pass {} to select all packages in the workspace, {} for each package by name, or {} to filter by name.",
"--workspace".style(Style::Label),
"--package".style(Style::Label),
"--filter".style(Style::Label),
)]
NoPackagesSelected,

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "app/client"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "app/server"
2 changes: 2 additions & 0 deletions crates/workspace/tests/__fixtures__/monorepo/jpm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
packages = ["packages/*"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "mono/bar"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "mono/baz"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "mono/foo"
Empty file.
2 changes: 2 additions & 0 deletions crates/workspace/tests/__fixtures__/polyrepo/jpm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "poly/root"
187 changes: 185 additions & 2 deletions crates/workspace/tests/workspace_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use jpm_workspace::Workspace;
use starbase_sandbox::create_empty_sandbox;
use jpm_common::PackageName;
use jpm_workspace::{SelectQuery, Workspace};
use starbase_sandbox::{create_empty_sandbox, create_sandbox};

mod workspace {
use super::*;
Expand Down Expand Up @@ -33,4 +34,186 @@ mod workspace {

assert_eq!(workspace.root, sandbox.path());
}

mod polyrepo {
use super::*;

#[test]
fn marks_as_polyrepo() {
let sandbox = create_sandbox("polyrepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

assert!(!workspace.monorepo);
}

#[test]
fn loads_a_single_package() {
let sandbox = create_sandbox("polyrepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();
let packages = workspace.load_packages().unwrap();
let root = packages
.get(&PackageName::parse("poly/root").unwrap())
.unwrap();

assert_eq!(root.root, sandbox.path());
}

#[test]
fn always_selects_one_package_regardless_of_filters() {
let sandbox = create_sandbox("polyrepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

let packages = workspace.select_packages(SelectQuery::default()).unwrap();

assert_eq!(packages.len(), 1);

let packages = workspace
.select_packages(SelectQuery {
all: true,
..SelectQuery::default()
})
.unwrap();

assert_eq!(packages.len(), 1);

let packages = workspace
.select_packages(SelectQuery {
names: Some(&vec![PackageName::parse("poly/root").unwrap()]),
..SelectQuery::default()
})
.unwrap();

assert_eq!(packages.len(), 1);

let packages = workspace
.select_packages(SelectQuery {
filters: Some(&vec!["poly/*".into()]),
..SelectQuery::default()
})
.unwrap();

assert_eq!(packages.len(), 1);
}
}

mod monorepo {
use super::*;

#[test]
fn marks_as_monorepo() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

assert!(workspace.monorepo);
}

#[test]
fn loads_all_packages_matching_glob() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();
let packages = workspace.load_packages().unwrap();

// Only packages
assert_eq!(packages.len(), 3);
assert!(packages.contains_key(&PackageName::parse("mono/foo").unwrap()));
assert!(packages.contains_key(&PackageName::parse("mono/bar").unwrap()));
assert!(packages.contains_key(&PackageName::parse("mono/baz").unwrap()));
}

#[test]
fn selects_all() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

let packages = workspace
.select_packages(SelectQuery {
all: true,
..SelectQuery::default()
})
.unwrap();

assert_eq!(packages.len(), 3);
}

#[test]
fn selects_by_name() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

let packages = workspace
.select_packages(SelectQuery {
names: Some(&vec![
PackageName::parse("mono/foo").unwrap(),
PackageName::parse("mono/baz").unwrap(),
]),
..SelectQuery::default()
})
.unwrap();

assert_eq!(packages.len(), 2);
assert_eq!(packages[0].name(), "mono/baz");
assert_eq!(packages[1].name(), "mono/foo");
}

#[test]
fn selects_by_filter() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

let packages = workspace
.select_packages(SelectQuery {
filters: Some(&vec!["*/ba{z,r}".into()]),
..SelectQuery::default()
})
.unwrap();

assert_eq!(packages.len(), 2);
assert_eq!(packages[0].name(), "mono/bar");
assert_eq!(packages[1].name(), "mono/baz");
}

#[test]
fn selects_by_filter_with_negated() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

let packages = workspace
.select_packages(SelectQuery {
filters: Some(&vec!["*/ba{z,r}".into(), "!*/bar".into()]),
..SelectQuery::default()
})
.unwrap();

assert_eq!(packages.len(), 1);
assert_eq!(packages[0].name(), "mono/baz");
}

#[test]
#[should_panic(expected = "No packages have been selected.")]
fn errors_none_selected() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

workspace
.select_packages(SelectQuery {
filters: Some(&vec!["*/unknown".into()]),
..SelectQuery::default()
})
.unwrap();
}

#[test]
#[should_panic(expected = "The package mono/unknown doesn't exist")]
fn errors_unknown_name() {
let sandbox = create_sandbox("monorepo");
let workspace = Workspace::load_from(sandbox.path()).unwrap();

workspace
.select_packages(SelectQuery {
names: Some(&vec![PackageName::parse("mono/unknown").unwrap()]),
..SelectQuery::default()
})
.unwrap();
}
}
}

0 comments on commit 530e840

Please sign in to comment.