diff --git a/crates/turborepo-lib/src/daemon/mod.rs b/crates/turborepo-lib/src/daemon/mod.rs index 08210ce10e846..d9bae7650ae4b 100644 --- a/crates/turborepo-lib/src/daemon/mod.rs +++ b/crates/turborepo-lib/src/daemon/mod.rs @@ -110,6 +110,7 @@ pub(crate) mod proto { PackageManager::Berry => Self::Berry, PackageManager::Pnpm => Self::Pnpm, PackageManager::Pnpm6 => Self::Pnpm6, + PackageManager::Pnpm9 => Self::Pnpm9, PackageManager::Bun => Self::Bun, } } @@ -123,6 +124,7 @@ pub(crate) mod proto { turborepo_repository::package_manager::PackageManager::Berry => Self::Berry, turborepo_repository::package_manager::PackageManager::Pnpm => Self::Pnpm, turborepo_repository::package_manager::PackageManager::Pnpm6 => Self::Pnpm6, + turborepo_repository::package_manager::PackageManager::Pnpm9 => Self::Pnpm9, turborepo_repository::package_manager::PackageManager::Bun => Self::Bun, } } diff --git a/crates/turborepo-lib/src/daemon/proto/turbod.proto b/crates/turborepo-lib/src/daemon/proto/turbod.proto index f80c487d6d5f7..d79960ac96781 100644 --- a/crates/turborepo-lib/src/daemon/proto/turbod.proto +++ b/crates/turborepo-lib/src/daemon/proto/turbod.proto @@ -110,4 +110,5 @@ enum PackageManager { Pnpm6 = 3; Yarn = 4; Bun = 5; + Pnpm9 = 6; } diff --git a/crates/turborepo-repository/src/package_graph/builder.rs b/crates/turborepo-repository/src/package_graph/builder.rs index 4f09812998e85..8afa8e9706cf4 100644 --- a/crates/turborepo-repository/src/package_graph/builder.rs +++ b/crates/turborepo-repository/src/package_graph/builder.rs @@ -368,6 +368,7 @@ impl<'a, T: PackageDiscovery> BuildState<'a, ResolvedWorkspaces, T> { self.repo_root, &entry.package_json_path, &self.workspaces, + package_manager, npmrc.as_ref(), entry.package_json.all_dependencies(), ), @@ -554,6 +555,7 @@ impl Dependencies { repo_root: &AbsoluteSystemPath, workspace_json_path: &AnchoredSystemPathBuf, workspaces: &HashMap, + package_manager: PackageManager, npmrc: Option<&NpmRc>, dependencies: I, ) -> Self { @@ -563,7 +565,8 @@ impl Dependencies { .expect("package.json path should have parent"); let mut internal = HashSet::new(); let mut external = BTreeMap::new(); - let splitter = DependencySplitter::new(repo_root, workspace_dir, workspaces, npmrc); + let splitter = + DependencySplitter::new(repo_root, workspace_dir, workspaces, package_manager, npmrc); for (name, version) in dependencies.into_iter() { if let Some(workspace) = splitter.is_internal(name, version) { internal.insert(workspace); diff --git a/crates/turborepo-repository/src/package_graph/dep_splitter.rs b/crates/turborepo-repository/src/package_graph/dep_splitter.rs index 19a317ab82139..7ba43b5293cb0 100644 --- a/crates/turborepo-repository/src/package_graph/dep_splitter.rs +++ b/crates/turborepo-repository/src/package_graph/dep_splitter.rs @@ -6,6 +6,7 @@ use turbopath::{ }; use super::{npmrc::NpmRc, PackageInfo, PackageName}; +use crate::package_manager::PackageManager; pub struct DependencySplitter<'a> { repo_root: &'a AbsoluteSystemPath, @@ -19,17 +20,16 @@ impl<'a> DependencySplitter<'a> { repo_root: &'a AbsoluteSystemPath, workspace_dir: &'a AbsoluteSystemPath, workspaces: &'a HashMap, + package_manager: PackageManager, npmrc: Option<&'a NpmRc>, ) -> Self { Self { repo_root, workspace_dir, workspaces, - // TODO: default needs to depend on package manager as pnpm 9 changes the default to - // false link_workspace_packages: npmrc .and_then(|npmrc| npmrc.link_workspace_packages) - .unwrap_or(true), + .unwrap_or(!matches!(package_manager, PackageManager::Pnpm9)), } } diff --git a/crates/turborepo-repository/src/package_manager/mod.rs b/crates/turborepo-repository/src/package_manager/mod.rs index dac912a07e21d..0a031ff26d705 100644 --- a/crates/turborepo-repository/src/package_manager/mod.rs +++ b/crates/turborepo-repository/src/package_manager/mod.rs @@ -68,6 +68,7 @@ impl From for Vec { pub enum PackageManager { Berry, Npm, + Pnpm9, Pnpm, Pnpm6, Yarn, @@ -76,13 +77,12 @@ pub enum PackageManager { impl Display for PackageManager { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Do not change these without also changing `GetPackageManager` in - // packagemanager.go match self { PackageManager::Berry => write!(f, "berry"), PackageManager::Npm => write!(f, "npm"), PackageManager::Pnpm => write!(f, "pnpm"), PackageManager::Pnpm6 => write!(f, "pnpm6"), + PackageManager::Pnpm9 => write!(f, "pnpm9"), PackageManager::Yarn => write!(f, "yarn"), PackageManager::Bun => write!(f, "bun"), } @@ -216,7 +216,7 @@ impl Display for NoPackageManager { impl Display for MissingWorkspaceError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let err = match self.package_manager { - PackageManager::Pnpm | PackageManager::Pnpm6 => { + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => { "pnpm-workspace.yaml: no packages found. Turborepo requires pnpm workspaces and \ thus packages to be defined in the root pnpm-workspace.yaml" } @@ -308,7 +308,7 @@ impl PackageManager { pub fn command(&self) -> &'static str { match self { PackageManager::Npm => "npm", - PackageManager::Pnpm | PackageManager::Pnpm6 => "pnpm", + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => "pnpm", PackageManager::Yarn | PackageManager::Berry => "yarn", PackageManager::Bun => "bun", } @@ -335,7 +335,7 @@ impl PackageManager { pub fn get_default_exclusions(&self) -> impl Iterator { let ignores = match self { - PackageManager::Pnpm | PackageManager::Pnpm6 => { + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => { ["**/node_modules/**", "**/bower_components/**"].as_slice() } PackageManager::Npm => ["**/node_modules/**"].as_slice(), @@ -351,7 +351,7 @@ impl PackageManager { root_path: &AbsoluteSystemPath, ) -> Result<(Vec, Vec), Error> { let globs = match self { - PackageManager::Pnpm | PackageManager::Pnpm6 => { + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => { // Make sure to convert this to a missing workspace error // so we can catch it in the case of single package mode. let source = self.workspace_glob_source(root_path); @@ -490,14 +490,16 @@ impl PackageManager { match self { PackageManager::Npm => npm::LOCKFILE, PackageManager::Bun => bun::LOCKFILE, - PackageManager::Pnpm | PackageManager::Pnpm6 => pnpm::LOCKFILE, + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => pnpm::LOCKFILE, PackageManager::Yarn | PackageManager::Berry => yarn::LOCKFILE, } } pub fn workspace_configuration_path(&self) -> Option<&'static str> { match self { - PackageManager::Pnpm | PackageManager::Pnpm6 => Some("pnpm-workspace.yaml"), + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => { + Some("pnpm-workspace.yaml") + } PackageManager::Npm | PackageManager::Berry | PackageManager::Yarn @@ -533,7 +535,7 @@ impl PackageManager { ) -> Result, Error> { Ok(match self { PackageManager::Npm => Box::new(turborepo_lockfiles::NpmLockfile::load(contents)?), - PackageManager::Pnpm | PackageManager::Pnpm6 => { + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => { Box::new(turborepo_lockfiles::PnpmLockfile::from_bytes(contents)?) } PackageManager::Yarn => { @@ -562,7 +564,7 @@ impl PackageManager { ) -> PackageJson { match self { PackageManager::Berry => yarn::prune_patches(package_json, patches), - PackageManager::Pnpm6 | PackageManager::Pnpm => { + PackageManager::Pnpm9 | PackageManager::Pnpm6 | PackageManager::Pnpm => { pnpm::prune_patches(package_json, patches) } PackageManager::Yarn | PackageManager::Npm | PackageManager::Bun => { @@ -589,7 +591,7 @@ impl PackageManager { } } PackageManager::Npm | PackageManager::Pnpm6 => Some("--"), - PackageManager::Pnpm | PackageManager::Berry => None, + PackageManager::Pnpm | PackageManager::Pnpm9 | PackageManager::Berry => None, } } } @@ -687,7 +689,7 @@ mod tests { PackageManager::Berry => &["**/node_modules", "**/.git", "**/.yarn"], PackageManager::Bun => &["**/node_modules", "**/.git"], PackageManager::Yarn => &["apps/*/node_modules/**", "packages/*/node_modules/**"], - PackageManager::Pnpm | PackageManager::Pnpm6 => &[ + PackageManager::Pnpm | PackageManager::Pnpm6 | PackageManager::Pnpm9 => &[ "**/node_modules/**", "**/bower_components/**", "packages/skip", diff --git a/crates/turborepo-repository/src/package_manager/pnpm.rs b/crates/turborepo-repository/src/package_manager/pnpm.rs index c47f50ad20788..d0fe7f9af1af1 100644 --- a/crates/turborepo-repository/src/package_manager/pnpm.rs +++ b/crates/turborepo-repository/src/package_manager/pnpm.rs @@ -25,8 +25,11 @@ impl<'a> PnpmDetector<'a> { pub fn detect_pnpm6_or_pnpm(version: &Version) -> Result { let pnpm6_constraint: Range = "<7.0.0".parse()?; + let pnpm9_constraint: Range = ">=9.0.0-alpha.0".parse()?; if pnpm6_constraint.satisfies(version) { Ok(PackageManager::Pnpm6) + } else if pnpm9_constraint.satisfies(version) { + Ok(PackageManager::Pnpm9) } else { Ok(PackageManager::Pnpm) } @@ -95,6 +98,7 @@ mod test { use std::collections::BTreeMap; use serde_json::json; + use test_case::test_case; use turbopath::RelativeUnixPathBuf; use super::*; @@ -127,4 +131,17 @@ mod test { .as_ref() ); } + + #[test_case("6.0.0", PackageManager::Pnpm6)] + #[test_case("7.0.0", PackageManager::Pnpm)] + #[test_case("8.0.0", PackageManager::Pnpm)] + #[test_case("9.0.0", PackageManager::Pnpm9)] + #[test_case("9.0.0-alpha.0", PackageManager::Pnpm9)] + fn test_version_detection(version: &str, expected: PackageManager) { + let version = Version::parse(version).unwrap(); + assert_eq!( + PnpmDetector::detect_pnpm6_or_pnpm(&version).unwrap(), + expected + ); + } }