From 5966983a7b4133543a5c0d6b1c845bb95a47069a Mon Sep 17 00:00:00 2001 From: Chris Olszewski Date: Thu, 9 May 2024 09:12:49 -0700 Subject: [PATCH] feat: require packageManager in package.json (#8017) ### Description With 2.0 we will now be requiring a `packageManager` field in `package.json` as this is a best practice and it helps us behave in a deterministic manner. The actual code change is very straightforward as we remove our package manager inference code and return an error if reading package manager from `package.json` fails. Most of the PR is updating tests. ### Testing Instructions Updated unit tests --- .../turborepo-filewatch/src/hash_watcher.rs | 4 +- .../src/package_watcher.rs | 30 +++--- crates/turborepo-repository/src/discovery.rs | 5 +- crates/turborepo-repository/src/inference.rs | 11 +- .../src/package_manager/bun.rs | 62 ----------- .../src/package_manager/mod.rs | 100 +++++------------- .../src/package_manager/npm.rs | 62 ----------- .../src/package_manager/pnpm.rs | 55 +--------- .../src/package_manager/yarn.rs | 85 ++------------- .../helpers/setup_integration_test.sh | 7 +- .../tests/dry-json/single-package-no-config.t | 6 +- .../tests/dry-json/single-package-with-deps.t | 10 +- .../tests/dry-json/single-package.t | 6 +- .../integration/tests/package-manager.t | 45 -------- .../tests/run/single-package/dry-run.t | 2 +- .../tests/run/single-package/no-config.t | 6 +- .../tests/run/single-package/run.t | 4 +- .../run/single-package/with-deps-dry-run.t | 4 +- .../tests/run/single-package/with-deps-run.t | 12 +-- .../tests/task-dependencies/root-worksapce.t | 2 +- 20 files changed, 99 insertions(+), 419 deletions(-) diff --git a/crates/turborepo-filewatch/src/hash_watcher.rs b/crates/turborepo-filewatch/src/hash_watcher.rs index 7578cdf0b28b6..b9dc4b5bb76a8 100644 --- a/crates/turborepo-filewatch/src/hash_watcher.rs +++ b/crates/turborepo-filewatch/src/hash_watcher.rs @@ -747,7 +747,9 @@ mod tests { .unwrap(); repo_root .join_component("package.json") - .create_with_contents(r#"{"workspaces": ["packages/*"]}"#) + .create_with_contents( + r#"{"workspaces": ["packages/*"], "packageManager": "npm@10.0.0"}"#, + ) .unwrap(); repo_root .join_component("package-lock.json") diff --git a/crates/turborepo-filewatch/src/package_watcher.rs b/crates/turborepo-filewatch/src/package_watcher.rs index da35e9387410a..76fcc974c5799 100644 --- a/crates/turborepo-filewatch/src/package_watcher.rs +++ b/crates/turborepo-filewatch/src/package_watcher.rs @@ -600,7 +600,9 @@ mod test { // write workspaces to root repo_root .join_component("package.json") - .create_with_contents(r#"{"workspaces":["packages/*"]}"#) + .create_with_contents( + r#"{"workspaces":["packages/*"], "packageManager": "npm@10.0.0"}"#, + ) .unwrap(); let watcher = FileSystemWatcher::new_with_default_cookie_dir(&repo_root).unwrap(); @@ -703,7 +705,9 @@ mod test { // write workspaces to root repo_root .join_component("package.json") - .create_with_contents(r#"{"workspaces":["packages/*", "packages2/*"]}"#) + .create_with_contents( + r#"{"workspaces":["packages/*", "packages2/*"], "packageManager": "npm@10.0.0"}"#, + ) .unwrap(); let watcher = FileSystemWatcher::new_with_default_cookie_dir(&repo_root).unwrap(); @@ -743,7 +747,9 @@ mod test { // update workspaces to no longer cover packages2 repo_root .join_component("package.json") - .create_with_contents(r#"{"workspaces":["packages/*"]}"#) + .create_with_contents( + r#"{"workspaces":["packages/*"], "packageManager": "npm@10.0.0"}"#, + ) .unwrap(); let mut data = package_watcher.discover_packages_blocking().await.unwrap(); @@ -804,7 +810,7 @@ mod test { let root_package_json_path = repo_root.join_component("package.json"); // Start with no workspace glob root_package_json_path - .create_with_contents(r#"{"packageManager": "pnpm@7.0"}"#) + .create_with_contents(r#"{"packageManager": "pnpm@7.0.0"}"#) .unwrap(); repo_root .join_component("pnpm-lock.yaml") @@ -873,7 +879,7 @@ mod test { let root_package_json_path = repo_root.join_component("package.json"); // Start with no workspace glob root_package_json_path - .create_with_contents(r#"{"packageManager": "npm@7.0"}"#) + .create_with_contents(r#"{"packageManager": "npm@7.0.0"}"#) .unwrap(); repo_root .join_component("package-lock.json") @@ -896,7 +902,7 @@ mod test { .unwrap_err(); root_package_json_path - .create_with_contents(r#"{"packageManager": "pnpm@7.0", "workspaces": ["foo/*"]}"#) + .create_with_contents(r#"{"packageManager": "npm@7.0.0", "workspaces": ["foo/*"]}"#) .unwrap(); let resp = package_watcher.discover_packages_blocking().await.unwrap(); @@ -911,7 +917,7 @@ mod test { // Create an invalid workspace glob root_package_json_path - .create_with_contents(r#"{"packageManager": "pnpm@7.0", "workspaces": ["foo/***"]}"#) + .create_with_contents(r#"{"packageManager": "npm@7.0.0", "workspaces": ["foo/***"]}"#) .unwrap(); // We expect an error due to invalid workspace glob @@ -922,7 +928,7 @@ mod test { // Set it back to valid, ensure we recover root_package_json_path - .create_with_contents(r#"{"packageManager": "pnpm@7.0", "workspaces": ["foo/*"]}"#) + .create_with_contents(r#"{"packageManager": "npm@7.0.0", "workspaces": ["foo/*"]}"#) .unwrap(); let resp = package_watcher.discover_packages_blocking().await.unwrap(); assert_eq!(resp.package_manager, PackageManager::Npm); @@ -945,7 +951,7 @@ mod test { let root_package_json_path = repo_root.join_component("package.json"); // Start with no workspace glob root_package_json_path - .create_with_contents(r#"{"packageManager": "pnpm@7.0"}"#) + .create_with_contents(r#"{"packageManager": "pnpm@7.0.0"}"#) .unwrap(); let pnpm_lock_file = repo_root.join_component("pnpm-lock.yaml"); pnpm_lock_file.create_with_contents("").unwrap(); @@ -963,8 +969,8 @@ mod test { let resp = package_watcher.discover_packages_blocking().await.unwrap(); assert_eq!(resp.package_manager, PackageManager::Pnpm); - pnpm_lock_file.remove_file().unwrap(); - // No more lock file, verify we're in an invalid state + workspaces_path.remove_file().unwrap(); + // No more workspaces file, verify we're in an invalid state package_watcher .discover_packages_blocking() .await @@ -980,7 +986,7 @@ mod test { // update package.json to complete the transition root_package_json_path - .create_with_contents(r#"{"packageManager": "npm@7.0", "workspaces": ["foo/*"]}"#) + .create_with_contents(r#"{"packageManager": "npm@7.0.0", "workspaces": ["foo/*"]}"#) .unwrap(); let resp = package_watcher.discover_packages_blocking().await.unwrap(); assert_eq!(resp.package_manager, PackageManager::Npm); diff --git a/crates/turborepo-repository/src/discovery.rs b/crates/turborepo-repository/src/discovery.rs index cafceb506960b..7a984666167ea 100644 --- a/crates/turborepo-repository/src/discovery.rs +++ b/crates/turborepo-repository/src/discovery.rs @@ -108,7 +108,10 @@ impl PackageDiscoveryBuilder for LocalPackageDiscoveryBuilder { let package_manager = match self.package_manager { Some(pm) => pm, None => { - PackageManager::get_package_manager(&self.repo_root, self.package_json.as_ref())? + let package_json = self.package_json.map(Ok).unwrap_or_else(|| { + PackageJson::load(&self.repo_root.join_component("package.json")) + })?; + PackageManager::get_package_manager(&package_json)? } }; diff --git a/crates/turborepo-repository/src/inference.rs b/crates/turborepo-repository/src/inference.rs index 681deeba162bf..b704d595de463 100644 --- a/crates/turborepo-repository/src/inference.rs +++ b/crates/turborepo-repository/src/inference.rs @@ -77,8 +77,7 @@ impl RepoState { .ok() .map(|package_json| { // FIXME: We should save this package manager that we detected - let package_manager = - PackageManager::get_package_manager(path, Some(&package_json)); + let package_manager = PackageManager::get_package_manager(&package_json); let workspace_globs = package_manager .as_ref() .ok() @@ -152,7 +151,9 @@ mod test { let monorepo_pkg_json = monorepo_root.join_component("package.json"); monorepo_pkg_json.ensure_dir().unwrap(); monorepo_pkg_json - .create_with_contents("{\"workspaces\": [\"packages/*\"]}") + .create_with_contents( + "{\"workspaces\": [\"packages/*\"], \"packageManager\": \"npm@7.0.0\"}", + ) .unwrap(); monorepo_root .join_component("package-lock.json") @@ -188,7 +189,9 @@ mod test { .unwrap(); standalone_monorepo .join_component("package.json") - .create_with_contents("{\"workspaces\": [\"packages/*\"]}") + .create_with_contents( + "{\"workspaces\": [\"packages/*\"], \"packageManager\": \"npm@7.0.0\"}", + ) .unwrap(); standalone_monorepo .join_component("package-lock.json") diff --git a/crates/turborepo-repository/src/package_manager/bun.rs b/crates/turborepo-repository/src/package_manager/bun.rs index 4ed64cb207d46..ab6c654664117 100644 --- a/crates/turborepo-repository/src/package_manager/bun.rs +++ b/crates/turborepo-repository/src/package_manager/bun.rs @@ -1,63 +1 @@ -use turbopath::AbsoluteSystemPath; - -use crate::package_manager::{Error, PackageManager}; - pub const LOCKFILE: &str = "bun.lockb"; - -pub struct BunDetector<'a> { - repo_root: &'a AbsoluteSystemPath, - found: bool, -} - -impl<'a> BunDetector<'a> { - pub fn new(repo_root: &'a AbsoluteSystemPath) -> Self { - Self { - repo_root, - found: false, - } - } -} - -impl<'a> Iterator for BunDetector<'a> { - type Item = Result; - - fn next(&mut self) -> Option { - if self.found { - return None; - } - - self.found = true; - let package_json = self.repo_root.join_component(LOCKFILE); - - if package_json.exists() { - Some(Ok(PackageManager::Bun)) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use std::fs::File; - - use anyhow::Result; - use tempfile::tempdir; - use turbopath::AbsoluteSystemPathBuf; - - use super::LOCKFILE; - use crate::package_manager::PackageManager; - - #[test] - fn test_detect_bun() -> Result<()> { - let repo_root = tempdir()?; - let repo_root_path = AbsoluteSystemPathBuf::try_from(repo_root.path())?; - - let lockfile_path = repo_root.path().join(LOCKFILE); - File::create(lockfile_path)?; - let package_manager = PackageManager::detect_package_manager(&repo_root_path)?; - assert_eq!(package_manager, PackageManager::Bun); - - Ok(()) - } -} diff --git a/crates/turborepo-repository/src/package_manager/mod.rs b/crates/turborepo-repository/src/package_manager/mod.rs index e8f0d95abe7ef..7530682f96ec7 100644 --- a/crates/turborepo-repository/src/package_manager/mod.rs +++ b/crates/turborepo-repository/src/package_manager/mod.rs @@ -24,8 +24,8 @@ use which::which; use crate::{ discovery, - package_json::PackageJson, - package_manager::{bun::BunDetector, npm::NpmDetector, pnpm::PnpmDetector, yarn::YarnDetector}, + package_json::{self, PackageJson}, + package_manager::{pnpm::PnpmDetector, yarn::YarnDetector}, }; #[derive(Debug, Deserialize)] @@ -273,6 +273,8 @@ pub enum Error { #[error("globbing error: {0}")] Wax(Box, #[backtrace] backtrace::Backtrace), #[error(transparent)] + PackageJson(#[from] package_json::Error), + #[error(transparent)] Other(#[from] anyhow::Error), #[error(transparent)] NoPackageManager(#[from] NoPackageManager), @@ -303,6 +305,10 @@ pub enum Error { #[error("discovering workspace: {0}")] WorkspaceDiscovery(#[from] discovery::Error), + #[error("missing packageManager field in package.json")] + MissingPackageManager, + #[error("{0} set in packageManager is not a supported package manager")] + UnsupportedPackageManager(String), } impl From for Error { @@ -414,57 +420,24 @@ impl PackageManager { /// /// TODO: consider if this method should not need an Option, and possibly be /// a method on PackageJSON - pub fn get_package_manager( - repo_root: &AbsoluteSystemPath, - pkg: Option<&PackageJson>, - ) -> Result { - // We don't surface errors for `read_package_manager` as we can fall back to - // `detect_package_manager` - if let Some(package_json) = pkg { - if let Ok(Some(package_manager)) = Self::read_package_manager(package_json) { - return Ok(package_manager); - } - } - - Self::detect_package_manager(repo_root) + pub fn get_package_manager(package_json: &PackageJson) -> Result { + Self::read_package_manager(package_json) } // Attempts to read the package manager from the package.json - fn read_package_manager(pkg: &PackageJson) -> Result, Error> { + fn read_package_manager(pkg: &PackageJson) -> Result { let Some(package_manager) = &pkg.package_manager else { - return Ok(None); + return Err(Error::MissingPackageManager); }; let (manager, version) = Self::parse_package_manager_string(package_manager)?; let version = version.parse()?; - let manager = match manager { - "npm" => Some(PackageManager::Npm), - "bun" => Some(PackageManager::Bun), - "yarn" => Some(YarnDetector::detect_berry_or_yarn(&version)?), - "pnpm" => Some(PnpmDetector::detect_pnpm6_or_pnpm(&version)?), - _ => None, - }; - - Ok(manager) - } - - fn detect_package_manager(repo_root: &AbsoluteSystemPath) -> Result { - let mut detected_package_managers = PnpmDetector::new(repo_root) - .chain(NpmDetector::new(repo_root)) - .chain(YarnDetector::new(repo_root)) - .chain(BunDetector::new(repo_root)) - .collect::, Error>>()?; - - match detected_package_managers.len() { - 0 => Err(NoPackageManager.into()), - 1 => Ok(detected_package_managers.pop().unwrap()), - _ => { - let managers = detected_package_managers - .iter() - .map(|mgr| mgr.to_string()) - .collect(); - Err(Error::MultiplePackageManagers { managers }) - } + match manager { + "npm" => Ok(PackageManager::Npm), + "bun" => Ok(PackageManager::Bun), + "yarn" => Ok(YarnDetector::detect_berry_or_yarn(&version)?), + "pnpm" => Ok(PnpmDetector::detect_pnpm6_or_pnpm(&version)?), + _ => Err(Error::UnsupportedPackageManager(manager.to_owned())), } } @@ -805,52 +778,27 @@ mod tests { ..Default::default() }; let package_manager = PackageManager::read_package_manager(&package_json)?; - assert_eq!(package_manager, Some(PackageManager::Npm)); + assert_eq!(package_manager, PackageManager::Npm); package_json.package_manager = Some("yarn@2.0.0".to_string()); let package_manager = PackageManager::read_package_manager(&package_json)?; - assert_eq!(package_manager, Some(PackageManager::Berry)); + assert_eq!(package_manager, PackageManager::Berry); package_json.package_manager = Some("yarn@1.9.0".to_string()); let package_manager = PackageManager::read_package_manager(&package_json)?; - assert_eq!(package_manager, Some(PackageManager::Yarn)); + assert_eq!(package_manager, PackageManager::Yarn); package_json.package_manager = Some("pnpm@6.0.0".to_string()); let package_manager = PackageManager::read_package_manager(&package_json)?; - assert_eq!(package_manager, Some(PackageManager::Pnpm6)); + assert_eq!(package_manager, PackageManager::Pnpm6); package_json.package_manager = Some("pnpm@7.2.0".to_string()); let package_manager = PackageManager::read_package_manager(&package_json)?; - assert_eq!(package_manager, Some(PackageManager::Pnpm)); + assert_eq!(package_manager, PackageManager::Pnpm); package_json.package_manager = Some("bun@1.0.1".to_string()); let package_manager = PackageManager::read_package_manager(&package_json)?; - assert_eq!(package_manager, Some(PackageManager::Bun)); - - Ok(()) - } - - #[test] - fn test_detect_multiple_package_managers() -> Result<(), Error> { - let repo_root = tempdir()?; - let repo_root_path = AbsoluteSystemPathBuf::try_from(repo_root.path())?; - - let package_lock_json_path = repo_root.path().join(npm::LOCKFILE); - File::create(&package_lock_json_path)?; - let pnpm_lock_path = repo_root.path().join(pnpm::LOCKFILE); - File::create(pnpm_lock_path)?; - - let error = PackageManager::detect_package_manager(&repo_root_path).unwrap_err(); - assert_eq!( - error.to_string(), - "We detected multiple package managers in your repository: pnpm, npm. Please remove \ - one of them." - ); - - fs::remove_file(&package_lock_json_path)?; - - let package_manager = PackageManager::detect_package_manager(&repo_root_path)?; - assert_eq!(package_manager, PackageManager::Pnpm); + assert_eq!(package_manager, PackageManager::Bun); Ok(()) } diff --git a/crates/turborepo-repository/src/package_manager/npm.rs b/crates/turborepo-repository/src/package_manager/npm.rs index 969e2dd3cb820..73a0f58646ce9 100644 --- a/crates/turborepo-repository/src/package_manager/npm.rs +++ b/crates/turborepo-repository/src/package_manager/npm.rs @@ -1,63 +1 @@ -use turbopath::AbsoluteSystemPath; - -use crate::package_manager::{Error, PackageManager}; - pub const LOCKFILE: &str = "package-lock.json"; - -pub struct NpmDetector<'a> { - repo_root: &'a AbsoluteSystemPath, - found: bool, -} - -impl<'a> NpmDetector<'a> { - pub fn new(repo_root: &'a AbsoluteSystemPath) -> Self { - Self { - repo_root, - found: false, - } - } -} - -impl<'a> Iterator for NpmDetector<'a> { - type Item = Result; - - fn next(&mut self) -> Option { - if self.found { - return None; - } - - self.found = true; - let package_json = self.repo_root.join_component(LOCKFILE); - - if package_json.exists() { - Some(Ok(PackageManager::Npm)) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use std::fs::File; - - use anyhow::Result; - use tempfile::tempdir; - use turbopath::AbsoluteSystemPathBuf; - - use super::LOCKFILE; - use crate::package_manager::PackageManager; - - #[test] - fn test_detect_npm() -> Result<()> { - let repo_root = tempdir()?; - let repo_root_path = AbsoluteSystemPathBuf::try_from(repo_root.path())?; - - let lockfile_path = repo_root.path().join(LOCKFILE); - File::create(lockfile_path)?; - let package_manager = PackageManager::detect_package_manager(&repo_root_path)?; - assert_eq!(package_manager, PackageManager::Npm); - - Ok(()) - } -} diff --git a/crates/turborepo-repository/src/package_manager/pnpm.rs b/crates/turborepo-repository/src/package_manager/pnpm.rs index d0fe7f9af1af1..50b4dd2de4d23 100644 --- a/crates/turborepo-repository/src/package_manager/pnpm.rs +++ b/crates/turborepo-repository/src/package_manager/pnpm.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use node_semver::{Range, Version}; -use turbopath::{AbsoluteSystemPath, RelativeUnixPath}; +use turbopath::RelativeUnixPath; use crate::{ package_json::PackageJson, @@ -10,19 +10,9 @@ use crate::{ pub const LOCKFILE: &str = "pnpm-lock.yaml"; -pub struct PnpmDetector<'a> { - found: bool, - repo_root: &'a AbsoluteSystemPath, -} - -impl<'a> PnpmDetector<'a> { - pub fn new(repo_root: &'a AbsoluteSystemPath) -> Self { - Self { - repo_root, - found: false, - } - } +pub struct PnpmDetector; +impl PnpmDetector { 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()?; @@ -36,21 +26,6 @@ impl<'a> PnpmDetector<'a> { } } -impl<'a> Iterator for PnpmDetector<'a> { - type Item = Result; - - fn next(&mut self) -> Option { - if self.found { - return None; - } - self.found = true; - - let pnpm_lockfile = self.repo_root.join_component(LOCKFILE); - - pnpm_lockfile.exists().then(|| Ok(PackageManager::Pnpm)) - } -} - pub(crate) fn prune_patches>( package_json: &PackageJson, patches: &[R], @@ -69,30 +44,6 @@ pub(crate) fn prune_patches>( pruned_json } -#[cfg(test)] -mod tests { - use std::fs::File; - - use anyhow::Result; - use tempfile::tempdir; - use turbopath::AbsoluteSystemPathBuf; - - use super::LOCKFILE; - use crate::package_manager::PackageManager; - - #[test] - fn test_detect_pnpm() -> Result<()> { - let repo_root = tempdir()?; - let repo_root_path = AbsoluteSystemPathBuf::try_from(repo_root.path())?; - let lockfile_path = repo_root.path().join(LOCKFILE); - File::create(lockfile_path)?; - let package_manager = PackageManager::detect_package_manager(&repo_root_path)?; - assert_eq!(package_manager, PackageManager::Pnpm); - - Ok(()) - } -} - #[cfg(test)] mod test { use std::collections::BTreeMap; diff --git a/crates/turborepo-repository/src/package_manager/yarn.rs b/crates/turborepo-repository/src/package_manager/yarn.rs index 7105e65958b34..65511255edef0 100644 --- a/crates/turborepo-repository/src/package_manager/yarn.rs +++ b/crates/turborepo-repository/src/package_manager/yarn.rs @@ -1,8 +1,5 @@ -use std::process::Command; - use node_semver::{Range, Version}; -use turbopath::{AbsoluteSystemPath, RelativeUnixPath}; -use which::which; +use turbopath::RelativeUnixPath; use crate::{ package_json::PackageJson, @@ -11,42 +8,9 @@ use crate::{ pub const LOCKFILE: &str = "yarn.lock"; -pub struct YarnDetector<'a> { - repo_root: &'a AbsoluteSystemPath, - // For testing purposes - version_override: Option, - found: bool, -} - -impl<'a> YarnDetector<'a> { - pub fn new(repo_root: &'a AbsoluteSystemPath) -> Self { - Self { - repo_root, - version_override: None, - found: false, - } - } - - #[cfg(test)] - fn set_version_override(&mut self, version: Version) { - self.version_override = Some(version); - } - - fn get_yarn_version(&self) -> Result { - if let Some(version) = &self.version_override { - return Ok(version.clone()); - } - - let binary = "yarn"; - let yarn_binary = which(binary).map_err(|e| Error::Which(e, binary.to_string()))?; - let output = Command::new(yarn_binary) - .arg("--version") - .current_dir(self.repo_root) - .output()?; - let yarn_version_output = String::from_utf8(output.stdout)?; - Ok(yarn_version_output.trim().parse()?) - } +pub struct YarnDetector; +impl YarnDetector { pub fn detect_berry_or_yarn(version: &Version) -> Result { let berry_constraint: Range = ">=2.0.0-0".parse()?; if berry_constraint.satisfies(version) { @@ -57,28 +21,6 @@ impl<'a> YarnDetector<'a> { } } -impl<'a> Iterator for YarnDetector<'a> { - type Item = Result; - - fn next(&mut self) -> Option { - if self.found { - return None; - } - self.found = true; - - let yarn_lockfile = self.repo_root.join_component(LOCKFILE); - - if yarn_lockfile.exists() { - Some( - self.get_yarn_version() - .and_then(|version| Self::detect_berry_or_yarn(&version)), - ) - } else { - None - } - } -} - pub(crate) fn prune_patches>( package_json: &PackageJson, patches: &[R], @@ -103,14 +45,13 @@ pub(crate) fn prune_patches>( #[cfg(test)] mod tests { - use std::{collections::BTreeMap, fs::File}; + use std::collections::BTreeMap; use anyhow::Result; use serde_json::json; - use tempfile::tempdir; - use turbopath::{AbsoluteSystemPathBuf, RelativeUnixPathBuf}; + use turbopath::RelativeUnixPathBuf; - use super::{prune_patches, LOCKFILE}; + use super::prune_patches; use crate::{ package_json::PackageJson, package_manager::{yarn::YarnDetector, PackageManager}, @@ -118,20 +59,10 @@ mod tests { #[test] fn test_detect_yarn() -> Result<()> { - let repo_root = tempdir()?; - let repo_root_path = AbsoluteSystemPathBuf::try_from(repo_root.path())?; - - let yarn_lock_path = repo_root.path().join(LOCKFILE); - File::create(yarn_lock_path)?; - - let mut detector = YarnDetector::new(&repo_root_path); - detector.set_version_override("1.22.10".parse()?); - let package_manager = detector.next().unwrap()?; + let package_manager = YarnDetector::detect_berry_or_yarn(&"1.22.10".parse()?)?; assert_eq!(package_manager, PackageManager::Yarn); - let mut detector = YarnDetector::new(&repo_root_path); - detector.set_version_override("2.22.10".parse()?); - let package_manager = detector.next().unwrap()?; + let package_manager = YarnDetector::detect_berry_or_yarn(&"2.22.10".parse()?)?; assert_eq!(package_manager, PackageManager::Berry); Ok(()) diff --git a/turborepo-tests/helpers/setup_integration_test.sh b/turborepo-tests/helpers/setup_integration_test.sh index 98ff0d709ecb7..eb09d44ee9c2e 100755 --- a/turborepo-tests/helpers/setup_integration_test.sh +++ b/turborepo-tests/helpers/setup_integration_test.sh @@ -3,7 +3,12 @@ set -eo pipefail FIXTURE_NAME="${1-basic_monorepo}" -PACKAGE_MANAGER="$2" + +# Default to version of npm installed with Node 18.20.2 +PACKAGE_MANAGER="npm@10.5.0" +if [[ $2 != "" ]]; then + PACKAGE_MANAGER="$2" +fi THIS_DIR=$(dirname "${BASH_SOURCE[0]}") MONOREPO_ROOT_DIR="$THIS_DIR/../.." diff --git a/turborepo-tests/integration/tests/dry-json/single-package-no-config.t b/turborepo-tests/integration/tests/dry-json/single-package-no-config.t index 4f22e1bfad203..747dfc8ace1cb 100644 --- a/turborepo-tests/integration/tests/dry-json/single-package-no-config.t +++ b/turborepo-tests/integration/tests/dry-json/single-package-no-config.t @@ -13,7 +13,7 @@ Setup "rootKey": "HEY STELLLLLLLAAAAAAAAAAAAA", "files": { "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328" + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32" }, "hashOfExternalDependencies": "", "globalDotEnv": null, @@ -33,11 +33,11 @@ Setup { "taskId": "build", "task": "build", - "hash": "e46d6df5143cae99", + "hash": "bfac661137d88079", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, "hashOfExternalDependencies": "", diff --git a/turborepo-tests/integration/tests/dry-json/single-package-with-deps.t b/turborepo-tests/integration/tests/dry-json/single-package-with-deps.t index 3acf6bc00bbd6..b8bb2e47cb482 100644 --- a/turborepo-tests/integration/tests/dry-json/single-package-with-deps.t +++ b/turborepo-tests/integration/tests/dry-json/single-package-with-deps.t @@ -11,7 +11,7 @@ Setup "rootKey": "HEY STELLLLLLLAAAAAAAAAAAAA", "files": { "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, "hashOfExternalDependencies": "", @@ -32,11 +32,11 @@ Setup { "taskId": "build", "task": "build", - "hash": "f09bf783beacf5c9", + "hash": "45fcb56a23295f63", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "turbo.json": "bf9ddbce36808b6ea5a0ea2b7ceb400ee6c42c4c" }, @@ -89,11 +89,11 @@ Setup { "taskId": "test", "task": "test", - "hash": "8bfab5dc6b4ccb3b", + "hash": "314a0e5a10072ae2", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "turbo.json": "bf9ddbce36808b6ea5a0ea2b7ceb400ee6c42c4c" }, diff --git a/turborepo-tests/integration/tests/dry-json/single-package.t b/turborepo-tests/integration/tests/dry-json/single-package.t index 3b18ebebe1803..dbff4661579f4 100644 --- a/turborepo-tests/integration/tests/dry-json/single-package.t +++ b/turborepo-tests/integration/tests/dry-json/single-package.t @@ -11,7 +11,7 @@ Setup "rootKey": "HEY STELLLLLLLAAAAAAAAAAAAA", "files": { "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, "hashOfExternalDependencies": "", @@ -32,11 +32,11 @@ Setup { "taskId": "build", "task": "build", - "hash": "f09bf783beacf5c9", + "hash": "45fcb56a23295f63", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "turbo.json": "bf9ddbce36808b6ea5a0ea2b7ceb400ee6c42c4c" }, diff --git a/turborepo-tests/integration/tests/package-manager.t b/turborepo-tests/integration/tests/package-manager.t index a1d0a6b29abee..34caf8a93253e 100644 --- a/turborepo-tests/integration/tests/package-manager.t +++ b/turborepo-tests/integration/tests/package-manager.t @@ -39,48 +39,3 @@ Set package manager to pnpm in package.json Run test run $ TURBO_LOG_VERBOSITY=off ${TURBO} info --json | jq .packageManager "pnpm" - -Clear package manager field in package.json - $ jq 'del(.packageManager)' package.json > package.json.tmp && mv package.json.tmp package.json - -Delete package-lock.json - $ rm package-lock.json - -Use yarn 1.22.19 - $ corepack prepare yarn@1.22.19 --activate - Preparing yarn@1.22.19 for immediate activation... - -Create yarn.lock - $ touch yarn.lock - -Run test run - $ TURBO_LOG_VERBOSITY=off ${TURBO} info --json | jq .packageManager - "yarn" - -Use yarn 3.5.1 - $ corepack prepare yarn@3.5.1 --activate - Preparing yarn@3.5.1 for immediate activation... - -Run test run - $ TURBO_LOG_VERBOSITY=off ${TURBO} info --json | jq .packageManager - "berry" - -Delete yarn.lock - $ rm yarn.lock - -Create pnpm-lock.yaml - $ touch pnpm-lock.yaml - -Run test run - $ TURBO_LOG_VERBOSITY=off ${TURBO} info --json | jq .packageManager - "pnpm" - -Delete pnpm-lock.yaml - $ rm pnpm-lock.yaml - -Create package-lock.json - $ touch package-lock.json - -Run test run - $ TURBO_LOG_VERBOSITY=off ${TURBO} info --json | jq .packageManager - "npm" diff --git a/turborepo-tests/integration/tests/run/single-package/dry-run.t b/turborepo-tests/integration/tests/run/single-package/dry-run.t index fc30d4917bdb5..5cb392a6ca671 100644 --- a/turborepo-tests/integration/tests/run/single-package/dry-run.t +++ b/turborepo-tests/integration/tests/run/single-package/dry-run.t @@ -18,7 +18,7 @@ Check Tasks to Run build Task = build\s* (re) - Hash = f09bf783beacf5c9\s* (re) + Hash = 45fcb56a23295f63 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = echo building > foo.txt\s* (re) diff --git a/turborepo-tests/integration/tests/run/single-package/no-config.t b/turborepo-tests/integration/tests/run/single-package/no-config.t index 83c4e36c030e2..9af9a572f9647 100644 --- a/turborepo-tests/integration/tests/run/single-package/no-config.t +++ b/turborepo-tests/integration/tests/run/single-package/no-config.t @@ -20,7 +20,7 @@ Check Tasks to Run build Task = build\s* (re) - Hash = e46d6df5143cae99\s* (re) + Hash = bfac661137d88079 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = echo building > foo.txt\s* (re) @@ -52,7 +52,7 @@ Run real once $ ${TURBO} run build \xe2\x80\xa2 Running build (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache bypass, force executing e46d6df5143cae99 + build: cache bypass, force executing bfac661137d88079 build: build: > build build: > echo building > foo.txt @@ -66,7 +66,7 @@ Run a second time, verify no caching because there is no config $ ${TURBO} run build \xe2\x80\xa2 Running build (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache bypass, force executing e46d6df5143cae99 + build: cache bypass, force executing bfac661137d88079 build: build: > build build: > echo building > foo.txt diff --git a/turborepo-tests/integration/tests/run/single-package/run.t b/turborepo-tests/integration/tests/run/single-package/run.t index 65ab3cddf1d8d..de4290a16e20f 100644 --- a/turborepo-tests/integration/tests/run/single-package/run.t +++ b/turborepo-tests/integration/tests/run/single-package/run.t @@ -5,7 +5,7 @@ Check $ ${TURBO} run build \xe2\x80\xa2 Running build (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache miss, executing f09bf783beacf5c9 + build: cache miss, executing 45fcb56a23295f63 build: build: > build build: > echo building > foo.txt @@ -22,7 +22,7 @@ Run a second time, verify caching works because there is a config $ ${TURBO} run build \xe2\x80\xa2 Running build (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache hit, replaying logs f09bf783beacf5c9 + build: cache hit, replaying logs 45fcb56a23295f63 build: build: > build build: > echo building > foo.txt diff --git a/turborepo-tests/integration/tests/run/single-package/with-deps-dry-run.t b/turborepo-tests/integration/tests/run/single-package/with-deps-dry-run.t index d345c44416323..6f251fb151239 100644 --- a/turborepo-tests/integration/tests/run/single-package/with-deps-dry-run.t +++ b/turborepo-tests/integration/tests/run/single-package/with-deps-dry-run.t @@ -18,7 +18,7 @@ Check Tasks to Run build Task = build\s* (re) - Hash = f09bf783beacf5c9\s* (re) + Hash = 45fcb56a23295f63 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = echo building > foo.txt\s* (re) @@ -37,7 +37,7 @@ Check Framework =\s* (re) test Task = test\s* (re) - Hash = 8bfab5dc6b4ccb3b\s* (re) + Hash = 314a0e5a10072ae2 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = cat foo.txt\s* (re) diff --git a/turborepo-tests/integration/tests/run/single-package/with-deps-run.t b/turborepo-tests/integration/tests/run/single-package/with-deps-run.t index 24706cdb5c6cf..2440a21185470 100644 --- a/turborepo-tests/integration/tests/run/single-package/with-deps-run.t +++ b/turborepo-tests/integration/tests/run/single-package/with-deps-run.t @@ -5,12 +5,12 @@ Check $ ${TURBO} run test \xe2\x80\xa2 Running test (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache miss, executing f09bf783beacf5c9 + build: cache miss, executing 45fcb56a23295f63 build: build: > build build: > echo building > foo.txt build: - test: cache miss, executing 8bfab5dc6b4ccb3b + test: cache miss, executing 314a0e5a10072ae2 test: test: > test test: > cat foo.txt @@ -25,12 +25,12 @@ Run a second time, verify caching works because there is a config $ ${TURBO} run test \xe2\x80\xa2 Running test (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache hit, replaying logs f09bf783beacf5c9 + build: cache hit, replaying logs 45fcb56a23295f63 build: build: > build build: > echo building > foo.txt build: - test: cache hit, replaying logs 8bfab5dc6b4ccb3b + test: cache hit, replaying logs 314a0e5a10072ae2 test: test: > test test: > cat foo.txt @@ -45,8 +45,8 @@ Run with --output-logs=hash-only $ ${TURBO} run test --output-logs=hash-only \xe2\x80\xa2 Running test (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache hit, suppressing logs f09bf783beacf5c9 - test: cache hit, suppressing logs 8bfab5dc6b4ccb3b + build: cache hit, suppressing logs 45fcb56a23295f63 + test: cache hit, suppressing logs 314a0e5a10072ae2 Tasks: 2 successful, 2 total Cached: 2 cached, 2 total diff --git a/turborepo-tests/integration/tests/task-dependencies/root-worksapce.t b/turborepo-tests/integration/tests/task-dependencies/root-worksapce.t index 48ece27d58c76..e59b98213a0be 100644 --- a/turborepo-tests/integration/tests/task-dependencies/root-worksapce.t +++ b/turborepo-tests/integration/tests/task-dependencies/root-worksapce.t @@ -11,7 +11,7 @@ This tests asserts that root tasks can depend on workspace#task lib-a:build: > echo build-lib-a lib-a:build: lib-a:build: build-lib-a - //:mytask: cache miss, executing 3ae433af4902b1a0 + //:mytask: cache miss, executing 8546b6a2ce1f1d1f //:mytask: //:mytask: > mytask //:mytask: > echo root-mytask