diff --git a/cli/LICENSE b/cli/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/cli/LICENSE +++ b/cli/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cli/scripts/npm-native-packages/template/template.package.json b/cli/scripts/npm-native-packages/template/template.package.json index fdc72c01b6bfb..08bef48a2aaee 100644 --- a/cli/scripts/npm-native-packages/template/template.package.json +++ b/cli/scripts/npm-native-packages/template/template.package.json @@ -5,7 +5,7 @@ "repository": "https://github.com/vercel/turbo", "bugs": "https://github.com/vercel/turbo/issues", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "os": ["{{Os}}"], "cpu": ["{{Arch}}"], "preferUnplugged": true diff --git a/crates/turborepo-analytics/Cargo.toml b/crates/turborepo-analytics/Cargo.toml index e774443b9c545..554c3a5675e63 100644 --- a/crates/turborepo-analytics/Cargo.toml +++ b/crates/turborepo-analytics/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-analytics" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-api-client/Cargo.toml b/crates/turborepo-api-client/Cargo.toml index 306ecb9656ede..b2fc9aca6b6a2 100644 --- a/crates/turborepo-api-client/Cargo.toml +++ b/crates/turborepo-api-client/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-api-client" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] diff --git a/crates/turborepo-auth/Cargo.toml b/crates/turborepo-auth/Cargo.toml index 11724cdfa54d7..477a04ab73664 100644 --- a/crates/turborepo-auth/Cargo.toml +++ b/crates/turborepo-auth/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-auth" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" [lints] workspace = true diff --git a/crates/turborepo-cache/Cargo.toml b/crates/turborepo-cache/Cargo.toml index 0a79d1bd10f11..08ea0eed08933 100644 --- a/crates/turborepo-cache/Cargo.toml +++ b/crates/turborepo-cache/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "turborepo-cache" version = "0.1.0" -license = "MPL-2.0" +license = "MIT" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-cache/src/async_cache.rs b/crates/turborepo-cache/src/async_cache.rs index f117d21aebc37..d03fd61912764 100644 --- a/crates/turborepo-cache/src/async_cache.rs +++ b/crates/turborepo-cache/src/async_cache.rs @@ -301,12 +301,8 @@ mod tests { // Wait for async cache to process async_cache.wait().await.unwrap(); - let fs_cache_path = repo_root_path.join_components(&[ - "node_modules", - ".cache", - "turbo", - &format!("{}.tar.zst", hash), - ]); + let fs_cache_path = + repo_root_path.join_components(&[".turbo", "cache", &format!("{}.tar.zst", hash)]); // Confirm that fs cache file does *not* exist assert!(!fs_cache_path.exists()); @@ -389,12 +385,8 @@ mod tests { // Wait for async cache to process async_cache.wait().await.unwrap(); - let fs_cache_path = repo_root_path.join_components(&[ - "node_modules", - ".cache", - "turbo", - &format!("{}.tar.zst", hash), - ]); + let fs_cache_path = + repo_root_path.join_components(&[".turbo", "cache", &format!("{}.tar.zst", hash)]); // Confirm that fs cache file exists assert!(fs_cache_path.exists()); @@ -483,12 +475,8 @@ mod tests { // Wait for async cache to process async_cache.wait().await.unwrap(); - let fs_cache_path = repo_root_path.join_components(&[ - "node_modules", - ".cache", - "turbo", - &format!("{}.tar.zst", hash), - ]); + let fs_cache_path = + repo_root_path.join_components(&[".turbo", "cache", &format!("{}.tar.zst", hash)]); // Confirm that fs cache file exists assert!(fs_cache_path.exists()); diff --git a/crates/turborepo-cache/src/fs.rs b/crates/turborepo-cache/src/fs.rs index 629d337241451..a8a205ec5d783 100644 --- a/crates/turborepo-cache/src/fs.rs +++ b/crates/turborepo-cache/src/fs.rs @@ -37,7 +37,7 @@ impl FSCache { if let Some(override_dir) = override_dir { AbsoluteSystemPathBuf::from_unknown(repo_root, override_dir) } else { - repo_root.join_components(&["node_modules", ".cache", "turbo"]) + repo_root.join_components(&[".turbo", "cache"]) } } diff --git a/crates/turborepo-ci/Cargo.toml b/crates/turborepo-ci/Cargo.toml index 343ec7900fbd1..4d833b5ddf49c 100644 --- a/crates/turborepo-ci/Cargo.toml +++ b/crates/turborepo-ci/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-ci" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-dirs/Cargo.toml b/crates/turborepo-dirs/Cargo.toml index 5ad3e4177f554..9761ce2f6cf59 100644 --- a/crates/turborepo-dirs/Cargo.toml +++ b/crates/turborepo-dirs/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-dirs" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-env/Cargo.toml b/crates/turborepo-env/Cargo.toml index eff52b2121c88..73ccd8f1f173d 100644 --- a/crates/turborepo-env/Cargo.toml +++ b/crates/turborepo-env/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-env" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-env/src/lib.rs b/crates/turborepo-env/src/lib.rs index ee35d5fd46cdc..399f0b5261565 100644 --- a/crates/turborepo-env/src/lib.rs +++ b/crates/turborepo-env/src/lib.rs @@ -13,22 +13,6 @@ use thiserror::Error; const DEFAULT_ENV_VARS: [&str; 1] = ["VERCEL_ANALYTICS_ID"]; -/// Environment mode after we've resolved the `Infer` variant -#[derive(Debug, Clone, Copy)] -pub enum ResolvedEnvMode { - Loose, - Strict, -} - -impl std::fmt::Display for ResolvedEnvMode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ResolvedEnvMode::Loose => write!(f, "loose"), - ResolvedEnvMode::Strict => write!(f, "strict"), - } - } -} - #[derive(Clone, Debug, Error)] pub enum Error { #[error("Failed to parse regex: {0}")] diff --git a/crates/turborepo-errors/Cargo.toml b/crates/turborepo-errors/Cargo.toml index 95704e4733bf3..3b2ce11bc2667 100644 --- a/crates/turborepo-errors/Cargo.toml +++ b/crates/turborepo-errors/Cargo.toml @@ -3,7 +3,7 @@ name = "turborepo-errors" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-filewatch/Cargo.toml b/crates/turborepo-filewatch/Cargo.toml index 3b8285a80c9db..e5726b630a252 100644 --- a/crates/turborepo-filewatch/Cargo.toml +++ b/crates/turborepo-filewatch/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-filewatch" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 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-fs/Cargo.toml b/crates/turborepo-fs/Cargo.toml index 26cf67a3fe05b..c7fa2c17646dd 100644 --- a/crates/turborepo-fs/Cargo.toml +++ b/crates/turborepo-fs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "turborepo-fs" version = "0.1.0" -license = "MPL-2.0" +license = "MIT" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-globwalk/Cargo.toml b/crates/turborepo-globwalk/Cargo.toml index 48b68a33b38aa..1765d34d076ac 100644 --- a/crates/turborepo-globwalk/Cargo.toml +++ b/crates/turborepo-globwalk/Cargo.toml @@ -2,7 +2,7 @@ name = "globwalk" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-globwalk/src/lib.rs b/crates/turborepo-globwalk/src/lib.rs index b25a6574c2def..f23cf43efdb8f 100644 --- a/crates/turborepo-globwalk/src/lib.rs +++ b/crates/turborepo-globwalk/src/lib.rs @@ -15,7 +15,8 @@ use path_clean::PathClean; use path_slash::PathExt; use rayon::prelude::*; use regex::Regex; -use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf, PathError}; +use tracing::debug; +use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf, PathError, RelativeUnixPath}; use wax::{walk::FileIterator, BuildError, Glob}; #[derive(Debug, PartialEq, Clone, Copy)] @@ -51,10 +52,13 @@ fn join_unix_like_paths(a: &str, b: &str) -> String { [a.trim_end_matches('/'), "/", b.trim_start_matches('/')].concat() } -fn escape_glob_literals(literal_glob: &str) -> Cow { +fn glob_literals() -> &'static Regex { static RE: OnceLock = OnceLock::new(); RE.get_or_init(|| Regex::new(r"(?[\?\*\$:<>\(\)\[\]{},])").unwrap()) - .replace_all(literal_glob, "\\$literal") +} + +fn escape_glob_literals(literal_glob: &str) -> Cow { + glob_literals().replace_all(literal_glob, "\\$literal") } #[tracing::instrument] @@ -63,6 +67,8 @@ fn preprocess_paths_and_globs( include: &[String], exclude: &[String], ) -> Result<(PathBuf, Vec, Vec), WalkError> { + debug!("processing includes: {include:?}"); + debug!("processing excludes: {exclude:?}"); let base_path_slash = base_path .as_std_path() .to_slash() @@ -76,6 +82,12 @@ fn preprocess_paths_and_globs( let (include_paths, lowest_segment) = include .iter() .map(|s| fix_glob_pattern(s)) + .map(|mut s| { + // We need to check inclusion globs before the join + // as to_slash doesn't preserve Windows drive names. + add_doublestar_to_dir(base_path, &mut s); + s + }) .map(|s| join_unix_like_paths(&base_path_slash, &s)) .filter_map(|s| collapse_path(&s).map(|(s, v)| (s.to_string(), v))) .fold( @@ -102,25 +114,12 @@ fn preprocess_paths_and_globs( .map(|s| join_unix_like_paths(&base_path_slash, &s)) .filter_map(|g| collapse_path(&g).map(|(s, _)| s.to_string())) { - let split = split.to_string(); // if the glob ends with a slash, then we need to add a double star, // unless it already ends with a double star - if split.ends_with('/') { - if split.ends_with("**/") { - exclude_paths.push(split[..split.len() - 1].to_string()); - } else { - exclude_paths.push(format!("{}**", split)); - } - } else if split.ends_with("/**") { - exclude_paths.push(split); - } else { - // Match Go globby behavior. If the glob doesn't already end in /**, add it - // TODO: The Go version uses system separator. Are we forcing all globs to unix - // paths? - exclude_paths.push(format!("{}/**", split)); - exclude_paths.push(split); - } + add_trailing_double_star(&mut exclude_paths, &split); } + debug!("processed includes: {include_paths:?}"); + debug!("processed excludes: {exclude_paths:?}"); Ok((base_path, include_paths, exclude_paths)) } @@ -215,6 +214,57 @@ fn collapse_path(path: &str) -> Option<(Cow, usize)> { } } +fn add_trailing_double_star(exclude_paths: &mut Vec, glob: &str) { + if let Some(stripped) = glob.strip_suffix('/') { + if stripped.ends_with("**") { + exclude_paths.push(stripped.to_string()); + } else { + exclude_paths.push(format!("{}**", glob)); + } + } else if glob.ends_with("/**") { + exclude_paths.push(glob.to_string()); + } else { + // Match Go globby behavior. If the glob doesn't already end in /**, add it + // We use the unix style operator as wax expects unix style paths + exclude_paths.push(format!("{}/**", glob)); + exclude_paths.push(glob.to_string()); + } +} + +fn add_doublestar_to_dir(base: &AbsoluteSystemPath, glob: &mut String) { + // If the glob has a glob literal in it e.g. * + // then skip trying to read it as a file path. + if glob_literals().is_match(&*glob) { + return; + } + + // Globs are given in unix style + let Ok(glob_path) = RelativeUnixPath::new(&*glob) else { + // Glob isn't valid relative unix path so can't check if dir + debug!("'{glob}' isn't valid path"); + return; + }; + + let path = base.join_unix_path(glob_path); + + let Ok(metadata) = path.symlink_metadata() else { + debug!("'{path}' doesn't have metadata"); + return; + }; + + if !metadata.is_dir() { + return; + } + + debug!("'{path}' is a directory"); + + // Glob points to a dir, must add ** + if !glob.ends_with('/') { + glob.push('/'); + } + glob.push_str("**"); +} + #[tracing::instrument] fn glob_with_contextual_error + std::fmt::Debug>( raw: S, @@ -370,12 +420,13 @@ mod test { use std::{collections::HashSet, str::FromStr}; use itertools::Itertools; + use tempdir::TempDir; use test_case::test_case; - use turbopath::AbsoluteSystemPathBuf; + use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf}; use crate::{ - collapse_path, escape_glob_literals, fix_glob_pattern, globwalk, ValidatedGlob, WalkError, - WalkType, + add_doublestar_to_dir, collapse_path, escape_glob_literals, fix_glob_pattern, globwalk, + ValidatedGlob, WalkError, WalkType, }; #[cfg(unix)] @@ -537,7 +588,7 @@ mod test { #[test_case("**/*f", 4, 4 => matches None ; "leading doublestar expansion")] #[test_case("**f", 4, 4 => matches None ; "transform leading doublestar")] #[test_case("a**", 22, 22 => matches None ; "transform trailing doublestar")] - #[test_case("abc", 1, 1 => matches None ; "exact match")] + #[test_case("abc", 3, 3 => matches None ; "exact match")] #[test_case("*", 19, 15 => matches None ; "single star match")] #[test_case("*c", 2, 2 => matches None ; "single star suffix match")] #[test_case("a*", 9, 9 => matches None ; "single star prefix match")] @@ -570,7 +621,7 @@ mod test { #[test_case("a/**/b", 2, 2 => matches None ; "a followed by double star and single subdirectory match")] #[test_case("a/**/c", 2, 2 => matches None ; "a followed by double star and multiple subdirectories match 2")] #[test_case("a/**/d", 1, 1 => matches None ; "a followed by double star and multiple subdirectories with target match")] - #[test_case("a/b/c", 1, 1 => matches None ; "a followed by subdirectories and double slash mismatch")] + #[test_case("a/b/c", 2, 2 => matches None ; "a followed by subdirectories and double slash mismatch")] #[test_case("ab{c,d}", 1, 1 => matches None ; "pattern with curly braces match")] #[test_case("ab{c,d,*}", 5, 5 => matches None ; "pattern with curly braces and wildcard match")] #[test_case("ab{c,d}[", 0, 0 => matches Some(WalkError::BadPattern(_, _)))] @@ -903,8 +954,21 @@ mod test { "/repos/some-app/", &["dist"], &[], - &["/repos/some-app/dist"], - &[] + &[ + "/repos/some-app/dist", + "/repos/some-app/dist/index.html", + "/repos/some-app/dist/js", + "/repos/some-app/dist/js/index.js", + "/repos/some-app/dist/js/lib.js", + "/repos/some-app/dist/js/node_modules", + "/repos/some-app/dist/js/node_modules/browserify.js", + ], + &[ + "/repos/some-app/dist/index.html", + "/repos/some-app/dist/js/index.js", + "/repos/some-app/dist/js/lib.js", + "/repos/some-app/dist/js/node_modules/browserify.js", + ] ; "passing just a directory captures no children")] #[test_case(&[ "/repos/some-app/dist/index.html", @@ -1423,4 +1487,26 @@ mod test { r"\?\*\$\:\<\>\(\)\[\]\{\}\," ); } + + #[test_case("foo", false, "foo" ; "file")] + #[test_case("foo", true, "foo/**" ; "dir")] + #[test_case("foo/", true, "foo/**" ; "dir slash")] + #[test_case("f[o0]o", true, "f[o0]o" ; "non-literal")] + fn test_add_double_star(glob: &str, is_dir: bool, expected: &str) { + let tmpdir = TempDir::new("doublestar").unwrap(); + let base = AbsoluteSystemPath::new(tmpdir.path().to_str().unwrap()).unwrap(); + + let foo = base.join_component("foo"); + + match is_dir { + true => foo.create_dir_all().unwrap(), + false => foo.create_with_contents(b"bar").unwrap(), + } + + let mut glob = glob.to_owned(); + + add_doublestar_to_dir(base, &mut glob); + + assert_eq!(glob, expected); + } } diff --git a/crates/turborepo-graph-utils/Cargo.toml b/crates/turborepo-graph-utils/Cargo.toml index 6b8ce2eea7434..e3772127fde4e 100644 --- a/crates/turborepo-graph-utils/Cargo.toml +++ b/crates/turborepo-graph-utils/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-graph-utils" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" [lints] workspace = true diff --git a/crates/turborepo-lib/Cargo.toml b/crates/turborepo-lib/Cargo.toml index e2bbccadd4506..23b1dfc030508 100644 --- a/crates/turborepo-lib/Cargo.toml +++ b/crates/turborepo-lib/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-lib" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" [features] # Allows configuring a specific tls backend for reqwest. diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index dd9dc72a7a1c7..2a6d54d361850 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -9,7 +9,7 @@ use clap::{ use clap_complete::{generate, Shell}; pub use error::Error; use serde::{Deserialize, Serialize}; -use tracing::{debug, error, warn}; +use tracing::{debug, error}; use turbopath::AbsoluteSystemPathBuf; use turborepo_api_client::AnonAPIClient; use turborepo_repository::inference::{RepoMode, RepoState}; @@ -121,17 +121,16 @@ impl Display for DryRunMode { } #[derive(Copy, Clone, Debug, Default, PartialEq, Serialize, ValueEnum)] +#[serde(rename_all = "lowercase")] pub enum EnvMode { - #[default] - Infer, Loose, + #[default] Strict, } impl fmt::Display for EnvMode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { - EnvMode::Infer => "infer", EnvMode::Loose => "loose", EnvMode::Strict => "strict", }) @@ -163,9 +162,6 @@ pub struct Args { /// Force color usage in the terminal #[clap(long, global = true)] pub color: bool, - /// Specify a file to save a cpu profile - #[clap(long = "cpuprofile", global = true, value_parser)] - pub cpu_profile: Option, /// The directory in which to run turbo #[clap(long, global = true, value_parser)] pub cwd: Option, @@ -203,9 +199,6 @@ pub struct Args { pub check_for_update: bool, #[clap(long = "__test-run", global = true, hide = true)] pub test_run: bool, - /// Enable the experimental UI - #[clap(long, hide = true, global = true)] - pub experimental_ui: bool, #[clap(flatten, next_help_heading = "Run Arguments")] #[serde(skip)] pub run_args: Option, @@ -400,7 +393,6 @@ impl Args { track_usage!(tel, &self.login, Option::is_some); track_usage!(tel, &self.cwd, Option::is_some); track_usage!(tel, &self.heap, Option::is_some); - track_usage!(tel, &self.cpu_profile, Option::is_some); track_usage!(tel, &self.team, Option::is_some); track_usage!(tel, &self.token, Option::is_some); track_usage!(tel, &self.trace, Option::is_some); @@ -677,9 +669,7 @@ pub struct ExecutionArgs { /// Environment variable mode. /// Use "loose" to pass the entire existing environment. /// Use "strict" to use an allowlist specified in turbo.json. - /// Use "infer" to defer to existence of "passThroughEnv" or - /// "globalPassThroughEnv" in turbo.json. (default infer) - #[clap(long = "env-mode", default_value = "infer", num_args = 0..=1, default_missing_value = "infer")] + #[clap(long = "env-mode", default_value = "strict", num_args = 0..=1, default_missing_value = "strict")] pub env_mode: EnvMode, /// Use the given selector to specify package(s) to act as /// entry points. The syntax mirrors pnpm's syntax, and @@ -688,38 +678,6 @@ pub struct ExecutionArgs { #[clap(short = 'F', long, group = "scope-filter-group")] pub filter: Vec, - /// DEPRECATED: Specify package(s) to act as entry - /// points for task execution. Supports globs. - #[clap(long, group = "scope-filter-group")] - pub scope: Vec, - - // ignore filters out files from scope and filter, so we require it here - // ----------------------- - /// Files to ignore when calculating changed files from '--filter'. - /// Supports globs. - #[clap(long, requires = "scope-filter-group")] - pub ignore: Vec, - - // since only works with scope, so we require it here - // ----------------------- - /// DEPRECATED: Limit/Set scope to changed packages - /// since a mergebase. This uses the git diff ${target_branch}... - /// mechanism to identify which packages have changed. - #[clap(long, requires = "scope")] - pub since: Option, - - // include_dependencies only works with scope, so we require it here - // ----------------------- - /// DEPRECATED: Include the dependencies of tasks in execution. - #[clap(long, requires = "scope")] - pub include_dependencies: bool, - - // no_deps only works with scope, so we require it here - // ----------------------- - /// DEPRECATED: Exclude dependent task consumers from execution. - #[clap(long, requires = "scope")] - pub no_deps: bool, - /// Set type of process output logging. Use "full" to show /// all output. Use "hash-only" to show only turbo-computed /// task hashes. Use "new-only" to show only new output with @@ -765,14 +723,11 @@ impl ExecutionArgs { track_usage!(telemetry, self.framework_inference, |val: bool| !val); track_usage!(telemetry, self.continue_execution, |val| val); - track_usage!(telemetry, self.include_dependencies, |val| { val }); track_usage!(telemetry, self.single_package, |val| val); - track_usage!(telemetry, self.no_deps, |val| val); track_usage!(telemetry, self.only, |val| val); track_usage!(telemetry, self.remote_only, |val| val); track_usage!(telemetry, &self.cache_dir, Option::is_some); track_usage!(telemetry, &self.force, Option::is_some); - track_usage!(telemetry, &self.since, Option::is_some); track_usage!(telemetry, &self.pkg_inference_root, Option::is_some); if let Some(concurrency) = &self.concurrency { @@ -807,14 +762,6 @@ impl ExecutionArgs { if !self.filter.is_empty() { telemetry.track_arg_value("filter:length", self.filter.len(), EventType::NonSensitive); } - - if !self.scope.is_empty() { - telemetry.track_arg_value("scope:length", self.scope.len(), EventType::NonSensitive); - } - - if !self.ignore.is_empty() { - telemetry.track_arg_value("ignore:length", self.ignore.len(), EventType::NonSensitive); - } } } @@ -1110,7 +1057,6 @@ pub async fn run( root_telemetry.track_cpus(num_cpus::get()); // track args cli_args.track(&root_telemetry); - warn_all_deprecated_flags(&cli_args); let cli_result = match cli_args.command.as_ref().unwrap() { Command::Bin { .. } => { @@ -1334,39 +1280,6 @@ pub async fn run( cli_result } -fn warn_all_deprecated_flags(args: &Args) { - if args.trace.is_some() { - warn_flag_removal("--trace"); - } - - if args.heap.is_some() { - warn_flag_removal("--heap"); - } - - if args.cpu_profile.is_some() { - warn_flag_removal("--cpuprofile"); - } - - if let Some(Command::Run { execution_args, .. }) = args.command.as_ref() { - if execution_args.since.is_some() { - warn_flag_removal("--since"); - } - if !execution_args.scope.is_empty() { - warn_flag_removal("--scope"); - } - if execution_args.include_dependencies { - warn_flag_removal("--include-dependencies"); - } - if execution_args.no_deps { - warn_flag_removal("--no-deps"); - } - } -} - -fn warn_flag_removal(flag: &str) { - warn!("{flag} is deprecated and will be removed in 2.0"); -} - #[cfg(test)] mod test { use std::assert_matches::assert_matches; @@ -1515,49 +1428,34 @@ mod test { "framework_inference: flag set to false" )] #[test_case::test_case( - &["turbo", "run", "build"], + &["turbo", "run", "build", "--env-mode"], Args { command: Some(Command::Run { execution_args: Box::new(ExecutionArgs { tasks: vec!["build".to_string()], - env_mode: EnvMode::Infer, - ..get_default_execution_args() - }), - run_args: Box::new(get_default_run_args()) - }), - ..Args::default() - } ; - "env_mode: default infer" - )] - #[test_case::test_case( - &["turbo", "run", "build", "--env-mode"], - Args { - command: Some(Command::Run { - execution_args: Box::new(ExecutionArgs { - tasks: vec!["build".to_string()], - env_mode: EnvMode::Infer, + env_mode: EnvMode::Strict, ..get_default_execution_args() }), run_args: Box::new(get_default_run_args()) }), ..Args::default() - } ; + } ; "env_mode: not fully-specified" - )] + )] #[test_case::test_case( - &["turbo", "run", "build", "--env-mode", "infer"], + &["turbo", "run", "build"], Args { command: Some(Command::Run { execution_args: Box::new(ExecutionArgs { tasks: vec!["build".to_string()], - env_mode: EnvMode::Infer, + env_mode: EnvMode::Strict, ..get_default_execution_args() }), run_args: Box::new(get_default_run_args()) }), ..Args::default() } ; - "env_mode: specified infer" + "env_mode: default strict" )] #[test_case::test_case( &["turbo", "run", "build", "--env-mode", "loose"], @@ -1838,54 +1736,6 @@ mod test { } ; "graph with output" )] - #[test_case::test_case( - &["turbo", "run", "build", "--filter", "[main]", "--ignore", "foo.js"], - Args { - command: Some(Command::Run { - execution_args: Box::new(ExecutionArgs { - tasks: vec!["build".to_string()], - ignore: vec!["foo.js".to_string()], - filter: vec![String::from("[main]")], - ..get_default_execution_args() - }), - run_args: Box::new(get_default_run_args()) - }), - ..Args::default() - } ; - "single ignore" - )] - #[test_case::test_case( - &["turbo", "run", "build", "--filter", "[main]", "--ignore", "foo.js", "--ignore", "bar.js"], - Args { - command: Some(Command::Run { - execution_args: Box::new(ExecutionArgs { - tasks: vec!["build".to_string()], - ignore: vec!["foo.js".to_string(), "bar.js".to_string()], - filter: vec![String::from("[main]")], - ..get_default_execution_args() - }), - run_args: Box::new(get_default_run_args()) - }), - ..Args::default() - } ; - "multiple ignores" - )] - #[test_case::test_case( - &["turbo", "run", "build", "--scope", "test", "--include-dependencies"], - Args { - command: Some(Command::Run { - execution_args: Box::new(ExecutionArgs { - tasks: vec!["build".to_string()], - include_dependencies: true, - scope: vec!["test".to_string()], - ..get_default_execution_args() - }), - run_args: Box::new(get_default_run_args()) - }), - ..Args::default() - } ; - "include dependencies" - )] #[test_case::test_case( &["turbo", "run", "build", "--no-cache"], Args { @@ -1937,22 +1787,6 @@ mod test { } ; "daemon" )] - #[test_case::test_case( - &["turbo", "run", "build", "--scope", "test", "--no-deps"], - Args { - command: Some(Command::Run { - execution_args: Box::new(ExecutionArgs { - tasks: vec!["build".to_string()], - scope: vec!["test".to_string()], - no_deps: true, - ..get_default_execution_args() - }), - run_args: Box::new(get_default_run_args()) - }), - ..Args::default() - } ; - "no deps" - )] #[test_case::test_case( &["turbo", "run", "build", "--output-logs", "full"], Args { @@ -2184,38 +2018,7 @@ mod test { "remote_only=false works" )] #[test_case::test_case( - &["turbo", "run", "build", "--scope", "foo", "--scope", "bar"], - Args { - command: Some(Command::Run { - execution_args: Box::new(ExecutionArgs { - tasks: vec!["build".to_string()], - scope: vec!["foo".to_string(), "bar".to_string()], - ..get_default_execution_args() - }), - run_args: Box::new(get_default_run_args()) - }), - ..Args::default() - } ; - "scope" - )] - #[test_case::test_case( - &["turbo", "run", "build", "--scope", "test", "--since", "foo"], - Args { - command: Some(Command::Run { - run_args: Box::new(get_default_run_args()), - execution_args: Box::new(ExecutionArgs { - tasks: vec!["build".to_string()], - scope: vec!["test".to_string()], - since: Some("foo".to_string()), - ..get_default_execution_args() - }) - }), - ..Args::default() - } ; - "scope and since" - )] - #[test_case::test_case( - &["turbo", "build"], + &["turbo", "build"], Args { execution_args: Some(ExecutionArgs { tasks: vec!["build".to_string()], @@ -2292,24 +2095,19 @@ mod test { "cannot be used with '--no-daemon'" ; "daemon and no-daemon at the same time" )] - #[test_case::test_case( - &["turbo", "run", "build", "--ignore", "foo/**"], - "the following required arguments were not provided" ; - "ignore without filter or scope" - )] #[test_case::test_case( &["turbo", "run", "build", "--since", "foo"], - "the following required arguments were not provided" ; + "unexpected argument '--since' found" ; "since without filter or scope" )] #[test_case::test_case( &["turbo", "run", "build", "--include-dependencies"], - "the following required arguments were not provided" ; + "unexpected argument '--include-dependencies' found" ; "include-dependencies without filter or scope" )] #[test_case::test_case( &["turbo", "run", "build", "--no-deps"], - "the following required arguments were not provided" ; + "unexpected argument '--no-deps' found" ; "no-deps without filter or scope" )] fn test_parse_run_failures(args: &[&str], expected: &str) { diff --git a/crates/turborepo-lib/src/commands/link.rs b/crates/turborepo-lib/src/commands/link.rs index 759df0c529995..a725b136f9289 100644 --- a/crates/turborepo-lib/src/commands/link.rs +++ b/crates/turborepo-lib/src/commands/link.rs @@ -720,7 +720,7 @@ mod test { fs::write( turbo_json_file.as_path(), - r#"{ "globalEnv": [], "pipeline": {} }"#, + r#"{ "globalEnv": [], "tasks": {} }"#, ) .unwrap(); diff --git a/crates/turborepo-lib/src/commands/mod.rs b/crates/turborepo-lib/src/commands/mod.rs index e20e860ee43dd..5788a2c7725ec 100644 --- a/crates/turborepo-lib/src/commands/mod.rs +++ b/crates/turborepo-lib/src/commands/mod.rs @@ -68,7 +68,6 @@ impl CommandBase { .with_token(self.args.token.clone()) .with_timeout(self.args.remote_cache_timeout) .with_preflight(self.args.preflight.then_some(true)) - .with_experimental_ui(self.args.experimental_ui.then_some(true)) .build() } diff --git a/crates/turborepo-lib/src/config.rs b/crates/turborepo-lib/src/config.rs index 1ab014ac18639..abc572ca2fa19 100644 --- a/crates/turborepo-lib/src/config.rs +++ b/crates/turborepo-lib/src/config.rs @@ -9,7 +9,6 @@ use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPath}; use turborepo_auth::{TURBO_TOKEN_DIR, TURBO_TOKEN_FILE, VERCEL_TOKEN_DIR, VERCEL_TOKEN_FILE}; use turborepo_dirs::{config_dir, vercel_config_dir}; use turborepo_errors::TURBO_SITE; -use turborepo_repository::package_json::{Error as PackageJsonError, PackageJson}; pub use crate::turbo_json::RawTurboJson; use crate::{commands::CommandBase, turbo_json}; @@ -103,6 +102,14 @@ pub enum Error { #[source_code] text: NamedSource, }, + #[error("`{field}` cannot contain an environment variable")] + InvalidDependsOnValue { + field: &'static str, + #[label("environment variable found here")] + span: Option, + #[source_code] + text: NamedSource, + }, #[error("`{field}` cannot contain an absolute path")] AbsolutePathInConfig { field: &'static str, @@ -125,6 +132,14 @@ pub enum Error { #[source_code] text: NamedSource, }, + #[error("found `pipeline` field instead of `tasks`")] + #[diagnostic(help("changed in 2.0: `pipeline` has been renamed to `tasks`"))] + PipelineField { + #[label("rename `pipeline` field to `tasks`")] + span: Option, + #[source_code] + text: NamedSource, + }, #[error("Failed to create APIClient: {0}")] ApiClient(#[source] turborepo_api_client::Error), #[error("{0} is not UTF8.")] @@ -187,8 +202,8 @@ pub struct ConfigurationOptions { pub(crate) upload_timeout: Option, pub(crate) enabled: Option, pub(crate) spaces_id: Option, - #[serde(rename = "experimentalUI")] - pub(crate) experimental_ui: Option, + #[serde(rename = "ui")] + pub(crate) ui: Option, } #[derive(Default)] @@ -252,8 +267,8 @@ impl ConfigurationOptions { self.spaces_id.as_deref() } - pub fn experimental_ui(&self) -> bool { - self.experimental_ui.unwrap_or_default() && atty::is(atty::Stream::Stdout) + pub fn ui(&self) -> bool { + self.ui.unwrap_or(true) && atty::is(atty::Stream::Stdout) } } @@ -266,21 +281,6 @@ trait ResolvedConfigurationOptions { fn get_configuration_options(self) -> Result; } -impl ResolvedConfigurationOptions for PackageJson { - fn get_configuration_options(self) -> Result { - match &self.legacy_turbo_config { - Some(legacy_turbo_config) => { - let synthetic_raw_turbo_json: RawTurboJson = RawTurboJson::parse( - &legacy_turbo_config.to_string(), - AnchoredSystemPath::new("package.json").unwrap(), - )?; - synthetic_raw_turbo_json.get_configuration_options() - } - None => Ok(ConfigurationOptions::default()), - } - } -} - impl ResolvedConfigurationOptions for RawTurboJson { fn get_configuration_options(self) -> Result { let mut opts = if let Some(remote_cache_options) = &self.remote_cache { @@ -294,7 +294,7 @@ impl ResolvedConfigurationOptions for RawTurboJson { .experimental_spaces .and_then(|spaces| spaces.id) .map(|spaces_id| spaces_id.into()); - opts.experimental_ui = self.experimental_ui; + opts.ui = self.ui.map(|ui| ui.use_tui()); Ok(opts) } } @@ -326,7 +326,7 @@ fn get_env_var_config( OsString::from("turbo_remote_cache_upload_timeout"), "upload_timeout", ); - turbo_mapping.insert(OsString::from("turbo_experimental_ui"), "experimental_ui"); + turbo_mapping.insert(OsString::from("turbo_ui"), "ui"); turbo_mapping.insert(OsString::from("turbo_preflight"), "preflight"); // We do not enable new config sources: @@ -408,13 +408,11 @@ fn get_env_var_config( }; // Process experimentalUI - let experimental_ui = output_map - .get("experimental_ui") - .and_then(|val| match val.as_str() { - "true" | "1" => Some(true), - "false" | "0" => Some(false), - _ => None, - }); + let ui = output_map.get("ui").and_then(|val| match val.as_str() { + "true" | "1" => Some(true), + "false" | "0" => Some(false), + _ => None, + }); // We currently don't pick up a Spaces ID via env var, we likely won't // continue using the Spaces name, we can add an env var when we have the @@ -432,7 +430,7 @@ fn get_env_var_config( signature, preflight, enabled, - experimental_ui, + ui, // Processed numbers timeout, @@ -480,7 +478,7 @@ fn get_override_env_var_config( signature: None, preflight: None, enabled: None, - experimental_ui: None, + ui: None, timeout: None, upload_timeout: None, spaces_id: None, @@ -618,11 +616,10 @@ impl TurborepoConfigBuilder { create_builder!(with_enabled, enabled, Option); create_builder!(with_preflight, preflight, Option); create_builder!(with_timeout, timeout, Option); - create_builder!(with_experimental_ui, experimental_ui, Option); + create_builder!(with_ui, ui, Option); pub fn build(&self) -> Result { // Priority, from least significant to most significant: - // - shared configuration (package.json .turbo) // - shared configuration (turbo.json) // - global configuration (~/.turbo/config.json) // - local configuration (/.turbo/config.json) @@ -630,16 +627,6 @@ impl TurborepoConfigBuilder { // - CLI arguments // - builder pattern overrides. - let root_package_json = PackageJson::load(&self.repo_root.join_component("package.json")) - .or_else(|e| { - if let PackageJsonError::Io(e) = &e { - if matches!(e.kind(), std::io::ErrorKind::NotFound) { - return Ok(Default::default()); - } - } - - Err(e) - })?; let turbo_json = RawTurboJson::read( &self.repo_root, AnchoredSystemPath::new("turbo.json").unwrap(), @@ -661,7 +648,6 @@ impl TurborepoConfigBuilder { let override_env_var_config = get_override_env_var_config(&env_vars)?; let sources = [ - root_package_json.get_configuration_options(), turbo_json.get_configuration_options(), global_config.get_configuration_options(), global_auth.get_configuration_options(), @@ -705,8 +691,8 @@ impl TurborepoConfigBuilder { if let Some(spaces_id) = current_source_config.spaces_id { acc.spaces_id = Some(spaces_id); } - if let Some(experimental_ui) = current_source_config.experimental_ui { - acc.experimental_ui = Some(experimental_ui); + if let Some(ui) = current_source_config.ui { + acc.ui = Some(ui); } acc @@ -763,7 +749,7 @@ mod test { "turbo_remote_cache_timeout".into(), turbo_remote_cache_timeout.to_string().into(), ); - env.insert("turbo_experimental_ui".into(), "true".into()); + env.insert("turbo_ui".into(), "true".into()); env.insert("turbo_preflight".into(), "true".into()); let config = get_env_var_config(&env).unwrap(); @@ -774,7 +760,7 @@ mod test { assert_eq!(turbo_teamid, config.team_id.unwrap()); assert_eq!(turbo_token, config.token.unwrap()); assert_eq!(turbo_remote_cache_timeout, config.timeout.unwrap()); - assert_eq!(Some(true), config.experimental_ui); + assert_eq!(Some(true), config.ui); } #[test] @@ -785,7 +771,7 @@ mod test { env.insert("turbo_team".into(), "".into()); env.insert("turbo_teamid".into(), "".into()); env.insert("turbo_token".into(), "".into()); - env.insert("turbo_experimental_ui".into(), "".into()); + env.insert("turbo_ui".into(), "".into()); env.insert("turbo_preflight".into(), "".into()); let config = get_env_var_config(&env).unwrap(); @@ -794,7 +780,7 @@ mod test { assert_eq!(config.team_slug(), None); assert_eq!(config.team_id(), None); assert_eq!(config.token(), None); - assert!(!config.experimental_ui()); + assert_eq!(config.ui, None); assert!(!config.preflight()); } diff --git a/crates/turborepo-lib/src/daemon/mod.rs b/crates/turborepo-lib/src/daemon/mod.rs index d9bae7650ae4b..ceb4f4eead4d0 100644 --- a/crates/turborepo-lib/src/daemon/mod.rs +++ b/crates/turborepo-lib/src/daemon/mod.rs @@ -100,7 +100,7 @@ pub(crate) mod proto { /// - Bump the minor version if adding new features, such that clients can /// mandate at least some set of features on the target server. /// - Bump the patch version if making backwards compatible bug fixes. - pub const VERSION: &str = "1.11.0"; + pub const VERSION: &str = "2.0.0"; impl From for turborepo_repository::package_manager::PackageManager { fn from(pm: PackageManager) -> Self { diff --git a/crates/turborepo-lib/src/engine/builder.rs b/crates/turborepo-lib/src/engine/builder.rs index 0d6c4eb1fb7bc..4ceeeb99cac70 100644 --- a/crates/turborepo-lib/src/engine/builder.rs +++ b/crates/turborepo-lib/src/engine/builder.rs @@ -153,6 +153,28 @@ impl<'a> EngineBuilder<'a> { self } + // Returns the set of allowed tasks that can be run if --only is used + // The set is exactly the product of the packages in filter and tasks specified + // by CLI + fn allowed_tasks(&self) -> Option>> { + if self.tasks_only { + Some( + self.workspaces + .iter() + .cartesian_product(self.tasks.iter()) + .map(|(package, task_name)| { + task_name + .task_id() + .unwrap_or(TaskId::new(package.as_ref(), task_name.task())) + .into_owned() + }) + .collect(), + ) + } else { + None + } + } + pub fn build(mut self) -> Result { // If there are no affected packages, we don't need to go through all this work // we can just exit early. @@ -205,6 +227,8 @@ impl<'a> EngineBuilder<'a> { return Err(Error::MissingTasks(errors)); } + let allowed_tasks = self.allowed_tasks(); + let mut visited = HashSet::new(); let mut engine = Engine::default(); @@ -265,22 +289,17 @@ impl<'a> EngineBuilder<'a> { // Note that the Go code has a whole if/else statement for putting stuff into // deps or calling e.AddDep the bool is cannot be true so we skip to // just doing deps - let mut deps = task_definition + let deps = task_definition .task_dependencies .iter() .map(|spanned| spanned.as_ref().split()) .collect::>(); - let mut topo_deps = task_definition + let topo_deps = task_definition .topological_dependencies .iter() .map(|spanned| spanned.as_ref().split()) .collect::>(); - if self.tasks_only { - deps.retain(|task_name, _| self.tasks.iter().any(|t| &t.value == *task_name)); - topo_deps.retain(|task_name, _| self.tasks.iter().any(|t| &t.value == *task_name)); - } - // Don't ask why, but for some reason we refer to the source as "to" // and the target node as "from" let to_task_id = task_id.as_inner().clone().into_owned(); @@ -299,9 +318,14 @@ impl<'a> EngineBuilder<'a> { .for_each(|((from, span), dependency_workspace)| { // We don't need to add an edge from the root node if we're in this branch if let PackageNode::Workspace(dependency_workspace) = dependency_workspace { - has_topo_deps = true; let from_task_id = TaskId::from_graph(dependency_workspace, from); + if let Some(allowed_tasks) = &allowed_tasks { + if !allowed_tasks.contains(&from_task_id) { + return; + } + } let from_task_index = engine.get_index(&from_task_id); + has_topo_deps = true; engine .task_graph .add_edge(to_task_index, from_task_index, ()); @@ -311,11 +335,16 @@ impl<'a> EngineBuilder<'a> { }); for (dep, span) in deps { - has_deps = true; let from_task_id = dep .task_id() .unwrap_or_else(|| TaskId::new(to_task_id.package(), dep.task())) .into_owned(); + if let Some(allowed_tasks) = &allowed_tasks { + if !allowed_tasks.contains(&from_task_id) { + continue; + } + } + has_deps = true; let from_task_index = engine.get_index(&from_task_id); engine .task_graph @@ -360,8 +389,8 @@ impl<'a> EngineBuilder<'a> { }; let task_id_as_name = task_id.as_task_name(); - if turbo_json.pipeline.contains_key(&task_id_as_name) - || turbo_json.pipeline.contains_key(task_name) + if turbo_json.tasks.contains_key(&task_id_as_name) + || turbo_json.tasks.contains_key(task_name) { Ok(true) } else if !matches!(workspace, PackageName::Root) { @@ -412,7 +441,7 @@ impl<'a> EngineBuilder<'a> { }); } - if let Some(workspace_def) = workspace_json.pipeline.get(task_name) { + if let Some(workspace_def) = workspace_json.tasks.get(task_name) { task_definitions.push(workspace_def.value.clone()); } } @@ -636,13 +665,13 @@ mod test { ); a_turbo_json - .create_with_contents(r#"{"pipeline": {"build": {}}}"#) + .create_with_contents(r#"{"tasks": {"build": {}}}"#) .unwrap(); let turbo_json = engine_builder .load_turbo_json(&PackageName::from("a")) .unwrap(); - assert_eq!(turbo_json.pipeline.len(), 1); + assert_eq!(turbo_json.tasks.len(), 1); } fn turbo_json(value: serde_json::Value) -> TurboJson { @@ -677,7 +706,7 @@ mod test { ( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "test": { "inputs": ["testing"] }, "build": { "inputs": ["primary"] }, "a#build": { "inputs": ["special"] }, @@ -687,7 +716,7 @@ mod test { ( PackageName::from("b"), turbo_json(json!({ - "pipeline": { + "tasks": { "build": { "inputs": ["outer"]}, } })), @@ -755,7 +784,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "test": { "dependsOn": ["^build", "prepare"] }, "build": { "dependsOn": ["^build", "prepare"] }, "prepare": {}, @@ -814,7 +843,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "test": { "dependsOn": ["^build"] }, "build": { "dependsOn": ["^build"] }, } @@ -853,7 +882,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"] }, "app1#special": { "dependsOn": ["^build"] }, } @@ -890,7 +919,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"] }, "test": { "dependsOn": ["^build"] }, "//#test": {}, @@ -943,7 +972,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"] }, "libA#build": { "dependsOn": ["//#root-task"] }, "//#root-task": {}, @@ -987,7 +1016,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"] }, "libA#build": { "dependsOn": ["//#root-task"] }, } @@ -1020,7 +1049,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "libA#build": { "dependsOn": ["app1#compile", "app1#test"] }, "build": { "dependsOn": ["^build"] }, "compile": {}, @@ -1066,7 +1095,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"] }, "foo": {}, "libA#build": { "dependsOn": ["//#foo"] } @@ -1105,7 +1134,7 @@ mod test { let turbo_jsons = vec![( PackageName::Root, turbo_json(json!({ - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build", "prepare"] }, "test": { "dependsOn": ["^build", "prepare"] }, "prepare": {}, @@ -1139,6 +1168,83 @@ mod test { assert_eq!(all_dependencies(&engine), expected); } + #[test] + fn test_engine_tasks_only_package_deps() { + let repo_root_dir = TempDir::new("repo").unwrap(); + let repo_root = AbsoluteSystemPathBuf::new(repo_root_dir.path().to_str().unwrap()).unwrap(); + let package_graph = mock_package_graph( + &repo_root, + package_jsons! { + repo_root, + "a" => [], + "b" => ["a"] + }, + ); + let turbo_jsons = vec![( + PackageName::Root, + turbo_json(json!({ + "tasks": { + "build": { "dependsOn": ["^build"] }, + } + })), + )] + .into_iter() + .collect(); + let engine = EngineBuilder::new(&repo_root, &package_graph, false) + .with_turbo_jsons(Some(turbo_jsons)) + .with_tasks_only(true) + .with_tasks(Some(Spanned::new(TaskName::from("build")))) + .with_workspaces(vec![PackageName::from("b")]) + .with_root_tasks(vec![TaskName::from("build")]) + .build() + .unwrap(); + + // With task only we shouldn't do package tasks dependencies either + let expected = deps! { + "b#build" => ["___ROOT___"] + }; + assert_eq!(all_dependencies(&engine), expected); + } + + #[test] + fn test_engine_tasks_only_task_dep() { + let repo_root_dir = TempDir::new("repo").unwrap(); + let repo_root = AbsoluteSystemPathBuf::new(repo_root_dir.path().to_str().unwrap()).unwrap(); + let package_graph = mock_package_graph( + &repo_root, + package_jsons! { + repo_root, + "a" => [], + "b" => [] + }, + ); + let turbo_jsons = vec![( + PackageName::Root, + turbo_json(json!({ + "tasks": { + "a#build": { }, + "b#build": { "dependsOn": ["a#build"] } + } + })), + )] + .into_iter() + .collect(); + let engine = EngineBuilder::new(&repo_root, &package_graph, false) + .with_turbo_jsons(Some(turbo_jsons)) + .with_tasks_only(true) + .with_tasks(Some(Spanned::new(TaskName::from("build")))) + .with_workspaces(vec![PackageName::from("b")]) + .with_root_tasks(vec![TaskName::from("build")]) + .build() + .unwrap(); + + // With task only we shouldn't do package tasks dependencies either + let expected = deps! { + "b#build" => ["___ROOT___"] + }; + assert_eq!(all_dependencies(&engine), expected); + } + #[allow(clippy::duplicated_attributes)] #[test_case("build", None)] #[test_case("build:prod", None)] diff --git a/crates/turborepo-lib/src/engine/mod.rs b/crates/turborepo-lib/src/engine/mod.rs index 0b254246f2e4f..3e6b7ac712043 100644 --- a/crates/turborepo-lib/src/engine/mod.rs +++ b/crates/turborepo-lib/src/engine/mod.rs @@ -16,7 +16,6 @@ use petgraph::Graph; use thiserror::Error; use turborepo_errors::Spanned; use turborepo_repository::package_graph::{PackageGraph, PackageName}; -use turborepo_telemetry::events::generic::GenericEventBuilder; use crate::{run::task_id::TaskId, task_graph::TaskDefinition}; @@ -380,12 +379,6 @@ impl Engine { &self.task_definitions } - pub fn track_usage(&self, telemetry: &GenericEventBuilder) { - for task in self.task_definitions.values() { - telemetry.track_dot_env(task.dot_env.as_deref()); - } - } - pub fn validate( &self, package_graph: &PackageGraph, diff --git a/crates/turborepo-lib/src/hash/mod.rs b/crates/turborepo-lib/src/hash/mod.rs index 2dd7a61de5071..74fd46ccbd224 100644 --- a/crates/turborepo-lib/src/hash/mod.rs +++ b/crates/turborepo-lib/src/hash/mod.rs @@ -10,12 +10,11 @@ use std::collections::HashMap; use capnp::message::{Builder, HeapAllocator}; pub use traits::TurboHash; -use turborepo_env::{EnvironmentVariablePairs, ResolvedEnvMode}; +use turborepo_env::EnvironmentVariablePairs; use crate::{cli::EnvMode, task_graph::TaskOutputs}; mod proto_capnp { - use turborepo_env::ResolvedEnvMode; use crate::cli::EnvMode; @@ -24,18 +23,17 @@ mod proto_capnp { impl From for global_hashable::EnvMode { fn from(value: EnvMode) -> Self { match value { - EnvMode::Infer => global_hashable::EnvMode::Infer, EnvMode::Loose => global_hashable::EnvMode::Loose, EnvMode::Strict => global_hashable::EnvMode::Strict, } } } - impl From for task_hashable::EnvMode { - fn from(value: ResolvedEnvMode) -> Self { + impl From for task_hashable::EnvMode { + fn from(value: EnvMode) -> Self { match value { - ResolvedEnvMode::Loose => task_hashable::EnvMode::Loose, - ResolvedEnvMode::Strict => task_hashable::EnvMode::Strict, + EnvMode::Loose => task_hashable::EnvMode::Loose, + EnvMode::Strict => task_hashable::EnvMode::Strict, } } } @@ -59,22 +57,22 @@ pub struct TaskHashable<'a> { pub(crate) env: &'a [String], pub(crate) resolved_env_vars: EnvVarPairs, pub(crate) pass_through_env: &'a [String], - pub(crate) env_mode: ResolvedEnvMode, - pub(crate) dot_env: &'a [turbopath::RelativeUnixPathBuf], + pub(crate) env_mode: EnvMode, } #[derive(Debug, Clone)] pub struct GlobalHashable<'a> { pub global_cache_key: &'static str, pub global_file_hash_map: &'a HashMap, - // This is None in single package mode + // These are None in single package mode pub root_external_dependencies_hash: Option<&'a str>, + pub root_internal_dependencies_hash: Option<&'a str>, + pub engines: HashMap<&'a str, &'a str>, pub env: &'a [String], pub resolved_env_vars: EnvironmentVariablePairs, pub pass_through_env: &'a [String], pub env_mode: EnvMode, pub framework_inference: bool, - pub dot_env: &'a [turbopath::RelativeUnixPathBuf], } pub struct LockFilePackages(pub Vec); @@ -253,15 +251,6 @@ impl From> for Builder { } } - { - let mut dotenv_builder = builder - .reborrow() - .init_dot_env(task_hashable.dot_env.len() as u32); - for (i, env) in task_hashable.dot_env.iter().enumerate() { - dotenv_builder.set(i as u32, env.as_str()); - } - } - { let mut resolved_env_vars_builder = builder .reborrow() @@ -315,10 +304,32 @@ impl From> for Builder { } } + { + let mut entries = builder + .reborrow() + .init_engines(hashable.engines.len() as u32); + + // get a sorted iterator over keys and values of the hashmap + // and set the entries in the capnp message + + let mut hashable: Vec<_> = hashable.engines.iter().collect(); + hashable.sort_by(|a, b| a.0.cmp(b.0)); + + for (i, (key, value)) in hashable.iter().enumerate() { + let mut entry = entries.reborrow().get(i as u32); + entry.set_key(key); + entry.set_value(value); + } + } + if let Some(root_external_dependencies_hash) = hashable.root_external_dependencies_hash { builder.set_root_external_deps_hash(root_external_dependencies_hash); } + if let Some(root_internal_dependencies_hash) = hashable.root_internal_dependencies_hash { + builder.set_root_internal_deps_hash(root_internal_dependencies_hash); + } + { let mut entries = builder.reborrow().init_env(hashable.env.len() as u32); for (i, env) in hashable.env.iter().enumerate() { @@ -345,22 +356,12 @@ impl From> for Builder { } builder.set_env_mode(match hashable.env_mode { - EnvMode::Infer => proto_capnp::global_hashable::EnvMode::Infer, EnvMode::Loose => proto_capnp::global_hashable::EnvMode::Loose, EnvMode::Strict => proto_capnp::global_hashable::EnvMode::Strict, }); builder.set_framework_inference(hashable.framework_inference); - { - let mut dot_env = builder - .reborrow() - .init_dot_env(hashable.dot_env.len() as u32); - for (i, env) in hashable.dot_env.iter().enumerate() { - dot_env.set(i as u32, env.as_str()); - } - } - // We're okay to unwrap here because we haven't hit the nesting // limit and the message will not have cycles. let size = builder @@ -381,7 +382,6 @@ impl From> for Builder { #[cfg(test)] mod test { use test_case::test_case; - use turborepo_env::ResolvedEnvMode; use turborepo_lockfiles::Package; use super::{ @@ -406,11 +406,10 @@ mod test { env: &["env".to_string()], resolved_env_vars: vec![], pass_through_env: &["pass_thru_env".to_string()], - env_mode: ResolvedEnvMode::Loose, - dot_env: &[turbopath::RelativeUnixPathBuf::new("dotenv".to_string()).unwrap()], + env_mode: EnvMode::Loose, }; - assert_eq!(task_hashable.hash(), "ff765ee2f83bc034"); + assert_eq!(task_hashable.hash(), "1f8b13161f57fca1"); } #[test] @@ -426,16 +425,16 @@ mod test { global_cache_key: "global_cache_key", global_file_hash_map: &global_file_hash_map, root_external_dependencies_hash: Some("0000000000000000"), + root_internal_dependencies_hash: Some("0000000000000001"), + engines: Default::default(), env: &["env".to_string()], resolved_env_vars: vec![], pass_through_env: &["pass_through_env".to_string()], - env_mode: EnvMode::Infer, + env_mode: EnvMode::Strict, framework_inference: true, - - dot_env: &[turbopath::RelativeUnixPathBuf::new("dotenv".to_string()).unwrap()], }; - assert_eq!(global_hash.hash(), "c0ddf8138bd686e8"); + assert_eq!(global_hash.hash(), "5072bd005ec02799"); } #[test_case(vec![], "459c029558afe716" ; "empty")] diff --git a/crates/turborepo-lib/src/hash/proto.capnp b/crates/turborepo-lib/src/hash/proto.capnp index 4f6f4c00b9459..9486bf0c0481a 100644 --- a/crates/turborepo-lib/src/hash/proto.capnp +++ b/crates/turborepo-lib/src/hash/proto.capnp @@ -19,7 +19,6 @@ struct TaskHashable { resolvedEnvVars @9 :List(Text); passThruEnv @10 :List(Text); envMode @11 :EnvMode; - dotEnv @12 :List(Text); enum EnvMode { loose @0; @@ -36,18 +35,18 @@ struct GlobalHashable { globalCacheKey @0 :Text; globalFileHashMap @1 :List(Entry); rootExternalDepsHash @2 :Text; - env @3 :List(Text); - resolvedEnvVars @4 :List(Text); - passThroughEnv @5 :List(Text); - envMode @6 :EnvMode; - frameworkInference @7 :Bool; - dotEnv @8 :List(Text); + rootInternalDepsHash @3 :Text; + env @4 :List(Text); + resolvedEnvVars @5 :List(Text); + passThroughEnv @6 :List(Text); + envMode @7 :EnvMode; + frameworkInference @8 :Bool; + engines @9 :List(Entry); enum EnvMode { - infer @0; - loose @1; - strict @2; + loose @0; + strict @1; } struct Entry { diff --git a/crates/turborepo-lib/src/opts.rs b/crates/turborepo-lib/src/opts.rs index c38b2c73c9683..cb109a49f9ac9 100644 --- a/crates/turborepo-lib/src/opts.rs +++ b/crates/turborepo-lib/src/opts.rs @@ -48,11 +48,6 @@ impl Opts { cmd.push_str(pattern); } - for pattern in &self.scope_opts.legacy_filter.as_filter_pattern() { - cmd.push_str(" --filter="); - cmd.push_str(pattern); - } - if self.run_opts.parallel { cmd.push_str(" --parallel"); } @@ -121,7 +116,7 @@ struct RunAndExecutionArgs<'a> { pub struct RunCacheOpts { pub(crate) skip_reads: bool, pub(crate) skip_writes: bool, - pub(crate) task_output_mode_override: Option, + pub(crate) task_output_logs_override: Option, } impl<'a> From> for RunCacheOpts { @@ -129,7 +124,7 @@ impl<'a> From> for RunCacheOpts { RunCacheOpts { skip_reads: args.execution_args.force.flatten().is_some_and(|f| f), skip_writes: args.run_args.no_cache, - task_output_mode_override: args.execution_args.output_logs, + task_output_logs_override: args.execution_args.output_logs, } } } @@ -286,57 +281,11 @@ impl From for ResolvedLogPrefix { } } -// LegacyFilter holds the options in use before the filter syntax. They have -// their own rules for how they are compiled into filter expressions. -#[derive(Debug, Default)] -pub struct LegacyFilter { - // include_dependencies is whether to include pkg.dependencies in execution (defaults to false) - include_dependencies: bool, - // skip_dependents is whether to skip dependent impacted consumers in execution (defaults to - // false) - skip_dependents: bool, - // entrypoints is a list of package entrypoints - entrypoints: Vec, - // since is the git ref used to calculate changed packages - pub since: Option, -} - -impl LegacyFilter { - pub fn as_filter_pattern(&self) -> Vec { - let prefix = if self.skip_dependents { "" } else { "..." }; - let suffix = if self.include_dependencies { "..." } else { "" }; - if self.entrypoints.is_empty() { - if let Some(since) = self.since.as_ref() { - vec![format!("{}[{}]{}", prefix, since, suffix)] - } else { - Vec::new() - } - } else { - let since = self - .since - .as_ref() - .map_or_else(String::new, |s| format!("...[{}]", s)); - self.entrypoints - .iter() - .map(|pattern| { - if pattern.starts_with('!') { - pattern.to_owned() - } else { - format!("{}{}{}{}", prefix, pattern, since, suffix) - } - }) - .collect() - } - } -} - #[derive(Debug)] pub struct ScopeOpts { pub pkg_inference_root: Option, - pub legacy_filter: LegacyFilter, pub global_deps: Vec, pub filter_patterns: Vec, - pub ignore_patterns: Vec, } impl<'a> TryFrom> for ScopeOpts { @@ -350,18 +299,10 @@ impl<'a> TryFrom> for ScopeOpts { .map(AnchoredSystemPathBuf::from_raw) .transpose()?; - let legacy_filter = LegacyFilter { - include_dependencies: args.execution_args.include_dependencies, - skip_dependents: args.execution_args.no_deps, - entrypoints: args.execution_args.scope.clone(), - since: args.execution_args.since.clone(), - }; Ok(Self { global_deps: args.execution_args.global_deps.clone(), pkg_inference_root, - legacy_filter, filter_patterns: args.execution_args.filter.clone(), - ignore_patterns: args.execution_args.ignore.clone(), }) } } @@ -388,11 +329,7 @@ impl RunOpts { impl ScopeOpts { pub fn get_filters(&self) -> Vec { - [ - self.filter_patterns.clone(), - self.legacy_filter.as_filter_pattern(), - ] - .concat() + self.filter_patterns.clone() } } @@ -401,36 +338,12 @@ mod test { use test_case::test_case; use turborepo_cache::CacheOpts; - use super::{LegacyFilter, RunOpts}; + use super::RunOpts; use crate::{ cli::DryRunMode, opts::{Opts, RunCacheOpts, ScopeOpts}, }; - #[test_case(LegacyFilter { - include_dependencies: true, - skip_dependents: false, - entrypoints: vec![], - since: Some("since".to_string()), - }, &["...[since]..."])] - #[test_case(LegacyFilter { - include_dependencies: false, - skip_dependents: true, - entrypoints: vec![], - since: Some("since".to_string()), - }, &["[since]"])] - #[test_case(LegacyFilter { - include_dependencies: false, - skip_dependents: true, - entrypoints: vec!["entry".to_string()], - since: Some("since".to_string()), - }, &["entry...[since]"])] - fn basic_legacy_filter_pattern(filter: LegacyFilter, expected: &[&str]) { - assert_eq!( - filter.as_filter_pattern(), - expected.iter().map(|s| s.to_string()).collect::>() - ) - } #[derive(Default)] struct TestCaseOpts { filter_patterns: Vec, @@ -440,7 +353,6 @@ mod test { parallel: bool, continue_on_error: bool, dry_run: Option, - legacy_filter: Option, } #[test_case(TestCaseOpts { @@ -468,47 +380,13 @@ mod test { )] #[test_case( TestCaseOpts { - legacy_filter: Some(LegacyFilter { - include_dependencies: false, - skip_dependents: true, - entrypoints: vec!["my-app".to_string()], - since: None, - }), - tasks: vec!["build".to_string()], - pass_through_args: vec!["-v".to_string(), "--foo=bar".to_string()], - ..Default::default() - }, - "turbo run build --filter=my-app -- -v --foo=bar" - )] - #[test_case( - TestCaseOpts { - legacy_filter: Some(LegacyFilter { - include_dependencies: false, - skip_dependents: true, - entrypoints: vec!["my-app".to_string()], - since: None, - }), - filter_patterns: vec!["other-app".to_string()], + filter_patterns: vec!["other-app".to_string(), "my-app".to_string()], tasks: vec!["build".to_string()], pass_through_args: vec!["-v".to_string(), "--foo=bar".to_string()], ..Default::default() }, "turbo run build --filter=other-app --filter=my-app -- -v --foo=bar" )] - #[test_case ( - TestCaseOpts { - legacy_filter: Some(LegacyFilter { - include_dependencies: true, - skip_dependents: false, - entrypoints: vec!["my-app".to_string()], - since: Some("some-ref".to_string()), - }), - filter_patterns: vec!["other-app".to_string()], - tasks: vec!["build".to_string()], - ..Default::default() - }, - "turbo run build --filter=other-app --filter=...my-app...[some-ref]..." - )] #[test_case ( TestCaseOpts { filter_patterns: vec!["my-app".to_string()], @@ -560,13 +438,10 @@ mod test { }; let cache_opts = CacheOpts::default(); let runcache_opts = RunCacheOpts::default(); - let legacy_filter = opts_input.legacy_filter.unwrap_or_default(); let scope_opts = ScopeOpts { pkg_inference_root: None, - legacy_filter, global_deps: vec![], filter_patterns: opts_input.filter_patterns, - ignore_patterns: vec![], }; let opts = Opts { run_opts, diff --git a/crates/turborepo-lib/src/run/builder.rs b/crates/turborepo-lib/src/run/builder.rs index 2eb49f335dde8..0d67fd258b30e 100644 --- a/crates/turborepo-lib/src/run/builder.rs +++ b/crates/turborepo-lib/src/run/builder.rs @@ -37,7 +37,7 @@ use { }; use crate::{ - cli::{DryRunMode, EnvMode}, + cli::DryRunMode, commands::CommandBase, engine::{Engine, EngineBuilder}, opts::Opts, @@ -94,7 +94,7 @@ impl RunBuilder { opts.run_opts.experimental_space_id = config.spaces_id().map(|s| s.to_owned()); } let version = base.version(); - let experimental_ui = config.experimental_ui(); + let experimental_ui = config.ui(); let processes = ProcessManager::new( // We currently only use a pty if the following are met: // - we're attached to a tty @@ -337,7 +337,6 @@ impl RunBuilder { &root_package_json, is_single_package, )?; - root_turbo_json.track_usage(&run_telemetry); pkg_dep_graph.validate()?; @@ -358,7 +357,7 @@ impl RunBuilder { task_name = task_name.into_root_task() } - if root_turbo_json.pipeline.contains_key(&task_name) { + if root_turbo_json.tasks.contains_key(&task_name) { filtered_pkgs.insert(PackageName::Root); break; } @@ -375,7 +374,6 @@ impl RunBuilder { pkg_dep_graph.remove_package_dependencies(); engine = self.build_engine(&pkg_dep_graph, &root_turbo_json, &filtered_pkgs)?; } - engine.track_usage(&run_telemetry); let color_selector = ColorSelector::default(); @@ -389,12 +387,6 @@ impl RunBuilder { self.opts.run_opts.dry_run.is_some(), )); - if matches!(self.opts.run_opts.env_mode, EnvMode::Infer) - && root_turbo_json.global_pass_through_env.is_some() - { - self.opts.run_opts.env_mode = EnvMode::Strict; - } - let should_print_prelude = self.should_print_prelude_override.unwrap_or_else(|| { self.opts.run_opts.dry_run.is_none() && self.opts.run_opts.graph.is_none() }); @@ -435,7 +427,7 @@ impl RunBuilder { pkg_dep_graph, self.opts.run_opts.single_package, ) - .with_root_tasks(root_turbo_json.pipeline.keys().cloned()) + .with_root_tasks(root_turbo_json.tasks.keys().cloned()) .with_turbo_jsons(Some( Some((PackageName::Root, root_turbo_json.clone())) .into_iter() diff --git a/crates/turborepo-lib/src/run/cache.rs b/crates/turborepo-lib/src/run/cache.rs index 4f49e9da3789d..14edd574dad20 100644 --- a/crates/turborepo-lib/src/run/cache.rs +++ b/crates/turborepo-lib/src/run/cache.rs @@ -45,7 +45,7 @@ pub enum Error { } pub struct RunCache { - task_output_mode: Option, + task_output_logs: Option, cache: AsyncCache, reads_disabled: bool, writes_disabled: bool, @@ -72,13 +72,13 @@ impl RunCache { ui: UI, is_dry_run: bool, ) -> Self { - let task_output_mode = if is_dry_run { + let task_output_logs = if is_dry_run { Some(OutputLogsMode::None) } else { - opts.task_output_mode_override + opts.task_output_logs_override }; RunCache { - task_output_mode, + task_output_logs, cache, reads_disabled: opts.skip_reads, writes_disabled: opts.skip_writes, @@ -104,9 +104,9 @@ impl RunCache { let repo_relative_globs = task_definition.repo_relative_hashable_outputs(&task_id, workspace_info.package_path()); - let mut task_output_mode = task_definition.output_mode; - if let Some(task_output_mode_override) = self.task_output_mode { - task_output_mode = task_output_mode_override; + let mut task_output_logs = task_definition.output_logs; + if let Some(task_output_logs_override) = self.task_output_logs { + task_output_logs = task_output_logs_override; } let caching_disabled = !task_definition.cache; @@ -117,7 +117,7 @@ impl RunCache { repo_relative_globs, hash: hash.to_owned(), task_id, - task_output_mode, + task_output_logs, caching_disabled, log_file_path, daemon_client: self.daemon_client.clone(), @@ -138,7 +138,7 @@ pub struct TaskCache { run_cache: Arc, repo_relative_globs: TaskOutputs, hash: String, - task_output_mode: OutputLogsMode, + task_output_logs: OutputLogsMode, caching_disabled: bool, log_file_path: AbsoluteSystemPathBuf, daemon_client: Option>, @@ -157,7 +157,7 @@ impl TaskCache { } pub fn on_error(&self, terminal_output: &mut impl CacheOutput) -> Result<(), Error> { - if self.task_output_mode == OutputLogsMode::ErrorsOnly { + if self.task_output_logs == OutputLogsMode::ErrorsOnly { terminal_output.status(&format!( "cache miss, executing {}", color!(self.ui, GREY, "{}", self.hash) @@ -179,7 +179,7 @@ impl TaskCache { log_writer.with_log_file(&self.log_file_path)?; if !matches!( - self.task_output_mode, + self.task_output_logs, OutputLogsMode::None | OutputLogsMode::HashOnly | OutputLogsMode::ErrorsOnly ) { log_writer.with_writer(writer); @@ -199,7 +199,7 @@ impl TaskCache { ) -> Result, Error> { if self.caching_disabled || self.run_cache.reads_disabled { if !matches!( - self.task_output_mode, + self.task_output_logs, OutputLogsMode::None | OutputLogsMode::ErrorsOnly ) { terminal_output.status(&format!( @@ -247,7 +247,7 @@ impl TaskCache { let Some((cache_hit_metadata, restored_files)) = cache_status else { if !matches!( - self.task_output_mode, + self.task_output_logs, OutputLogsMode::None | OutputLogsMode::ErrorsOnly ) { terminal_output.status(&format!( @@ -296,7 +296,7 @@ impl TaskCache { " (outputs already on disk)" }; - match self.task_output_mode { + match self.task_output_logs { OutputLogsMode::HashOnly | OutputLogsMode::NewOnly => { terminal_output.status(&format!( "cache hit{}, suppressing logs {}", diff --git a/crates/turborepo-lib/src/run/global_hash.rs b/crates/turborepo-lib/src/run/global_hash.rs index 0019ab8ef1630..d4a405c8ef920 100644 --- a/crates/turborepo-lib/src/run/global_hash.rs +++ b/crates/turborepo-lib/src/run/global_hash.rs @@ -3,13 +3,18 @@ use std::{ str::FromStr, }; +use either::Either; use globwalk::{ValidatedGlob, WalkType}; +use itertools::Itertools; use thiserror::Error; use tracing::debug; use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf, RelativeUnixPathBuf}; use turborepo_env::{get_global_hashable_env_vars, DetailedMap, EnvironmentVariableMap}; use turborepo_lockfiles::Lockfile; -use turborepo_repository::package_manager::{self, PackageManager}; +use turborepo_repository::{ + package_graph::PackageInfo, + package_manager::{self, PackageManager}, +}; use turborepo_scm::SCM; use crate::{ @@ -19,7 +24,7 @@ use crate::{ static DEFAULT_ENV_VARS: [&str; 1] = ["VERCEL_ANALYTICS_ID"]; -const GLOBAL_CACHE_KEY: &str = "HEY STELLLLLLLAAAAAAAAAAAAA"; +const GLOBAL_CACHE_KEY: &str = "I can’t see ya, but I know you’re here"; #[derive(Debug, Error)] pub enum Error { @@ -41,19 +46,22 @@ pub struct GlobalHashableInputs<'a> { pub global_file_hash_map: HashMap, // This is `None` in single package mode pub root_external_dependencies_hash: Option<&'a str>, + pub root_internal_dependencies_hash: Option<&'a str>, + pub engines: Option>, pub env: &'a [String], // Only Option to allow #[derive(Default)] pub resolved_env_vars: Option, pub pass_through_env: Option<&'a [String]>, pub env_mode: EnvMode, pub framework_inference: bool, - pub dot_env: Option<&'a [RelativeUnixPathBuf]>, pub env_at_execution_start: &'a EnvironmentVariableMap, } #[allow(clippy::too_many_arguments)] pub fn get_global_hash_inputs<'a, L: ?Sized + Lockfile>( root_external_dependencies_hash: Option<&'a str>, + root_internal_dependencies_hash: Option<&'a str>, + root_package: &'a PackageInfo, root_path: &AbsoluteSystemPath, package_manager: &PackageManager, lockfile: Option<&L>, @@ -63,9 +71,10 @@ pub fn get_global_hash_inputs<'a, L: ?Sized + Lockfile>( global_pass_through_env: Option<&'a [String]>, env_mode: EnvMode, framework_inference: bool, - dot_env: Option<&'a [RelativeUnixPathBuf]>, hasher: &SCM, ) -> Result, Error> { + let engines = root_package.package_json.engines(); + let global_hashable_env_vars = get_global_hashable_env_vars(env_at_execution_start, global_env)?; @@ -90,19 +99,7 @@ pub fn get_global_hash_inputs<'a, L: ?Sized + Lockfile>( .map(|p| root_path.anchor(p).expect("path should be from root")) .collect::>(); - let mut global_file_hash_map = - hasher.get_hashes_for_files(root_path, &global_deps_paths, false)?; - - if !dot_env.unwrap_or_default().is_empty() { - let system_dot_env = dot_env - .into_iter() - .flatten() - .map(|p| p.to_anchored_system_path_buf()); - - let dot_env_object = hasher.hash_existing_of(root_path, system_dot_env)?; - - global_file_hash_map.extend(dot_env_object); - } + let global_file_hash_map = hasher.get_hashes_for_files(root_path, &global_deps_paths, false)?; debug!( "external deps hash: {}", @@ -113,12 +110,13 @@ pub fn get_global_hash_inputs<'a, L: ?Sized + Lockfile>( global_cache_key: GLOBAL_CACHE_KEY, global_file_hash_map, root_external_dependencies_hash, + root_internal_dependencies_hash, + engines, env: global_env, resolved_env_vars: Some(global_hashable_env_vars), pass_through_env: global_pass_through_env, env_mode, framework_inference, - dot_env, env_at_execution_start, }) } @@ -131,7 +129,7 @@ fn collect_global_deps( if global_file_dependencies.is_empty() { return Ok(HashSet::new()); } - let raw_exclusions = match package_manager.get_workspace_globs(root_path) { + let workspace_exclusions = match package_manager.get_workspace_globs(root_path) { Ok(globs) => globs.raw_exclusions, // If we hit a missing workspaces error, we could be in single package mode // so we should just use the default globs @@ -143,13 +141,21 @@ fn collect_global_deps( return Err(err.into()); } }; - let exclusions = raw_exclusions + let (raw_inclusions, raw_exclusions): (Vec<_>, Vec<_>) = global_file_dependencies + .iter() + .partition_map(|glob| match glob.strip_prefix('!') { + None => Either::Left(glob.as_str()), + Some(exclusion) => Either::Right(exclusion), + }); + let exclusions = workspace_exclusions .iter() - .map(|e| ValidatedGlob::from_str(e)) + .map(|s| s.as_str()) + .chain(raw_exclusions.iter().copied()) + .map(ValidatedGlob::from_str) .collect::, _>>()?; #[cfg(not(windows))] - let inclusions = global_file_dependencies + let inclusions = raw_inclusions .iter() .map(|i| ValidatedGlob::from_str(i)) .collect::, _>>()?; @@ -181,6 +187,8 @@ impl<'a> GlobalHashableInputs<'a> { global_cache_key: self.global_cache_key, global_file_hash_map: &self.global_file_hash_map, root_external_dependencies_hash: self.root_external_dependencies_hash, + root_internal_dependencies_hash: self.root_internal_dependencies_hash, + engines: self.engines.clone().unwrap_or_default(), env: self.env, resolved_env_vars: self .resolved_env_vars @@ -190,7 +198,6 @@ impl<'a> GlobalHashableInputs<'a> { pass_through_env: self.pass_through_env.unwrap_or_default(), env_mode: self.env_mode, framework_inference: self.framework_inference, - dot_env: self.dot_env.unwrap_or_default(), }; global_hashable.hash() @@ -202,7 +209,7 @@ mod tests { use turbopath::AbsoluteSystemPathBuf; use turborepo_env::EnvironmentVariableMap; use turborepo_lockfiles::Lockfile; - use turborepo_repository::package_manager::PackageManager; + use turborepo_repository::{package_graph::PackageInfo, package_manager::PackageManager}; use turborepo_scm::SCM; use super::get_global_hash_inputs; @@ -224,6 +231,7 @@ mod tests { .unwrap(); let env_var_map = EnvironmentVariableMap::default(); + let package_info = PackageInfo::default(); let lockfile: Option<&dyn Lockfile> = None; #[cfg(windows)] let file_deps = ["C:\\some\\path".to_string()]; @@ -231,6 +239,8 @@ mod tests { let file_deps = ["/some/path".to_string()]; let result = get_global_hash_inputs( None, + None, + &package_info, &root, &PackageManager::Pnpm, lockfile, @@ -238,9 +248,8 @@ mod tests { &env_var_map, &[], None, - EnvMode::Infer, + EnvMode::Strict, false, - None, &SCM::new(&root), ); assert!(result.is_ok()); diff --git a/crates/turborepo-lib/src/run/mod.rs b/crates/turborepo-lib/src/run/mod.rs index a2a291b4e40cc..2b8d352e03227 100644 --- a/crates/turborepo-lib/src/run/mod.rs +++ b/crates/turborepo-lib/src/run/mod.rs @@ -37,7 +37,7 @@ use crate::{ run::{global_hash::get_global_hash_inputs, summary::RunTracker, task_access::TaskAccess}, signal::SignalHandler, task_graph::Visitor, - task_hash::{get_external_deps_hash, PackageInputsHashes}, + task_hash::{get_external_deps_hash, get_internal_deps_hash, PackageInputsHashes}, turbo_json::TurboJson, DaemonClient, DaemonConnector, }; @@ -141,7 +141,12 @@ impl Run { } pub fn start_experimental_ui(&self) -> Option<(AppSender, JoinHandle>)> { - if !self.experimental_ui { + // Print prelude here as this needs to happen before the UI is started + if self.should_print_prelude { + self.print_run_prelude(); + } + // Don't start UI if doing a dry run + if !self.experimental_ui || self.opts.run_opts.dry_run.is_some() { return None; } @@ -153,9 +158,6 @@ impl Run { } pub async fn run(&mut self, experimental_ui_sender: Option) -> Result { - if self.should_print_prelude { - self.print_run_prelude(); - } if let Some(subscriber) = self.signal_handler.subscribe() { let run_cache = self.run_cache.clone(); tokio::spawn(async move { @@ -259,27 +261,30 @@ impl Run { let root_external_dependencies_hash = is_monorepo.then(|| get_external_deps_hash(&root_workspace.transitive_dependencies)); + let root_internal_dependencies_hash = is_monorepo + .then(|| { + get_internal_deps_hash( + &self.scm, + &self.repo_root, + self.pkg_dep_graph.root_internal_package_dependencies(), + ) + }) + .transpose()?; + let global_hash_inputs = { - let (env_mode, pass_through_env) = match self.opts.run_opts.env_mode { - // In infer mode, if there is any pass_through config (even if it is an empty array) - // we'll hash the whole object, so we can detect changes to that config - // Further, resolve the envMode to the concrete value. - EnvMode::Infer if self.root_turbo_json.global_pass_through_env.is_some() => ( - EnvMode::Strict, - self.root_turbo_json.global_pass_through_env.as_deref(), - ), + let env_mode = self.opts.run_opts.env_mode; + let pass_through_env = match env_mode { EnvMode::Loose => { // Remove the passthroughs from hash consideration if we're explicitly loose. - (EnvMode::Loose, None) + None } - env_mode => ( - env_mode, - self.root_turbo_json.global_pass_through_env.as_deref(), - ), + EnvMode::Strict => self.root_turbo_json.global_pass_through_env.as_deref(), }; get_global_hash_inputs( root_external_dependencies_hash.as_deref(), + root_internal_dependencies_hash.as_deref(), + root_workspace, &self.repo_root, self.pkg_dep_graph.package_manager(), self.pkg_dep_graph.lockfile(), @@ -289,7 +294,6 @@ impl Run { pass_through_env, env_mode, self.opts.run_opts.framework_inference, - self.root_turbo_json.global_dot_env.as_deref(), &self.scm, )? }; diff --git a/crates/turborepo-lib/src/run/scope/filter.rs b/crates/turborepo-lib/src/run/scope/filter.rs index 14081acccdf46..cf8f1bf83300b 100644 --- a/crates/turborepo-lib/src/run/scope/filter.rs +++ b/crates/turborepo-lib/src/run/scope/filter.rs @@ -5,7 +5,7 @@ use std::{ }; use tracing::debug; -use turbopath::{AbsoluteSystemPath, AnchoredSystemPathBuf}; +use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf, AnchoredSystemPathBuf}; use turborepo_repository::{ change_mapper::ChangeMapError, package_graph::{self, PackageGraph, PackageName}, @@ -81,20 +81,22 @@ impl PackageInference { selector.name_pattern.clone_from(name); } - if selector.parent_dir != AnchoredSystemPathBuf::default() { - let repo_relative_parent_dir = self.directory_root.join(&selector.parent_dir); + if let Some(parent_dir) = selector.parent_dir.as_deref() { + let repo_relative_parent_dir = self.directory_root.join(parent_dir); let clean_parent_dir = path_clean::clean(Path::new(repo_relative_parent_dir.as_path())) .into_os_string() .into_string() .expect("path was valid utf8 before cleaning"); - selector.parent_dir = AnchoredSystemPathBuf::try_from(clean_parent_dir.as_str()) - .expect("path wasn't absolute before cleaning"); + selector.parent_dir = Some( + AnchoredSystemPathBuf::try_from(clean_parent_dir.as_str()) + .expect("path wasn't absolute before cleaning"), + ); } else if self.package_name.is_none() { // fallback: the user didn't set a parent directory and we didn't find a single // package, so use the directory we inferred and select all subdirectories let mut parent_dir = self.directory_root.clone(); parent_dir.push("**"); - selector.parent_dir = parent_dir; + selector.parent_dir = Some(parent_dir); } } } @@ -122,13 +124,8 @@ impl<'a> FilterResolver<'a, ScopeChangeDetector<'a>> { .map(|s| s.as_str()) .chain(root_turbo_json.global_deps.iter().map(|s| s.as_str())); - let change_detector = ScopeChangeDetector::new( - turbo_root, - scm, - pkg_graph, - global_deps, - opts.ignore_patterns.clone(), - )?; + let change_detector = + ScopeChangeDetector::new(turbo_root, scm, pkg_graph, global_deps, vec![])?; Ok(Self::new_with_change_detector( pkg_graph, @@ -365,16 +362,16 @@ impl<'a, T: GitChangeDetector> FilterResolver<'a, T> { let mut entry_packages = HashSet::new(); for (name, info) in self.pkg_graph.packages() { - if selector.parent_dir == AnchoredSystemPathBuf::default() { - entry_packages.insert(name.to_owned()); - } else { - let path = selector.parent_dir.to_unix(); + if let Some(parent_dir) = selector.parent_dir.as_deref() { + let path = parent_dir.to_unix(); let parent_dir_matcher = wax::Glob::new(path.as_str())?; let matches = parent_dir_matcher.is_match(info.package_path().as_path()); if matches { entry_packages.insert(name.to_owned()); } + } else { + entry_packages.insert(name.to_owned()); } } @@ -429,12 +426,33 @@ impl<'a, T: GitChangeDetector> FilterResolver<'a, T> { let mut entry_packages = HashSet::new(); let mut selector_valid = false; - let path = selector.parent_dir.to_unix(); - let parent_dir_globber = - wax::Glob::new(path.as_str()).map_err(|err| ResolutionError::InvalidDirectoryGlob { - glob: path.as_str().to_string(), - err: Box::new(err), - })?; + let parent_dir_unix = selector.parent_dir.as_deref().map(|path| path.to_unix()); + let parent_dir_globber = parent_dir_unix + .as_deref() + .map(|path| { + wax::Glob::new(path.as_str()).map_err(|err| ResolutionError::InvalidDirectoryGlob { + glob: path.as_str().to_string(), + err: Box::new(err), + }) + }) + .transpose()?; + + if let Some(globber) = parent_dir_globber.clone() { + let (base, _) = globber.partition(); + // wax takes a unix-like glob, but partition will return a system path + // TODO: it would be more proper to use + // `AnchoredSystemPathBuf::from_system_path` but that function + // doesn't allow leading `.` or `..`. + let base = AnchoredSystemPathBuf::from_raw( + base.to_str().expect("glob base should be valid utf8"), + ) + .expect("partitioned glob gave absolute path"); + // need to join this with globbing's current dir :) + let path = self.turbo_root.resolve(&base); + if !path.exists() { + return Err(ResolutionError::DirectoryDoesNotExist(path)); + } + } if let Some(git_range) = selector.git_range.as_ref() { selector_valid = true; @@ -446,31 +464,33 @@ impl<'a, T: GitChangeDetector> FilterResolver<'a, T> { .collect::>(); for package in changed_packages { - if selector.parent_dir == AnchoredSystemPathBuf::default() { - entry_packages.insert(package); - continue; - }; + if let Some(parent_dir_globber) = parent_dir_globber.as_ref() { + if package == PackageName::Root { + // The root package changed, only add it if + // the parentDir is equivalent to the root + if parent_dir_globber.matched(&Path::new(".").into()).is_some() { + entry_packages.insert(package); + } + } else { + let path = package_path_lookup + .get(&package) + .ok_or(ResolutionError::MissingPackageInfo(package.to_string()))?; - if package == PackageName::Root { - // The root package changed, only add it if - // the parentDir is equivalent to the root - if parent_dir_globber.matched(&Path::new(".").into()).is_some() { - entry_packages.insert(package); + if parent_dir_globber.is_match(path.as_path()) { + entry_packages.insert(package); + } } } else { - let path = package_path_lookup - .get(&package) - .ok_or(ResolutionError::MissingPackageInfo(package.to_string()))?; - - if parent_dir_globber.is_match(path.as_path()) { - entry_packages.insert(package); - } + entry_packages.insert(package); } } - } else if selector.parent_dir != AnchoredSystemPathBuf::default() { + } else if let Some((parent_dir, parent_dir_globber)) = selector + .parent_dir + .as_deref() + .zip(parent_dir_globber.as_ref()) + { selector_valid = true; - if selector.parent_dir == AnchoredSystemPathBuf::from_raw(".").expect("valid anchored") - { + if parent_dir == &*AnchoredSystemPathBuf::from_raw(".").expect("valid anchored") { entry_packages.insert(PackageName::Root); } else { let packages = self.pkg_graph.packages(); @@ -525,7 +545,7 @@ impl<'a, T: GitChangeDetector> FilterResolver<'a, T> { // add the root package to the entry packages entry_packages.insert(PackageName::Root); - Ok(match_package_names(name_pattern, entry_packages)?) + match_package_names(name_pattern, entry_packages) } } @@ -536,35 +556,17 @@ impl<'a, T: GitChangeDetector> FilterResolver<'a, T> { fn match_package_names( name_pattern: &str, mut entry_packages: HashSet, -) -> Result, regex::Error> { +) -> Result, ResolutionError> { let matcher = SimpleGlob::new(name_pattern)?; let matched_packages = entry_packages .extract_if(|e| matcher.is_match(e.as_ref())) .collect::>(); - // if we got no matches and the pattern is not scoped - // check if we have exactly one scoped package that does match - if matched_packages.is_empty() - && !name_pattern.starts_with('@') - && !name_pattern.starts_with('/') - { - let scoped_pattern = format!("@*/{}", name_pattern); - let scoped_matcher = SimpleGlob::new(&scoped_pattern)?; - - let (first_item, multiple_matches) = { - let mut scoped_matched_packages = - entry_packages.extract_if(|e| scoped_matcher.is_match(e.as_ref())); // we can extract again since the original set is untouched - let first_item = scoped_matched_packages.next(); - (first_item, scoped_matched_packages.count() > 0) - }; - - if multiple_matches { - // if we have more than one, we can't disambiguate - Ok(Default::default()) - } else { - // otherwise we either have a match or no match - Ok(first_item.into_iter().collect()) - } + // If the pattern was an exact name and it matched no packages, then error + if matcher.is_exact() && matched_packages.is_empty() { + Err(ResolutionError::NoPackagesMatchedWithName( + name_pattern.to_owned(), + )) } else { Ok(matched_packages) } @@ -580,6 +582,8 @@ pub enum ResolutionError { MultiplePackagesMatched, #[error("The provided filter matched a package that is not in the workspace")] PackageNotInWorkspace, + #[error("No package found with name '{0}' in workspace")] + NoPackagesMatchedWithName(String), #[error("selector not used: {0}")] InvalidSelector(#[from] InvalidSelectorError), #[error("Invalid regex pattern")] @@ -595,6 +599,8 @@ pub enum ResolutionError { glob: String, err: Box, }, + #[error("Directory '{0}' specified in filter does not exist")] + DirectoryDoesNotExist(AbsoluteSystemPathBuf), #[error("failed to construct glob for globalDependencies")] GlobalDependenciesGlob(#[from] global_deps_package_change_mapper::Error), } @@ -603,6 +609,7 @@ pub enum ResolutionError { mod test { use std::collections::{HashMap, HashSet}; + use tempfile::TempDir; use test_case::test_case; use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPathBuf, RelativeUnixPathBuf}; use turborepo_repository::{ @@ -666,7 +673,7 @@ mod test { extras: &[&str], package_inference: Option, change_detector: T, - ) -> super::FilterResolver<'static, T> { + ) -> (TempDir, super::FilterResolver<'static, T>) { let temp_folder = tempfile::tempdir().unwrap(); let turbo_root = Box::leak(Box::new( AbsoluteSystemPathBuf::new(temp_folder.path().as_os_str().to_str().unwrap()).unwrap(), @@ -707,7 +714,11 @@ mod test { }, ) }) - .collect(); + .collect::>(); + + for package_dir in package_jsons.keys() { + package_dir.ensure_dir().unwrap(); + } let graph = { let rt = tokio::runtime::Builder::new_current_thread() @@ -735,7 +746,10 @@ mod test { change_detector, ); - resolver + // TempDir's drop implementation will mark the folder as ready for cleanup + // which can lead to non-deterministic test results if the folder is removed + // before the test finishes. + (temp_folder, resolver) } #[test_case( @@ -861,7 +875,7 @@ mod test { vec![ TargetSelector { parent_dir: - AnchoredSystemPathBuf::try_from("packages/*").unwrap(), + Some(AnchoredSystemPathBuf::try_from("packages/*").unwrap()), ..Default::default() } ], None, @@ -870,7 +884,7 @@ mod test { )] #[test_case( vec![TargetSelector { - parent_dir: AnchoredSystemPathBuf::try_from(if cfg!(windows) { "..\\packages\\*" } else { "../packages/*" }).unwrap(), + parent_dir: Some(AnchoredSystemPathBuf::try_from(if cfg!(windows) { "..\\packages\\*" } else { "../packages/*" }).unwrap()), ..Default::default() }], Some(PackageInference{ @@ -884,7 +898,7 @@ mod test { vec![ TargetSelector { parent_dir: - AnchoredSystemPathBuf::try_from("project-5/**").unwrap(), + Some(AnchoredSystemPathBuf::try_from("project-5/**").unwrap()), ..Default::default() } ], None, @@ -895,7 +909,7 @@ mod test { vec![ TargetSelector { parent_dir: - AnchoredSystemPathBuf::try_from("project-5").unwrap(), + Some(AnchoredSystemPathBuf::try_from("project-5").unwrap()), ..Default::default() } ], None, @@ -917,7 +931,7 @@ mod test { #[test_case( vec![ TargetSelector { - parent_dir: AnchoredSystemPathBuf::try_from("packages/*").unwrap(), + parent_dir: Some(AnchoredSystemPathBuf::try_from("packages/*").unwrap()), ..Default::default() }, TargetSelector { @@ -933,7 +947,7 @@ mod test { #[test_case( vec![ TargetSelector { - parent_dir: AnchoredSystemPathBuf::try_from(".").unwrap(), + parent_dir: Some(AnchoredSystemPathBuf::try_from(".").unwrap()), ..Default::default() } ], @@ -973,7 +987,7 @@ mod test { package_inference: Option, expected: &[&str], ) { - let resolver = make_project( + let (_tempdir, resolver) = make_project( &[ ("packages/project-0", "packages/project-1"), ("packages/project-0", "project-5"), @@ -995,7 +1009,7 @@ mod test { #[test] fn match_exact() { - let resolver = make_project( + let (_tempdir, resolver) = make_project( &[], &["packages/@foo/bar", "packages/bar"], None, @@ -1018,43 +1032,73 @@ mod test { #[test] fn match_scoped_package() { - let resolver = make_project( + let (_tempdir, resolver) = make_project( &[], &["packages/bar/@foo/bar"], None, TestChangeDetector::new(&[]), ); + let packages = resolver.get_filtered_packages(vec![TargetSelector { + name_pattern: "bar".to_string(), + ..Default::default() + }]); + + assert!(packages.is_err(), "non existing package name should error",); + let packages = resolver .get_filtered_packages(vec![TargetSelector { - name_pattern: "bar".to_string(), + name_pattern: "@foo/bar".to_string(), ..Default::default() }]) .unwrap(); - assert_eq!( packages, - vec![PackageName::Other("@foo/bar".to_string())] - .into_iter() - .collect() + vec![PackageName::from("@foo/bar")].into_iter().collect() ); } #[test] - fn match_multiple_scoped() { - let resolver = make_project( + fn test_no_matching_name() { + let (_tempdir, resolver) = make_project( &[], - &["packages/@foo/bar", "packages/@types/bar"], + &["packages/bar/@foo/bar"], None, TestChangeDetector::new(&[]), ); + let packages = resolver.get_filtered_packages(vec![TargetSelector { + name_pattern: "bar".to_string(), + ..Default::default() + }]); + + assert!(packages.is_err(), "non existing package name should error",); + let packages = resolver .get_filtered_packages(vec![TargetSelector { - name_pattern: "bar".to_string(), + name_pattern: "baz*".to_string(), ..Default::default() }]) .unwrap(); + assert!( + packages.is_empty(), + "expected no matches, got {:?}", + packages + ); + } + + #[test] + fn test_no_directory() { + let (_tempdir, resolver) = make_project( + &[("packages/foo", "packages/bar")], + &[], + None, + TestChangeDetector::new(&[]), + ); + let packages = resolver.get_filtered_packages(vec![TargetSelector { + parent_dir: Some(AnchoredSystemPathBuf::try_from("pakcages/*").unwrap()), + ..Default::default() + }]); - assert_eq!(packages, HashSet::new()); + assert!(packages.is_err(), "non existing dir should error",); } #[test_case( @@ -1071,7 +1115,7 @@ mod test { vec![ TargetSelector { git_range: Some(GitRange { from_ref: "HEAD~1".to_string(), to_ref: None }), - parent_dir: AnchoredSystemPathBuf::try_from(".").unwrap(), + parent_dir: Some(AnchoredSystemPathBuf::try_from(".").unwrap()), ..Default::default() } ], @@ -1082,7 +1126,7 @@ mod test { vec![ TargetSelector { git_range: Some(GitRange { from_ref: "HEAD~1".to_string(), to_ref: None }), - parent_dir: AnchoredSystemPathBuf::try_from("package-2").unwrap(), + parent_dir: Some(AnchoredSystemPathBuf::try_from("package-2").unwrap()), ..Default::default() } ], @@ -1136,9 +1180,8 @@ mod test { vec![ TargetSelector { git_range: Some(GitRange { from_ref: "HEAD~1".to_string(), to_ref: None }), - parent_dir: - AnchoredSystemPathBuf::try_from("package-*").unwrap(), - match_dependencies: true, ..Default::default() + parent_dir: Some(AnchoredSystemPathBuf::try_from("package-*").unwrap()), + match_dependencies: true, ..Default::default() } ], &["package-1", "package-2"] ; @@ -1155,7 +1198,7 @@ mod test { ), ]); - let resolver = make_project( + let (_tempdir, resolver) = make_project( &[("package-3", "package-20")], &["package-1", "package-2"], None, diff --git a/crates/turborepo-lib/src/run/scope/simple_glob.rs b/crates/turborepo-lib/src/run/scope/simple_glob.rs index 16e0cad17db3f..b0ccb4aae633d 100644 --- a/crates/turborepo-lib/src/run/scope/simple_glob.rs +++ b/crates/turborepo-lib/src/run/scope/simple_glob.rs @@ -24,6 +24,10 @@ impl SimpleGlob { Ok(SimpleGlob::String(pattern.to_string())) } } + + pub fn is_exact(&self) -> bool { + matches!(self, Self::String(_)) + } } impl Match for SimpleGlob { diff --git a/crates/turborepo-lib/src/run/scope/target_selector.rs b/crates/turborepo-lib/src/run/scope/target_selector.rs index e55e7fbd676f5..169257ddce54f 100644 --- a/crates/turborepo-lib/src/run/scope/target_selector.rs +++ b/crates/turborepo-lib/src/run/scope/target_selector.rs @@ -18,7 +18,7 @@ pub struct TargetSelector { pub exclude: bool, pub exclude_self: bool, pub follow_prod_deps_only: bool, - pub parent_dir: AnchoredSystemPathBuf, + pub parent_dir: Option, pub name_pattern: String, pub git_range: Option, pub raw: String, @@ -79,7 +79,7 @@ impl FromStr for TargetSelector { exclude, include_dependencies, include_dependents, - parent_dir: relative_path?, + parent_dir: Some(relative_path?), raw: raw_selector.to_string(), ..Default::default() }) @@ -103,7 +103,7 @@ impl FromStr for TargetSelector { .name("name") .map_or(String::new(), |m| m.as_str().to_string()); - let mut parent_dir = AnchoredSystemPathBuf::default(); + let mut parent_dir = None; if let Some(directory) = captures.name("directory") { let directory = directory.as_str().to_string(); @@ -114,14 +114,16 @@ impl FromStr for TargetSelector { .into_os_string() .into_string() .expect("directory was valid utf8 before cleaning"); - parent_dir = AnchoredSystemPathBuf::try_from(clean_directory.as_str()) - .map_err(|_| InvalidSelectorError::InvalidAnchoredPath(directory))?; + parent_dir = Some( + AnchoredSystemPathBuf::try_from(clean_directory.as_str()) + .map_err(|_| InvalidSelectorError::InvalidAnchoredPath(directory))?, + ); } } let git_range = if let Some(commits) = captures.name("commits") { let commits_str = if let Some(commits) = commits.as_str().strip_prefix("...") { - if parent_dir == AnchoredSystemPathBuf::default() && name_pattern.is_empty() { + if parent_dir.is_none() && name_pattern.is_empty() { return Err(InvalidSelectorError::CantMatchDependencies); } pre_add_dependencies = true; @@ -233,23 +235,23 @@ mod test { #[test_case("...foo...", TargetSelector { name_pattern: "foo".to_string(), raw: "...foo...".to_string(), include_dependents: true, include_dependencies: true, ..Default::default() }; "dot dot dot foo dot dot dot")] #[test_case("foo^...", TargetSelector { name_pattern: "foo".to_string(), raw: "foo^...".to_string(), include_dependencies: true, exclude_self: true, ..Default::default() }; "foo caret dot dot dot")] #[test_case("...^foo", TargetSelector { name_pattern: "foo".to_string(), raw: "...^foo".to_string(), include_dependents: true, exclude_self: true, ..Default::default() }; "dot dot dot caret foo")] - #[test_case("../foo", TargetSelector { raw: "../foo".to_string(), parent_dir: AnchoredSystemPathBuf::try_from(if cfg!(windows) { "..\\foo" } else { "../foo" }).unwrap(), ..Default::default() }; "dot dot slash foo")] - #[test_case("./foo", TargetSelector { raw: "./foo".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("foo").unwrap(), ..Default::default() }; "dot slash foo")] - #[test_case("./foo/*", TargetSelector { raw: "./foo/*".to_string(), parent_dir: AnchoredSystemPathBuf::try_from(if cfg!(windows) { "foo\\*" } else { "foo/*" }).unwrap(), ..Default::default() }; "dot slash foo star")] - #[test_case("...{./foo}", TargetSelector { raw: "...{./foo}".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("foo").unwrap(), include_dependents: true, ..Default::default() }; "dot dot dot curly bracket foo")] - #[test_case(".", TargetSelector { raw: ".".to_string(), parent_dir: AnchoredSystemPathBuf::try_from(".").unwrap(), ..Default::default() }; "parent dir dot")] - #[test_case("..", TargetSelector { raw: "..".to_string(), parent_dir: AnchoredSystemPathBuf::try_from("..").unwrap(), ..Default::default() }; "parent dir dot dot")] + #[test_case("../foo", TargetSelector { raw: "../foo".to_string(), parent_dir: Some(AnchoredSystemPathBuf::try_from(if cfg!(windows) { "..\\foo" } else { "../foo" }).unwrap()), ..Default::default() }; "dot dot slash foo")] + #[test_case("./foo", TargetSelector { raw: "./foo".to_string(), parent_dir: Some(AnchoredSystemPathBuf::try_from("foo").unwrap()), ..Default::default() }; "dot slash foo")] + #[test_case("./foo/*", TargetSelector { raw: "./foo/*".to_string(), parent_dir: Some(AnchoredSystemPathBuf::try_from(if cfg!(windows) { "foo\\*" } else { "foo/*" }).unwrap()), ..Default::default() }; "dot slash foo star")] + #[test_case("...{./foo}", TargetSelector { raw: "...{./foo}".to_string(), parent_dir: Some(AnchoredSystemPathBuf::try_from("foo").unwrap()), include_dependents: true, ..Default::default() }; "dot dot dot curly bracket foo")] + #[test_case(".", TargetSelector { raw: ".".to_string(), parent_dir: Some(AnchoredSystemPathBuf::try_from(".").unwrap()), ..Default::default() }; "parent dir dot")] + #[test_case("..", TargetSelector { raw: "..".to_string(), parent_dir: Some(AnchoredSystemPathBuf::try_from("..").unwrap()), ..Default::default() }; "parent dir dot dot")] #[test_case("[master]", TargetSelector { raw: "[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), ..Default::default() }; "square brackets master")] #[test_case("[from...to]", TargetSelector { raw: "[from...to]".to_string(), git_range: Some(GitRange { from_ref: "from".to_string(), to_ref: Some("to".to_string()) }), ..Default::default() }; "[from...to]")] - #[test_case("{foo}[master]", TargetSelector { raw: "{foo}[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), parent_dir: AnchoredSystemPathBuf::try_from("foo").unwrap(), ..Default::default() }; "{foo}[master]")] - #[test_case("pattern{foo}[master]", TargetSelector { raw: "pattern{foo}[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), parent_dir: AnchoredSystemPathBuf::try_from("foo").unwrap(), name_pattern: "pattern".to_string(), ..Default::default() }; "pattern{foo}[master]")] + #[test_case("{foo}[master]", TargetSelector { raw: "{foo}[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), parent_dir: Some(AnchoredSystemPathBuf::try_from("foo").unwrap()), ..Default::default() }; "{foo}[master]")] + #[test_case("pattern{foo}[master]", TargetSelector { raw: "pattern{foo}[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), parent_dir: Some(AnchoredSystemPathBuf::try_from("foo").unwrap()), name_pattern: "pattern".to_string(), ..Default::default() }; "pattern{foo}[master]")] #[test_case("[master]...", TargetSelector { raw: "[master]...".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), include_dependencies: true, ..Default::default() }; "square brackets master dot dot dot")] #[test_case("...[master]", TargetSelector { raw: "...[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), include_dependents: true, ..Default::default() }; "dot dot dot master square brackets")] #[test_case("...[master]...", TargetSelector { raw: "...[master]...".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), include_dependencies: true, include_dependents: true, ..Default::default() }; "dot dot dot master square brackets dot dot dot")] #[test_case("...[from...to]...", TargetSelector { raw: "...[from...to]...".to_string(), git_range: Some(GitRange { from_ref: "from".to_string(), to_ref: Some("to".to_string()) }), include_dependencies: true, include_dependents: true, ..Default::default() }; "dot dot dot [from...to] dot dot dot")] #[test_case("foo...[master]", TargetSelector { raw: "foo...[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), name_pattern: "foo".to_string(), match_dependencies: true, ..Default::default() }; "foo...[master]")] #[test_case("foo...[master]...", TargetSelector { raw: "foo...[master]...".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), name_pattern: "foo".to_string(), match_dependencies: true, include_dependencies: true, ..Default::default() }; "foo...[master] dot dot dot")] - #[test_case("{foo}...[master]", TargetSelector { raw: "{foo}...[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), parent_dir: AnchoredSystemPathBuf::try_from("foo").unwrap(), match_dependencies: true, ..Default::default() }; "curly brackets foo...[master]")] + #[test_case("{foo}...[master]", TargetSelector { raw: "{foo}...[master]".to_string(), git_range: Some(GitRange { from_ref: "master".to_string(), to_ref: None }), parent_dir: Some(AnchoredSystemPathBuf::try_from("foo").unwrap()), match_dependencies: true, ..Default::default() }; "curly brackets foo...[master]")] fn parse_target_selector(raw_selector: &str, want: TargetSelector) { let result = TargetSelector::from_str(raw_selector); diff --git a/crates/turborepo-lib/src/run/summary/global_hash.rs b/crates/turborepo-lib/src/run/summary/global_hash.rs index 85e7aa4e287a6..3f693308ae890 100644 --- a/crates/turborepo-lib/src/run/summary/global_hash.rs +++ b/crates/turborepo-lib/src/run/summary/global_hash.rs @@ -31,8 +31,9 @@ pub struct GlobalHashSummary<'a> { pub root_key: &'static str, pub files: BTreeMap, pub hash_of_external_dependencies: &'a str, - pub global_dot_env: Option<&'a [RelativeUnixPathBuf]>, + pub hash_of_internal_dependencies: &'a str, pub environment_variables: GlobalEnvVarSummary<'a>, + pub engines: Option>, } impl<'a> TryFrom> for GlobalHashSummary<'a> { @@ -43,11 +44,12 @@ impl<'a> TryFrom> for GlobalHashSummary<'a> { global_cache_key, global_file_hash_map, root_external_dependencies_hash, + root_internal_dependencies_hash, env, resolved_env_vars, pass_through_env, - dot_env, env_at_execution_start, + engines, .. } = global_hashable_inputs; @@ -62,11 +64,14 @@ impl<'a> TryFrom> for GlobalHashSummary<'a> { ) .transpose()?; + let engines = engines.map(|engines| engines.into_iter().collect()); + Ok(Self { root_key: global_cache_key, files: global_file_hash_map.into_iter().collect(), // This can be empty in single package mode hash_of_external_dependencies: root_external_dependencies_hash.unwrap_or_default(), + hash_of_internal_dependencies: root_internal_dependencies_hash.unwrap_or_default(), environment_variables: GlobalEnvVarSummary { specified: GlobalEnvConfiguration { env, @@ -80,8 +85,7 @@ impl<'a> TryFrom> for GlobalHashSummary<'a> { .map(|vars| vars.by_source.matching.to_secret_hashable()), pass_through, }, - - global_dot_env: dot_env, + engines, }) } } diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index 4def93fa02742..0c6a0bd8fe7ff 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -37,7 +37,7 @@ use self::{ use super::task_id::TaskId; use crate::{ cli, - cli::DryRunMode, + cli::{DryRunMode, EnvMode}, engine::Engine, opts::RunOpts, run::summary::{ @@ -83,26 +83,6 @@ enum RunType { DryJson, } -// Can't reuse `cli::EnvMode` because the serialization -// is different (lowercase vs uppercase) -#[derive(Clone, Copy, Debug, Serialize)] -#[serde(rename_all = "lowercase")] -pub enum EnvMode { - Infer, - Loose, - Strict, -} - -impl From for EnvMode { - fn from(env_mode: cli::EnvMode) -> Self { - match env_mode { - cli::EnvMode::Infer => EnvMode::Infer, - cli::EnvMode::Loose => EnvMode::Loose, - cli::EnvMode::Strict => EnvMode::Strict, - } - } -} - #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct RunSummary<'a> { @@ -300,7 +280,7 @@ impl RunTracker { run_opts, packages, global_hash_summary, - global_env_mode.into(), + global_env_mode, task_factory, ) .await?; @@ -499,16 +479,6 @@ impl<'a> RunSummary<'a> { " Global Cache Key\t=\t{}", self.global_hash_summary.root_key )?; - cwriteln!( - tab_writer, - ui, - GREY, - " Global .env Files Considered\t=\t{}", - self.global_hash_summary - .global_dot_env - .unwrap_or_default() - .len() - )?; cwriteln!( tab_writer, ui, @@ -568,6 +538,20 @@ impl<'a> RunSummary<'a> { .unwrap_or_default() .join(", ") )?; + cwriteln!( + tab_writer, + ui, + GREY, + " Engines Values\t=\t{}", + self.global_hash_summary + .engines + .as_ref() + .map(|engines| engines + .iter() + .map(|(key, value)| format!("{key}={value}")) + .join(", ")) + .unwrap_or_default() + )?; tab_writer.flush()?; println!(); @@ -661,16 +645,6 @@ impl<'a> RunSummary<'a> { " Inputs Files Considered\t=\t{}", task.shared.inputs.len() )?; - cwriteln!( - tab_writer, - ui, - GREY, - " .env Files Considered\t=\t{}", - task.shared - .dot_env - .as_ref() - .map_or(0, |dot_env| dot_env.len()) - )?; cwriteln!( tab_writer, diff --git a/crates/turborepo-lib/src/run/summary/spaces.rs b/crates/turborepo-lib/src/run/summary/spaces.rs index e35d8c1bc0a05..3616fc5da1aab 100644 --- a/crates/turborepo-lib/src/run/summary/spaces.rs +++ b/crates/turborepo-lib/src/run/summary/spaces.rs @@ -148,10 +148,7 @@ impl SpacesClient { let space_id = space_id?; let is_linked = api_auth.as_ref().map_or(false, |auth| auth.is_linked()); if !is_linked { - eprintln!( - "Error: experimentalSpaceId is enabled, but repo is not linked to API. Run `turbo \ - link` or `turbo login` first" - ); + // TODO: Add back spaces warning with new UI return None; } let api_auth = api_auth.expect("presence of api auth was just checked"); diff --git a/crates/turborepo-lib/src/run/summary/task.rs b/crates/turborepo-lib/src/run/summary/task.rs index 17361fd8104f6..77aaa18c2689a 100644 --- a/crates/turborepo-lib/src/run/summary/task.rs +++ b/crates/turborepo-lib/src/run/summary/task.rs @@ -81,7 +81,6 @@ pub(crate) struct SharedTaskSummary { pub framework: String, pub env_mode: EnvMode, pub environment_variables: TaskEnvVarSummary, - pub dot_env: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub execution: Option, } @@ -100,11 +99,10 @@ pub struct TaskSummaryTaskDefinition { cache: bool, depends_on: Vec, inputs: Vec, - output_mode: OutputLogsMode, + output_logs: OutputLogsMode, persistent: bool, env: Vec, pass_through_env: Option>, - dot_env: Option>, interactive: bool, } @@ -233,7 +231,6 @@ impl From>> for SharedTaskSummary { execution, env_mode, environment_variables, - dot_env, .. } = value; Self { @@ -261,7 +258,6 @@ impl From>> for SharedTaskSummary { execution, env_mode, environment_variables, - dot_env, } } } @@ -277,11 +273,10 @@ impl From for TaskSummaryTaskDefinition { cache, mut env, pass_through_env, - dot_env, topological_dependencies, task_dependencies, mut inputs, - output_mode, + output_logs, persistent, interactive, } = value; @@ -313,13 +308,11 @@ impl From for TaskSummaryTaskDefinition { cache, depends_on, inputs, - output_mode, + output_logs, persistent, interactive, env, pass_through_env, - // This should _not_ be sorted. - dot_env, } } } @@ -373,12 +366,11 @@ mod test { "cache": true, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "interactive": false, "env": [], "passThroughEnv": null, - "dotEnv": null, }) ; "resolved task definition" )] diff --git a/crates/turborepo-lib/src/run/summary/task_factory.rs b/crates/turborepo-lib/src/run/summary/task_factory.rs index b046f811674b9..e2bbaeb726a2d 100644 --- a/crates/turborepo-lib/src/run/summary/task_factory.rs +++ b/crates/turborepo-lib/src/run/summary/task_factory.rs @@ -6,7 +6,7 @@ use turborepo_repository::package_graph::{PackageGraph, PackageInfo, PackageName use super::{ execution::TaskExecutionSummary, task::{SharedTaskSummary, TaskEnvVarSummary}, - EnvMode, SinglePackageTaskSummary, TaskSummary, + SinglePackageTaskSummary, TaskSummary, }; use crate::{ cli, @@ -175,29 +175,13 @@ impl<'a> TaskSummaryFactory<'a> { framework, dependencies, dependents, - // TODO: this is some very messy code that appears in a few places - // we should attempt to calculate this once and reuse it - env_mode: match self.global_env_mode { - cli::EnvMode::Infer => { - if task_definition.pass_through_env.is_some() { - EnvMode::Strict - } else { - // If we're in infer mode we have just detected non-usage of strict env - // vars. But our behavior's actual meaning of this - // state is `loose`. - EnvMode::Loose - } - } - cli::EnvMode::Strict => EnvMode::Strict, - cli::EnvMode::Loose => EnvMode::Loose, - }, + env_mode: self.global_env_mode, environment_variables: TaskEnvVarSummary::new( task_definition, env_vars, self.env_at_start, ) .expect("invalid glob in task definition should have been caught earlier"), - dot_env: task_definition.dot_env.clone(), execution, }) } diff --git a/crates/turborepo-lib/src/task_graph/mod.rs b/crates/turborepo-lib/src/task_graph/mod.rs index 1c709e0d3ad6d..650adcfaf4519 100644 --- a/crates/turborepo-lib/src/task_graph/mod.rs +++ b/crates/turborepo-lib/src/task_graph/mod.rs @@ -49,8 +49,6 @@ pub struct TaskDefinition { pub(crate) pass_through_env: Option>, - pub(crate) dot_env: Option>, - // TopologicalDependencies are tasks from package dependencies. // E.g. "build" is a topological dependency in: // dependsOn: ['^build']. @@ -68,7 +66,7 @@ pub struct TaskDefinition { pub(crate) inputs: Vec, // OutputMode determines how we should log the output. - pub(crate) output_mode: OutputLogsMode, + pub(crate) output_logs: OutputLogsMode, // Persistent indicates whether the Task is expected to exit or not // Tasks marked Persistent do not exit (e.g. --watch mode or dev servers) @@ -90,9 +88,8 @@ impl Default for TaskDefinition { topological_dependencies: Default::default(), task_dependencies: Default::default(), inputs: Default::default(), - output_mode: Default::default(), + output_logs: Default::default(), persistent: Default::default(), - dot_env: Default::default(), interactive: Default::default(), } } diff --git a/crates/turborepo-lib/src/task_graph/visitor.rs b/crates/turborepo-lib/src/task_graph/visitor.rs index 64b2b0937a145..7d8956719890c 100644 --- a/crates/turborepo-lib/src/task_graph/visitor.rs +++ b/crates/turborepo-lib/src/task_graph/visitor.rs @@ -15,7 +15,7 @@ use tokio::sync::{mpsc, oneshot}; use tracing::{debug, error, Instrument, Span}; use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf, AnchoredSystemPath}; use turborepo_ci::{Vendor, VendorBehavior}; -use turborepo_env::{EnvironmentVariableMap, ResolvedEnvMode}; +use turborepo_env::EnvironmentVariableMap; use turborepo_repository::{ package_graph::{PackageGraph, PackageName, ROOT_PKG_NAME}, package_manager::PackageManager, @@ -195,18 +195,7 @@ impl<'a> Visitor<'a> { .task_definition(&info) .ok_or(Error::MissingDefinition)?; - let task_env_mode = match self.global_env_mode { - // Task env mode is only independent when global env mode is `infer`. - EnvMode::Infer if task_definition.pass_through_env.is_some() => { - ResolvedEnvMode::Strict - } - // If we're in infer mode we have just detected non-usage of strict env vars. - // But our behavior's actual meaning of this state is `loose`. - EnvMode::Infer => ResolvedEnvMode::Loose, - // Otherwise we just use the global env mode. - EnvMode::Strict => ResolvedEnvMode::Strict, - EnvMode::Loose => ResolvedEnvMode::Loose, - }; + let task_env_mode = self.global_env_mode; package_task_event.track_env_mode(&task_env_mode.to_string()); let dependency_set = engine.dependencies(&info).ok_or(Error::MissingDefinition)?; diff --git a/crates/turborepo-lib/src/task_hash.rs b/crates/turborepo-lib/src/task_hash.rs index 13e455e32491c..1c8452b655f4e 100644 --- a/crates/turborepo-lib/src/task_hash.rs +++ b/crates/turborepo-lib/src/task_hash.rs @@ -9,7 +9,7 @@ use thiserror::Error; use tracing::{debug, Span}; use turbopath::{AbsoluteSystemPath, AnchoredSystemPath, AnchoredSystemPathBuf}; use turborepo_cache::CacheHitMetadata; -use turborepo_env::{BySource, DetailedMap, EnvironmentVariableMap, ResolvedEnvMode}; +use turborepo_env::{BySource, DetailedMap, EnvironmentVariableMap}; use turborepo_repository::package_graph::{PackageInfo, PackageName}; use turborepo_scm::SCM; use turborepo_telemetry::events::{ @@ -17,6 +17,7 @@ use turborepo_telemetry::events::{ }; use crate::{ + cli::EnvMode, engine::TaskNode, framework::infer_framework, hash::{FileHashes, LockFilePackages, TaskHashable, TurboHash}, @@ -52,7 +53,7 @@ pub enum Error { impl TaskHashable<'_> { fn calculate_task_hash(mut self) -> String { - if matches!(self.env_mode, ResolvedEnvMode::Loose) { + if matches!(self.env_mode, EnvMode::Loose) { self.pass_through_env = &[]; } @@ -184,7 +185,7 @@ impl PackageInputsHashes { None }; - let mut hash_object = match hash_object { + let hash_object = match hash_object { Some(hash_object) => hash_object, None => { let local_hash_result = scm.get_package_file_hashes( @@ -199,22 +200,6 @@ impl PackageInputsHashes { } } }; - if let Some(dot_env) = &task_definition.dot_env { - if !dot_env.is_empty() { - let absolute_package_path = repo_root.resolve(package_path); - let dot_env_object = match scm.hash_existing_of( - &absolute_package_path, - dot_env.iter().map(|p| p.to_anchored_system_path_buf()), - ) { - Ok(dot_env_object) => dot_env_object, - Err(err) => return Some(Err(err.into())), - }; - - for (key, value) in dot_env_object { - hash_object.insert(key, value); - } - } - } let file_hashes = FileHashes(hash_object); let hash = file_hashes.clone().hash(); @@ -287,7 +272,7 @@ impl<'a> TaskHasher<'a> { &self, task_id: &TaskId<'static>, task_definition: &TaskDefinition, - task_env_mode: ResolvedEnvMode, + task_env_mode: EnvMode, workspace: &PackageInfo, dependency_set: HashSet<&TaskNode>, telemetry: PackageTaskEventBuilder, @@ -410,7 +395,6 @@ impl<'a> TaskHasher<'a> { .as_deref() .unwrap_or_default(), env_mode: task_env_mode, - dot_env: task_definition.dot_env.as_deref().unwrap_or_default(), }; let task_hash = task_hashable.calculate_task_hash(); @@ -471,22 +455,24 @@ impl<'a> TaskHasher<'a> { pub fn env( &self, task_id: &TaskId, - task_env_mode: ResolvedEnvMode, + task_env_mode: EnvMode, task_definition: &TaskDefinition, global_env: &EnvironmentVariableMap, ) -> Result { match task_env_mode { - ResolvedEnvMode::Strict => { + EnvMode::Strict => { let mut pass_through_env = EnvironmentVariableMap::default(); let default_env_var_pass_through_map = self.env_at_execution_start.from_wildcards(&[ "SHELL", // Command Prompt casing of env variables + "APPDATA", "PATH", "SYSTEMROOT", // Powershell casing of env variables "Path", "SystemRoot", + "AppData", ])?; let tracker_env = self .task_hash_tracker @@ -507,7 +493,7 @@ impl<'a> TaskHasher<'a> { Ok(pass_through_env) } - ResolvedEnvMode::Loose => Ok(self.env_at_execution_start.clone()), + EnvMode::Loose => Ok(self.env_at_execution_start.clone()), } } } @@ -533,6 +519,31 @@ pub fn get_external_deps_hash( LockFilePackages(transitive_deps).hash() } +pub fn get_internal_deps_hash( + scm: &SCM, + root: &AbsoluteSystemPath, + package_dirs: Vec<&AnchoredSystemPath>, +) -> Result { + if package_dirs.is_empty() { + return Ok("".into()); + } + + let file_hashes = package_dirs + .into_par_iter() + .map(|package_dir| scm.get_package_file_hashes::<&str>(root, package_dir, &[], None)) + .reduce( + || Ok(HashMap::new()), + |acc, hashes| { + let mut acc = acc?; + let hashes = hashes?; + acc.extend(hashes.into_iter()); + Ok(acc) + }, + )?; + + Ok(FileHashes(file_hashes).hash()) +} + impl TaskHashTracker { pub fn new(input_expanded_hashes: HashMap, FileHashes>) -> Self { Self { diff --git a/crates/turborepo-lib/src/turbo_json/mod.rs b/crates/turborepo-lib/src/turbo_json/mod.rs index 2de4b4533a046..bd4c441ec68ab 100644 --- a/crates/turborepo-lib/src/turbo_json/mod.rs +++ b/crates/turborepo-lib/src/turbo_json/mod.rs @@ -10,10 +10,9 @@ use miette::{NamedSource, SourceSpan}; use serde::{Deserialize, Serialize}; use struct_iterable::Iterable; use tracing::debug; -use turbopath::{AbsoluteSystemPath, AnchoredSystemPath, RelativeUnixPathBuf}; +use turbopath::{AbsoluteSystemPath, AnchoredSystemPath}; use turborepo_errors::Spanned; use turborepo_repository::{package_graph::ROOT_PKG_NAME, package_json::PackageJson}; -use turborepo_telemetry::events::generic::GenericEventBuilder; use crate::{ cli::OutputLogsMode, @@ -50,10 +49,9 @@ pub struct TurboJson { path: Option>, pub(crate) extends: Spanned>, pub(crate) global_deps: Vec, - pub(crate) global_dot_env: Option>, pub(crate) global_env: Vec, pub(crate) global_pass_through_env: Option>, - pub(crate) pipeline: Pipeline, + pub(crate) tasks: Pipeline, } // Iterable is required to enumerate allowed keys @@ -115,18 +113,18 @@ pub struct RawTurboJson { global_env: Option>>, #[serde(skip_serializing_if = "Option::is_none")] global_pass_through_env: Option>>, - // .env files to consider, in order. - #[serde(skip_serializing_if = "Option::is_none")] - global_dot_env: Option>, - // Pipeline is a map of Turbo pipeline entries which define the task graph + // Tasks is a map of task entries which define the task graph // and cache behavior on a per task or per package-task basis. #[serde(skip_serializing_if = "Option::is_none")] - pub pipeline: Option, + pub tasks: Option, + + #[serde(skip_serializing)] + pub pipeline: Option>, // Configuration options when interfacing with the remote cache #[serde(skip_serializing_if = "Option::is_none")] pub(crate) remote_cache: Option, - #[serde(skip_serializing_if = "Option::is_none", rename = "experimentalUI")] - pub experimental_ui: Option, + #[serde(skip_serializing_if = "Option::is_none", rename = "ui")] + pub ui: Option, #[deserializable(rename = "//")] #[serde(skip)] @@ -161,6 +159,24 @@ impl DerefMut for Pipeline { } } +#[derive(Serialize, Debug, Copy, Clone, Deserializable, PartialEq, Eq)] +pub enum UI { + Tui, + Stream, +} + +impl Default for UI { + fn default() -> Self { + Self::Tui + } +} + +impl UI { + pub fn use_tui(&self) -> bool { + matches!(self, Self::Tui) + } +} + #[derive(Serialize, Default, Debug, PartialEq, Clone, Iterable, Deserializable)] #[serde(rename_all = "camelCase")] #[deserializable(unknown_fields = "deny")] @@ -170,8 +186,6 @@ pub struct RawTaskDefinition { #[serde(skip_serializing_if = "Option::is_none")] depends_on: Option>>>, #[serde(skip_serializing_if = "Option::is_none")] - dot_env: Option>>, - #[serde(skip_serializing_if = "Option::is_none")] env: Option>>, #[serde(skip_serializing_if = "Option::is_none")] inputs: Option>>, @@ -182,7 +196,7 @@ pub struct RawTaskDefinition { #[serde(skip_serializing_if = "Option::is_none")] outputs: Option>>, #[serde(skip_serializing_if = "Option::is_none")] - output_mode: Option>, + output_logs: Option>, #[serde(skip_serializing_if = "Option::is_none")] interactive: Option>, } @@ -212,11 +226,10 @@ impl RawTaskDefinition { } set_field!(self, other, depends_on); set_field!(self, other, inputs); - set_field!(self, other, output_mode); + set_field!(self, other, output_logs); set_field!(self, other, persistent); set_field!(self, other, env); set_field!(self, other, pass_through_env); - set_field!(self, other, dot_env); set_field!(self, other, interactive); } } @@ -292,22 +305,21 @@ impl TryFrom for TaskDefinition { let mut task_dependencies: Vec> = Vec::new(); if let Some(depends_on) = raw_task.depends_on { for dependency in depends_on.into_inner() { - let (dependency, span) = dependency.split(); + let (span, text) = dependency.span_and_text("turbo.json"); + let (dependency, depspan) = dependency.split(); let dependency: String = dependency.into(); - if let Some(dependency) = dependency.strip_prefix(ENV_PIPELINE_DELIMITER) { - println!( - "[DEPRECATED] Declaring an environment variable in \"dependsOn\" is \ - deprecated, found {}. Use the \"env\" key or use `npx @turbo/codemod \ - migrate-env-var-dependencies`.\n", - dependency - ); - env_var_dependencies.insert(dependency.to_string()); + if dependency.strip_prefix(ENV_PIPELINE_DELIMITER).is_some() { + return Err(Error::InvalidDependsOnValue { + field: "dependsOn", + span, + text, + }); } else if let Some(topo_dependency) = dependency.strip_prefix(TOPOLOGICAL_PIPELINE_DELIMITER) { - topological_dependencies.push(span.to(topo_dependency.to_string().into())); + topological_dependencies.push(depspan.to(topo_dependency.to_string().into())); } else { - task_dependencies.push(span.to(dependency.into())); + task_dependencies.push(depspan.to(dependency.into())); } } } @@ -356,21 +368,6 @@ impl TryFrom for TaskDefinition { }) .transpose()?; - let dot_env = raw_task - .dot_env - .map(|env| -> Result, Error> { - // Going to _at least_ be an empty array. - let mut dot_env = Vec::new(); - for dot_env_path in env.into_inner() { - let type_checked_path = RelativeUnixPathBuf::new(dot_env_path)?; - // These are _explicitly_ not sorted. - dot_env.push(type_checked_path); - } - - Ok(dot_env) - }) - .transpose()?; - Ok(TaskDefinition { outputs, cache, @@ -379,8 +376,7 @@ impl TryFrom for TaskDefinition { env, inputs, pass_through_env, - dot_env, - output_mode: *raw_task.output_mode.unwrap_or_default(), + output_logs: *raw_task.output_logs.unwrap_or_default(), persistent: *raw_task.persistent.unwrap_or_default(), interactive, }) @@ -403,7 +399,7 @@ impl RawTurboJson { /// workspaces pub fn prune_tasks>(&self, workspaces: &[S]) -> Self { let mut this = self.clone(); - if let Some(pipeline) = &mut this.pipeline { + if let Some(pipeline) = &mut this.tasks { pipeline.0.retain(|task_name, _| { task_name.in_workspace(ROOT_PKG_NAME) || workspaces @@ -447,7 +443,7 @@ impl RawTurboJson { } Some(RawTurboJson { - pipeline: Some(pipeline), + tasks: Some(pipeline), ..RawTurboJson::default() }) } @@ -457,6 +453,10 @@ impl TryFrom for TurboJson { type Error = Error; fn try_from(raw_turbo: RawTurboJson) -> Result { + if let Some(pipeline) = raw_turbo.pipeline { + let (span, text) = pipeline.span_and_text("turbo.json"); + return Err(Error::PipelineField { span, text }); + } let mut global_env = HashSet::new(); let mut global_file_dependencies = HashSet::new(); @@ -465,25 +465,21 @@ impl TryFrom for TurboJson { } for global_dep in raw_turbo.global_dependencies.into_iter().flatten() { - if let Some(env_var) = global_dep.strip_prefix(ENV_PIPELINE_DELIMITER) { - println!( - "[DEPRECATED] Declaring an environment variable in \"dependsOn\" is \ - deprecated, found {}. Use the \"env\" key or use `npx @turbo/codemod \ - migrate-env-var-dependencies`.\n", - env_var - ); - - global_env.insert(env_var.to_string()); + if global_dep.strip_prefix(ENV_PIPELINE_DELIMITER).is_some() { + let (span, text) = global_dep.span_and_text("turbo.json"); + return Err(Error::InvalidDependsOnValue { + field: "globalDependencies", + span, + text, + }); + } else if Utf8Path::new(&global_dep.value).is_absolute() { + let (span, text) = global_dep.span_and_text("turbo.json"); + return Err(Error::AbsolutePathInConfig { + field: "globalDependencies", + span, + text, + }); } else { - if Utf8Path::new(&global_dep.value).is_absolute() { - let (span, text) = global_dep.span_and_text("turbo.json"); - return Err(Error::AbsolutePathInConfig { - field: "globalDependencies", - span, - text, - }); - } - global_file_dependencies.insert(global_dep.into_inner().into()); } } @@ -513,20 +509,7 @@ impl TryFrom for TurboJson { global_deps }, - global_dot_env: raw_turbo - .global_dot_env - .map(|env| -> Result, Error> { - let mut global_dot_env = Vec::new(); - for dot_env_path in env { - let type_checked_path = RelativeUnixPathBuf::new(dot_env_path)?; - // These are _explicitly_ not sorted. - global_dot_env.push(type_checked_path); - } - - Ok(global_dot_env) - }) - .transpose()?, - pipeline: raw_turbo.pipeline.unwrap_or_default(), + tasks: raw_turbo.tasks.unwrap_or_default(), // copy these over, we don't need any changes here. extends: raw_turbo .extends @@ -546,14 +529,6 @@ impl TurboJson { root_package_json: &PackageJson, include_synthesized_from_root_package_json: bool, ) -> Result { - if root_package_json.legacy_turbo_config.is_some() { - println!( - "[WARNING] \"turbo\" in package.json is no longer supported. Migrate to {} by \ - running \"npx @turbo/codemod create-turbo-config\"\n", - CONFIG_FILE - ); - } - let turbo_from_files = Self::read(repo_root, &dir.join_component(CONFIG_FILE)); let turbo_from_trace = Self::read(repo_root, &dir.join_components(&TASK_ACCESS_CONFIG_PATH)); @@ -584,7 +559,7 @@ impl TurboJson { // tasks (true, Ok(mut turbo_from_files)) => { let mut pipeline = Pipeline::default(); - for (task_name, task_definition) in turbo_from_files.pipeline { + for (task_name, task_definition) in turbo_from_files.tasks { if task_name.is_package_task() { let (span, text) = task_definition.span_and_text("turbo.json"); @@ -598,7 +573,7 @@ impl TurboJson { pipeline.insert(task_name.into_root_task(), task_definition); } - turbo_from_files.pipeline = pipeline; + turbo_from_files.tasks = pipeline; turbo_from_files } @@ -612,7 +587,7 @@ impl TurboJson { // Explicitly set cache to Some(false) in this definition // so we can pretend it was set on purpose. That way it // won't get clobbered by the merge function. - turbo_json.pipeline.insert( + turbo_json.tasks.insert( task_name, Spanned::new(RawTaskDefinition { cache: Some(Spanned::new(false)), @@ -626,7 +601,7 @@ impl TurboJson { } fn has_task(&self, task_name: &TaskName) -> bool { - for key in self.pipeline.keys() { + for key in self.tasks.keys() { if key == task_name || (key.task() == task_name.task() && !task_name.is_package_task()) { return true; @@ -647,12 +622,9 @@ impl TurboJson { } pub fn task(&self, task_id: &TaskId, task_name: &TaskName) -> Option { - match self.pipeline.get(&task_id.as_task_name()) { + match self.tasks.get(&task_id.as_task_name()) { Some(entry) => Some(entry.value.clone()), - None => self - .pipeline - .get(task_name) - .map(|entry| entry.value.clone()), + None => self.tasks.get(task_name).map(|entry| entry.value.clone()), } } @@ -663,13 +635,8 @@ impl TurboJson { .collect() } - pub fn track_usage(&self, telemetry: &GenericEventBuilder) { - let global_dot_env = self.global_dot_env.as_deref(); - telemetry.track_global_dot_env(global_dot_env); - } - pub fn has_root_tasks(&self) -> bool { - self.pipeline + self.tasks .iter() .any(|(task_name, _)| task_name.package() == Some(ROOT_PKG_NAME)) } @@ -679,7 +646,7 @@ type TurboJSONValidation = fn(&TurboJson) -> Vec; pub fn validate_no_package_task_syntax(turbo_json: &TurboJson) -> Vec { turbo_json - .pipeline + .tasks .iter() .filter(|(task_name, _)| task_name.is_package_task()) .map(|(task_name, entry)| { @@ -765,10 +732,10 @@ mod tests { use serde_json::json; use tempfile::tempdir; use test_case::test_case; - use turbopath::{AbsoluteSystemPath, AnchoredSystemPath, RelativeUnixPathBuf}; + use turbopath::{AbsoluteSystemPath, AnchoredSystemPath}; use turborepo_repository::package_json::PackageJson; - use super::{Pipeline, RawTurboJson, Spanned}; + use super::{Pipeline, RawTurboJson, Spanned, UI}; use crate::{ cli::OutputLogsMode, run::task_id::TaskName, @@ -784,12 +751,6 @@ mod tests { ..TurboJson::default() } ; "global dependencies (sorted)")] - #[test_case(r#"{ "globalDotEnv": [".env.local", ".env"] }"#, - TurboJson { - global_dot_env: Some(vec![RelativeUnixPathBuf::new(".env.local").unwrap(), RelativeUnixPathBuf::new(".env").unwrap()]), - ..TurboJson::default() - } - ; "global dot env (unsorted)")] #[test_case(r#"{ "globalPassThroughEnv": ["GITHUB_TOKEN", "AWS_SECRET_KEY"] }"#, TurboJson { global_pass_through_env: Some(vec!["AWS_SECRET_KEY".to_string(), "GITHUB_TOKEN".to_string()]), @@ -828,7 +789,7 @@ mod tests { ..PackageJson::default() }, TurboJson { - pipeline: Pipeline([( + tasks: Pipeline([( "//#build".into(), Spanned::new(RawTaskDefinition { cache: Some(Spanned::new(false)), @@ -839,17 +800,9 @@ mod tests { ..TurboJson::default() } )] - #[test_case( - Some("{}"), - PackageJson { - legacy_turbo_config: Some(serde_json::Value::String("build".to_string())), - ..PackageJson::default() - }, - TurboJson::default() - )] #[test_case( Some(r#"{ - "pipeline": { + "tasks": { "build": { "cache": true } @@ -860,12 +813,12 @@ mod tests { ..PackageJson::default() }, TurboJson { - pipeline: Pipeline([( + tasks: Pipeline([( "//#build".into(), Spanned::new(RawTaskDefinition { - cache: Some(Spanned::new(true).with_range(84..88)), + cache: Some(Spanned::new(true).with_range(81..85)), ..RawTaskDefinition::default() - }).with_range(53..106) + }).with_range(50..103) ), ( "//#test".into(), @@ -897,7 +850,7 @@ mod tests { )?; turbo_json.text = None; turbo_json.path = None; - for (_, task_definition) in turbo_json.pipeline.iter_mut() { + for (_, task_definition) in turbo_json.tasks.iter_mut() { task_definition.path = None; task_definition.text = None; } @@ -920,50 +873,30 @@ mod tests { TaskDefinition::default() ; "just persistent" )] - #[test_case( - r#"{ "dotEnv": [] }"#, - RawTaskDefinition { - dot_env: Some(Spanned { - value: Vec::new(), - range: Some(12..14), - path: None, - text: None, - }), - ..RawTaskDefinition::default() - }, - TaskDefinition { - dot_env: Some(Vec::new()), - ..Default::default() - } - ; "empty dotenv" - )] #[test_case( r#"{ "dependsOn": ["cli#build"], - "dotEnv": ["package/a/.env"], "env": ["OS"], "passThroughEnv": ["AWS_SECRET_KEY"], "outputs": ["package/a/dist"], "cache": false, "inputs": ["package/a/src/**"], - "outputMode": "full", + "outputLogs": "full", "persistent": true, "interactive": true }"#, RawTaskDefinition { depends_on: Some(Spanned::new(vec![Spanned::::new("cli#build".into()).with_range(26..37)]).with_range(25..38)), - dot_env: Some(Spanned::new(vec!["package/a/.env".into()]).with_range(60..78)), - env: Some(vec![Spanned::::new("OS".into()).with_range(98..102)]), - pass_through_env: Some(vec![Spanned::::new("AWS_SECRET_KEY".into()).with_range(134..150)]), - outputs: Some(vec![Spanned::::new("package/a/dist".into()).with_range(175..191)]), - cache: Some(Spanned::new(false).with_range(213..218)), - inputs: Some(vec![Spanned::::new("package/a/src/**".into()).with_range(241..259)]), - output_mode: Some(Spanned::new(OutputLogsMode::Full).with_range(286..292)), - persistent: Some(Spanned::new(true).with_range(318..322)), - interactive: Some(Spanned::new(true).with_range(349..353)), + env: Some(vec![Spanned::::new("OS".into()).with_range(58..62)]), + pass_through_env: Some(vec![Spanned::::new("AWS_SECRET_KEY".into()).with_range(94..110)]), + outputs: Some(vec![Spanned::::new("package/a/dist".into()).with_range(135..151)]), + cache: Some(Spanned::new(false).with_range(173..178)), + inputs: Some(vec![Spanned::::new("package/a/src/**".into()).with_range(201..219)]), + output_logs: Some(Spanned::new(OutputLogsMode::Full).with_range(246..252)), + persistent: Some(Spanned::new(true).with_range(278..282)), + interactive: Some(Spanned::new(true).with_range(309..313)), }, TaskDefinition { - dot_env: Some(vec![RelativeUnixPathBuf::new("package/a/.env").unwrap()]), env: vec!["OS".to_string()], outputs: TaskOutputs { inclusions: vec!["package/a/dist".to_string()], @@ -971,7 +904,7 @@ mod tests { }, cache: false, inputs: vec!["package/a/src/**".to_string()], - output_mode: OutputLogsMode::Full, + output_logs: OutputLogsMode::Full, pass_through_env: Some(vec!["AWS_SECRET_KEY".to_string()]), task_dependencies: vec![Spanned::>::new("cli#build".into()).with_range(26..37)], topological_dependencies: vec![], @@ -983,29 +916,26 @@ mod tests { #[test_case( r#"{ "dependsOn": ["cli#build"], - "dotEnv": ["package\\a\\.env"], "env": ["OS"], "passThroughEnv": ["AWS_SECRET_KEY"], "outputs": ["package\\a\\dist"], "cache": false, "inputs": ["package\\a\\src\\**"], - "outputMode": "full", + "outputLogs": "full", "persistent": true }"#, RawTaskDefinition { depends_on: Some(Spanned::new(vec![Spanned::::new("cli#build".into()).with_range(30..41)]).with_range(29..42)), - dot_env: Some(Spanned::new(vec!["package\\a\\.env".into()]).with_range(68..88)), - env: Some(vec![Spanned::::new("OS".into()).with_range(112..116)]), - pass_through_env: Some(vec![Spanned::::new("AWS_SECRET_KEY".into()).with_range(152..168)]), - outputs: Some(vec![Spanned::::new("package\\a\\dist".into()).with_range(197..215)]), - cache: Some(Spanned::new(false).with_range(241..246)), - inputs: Some(vec![Spanned::::new("package\\a\\src\\**".into()).with_range(273..294)]), - output_mode: Some(Spanned::new(OutputLogsMode::Full).with_range(325..331)), - persistent: Some(Spanned::new(true).with_range(361..365)), + env: Some(vec![Spanned::::new("OS".into()).with_range(66..70)]), + pass_through_env: Some(vec![Spanned::::new("AWS_SECRET_KEY".into()).with_range(106..122)]), + outputs: Some(vec![Spanned::::new("package\\a\\dist".into()).with_range(151..169)]), + cache: Some(Spanned::new(false).with_range(195..200)), + inputs: Some(vec![Spanned::::new("package\\a\\src\\**".into()).with_range(227..248)]), + output_logs: Some(Spanned::new(OutputLogsMode::Full).with_range(279..285)), + persistent: Some(Spanned::new(true).with_range(315..319)), interactive: None, }, TaskDefinition { - dot_env: Some(vec![RelativeUnixPathBuf::new("package\\a\\.env").unwrap()]), env: vec!["OS".to_string()], outputs: TaskOutputs { inclusions: vec!["package\\a\\dist".to_string()], @@ -1013,7 +943,7 @@ mod tests { }, cache: false, inputs: vec!["package\\a\\src\\**".to_string()], - output_mode: OutputLogsMode::Full, + output_logs: OutputLogsMode::Full, pass_through_env: Some(vec!["AWS_SECRET_KEY".to_string()]), task_dependencies: vec![Spanned::>::new("cli#build".into()).with_range(30..41)], topological_dependencies: vec![], @@ -1078,7 +1008,7 @@ mod tests { #[test] fn test_turbo_task_pruning() { let json = RawTurboJson::parse_from_serde(json!({ - "pipeline": { + "tasks": { "//#top": {}, "build": {}, "a#build": {}, @@ -1088,7 +1018,7 @@ mod tests { .unwrap(); let pruned_json = json.prune_tasks(&["a"]); let expected: RawTurboJson = RawTurboJson::parse_from_serde(json!({ - "pipeline": { + "tasks": { "//#top": {}, "build": {}, "a#build": {}, @@ -1097,8 +1027,8 @@ mod tests { .unwrap(); // We do this comparison manually so we don't compare the `task_name_range` // fields, which are expected to be different - let pruned_pipeline = pruned_json.pipeline.unwrap(); - let expected_pipeline = expected.pipeline.unwrap(); + let pruned_pipeline = pruned_json.tasks.unwrap(); + let expected_pipeline = expected.tasks.unwrap(); for ( (pruned_task_name, pruned_pipeline_entry), (expected_task_name, expected_pipeline_entry), @@ -1117,11 +1047,11 @@ mod tests { #[test_case("errors-only", Some(OutputLogsMode::ErrorsOnly) ; "errors-only")] #[test_case("none", Some(OutputLogsMode::None) ; "none")] #[test_case("junk", None ; "invalid value")] - fn test_parsing_output_mode(output_mode: &str, expected: Option) { + fn test_parsing_output_logs_mode(output_logs: &str, expected: Option) { let json: Result = RawTurboJson::parse_from_serde(json!({ - "pipeline": { + "tasks": { "build": { - "outputMode": output_mode, + "outputLogs": output_logs, } } })); @@ -1129,18 +1059,18 @@ mod tests { let actual = json .as_ref() .ok() - .and_then(|j| j.pipeline.as_ref()) + .and_then(|j| j.tasks.as_ref()) .and_then(|pipeline| pipeline.0.get(&TaskName::from("build"))) - .and_then(|build| build.value.output_mode.clone()) + .and_then(|build| build.value.output_logs.clone()) .map(|mode| mode.into_inner()); assert_eq!(actual, expected); } - #[test_case(r#"{ "experimentalUI": true }"#, Some(true) ; "t")] - #[test_case(r#"{ "experimentalUI": false }"#, Some(false) ; "f")] + #[test_case(r#"{ "ui": "tui" }"#, Some(UI::Tui) ; "tui")] + #[test_case(r#"{ "ui": "stream" }"#, Some(UI::Stream) ; "stream")] #[test_case(r#"{}"#, None ; "missing")] - fn test_experimental_ui(json: &str, expected: Option) { + fn test_ui(json: &str, expected: Option) { let json = RawTurboJson::parse(json, AnchoredSystemPath::new("").unwrap()).unwrap(); - assert_eq!(json.experimental_ui, expected); + assert_eq!(json.ui, expected); } } diff --git a/crates/turborepo-lib/src/turbo_json/parser.rs b/crates/turborepo-lib/src/turbo_json/parser.rs index 33a1a92605538..47e16702a537c 100644 --- a/crates/turborepo-lib/src/turbo_json/parser.rs +++ b/crates/turborepo-lib/src/turbo_json/parser.rs @@ -147,6 +147,7 @@ impl WithMetadata for RawTurboJson { self.global_dependencies.add_text(text.clone()); self.global_env.add_text(text.clone()); self.global_pass_through_env.add_text(text.clone()); + self.tasks.add_text(text.clone()); self.pipeline.add_text(text); } @@ -156,6 +157,7 @@ impl WithMetadata for RawTurboJson { self.global_dependencies.add_path(path.clone()); self.global_env.add_path(path.clone()); self.global_pass_through_env.add_path(path.clone()); + self.tasks.add_path(path.clone()); self.pipeline.add_path(path); } } @@ -182,13 +184,12 @@ impl WithMetadata for RawTaskDefinition { if let Some(depends_on) = &mut self.depends_on { depends_on.value.add_text(text.clone()); } - self.dot_env.add_text(text.clone()); self.env.add_text(text.clone()); self.inputs.add_text(text.clone()); self.pass_through_env.add_text(text.clone()); self.persistent.add_text(text.clone()); self.outputs.add_text(text.clone()); - self.output_mode.add_text(text.clone()); + self.output_logs.add_text(text.clone()); self.interactive.add_text(text); } @@ -197,13 +198,12 @@ impl WithMetadata for RawTaskDefinition { if let Some(depends_on) = &mut self.depends_on { depends_on.value.add_path(path.clone()); } - self.dot_env.add_path(path.clone()); self.env.add_path(path.clone()); self.inputs.add_path(path.clone()); self.pass_through_env.add_path(path.clone()); self.persistent.add_path(path.clone()); self.outputs.add_path(path.clone()); - self.output_mode.add_path(path.clone()); + self.output_logs.add_path(path.clone()); self.interactive.add_path(path); } } diff --git a/crates/turborepo-lockfiles/Cargo.toml b/crates/turborepo-lockfiles/Cargo.toml index e8f2ad2aeafa9..de412cd79992b 100644 --- a/crates/turborepo-lockfiles/Cargo.toml +++ b/crates/turborepo-lockfiles/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-lockfiles" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-lsp/Cargo.toml b/crates/turborepo-lsp/Cargo.toml index 9d37dd517fcfe..5b1f508321fb9 100644 --- a/crates/turborepo-lsp/Cargo.toml +++ b/crates/turborepo-lsp/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-lsp" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" [features] default = ["rustls-tls"] diff --git a/crates/turborepo-lsp/src/lib.rs b/crates/turborepo-lsp/src/lib.rs index 7001942f656d0..7ba126002a34a 100644 --- a/crates/turborepo-lsp/src/lib.rs +++ b/crates/turborepo-lsp/src/lib.rs @@ -216,7 +216,7 @@ impl LanguageServer for Backend { .value .as_ref() .and_then(|v| v.as_object()) - .and_then(|o| o.get_object("pipeline")) + .and_then(|o| o.get_object("tasks")) .map(|p| p.properties.iter()) .into_iter() .flatten() @@ -388,7 +388,7 @@ impl LanguageServer for Backend { .value .as_ref() .and_then(|v| v.as_object()) - .and_then(|o| o.get_object("pipeline")) + .and_then(|o| o.get_object("tasks")) .map(|p| p.properties.iter()) .into_iter() .flatten(); @@ -736,7 +736,7 @@ impl Backend { ); let pipeline = object - .and_then(|o| o.get_object("pipeline")) + .and_then(|o| o.get_object("tasks")) .map(|p| p.properties.iter()); for property in pipeline.into_iter().flatten() { diff --git a/crates/turborepo-paths/Cargo.toml b/crates/turborepo-paths/Cargo.toml index 7b0f8a8782d86..73699b825139d 100644 --- a/crates/turborepo-paths/Cargo.toml +++ b/crates/turborepo-paths/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "turbopath" version = "0.1.0" -license = "MPL-2.0" +license = "MIT" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-paths/src/relative_unix_path.rs b/crates/turborepo-paths/src/relative_unix_path.rs index 56150d0b810a0..9cfd6027dffc7 100644 --- a/crates/turborepo-paths/src/relative_unix_path.rs +++ b/crates/turborepo-paths/src/relative_unix_path.rs @@ -52,6 +52,10 @@ impl RelativeUnixPath { self.0.is_empty() } + pub fn as_str(&self) -> &str { + &self.0 + } + pub fn to_owned(&self) -> RelativeUnixPathBuf { RelativeUnixPathBuf(self.0.to_owned()) } diff --git a/crates/turborepo-paths/src/relative_unix_path_buf.rs b/crates/turborepo-paths/src/relative_unix_path_buf.rs index ce49d7a9e7d04..15761f8818898 100644 --- a/crates/turborepo-paths/src/relative_unix_path_buf.rs +++ b/crates/turborepo-paths/src/relative_unix_path_buf.rs @@ -34,10 +34,6 @@ impl RelativeUnixPathBuf { self.0 } - pub fn as_str(&self) -> &str { - self.0.as_str() - } - pub fn make_canonical_for_tar(&mut self, is_dir: bool) { if is_dir && !self.0.ends_with('/') { self.0.push('/'); diff --git a/crates/turborepo-repository/Cargo.toml b/crates/turborepo-repository/Cargo.toml index 213a115e65006..1f16fd54b72c5 100644 --- a/crates/turborepo-repository/Cargo.toml +++ b/crates/turborepo-repository/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-repository" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" [lints] workspace = true 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_graph/builder.rs b/crates/turborepo-repository/src/package_graph/builder.rs index 1bf6caa82cbd4..a9238888cd5bc 100644 --- a/crates/turborepo-repository/src/package_graph/builder.rs +++ b/crates/turborepo-repository/src/package_graph/builder.rs @@ -325,6 +325,7 @@ impl<'a, T: PackageDiscovery> BuildState<'a, ResolvedPackageManager, T> { node_lookup, lockfile, package_discovery, + repo_root, .. } = self; @@ -337,6 +338,7 @@ impl<'a, T: PackageDiscovery> BuildState<'a, ResolvedPackageManager, T> { packages: workspaces, lockfile, package_manager, + repo_root: repo_root.to_owned(), }) } } @@ -536,6 +538,7 @@ impl<'a, T: PackageDiscovery> BuildState<'a, ResolvedLockfile, T> { workspace_graph, node_lookup, lockfile, + repo_root, .. } = self; Ok(PackageGraph { @@ -544,6 +547,7 @@ impl<'a, T: PackageDiscovery> BuildState<'a, ResolvedLockfile, T> { packages: workspaces, package_manager, lockfile, + repo_root: repo_root.to_owned(), }) } } diff --git a/crates/turborepo-repository/src/package_graph/mod.rs b/crates/turborepo-repository/src/package_graph/mod.rs index eb8a902adcf3e..c711cfe9fde9f 100644 --- a/crates/turborepo-repository/src/package_graph/mod.rs +++ b/crates/turborepo-repository/src/package_graph/mod.rs @@ -3,9 +3,12 @@ use std::{ fmt, }; +use itertools::Itertools; use petgraph::visit::{depth_first_search, Reversed}; use serde::Serialize; -use turbopath::{AbsoluteSystemPath, AnchoredSystemPath, AnchoredSystemPathBuf}; +use turbopath::{ + AbsoluteSystemPath, AbsoluteSystemPathBuf, AnchoredSystemPath, AnchoredSystemPathBuf, +}; use turborepo_graph_utils as graph; use turborepo_lockfiles::Lockfile; @@ -30,6 +33,7 @@ pub struct PackageGraph { packages: HashMap, package_manager: PackageManager, lockfile: Option>, + repo_root: AbsoluteSystemPathBuf, } /// The WorkspacePackage follows the Vercel glossary of terms where "Workspace" @@ -128,7 +132,16 @@ impl PackageGraph { #[tracing::instrument(skip(self))] pub fn validate(&self) -> Result<(), Error> { - graph::validate_graph(&self.graph).map_err(Error::InvalidPackageGraph) + for info in self.packages.values() { + let name = info.package_json.name.as_deref(); + if matches!(name, None | Some("")) { + let package_json_path = self.repo_root.resolve(info.package_json_path()); + return Err(Error::PackageJsonMissingName(package_json_path)); + } + } + graph::validate_graph(&self.graph).map_err(Error::InvalidPackageGraph)?; + + Ok(()) } pub fn remove_package_dependencies(&mut self) { @@ -266,6 +279,21 @@ impl PackageGraph { dependents } + pub fn root_internal_package_dependencies(&self) -> Vec<&AnchoredSystemPath> { + let dependencies = self.dependencies(&PackageNode::Workspace(PackageName::Root)); + dependencies + .into_iter() + .filter_map(|package| match package { + PackageNode::Workspace(package) => Some( + self.package_dir(package) + .expect("packages in graph should have info"), + ), + PackageNode::Root => None, + }) + .sorted() + .collect() + } + /// Returns the transitive closure of the given nodes in the package /// graph. Note that this includes the nodes themselves. If you want just /// the dependencies, or the dependents, use `dependencies` or `ancestors`. @@ -454,7 +482,6 @@ mod test { use std::assert_matches::assert_matches; use serde_json::json; - use turbopath::AbsoluteSystemPathBuf; use super::*; use crate::discovery::PackageDiscovery; @@ -481,17 +508,24 @@ mod test { async fn test_single_package_is_depends_on_root() { let root = AbsoluteSystemPathBuf::new(if cfg!(windows) { r"C:\repo" } else { "/repo" }).unwrap(); - let pkg_graph = PackageGraph::builder(&root, PackageJson::default()) - .with_package_discovery(MockDiscovery) - .with_single_package_mode(true) - .build() - .await - .unwrap(); + let pkg_graph = PackageGraph::builder( + &root, + PackageJson { + name: Some("my-package".to_owned()), + ..Default::default() + }, + ) + .with_package_discovery(MockDiscovery) + .with_single_package_mode(true) + .build() + .await + .unwrap(); let closure = pkg_graph.transitive_closure(Some(&PackageNode::Workspace(PackageName::Root))); assert!(closure.contains(&PackageNode::Root)); - assert!(pkg_graph.validate().is_ok()); + let result = pkg_graph.validate(); + assert!(result.is_ok(), "expected ok {:?}", result); } #[tokio::test] @@ -500,7 +534,10 @@ mod test { AbsoluteSystemPathBuf::new(if cfg!(windows) { r"C:\repo" } else { "/repo" }).unwrap(); let pkg_graph = PackageGraph::builder( &root, - PackageJson::from_value(json!({ "name": "root" })).unwrap(), + PackageJson::from_value( + json!({ "name": "root", "dependencies": { "a": "workspace:*"} }), + ) + .unwrap(), ) .with_package_discovery(MockDiscovery) .with_package_jsons(Some({ @@ -553,6 +590,19 @@ mod test { let pkg_version = b_external.get("c").unwrap(); assert_eq!(pkg_version, "1.2.3"); + let closure = + pkg_graph.transitive_closure(Some(&PackageNode::Workspace(PackageName::Root))); + assert_eq!( + closure, + [ + PackageNode::Root, + PackageNode::Workspace(PackageName::Root), + PackageNode::Workspace("a".into()), + PackageNode::Workspace("b".into()), + ] + .iter() + .collect::>() + ); } #[derive(Debug)] diff --git a/crates/turborepo-repository/src/package_json.rs b/crates/turborepo-repository/src/package_json.rs index 982397217c047..b1ba183177bc2 100644 --- a/crates/turborepo-repository/src/package_json.rs +++ b/crates/turborepo-repository/src/package_json.rs @@ -1,4 +1,7 @@ -use std::{collections::BTreeMap, str::FromStr}; +use std::{ + collections::{BTreeMap, HashMap}, + str::FromStr, +}; use anyhow::Result; use serde::{Deserialize, Serialize}; @@ -22,8 +25,6 @@ pub struct PackageJson { pub optional_dependencies: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub peer_dependencies: Option>, - #[serde(rename = "turbo", default, skip_serializing_if = "Option::is_none")] - pub legacy_turbo_config: Option, #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] pub scripts: BTreeMap, #[serde(skip_serializing_if = "Option::is_none")] @@ -81,6 +82,19 @@ impl PackageJson { .filter(|command| !command.is_empty()) .map(|command| command.as_str()) } + + pub fn engines(&self) -> Option> { + let engines = self.other.get("engines")?.as_object()?; + Some( + engines + .iter() + .filter_map(|(key, value)| { + let value = value.as_str()?; + Some((key.as_str(), value)) + }) + .collect(), + ) + } } impl FromStr for PackageJson { @@ -108,19 +122,4 @@ mod test { let actual = serde_json::to_value(package_json).unwrap(); assert_eq!(actual, json); } - - #[test] - fn test_legacy_turbo_config() -> Result<()> { - let contents = r#"{"turbo": {}}"#; - let package_json = serde_json::from_str::(contents)?; - - assert!(package_json.legacy_turbo_config.is_some()); - - let contents = r#"{"turbo": { "globalDependencies": [".env"] } }"#; - let package_json = serde_json::from_str::(contents)?; - - assert!(package_json.legacy_turbo_config.is_some()); - - Ok(()) - } } 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/crates/turborepo-scm/Cargo.toml b/crates/turborepo-scm/Cargo.toml index 07d37d5eeda1f..92cd555381067 100644 --- a/crates/turborepo-scm/Cargo.toml +++ b/crates/turborepo-scm/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-scm" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-telemetry/Cargo.toml b/crates/turborepo-telemetry/Cargo.toml index ab81ee991ea7d..385f1f0ba00d0 100644 --- a/crates/turborepo-telemetry/Cargo.toml +++ b/crates/turborepo-telemetry/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-telemetry" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-telemetry/src/events/generic.rs b/crates/turborepo-telemetry/src/events/generic.rs index 9ae6fb2ee2742..0717faf3a2999 100644 --- a/crates/turborepo-telemetry/src/events/generic.rs +++ b/crates/turborepo-telemetry/src/events/generic.rs @@ -1,7 +1,6 @@ use std::fmt::Display; use serde::{Deserialize, Serialize}; -use turbopath::RelativeUnixPathBuf; use turborepo_vercel_api::telemetry::{TelemetryEvent, TelemetryGenericEvent}; use uuid::Uuid; @@ -213,28 +212,6 @@ impl GenericEventBuilder { self } - pub fn track_global_dot_env(&self, global_dot_env: Option<&[RelativeUnixPathBuf]>) -> &Self { - if let Some(global_dot_env) = global_dot_env { - self.track(Event { - key: "global_dot_env".into(), - value: global_dot_env.len().to_string(), - is_sensitive: EventType::NonSensitive, - }); - } - self - } - - pub fn track_dot_env(&self, dot_env: Option<&[RelativeUnixPathBuf]>) -> &Self { - if let Some(dot_env) = dot_env { - self.track(Event { - key: "dot_env".into(), - value: dot_env.len().to_string(), - is_sensitive: EventType::NonSensitive, - }); - } - self - } - // errors pub fn track_error(&self, error: TrackedErrors) -> &Self { self.track(Event { diff --git a/crates/turborepo-ui/Cargo.toml b/crates/turborepo-ui/Cargo.toml index f0d1881aeeb58..68b9aaaf9219d 100644 --- a/crates/turborepo-ui/Cargo.toml +++ b/crates/turborepo-ui/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-ui" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dev-dependencies] diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index d0ab438cda9cc..ce57ea9b078ee 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -1,5 +1,5 @@ use std::{ - io::{self, Stdout}, + io::{self, Stdout, Write}, time::{Duration, Instant}, }; @@ -160,6 +160,8 @@ fn poll(interact: bool, receiver: &AppReceiver, deadline: Instant) -> Option io::Result>> { crossterm::terminal::enable_raw_mode()?; let mut stdout = io::stdout(); + // Ensure all pending writes are flushed before we switch to alternative screen + stdout.flush()?; crossterm::execute!( stdout, crossterm::event::EnableMouseCapture, diff --git a/crates/turborepo-updater/Cargo.toml b/crates/turborepo-updater/Cargo.toml index 41f70f594dc73..40c7cd268d2c4 100644 --- a/crates/turborepo-updater/Cargo.toml +++ b/crates/turborepo-updater/Cargo.toml @@ -3,7 +3,7 @@ name = "turbo-updater" version = "0.1.0" edition = "2021" description = "Minimal wrapper around update-informer to provide npm registry support and consistent UI" -license = "MPL-2.0" +license = "MIT" publish = false [features] diff --git a/crates/turborepo-vercel-api-mock/Cargo.toml b/crates/turborepo-vercel-api-mock/Cargo.toml index 920ad4be42ff3..76e876234f63f 100644 --- a/crates/turborepo-vercel-api-mock/Cargo.toml +++ b/crates/turborepo-vercel-api-mock/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-vercel-api-mock" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo-vercel-api/Cargo.toml b/crates/turborepo-vercel-api/Cargo.toml index e9931d614e03a..bbfbb807f4a2c 100644 --- a/crates/turborepo-vercel-api/Cargo.toml +++ b/crates/turborepo-vercel-api/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-vercel-api" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/turborepo/Cargo.toml b/crates/turborepo/Cargo.toml index a71cde9ffb183..71d99c5401ce4 100644 --- a/crates/turborepo/Cargo.toml +++ b/crates/turborepo/Cargo.toml @@ -2,7 +2,7 @@ name = "turbo" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" [features] # By default, we enable rustls-tls for reqwest via downstream transitive features. diff --git a/packages/create-turbo/LICENSE b/packages/create-turbo/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/create-turbo/LICENSE +++ b/packages/create-turbo/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/create-turbo/__tests__/index.test.ts b/packages/create-turbo/__tests__/index.test.ts index 7892ed6cd453d..5d77cfdaa5b46 100644 --- a/packages/create-turbo/__tests__/index.test.ts +++ b/packages/create-turbo/__tests__/index.test.ts @@ -85,15 +85,12 @@ describe("create-turbo", () => { return "success"; }); - await create( - root as CreateCommandArgument, - packageManager as CreateCommandArgument, - { - skipInstall: true, - example: "default", - telemetry, - } - ); + await create(root as CreateCommandArgument, { + packageManager, + skipInstall: true, + example: "default", + telemetry, + }); const expected = `${chalk.bold( logger.turboGradient(">>> Success!") @@ -161,7 +158,7 @@ describe("create-turbo", () => { return "success"; }); - await create(root as CreateCommandArgument, undefined, { + await create(root as CreateCommandArgument, { packageManager, skipInstall: true, example: "default", @@ -221,15 +218,12 @@ describe("create-turbo", () => { return "success"; }); - await create( - root as CreateCommandArgument, - packageManager as CreateCommandArgument, - { - skipInstall: true, - example: "default", - telemetry, - } - ); + await create(root as CreateCommandArgument, { + packageManager, + skipInstall: true, + example: "default", + telemetry, + }); expect(mockConsole.error).toHaveBeenCalledTimes(2); expect(mockConsole.error).toHaveBeenNthCalledWith( diff --git a/packages/create-turbo/package.json b/packages/create-turbo/package.json index 6d76d35f78e98..4bcdfb8509058 100644 --- a/packages/create-turbo/package.json +++ b/packages/create-turbo/package.json @@ -1,9 +1,9 @@ { "name": "create-turbo", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "Create a new Turborepo", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/create-turbo/src/cli.ts b/packages/create-turbo/src/cli.ts index f07ea6102dd08..3d1b252d7db0c 100644 --- a/packages/create-turbo/src/cli.ts +++ b/packages/create-turbo/src/cli.ts @@ -48,9 +48,6 @@ createTurboCli }) .argument("[project-directory]") - // TODO: argument is still provided (but removed from help) - // for backwards compatibility, remove this in the next major - .argument("[package-manager]") .addOption( new Option( "-m, --package-manager ", diff --git a/packages/create-turbo/src/commands/create/index.ts b/packages/create-turbo/src/commands/create/index.ts index 7920a1f41cd28..a8844e43f1797 100644 --- a/packages/create-turbo/src/commands/create/index.ts +++ b/packages/create-turbo/src/commands/create/index.ts @@ -69,27 +69,18 @@ const SCRIPTS_TO_DISPLAY: Record = { export async function create( directory: CreateCommandArgument, - packageManagerCmd: CreateCommandArgument, opts: CreateCommandOptions ) { // track CLI command start opts.telemetry?.trackCommandStatus({ command: "create", status: "start" }); - opts.telemetry?.trackArgumentPackageManager(packageManagerCmd); opts.telemetry?.trackArgumentDirectory(Boolean(directory)); trackOptions(opts); - const { - packageManager: packageManagerOpt, - skipInstall, - skipTransforms, - } = opts; + const { packageManager, skipInstall, skipTransforms } = opts; logger.log(chalk.bold(turboGradient(`\n>>> TURBOREPO\n`))); info(`Welcome to Turborepo! Let's get you set up with a new codebase.`); logger.log(); - // if both the package manager option and command are provided, the option takes precedence - const packageManager = packageManagerOpt ?? packageManagerCmd; - const [online, availablePackageManagers] = await Promise.all([ isOnline(), getAvailablePackageManagers(), diff --git a/packages/eslint-config-turbo/LICENSE b/packages/eslint-config-turbo/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/eslint-config-turbo/LICENSE +++ b/packages/eslint-config-turbo/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/eslint-config-turbo/package.json b/packages/eslint-config-turbo/package.json index 9d6429447ac7a..615e0373d3e36 100644 --- a/packages/eslint-config-turbo/package.json +++ b/packages/eslint-config-turbo/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-turbo", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "ESLint config for Turborepo", "repository": { "type": "git", @@ -29,7 +29,7 @@ "peerDependencies": { "eslint": ">6.6.0" }, - "license": "MPL-2.0", + "license": "MIT", "devDependencies": { "@turbo/eslint-config": "workspace:*", "@types/eslint": "^8.44.2" diff --git a/packages/eslint-plugin-turbo/LICENSE b/packages/eslint-plugin-turbo/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/eslint-plugin-turbo/LICENSE +++ b/packages/eslint-plugin-turbo/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/eslint-plugin-turbo/lib/utils/calculate-inputs.ts b/packages/eslint-plugin-turbo/lib/utils/calculate-inputs.ts index 3965ad24982d8..656cd770e2257 100644 --- a/packages/eslint-plugin-turbo/lib/utils/calculate-inputs.ts +++ b/packages/eslint-plugin-turbo/lib/utils/calculate-inputs.ts @@ -4,7 +4,8 @@ import path from "node:path"; import type { WorkspaceConfig } from "@turbo/utils"; import { getWorkspaceConfigs } from "@turbo/utils"; import type { Pipeline } from "@turbo/types"; -import type { RootSchema } from "@turbo/types/src/types/config"; +import type { RootSchema, RootSchemaV1 } from "@turbo/types/src/types/config"; +import { forEachTaskDef } from "@turbo/utils/src/getTurboConfigs"; import { dotEnv } from "./dotenv-processing"; import { wildcardTests } from "./wildcard-processing"; @@ -131,7 +132,7 @@ function processDotEnv( function processGlobal( workspacePath: string, - rootTurboJson: RootSchema + rootTurboJson: RootSchema | RootSchemaV1 ): EnvironmentConfig { return { legacyConfig: processLegacyConfig(rootTurboJson.globalDependencies), @@ -314,7 +315,8 @@ export class Project { this.projectRoot.turboConfig ); - Object.entries(this.projectRoot.turboConfig.pipeline).forEach( + forEachTaskDef( + this.projectRoot.turboConfig, ([taskName, taskDefinition]) => { const { workspaceName, scriptName } = getTaskAddress(taskName); if (workspaceName) { @@ -341,7 +343,8 @@ export class Project { return; } - Object.entries(projectWorkspace.turboConfig.pipeline).forEach( + forEachTaskDef( + projectWorkspace.turboConfig, ([taskName, taskDefinition]) => { const { workspaceName: erroneousWorkspaceName, scriptName } = getTaskAddress(taskName); diff --git a/packages/eslint-plugin-turbo/package.json b/packages/eslint-plugin-turbo/package.json index 5df0f42615352..25273fdc4fd59 100644 --- a/packages/eslint-plugin-turbo/package.json +++ b/packages/eslint-plugin-turbo/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-turbo", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "ESLint plugin for Turborepo", "keywords": [ "turbo", @@ -52,5 +52,5 @@ "peerDependencies": { "eslint": ">6.6.0" }, - "license": "MPL-2.0" + "license": "MIT" } diff --git a/packages/turbo-codemod/LICENSE b/packages/turbo-codemod/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/turbo-codemod/LICENSE +++ b/packages/turbo-codemod/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/package.json new file mode 100644 index 0000000000000..4da92049f9be5 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/package.json @@ -0,0 +1,10 @@ +{ + "name": "root", + "workspaces": [ + "packages/*" + ], + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/packages/ui/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/packages/ui/package.json new file mode 100644 index 0000000000000..0a833e899ae58 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/packages/ui/package.json @@ -0,0 +1,6 @@ +{ + "name": "ui", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/packages/utils/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/packages/utils/package.json new file mode 100644 index 0000000000000..f980397cf1c01 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/correct-names/packages/utils/package.json @@ -0,0 +1,6 @@ +{ + "name": "utils", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/package.json new file mode 100644 index 0000000000000..4da92049f9be5 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/package.json @@ -0,0 +1,10 @@ +{ + "name": "root", + "workspaces": [ + "packages/*" + ], + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/apps/docs/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/apps/docs/package.json new file mode 100644 index 0000000000000..3abadc5cc44c3 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/apps/docs/package.json @@ -0,0 +1,6 @@ +{ + "name": "@acme/docs", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/apps/web/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/apps/web/package.json new file mode 100644 index 0000000000000..3abadc5cc44c3 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/apps/web/package.json @@ -0,0 +1,6 @@ +{ + "name": "@acme/docs", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/ui/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/ui/package.json new file mode 100644 index 0000000000000..fe616c702a22a --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/ui/package.json @@ -0,0 +1,6 @@ +{ + "name": "some-pkg", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/utils/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/utils/package.json new file mode 100644 index 0000000000000..fe616c702a22a --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/duplicate-names/packages/utils/package.json @@ -0,0 +1,6 @@ +{ + "name": "some-pkg", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/package.json new file mode 100644 index 0000000000000..4da92049f9be5 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/package.json @@ -0,0 +1,10 @@ +{ + "name": "root", + "workspaces": [ + "packages/*" + ], + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/packages/ui/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/packages/ui/package.json new file mode 100644 index 0000000000000..2e5879a21b308 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/packages/ui/package.json @@ -0,0 +1,5 @@ +{ + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/packages/utils/package.json b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/packages/utils/package.json new file mode 100644 index 0000000000000..2e5879a21b308 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/add-package-names/missing-names/packages/utils/package.json @@ -0,0 +1,5 @@ +{ + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-dot-env/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-dot-env/package.json new file mode 100644 index 0000000000000..4e17dc1580d17 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-dot-env/package.json @@ -0,0 +1,7 @@ +{ + "name": "no-outputs", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-dot-env/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-dot-env/turbo.json new file mode 100644 index 0000000000000..8626eccbf24e0 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-dot-env/turbo.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build-one": { + "dependsOn": ["build-two"] + }, + "build-two": { + "cache": false + }, + "build-three": { + "persistent": true + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-pipeline/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-pipeline/package.json new file mode 100644 index 0000000000000..6e20fc8fea33f --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-pipeline/package.json @@ -0,0 +1,7 @@ +{ + "name": "no-pipeline", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-pipeline/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-pipeline/turbo.json new file mode 100644 index 0000000000000..43131abdbb781 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-pipeline/turbo.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": ["$NEXT_PUBLIC_API_KEY", "$STRIPE_API_KEY", ".env"], + "tasks": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-turbo-json/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-turbo-json/package.json new file mode 100644 index 0000000000000..cd983346b8584 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/no-turbo-json/package.json @@ -0,0 +1,7 @@ +{ + "name": "set-default-outputs-no-turbo-json", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/with-dot-env/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/with-dot-env/package.json new file mode 100644 index 0000000000000..e4220baf4c6b9 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/with-dot-env/package.json @@ -0,0 +1,7 @@ +{ + "name": "old-outputs", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/with-dot-env/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/with-dot-env/turbo.json new file mode 100644 index 0000000000000..1a7fda5aa2c8c --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/with-dot-env/turbo.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDotEnv": [".env"], + "tasks": { + "build-one": { + "dotEnv": ["build-one/.env"] + }, + "build-two": { + "dotEnv": ["build-two/.env"], + "inputs": ["build-two/main.js"] + }, + "build-three": {} + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/index.js b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/index.js new file mode 100644 index 0000000000000..4de53f5ec2caa --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/index.js @@ -0,0 +1,6 @@ +export default function docs() { + if (process.env.ENV_1 === undefined) { + return "does not exist"; + } + return "exists"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/package.json new file mode 100644 index 0000000000000..82f9a44736f00 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/package.json @@ -0,0 +1,4 @@ +{ + "name": "docs", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/turbo.json new file mode 100644 index 0000000000000..ffd1e39374ab9 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/docs/turbo.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": {} + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/index.js b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/index.js new file mode 100644 index 0000000000000..bfd3ab817a0de --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/index.js @@ -0,0 +1,6 @@ +export default function web() { + if (!process.env.ENV_2) { + return "bar"; + } + return "foo"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/package.json new file mode 100644 index 0000000000000..d8a83edbd32a1 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/package.json @@ -0,0 +1,4 @@ +{ + "name": "web", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/turbo.json new file mode 100644 index 0000000000000..b45133c008346 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/apps/web/turbo.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + // old + "dotEnv": [".env"], + "inputs": ["src/**/*.ts"] + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/package.json new file mode 100644 index 0000000000000..c6616a615d2d5 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "workspaces": [ + "apps/*", + "packages/*" + ], + "scripts": { + "build": "turbo run build" + }, + "devDependencies": { + "turbo": "latest" + }, + "packageManager": "yarn@1.22.19" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/index.js b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/index.js new file mode 100644 index 0000000000000..dee5e80cd6992 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/index.js @@ -0,0 +1,6 @@ +export default function foo() { + if (!process.env.IS_SERVER) { + return "bar"; + } + return "foo"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/package.json new file mode 100644 index 0000000000000..7cb7cf17345dc --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/package.json @@ -0,0 +1,4 @@ +{ + "name": "ui", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/turbo.json new file mode 100644 index 0000000000000..852b684e6a67e --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/packages/ui/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build-three": { + "dotEnv": [".env"] + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/turbo.json new file mode 100644 index 0000000000000..6e047ca1f5bfd --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate-dot-env/workspace-configs/turbo.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build-one": { + "dotEnv": ["build-one/.env"] + }, + "build-two": { + "dotEnv": ["build-two/.env"], + "inputs": ["build-two/**/*.ts"] + }, + "build-three": {} + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate/turbo-1/package.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate/turbo-1/package.json new file mode 100644 index 0000000000000..24a20e7c3b688 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate/turbo-1/package.json @@ -0,0 +1,8 @@ +{ + "name": "turbo-1", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": { + "turbo": "1.7.1" + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/migrate/turbo-1/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/migrate/turbo-1/turbo.json new file mode 100644 index 0000000000000..68f85a6513427 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/migrate/turbo-1/turbo.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://turbo.build/schema.json", + // A comment which we allow + "pipeline": { + "build": { + "outputs": [".next/**", "!.next/cache/**"] + }, + "lint": { + "dotEnv": [".env.local"], + "outputs": [] + }, + "test": { + "outputMode": "errors-only" + }, + "dev": { + "cache": false + } + }, + "experimentalUI": true +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/invalid-output-mode/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/invalid-output-mode/package.json new file mode 100644 index 0000000000000..6b50aacd6c2a7 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/invalid-output-mode/package.json @@ -0,0 +1,7 @@ +{ + "name": "invalid-outputs", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/invalid-output-mode/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/invalid-output-mode/turbo.json new file mode 100644 index 0000000000000..816e9f6295cfc --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/invalid-output-mode/turbo.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "build-one": { + "outputMode": "errors-only" + }, + "build-two": { + "outputMode": [] + }, + "build-three": {}, + "garbage-in-numeric-0": { + "outputMode": 0 + }, + "garbage-in-numeric": { + "outputMode": 42 + }, + "garbage-in-string": { + "outputMode": "string" + }, + "garbage-in-empty-string": { + "outputMode": "" + }, + "garbage-in-null": { + "outputMode": null + }, + "garbage-in-false": { + "outputMode": false + }, + "garbage-in-true": { + "outputMode": true + }, + "garbage-in-object": { + "outputMode": {} + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-output-mode/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-output-mode/package.json new file mode 100644 index 0000000000000..4e17dc1580d17 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-output-mode/package.json @@ -0,0 +1,7 @@ +{ + "name": "no-outputs", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-output-mode/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-output-mode/turbo.json new file mode 100644 index 0000000000000..f5d57fcc231bb --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-output-mode/turbo.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "build-one": { + "dependsOn": ["build-two"] + }, + "build-two": { + "cache": false + }, + "build-three": { + "persistent": true + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-pipeline/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-pipeline/package.json new file mode 100644 index 0000000000000..6e20fc8fea33f --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-pipeline/package.json @@ -0,0 +1,7 @@ +{ + "name": "no-pipeline", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-pipeline/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-pipeline/turbo.json new file mode 100644 index 0000000000000..0e2d6fd17ed74 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-pipeline/turbo.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": ["$NEXT_PUBLIC_API_KEY", "$STRIPE_API_KEY", ".env"], + "pipeline": {} +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-turbo-json/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-turbo-json/package.json new file mode 100644 index 0000000000000..cd983346b8584 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/no-turbo-json/package.json @@ -0,0 +1,7 @@ +{ + "name": "set-default-outputs-no-turbo-json", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-config/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-config/package.json new file mode 100644 index 0000000000000..662a519471385 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-config/package.json @@ -0,0 +1,18 @@ +{ + "name": "set-default-outputs-old-config", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3", + "turbo": { + "pipeline": { + "build-one": { + "outputMode": "errors-only" + }, + "build-two": { + "outputMode": "none" + }, + "build-three": {} + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-config/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-config/turbo.json new file mode 100644 index 0000000000000..1e2d653f41ae0 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-config/turbo.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "build-one": { + "outputMode": "errors-only" + }, + "build-two": { + "outputMode": "none" + }, + "build-three": {} + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-output-mode/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-output-mode/package.json new file mode 100644 index 0000000000000..e4220baf4c6b9 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-output-mode/package.json @@ -0,0 +1,7 @@ +{ + "name": "old-outputs", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-output-mode/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-output-mode/turbo.json new file mode 100644 index 0000000000000..3338946304cc6 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/old-output-mode/turbo.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "build-one": { + "outputMode": "hash-only" + }, + "build-two": { + "outputMode": "full" + }, + "build-three": {} + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/index.js b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/index.js new file mode 100644 index 0000000000000..4de53f5ec2caa --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/index.js @@ -0,0 +1,6 @@ +export default function docs() { + if (process.env.ENV_1 === undefined) { + return "does not exist"; + } + return "exists"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/package.json new file mode 100644 index 0000000000000..82f9a44736f00 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/package.json @@ -0,0 +1,4 @@ +{ + "name": "docs", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/turbo.json new file mode 100644 index 0000000000000..e60cdb750955c --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/docs/turbo.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "build": {} + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/index.js b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/index.js new file mode 100644 index 0000000000000..bfd3ab817a0de --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/index.js @@ -0,0 +1,6 @@ +export default function web() { + if (!process.env.ENV_2) { + return "bar"; + } + return "foo"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/package.json new file mode 100644 index 0000000000000..d8a83edbd32a1 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/package.json @@ -0,0 +1,4 @@ +{ + "name": "web", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/turbo.json new file mode 100644 index 0000000000000..9154476a84363 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/apps/web/turbo.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "build": { + // old + "outputMode": "none" + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/package.json new file mode 100644 index 0000000000000..c6616a615d2d5 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "workspaces": [ + "apps/*", + "packages/*" + ], + "scripts": { + "build": "turbo run build" + }, + "devDependencies": { + "turbo": "latest" + }, + "packageManager": "yarn@1.22.19" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/index.js b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/index.js new file mode 100644 index 0000000000000..dee5e80cd6992 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/index.js @@ -0,0 +1,6 @@ +export default function foo() { + if (!process.env.IS_SERVER) { + return "bar"; + } + return "foo"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/package.json new file mode 100644 index 0000000000000..7cb7cf17345dc --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/package.json @@ -0,0 +1,4 @@ +{ + "name": "ui", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/turbo.json new file mode 100644 index 0000000000000..caf46e51da937 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/packages/ui/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "build-three": { + "outputMode": "new-only" + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/turbo.json new file mode 100644 index 0000000000000..252d4a27e035f --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-output-mode/workspace-configs/turbo.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "build-one": { + "outputMode": "new-only" + }, + "build-two": { + "outputMode": "none" + }, + "build-three": {} + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/no-turbo-json/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/no-turbo-json/package.json new file mode 100644 index 0000000000000..cd983346b8584 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/no-turbo-json/package.json @@ -0,0 +1,7 @@ +{ + "name": "set-default-outputs-no-turbo-json", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/important.txt b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/important.txt new file mode 100644 index 0000000000000..ce013625030ba --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/important.txt @@ -0,0 +1 @@ +hello diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/package.json new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/turbo.json new file mode 100644 index 0000000000000..caa7754bb02c9 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/root-only/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": ["important.txt"], + "pipeline": { + "build": { + "outputs": ["dist"] + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/index.js b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/index.js new file mode 100644 index 0000000000000..4de53f5ec2caa --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/index.js @@ -0,0 +1,6 @@ +export default function docs() { + if (process.env.ENV_1 === undefined) { + return "does not exist"; + } + return "exists"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/package.json new file mode 100644 index 0000000000000..82f9a44736f00 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/package.json @@ -0,0 +1,4 @@ +{ + "name": "docs", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/turbo.json new file mode 100644 index 0000000000000..a3713efab8eec --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/docs/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "build": { + "env": ["ENV_3"] + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/index.js b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/index.js new file mode 100644 index 0000000000000..bfd3ab817a0de --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/index.js @@ -0,0 +1,6 @@ +export default function web() { + if (!process.env.ENV_2) { + return "bar"; + } + return "foo"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/package.json new file mode 100644 index 0000000000000..d8a83edbd32a1 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/package.json @@ -0,0 +1,4 @@ +{ + "name": "web", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/turbo.json new file mode 100644 index 0000000000000..2adc44b444f16 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/apps/web/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "build": { + "dependsOn": [] + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/package.json new file mode 100644 index 0000000000000..c6616a615d2d5 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "workspaces": [ + "apps/*", + "packages/*" + ], + "scripts": { + "build": "turbo run build" + }, + "devDependencies": { + "turbo": "latest" + }, + "packageManager": "yarn@1.22.19" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/index.js b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/index.js new file mode 100644 index 0000000000000..dee5e80cd6992 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/index.js @@ -0,0 +1,6 @@ +export default function foo() { + if (!process.env.IS_SERVER) { + return "bar"; + } + return "foo"; +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/package.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/package.json new file mode 100644 index 0000000000000..7cb7cf17345dc --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/package.json @@ -0,0 +1,4 @@ +{ + "name": "ui", + "version": "1.0.0" +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/turbo.json new file mode 100644 index 0000000000000..f82702d1356df --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/packages/ui/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "pipeline": { + "test": { + "dependsOn": ["build"] + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/turbo.json new file mode 100644 index 0000000000000..6a7d63e0dcb41 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/rename-pipeline/workspace-configs/turbo.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "build": { + "outputs": [".next/**", "!.next/cache/**"], + "dependsOn": ["^build"] + }, + "lint": { + "outputs": [] + }, + "test": { + "outputs": [] + }, + "dev": { + "cache": false + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/disabled/package.json b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/disabled/package.json new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/disabled/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/disabled/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/disabled/turbo.json new file mode 100644 index 0000000000000..f0d4e6a0422d0 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/disabled/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "outputs": ["dist"] + } + }, + "experimentalUI": false +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/enabled/package.json b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/enabled/package.json new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/enabled/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/enabled/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/enabled/turbo.json new file mode 100644 index 0000000000000..6083eb8b249d8 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/enabled/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "outputs": ["dist"] + } + }, + "experimentalUI": true +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-config/package.json b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-config/package.json new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-config/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-config/turbo.json b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-config/turbo.json new file mode 100644 index 0000000000000..3d6dcac06cfac --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-config/turbo.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "outputs": ["dist"] + } + } +} diff --git a/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-turbo-json/package.json b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-turbo-json/package.json new file mode 100644 index 0000000000000..cd983346b8584 --- /dev/null +++ b/packages/turbo-codemod/__tests__/__fixtures__/stabilize-ui/no-turbo-json/package.json @@ -0,0 +1,7 @@ +{ + "name": "set-default-outputs-no-turbo-json", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": {}, + "packageManager": "npm@1.2.3" +} diff --git a/packages/turbo-codemod/__tests__/add-package-manager.test.ts b/packages/turbo-codemod/__tests__/add-package-manager.test.ts index 98651a9eb6be5..376ad180b3fe1 100644 --- a/packages/turbo-codemod/__tests__/add-package-manager.test.ts +++ b/packages/turbo-codemod/__tests__/add-package-manager.test.ts @@ -29,7 +29,7 @@ const TEST_CASES: Array = [ existingPackageManagerString: undefined, packageManager: "npm", packageManagerVersion: "7.0.0", - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, result: { changes: { "package.json": { @@ -46,7 +46,7 @@ const TEST_CASES: Array = [ existingPackageManagerString: undefined, packageManager: "npm", packageManagerVersion: "7.0.0", - options: { force: false, dry: true, print: false }, + options: { force: false, dryRun: true, print: false }, result: { changes: { "package.json": { @@ -63,7 +63,7 @@ const TEST_CASES: Array = [ existingPackageManagerString: undefined, packageManager: "yarn", packageManagerVersion: "1.2.3", - options: { force: false, dry: false, print: true }, + options: { force: false, dryRun: false, print: true }, result: { changes: { "package.json": { @@ -80,7 +80,7 @@ const TEST_CASES: Array = [ existingPackageManagerString: undefined, packageManager: "pnpm", packageManagerVersion: "1.2.3", - options: { force: false, dry: true, print: true }, + options: { force: false, dryRun: true, print: true }, result: { changes: { "package.json": { @@ -97,7 +97,7 @@ const TEST_CASES: Array = [ existingPackageManagerString: "npm@1.2.3", packageManager: "npm", packageManagerVersion: "1.2.3", - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, result: { changes: { "package.json": { @@ -114,7 +114,7 @@ const TEST_CASES: Array = [ existingPackageManagerString: "turbo@1.7.0", packageManager: "pnpm", packageManagerVersion: "1.2.3", - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, result: { changes: { "package.json": { @@ -180,7 +180,9 @@ describe("add-package-manager-2", () => { expect(mockGetWorkspaceDetails).toHaveBeenCalled(); expect(JSON.parse(read("package.json") || "{}").packageManager).toEqual( - options.dry ? undefined : `${packageManager}@${packageManagerVersion}` + options.dryRun + ? undefined + : `${packageManager}@${packageManagerVersion}` ); // result should be correct @@ -194,9 +196,13 @@ describe("add-package-manager-2", () => { expect(repeatResult.fatalError).toBeUndefined(); expect(repeatResult.changes).toMatchObject({ "package.json": { - action: options.dry ? "skipped" : "unchanged", - additions: options.dry ? result.changes["package.json"].additions : 0, - deletions: options.dry ? result.changes["package.json"].deletions : 0, + action: options.dryRun ? "skipped" : "unchanged", + additions: options.dryRun + ? result.changes["package.json"].additions + : 0, + deletions: options.dryRun + ? result.changes["package.json"].deletions + : 0, }, }); @@ -221,7 +227,7 @@ describe("add-package-manager-2", () => { // run the transformer const result = await transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(mockGetWorkspaceDetails).toHaveBeenCalledTimes(1); @@ -263,7 +269,7 @@ describe("add-package-manager-2", () => { // run the transformer const result = await transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(mockGetAvailablePackageManagers).toHaveBeenCalledTimes(1); @@ -317,7 +323,7 @@ describe("add-package-manager-2", () => { // run the transformer const result = await transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // package manager should still not exist (we couldn't write it) diff --git a/packages/turbo-codemod/__tests__/add-package-names.test.ts b/packages/turbo-codemod/__tests__/add-package-names.test.ts new file mode 100644 index 0000000000000..78e9a988c618a --- /dev/null +++ b/packages/turbo-codemod/__tests__/add-package-names.test.ts @@ -0,0 +1,117 @@ +import { setupTestFixtures } from "@turbo/test-utils"; +import { transformer } from "../src/transforms/add-package-names"; + +describe("add-package-names", () => { + const { useFixture } = setupTestFixtures({ + directory: __dirname, + test: "add-package-names", + }); + + test("missing names", async () => { + // load the fixture for the test + const { root, readJson } = useFixture({ + fixture: "missing-names", + }); + + // run the transformer + const result = await transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + // result should be correct + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "packages/ui/package.json": Object { + "action": "modified", + "additions": 1, + "deletions": 0, + }, + "packages/utils/package.json": Object { + "action": "modified", + "additions": 1, + "deletions": 0, + }, + } + `); + + // validate unique names + const names = new Set(); + + for (const pkg of ["ui", "utils"]) { + const pkgJson = readJson<{ name: string }>( + `packages/${pkg}/package.json` + ); + expect(pkgJson?.name).toBeDefined(); + expect(names.has(pkgJson?.name)).toBe(false); + names.add(pkgJson?.name); + } + }); + + test("duplicate names", async () => { + // load the fixture for the test + const { root, readJson } = useFixture({ + fixture: "duplicate-names", + }); + + // run the transformer + const result = await transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + // result should be correct + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "packages/utils/package.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + } + `); + + // validate unique names + const names = new Set(); + + for (const pkg of ["ui", "utils"]) { + const pkgJson = readJson<{ name: string }>( + `packages/${pkg}/package.json` + ); + expect(pkgJson?.name).toBeDefined(); + expect(names.has(pkgJson?.name)).toBe(false); + names.add(pkgJson?.name); + } + }); + + test("correct names", async () => { + // load the fixture for the test + const { root, readJson } = useFixture({ + fixture: "correct-names", + }); + + // run the transformer + const result = await transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + // result should be correct + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(`Object {}`); + + // validate unique names + const names = new Set(); + + for (const pkg of ["ui", "utils"]) { + const pkgJson = readJson<{ name: string }>( + `packages/${pkg}/package.json` + ); + expect(pkgJson?.name).toBeDefined(); + expect(names.has(pkgJson?.name)).toBe(false); + names.add(pkgJson?.name); + } + }); +}); diff --git a/packages/turbo-codemod/__tests__/clean-globs.test.ts b/packages/turbo-codemod/__tests__/clean-globs.test.ts index 89889fdb4c6b5..67e4e03f6d2b3 100644 --- a/packages/turbo-codemod/__tests__/clean-globs.test.ts +++ b/packages/turbo-codemod/__tests__/clean-globs.test.ts @@ -16,7 +16,7 @@ describe("clean-globs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // result should be correct diff --git a/packages/turbo-codemod/__tests__/create-turbo-config.test.ts b/packages/turbo-codemod/__tests__/create-turbo-config.test.ts index c820ee926bfbd..d3165f07dac83 100644 --- a/packages/turbo-codemod/__tests__/create-turbo-config.test.ts +++ b/packages/turbo-codemod/__tests__/create-turbo-config.test.ts @@ -21,7 +21,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // turbo.json should now exist (and match the package.json config) @@ -58,7 +58,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // turbo.json should now exist (and match the package.json config) @@ -84,7 +84,7 @@ describe("create-turbo-config", () => { // run the transformer const repeatResult = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // result should be correct expect(repeatResult.fatalError).toBeUndefined(); @@ -117,7 +117,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: true, print: false }, + options: { force: false, dryRun: true, print: false }, }); // turbo.json still not exist (dry run) @@ -154,7 +154,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: true }, + options: { force: false, dryRun: false, print: true }, }); // turbo.json should now exist (and match the package.json config) @@ -191,7 +191,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: true, print: true }, + options: { force: false, dryRun: true, print: true }, }); // turbo.json still not exist (dry run) @@ -229,7 +229,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // turbo.json should still not exist @@ -266,7 +266,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // turbo.json should still not exist @@ -293,7 +293,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // turbo.json should still exist @@ -336,7 +336,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // make sure we didn't change the package.json @@ -383,7 +383,7 @@ describe("create-turbo-config", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); // turbo.json should still not exist (error writing) diff --git a/packages/turbo-codemod/__tests__/generate-package-name.test.ts b/packages/turbo-codemod/__tests__/generate-package-name.test.ts new file mode 100644 index 0000000000000..9a4e210471113 --- /dev/null +++ b/packages/turbo-codemod/__tests__/generate-package-name.test.ts @@ -0,0 +1,29 @@ +import { getNewPkgName } from "../src/transforms/add-package-names"; + +describe("getNewPkgName", () => { + it.each([ + { + pkgPath: "/packages/ui/package.json", + pkgName: "old-name", + expected: "ui-old-name", + }, + // scoped + { + pkgPath: "/packages/ui/package.json", + pkgName: "@acme/name", + expected: "@acme/ui-name", + }, + // no name + { + pkgPath: "/packages/ui/package.json", + pkgName: undefined, + expected: "ui", + }, + ])( + "should return a new package name for pkgPath: $pkgPath and pkgName: $pkgName", + ({ pkgPath, pkgName, expected }) => { + const newName = getNewPkgName({ pkgPath, pkgName }); + expect(newName).toBe(expected); + } + ); +}); diff --git a/packages/turbo-codemod/__tests__/migrate-dot-env.test.ts b/packages/turbo-codemod/__tests__/migrate-dot-env.test.ts new file mode 100644 index 0000000000000..0d299928ce740 --- /dev/null +++ b/packages/turbo-codemod/__tests__/migrate-dot-env.test.ts @@ -0,0 +1,313 @@ +import { setupTestFixtures } from "@turbo/test-utils"; +import { type Schema } from "@turbo/types"; +import { transformer } from "../src/transforms/migrate-dot-env"; + +describe("migrate-dot-env", () => { + const { useFixture } = setupTestFixtures({ + directory: __dirname, + test: "migrate-dot-env", + }); + it("migrates turbo.json dot-env - basic", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "with-dot-env", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + globalDependencies: [".env"], + tasks: { + "build-one": { + inputs: ["$TURBO_DEFAULT$", "build-one/.env"], + }, + "build-two": { + inputs: ["build-two/main.js", "build-two/.env"], + }, + "build-three": {}, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 3, + "deletions": 3, + }, + } + `); + }); + + it("migrates turbo.json dot-env - workspace configs", () => { + // load the fixture for the test + const { root, readJson } = useFixture({ + fixture: "workspace-configs", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(readJson("turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + tasks: { + "build-one": { + inputs: ["$TURBO_DEFAULT$", "build-one/.env"], + }, + "build-two": { + inputs: ["build-two/**/*.ts", "build-two/.env"], + }, + "build-three": {}, + }, + }); + + expect(readJson("apps/docs/turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + tasks: { + build: {}, + }, + }); + + expect(readJson("apps/web/turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + tasks: { + build: { + inputs: ["src/**/*.ts", ".env"], + }, + }, + }); + + expect(readJson("packages/ui/turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + tasks: { + "build-three": { + inputs: ["$TURBO_DEFAULT$", ".env"], + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "apps/docs/turbo.json": Object { + "action": "unchanged", + "additions": 0, + "deletions": 0, + }, + "apps/web/turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 0, + }, + "packages/ui/turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + "turbo.json": Object { + "action": "modified", + "additions": 2, + "deletions": 2, + }, + } + `); + }); + + it("migrates turbo.json dot-env - dry", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "with-dot-env", + }); + + const turboJson = JSON.parse(read("turbo.json") || "{}") as Schema; + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: true, print: false }, + }); + + // make sure it didn't change + expect(JSON.parse(read("turbo.json") || "{}")).toEqual(turboJson); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "skipped", + "additions": 3, + "deletions": 3, + }, + } + `); + }); + + it("migrates turbo.json dot-env - print", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "with-dot-env", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: true }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + globalDependencies: [".env"], + tasks: { + "build-one": { + inputs: ["$TURBO_DEFAULT$", "build-one/.env"], + }, + "build-three": {}, + "build-two": { + inputs: ["build-two/main.js", "build-two/.env"], + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 3, + "deletions": 3, + }, + } + `); + }); + + it("migrates turbo.json dot-env - dry & print", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "with-dot-env", + }); + + const turboJson = JSON.parse(read("turbo.json") || "{}") as Schema; + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: true, print: false }, + }); + + // make sure it didn't change + expect(JSON.parse(read("turbo.json") || "{}")).toEqual(turboJson); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "skipped", + "additions": 3, + "deletions": 3, + }, + } + `); + }); + + it("migrates turbo.json dot-env - config with no pipeline", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-pipeline", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + globalDependencies: ["$NEXT_PUBLIC_API_KEY", "$STRIPE_API_KEY", ".env"], + tasks: {}, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "unchanged", + "additions": 0, + "deletions": 0, + }, + } + `); + }); + + it("migrates turbo.json dot-env - config with no dot env", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-dot-env", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + tasks: { + "build-one": { + dependsOn: ["build-two"], + }, + "build-two": { + cache: false, + }, + "build-three": { + persistent: true, + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "unchanged", + "additions": 0, + "deletions": 0, + }, + } + `); + }); + + it("errors if no turbo.json can be found", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-turbo-json", + }); + + expect(read("turbo.json")).toBeUndefined(); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(read("turbo.json")).toBeUndefined(); + expect(result.fatalError).toBeDefined(); + expect(result.fatalError?.message).toMatch( + /No turbo\.json found at .*?\. Is the path correct\?/ + ); + }); +}); diff --git a/packages/turbo-codemod/__tests__/migrate-env-var-dependencies.test.ts b/packages/turbo-codemod/__tests__/migrate-env-var-dependencies.test.ts index 86c7de9a9f859..77f33e81941f5 100644 --- a/packages/turbo-codemod/__tests__/migrate-env-var-dependencies.test.ts +++ b/packages/turbo-codemod/__tests__/migrate-env-var-dependencies.test.ts @@ -1,5 +1,6 @@ import merge from "deepmerge"; import type { Schema } from "@turbo/types"; +import type { SchemaV1 } from "@turbo/types/src/types/config"; import { setupTestFixtures } from "@turbo/test-utils"; import { hasLegacyEnvVarDependencies, @@ -8,7 +9,9 @@ import { transformer, } from "../src/transforms/migrate-env-var-dependencies"; -const getTestTurboConfig = (override: Schema = { pipeline: {} }): Schema => { +const getTestTurboConfig = ( + override: SchemaV1 = { pipeline: {} } +): SchemaV1 => { const config = { $schema: "./docs/public/schema.json", globalDependencies: ["$GLOBAL_ENV_KEY"], @@ -388,7 +391,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -438,7 +441,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(readJson("turbo.json") || "{}").toStrictEqual({ @@ -522,7 +525,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -565,7 +568,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const repeatResult = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(repeatResult.fatalError).toBeUndefined(); @@ -591,7 +594,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: true, print: false }, + options: { force: false, dryRun: true, print: false }, }); // make sure it didn't change @@ -618,7 +621,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: true }, + options: { force: false, dryRun: false, print: true }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -670,7 +673,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: true, print: true }, + options: { force: false, dryRun: true, print: true }, }); // make sure it didn't change @@ -699,7 +702,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toEqual(turboJson); @@ -727,7 +730,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(read("turbo.json")).toBeUndefined(); @@ -746,7 +749,7 @@ describe("migrate-env-var-dependencies", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(result.fatalError).toBeDefined(); diff --git a/packages/turbo-codemod/__tests__/migrate.test.ts b/packages/turbo-codemod/__tests__/migrate.test.ts index 1a6171b5e9d62..e31ef203dabc6 100644 --- a/packages/turbo-codemod/__tests__/migrate.test.ts +++ b/packages/turbo-codemod/__tests__/migrate.test.ts @@ -61,7 +61,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, }); @@ -151,7 +151,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: true, + dryRun: true, print: false, install: true, }); @@ -217,7 +217,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, to: "1.7.0", @@ -302,7 +302,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, from: "1.0.0", @@ -376,7 +376,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, }); @@ -429,7 +429,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: true, }); @@ -509,7 +509,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: true, }); @@ -617,7 +617,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: true, }); @@ -701,7 +701,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, }); @@ -747,7 +747,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, }); @@ -794,7 +794,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, }); @@ -851,7 +851,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: true, + dryRun: true, print: false, install: true, }); @@ -885,7 +885,7 @@ describe("migrate", () => { await migrate("~/path/that/does/not/exist", { force: false, - dry: false, + dryRun: false, print: false, install: false, }); @@ -911,7 +911,7 @@ describe("migrate", () => { await migrate(root, { force: false, - dry: false, + dryRun: false, print: false, install: false, }); @@ -924,4 +924,94 @@ describe("migrate", () => { // restore mocks mockedCheckGitStatus.mockRestore(); }); + + it("migrates across majors with all required codemods", async () => { + const { root, readJson } = useFixture({ + fixture: "turbo-1", + }); + + const packageManager = "pnpm"; + const packageManagerVersion = "1.2.3"; + + // setup mocks + const mockedCheckGitStatus = jest + .spyOn(checkGitStatus, "checkGitStatus") + .mockReturnValue(undefined); + const mockedGetCurrentVersion = jest + .spyOn(getCurrentVersion, "getCurrentVersion") + .mockReturnValue("1.99.99"); + const mockedGetLatestVersion = jest + .spyOn(getLatestVersion, "getLatestVersion") + .mockResolvedValue("2.0.0"); + const mockedGetTurboUpgradeCommand = jest + .spyOn(getTurboUpgradeCommand, "getTurboUpgradeCommand") + .mockResolvedValue("pnpm install -g turbo@latest"); + const mockedGetAvailablePackageManagers = jest + .spyOn(turboUtils, "getAvailablePackageManagers") + .mockResolvedValue({ + pnpm: packageManagerVersion, + npm: undefined, + yarn: undefined, + bun: undefined, + }); + const mockedGetWorkspaceDetails = jest + .spyOn(turboWorkspaces, "getWorkspaceDetails") + .mockResolvedValue( + getWorkspaceDetailsMockReturnValue({ + root, + packageManager, + }) + ); + + await migrate(root, { + force: false, + dryRun: false, + print: false, + install: false, + }); + + expect(readJson("package.json")).toStrictEqual({ + dependencies: {}, + devDependencies: { + turbo: "1.7.1", + }, + name: "turbo-1", + packageManager: "pnpm@1.2.3", + version: "1.0.0", + }); + expect(readJson("turbo.json")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + tasks: { + build: { + outputs: [".next/**", "!.next/cache/**"], + }, + dev: { + cache: false, + }, + lint: { + inputs: ["$TURBO_DEFAULT$", ".env.local"], + outputs: [], + }, + test: { + outputLogs: "errors-only", + }, + }, + }); + + // verify mocks were called + expect(mockedCheckGitStatus).toHaveBeenCalled(); + expect(mockedGetCurrentVersion).toHaveBeenCalled(); + expect(mockedGetLatestVersion).toHaveBeenCalled(); + expect(mockedGetTurboUpgradeCommand).toHaveBeenCalled(); + expect(mockedGetAvailablePackageManagers).toHaveBeenCalled(); + expect(mockedGetWorkspaceDetails).toHaveBeenCalled(); + + // restore mocks + mockedCheckGitStatus.mockRestore(); + mockedGetCurrentVersion.mockRestore(); + mockedGetLatestVersion.mockRestore(); + mockedGetTurboUpgradeCommand.mockRestore(); + mockedGetAvailablePackageManagers.mockRestore(); + mockedGetWorkspaceDetails.mockRestore(); + }); }); diff --git a/packages/turbo-codemod/__tests__/rename-output-mode.test.ts b/packages/turbo-codemod/__tests__/rename-output-mode.test.ts new file mode 100644 index 0000000000000..caa422db48fc2 --- /dev/null +++ b/packages/turbo-codemod/__tests__/rename-output-mode.test.ts @@ -0,0 +1,390 @@ +import { setupTestFixtures } from "@turbo/test-utils"; +import { type Schema } from "@turbo/types"; +import { transformer } from "../src/transforms/rename-output-mode"; + +describe("rename-output-mode", () => { + const { useFixture } = setupTestFixtures({ + directory: __dirname, + test: "rename-output-mode", + }); + it("migrates turbo.json outputs - basic", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "old-output-mode", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + pipeline: { + "build-one": { + outputLogs: "hash-only", + }, + "build-two": { + outputLogs: "full", + }, + "build-three": {}, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 2, + "deletions": 2, + }, + } + `); + }); + + it("migrates turbo.json outputs - workspace configs", () => { + // load the fixture for the test + const { root, readJson } = useFixture({ + fixture: "workspace-configs", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(readJson("turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + pipeline: { + "build-one": { + outputLogs: "new-only", + }, + "build-two": { + outputLogs: "none", + }, + "build-three": {}, + }, + }); + + expect(readJson("apps/docs/turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + pipeline: { + build: {}, + }, + }); + + expect(readJson("apps/web/turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + pipeline: { + build: { + outputLogs: "none", + }, + }, + }); + + expect(readJson("packages/ui/turbo.json") || "{}").toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + pipeline: { + "build-three": { + outputLogs: "new-only", + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "apps/docs/turbo.json": Object { + "action": "unchanged", + "additions": 0, + "deletions": 0, + }, + "apps/web/turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 0, + }, + "packages/ui/turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + "turbo.json": Object { + "action": "modified", + "additions": 2, + "deletions": 2, + }, + } + `); + }); + + it("migrates turbo.json outputs - dry", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "old-output-mode", + }); + + const turboJson = JSON.parse(read("turbo.json") || "{}") as Schema; + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: true, print: false }, + }); + + // make sure it didn't change + expect(JSON.parse(read("turbo.json") || "{}")).toEqual(turboJson); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "skipped", + "additions": 2, + "deletions": 2, + }, + } + `); + }); + + it("migrates turbo.json outputs - print", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "old-output-mode", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: true }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + pipeline: { + "build-one": { + outputLogs: "hash-only", + }, + "build-three": {}, + "build-two": { + outputLogs: "full", + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 2, + "deletions": 2, + }, + } + `); + }); + + it("migrates turbo.json outputs - dry & print", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "old-output-mode", + }); + + const turboJson = JSON.parse(read("turbo.json") || "{}") as Schema; + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: true, print: false }, + }); + + // make sure it didn't change + expect(JSON.parse(read("turbo.json") || "{}")).toEqual(turboJson); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "skipped", + "additions": 2, + "deletions": 2, + }, + } + `); + }); + + it("migrates turbo.json outputs - invalid", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "invalid-output-mode", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + pipeline: { + "build-one": { + outputLogs: "errors-only", + }, + "build-two": { + outputLogs: [], + }, + "build-three": {}, + "garbage-in-numeric-0": { + outputLogs: 0, + }, + "garbage-in-numeric": { + outputLogs: 42, + }, + "garbage-in-string": { + outputLogs: "string", + }, + "garbage-in-empty-string": { + outputLogs: "", + }, + "garbage-in-null": { + outputLogs: null, + }, + "garbage-in-false": { + outputLogs: false, + }, + "garbage-in-true": { + outputLogs: true, + }, + "garbage-in-object": { + outputLogs: {}, + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 10, + "deletions": 10, + }, + } + `); + }); + + it("migrates turbo.json outputs - config with no pipeline", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-pipeline", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + globalDependencies: ["$NEXT_PUBLIC_API_KEY", "$STRIPE_API_KEY", ".env"], + pipeline: {}, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "unchanged", + "additions": 0, + "deletions": 0, + }, + } + `); + }); + + it("migrates turbo.json outputs - config with no output mode", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-output-mode", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + pipeline: { + "build-one": { + dependsOn: ["build-two"], + }, + "build-two": { + cache: false, + }, + "build-three": { + persistent: true, + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "unchanged", + "additions": 0, + "deletions": 0, + }, + } + `); + }); + + it("errors if no turbo.json can be found", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-turbo-json", + }); + + expect(read("turbo.json")).toBeUndefined(); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(read("turbo.json")).toBeUndefined(); + expect(result.fatalError).toBeDefined(); + expect(result.fatalError?.message).toMatch( + /No turbo\.json found at .*?\. Is the path correct\?/ + ); + }); + + it("errors if package.json config exists and has not been migrated", () => { + // load the fixture for the test + const { root } = useFixture({ + fixture: "old-config", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(result.fatalError).toBeDefined(); + expect(result.fatalError?.message).toMatch( + 'turbo" key detected in package.json. Run `npx @turbo/codemod transform create-turbo-config` first' + ); + }); +}); diff --git a/packages/turbo-codemod/__tests__/rename-pipeline.ts b/packages/turbo-codemod/__tests__/rename-pipeline.ts new file mode 100644 index 0000000000000..c91619588e3ec --- /dev/null +++ b/packages/turbo-codemod/__tests__/rename-pipeline.ts @@ -0,0 +1,142 @@ +import { setupTestFixtures } from "@turbo/test-utils"; +import { transformer } from "../src/transforms/rename-pipeline"; + +describe("rename-pipeline", () => { + const { useFixture } = setupTestFixtures({ + directory: __dirname, + test: "rename-pipeline", + }); + + it("migrates turbo.json pipeline - root config only", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "root-only", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + globalDependencies: ["important.txt"], + tasks: { + build: { + outputs: ["dist"], + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + } + `); + }); + + it("migrates turbo.json pipeline - workspace configs", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "workspace-configs", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + tasks: { + build: { + dependsOn: ["^build"], + outputs: [".next/**", "!.next/cache/**"], + }, + dev: { + cache: false, + }, + lint: { + outputs: [], + }, + test: { + outputs: [], + }, + }, + }); + + expect(JSON.parse(read("apps/web/turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + tasks: { + build: { + dependsOn: [], + }, + }, + }); + + expect(JSON.parse(read("packages/ui/turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + extends: ["//"], + tasks: { + test: { + dependsOn: ["build"], + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "apps/docs/turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + "apps/web/turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + "packages/ui/turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + "turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + } + `); + }); + + it("errors if no turbo.json can be found", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-turbo-json", + }); + + expect(read("turbo.json")).toBeUndefined(); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(read("turbo.json")).toBeUndefined(); + expect(result.fatalError).toBeDefined(); + expect(result.fatalError?.message).toMatch( + /No turbo\.json found at .*?\. Is the path correct\?/ + ); + }); +}); diff --git a/packages/turbo-codemod/__tests__/set-default-outputs.test.ts b/packages/turbo-codemod/__tests__/set-default-outputs.test.ts index ed77b7f60a01a..b6ef9e537bf58 100644 --- a/packages/turbo-codemod/__tests__/set-default-outputs.test.ts +++ b/packages/turbo-codemod/__tests__/set-default-outputs.test.ts @@ -16,7 +16,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -53,7 +53,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(readJson("turbo.json") || "{}").toStrictEqual({ @@ -135,7 +135,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: true, print: false }, + options: { force: false, dryRun: true, print: false }, }); // make sure it didn't change @@ -162,7 +162,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: true }, + options: { force: false, dryRun: false, print: true }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -201,7 +201,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: true, print: false }, + options: { force: false, dryRun: true, print: false }, }); // make sure it didn't change @@ -228,7 +228,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -289,7 +289,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -319,7 +319,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -362,7 +362,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(read("turbo.json")).toBeUndefined(); @@ -381,7 +381,7 @@ describe("set-default-outputs", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(result.fatalError).toBeDefined(); diff --git a/packages/turbo-codemod/__tests__/stabilize-env-mode.test.ts b/packages/turbo-codemod/__tests__/stabilize-env-mode.test.ts index ff939c3ae9663..750646a2db078 100644 --- a/packages/turbo-codemod/__tests__/stabilize-env-mode.test.ts +++ b/packages/turbo-codemod/__tests__/stabilize-env-mode.test.ts @@ -1,7 +1,7 @@ import { setupTestFixtures } from "@turbo/test-utils"; import { transformer } from "../src/transforms/stabilize-env-mode"; -describe.only("stabilize-env-mode", () => { +describe("stabilize-env-mode", () => { const { useFixture } = setupTestFixtures({ directory: __dirname, test: "stabilize-env-mode", @@ -16,7 +16,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -53,7 +53,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -95,7 +95,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -129,7 +129,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -160,7 +160,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -194,7 +194,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -228,7 +228,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -301,7 +301,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(read("turbo.json")).toBeUndefined(); @@ -320,7 +320,7 @@ describe.only("stabilize-env-mode", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(result.fatalError).toBeDefined(); diff --git a/packages/turbo-codemod/__tests__/stabilize-ui.test.ts b/packages/turbo-codemod/__tests__/stabilize-ui.test.ts new file mode 100644 index 0000000000000..48f3e955010c6 --- /dev/null +++ b/packages/turbo-codemod/__tests__/stabilize-ui.test.ts @@ -0,0 +1,130 @@ +import { setupTestFixtures } from "@turbo/test-utils"; +import { transformer } from "../src/transforms/stabilize-ui"; + +describe("stabilize-ui", () => { + const { useFixture } = setupTestFixtures({ + directory: __dirname, + test: "stabilize-ui", + }); + + it("adds no config where there was none", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-config", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + tasks: { + build: { + outputs: ["dist"], + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "unchanged", + "additions": 0, + "deletions": 0, + }, + } + `); + }); + + it("removes config if it was already enabled", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "enabled", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + tasks: { + build: { + outputs: ["dist"], + }, + }, + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 0, + "deletions": 1, + }, + } + `); + }); + + it("renames config if disabled", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "disabled", + }); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ + $schema: "https://turbo.build/schema.json", + tasks: { + build: { + outputs: ["dist"], + }, + }, + ui: "stream", + }); + + expect(result.fatalError).toBeUndefined(); + expect(result.changes).toMatchInlineSnapshot(` + Object { + "turbo.json": Object { + "action": "modified", + "additions": 1, + "deletions": 1, + }, + } + `); + }); + + it("errors if no turbo.json can be found", () => { + // load the fixture for the test + const { root, read } = useFixture({ + fixture: "no-turbo-json", + }); + + expect(read("turbo.json")).toBeUndefined(); + + // run the transformer + const result = transformer({ + root, + options: { force: false, dryRun: false, print: false }, + }); + + expect(read("turbo.json")).toBeUndefined(); + expect(result.fatalError).toBeDefined(); + expect(result.fatalError?.message).toMatch( + /No turbo\.json found at .*?\. Is the path correct\?/ + ); + }); +}); diff --git a/packages/turbo-codemod/__tests__/transform-env-literals-to-wildcards.test.ts b/packages/turbo-codemod/__tests__/transform-env-literals-to-wildcards.test.ts index 2a3a5f7aaefe1..fd383e5d024e1 100644 --- a/packages/turbo-codemod/__tests__/transform-env-literals-to-wildcards.test.ts +++ b/packages/turbo-codemod/__tests__/transform-env-literals-to-wildcards.test.ts @@ -16,7 +16,7 @@ describe.only("transform-env-literals-to-wildcards", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -52,7 +52,7 @@ describe.only("transform-env-literals-to-wildcards", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -83,7 +83,7 @@ describe.only("transform-env-literals-to-wildcards", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -119,7 +119,7 @@ describe.only("transform-env-literals-to-wildcards", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(JSON.parse(read("turbo.json") || "{}")).toStrictEqual({ @@ -187,7 +187,7 @@ describe.only("transform-env-literals-to-wildcards", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(read("turbo.json")).toBeUndefined(); @@ -206,7 +206,7 @@ describe.only("transform-env-literals-to-wildcards", () => { // run the transformer const result = transformer({ root, - options: { force: false, dry: false, print: false }, + options: { force: false, dryRun: false, print: false }, }); expect(result.fatalError).toBeDefined(); diff --git a/packages/turbo-codemod/__tests__/transform.test.ts b/packages/turbo-codemod/__tests__/transform.test.ts index 01953e4037434..84e68fb007f0e 100644 --- a/packages/turbo-codemod/__tests__/transform.test.ts +++ b/packages/turbo-codemod/__tests__/transform.test.ts @@ -51,7 +51,7 @@ describe("transform", () => { await transform("add-package-manager", root as MigrateCommandArgument, { list: false, force: false, - dry: false, + dryRun: false, print: false, }); @@ -109,7 +109,7 @@ describe("transform", () => { await transform("add-package-manager", root, { list: false, force: false, - dry: true, + dryRun: true, print: true, }); @@ -141,7 +141,7 @@ describe("transform", () => { await transform("add-package-manager", root, { list: true, force: false, - dry: false, + dryRun: false, print: false, }); @@ -156,7 +156,7 @@ describe("transform", () => { await transform("not-a-real-option", root, { list: false, force: false, - dry: false, + dryRun: false, print: false, }); @@ -171,7 +171,7 @@ describe("transform", () => { await transform("add-package-manager", "~/path/that/does/not/exist", { list: false, force: false, - dry: false, + dryRun: false, print: false, }); diff --git a/packages/turbo-codemod/package.json b/packages/turbo-codemod/package.json index ba8623f75a193..c3d278079a1de 100644 --- a/packages/turbo-codemod/package.json +++ b/packages/turbo-codemod/package.json @@ -1,9 +1,9 @@ { "name": "@turbo/codemod", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "Provides Codemod transformations to help upgrade your Turborepo codebase when a feature is deprecated.", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", @@ -31,6 +31,7 @@ "gradient-string": "^2.0.0", "inquirer": "^8.2.4", "inquirer-file-tree-selection-prompt": "^1.0.19", + "json5": "^2.2.3", "is-git-clean": "^1.1.0", "ora": "4.1.1", "semver": "^7.3.7", diff --git a/packages/turbo-codemod/src/cli.ts b/packages/turbo-codemod/src/cli.ts index ab7359889c373..8ef880d6057ab 100644 --- a/packages/turbo-codemod/src/cli.ts +++ b/packages/turbo-codemod/src/cli.ts @@ -36,7 +36,11 @@ codemodCli "Bypass Git safety checks and forcibly run codemods", false ) - .option("--dry", "Dry run (no changes are made to files)", false) + .option( + "--dry, --dry-run, -d", + "Dry run (no changes are made to files)", + false + ) .option("--print", "Print transformed files to your terminal", false) .action(migrate); @@ -52,7 +56,11 @@ codemodCli false ) .option("--list", "List all available transforms", false) - .option("--dry", "Dry run (no changes are made to files)", false) + .option( + "--dry, --dry-run, -d", + "Dry run (no changes are made to files)", + false + ) .option("--print", "Print transformed files to your terminal", false) .action(transform); diff --git a/packages/turbo-codemod/src/commands/migrate/index.ts b/packages/turbo-codemod/src/commands/migrate/index.ts index 6d83d242b3aed..5958d97a9655d 100644 --- a/packages/turbo-codemod/src/commands/migrate/index.ts +++ b/packages/turbo-codemod/src/commands/migrate/index.ts @@ -53,7 +53,7 @@ export async function migrate( options: MigrateCommandOptions ) { // check git status - if (!options.dry) { + if (!options.dryRun) { checkGitStatus({ directory, force: options.force }); } @@ -161,7 +161,7 @@ export async function migrate( // shutdown the turbo daemon before running codemods and upgrading // the daemon can handle version mismatches, but we do this as an extra precaution - if (!options.dry) { + if (!options.dryRun) { shutdownDaemon({ project }); } @@ -224,7 +224,7 @@ export async function migrate( // install if (options.install) { - if (options.dry) { + if (options.dryRun) { logger.log( `Upgrading turbo with ${chalk.bold(upgradeCommand)} ${chalk.dim( "(dry run)" diff --git a/packages/turbo-codemod/src/commands/migrate/steps/getTransformsForMigration.ts b/packages/turbo-codemod/src/commands/migrate/steps/getTransformsForMigration.ts index d36493b8b8bdf..12ad1410c3bf6 100644 --- a/packages/turbo-codemod/src/commands/migrate/steps/getTransformsForMigration.ts +++ b/packages/turbo-codemod/src/commands/migrate/steps/getTransformsForMigration.ts @@ -12,11 +12,21 @@ export function getTransformsForMigration({ fromVersion: string; toVersion: string; }): Array { + const fromMajor = fromVersion.split(".")[0]; + // if migrating "from" to "to" spans a major, floor "from" to ensure all required codemods are run + const isMajorBump = fromMajor !== toVersion.split(".")[0]; + const resolvedFromVersion = isMajorBump ? `${fromMajor}.0.0` : fromVersion; const transforms = loadTransformers().filter((transformer) => { - return ( + const inOriginalRange = gt(transformer.introducedIn, fromVersion) && - lte(transformer.introducedIn, toVersion) - ); + lte(transformer.introducedIn, toVersion); + // If a transform is only in the expanded range, then we should only perform it + // if it is idempotent. + const idempotentAndInExpandedRange = + (transformer.idempotent ?? true) && + gt(transformer.introducedIn, resolvedFromVersion) && + lte(transformer.introducedIn, toVersion); + return inOriginalRange || idempotentAndInExpandedRange; }); // Sort the transforms from oldest (1.0) to newest (1.10). diff --git a/packages/turbo-codemod/src/commands/transform/index.ts b/packages/turbo-codemod/src/commands/transform/index.ts index c8a7cf73a9e3d..e31d16cdf1eb3 100644 --- a/packages/turbo-codemod/src/commands/transform/index.ts +++ b/packages/turbo-codemod/src/commands/transform/index.ts @@ -22,7 +22,7 @@ export async function transform( } // check git status - if (!options.dry) { + if (!options.dryRun) { checkGitStatus({ directory, force: options.force }); } diff --git a/packages/turbo-codemod/src/runner/Runner.ts b/packages/turbo-codemod/src/runner/Runner.ts index dc5ff8723d041..8e7887ab1e861 100644 --- a/packages/turbo-codemod/src/runner/Runner.ts +++ b/packages/turbo-codemod/src/runner/Runner.ts @@ -21,7 +21,7 @@ export class Runner { constructor(options: UtilityArgs) { this.transform = options.transformer; this.rootPath = options.rootPath; - this.dry = options.dry; + this.dry = options.dryRun; this.print = options.print; this.logger = new Logger(options); } diff --git a/packages/turbo-codemod/src/transforms/add-package-manager.ts b/packages/turbo-codemod/src/transforms/add-package-manager.ts index bfe8e59cf6cc5..c7e07085b1449 100644 --- a/packages/turbo-codemod/src/transforms/add-package-manager.ts +++ b/packages/turbo-codemod/src/transforms/add-package-manager.ts @@ -4,7 +4,7 @@ import { getWorkspaceDetails, type Project } from "@turbo/workspaces"; import { type PackageJson, getAvailablePackageManagers } from "@turbo/utils"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; import type { TransformerResults } from "../runner"; -import type { TransformerArgs } from "../types"; +import type { Transformer, TransformerArgs } from "../types"; // transformer details const TRANSFORMER = "add-package-manager"; @@ -66,7 +66,7 @@ export async function transformer({ return runner.finish(); } -const transformerMeta = { +const transformerMeta: Transformer = { name: TRANSFORMER, description: DESCRIPTION, introducedIn: INTRODUCED_IN, diff --git a/packages/turbo-codemod/src/transforms/add-package-names.ts b/packages/turbo-codemod/src/transforms/add-package-names.ts new file mode 100644 index 0000000000000..a34b3df3ec91a --- /dev/null +++ b/packages/turbo-codemod/src/transforms/add-package-names.ts @@ -0,0 +1,127 @@ +import path from "node:path"; +import { getWorkspaceDetails, type Project } from "@turbo/workspaces"; +import { readJson } from "fs-extra"; +import type { Transformer, TransformerArgs } from "../types"; +import type { TransformerResults } from "../runner"; +import { getTransformerHelpers } from "../utils/getTransformerHelpers"; + +// transformer details +const TRANSFORMER = "add-package-names"; +const DESCRIPTION = "Ensure all packages have a name in their package.json"; +const INTRODUCED_IN = "2.0.0-canary.0"; + +interface PartialPackageJson { + name?: string; +} + +async function readPkgJson( + pkgJsonPath: string +): Promise { + try { + return (await readJson(pkgJsonPath)) as { name?: string }; + } catch (e) { + return null; + } +} + +export function getNewPkgName({ + pkgPath, + pkgName, +}: { + pkgPath: string; + pkgName?: string; +}): string { + // find the scope if it exists + let scope = ""; + let name = pkgName; + if (pkgName && pkgName.startsWith("@") && pkgName.includes("/")) { + const parts = pkgName.split("/"); + scope = `${parts[0]}/`; + name = parts[1]; + } + + const dirName = path.basename(path.dirname(pkgPath)); + if (pkgName) { + return `${scope}${dirName}-${name}`; + } + + return `${scope}${dirName}`; +} + +export async function transformer({ + root, + options, +}: TransformerArgs): Promise { + const { log, runner } = getTransformerHelpers({ + transformer: TRANSFORMER, + rootPath: root, + options, + }); + + log.info('Validating that each package has a unique "name"...'); + + let project: Project; + try { + project = await getWorkspaceDetails({ root }); + } catch (e) { + return runner.abortTransform({ + reason: `Unable to determine package manager for ${root}`, + }); + } + + const packagePaths: Array = [project.paths.packageJson]; + const packagePromises: Array> = [ + readPkgJson(project.paths.packageJson), + ]; + + // add all workspace package.json files + project.workspaceData.workspaces.forEach((workspace) => { + const pkgJsonPath = workspace.paths.packageJson; + packagePaths.push(pkgJsonPath); + packagePromises.push(readPkgJson(pkgJsonPath)); + }); + + // await, and then zip the paths and promise results together + const packageContent = await Promise.all(packagePromises); + const packageToContent = Object.fromEntries( + packagePaths.map((pkgJsonPath, idx) => [pkgJsonPath, packageContent[idx]]) + ); + + // wait for all package.json files to be read + const names = new Set(); + for (const [pkgJsonPath, pkgJsonContent] of Object.entries( + packageToContent + )) { + if (pkgJsonContent) { + // name is missing or isn't unique + if (!pkgJsonContent.name || names.has(pkgJsonContent.name)) { + const newName = getNewPkgName({ + pkgPath: pkgJsonPath, + pkgName: pkgJsonContent.name, + }); + runner.modifyFile({ + filePath: pkgJsonPath, + after: { + ...pkgJsonContent, + name: newName, + }, + }); + names.add(newName); + } else { + names.add(pkgJsonContent.name); + } + } + } + + return runner.finish(); +} + +const transformerMeta: Transformer = { + name: TRANSFORMER, + description: DESCRIPTION, + introducedIn: INTRODUCED_IN, + transformer, +}; + +// eslint-disable-next-line import/no-default-export -- transforms require default export +export default transformerMeta; diff --git a/packages/turbo-codemod/src/transforms/clean-globs.ts b/packages/turbo-codemod/src/transforms/clean-globs.ts index ecd16d63f199f..7cf36cc7701a9 100644 --- a/packages/turbo-codemod/src/transforms/clean-globs.ts +++ b/packages/turbo-codemod/src/transforms/clean-globs.ts @@ -1,10 +1,10 @@ import path from "node:path"; -import type { Schema as TurboJsonSchema } from "@turbo/types"; -import { readJsonSync } from "fs-extra"; +import type { SchemaV1 } from "@turbo/types/src/types/config"; import { getTurboConfigs } from "@turbo/utils"; -import type { TransformerArgs } from "../types"; +import type { TransformerArgs, Transformer } from "../types"; import type { TransformerResults } from "../runner"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; +import { loadTurboJson } from "../utils/loadTurboJson"; // transformer details const TRANSFORMER = "clean-globs"; @@ -24,7 +24,7 @@ export function transformer({ const turboConfigPath = path.join(root, "turbo.json"); - const turboJson = readJsonSync(turboConfigPath) as TurboJsonSchema; + const turboJson: SchemaV1 = loadTurboJson(turboConfigPath); runner.modifyFile({ filePath: turboConfigPath, after: migrateConfig(turboJson), @@ -34,16 +34,18 @@ export function transformer({ const workspaceConfigs = getTurboConfigs(root); workspaceConfigs.forEach((workspaceConfig) => { const { config, turboConfigPath: filePath } = workspaceConfig; - runner.modifyFile({ - filePath, - after: migrateConfig(config), - }); + if ("pipeline" in config) { + runner.modifyFile({ + filePath, + after: migrateConfig(config), + }); + } }); return runner.finish(); } -function migrateConfig(config: TurboJsonSchema) { +function migrateConfig(config: SchemaV1) { const mapGlob = (glob: string) => fixGlobPattern(glob); for (const [_, taskDef] of Object.entries(config.pipeline)) { taskDef.inputs = taskDef.inputs?.map(mapGlob); @@ -82,9 +84,9 @@ export function fixGlobPattern(pattern: string): string { return oldPattern; } -const transformerMeta = { - name: `${TRANSFORMER}: ${DESCRIPTION}`, - value: TRANSFORMER, +const transformerMeta: Transformer = { + name: TRANSFORMER, + description: DESCRIPTION, introducedIn: INTRODUCED_IN, transformer, }; diff --git a/packages/turbo-codemod/src/transforms/create-turbo-config.ts b/packages/turbo-codemod/src/transforms/create-turbo-config.ts index 74f9d700a5c3c..a7a45d37e8ab0 100644 --- a/packages/turbo-codemod/src/transforms/create-turbo-config.ts +++ b/packages/turbo-codemod/src/transforms/create-turbo-config.ts @@ -4,7 +4,7 @@ import { type PackageJson } from "@turbo/utils"; import type { Schema } from "@turbo/types"; import type { TransformerResults } from "../runner"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; -import type { TransformerArgs } from "../types"; +import type { Transformer, TransformerArgs } from "../types"; // transformer details const TRANSFORMER = "create-turbo-config"; @@ -61,7 +61,7 @@ export function transformer({ return runner.finish(); } -const transformerMeta = { +const transformerMeta: Transformer = { name: TRANSFORMER, description: DESCRIPTION, introducedIn: INTRODUCED_IN, diff --git a/packages/turbo-codemod/src/transforms/migrate-dot-env.ts b/packages/turbo-codemod/src/transforms/migrate-dot-env.ts new file mode 100644 index 0000000000000..ff913367f69a7 --- /dev/null +++ b/packages/turbo-codemod/src/transforms/migrate-dot-env.ts @@ -0,0 +1,109 @@ +import path from "node:path"; +import { readJsonSync, existsSync } from "fs-extra"; +import { + type PackageJson, + getTurboConfigs, + forEachTaskDef, +} from "@turbo/utils"; +import type { Schema as TurboJsonSchema } from "@turbo/types"; +import type { LegacySchema } from "@turbo/types/src/types/config"; +import type { Transformer, TransformerArgs } from "../types"; +import { getTransformerHelpers } from "../utils/getTransformerHelpers"; +import type { TransformerResults } from "../runner"; +import { loadTurboJson } from "../utils/loadTurboJson"; + +// transformer details +const TRANSFORMER = "migrate-dot-env"; +const DESCRIPTION = 'Migrate the "dotEnv" entries to "inputs" in `turbo.json`'; +const INTRODUCED_IN = "2.0.0-canary.0"; + +function migrateConfig(config: LegacySchema) { + if ("globalDotEnv" in config) { + if (config.globalDotEnv) { + config.globalDependencies = config.globalDependencies ?? []; + for (const dotEnvPath of config.globalDotEnv) { + config.globalDependencies.push(dotEnvPath); + } + } + delete config.globalDotEnv; + } + + forEachTaskDef(config, ([_, taskDef]) => { + if ("dotEnv" in taskDef) { + if (taskDef.dotEnv) { + taskDef.inputs = taskDef.inputs ?? ["$TURBO_DEFAULT$"]; + for (const dotEnvPath of taskDef.dotEnv) { + taskDef.inputs.push(dotEnvPath); + } + } + delete taskDef.dotEnv; + } + }); + + return config; +} + +export function transformer({ + root, + options, +}: TransformerArgs): TransformerResults { + const { log, runner } = getTransformerHelpers({ + transformer: TRANSFORMER, + rootPath: root, + options, + }); + + // If `turbo` key is detected in package.json, require user to run the other codemod first. + const packageJsonPath = path.join(root, "package.json"); + // package.json should always exist, but if it doesn't, it would be a silly place to blow up this codemod + let packageJSON = {}; + + try { + packageJSON = readJsonSync(packageJsonPath) as PackageJson; + } catch (e) { + // readJSONSync probably failed because the file doesn't exist + } + + if ("turbo" in packageJSON) { + return runner.abortTransform({ + reason: + '"turbo" key detected in package.json. Run `npx @turbo/codemod transform create-turbo-config` first', + }); + } + + log.info(`Moving entries in \`dotEnv\` key in task config to \`inputs\``); + const turboConfigPath = path.join(root, "turbo.json"); + if (!existsSync(turboConfigPath)) { + return runner.abortTransform({ + reason: `No turbo.json found at ${root}. Is the path correct?`, + }); + } + + const turboJson: TurboJsonSchema = loadTurboJson(turboConfigPath); + runner.modifyFile({ + filePath: turboConfigPath, + after: migrateConfig(turboJson), + }); + + // find and migrate any workspace configs + const workspaceConfigs = getTurboConfigs(root); + workspaceConfigs.forEach((workspaceConfig) => { + const { config, turboConfigPath: filePath } = workspaceConfig; + runner.modifyFile({ + filePath, + after: migrateConfig(config), + }); + }); + + return runner.finish(); +} + +const transformerMeta: Transformer = { + name: TRANSFORMER, + description: DESCRIPTION, + introducedIn: INTRODUCED_IN, + transformer, +}; + +// eslint-disable-next-line import/no-default-export -- transforms require default export +export default transformerMeta; diff --git a/packages/turbo-codemod/src/transforms/migrate-env-var-dependencies.ts b/packages/turbo-codemod/src/transforms/migrate-env-var-dependencies.ts index f889fdbd172cd..ded1362956d9c 100644 --- a/packages/turbo-codemod/src/transforms/migrate-env-var-dependencies.ts +++ b/packages/turbo-codemod/src/transforms/migrate-env-var-dependencies.ts @@ -1,10 +1,12 @@ import path from "node:path"; import { readJsonSync, existsSync } from "fs-extra"; import { type PackageJson, getTurboConfigs } from "@turbo/utils"; -import type { Schema as TurboJsonSchema, Pipeline } from "@turbo/types"; +import type { Pipeline } from "@turbo/types"; +import type { SchemaV1 } from "@turbo/types/src/types/config"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; import type { TransformerResults } from "../runner"; -import type { TransformerArgs } from "../types"; +import type { Transformer, TransformerArgs } from "../types"; +import { loadTurboJson } from "../utils/loadTurboJson"; // transformer details const TRANSFORMER = "migrate-env-var-dependencies"; @@ -12,7 +14,7 @@ const DESCRIPTION = 'Migrate environment variable dependencies from "dependsOn" to "env" in `turbo.json`'; const INTRODUCED_IN = "1.5.0"; -export function hasLegacyEnvVarDependencies(config: TurboJsonSchema) { +export function hasLegacyEnvVarDependencies(config: SchemaV1) { const dependsOn = [ "extends" in config ? [] : config.globalDependencies, Object.values(config.pipeline).flatMap( @@ -68,7 +70,7 @@ export function migratePipeline(pipeline: Pipeline) { return migratedPipeline; } -export function migrateGlobal(config: TurboJsonSchema) { +export function migrateGlobal(config: SchemaV1) { if ("extends" in config) { return config; } @@ -91,7 +93,7 @@ export function migrateGlobal(config: TurboJsonSchema) { return migratedConfig; } -export function migrateConfig(config: TurboJsonSchema) { +export function migrateConfig(config: SchemaV1) { const migratedConfig = migrateGlobal(config); Object.keys(config.pipeline).forEach((pipelineKey) => { config.pipeline; @@ -144,7 +146,7 @@ export function transformer({ }); } - let turboJson = readJsonSync(turboConfigPath) as TurboJsonSchema; + let turboJson: SchemaV1 = loadTurboJson(turboConfigPath); if (hasLegacyEnvVarDependencies(turboJson).hasKeys) { turboJson = migrateConfig(turboJson); } @@ -158,7 +160,7 @@ export function transformer({ const workspaceConfigs = getTurboConfigs(root); workspaceConfigs.forEach((workspaceConfig) => { const { config, turboConfigPath: filePath } = workspaceConfig; - if (hasLegacyEnvVarDependencies(config).hasKeys) { + if ("pipeline" in config && hasLegacyEnvVarDependencies(config).hasKeys) { runner.modifyFile({ filePath, after: migrateConfig(config), @@ -169,7 +171,7 @@ export function transformer({ return runner.finish(); } -const transformerMeta = { +const transformerMeta: Transformer = { name: TRANSFORMER, description: DESCRIPTION, introducedIn: INTRODUCED_IN, diff --git a/packages/turbo-codemod/src/transforms/rename-output-mode.ts b/packages/turbo-codemod/src/transforms/rename-output-mode.ts new file mode 100644 index 0000000000000..6009e82933129 --- /dev/null +++ b/packages/turbo-codemod/src/transforms/rename-output-mode.ts @@ -0,0 +1,95 @@ +import path from "node:path"; +import { readJsonSync, existsSync } from "fs-extra"; +import { type PackageJson, getTurboConfigs } from "@turbo/utils"; +import type { OutputMode } from "@turbo/types"; +import type { SchemaV1 } from "@turbo/types/src/types/config"; +import type { Transformer, TransformerArgs } from "../types"; +import { getTransformerHelpers } from "../utils/getTransformerHelpers"; +import type { TransformerResults } from "../runner"; +import { loadTurboJson } from "../utils/loadTurboJson"; + +// transformer details +const TRANSFORMER = "rename-output-mode"; +const DESCRIPTION = + 'Rename the "outputMode" key to "outputLogs" in `turbo.json`'; +const INTRODUCED_IN = "2.0.0-canary.0"; + +function migrateConfig(config: SchemaV1) { + for (const [_, taskDef] of Object.entries(config.pipeline)) { + if (Object.prototype.hasOwnProperty.call(taskDef, "outputMode")) { + //@ts-expect-error - outputMode is no longer in the schema + taskDef.outputLogs = taskDef.outputMode as OutputMode; + //@ts-expect-error - outputMode is no longer in the schema + delete taskDef.outputMode; + } + } + + return config; +} + +export function transformer({ + root, + options, +}: TransformerArgs): TransformerResults { + const { log, runner } = getTransformerHelpers({ + transformer: TRANSFORMER, + rootPath: root, + options, + }); + + // If `turbo` key is detected in package.json, require user to run the other codemod first. + const packageJsonPath = path.join(root, "package.json"); + // package.json should always exist, but if it doesn't, it would be a silly place to blow up this codemod + let packageJSON = {}; + + try { + packageJSON = readJsonSync(packageJsonPath) as PackageJson; + } catch (e) { + // readJSONSync probably failed because the file doesn't exist + } + + if ("turbo" in packageJSON) { + return runner.abortTransform({ + reason: + '"turbo" key detected in package.json. Run `npx @turbo/codemod transform create-turbo-config` first', + }); + } + + log.info(`Renaming \`outputMode\` key in task config to \`outputLogs\``); + const turboConfigPath = path.join(root, "turbo.json"); + if (!existsSync(turboConfigPath)) { + return runner.abortTransform({ + reason: `No turbo.json found at ${root}. Is the path correct?`, + }); + } + + const turboJson: SchemaV1 = loadTurboJson(turboConfigPath); + runner.modifyFile({ + filePath: turboConfigPath, + after: migrateConfig(turboJson), + }); + + // find and migrate any workspace configs + const workspaceConfigs = getTurboConfigs(root); + workspaceConfigs.forEach((workspaceConfig) => { + const { config, turboConfigPath: filePath } = workspaceConfig; + if ("pipeline" in config) { + runner.modifyFile({ + filePath, + after: migrateConfig(config), + }); + } + }); + + return runner.finish(); +} + +const transformerMeta: Transformer = { + name: TRANSFORMER, + description: DESCRIPTION, + introducedIn: INTRODUCED_IN, + transformer, +}; + +// eslint-disable-next-line import/no-default-export -- transforms require default export +export default transformerMeta; diff --git a/packages/turbo-codemod/src/transforms/rename-pipeline.ts b/packages/turbo-codemod/src/transforms/rename-pipeline.ts new file mode 100644 index 0000000000000..6b0045b6c98c4 --- /dev/null +++ b/packages/turbo-codemod/src/transforms/rename-pipeline.ts @@ -0,0 +1,68 @@ +import path from "node:path"; +import { existsSync } from "fs-extra"; +import { getTurboConfigs } from "@turbo/utils"; +import type { Schema, SchemaV1 } from "@turbo/types/src/types/config"; +import type { Transformer, TransformerArgs } from "../types"; +import { getTransformerHelpers } from "../utils/getTransformerHelpers"; +import type { TransformerResults } from "../runner"; +import { loadTurboJson } from "../utils/loadTurboJson"; + +// transformer details +const TRANSFORMER = "rename-pipeline"; +const DESCRIPTION = 'Rename the "pipeline" key to "tasks" in `turbo.json`'; +const INTRODUCED_IN = "2.0.0-canary.0"; + +function migrateConfig(config: SchemaV1): Schema { + const { pipeline, ...rest } = config; + + return { ...rest, tasks: pipeline }; +} + +export function transformer({ + root, + options, +}: TransformerArgs): TransformerResults { + const { log, runner } = getTransformerHelpers({ + transformer: TRANSFORMER, + rootPath: root, + options, + }); + + log.info(`Renaming \`pipeline\` key in turbo.json to \`tasks\``); + const turboConfigPath = path.join(root, "turbo.json"); + if (!existsSync(turboConfigPath)) { + return runner.abortTransform({ + reason: `No turbo.json found at ${root}. Is the path correct?`, + }); + } + + const turboJson: SchemaV1 = loadTurboJson(turboConfigPath); + runner.modifyFile({ + filePath: turboConfigPath, + after: migrateConfig(turboJson), + }); + + // find and migrate any workspace configs + const workspaceConfigs = getTurboConfigs(root); + workspaceConfigs.forEach((workspaceConfig) => { + const { config, turboConfigPath: filePath } = workspaceConfig; + if ("pipeline" in config) { + runner.modifyFile({ + filePath, + after: migrateConfig(config), + }); + } + }); + + return runner.finish(); +} + +const transformerMeta: Transformer = { + name: TRANSFORMER, + description: DESCRIPTION, + introducedIn: INTRODUCED_IN, + transformer, +}; + +// eslint-disable-next-line import/no-default-export -- transforms require default export +export default transformerMeta; diff --git a/packages/turbo-codemod/src/transforms/set-default-outputs.ts b/packages/turbo-codemod/src/transforms/set-default-outputs.ts index 78d4f4ca3eb7e..c9e90a058e399 100644 --- a/packages/turbo-codemod/src/transforms/set-default-outputs.ts +++ b/packages/turbo-codemod/src/transforms/set-default-outputs.ts @@ -1,10 +1,11 @@ import path from "node:path"; import { readJsonSync, existsSync } from "fs-extra"; import { type PackageJson, getTurboConfigs } from "@turbo/utils"; -import type { Schema as TurboJsonSchema } from "@turbo/types"; -import type { TransformerArgs } from "../types"; +import type { SchemaV1 } from "@turbo/types/src/types/config"; +import type { Transformer, TransformerArgs } from "../types"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; import type { TransformerResults } from "../runner"; +import { loadTurboJson } from "../utils/loadTurboJson"; const DEFAULT_OUTPUTS = ["dist/**", "build/**"]; @@ -13,8 +14,9 @@ const TRANSFORMER = "set-default-outputs"; const DESCRIPTION = 'Add the "outputs" key with defaults where it is missing in `turbo.json`'; const INTRODUCED_IN = "1.7.0"; +const IDEMPOTENT = false; -function migrateConfig(config: TurboJsonSchema) { +function migrateConfig(config: SchemaV1) { for (const [_, taskDef] of Object.entries(config.pipeline)) { if (taskDef.cache !== false) { if (!taskDef.outputs) { @@ -67,7 +69,7 @@ export function transformer({ }); } - const turboJson = readJsonSync(turboConfigPath) as TurboJsonSchema; + const turboJson: SchemaV1 = loadTurboJson(turboConfigPath); runner.modifyFile({ filePath: turboConfigPath, after: migrateConfig(turboJson), @@ -77,19 +79,22 @@ export function transformer({ const workspaceConfigs = getTurboConfigs(root); workspaceConfigs.forEach((workspaceConfig) => { const { config, turboConfigPath: filePath } = workspaceConfig; - runner.modifyFile({ - filePath, - after: migrateConfig(config), - }); + if ("pipeline" in config) { + runner.modifyFile({ + filePath, + after: migrateConfig(config), + }); + } }); return runner.finish(); } -const transformerMeta = { +const transformerMeta: Transformer = { name: TRANSFORMER, description: DESCRIPTION, introducedIn: INTRODUCED_IN, + idempotent: IDEMPOTENT, transformer, }; diff --git a/packages/turbo-codemod/src/transforms/stabilize-env-mode.ts b/packages/turbo-codemod/src/transforms/stabilize-env-mode.ts index 8a03579bd77e2..d47a70ffee52b 100644 --- a/packages/turbo-codemod/src/transforms/stabilize-env-mode.ts +++ b/packages/turbo-codemod/src/transforms/stabilize-env-mode.ts @@ -1,11 +1,11 @@ import path from "node:path"; import { readJsonSync, existsSync } from "fs-extra"; import { type PackageJson, getTurboConfigs } from "@turbo/utils"; -import type { Schema as TurboJsonSchema } from "@turbo/types"; -import type { RootSchema } from "@turbo/types/src/types/config"; -import type { TransformerArgs } from "../types"; +import type { SchemaV1, RootSchemaV1 } from "@turbo/types/src/types/config"; +import type { Transformer, TransformerArgs } from "../types"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; import type { TransformerResults } from "../runner"; +import { loadTurboJson } from "../utils/loadTurboJson"; // transformer details const TRANSFORMER = "stabilize-env-mode"; @@ -13,7 +13,7 @@ const DESCRIPTION = "Rewrite experimentalPassThroughEnv and experimentalGlobalPassThroughEnv"; const INTRODUCED_IN = "1.10.0"; -function migrateRootConfig(config: RootSchema) { +function migrateRootConfig(config: RootSchemaV1) { const oldConfig = config.experimentalGlobalPassThroughEnv; const newConfig = config.globalPassThroughEnv; // Set to an empty array is meaningful, so we have undefined as an option here. @@ -45,7 +45,7 @@ function migrateRootConfig(config: RootSchema) { return migrateTaskConfigs(config); } -function migrateTaskConfigs(config: TurboJsonSchema) { +function migrateTaskConfigs(config: SchemaV1) { for (const [_, taskDef] of Object.entries(config.pipeline)) { const oldConfig = taskDef.experimentalPassThroughEnv; const newConfig = taskDef.passThroughEnv; @@ -119,7 +119,7 @@ export function transformer({ }); } - const turboJson = readJsonSync(turboConfigPath) as TurboJsonSchema; + const turboJson: SchemaV1 = loadTurboJson(turboConfigPath); runner.modifyFile({ filePath: turboConfigPath, after: migrateRootConfig(turboJson), @@ -129,7 +129,7 @@ export function transformer({ const allTurboJsons = getTurboConfigs(root); allTurboJsons.forEach((workspaceConfig) => { const { config, turboConfigPath: filePath, isRootConfig } = workspaceConfig; - if (!isRootConfig) { + if (!isRootConfig && "pipeline" in config) { runner.modifyFile({ filePath, after: migrateTaskConfigs(config), @@ -140,7 +140,7 @@ export function transformer({ return runner.finish(); } -const transformerMeta = { +const transformerMeta: Transformer = { name: TRANSFORMER, description: DESCRIPTION, introducedIn: INTRODUCED_IN, diff --git a/packages/turbo-codemod/src/transforms/stabilize-ui.ts b/packages/turbo-codemod/src/transforms/stabilize-ui.ts new file mode 100644 index 0000000000000..447e1de26dda2 --- /dev/null +++ b/packages/turbo-codemod/src/transforms/stabilize-ui.ts @@ -0,0 +1,63 @@ +import path from "node:path"; +import { existsSync } from "fs-extra"; +import type { RootSchema } from "@turbo/types/src/types/config"; +import type { Transformer, TransformerArgs } from "../types"; +import { getTransformerHelpers } from "../utils/getTransformerHelpers"; +import type { TransformerResults } from "../runner"; +import { loadTurboJson } from "../utils/loadTurboJson"; + +// transformer details +const TRANSFORMER = "stabilize-ui"; +const DESCRIPTION = 'Rename the "experimentalUI" key to "ui" in `turbo.json`'; +const INTRODUCED_IN = "2.0.0-canary.0"; + +interface ExperimentalSchema extends RootSchema { + experimentalUI?: boolean; +} + +function migrateConfig(config: ExperimentalSchema): RootSchema { + const ui = config.experimentalUI; + delete config.experimentalUI; + // If UI is enabled we can just remove the config now that it's enabled by default + if (ui !== undefined && !ui) { + config.ui = "stream"; + } + return config; +} + +export function transformer({ + root, + options, +}: TransformerArgs): TransformerResults { + const { log, runner } = getTransformerHelpers({ + transformer: TRANSFORMER, + rootPath: root, + options, + }); + + log.info(`Renaming \`experimentalUI\` key in turbo.json to \`ui\``); + const turboConfigPath = path.join(root, "turbo.json"); + if (!existsSync(turboConfigPath)) { + return runner.abortTransform({ + reason: `No turbo.json found at ${root}. Is the path correct?`, + }); + } + + const turboJson: RootSchema = loadTurboJson(turboConfigPath); + runner.modifyFile({ + filePath: turboConfigPath, + after: migrateConfig(turboJson), + }); + + return runner.finish(); +} + +const transformerMeta: Transformer = { + name: TRANSFORMER, + description: DESCRIPTION, + introducedIn: INTRODUCED_IN, + transformer, +}; + +// eslint-disable-next-line import/no-default-export -- transforms require default export +export default transformerMeta; diff --git a/packages/turbo-codemod/src/transforms/transform-env-literals-to-wildcards.ts b/packages/turbo-codemod/src/transforms/transform-env-literals-to-wildcards.ts index 42563f244098d..62d7e66fc8632 100644 --- a/packages/turbo-codemod/src/transforms/transform-env-literals-to-wildcards.ts +++ b/packages/turbo-codemod/src/transforms/transform-env-literals-to-wildcards.ts @@ -1,11 +1,12 @@ import path from "node:path"; import { readJsonSync, existsSync } from "fs-extra"; import { type PackageJson, getTurboConfigs } from "@turbo/utils"; -import type { EnvWildcard, Schema as TurboJsonSchema } from "@turbo/types"; -import type { RootSchema } from "@turbo/types/src/types/config"; -import type { TransformerArgs } from "../types"; +import type { EnvWildcard } from "@turbo/types"; +import type { RootSchemaV1, SchemaV1 } from "@turbo/types/src/types/config"; +import type { Transformer, TransformerArgs } from "../types"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; import type { TransformerResults } from "../runner"; +import { loadTurboJson } from "../utils/loadTurboJson"; // transformer details const TRANSFORMER = "transform-env-literals-to-wildcards"; @@ -27,7 +28,7 @@ function transformEnvVarName(envVarName: string): EnvWildcard { return output; } -function migrateRootConfig(config: RootSchema) { +function migrateRootConfig(config: RootSchemaV1) { const { globalEnv, globalPassThroughEnv } = config; if (Array.isArray(globalEnv)) { @@ -40,7 +41,7 @@ function migrateRootConfig(config: RootSchema) { return migrateTaskConfigs(config); } -function migrateTaskConfigs(config: TurboJsonSchema) { +function migrateTaskConfigs(config: SchemaV1) { for (const [_, taskDef] of Object.entries(config.pipeline)) { const { env, passThroughEnv } = taskDef; @@ -91,7 +92,7 @@ export function transformer({ }); } - const turboJson = readJsonSync(turboConfigPath) as TurboJsonSchema; + const turboJson: SchemaV1 = loadTurboJson(turboConfigPath); runner.modifyFile({ filePath: turboConfigPath, after: migrateRootConfig(turboJson), @@ -101,7 +102,7 @@ export function transformer({ const allTurboJsons = getTurboConfigs(root); allTurboJsons.forEach((workspaceConfig) => { const { config, turboConfigPath: filePath, isRootConfig } = workspaceConfig; - if (!isRootConfig) { + if (!isRootConfig && "pipeline" in config) { runner.modifyFile({ filePath, after: migrateTaskConfigs(config), @@ -112,7 +113,7 @@ export function transformer({ return runner.finish(); } -const transformerMeta = { +const transformerMeta: Transformer = { name: TRANSFORMER, description: DESCRIPTION, introducedIn: INTRODUCED_IN, diff --git a/packages/turbo-codemod/src/types.ts b/packages/turbo-codemod/src/types.ts index 625c46e828867..fffb77539b691 100644 --- a/packages/turbo-codemod/src/types.ts +++ b/packages/turbo-codemod/src/types.ts @@ -4,6 +4,7 @@ export interface Transformer { name: string; description: string; introducedIn: string; + idempotent?: boolean; transformer: ( args: TransformerArgs ) => Promise | TransformerResults; @@ -11,7 +12,7 @@ export interface Transformer { export interface TransformerOptions { force: boolean; - dry: boolean; + dryRun: boolean; print: boolean; } diff --git a/packages/turbo-codemod/src/utils/loadTurboJson.ts b/packages/turbo-codemod/src/utils/loadTurboJson.ts new file mode 100644 index 0000000000000..8da42ccd03fd8 --- /dev/null +++ b/packages/turbo-codemod/src/utils/loadTurboJson.ts @@ -0,0 +1,7 @@ +import { readFileSync } from "fs-extra"; +import { parse as JSON5Parse } from "json5"; + +export function loadTurboJson(filePath: string): T { + const contents = readFileSync(filePath, "utf8"); + return JSON5Parse(contents); +} diff --git a/packages/turbo-codemod/src/utils/logger.ts b/packages/turbo-codemod/src/utils/logger.ts index 34b5f461b0fa3..4e21103129545 100644 --- a/packages/turbo-codemod/src/utils/logger.ts +++ b/packages/turbo-codemod/src/utils/logger.ts @@ -7,7 +7,7 @@ export class Logger { constructor(args: UtilityArgs) { this.transform = args.transformer; - this.dry = args.dry; + this.dry = args.dryRun; } _log(...args: Array) { diff --git a/packages/turbo-codemod/turbo/generators/templates/transformer.hbs b/packages/turbo-codemod/turbo/generators/templates/transformer.hbs index ba16d73f1ff73..145d5c058e5fb 100644 --- a/packages/turbo-codemod/turbo/generators/templates/transformer.hbs +++ b/packages/turbo-codemod/turbo/generators/templates/transformer.hbs @@ -1,5 +1,5 @@ -import { TransformerArgs } from "../types"; -import { TransformerResults } from "../runner"; +import type { Transformer, TransformerArgs } from "../types"; +import type { TransformerResults } from "../runner"; import { getTransformerHelpers } from "../utils/getTransformerHelpers"; // transformer details @@ -7,10 +7,10 @@ const TRANSFORMER = "{{ name }}"; const DESCRIPTION = "{{ description }}"; const INTRODUCED_IN = "{{ introducedIn }}"; -export function transformer({ +export async function transformer({ root, options, -}: TransformerArgs): TransformerResults { +}: TransformerArgs): Promise { const { log, runner } = getTransformerHelpers({ transformer: TRANSFORMER, rootPath: root, @@ -33,13 +33,14 @@ export function transformer({ return runner.finish(); } -const transformerMeta = { - name: `${TRANSFORMER}: ${DESCRIPTION}`, - value: TRANSFORMER, +const transformerMeta: Transformer = { + name: TRANSFORMER, + description: DESCRIPTION, introducedIn: INTRODUCED_IN, transformer, }; +// eslint-disable-next-line import/no-default-export -- transforms require default export export default transformerMeta; diff --git a/packages/turbo-gen/LICENSE b/packages/turbo-gen/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/turbo-gen/LICENSE +++ b/packages/turbo-gen/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/turbo-gen/package.json b/packages/turbo-gen/package.json index 793fd309412a8..246c069d5af44 100644 --- a/packages/turbo-gen/package.json +++ b/packages/turbo-gen/package.json @@ -1,9 +1,9 @@ { "name": "@turbo/gen", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "Extend a Turborepo", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/turbo-ignore/package.json b/packages/turbo-ignore/package.json index 8ec6c1739aac7..0994b3a71df01 100644 --- a/packages/turbo-ignore/package.json +++ b/packages/turbo-ignore/package.json @@ -1,11 +1,11 @@ { "name": "turbo-ignore", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "", "homepage": "https://turbo.build/repo", "keywords": [], "author": "Jared Palmer", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/turbo-repository/js/package.json b/packages/turbo-repository/js/package.json index 56b14abde783b..b007457f2d5ad 100644 --- a/packages/turbo-repository/js/package.json +++ b/packages/turbo-repository/js/package.json @@ -4,7 +4,7 @@ "description": "", "bugs": "https://github.com/vercel/turbo/issues", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "main": "dist/index.js", "scripts": { "build": "mkdir -p dist && cp index.js dist/index.js && cp index.d.ts dist/index.d.ts" diff --git a/packages/turbo-repository/npm/darwin-arm64/package.json b/packages/turbo-repository/npm/darwin-arm64/package.json index cb26126be4b14..44be247eeed13 100644 --- a/packages/turbo-repository/npm/darwin-arm64/package.json +++ b/packages/turbo-repository/npm/darwin-arm64/package.json @@ -16,7 +16,7 @@ "files": [ "repository.darwin-arm64.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/npm/darwin-x64/package.json b/packages/turbo-repository/npm/darwin-x64/package.json index 799a5b61299fa..ca59b280c30d9 100644 --- a/packages/turbo-repository/npm/darwin-x64/package.json +++ b/packages/turbo-repository/npm/darwin-x64/package.json @@ -16,7 +16,7 @@ "files": [ "repository.darwin-x64.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/npm/linux-arm64-gnu/package.json b/packages/turbo-repository/npm/linux-arm64-gnu/package.json index f70ff44aea602..4297f66601433 100644 --- a/packages/turbo-repository/npm/linux-arm64-gnu/package.json +++ b/packages/turbo-repository/npm/linux-arm64-gnu/package.json @@ -19,7 +19,7 @@ "files": [ "repository.linux-arm64-gnu.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/npm/linux-arm64-musl/package.json b/packages/turbo-repository/npm/linux-arm64-musl/package.json index 995dc27dad0a5..5ae918f399522 100644 --- a/packages/turbo-repository/npm/linux-arm64-musl/package.json +++ b/packages/turbo-repository/npm/linux-arm64-musl/package.json @@ -19,7 +19,7 @@ "files": [ "repository.linux-arm64-musl.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/npm/linux-x64-gnu/package.json b/packages/turbo-repository/npm/linux-x64-gnu/package.json index de5ade6a29590..d58efdeeeddb6 100644 --- a/packages/turbo-repository/npm/linux-x64-gnu/package.json +++ b/packages/turbo-repository/npm/linux-x64-gnu/package.json @@ -19,7 +19,7 @@ "files": [ "repository.linux-x64-gnu.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/npm/linux-x64-musl/package.json b/packages/turbo-repository/npm/linux-x64-musl/package.json index 3362d681703d0..c87692d9824a2 100644 --- a/packages/turbo-repository/npm/linux-x64-musl/package.json +++ b/packages/turbo-repository/npm/linux-x64-musl/package.json @@ -19,7 +19,7 @@ "files": [ "repository.linux-x64-musl.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/npm/win32-arm64-msvc/package.json b/packages/turbo-repository/npm/win32-arm64-msvc/package.json index 175e0d82feaef..f1923df5da400 100644 --- a/packages/turbo-repository/npm/win32-arm64-msvc/package.json +++ b/packages/turbo-repository/npm/win32-arm64-msvc/package.json @@ -16,7 +16,7 @@ "files": [ "repository.win32-arm64-msvc.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/npm/win32-x64-msvc/package.json b/packages/turbo-repository/npm/win32-x64-msvc/package.json index 50047b5381331..f4f02719ff883 100644 --- a/packages/turbo-repository/npm/win32-x64-msvc/package.json +++ b/packages/turbo-repository/npm/win32-x64-msvc/package.json @@ -16,7 +16,7 @@ "files": [ "repository.win32-x64-msvc.node" ], - "license": "MPL-2.0", + "license": "MIT", "engines": { "node": ">= 10" } diff --git a/packages/turbo-repository/package.json b/packages/turbo-repository/package.json index e438a24a14ba8..a4bc426494d6b 100644 --- a/packages/turbo-repository/package.json +++ b/packages/turbo-repository/package.json @@ -12,7 +12,7 @@ }, "keywords": [], "author": "", - "license": "MPL-2.0", + "license": "MIT", "devDependencies": { "@napi-rs/cli": "^2.16.3", "execa": "^8.0.1", diff --git a/packages/turbo-repository/rust/Cargo.toml b/packages/turbo-repository/rust/Cargo.toml index d94cfc428de53..d26c16f4718d3 100644 --- a/packages/turbo-repository/rust/Cargo.toml +++ b/packages/turbo-repository/rust/Cargo.toml @@ -2,7 +2,7 @@ name = "turborepo-napi" version = "0.1.0" edition = "2021" -license = "MPL-2.0" +license = "MIT" [lib] crate-type = ["cdylib"] diff --git a/packages/turbo-telemetry/LICENSE b/packages/turbo-telemetry/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/turbo-telemetry/LICENSE +++ b/packages/turbo-telemetry/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/turbo-telemetry/package.json b/packages/turbo-telemetry/package.json index a9ab772e89f51..012fbdd9b9b0d 100644 --- a/packages/turbo-telemetry/package.json +++ b/packages/turbo-telemetry/package.json @@ -6,7 +6,7 @@ "homepage": "https://turbo.build/repo", "keywords": [], "author": "Vercel", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/turbo-test-utils/package.json b/packages/turbo-test-utils/package.json index e6badc8d6cb13..2a5289500ba1b 100644 --- a/packages/turbo-test-utils/package.json +++ b/packages/turbo-test-utils/package.json @@ -7,7 +7,7 @@ "keywords": [], "author": "Vercel", "main": "src/index.ts", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/turbo-types/package.json b/packages/turbo-types/package.json index 6a7999c7b02fc..1a50d37cc2248 100644 --- a/packages/turbo-types/package.json +++ b/packages/turbo-types/package.json @@ -1,9 +1,9 @@ { "name": "@turbo/types", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "Turborepo types", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/turbo-types/src/index.ts b/packages/turbo-types/src/index.ts index 2973ce287e887..7a16f5d0c3531 100644 --- a/packages/turbo-types/src/index.ts +++ b/packages/turbo-types/src/index.ts @@ -3,6 +3,7 @@ export type { Schema, Pipeline, RemoteCache, + OutputMode, } from "./types/config"; export type { DryRun } from "./types/dry"; diff --git a/packages/turbo-types/src/types/config.ts b/packages/turbo-types/src/types/config.ts index 6673782de3141..8f957b04c6b75 100644 --- a/packages/turbo-types/src/types/config.ts +++ b/packages/turbo-types/src/types/config.ts @@ -1,6 +1,11 @@ /* This file generates the `schema.json` file. */ export type Schema = RootSchema | WorkspaceSchema; +/* Used to support codemods that target turbo 1 */ +export type LegacySchema = LegacyRootSchema | LegacyWorkspaceSchema; + +export type SchemaV1 = RootSchemaV1 | WorkspaceSchemaV1; + export interface BaseSchema { /** @defaultValue https://turbo.build/schema.json */ $schema?: string; @@ -14,7 +19,7 @@ export interface BaseSchema { * @defaultValue `{}` */ // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style -- it's more readable to specify a name for the key - pipeline: { + tasks: { /** * The name of a task that can be executed by turbo. If turbo finds a workspace * package with a package.json scripts object with a matching key, it will apply the @@ -24,6 +29,15 @@ export interface BaseSchema { }; } +export interface BaseSchemaV1 { + // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style -- it's more readable to specify a name for the key + pipeline: { + [script: string]: Pipeline; + }; +} + +export type LegacyBaseSchema = BaseSchema | BaseSchemaV1; + export interface WorkspaceSchema extends BaseSchema { /** * This key is only available in Workspace Configs @@ -40,6 +54,10 @@ export interface WorkspaceSchema extends BaseSchema { extends: Array; } +export type LegacyWorkspaceSchema = WorkspaceSchema & LegacyBaseSchema; + +export type WorkspaceSchemaV1 = Omit & BaseSchemaV1; + export interface RootSchema extends BaseSchema { /** * A list of globs to include in the set of implicit global hash dependencies. @@ -113,15 +131,19 @@ export interface RootSchema extends BaseSchema { remoteCache?: RemoteCache; /** - * Enable use of the new UI for `turbo`. + * Enable use of the UI for `turbo`. * * Documentation: https://turbo.build/repo/docs/reference/configuration#experimentalui * - * @defaultValue `{}` + * @defaultValue `"tui"` */ - experimentalUI?: boolean; + ui?: UI; } +export type LegacyRootSchema = RootSchema & LegacyBaseSchema; + +export type RootSchemaV1 = Omit & BaseSchemaV1; + export interface Pipeline { /** * The list of tasks that this task depends on. @@ -246,7 +268,7 @@ export interface Pipeline { * * @defaultValue full */ - outputMode?: OutputMode; + outputLogs?: OutputMode; /** * Indicates whether the task exits or not. Setting `persistent` to `true` tells @@ -298,5 +320,7 @@ export type OutputMode = | "errors-only" | "none"; +export type UI = "tui" | "stream"; + export type AnchoredUnixPath = string; export type EnvWildcard = string; diff --git a/packages/turbo-utils/LICENSE b/packages/turbo-utils/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/turbo-utils/LICENSE +++ b/packages/turbo-utils/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/turbo-utils/__fixtures__/common/old-workspace-config/turbo.json b/packages/turbo-utils/__fixtures__/common/old-workspace-config/turbo.json index d44dedb04af78..2e645e4810e47 100644 --- a/packages/turbo-utils/__fixtures__/common/old-workspace-config/turbo.json +++ b/packages/turbo-utils/__fixtures__/common/old-workspace-config/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalDependencies": ["**/.env.*local"], - "pipeline": { + "tasks": { "build": { "outputs": [".next/**", "!.next/cache/**"] }, diff --git a/packages/turbo-utils/__fixtures__/common/single-package/turbo.json b/packages/turbo-utils/__fixtures__/common/single-package/turbo.json index 8079eb24634da..ef677c3a7298f 100644 --- a/packages/turbo-utils/__fixtures__/common/single-package/turbo.json +++ b/packages/turbo-utils/__fixtures__/common/single-package/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalEnv": ["UNORDERED", "CI"], - "pipeline": { + "tasks": { "build": { // A workspace's `build` task depends on that workspace's // topological dependencies' and devDependencies' diff --git a/packages/turbo-utils/__fixtures__/common/workspace-configs/apps/web/turbo.json b/packages/turbo-utils/__fixtures__/common/workspace-configs/apps/web/turbo.json index 0d1b80f43964c..f024dd2535d73 100644 --- a/packages/turbo-utils/__fixtures__/common/workspace-configs/apps/web/turbo.json +++ b/packages/turbo-utils/__fixtures__/common/workspace-configs/apps/web/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "extends": ["//"], - "pipeline": { + "tasks": { "build": { "env": ["ENV_2"] } diff --git a/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/ui/turbo.json b/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/ui/turbo.json index 8bff09ede4657..08163b5fa3653 100644 --- a/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/ui/turbo.json +++ b/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/ui/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "extends": ["//"], - "pipeline": { + "tasks": { "build": { "env": ["IS_SERVER"] } diff --git a/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/utils/turbo.json b/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/utils/turbo.json index fcb2aa74fe929..6774a20048a10 100644 --- a/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/utils/turbo.json +++ b/packages/turbo-utils/__fixtures__/common/workspace-configs/packages/utils/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", // invalid config - missing extends - "pipeline": { + "tasks": { "build": { "env": ["IS_SERVER"] } diff --git a/packages/turbo-utils/__fixtures__/common/workspace-configs/turbo.json b/packages/turbo-utils/__fixtures__/common/workspace-configs/turbo.json index cb4fb203398fa..e985aa6441260 100644 --- a/packages/turbo-utils/__fixtures__/common/workspace-configs/turbo.json +++ b/packages/turbo-utils/__fixtures__/common/workspace-configs/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalEnv": ["CI"], - "pipeline": { + "tasks": { "build": { "env": ["ENV_1"] } diff --git a/packages/turbo-utils/__tests__/getTurboConfigs.test.ts b/packages/turbo-utils/__tests__/getTurboConfigs.test.ts index c8506886c3fdf..27b0e458e6917 100644 --- a/packages/turbo-utils/__tests__/getTurboConfigs.test.ts +++ b/packages/turbo-utils/__tests__/getTurboConfigs.test.ts @@ -20,7 +20,7 @@ describe("getTurboConfigs", () => { "UNORDERED", "CI", ], - "pipeline": Object { + "tasks": Object { "build": Object { "dependsOn": Array [ "^build", @@ -66,7 +66,7 @@ describe("getTurboConfigs", () => { "globalEnv": Array [ "CI", ], - "pipeline": Object { + "tasks": Object { "build": Object { "env": Array [ "ENV_1", @@ -82,7 +82,7 @@ describe("getTurboConfigs", () => { "extends": Array [ "//", ], - "pipeline": Object { + "tasks": Object { "build": Object { "env": Array [ "ENV_2", @@ -99,7 +99,7 @@ describe("getTurboConfigs", () => { "extends": Array [ "//", ], - "pipeline": Object { + "tasks": Object { "build": Object { "env": Array [ "IS_SERVER", @@ -122,7 +122,7 @@ describe("getTurboConfigs", () => { "globalDependencies": Array [ "**/.env.*local", ], - "pipeline": Object { + "tasks": Object { "build": Object { "outputs": Array [ ".next/**", diff --git a/packages/turbo-utils/package.json b/packages/turbo-utils/package.json index 4a1789b0c4a92..b8b2994c87112 100644 --- a/packages/turbo-utils/package.json +++ b/packages/turbo-utils/package.json @@ -6,7 +6,7 @@ "homepage": "https://turbo.build/repo", "keywords": [], "author": "Vercel", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/turbo-utils/src/getTurboConfigs.ts b/packages/turbo-utils/src/getTurboConfigs.ts index 04a7e8e8b7de1..17ff5c31baa4c 100644 --- a/packages/turbo-utils/src/getTurboConfigs.ts +++ b/packages/turbo-utils/src/getTurboConfigs.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import yaml from "js-yaml"; import { sync } from "fast-glob"; -import type { Schema } from "@turbo/types"; +import type { LegacySchema, Pipeline } from "@turbo/types/src/types/config"; import JSON5 from "json5"; import * as logger from "./logger"; import { getTurboRoot } from "./getTurboRoot"; @@ -15,11 +15,11 @@ export interface WorkspaceConfig { workspaceName: string; workspacePath: string; isWorkspaceRoot: boolean; - turboConfig?: Schema; + turboConfig?: LegacySchema; } export interface TurboConfig { - config: Schema; + config: LegacySchema; turboConfigPath: string; workspacePath: string; isRootConfig: boolean; @@ -92,7 +92,7 @@ export function getTurboConfigs(cwd?: string, opts?: Options): TurboConfigs { try { const raw = fs.readFileSync(configPath, "utf8"); // eslint-disable-next-line import/no-named-as-default-member -- json5 exports different objects depending on if you're using esm or cjs (https://github.com/json5/json5/issues/240) - const turboJsonContent: Schema = JSON5.parse(raw); + const turboJsonContent: LegacySchema = JSON5.parse(raw); // basic config validation const isRootConfig = path.dirname(configPath) === turboRoot; if (isRootConfig) { @@ -163,7 +163,7 @@ export function getWorkspaceConfigs( // Try and get turbo.json const turboJsonPath = path.join(workspacePath, "turbo.json"); let rawTurboJson = null; - let turboConfig: Schema | undefined; + let turboConfig: LegacySchema | undefined; try { rawTurboJson = fs.readFileSync(turboJsonPath, "utf8"); // eslint-disable-next-line import/no-named-as-default-member -- json5 exports different objects depending on if you're using esm or cjs (https://github.com/json5/json5/issues/240) @@ -204,3 +204,14 @@ export function getWorkspaceConfigs( return configs; } + +export function forEachTaskDef( + config: LegacySchema, + f: (value: [string, Pipeline]) => void +): void { + if ("pipeline" in config) { + Object.entries(config.pipeline).forEach(f); + } else { + Object.entries(config.tasks).forEach(f); + } +} diff --git a/packages/turbo-utils/src/index.ts b/packages/turbo-utils/src/index.ts index 0908872cd35b5..118c91fb74f95 100644 --- a/packages/turbo-utils/src/index.ts +++ b/packages/turbo-utils/src/index.ts @@ -1,6 +1,10 @@ // utils export { getTurboRoot } from "./getTurboRoot"; -export { getTurboConfigs, getWorkspaceConfigs } from "./getTurboConfigs"; +export { + getTurboConfigs, + getWorkspaceConfigs, + forEachTaskDef, +} from "./getTurboConfigs"; export { searchUp } from "./searchUp"; export { getAvailablePackageManagers, diff --git a/packages/turbo-vsc/LICENSE b/packages/turbo-vsc/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/turbo-vsc/LICENSE +++ b/packages/turbo-vsc/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/turbo-vsc/package.json b/packages/turbo-vsc/package.json index fccc82e5982a5..b46d10ae9e67f 100644 --- a/packages/turbo-vsc/package.json +++ b/packages/turbo-vsc/package.json @@ -40,7 +40,7 @@ "directory": "packages/turbo-vsc" }, "author": "Vercel", - "license": "MPL-2.0", + "license": "MIT", "dependencies": { "jsonc-parser": "^3.2.0", "vscode-languageclient": "^9.0.1" diff --git a/packages/turbo-workspaces/LICENSE b/packages/turbo-workspaces/LICENSE index fa0086a952236..5c3db8bb6f857 100644 --- a/packages/turbo-workspaces/LICENSE +++ b/packages/turbo-workspaces/LICENSE @@ -1,373 +1,7 @@ -Mozilla Public License Version 2.0 -================================== +Copyright (c) 2024 Vercel, Inc -1. Definitions --------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/turbo-workspaces/package.json b/packages/turbo-workspaces/package.json index 071367c6c2b74..be31f73a3887d 100644 --- a/packages/turbo-workspaces/package.json +++ b/packages/turbo-workspaces/package.json @@ -1,9 +1,9 @@ { "name": "@turbo/workspaces", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "Tools for working with package managers", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "repository": { "type": "git", "url": "https://github.com/vercel/turbo", diff --git a/packages/turbo/package.json b/packages/turbo/package.json index 35c462b4bafcb..9aad3b770e1cf 100644 --- a/packages/turbo/package.json +++ b/packages/turbo/package.json @@ -1,11 +1,11 @@ { "name": "turbo", - "version": "1.13.4", + "version": "2.0.0-canary.4", "description": "Turborepo is a high-performance build system for JavaScript and TypeScript codebases.", "repository": "https://github.com/vercel/turbo", "bugs": "https://github.com/vercel/turbo/issues", "homepage": "https://turbo.build/repo", - "license": "MPL-2.0", + "license": "MIT", "main": "./bin/turbo", "scripts": { "postversion": "node bump-version.js" @@ -17,11 +17,11 @@ "bin" ], "optionalDependencies": { - "turbo-darwin-64": "1.13.4", - "turbo-darwin-arm64": "1.13.4", - "turbo-linux-64": "1.13.4", - "turbo-linux-arm64": "1.13.4", - "turbo-windows-64": "1.13.4", - "turbo-windows-arm64": "1.13.4" + "turbo-darwin-64": "2.0.0-canary.4", + "turbo-darwin-arm64": "2.0.0-canary.4", + "turbo-linux-64": "2.0.0-canary.4", + "turbo-linux-arm64": "2.0.0-canary.4", + "turbo-windows-64": "2.0.0-canary.4", + "turbo-windows-arm64": "2.0.0-canary.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf41a7cf31b20..92b88d150c635 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,6 +461,9 @@ importers: is-git-clean: specifier: ^1.1.0 version: 1.1.0 + json5: + specifier: ^2.2.3 + version: 2.2.3 ora: specifier: 4.1.1 version: 4.1.1 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/fixtures/basic_monorepo/turbo.json b/turborepo-tests/integration/fixtures/basic_monorepo/turbo.json index cfee1ac9613ab..d3f04c97c336e 100644 --- a/turborepo-tests/integration/fixtures/basic_monorepo/turbo.json +++ b/turborepo-tests/integration/fixtures/basic_monorepo/turbo.json @@ -2,15 +2,15 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] }, // this comment verifies that turbo can read .json files with comments "my-app#build": { - "outputs": ["banana.txt", "apple.json"], - "dotEnv": [".env.local"] + "inputs": ["$TURBO_DEFAULT$", ".env.local"], + "outputs": ["banana.txt", "apple.json"] }, "something": {}, diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/add-keys/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/add-keys/turbo.json index 91bbd1a6ebd4b..2e8e6af12db13 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/add-keys/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/add-keys/turbo.json @@ -1,13 +1,20 @@ { "extends": ["//"], - - "pipeline": { + "tasks": { "add-keys-task": { - "dependsOn": ["add-keys-underlying-task"], - "inputs": ["src/foo.txt"], - "outputs": ["out/**"], - "env": ["SOME_VAR"], - "outputMode": "new-only" + "dependsOn": [ + "add-keys-underlying-task" + ], + "inputs": [ + "src/foo.txt" + ], + "outputs": [ + "out/**" + ], + "env": [ + "SOME_VAR" + ], + "outputLogs": "new-only" }, "add-keys-underlying-task": {} } diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/add-tasks/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/add-tasks/turbo.json index 6be0e0aadeac8..653a3f17bd740 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/add-tasks/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/add-tasks/turbo.json @@ -1,7 +1,7 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "added-task": { "outputs": ["out/**"] } diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/cached/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/cached/turbo.json index 89633c6bb9bd6..a5852aab9901b 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/cached/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/cached/turbo.json @@ -1,6 +1,6 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "cached-task-1": { "cache": true }, diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo-changed.json b/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo-changed.json index 59794bd4698db..8afcea50a9090 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo-changed.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo-changed.json @@ -1,6 +1,6 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "config-change-task": {}, "other-task": { "env": ["ARBITRARY_CHANGE"] diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo.json index cedcef6a2d303..1bc6503605dea 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/config-change/turbo.json @@ -1,6 +1,6 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "config-change-task": {}, "other-task": {} } diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/cross-workspace/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/cross-workspace/turbo.json index da8bb470e9074..99d39eb16c931 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/cross-workspace/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/cross-workspace/turbo.json @@ -1,6 +1,6 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "cross-workspace-task": { "dependsOn": ["blank-pkg#cross-workspace-underlying-task"] } diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/invalid-config/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/invalid-config/turbo.json index 375a220129953..4cca66d5760ef 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/invalid-config/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/invalid-config/turbo.json @@ -1,5 +1,5 @@ { - "pipeline": { + "tasks": { "invalid-config#build": { "outputs": ["out/**", "lib/**"] }, diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/omit-keys/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/omit-keys/turbo.json index 35ddebb5803f9..91e0bb163452c 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/omit-keys/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/omit-keys/turbo.json @@ -1,7 +1,7 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "omit-keys-task": {}, "omit-keys-task-with-deps": {} } diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/override-values/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/override-values/turbo.json index a508471fdd876..f9ec258ee8e9c 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/override-values/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/override-values/turbo.json @@ -1,12 +1,17 @@ { "extends": ["//"], - - "pipeline": { + "tasks": { "override-values-task": { - "inputs": ["src/bar.txt"], - "outputs": ["lib/**"], - "env": ["OTHER_VAR"], - "outputMode": "full" + "inputs": [ + "src/bar.txt" + ], + "outputs": [ + "lib/**" + ], + "env": [ + "OTHER_VAR" + ], + "outputLogs": "full" }, "override-values-task-with-deps": { "dependsOn": [] diff --git a/turborepo-tests/integration/fixtures/composable_config/apps/persistent/turbo.json b/turborepo-tests/integration/fixtures/composable_config/apps/persistent/turbo.json index e1f98a5b4f1af..06bbde343f979 100644 --- a/turborepo-tests/integration/fixtures/composable_config/apps/persistent/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/apps/persistent/turbo.json @@ -1,6 +1,6 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "persistent-task-2": { "persistent": false }, diff --git a/turborepo-tests/integration/fixtures/composable_config/packages/blank-pkg/turbo.json b/turborepo-tests/integration/fixtures/composable_config/packages/blank-pkg/turbo.json index 7b7cadf305971..dfcfa5f61728b 100644 --- a/turborepo-tests/integration/fixtures/composable_config/packages/blank-pkg/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/packages/blank-pkg/turbo.json @@ -1,6 +1,6 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "cross-workspace-underlying-task": {} } } diff --git a/turborepo-tests/integration/fixtures/composable_config/turbo.json b/turborepo-tests/integration/fixtures/composable_config/turbo.json index 3e1cdadc2f4e7..fc76820c940a9 100644 --- a/turborepo-tests/integration/fixtures/composable_config/turbo.json +++ b/turborepo-tests/integration/fixtures/composable_config/turbo.json @@ -1,48 +1,65 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "add-keys-task": {}, "add-keys-underlying-task": {}, - "omit-keys-task-with-deps": { "dependsOn": [ "omit-keys-underlying-task", "^omit-keys-underlying-topo-task" ], - "outputs": ["out/**"] + "outputs": [ + "out/**" + ] }, "omit-keys-underlying-task": {}, "omit-keys-underlying-topo-task": {}, - "omit-keys-task": { - "inputs": ["src/foo.txt"], - "outputs": ["out/**"], - "env": ["SOME_VAR"], - "outputMode": "new-only" + "inputs": [ + "src/foo.txt" + ], + "outputs": [ + "out/**" + ], + "env": [ + "SOME_VAR" + ], + "outputLogs": "new-only" }, - "missing-workspace-config-task-with-deps": { "dependsOn": [ "missing-workspace-config-underlying-task", "^missing-workspace-config-underlying-topo-task" ], - "outputs": ["out/**"] + "outputs": [ + "out/**" + ] }, "missing-workspace-config-underlying-task": {}, "missing-workspace-config-underlying-topo-task": {}, - "missing-workspace-config-task": { - "inputs": ["src/foo.txt"], - "outputs": ["out/**"], - "env": ["SOME_VAR"], - "outputMode": "new-only" + "inputs": [ + "src/foo.txt" + ], + "outputs": [ + "out/**" + ], + "env": [ + "SOME_VAR" + ], + "outputLogs": "new-only" }, - "override-values-task": { - "inputs": ["src/foo.txt"], - "outputs": ["out/**"], - "env": ["SOME_VAR"], - "outputMode": "new-only" + "inputs": [ + "src/foo.txt" + ], + "outputs": [ + "out/**" + ], + "env": [ + "SOME_VAR" + ], + "outputLogs": "new-only" }, "override-values-task-with-deps": { "dependsOn": [ @@ -51,11 +68,12 @@ ] }, "override-values-task-with-deps-2": { - "dependsOn": ["^override-values-underlying-topo-task"] + "dependsOn": [ + "^override-values-underlying-topo-task" + ] }, "override-values-underlying-task": {}, "override-values-underlying-topo-task": {}, - "persistent-task-1": { "persistent": true }, @@ -67,36 +85,52 @@ }, "persistent-task-4": {}, "persistent-task-1-parent": { - "dependsOn": ["persistent-task-1"] + "dependsOn": [ + "persistent-task-1" + ] }, "persistent-task-2-parent": { - "dependsOn": ["persistent-task-2"] + "dependsOn": [ + "persistent-task-2" + ] }, "persistent-task-3-parent": { - "dependsOn": ["persistent-task-3"] + "dependsOn": [ + "persistent-task-3" + ] }, "persistent-task-4-parent": { - "dependsOn": ["persistent-task-4"] + "dependsOn": [ + "persistent-task-4" + ] }, - "cached-task-1": { "cache": false, - "outputs": ["out/**"] + "outputs": [ + "out/**" + ] }, "cached-task-2": { "cache": true, - "outputs": ["out/**"] + "outputs": [ + "out/**" + ] }, "cached-task-3": { - "outputs": ["out/**"] + "outputs": [ + "out/**" + ] }, "cached-task-4": { "cache": false, - "outputs": ["out/**"] + "outputs": [ + "out/**" + ] }, - "config-change-task": { - "inputs": ["src/foo.txt"] + "inputs": [ + "src/foo.txt" + ] } } } diff --git a/turborepo-tests/integration/fixtures/dir_globs/.gitignore b/turborepo-tests/integration/fixtures/dir_globs/.gitignore new file mode 100644 index 0000000000000..77af9fc60321d --- /dev/null +++ b/turborepo-tests/integration/fixtures/dir_globs/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.turbo +.npmrc diff --git a/turborepo-tests/integration/fixtures/dir_globs/apps/my-app/package.json b/turborepo-tests/integration/fixtures/dir_globs/apps/my-app/package.json new file mode 100644 index 0000000000000..1746e0db23610 --- /dev/null +++ b/turborepo-tests/integration/fixtures/dir_globs/apps/my-app/package.json @@ -0,0 +1,10 @@ +{ + "name": "my-app", + "scripts": { + "build": "echo building", + "maybefails": "exit 4" + }, + "dependencies": { + "util": "*" + } +} diff --git a/turborepo-tests/integration/fixtures/dir_globs/package.json b/turborepo-tests/integration/fixtures/dir_globs/package.json new file mode 100644 index 0000000000000..b3601d4b13a2c --- /dev/null +++ b/turborepo-tests/integration/fixtures/dir_globs/package.json @@ -0,0 +1,10 @@ +{ + "name": "monorepo", + "scripts": { + "something": "turbo run build" + }, + "workspaces": [ + "apps/**", + "packages/**" + ] +} diff --git a/turborepo-tests/integration/fixtures/dir_globs/packages/util/package.json b/turborepo-tests/integration/fixtures/dir_globs/packages/util/package.json new file mode 100644 index 0000000000000..e8a7130a1662d --- /dev/null +++ b/turborepo-tests/integration/fixtures/dir_globs/packages/util/package.json @@ -0,0 +1,6 @@ +{ + "name": "util", + "scripts": { + "build": "echo building; mkdir dist; echo 'world' > dist/hello.txt " + } +} diff --git a/turborepo-tests/integration/fixtures/dir_globs/packages/util/src/boo.txt b/turborepo-tests/integration/fixtures/dir_globs/packages/util/src/boo.txt new file mode 100644 index 0000000000000..5626abf0f72e5 --- /dev/null +++ b/turborepo-tests/integration/fixtures/dir_globs/packages/util/src/boo.txt @@ -0,0 +1 @@ +one diff --git a/turborepo-tests/integration/fixtures/dir_globs/turbo.json b/turborepo-tests/integration/fixtures/dir_globs/turbo.json new file mode 100644 index 0000000000000..bdea068bec038 --- /dev/null +++ b/turborepo-tests/integration/fixtures/dir_globs/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "inputs": ["src/"], + "outputs": ["dist"] + } + } +} diff --git a/turborepo-tests/integration/fixtures/framework_inference/turbo.json b/turborepo-tests/integration/fixtures/framework_inference/turbo.json index b7f071fb387ec..0dcebba049467 100644 --- a/turborepo-tests/integration/fixtures/framework_inference/turbo.json +++ b/turborepo-tests/integration/fixtures/framework_inference/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalPassThroughEnv": [], - "pipeline": { + "tasks": { "build": {} } } diff --git a/turborepo-tests/integration/fixtures/global_deps/README.md b/turborepo-tests/integration/fixtures/global_deps/README.md new file mode 100644 index 0000000000000..8b07e5a1b1e03 --- /dev/null +++ b/turborepo-tests/integration/fixtures/global_deps/README.md @@ -0,0 +1,3 @@ +# My Monorepo + +Hello! diff --git a/turborepo-tests/integration/fixtures/global_deps/turbo.json b/turborepo-tests/integration/fixtures/global_deps/turbo.json index 390c719bdf582..b809448be70bf 100644 --- a/turborepo-tests/integration/fixtures/global_deps/turbo.json +++ b/turborepo-tests/integration/fixtures/global_deps/turbo.json @@ -1,8 +1,8 @@ { "$schema": "https://turbo.build/schema.json", - "globalDependencies": ["global_deps/**"], + "globalDependencies": ["global_deps/**", "!global_deps/**/*.md"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] @@ -10,7 +10,7 @@ // this comment verifies that turbo can read .json files with comments "my-app#build": { "outputs": ["banana.txt", "apple.json"], - "dotEnv": [".env.local"] + "inputs": ["$TURBO_DEFAULT$", ".env.local"] }, "something": {}, diff --git a/turborepo-tests/integration/fixtures/inference/has_workspaces/packages/ui-library/turbo.json b/turborepo-tests/integration/fixtures/inference/has_workspaces/packages/ui-library/turbo.json index 924a1fc613ae9..dea276bc6bd3d 100644 --- a/turborepo-tests/integration/fixtures/inference/has_workspaces/packages/ui-library/turbo.json +++ b/turborepo-tests/integration/fixtures/inference/has_workspaces/packages/ui-library/turbo.json @@ -1,5 +1,5 @@ { "$schema": "https://turbo.build/schema.json", "extends": ["//"], - "pipeline": {} + "tasks": {} } diff --git a/turborepo-tests/integration/fixtures/inference/has_workspaces/turbo.json b/turborepo-tests/integration/fixtures/inference/has_workspaces/turbo.json index 2fc9d06fe4d5a..9d4fcdc74f3b4 100644 --- a/turborepo-tests/integration/fixtures/inference/has_workspaces/turbo.json +++ b/turborepo-tests/integration/fixtures/inference/has_workspaces/turbo.json @@ -1,7 +1,7 @@ // Has a comment! { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": {} } } diff --git a/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer-no-turbo/inner/turbo.json b/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer-no-turbo/inner/turbo.json index d4487028869da..a383ddeb487c9 100644 --- a/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer-no-turbo/inner/turbo.json +++ b/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer-no-turbo/inner/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": {} } } diff --git a/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/inner/turbo.json b/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/inner/turbo.json index d4487028869da..a383ddeb487c9 100644 --- a/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/inner/turbo.json +++ b/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/inner/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": {} } } diff --git a/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/turbo.json b/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/turbo.json index d4487028869da..a383ddeb487c9 100644 --- a/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/turbo.json +++ b/turborepo-tests/integration/fixtures/inference/nested_workspaces/outer/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": {} } } diff --git a/turborepo-tests/integration/fixtures/lockfile_aware_caching/turbo.json b/turborepo-tests/integration/fixtures/lockfile_aware_caching/turbo.json index 383437544e6e7..66ceb3ce7ac14 100644 --- a/turborepo-tests/integration/fixtures/lockfile_aware_caching/turbo.json +++ b/turborepo-tests/integration/fixtures/lockfile_aware_caching/turbo.json @@ -1,9 +1,14 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": [], - "inputs": ["package.json"] + "env": [ + "COREPACK_ENABLE_DOWNLOAD_PROMPT" + ], + "inputs": [ + "package.json" + ] } } } diff --git a/turborepo-tests/integration/fixtures/monorepo_dependency_error/turbo.json b/turborepo-tests/integration/fixtures/monorepo_dependency_error/turbo.json index 30922a61b1baf..89b91e89da259 100644 --- a/turborepo-tests/integration/fixtures/monorepo_dependency_error/turbo.json +++ b/turborepo-tests/integration/fixtures/monorepo_dependency_error/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"], "outputs": [] diff --git a/turborepo-tests/integration/fixtures/monorepo_one_script_error/turbo.json b/turborepo-tests/integration/fixtures/monorepo_one_script_error/turbo.json index 54b3b12ee34be..acf03c909f7af 100644 --- a/turborepo-tests/integration/fixtures/monorepo_one_script_error/turbo.json +++ b/turborepo-tests/integration/fixtures/monorepo_one_script_error/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "error": { "dependsOn": ["okay"], "outputs": ["foo"] diff --git a/turborepo-tests/integration/fixtures/monorepo_with_root_dep/apps/docs/turbo.json b/turborepo-tests/integration/fixtures/monorepo_with_root_dep/apps/docs/turbo.json index 93e9625690ab3..57e9a40018036 100644 --- a/turborepo-tests/integration/fixtures/monorepo_with_root_dep/apps/docs/turbo.json +++ b/turborepo-tests/integration/fixtures/monorepo_with_root_dep/apps/docs/turbo.json @@ -1,6 +1,6 @@ { "extends": ["//"], - "pipeline": { + "tasks": { "new-task": {} } } diff --git a/turborepo-tests/integration/fixtures/monorepo_with_root_dep/turbo.json b/turborepo-tests/integration/fixtures/monorepo_with_root_dep/turbo.json index c42bb9ff19e47..b8ef3df99416b 100644 --- a/turborepo-tests/integration/fixtures/monorepo_with_root_dep/turbo.json +++ b/turborepo-tests/integration/fixtures/monorepo_with_root_dep/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": [] }, diff --git a/turborepo-tests/integration/fixtures/nested_packages/turbo.json b/turborepo-tests/integration/fixtures/nested_packages/turbo.json index 0d547fb58901a..aa0b0be65ca8a 100644 --- a/turborepo-tests/integration/fixtures/nested_packages/turbo.json +++ b/turborepo-tests/integration/fixtures/nested_packages/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": [] } diff --git a/turborepo-tests/integration/fixtures/ordered/turbo.json b/turborepo-tests/integration/fixtures/ordered/turbo.json index 3fedbd641120c..8acc697061308 100644 --- a/turborepo-tests/integration/fixtures/ordered/turbo.json +++ b/turborepo-tests/integration/fixtures/ordered/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": {}, "fail": {} } diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/1-topological/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/1-topological/turbo.json index c1a03e77ab652..4171bea063e7e 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/1-topological/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/1-topological/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "dev": { "dependsOn": ["^dev"], "persistent": true diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/10-too-many/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/10-too-many/turbo.json index fb2077e4f4ecd..3b92d9b2c6dc0 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/10-too-many/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/10-too-many/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "persistent": true } diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/2-same-workspace/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/2-same-workspace/turbo.json index a9c86b1b85eb8..77e6483fa4c7e 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/2-same-workspace/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/2-same-workspace/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "dependsOn": ["dev"] }, diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/3-workspace-specific/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/3-workspace-specific/turbo.json index 7d6afe90f180b..5e2c63f85bccf 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/3-workspace-specific/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/3-workspace-specific/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "dependsOn": ["pkg-a#dev"] }, diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/4-cross-workspace/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/4-cross-workspace/turbo.json index c72700ecbb850..482595dc0410c 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/4-cross-workspace/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/4-cross-workspace/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "app-a#dev": { "dependsOn": ["pkg-a#dev"], "persistent": true diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/5-root-workspace/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/5-root-workspace/turbo.json index c5eee83836181..b3880a210565c 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/5-root-workspace/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/5-root-workspace/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "dependsOn": ["//#dev"], "persistent": true diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/6-topological-unimplemented/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/6-topological-unimplemented/turbo.json index c1a03e77ab652..4171bea063e7e 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/6-topological-unimplemented/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/6-topological-unimplemented/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "dev": { "dependsOn": ["^dev"], "persistent": true diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/7-topological-nested/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/7-topological-nested/turbo.json index c1a03e77ab652..4171bea063e7e 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/7-topological-nested/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/7-topological-nested/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "dev": { "dependsOn": ["^dev"], "persistent": true diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/8-topological-with-extra/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/8-topological-with-extra/turbo.json index e04097b2c4c8a..e779360980573 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/8-topological-with-extra/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/8-topological-with-extra/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"] }, diff --git a/turborepo-tests/integration/fixtures/persistent_dependencies/9-cross-workspace-nested/turbo.json b/turborepo-tests/integration/fixtures/persistent_dependencies/9-cross-workspace-nested/turbo.json index 350c7db5ef75a..76e6d670a134d 100644 --- a/turborepo-tests/integration/fixtures/persistent_dependencies/9-cross-workspace-nested/turbo.json +++ b/turborepo-tests/integration/fixtures/persistent_dependencies/9-cross-workspace-nested/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "app-a#build": { "dependsOn": ["app-b#build"] }, diff --git a/turborepo-tests/integration/fixtures/root_deps/.gitignore b/turborepo-tests/integration/fixtures/root_deps/.gitignore new file mode 100644 index 0000000000000..088f9174d69f8 --- /dev/null +++ b/turborepo-tests/integration/fixtures/root_deps/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +.turbo +.npmrc +dist diff --git a/turborepo-tests/integration/fixtures/root_deps/apps/my-app/package.json b/turborepo-tests/integration/fixtures/root_deps/apps/my-app/package.json new file mode 100644 index 0000000000000..162bcddf217ef --- /dev/null +++ b/turborepo-tests/integration/fixtures/root_deps/apps/my-app/package.json @@ -0,0 +1,9 @@ +{ + "name": "my-app", + "scripts": { + "build": "echo building" + }, + "dependencies": { + "util": "*" + } +} diff --git a/turborepo-tests/integration/fixtures/root_deps/package.json b/turborepo-tests/integration/fixtures/root_deps/package.json new file mode 100644 index 0000000000000..295acadb1c52d --- /dev/null +++ b/turborepo-tests/integration/fixtures/root_deps/package.json @@ -0,0 +1,11 @@ +{ + "name": "monorepo", + "workspaces": [ + "apps/**", + "packages/**" + ], + "dependencies": { + "util": "*", + "yet-another": "*" + } +} diff --git a/turborepo-tests/integration/fixtures/root_deps/packages/another/package.json b/turborepo-tests/integration/fixtures/root_deps/packages/another/package.json new file mode 100644 index 0000000000000..b45b1b072f8bd --- /dev/null +++ b/turborepo-tests/integration/fixtures/root_deps/packages/another/package.json @@ -0,0 +1,6 @@ +{ + "name": "another", + "scripts": { + "build": "echo building" + } +} diff --git a/turborepo-tests/integration/fixtures/root_deps/packages/util/package.json b/turborepo-tests/integration/fixtures/root_deps/packages/util/package.json new file mode 100644 index 0000000000000..7309726a1df4e --- /dev/null +++ b/turborepo-tests/integration/fixtures/root_deps/packages/util/package.json @@ -0,0 +1,6 @@ +{ + "name": "util", + "scripts": { + "build": "echo building" + } +} diff --git a/turborepo-tests/integration/fixtures/root_deps/packages/yet-another/package.json b/turborepo-tests/integration/fixtures/root_deps/packages/yet-another/package.json new file mode 100644 index 0000000000000..0b0701721cdb8 --- /dev/null +++ b/turborepo-tests/integration/fixtures/root_deps/packages/yet-another/package.json @@ -0,0 +1,6 @@ +{ + "name": "yet-another", + "scripts": { + "build": "echo building" + } +} diff --git a/turborepo-tests/integration/fixtures/root_deps/turbo.json b/turborepo-tests/integration/fixtures/root_deps/turbo.json new file mode 100644 index 0000000000000..a8d8d805e85f0 --- /dev/null +++ b/turborepo-tests/integration/fixtures/root_deps/turbo.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": ["foo.txt"], + "globalEnv": ["SOME_ENV_VAR"], + "tasks": { + "build": { + "env": ["NODE_ENV"], + "dependsOn": ["^build"], + "outputs": ["dist/**"] + } + } +} diff --git a/turborepo-tests/integration/fixtures/run_logging/turbo.json b/turborepo-tests/integration/fixtures/run_logging/turbo.json index 06b2f211acc62..15ae3fba0a36d 100644 --- a/turborepo-tests/integration/fixtures/run_logging/turbo.json +++ b/turborepo-tests/integration/fixtures/run_logging/turbo.json @@ -1,13 +1,12 @@ { - "pipeline": { + "tasks": { "build": {}, - "builderror": {}, "builderror2": { - "outputMode": "errors-only" + "outputLogs": "errors-only" }, "buildsuccess": { - "outputMode": "errors-only" + "outputLogs": "errors-only" } } } diff --git a/turborepo-tests/integration/fixtures/single_package/turbo.json b/turborepo-tests/integration/fixtures/single_package/turbo.json index bf9ddbce36808..ce5bdbed55601 100644 --- a/turborepo-tests/integration/fixtures/single_package/turbo.json +++ b/turborepo-tests/integration/fixtures/single_package/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalDependencies": ["somefile.txt"], - "pipeline": { + "tasks": { "build": { "outputs": ["foo.txt"] }, diff --git a/turborepo-tests/integration/fixtures/strict_env_vars/turbo.json b/turborepo-tests/integration/fixtures/strict_env_vars/turbo.json index fb6a143e3f51d..b61b61ca90940 100644 --- a/turborepo-tests/integration/fixtures/strict_env_vars/turbo.json +++ b/turborepo-tests/integration/fixtures/strict_env_vars/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["dist/**"] } diff --git a/turborepo-tests/integration/fixtures/task_dependencies/complex/turbo.json b/turborepo-tests/integration/fixtures/task_dependencies/complex/turbo.json index 998a9d6c6fd46..9c7ae2be4125e 100644 --- a/turborepo-tests/integration/fixtures/task_dependencies/complex/turbo.json +++ b/turborepo-tests/integration/fixtures/task_dependencies/complex/turbo.json @@ -1,5 +1,5 @@ { - "pipeline": { + "tasks": { "build0": { "dependsOn": ["^build0", "prepare"] }, diff --git a/turborepo-tests/integration/fixtures/task_dependencies/overwriting/turbo.json b/turborepo-tests/integration/fixtures/task_dependencies/overwriting/turbo.json index d16b6d0cb2a57..c5241441bea82 100644 --- a/turborepo-tests/integration/fixtures/task_dependencies/overwriting/turbo.json +++ b/turborepo-tests/integration/fixtures/task_dependencies/overwriting/turbo.json @@ -1,5 +1,5 @@ { - "pipeline": { + "tasks": { "build": { "dependsOn": ["generate"] }, diff --git a/turborepo-tests/integration/fixtures/task_dependencies/root-to-workspace/turbo.json b/turborepo-tests/integration/fixtures/task_dependencies/root-to-workspace/turbo.json index 3b0f3d5582dfc..e2d0fdd451f0b 100644 --- a/turborepo-tests/integration/fixtures/task_dependencies/root-to-workspace/turbo.json +++ b/turborepo-tests/integration/fixtures/task_dependencies/root-to-workspace/turbo.json @@ -1,9 +1,7 @@ { - "pipeline": { + "tasks": { "//#mytask": { - "dependsOn": [ - "lib-a#build" - ] + "dependsOn": ["lib-a#build"] }, "build": {} } diff --git a/turborepo-tests/integration/fixtures/task_dependencies/topological/turbo.json b/turborepo-tests/integration/fixtures/task_dependencies/topological/turbo.json index 35f359404228c..ad728338d3903 100644 --- a/turborepo-tests/integration/fixtures/task_dependencies/topological/turbo.json +++ b/turborepo-tests/integration/fixtures/task_dependencies/topological/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "dependsOn": ["^build"] }, diff --git a/turborepo-tests/integration/fixtures/task_dependencies/workspace-tasks/turbo.json b/turborepo-tests/integration/fixtures/task_dependencies/workspace-tasks/turbo.json index fe53b0720a930..bf3683219f757 100644 --- a/turborepo-tests/integration/fixtures/task_dependencies/workspace-tasks/turbo.json +++ b/turborepo-tests/integration/fixtures/task_dependencies/workspace-tasks/turbo.json @@ -1,5 +1,5 @@ { - "pipeline": { + "tasks": { "build1": {}, "//#build1": {}, diff --git a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs-win.json b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs-win.json index 90ee505b29818..de6732b2eb11d 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs-win.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs-win.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "inputs": ["C:\\another\\absolute\\path", "a\\relative\\path"] } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs.json b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs.json index 4030d358ccade..b4d0dd0f954c5 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-inputs.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "inputs": ["/another/absolute/path", "a/relative/path"] } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs-win.json b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs-win.json index dfc11bdf16efd..ced621aaf819b 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs-win.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs-win.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["C:\\another\\absolute\\path", "a\\relative\\path"] } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs.json b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs.json index 8549776d8bccb..ce38d4e55ca31 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/abs-path-outputs.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["/another/absolute/path", "a/relative/path"] } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/gitignored-inputs.json b/turborepo-tests/integration/fixtures/turbo-configs/gitignored-inputs.json index 03679e958de7a..8a66d16710ca6 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/gitignored-inputs.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/gitignored-inputs.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "inputs": ["internal.txt"] } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/interactive.json b/turborepo-tests/integration/fixtures/turbo-configs/interactive.json index 56baec07fe610..043c0250487a0 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/interactive.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/interactive.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "interactive": true } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/invalid-env-var.json b/turborepo-tests/integration/fixtures/turbo-configs/invalid-env-var.json index a97adf5692d34..c0b162e1cc3f6 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/invalid-env-var.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/invalid-env-var.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV", "$FOOBAR"], "outputs": [] @@ -10,7 +10,7 @@ // this comment verifies that turbo can read .json files with comments "my-app#build": { "outputs": ["banana.txt", "apple.json"], - "dotEnv": [".env.local"] + "inputs": ["$TURBO_DEFAULT$", ".env.local"] }, "something": {}, diff --git a/turborepo-tests/integration/fixtures/turbo-configs/package-task.json b/turborepo-tests/integration/fixtures/turbo-configs/package-task.json index 5ef775e5892ae..9cf24afafc7f8 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/package-task.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/package-task.json @@ -3,11 +3,11 @@ "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], "extends": ["//"], - "pipeline": { + "tasks": { // this comment verifies that turbo can read .json files with comments "my-app#build": { "outputs": ["banana.txt", "apple.json"], - "dotEnv": [".env.local"] + "inputs": ["$TURBO_DEFAULT$", ".env.local"] } } } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/parse-error.json b/turborepo-tests/integration/fixtures/turbo-configs/parse-error.json index 15d3d9546a80d..a97106a035b86 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/parse-error.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/parse-error.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"],, "outputs": [] @@ -10,7 +10,7 @@ // this comment verifies that turbo can read .json files with comments "my-app#build": { "outputs": ["banana.txt", "apple.json"]5, - "dotEnv": [".env.local"] + "inputs": ["$TURBO_DEFAULT$", ".env.local"] }, "something": {}, diff --git a/turborepo-tests/integration/fixtures/turbo-configs/spaces-failure.json b/turborepo-tests/integration/fixtures/turbo-configs/spaces-failure.json index bef35a6246b31..1588568ce6e2e 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/spaces-failure.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/spaces-failure.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] @@ -10,7 +10,7 @@ // this comment verifies that turbo can read .json files with comments "my-app#build": { "outputs": ["banana.txt", "apple.json"], - "dotEnv": [".env.local"] + "inputs": ["$TURBO_DEFAULT$", ".env.local"] }, "something": {}, diff --git a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/all.json b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/all.json index 1432fa2ad354e..c854bbf60f54f 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/all.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/all.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["dist/**"], "passThroughEnv": ["LOCAL_VAR_PT"], diff --git a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt-empty.json b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt-empty.json index 16e1ab9636a95..0d9986ea82da7 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt-empty.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt-empty.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["dist/**"] } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt.json b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt.json index ae7f1281aaa29..420a12f632dfd 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/global_pt.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["dist/**"] } diff --git a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt-empty.json b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt-empty.json index 0bdf3e397595c..9fcd9ce443750 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt-empty.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt-empty.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["dist/**"], "passThroughEnv": [] diff --git a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt.json b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt.json index 905b853753b61..600c1381b217f 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/strict_env_vars/task_pt.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": ["dist/**"], "passThroughEnv": ["LOCAL_VAR_PT"] diff --git a/turborepo-tests/integration/fixtures/turbo-configs/syntax-error.json b/turborepo-tests/integration/fixtures/turbo-configs/syntax-error.json index 43dc12146e5fd..878d1e2e7cff6 100644 --- a/turborepo-tests/integration/fixtures/turbo-configs/syntax-error.json +++ b/turborepo-tests/integration/fixtures/turbo-configs/syntax-error.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json",, "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV", "$FOOBAR"], "outputs": [] @@ -10,7 +10,7 @@ // this comment verifies that turbo can read .json files with comments "my-app#build": { "outputs": ["banana.txt", "apple.json"]42, - "dotEnv": [".env.local" + "inputs": [".env.local" }, "something": {}, diff --git a/turborepo-tests/integration/fixtures/with-pkg-deps/turbo.json b/turborepo-tests/integration/fixtures/with-pkg-deps/turbo.json index 4216c8201cbcd..07252a496d131 100644 --- a/turborepo-tests/integration/fixtures/with-pkg-deps/turbo.json +++ b/turborepo-tests/integration/fixtures/with-pkg-deps/turbo.json @@ -1,10 +1,8 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { - "dependsOn": [ - "^build" - ] + "dependsOn": ["^build"] } } } diff --git a/turborepo-tests/integration/tests/bad-flag.t b/turborepo-tests/integration/tests/bad-flag.t index 8588d75503c65..0fb9de1a3dcf8 100644 --- a/turborepo-tests/integration/tests/bad-flag.t +++ b/turborepo-tests/integration/tests/bad-flag.t @@ -19,7 +19,7 @@ Bad flag with an implied run command should display run flags tip: to pass '--bad-flag' as a value, use '-- --bad-flag' - Usage: turbo(\.exe)? <--cache-dir |--cache-workers |--concurrency |--continue|--dry-run []|--single-package|--filter |--force []|--framework-inference []|--global-deps |--graph []|--env-mode []|--ignore |--include-dependencies|--no-cache|--no-daemon|--no-deps|--output-logs |--log-order |--only|--parallel|--pkg-inference-root |--profile |--remote-only []|--scope |--since |--summarize []|--log-prefix |TASKS|PASS_THROUGH_ARGS|--experimental-space-id > (re) + Usage: turbo(\.exe)? <--cache-dir |--cache-workers |--concurrency |--continue|--dry-run []|--single-package|--filter |--force []|--framework-inference []|--global-deps |--graph []|--env-mode []|--ignore |--no-cache|--no-daemon|--output-logs |--log-order |--only|--parallel|--pkg-inference-root |--profile |--remote-only []|--summarize []|--log-prefix |TASKS|PASS_THROUGH_ARGS|--experimental-space-id > (re) For more information, try '--help'. diff --git a/turborepo-tests/integration/tests/bad-turbo-json.t b/turborepo-tests/integration/tests/bad-turbo-json.t index fa83e88db098c..68e75ec27806d 100644 --- a/turborepo-tests/integration/tests/bad-turbo-json.t +++ b/turborepo-tests/integration/tests/bad-turbo-json.t @@ -15,7 +15,7 @@ Run build with package task in non-root turbo.json 7 | // this comment verifies that turbo can read .json files with comments 8 | ,-> "my-app#build": { 9 | | "outputs": ["banana.txt", "apple.json"], - 10 | | "dotEnv": [".env.local"] + 10 | | "inputs": ["$TURBO_DEFAULT$", ".env.local"] 11 | |-> } : `---- unnecessary package syntax found here 12 | } @@ -92,13 +92,13 @@ Run build with syntax errors in turbo.json 11 | "my-app#build": { 12 | "outputs": ["banana.txt", "apple.json"]42, : ^^ - 13 | "dotEnv": [".env.local" + 13 | "inputs": [".env.local" `---- Error: turbo_json_parse_error x expected `,` but instead found `}` ,-[13:1] - 13 | "dotEnv": [".env.local" + 13 | "inputs": [".env.local" 14 | }, : ^ 15 | diff --git a/turborepo-tests/integration/tests/conflicting-flags.t b/turborepo-tests/integration/tests/conflicting-flags.t index 872ea520d1b9e..60683f5891d9e 100644 --- a/turborepo-tests/integration/tests/conflicting-flags.t +++ b/turborepo-tests/integration/tests/conflicting-flags.t @@ -8,40 +8,3 @@ Setup For more information, try '--help'. [1] - - $ ${TURBO} run build --since main - ERROR the following required arguments were not provided: - --scope - - Usage: turbo(\.exe)? run --scope --since (re) - - For more information, try '--help'. - - [1] - $ ${TURBO} run build --ignore 'app/**' - ERROR the following required arguments were not provided: - <--filter |--scope > - - Usage: turbo(\.exe)? run --ignore <--filter |--scope > (re) - - For more information, try '--help'. - - [1] - $ ${TURBO} run build --no-deps - ERROR the following required arguments were not provided: - --scope - - Usage: turbo(\.exe)? run --scope --no-deps (re) - - For more information, try '--help'. - - [1] - $ ${TURBO} run build --include-dependencies - ERROR the following required arguments were not provided: - --scope - - Usage: turbo(\.exe)? run --scope --include-dependencies (re) - - For more information, try '--help'. - - [1] diff --git a/turborepo-tests/integration/tests/dry-json/monorepo-no-changes.t b/turborepo-tests/integration/tests/dry-json/monorepo-no-changes.t index a9332bd114901..8518b4ca7f6b5 100644 --- a/turborepo-tests/integration/tests/dry-json/monorepo-no-changes.t +++ b/turborepo-tests/integration/tests/dry-json/monorepo-no-changes.t @@ -2,13 +2,17 @@ Setup $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh # Save JSON to tmp file so we don't need to keep re-running the build - $ ${TURBO} run build --dry=json --filter=main > tmpjson.log + $ ${TURBO} run build --dry=json --filter='[main]' > tmpjson.log $ cat tmpjson.log | jq .packages - [] + [ + "//" + ] # Save JSON to tmp file so we don't need to keep re-running the build - $ ${TURBO} run build --dry=json --filter=main > tmpjson.log + $ ${TURBO} run build --dry=json --filter='[main]' > tmpjson.log $ cat tmpjson.log | jq .packages - [] + [ + "//" + ] diff --git a/turborepo-tests/integration/tests/dry-json/monorepo.t b/turborepo-tests/integration/tests/dry-json/monorepo.t index 90854d09cbdb1..75379b04e98d1 100644 --- a/turborepo-tests/integration/tests/dry-json/monorepo.t +++ b/turborepo-tests/integration/tests/dry-json/monorepo.t @@ -10,12 +10,12 @@ Setup $ cat tmpjson.log | jq .globalCacheInputs { - "rootKey": "HEY STELLLLLLLAAAAAAAAAAAAA", + "rootKey": "I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here", (esc) "files": { "foo.txt": "eebae5f3ca7b5831e429e947b7d61edd0de69236" }, "hashOfExternalDependencies": "459c029558afe716", - "globalDotEnv": null, + "hashOfInternalDependencies": "", "environmentVariables": { "specified": { "env": [ @@ -26,7 +26,8 @@ Setup "configured": [], "inferred": [], "passthrough": null - } + }, + "engines": null } $ cat tmpjson.log | jq 'keys' @@ -50,7 +51,7 @@ Setup "taskId": "my-app#build", "task": "build", "package": "my-app", - "hash": "f5b905676d8a275c", + "hash": "0555ce94ca234049", "inputs": { ".env.local": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "package.json": "1746e0db2361085b5953a6a3beab08c24af5bc08" @@ -80,19 +81,19 @@ Setup ], "cache": true, "dependsOn": [], - "inputs": [], - "outputMode": "full", + "inputs": [ + "$TURBO_DEFAULT$", + ".env.local" + ], + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": [ - ".env.local" - ], "interactive": false }, "expandedOutputs": [], "framework": "", - "envMode": "loose", + "envMode": "strict", "environmentVariables": { "specified": { "env": [], @@ -101,10 +102,7 @@ Setup "configured": [], "inferred": [], "passthrough": null - }, - "dotEnv": [ - ".env.local" - ] + } } # Validate output of util#build task @@ -113,7 +111,7 @@ Setup "taskId": "util#build", "task": "build", "package": "util", - "hash": "1ce33e04f265f95c", + "hash": "bf1798d3e46e1b48", "inputs": { "package.json": "e755064fd7893809d10fc067bb409c7ae516327f" }, @@ -137,18 +135,17 @@ Setup "cache": true, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [ "NODE_ENV" ], "passThroughEnv": null, - "dotEnv": null, "interactive": false }, "expandedOutputs": [], "framework": "", - "envMode": "loose", + "envMode": "strict", "environmentVariables": { "specified": { "env": [ @@ -159,8 +156,7 @@ Setup "configured": [], "inferred": [], "passthrough": null - }, - "dotEnv": null + } } Run again with NODE_ENV set and see the value in the summary. --filter=util workspace so the output is smaller diff --git a/turborepo-tests/integration/tests/dry-json/single-package-no-change.t b/turborepo-tests/integration/tests/dry-json/single-package-no-change.t index 574228234d430..816d19dab2a8a 100644 --- a/turborepo-tests/integration/tests/dry-json/single-package-no-change.t +++ b/turborepo-tests/integration/tests/dry-json/single-package-no-change.t @@ -2,7 +2,7 @@ Setup $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh single_package # Save JSON to tmp file so we don't need to keep re-running the build - $ ${TURBO} run build --dry=json --filter=main > tmpjson.log + $ ${TURBO} run build --dry=json --filter='[main]' > tmpjson.log $ cat tmpjson.log | jq .packages null 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..248ffc91f51c8 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 @@ -10,13 +10,13 @@ Setup "turboVersion": "[a-z0-9\.-]+", (re) "monorepo": false, "globalCacheInputs": { - "rootKey": "HEY STELLLLLLLAAAAAAAAAAAAA", + "rootKey": "I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here", (esc) "files": { "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328" + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32" }, "hashOfExternalDependencies": "", - "globalDotEnv": null, + "hashOfInternalDependencies": "", "environmentVariables": { "specified": { "env": [], @@ -25,19 +25,20 @@ Setup "configured": [], "inferred": [], "passthrough": null - } + }, + "engines": null }, - "envMode": "infer", + "envMode": "strict", "frameworkInference": true, "tasks": [ { "taskId": "build", "task": "build", - "hash": "e46d6df5143cae99", + "hash": "e2b99dad85a4ff66", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, "hashOfExternalDependencies": "", @@ -59,16 +60,15 @@ Setup "cache": false, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": null, "interactive": false }, "expandedOutputs": [], "framework": "", - "envMode": "loose", + "envMode": "strict", "environmentVariables": { "specified": { "env": [], @@ -77,8 +77,7 @@ Setup "configured": [], "inferred": [], "passthrough": null - }, - "dotEnv": null + } } ], "user": ".*", (re) 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..2f73cdf82e72f 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 @@ -8,14 +8,14 @@ Setup "turboVersion": "[a-z0-9\.-]+", (re) "monorepo": false, "globalCacheInputs": { - "rootKey": "HEY STELLLLLLLAAAAAAAAAAAAA", + "rootKey": "I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here", (esc) "files": { "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, "hashOfExternalDependencies": "", - "globalDotEnv": null, + "hashOfInternalDependencies": "", "environmentVariables": { "specified": { "env": [], @@ -24,21 +24,22 @@ Setup "configured": [], "inferred": [], "passthrough": null - } + }, + "engines": null }, - "envMode": "infer", + "envMode": "strict", "frameworkInference": true, "tasks": [ { "taskId": "build", "task": "build", - "hash": "f09bf783beacf5c9", + "hash": "7ece7b62aad25615", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", - "turbo.json": "bf9ddbce36808b6ea5a0ea2b7ceb400ee6c42c4c" + "turbo.json": "ce5bdbed55601768de641f5d8d005a8f5be8d3f7" }, "hashOfExternalDependencies": "", "cache": { @@ -65,16 +66,15 @@ Setup "cache": true, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": null, "interactive": false }, "expandedOutputs": [], "framework": "", - "envMode": "loose", + "envMode": "strict", "environmentVariables": { "specified": { "env": [], @@ -83,19 +83,18 @@ Setup "configured": [], "inferred": [], "passthrough": null - }, - "dotEnv": null + } }, { "taskId": "test", "task": "test", - "hash": "8bfab5dc6b4ccb3b", + "hash": "cb5839f7284aa5f3", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", - "turbo.json": "bf9ddbce36808b6ea5a0ea2b7ceb400ee6c42c4c" + "turbo.json": "ce5bdbed55601768de641f5d8d005a8f5be8d3f7" }, "hashOfExternalDependencies": "", "cache": { @@ -120,16 +119,15 @@ Setup "build" ], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": null, "interactive": false }, "expandedOutputs": [], "framework": "", - "envMode": "loose", + "envMode": "strict", "environmentVariables": { "specified": { "env": [], @@ -138,8 +136,7 @@ Setup "configured": [], "inferred": [], "passthrough": null - }, - "dotEnv": null + } } ], "user": ".*", (re) diff --git a/turborepo-tests/integration/tests/dry-json/single-package.t b/turborepo-tests/integration/tests/dry-json/single-package.t index 3b18ebebe1803..452725a66603a 100644 --- a/turborepo-tests/integration/tests/dry-json/single-package.t +++ b/turborepo-tests/integration/tests/dry-json/single-package.t @@ -8,14 +8,14 @@ Setup "turboVersion": "[a-z0-9\.-]+", (re) "monorepo": false, "globalCacheInputs": { - "rootKey": "HEY STELLLLLLLAAAAAAAAAAAAA", + "rootKey": "I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here", (esc) "files": { "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, "hashOfExternalDependencies": "", - "globalDotEnv": null, + "hashOfInternalDependencies": "", "environmentVariables": { "specified": { "env": [], @@ -24,21 +24,22 @@ Setup "configured": [], "inferred": [], "passthrough": null - } + }, + "engines": null }, - "envMode": "infer", + "envMode": "strict", "frameworkInference": true, "tasks": [ { "taskId": "build", "task": "build", - "hash": "f09bf783beacf5c9", + "hash": "7ece7b62aad25615", "inputs": { ".gitignore": "03b541460c1b836f96f9c0a941ceb48e91a9fd83", "package-lock.json": "1c117cce37347befafe3a9cba1b8a609b3600021", - "package.json": "5519edda652c463054307421a3c05ff49f080328", + "package.json": "8606ff4b95a5330740d8d9d0948faeada64f1f32", "somefile.txt": "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", - "turbo.json": "bf9ddbce36808b6ea5a0ea2b7ceb400ee6c42c4c" + "turbo.json": "ce5bdbed55601768de641f5d8d005a8f5be8d3f7" }, "hashOfExternalDependencies": "", "cache": { @@ -63,16 +64,15 @@ Setup "cache": true, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": null, "interactive": false }, "expandedOutputs": [], "framework": "", - "envMode": "loose", + "envMode": "strict", "environmentVariables": { "specified": { "env": [], @@ -81,8 +81,7 @@ Setup "configured": [], "inferred": [], "passthrough": null - }, - "dotEnv": null + } } ], "user": ".*", (re) diff --git a/turborepo-tests/integration/tests/dry-run.t b/turborepo-tests/integration/tests/dry-run.t index ce23fb4aadd52..bb0363e41b66d 100644 --- a/turborepo-tests/integration/tests/dry-run.t +++ b/turborepo-tests/integration/tests/dry-run.t @@ -18,20 +18,20 @@ Setup Global Hash Inputs Global Files = 1 External Dependencies Hash = 459c029558afe716 - Global Cache Key = HEY STELLLLLLLAAAAAAAAAAAAA - Global .env Files Considered = 0 + Global Cache Key = I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here (esc) Global Env Vars = SOME_ENV_VAR Global Env Vars Values = Inferred Global Env Vars Values = Global Passed Through Env Vars = Global Passed Through Env Vars Values = + Engines Values = # Part 3 are Tasks to Run, and we have to validate each task separately - $ cat tmp-3.txt | grep "my-app#build" -A 18 + $ cat tmp-3.txt | grep "my-app#build" -A 17 my-app#build Task = build\s* (re) Package = my-app\s* (re) - Hash = f5b905676d8a275c\s* (re) + Hash = 0555ce94ca234049 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Directory = apps(\/|\\)my-app\s* (re) @@ -41,18 +41,17 @@ Setup Dependencies =\s* (re) Dependents =\s* (re) Inputs Files Considered = 2\s* (re) - .env Files Considered = 1\s* (re) Env Vars =\s* (re) Env Vars Values =\s* (re) Inferred Env Vars Values =\s* (re) Passed Through Env Vars =\s* (re) Passed Through Env Vars Values =\s* (re) - $ cat tmp-3.txt | grep "util#build" -A 18 + $ cat tmp-3.txt | grep "util#build" -A 17 util#build Task = build\s* (re) Package = util\s* (re) - Hash = 1ce33e04f265f95c\s* (re) + Hash = bf1798d3e46e1b48 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Directory = packages(\/|\\)util\s* (re) @@ -62,7 +61,6 @@ Setup Dependencies =\s* (re) Dependents =\s* (re) Inputs Files Considered = 1\s* (re) - .env Files Considered = 0\s* (re) Env Vars = NODE_ENV\s* (re) Env Vars Values =\s* (re) Inferred Env Vars Values =\s* (re) diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/1-baseline.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/1-baseline.json index 9c9c4ee347ff4..fc3749db3fd1e 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/1-baseline.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/1-baseline.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/2-update-pipeline.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/2-update-pipeline.json index d75c02b701257..a8162a1ebb8fa 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/2-update-pipeline.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/2-update-pipeline.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV", "NEW_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/3-update-global-env.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/3-update-global-env.json index 4966c92b5f6b9..d09d9cdcce8aa 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/3-update-global-env.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/3-update-global-env.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR", "NEW_ENV"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/4-update-global-deps.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/4-update-global-deps.json index eb0cad40ff0a4..efd6a141e0d1b 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/4-update-global-deps.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/4-update-global-deps.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo*.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/5-update-global-deps-materially.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/5-update-global-deps-materially.json index 7392198df3957..7dac14e455a1a 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/5-update-global-deps-materially.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/5-update-global-deps-materially.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt", "bar.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/6-update-passthrough-env.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/6-update-passthrough-env.json index 0e7e6f2413e56..ce8ddf25f4ffe 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/6-update-passthrough-env.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/6-update-passthrough-env.json @@ -3,7 +3,7 @@ "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], "globalPassThroughEnv": ["PASSTHROUGH"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/a-baseline.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/a-baseline.json index 9c9c4ee347ff4..fc3749db3fd1e 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/a-baseline.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/a-baseline.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/b-change-only-my-app.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/b-change-only-my-app.json index d14227552234b..ee6f8ba3a2e10 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/b-change-only-my-app.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/b-change-only-my-app.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/c-my-app-depends-on.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/c-my-app-depends-on.json index 6f3d11a73b231..40222c6d60146 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/c-my-app-depends-on.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/c-my-app-depends-on.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/d-depends-on-util.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/d-depends-on-util.json index 6de9c73c20174..998363166ddb7 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/d-depends-on-util.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/d-depends-on-util.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/e-depends-on-util-but-modified.json b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/e-depends-on-util-but-modified.json index 7f8f9e34929d6..2ec766c54c822 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/e-depends-on-util-but-modified.json +++ b/turborepo-tests/integration/tests/edit-turbo-json/fixture-configs/e-depends-on-util-but-modified.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "globalDependencies": ["foo.txt"], "globalEnv": ["SOME_ENV_VAR"], - "pipeline": { + "tasks": { "build": { "env": ["NODE_ENV"], "outputs": [] diff --git a/turborepo-tests/integration/tests/edit-turbo-json/task.t b/turborepo-tests/integration/tests/edit-turbo-json/task.t index 9d4f0a5e46f36..d72b6cdf7287b 100644 --- a/turborepo-tests/integration/tests/edit-turbo-json/task.t +++ b/turborepo-tests/integration/tests/edit-turbo-json/task.t @@ -6,15 +6,15 @@ Baseline task hashes $ ${TURBO} build --dry=json | jq -r '.tasks | sort_by(.taskId)[] | {taskId, hash}' { "taskId": "another#build", - "hash": "02f55362198a6c3d" + "hash": "3639431fdcdf9f9e" } { "taskId": "my-app#build", - "hash": "8a8944ef32696847" + "hash": "0555ce94ca234049" } { "taskId": "util#build", - "hash": "1ce33e04f265f95c" + "hash": "bf1798d3e46e1b48" } Change only my-app#build @@ -22,15 +22,15 @@ Change only my-app#build $ ${TURBO} build --dry=json | jq -r '.tasks | sort_by(.taskId)[] | {taskId, hash}' { "taskId": "another#build", - "hash": "02f55362198a6c3d" + "hash": "3639431fdcdf9f9e" } { "taskId": "my-app#build", - "hash": "83bb5352c916557e" + "hash": "6eea03fab6f9a8c8" } { "taskId": "util#build", - "hash": "1ce33e04f265f95c" + "hash": "bf1798d3e46e1b48" } Change my-app#build dependsOn @@ -38,15 +38,15 @@ Change my-app#build dependsOn $ ${TURBO} build --dry=json | jq -r '.tasks | sort_by(.taskId)[] | {taskId, hash}' { "taskId": "another#build", - "hash": "02f55362198a6c3d" + "hash": "3639431fdcdf9f9e" } { "taskId": "my-app#build", - "hash": "346838a5f9d9a530" + "hash": "8637a0f5db686164" } { "taskId": "util#build", - "hash": "1ce33e04f265f95c" + "hash": "bf1798d3e46e1b48" } Non-materially modifying the dep graph does nothing. @@ -54,15 +54,15 @@ Non-materially modifying the dep graph does nothing. $ ${TURBO} build --dry=json | jq -r '.tasks | sort_by(.taskId)[] | {taskId, hash}' { "taskId": "another#build", - "hash": "02f55362198a6c3d" + "hash": "3639431fdcdf9f9e" } { "taskId": "my-app#build", - "hash": "346838a5f9d9a530" + "hash": "8637a0f5db686164" } { "taskId": "util#build", - "hash": "1ce33e04f265f95c" + "hash": "bf1798d3e46e1b48" } @@ -71,13 +71,13 @@ Change util#build impacts itself and my-app $ ${TURBO} build --dry=json | jq -r '.tasks | sort_by(.taskId)[] | {taskId, hash}' { "taskId": "another#build", - "hash": "02f55362198a6c3d" + "hash": "3639431fdcdf9f9e" } { "taskId": "my-app#build", - "hash": "b15e1a917912cd09" + "hash": "2721f01b53b758d0" } { "taskId": "util#build", - "hash": "2ee29eb57d7f69b3" + "hash": "74c8eb9bab702b4b" } diff --git a/turborepo-tests/integration/tests/engines.t b/turborepo-tests/integration/tests/engines.t new file mode 100644 index 0000000000000..bee444d45cfcb --- /dev/null +++ b/turborepo-tests/integration/tests/engines.t @@ -0,0 +1,21 @@ +Setup + $ . ${TESTDIR}/../../helpers/setup_integration_test.sh + $ jq '.engines = {"node": ">=12"}' package.json > package.json.new + $ mv package.json.new package.json + +Check a hash + $ ${TURBO} build --dry=json --filter=my-app | jq '.tasks | last | .hash' + "56d7eb9a31d82ee0" +Change engines + $ jq '.engines = {"node": ">=16"}' package.json > package.json.new + $ mv package.json.new package.json + +Verify hash has changed + $ ${TURBO} build --dry=json --filter=my-app | jq ".tasks | last | .hash" + "1d8b8596ae37a40c" + +Verify engines are part of global cache inputs + $ ${TURBO} build --dry=json | jq '.globalCacheInputs.engines' + { + "node": ">=16" + } diff --git a/turborepo-tests/integration/tests/filter-run.t b/turborepo-tests/integration/tests/filter-run.t index 37fda189d78e9..346f2ec085f85 100644 --- a/turborepo-tests/integration/tests/filter-run.t +++ b/turborepo-tests/integration/tests/filter-run.t @@ -41,3 +41,8 @@ Setup Time:\s*[\.0-9]+m?s (re) +Non existent package name should error + $ ${TURBO} run build --filter="foo" --output-logs none + x No package found with name 'foo' in workspace + + [1] diff --git a/turborepo-tests/integration/tests/global-deps.t b/turborepo-tests/integration/tests/global-deps.t index 6b01cf8d9a93d..05cee80e19e78 100644 --- a/turborepo-tests/integration/tests/global-deps.t +++ b/turborepo-tests/integration/tests/global-deps.t @@ -6,7 +6,7 @@ Run a build \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache miss, executing 81165ceb4ed0e31f + my-app:build: cache miss, executing 2a57e19ce0b2cfd5 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -18,9 +18,20 @@ Run a build \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache miss, executing 7bc88ba3e84628fd + my-app:build: cache miss, executing 3883869b5e1dc9cf Tasks: 1 successful, 1 total Cached: 0 cached, 1 total Time:\s*[\.0-9]+m?s (re) + $ echo "Submit a PR!" >> global_deps/CONTRIBUTING.md + $ ${TURBO} build -F my-app --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: my-app (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + my-app:build: cache hit, suppressing logs 3883869b5e1dc9cf + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) + diff --git a/turborepo-tests/integration/tests/global-env.t b/turborepo-tests/integration/tests/global-env.t index ed1c90c47c95e..a22269cf5b2e9 100644 --- a/turborepo-tests/integration/tests/global-env.t +++ b/turborepo-tests/integration/tests/global-env.t @@ -8,7 +8,7 @@ Setup \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache miss, executing 1ce33e04f265f95c + util:build: cache miss, executing bf1798d3e46e1b48 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -19,7 +19,7 @@ Setup \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache hit, suppressing logs 1ce33e04f265f95c + util:build: cache hit, suppressing logs bf1798d3e46e1b48 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -30,7 +30,7 @@ Setup \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache miss, executing 70278c4ec3fb5ac9 + util:build: cache miss, executing 265e40ee03ae83ec Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -41,7 +41,7 @@ Setup \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache hit, suppressing logs 1ce33e04f265f95c + util:build: cache hit, suppressing logs bf1798d3e46e1b48 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -52,7 +52,7 @@ Setup \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache miss, executing 8b12fdc0e2d94c8d + util:build: cache miss, executing b8f403756f67074c Tasks: 1 successful, 1 total Cached: 0 cached, 1 total diff --git a/turborepo-tests/integration/tests/inference/has-workspaces.t b/turborepo-tests/integration/tests/inference/has-workspaces.t index 22c5cece74e7b..5e2b43d7d2fdf 100644 --- a/turborepo-tests/integration/tests/inference/has-workspaces.t +++ b/turborepo-tests/integration/tests/inference/has-workspaces.t @@ -2,22 +2,27 @@ Setup $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh inference/has_workspaces $ cd $TARGET_DIR && ${TURBO} run build --filter=nothing -vv 1> ROOT 2>&1 + [1] $ grep --quiet 'pkg_inference_root set' ROOT [1] - $ grep --quiet "No tasks were executed as part of this run." ROOT + $ grep --quiet "No package found with name 'nothing' in workspace" ROOT $ cd $TARGET_DIR/apps/web && ${TURBO} run build --filter=nothing -vv 1> WEB 2>&1 + [1] $ grep --quiet 'pkg_inference_root set to "apps[\/\\]web"' WEB - $ grep --quiet "No tasks were executed as part of this run." WEB + $ grep --quiet "No package found with name 'nothing' in workspace" WEB $ cd $TARGET_DIR/crates && ${TURBO} run build --filter=nothing -vv 1> CRATES 2>&1 + [1] $ grep --quiet 'pkg_inference_root set to "crates"' CRATES - $ grep --quiet "No tasks were executed as part of this run." CRATES + $ grep --quiet "No package found with name 'nothing' in workspace" CRATES $ cd $TARGET_DIR/crates/super-crate/tests/test-package && ${TURBO} run build --filter=nothing -vv 1> TEST_PACKAGE 2>&1 + [1] $ grep --quiet -E 'pkg_inference_root set to "crates[\/\\]super-crate[\/\\]tests[\/\\]test-package"' TEST_PACKAGE - $ grep --quiet "No tasks were executed as part of this run." TEST_PACKAGE + $ grep --quiet "No package found with name 'nothing' in workspace" TEST_PACKAGE $ cd $TARGET_DIR/packages/ui-library/src && ${TURBO} run build --filter=nothing -vv 1> UI_LIBRARY 2>&1 + [1] $ grep --quiet -E 'pkg_inference_root set to "packages[\/\\]ui-library[\/\\]src"' UI_LIBRARY - $ grep --quiet "No tasks were executed as part of this run." UI_LIBRARY + $ grep --quiet "No package found with name 'nothing' in workspace" UI_LIBRARY diff --git a/turborepo-tests/integration/tests/inference/nested-workspaces.t b/turborepo-tests/integration/tests/inference/nested-workspaces.t index 6e2363bde791f..4a03406422ad4 100644 --- a/turborepo-tests/integration/tests/inference/nested-workspaces.t +++ b/turborepo-tests/integration/tests/inference/nested-workspaces.t @@ -3,20 +3,24 @@ Setup $ . ${TESTDIR}/nested_workspaces_setup.sh $(pwd)/nested_workspaces $ cd $TARGET_DIR/outer && ${TURBO} run build --filter=nothing -vv 1> OUTER 2>&1 + [1] $ grep --quiet -E "Repository Root: .*[\/\\]nested_workspaces[\/\\]outer" OUTER - $ grep --quiet "No tasks were executed as part of this run." OUTER + $ grep --quiet "No package found with name 'nothing' in workspace" OUTER $ cd $TARGET_DIR/outer/apps && ${TURBO} run build --filter=nothing -vv 1> OUTER_APPS 2>&1 + [1] $ grep --quiet -E "Repository Root: .*[\/\\]nested_workspaces[\/\\]outer" OUTER_APPS - $ grep --quiet "No tasks were executed as part of this run." OUTER_APPS + $ grep --quiet "No package found with name 'nothing' in workspace" OUTER_APPS $ cd $TARGET_DIR/outer/inner && ${TURBO} run build --filter=nothing -vv 1> OUTER_INNER 2>&1 + [1] $ grep --quiet -E "Repository Root: .*[\/\\]nested_workspaces[\/\\]outer[\/\\]inner" OUTER_INNER - $ grep --quiet "No tasks were executed as part of this run." OUTER_INNER + $ grep --quiet "No package found with name 'nothing' in workspace" OUTER_INNER $ cd $TARGET_DIR/outer/inner/apps && ${TURBO} run build --filter=nothing -vv 1> OUTER_INNER_APPS 2>&1 + [1] $ grep --quiet -E "Repository Root: .*[\/\\]nested_workspaces[\/\\]outer[\/\\]inner" OUTER_INNER_APPS - $ grep --quiet "No tasks were executed as part of this run." OUTER_INNER_APPS + $ grep --quiet "No package found with name 'nothing' in workspace" OUTER_INNER_APPS Locate a repository with no turbo.json. We'll get the right root, but there's nothing to run $ cd $TARGET_DIR/outer/inner-no-turbo && ${TURBO} run build --filter=nothing -vv 1> INNER_NO_TURBO 2>&1 @@ -45,12 +49,14 @@ Locate a repository with no turbo.json. We'll get the right root and inference d $ grep --quiet "| Follow directions at https://turbo.build/repo/docs to create one" OUTER_NO_TURBO_APPS $ cd $TARGET_DIR/outer-no-turbo/inner && ${TURBO} run build --filter=nothing -vv 1> OUTER_NO_TURBO_INNER 2>&1 + [1] $ grep --quiet -E "Repository Root: .*[\/\\]nested_workspaces[\/\\]outer-no-turbo[\/\\]inner" OUTER_NO_TURBO_INNER - $ grep --quiet "No tasks were executed as part of this run." OUTER_NO_TURBO_INNER + $ grep --quiet "No package found with name 'nothing' in workspace" OUTER_NO_TURBO_INNER $ cd $TARGET_DIR/outer-no-turbo/inner/apps && ${TURBO} run build --filter=nothing -vv 1> OUTER_NO_TURBO_INNER_APPS 2>&1 + [1] $ grep --quiet -E "Repository Root: .*[\/\\]nested_workspaces[\/\\]outer-no-turbo[\/\\]inner" OUTER_NO_TURBO_INNER_APPS - $ grep --quiet "No tasks were executed as part of this run." OUTER_NO_TURBO_INNER_APPS + $ grep --quiet "No package found with name 'nothing' in workspace" OUTER_NO_TURBO_INNER_APPS $ cd $TARGET_DIR/outer-no-turbo/inner-no-turbo && ${TURBO} run build --filter=nothing -vv 1> INNER_NO_TURBO 2>&1 [1] diff --git a/turborepo-tests/integration/tests/inference/no-workspaces.t b/turborepo-tests/integration/tests/inference/no-workspaces.t index 78200e28e1042..5e99e35289418 100644 --- a/turborepo-tests/integration/tests/inference/no-workspaces.t +++ b/turborepo-tests/integration/tests/inference/no-workspaces.t @@ -3,32 +3,15 @@ Setup $ . ${TESTDIR}/no_workspaces_setup.sh $(pwd)/no_workspaces $ cd $TARGET_DIR && ${TURBO} run build --filter=nothing - \xe2\x80\xa2 Running build (esc) - \xe2\x80\xa2 Remote caching disabled (esc) - - No tasks were executed as part of this run. - - Tasks: 0 successful, 0 total - Cached: 0 cached, 0 total - Time:\s*[\.0-9]+m?s (re) + x No package found with name 'nothing' in workspace + [1] + $ cd $TARGET_DIR/parent && ${TURBO} run build --filter=nothing - \xe2\x80\xa2 Running build (esc) - \xe2\x80\xa2 Remote caching disabled (esc) - - No tasks were executed as part of this run. - - Tasks: 0 successful, 0 total - Cached: 0 cached, 0 total - Time:\s*[\.0-9]+m?s (re) + x No package found with name 'nothing' in workspace + [1] $ cd $TARGET_DIR/parent/child && ${TURBO} run build --filter=nothing - \xe2\x80\xa2 Running build (esc) - \xe2\x80\xa2 Remote caching disabled (esc) - - No tasks were executed as part of this run. + x No package found with name 'nothing' in workspace - Tasks: 0 successful, 0 total - Cached: 0 cached, 0 total - Time:\s*[\.0-9]+m?s (re) - \ No newline at end of file + [1] diff --git a/turborepo-tests/integration/tests/invalid-package-json.t b/turborepo-tests/integration/tests/invalid-package-json.t new file mode 100644 index 0000000000000..160e4ca8d33ca --- /dev/null +++ b/turborepo-tests/integration/tests/invalid-package-json.t @@ -0,0 +1,9 @@ +Setup + $ . ${TESTDIR}/../../helpers/setup_integration_test.sh +Clear name field + $ jq '.name = ""' apps/my-app/package.json > package.json.new + $ mv package.json.new apps/my-app/package.json +Build should fail due to missing name field + $ ${TURBO} build 1> ERR + [1] + $ grep -F --quiet 'x package.json must have a name field:' ERR diff --git a/turborepo-tests/integration/tests/no-args.t b/turborepo-tests/integration/tests/no-args.t index c5f0d94e7266f..14f877855a30b 100644 --- a/turborepo-tests/integration/tests/no-args.t +++ b/turborepo-tests/integration/tests/no-args.t @@ -28,7 +28,6 @@ Make sure exit code is 2 when no args are passed --no-update-notifier Disable the turbo update notification --api Override the endpoint for API calls --color Force color usage in the terminal - --cpuprofile Specify a file to save a cpu profile --cwd The directory in which to run turbo --heap Specify a file to save a pprof heap profile --login Override the login endpoint @@ -77,19 +76,9 @@ Make sure exit code is 2 when no args are passed --global-deps Specify glob of global filesystem dependencies to be hashed. Useful for .env and files --env-mode [] - Environment variable mode. Use "loose" to pass the entire existing environment. Use "strict" to use an allowlist specified in turbo.json. Use "infer" to defer to existence of "passThroughEnv" or "globalPassThroughEnv" in turbo.json. (default infer) [default: infer] [possible values: infer, loose, strict] + Environment variable mode. Use "loose" to pass the entire existing environment. Use "strict" to use an allowlist specified in turbo.json [default: strict] [possible values: loose, strict] -F, --filter Use the given selector to specify package(s) to act as entry points. The syntax mirrors pnpm's syntax, and additional documentation and examples can be found in turbo's documentation https://turbo.build/repo/docs/reference/command-line-reference/run#--filter - --scope - DEPRECATED: Specify package(s) to act as entry points for task execution. Supports globs - --ignore - Files to ignore when calculating changed files from '--filter'. Supports globs - --since - DEPRECATED: Limit/Set scope to changed packages since a mergebase. This uses the git diff ${target_branch}... mechanism to identify which packages have changed - --include-dependencies - DEPRECATED: Include the dependencies of tasks in execution - --no-deps - DEPRECATED: Exclude dependent task consumers from execution --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only] --log-order 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/persistent-dependencies/6-topological-unimplemented.t b/turborepo-tests/integration/tests/persistent-dependencies/6-topological-unimplemented.t index 062a3bd1d275a..429824d258d25 100644 --- a/turborepo-tests/integration/tests/persistent-dependencies/6-topological-unimplemented.t +++ b/turborepo-tests/integration/tests/persistent-dependencies/6-topological-unimplemented.t @@ -17,7 +17,7 @@ \xe2\x80\xa2 Packages in scope: app-a, pkg-a (esc) \xe2\x80\xa2 Running dev in 2 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - app-a:dev: cache miss, executing 6ae3691e15cf83ab + app-a:dev: cache miss, executing 7def3a3e7f1235de app-a:dev: app-a:dev: > dev app-a:dev: > echo dev-app-a diff --git a/turborepo-tests/integration/tests/pkg-inference.t b/turborepo-tests/integration/tests/pkg-inference.t index c9efbf81bc33c..51eeadef87124 100644 --- a/turborepo-tests/integration/tests/pkg-inference.t +++ b/turborepo-tests/integration/tests/pkg-inference.t @@ -6,7 +6,7 @@ Setup \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache miss, executing 1ce33e04f265f95c + util:build: cache miss, executing bf1798d3e46e1b48 util:build: util:build: > build util:build: > echo building diff --git a/turborepo-tests/integration/tests/prune/composable-config.t b/turborepo-tests/integration/tests/prune/composable-config.t index ca8d88fd19080..e9dd448c009b7 100644 --- a/turborepo-tests/integration/tests/prune/composable-config.t +++ b/turborepo-tests/integration/tests/prune/composable-config.t @@ -11,7 +11,7 @@ Make sure that the internal util package is part of the prune output \xe2\x80\xa2 Packages in scope: docs, shared, util (esc) \xe2\x80\xa2 Running new-task in 3 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - docs:new-task: cache miss, executing caf7e46550cd3151 + docs:new-task: cache miss, executing 869a9c24e803c5d6 docs:new-task: docs:new-task: > docs@ new-task .*out(\/|\\)apps(\/|\\)docs (re) docs:new-task: > echo building diff --git a/turborepo-tests/integration/tests/prune/produces-valid-turbo-json.t b/turborepo-tests/integration/tests/prune/produces-valid-turbo-json.t index 5173bed41a654..8614ec80376de 100644 --- a/turborepo-tests/integration/tests/prune/produces-valid-turbo-json.t +++ b/turborepo-tests/integration/tests/prune/produces-valid-turbo-json.t @@ -12,7 +12,7 @@ Make sure we prune tasks that reference a pruned workspace $ cat out/turbo.json | jq { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "outputs": [] } diff --git a/turborepo-tests/integration/tests/run-caching/cache-state.t b/turborepo-tests/integration/tests/run-caching/cache-state.t index 6c441317fa974..fbe40396cdcdd 100644 --- a/turborepo-tests/integration/tests/run-caching/cache-state.t +++ b/turborepo-tests/integration/tests/run-caching/cache-state.t @@ -17,7 +17,7 @@ Do a dry run so we can see the state of the cache Get the hash of the my-app#build task, so we can inspect the cache $ HASH=$(cat dry.json | jq -r '.tasks | map(select(.taskId == "my-app#build")) | .[0].hash') - $ duration=$(cat "node_modules/.cache/turbo/$HASH-meta.json" | jq .duration) + $ duration=$(cat ".turbo/cache/$HASH-meta.json" | jq .duration) check that it exists $ echo $duration [0-9]+ (re) diff --git a/turborepo-tests/integration/tests/run-caching/excluded-inputs/excluded-inputs.t b/turborepo-tests/integration/tests/run-caching/excluded-inputs/excluded-inputs.t index 732fe6757aed7..6ebf04aa02419 100644 --- a/turborepo-tests/integration/tests/run-caching/excluded-inputs/excluded-inputs.t +++ b/turborepo-tests/integration/tests/run-caching/excluded-inputs/excluded-inputs.t @@ -9,7 +9,7 @@ Running build for my-app succeeds \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache miss, executing 2fa14ad1b3e50ac8 + my-app:build: cache miss, executing e228bd94fd46352c my-app:build: my-app:build: > build my-app:build: > echo building @@ -26,7 +26,7 @@ Update exluded file and try again \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache hit, replaying logs 2fa14ad1b3e50ac8 + my-app:build: cache hit, replaying logs e228bd94fd46352c my-app:build: my-app:build: > build my-app:build: > echo building diff --git a/turborepo-tests/integration/tests/run-caching/excluded-inputs/turbo.json b/turborepo-tests/integration/tests/run-caching/excluded-inputs/turbo.json index c3d2f67aebdaa..c0ee2fe496d84 100644 --- a/turborepo-tests/integration/tests/run-caching/excluded-inputs/turbo.json +++ b/turborepo-tests/integration/tests/run-caching/excluded-inputs/turbo.json @@ -1,6 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "tasks": { "build": { "inputs": ["*.txt", "!excluded.txt"], "outputs": ["banana.txt", "apple.json"] diff --git a/turborepo-tests/integration/tests/run-caching/root-deps.t b/turborepo-tests/integration/tests/run-caching/root-deps.t new file mode 100644 index 0000000000000..646f5b5ebd3bc --- /dev/null +++ b/turborepo-tests/integration/tests/run-caching/root-deps.t @@ -0,0 +1,56 @@ +Setup + $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh root_deps + +Warm the cache + $ ${TURBO} build --filter=another --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: another (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + another:build: cache miss, executing 6a4c300cb14847b0 + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s+[.0-9]+m?s (re) + + +Confirm cache hit + $ ${TURBO} build --filter=another --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: another (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + another:build: cache hit, suppressing logs 6a4c300cb14847b0 + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s+[.0-9]+m?s >>> FULL TURBO (re) + + + +Change a root internal dependency + $ touch packages/util/important.txt +All tasks should be a cache miss, even ones that don't depend on changed package + $ ${TURBO} build --filter=another --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: another (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + another:build: cache miss, executing 34787620f332fb95 + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s+[.0-9]+m?s (re) + + +Change a file that is git ignored + $ mkdir packages/util/dist + $ touch packages/util/dist/unused.txt +Cache hit since only tracked files contribute to root dep hash + $ ${TURBO} build --filter=another --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: another (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + another:build: cache hit, suppressing logs 34787620f332fb95 + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) + diff --git a/turborepo-tests/integration/tests/run-logging/errors-only.t b/turborepo-tests/integration/tests/run-logging/errors-only.t index 6093ebb51869d..403f3aa02343d 100644 --- a/turborepo-tests/integration/tests/run-logging/errors-only.t +++ b/turborepo-tests/integration/tests/run-logging/errors-only.t @@ -2,7 +2,7 @@ Setup $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh run_logging # [ ] error exit -# [ ] outputMode: errors-only +# [ ] outputLogs: errors-only # [x] --ouptut-logs=errors-only $ ${TURBO} run build --output-logs=errors-only \xe2\x80\xa2 Packages in scope: app-a (esc) @@ -17,7 +17,7 @@ Setup # [ ] error exit -# [x] outputMode: errors-only +# [x] outputLogs: errors-only # [ ] --ouptut-logs=errors-only $ ${TURBO} run buildsuccess \xe2\x80\xa2 Packages in scope: app-a (esc) @@ -31,13 +31,13 @@ Setup # [x] error exit -# [ ] outputMode: errors-only +# [ ] outputLogs: errors-only # [x] --ouptut-logs=errors-only $ ${TURBO} run builderror --output-logs=errors-only \xe2\x80\xa2 Packages in scope: app-a (esc) \xe2\x80\xa2 Running builderror in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - app-a:builderror: cache miss, executing 63f09c22afb626a8 + app-a:builderror: cache miss, executing 7e337a3261100818 app-a:builderror: app-a:builderror: > builderror app-a:builderror: > echo error-builderror-app-a && exit 1 @@ -61,13 +61,13 @@ Setup # [x] error exit -# [x] outputMode: errors-only +# [x] outputLogs: errors-only # [ ] --ouptut-logs=errors-only $ ${TURBO} run builderror2 \xe2\x80\xa2 Packages in scope: app-a (esc) \xe2\x80\xa2 Running builderror2 in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - app-a:builderror2: cache miss, executing 7303c469d075d34c + app-a:builderror2: cache miss, executing 3731518fa339b920 app-a:builderror2: app-a:builderror2: > builderror2 app-a:builderror2: > echo error-builderror2-app-a && exit 1 diff --git a/turborepo-tests/integration/tests/run-logging/log-order-github.t b/turborepo-tests/integration/tests/run-logging/log-order-github.t index 96c17cfb3977a..7e07ce8aa8de3 100644 --- a/turborepo-tests/integration/tests/run-logging/log-order-github.t +++ b/turborepo-tests/integration/tests/run-logging/log-order-github.t @@ -9,7 +9,7 @@ because otherwise prysk interprets them as multiline commands \xe2\x80\xa2 Running build in 2 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) ::group::my-app:build - cache bypass, force executing c1d33a8183d8cf0b + cache bypass, force executing 0af90ec6a57471be >\sbuild (re) \>\secho building && sleep 1 && echo done (re) @@ -18,7 +18,7 @@ because otherwise prysk interprets them as multiline commands done ::endgroup:: ::group::util:build - cache bypass, force executing ff1050c513839636 + cache bypass, force executing 2da422600daca8be >\sbuild (re) \>\ssleep 0.5 && echo building && sleep 1 && echo completed (re) @@ -37,7 +37,7 @@ because otherwise prysk interprets them as multiline commands \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) ::group::util:build - util:build: cache bypass, force executing ff1050c513839636 + util:build: cache bypass, force executing 2da422600daca8be util:build: util:build: > build util:build: > sleep 0.5 && echo building && sleep 1 && echo completed @@ -57,7 +57,7 @@ Verify that errors are grouped properly \xe2\x80\xa2 Running fail in 2 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) \x1b[;31mutil:fail\x1b[;0m (esc) - cache miss, executing 122cca10fdcda4f0 + cache miss, executing 91d719104281046f \> fail (re) \> echo failing; exit 1 (re) diff --git a/turborepo-tests/integration/tests/run-logging/log-prefix.t b/turborepo-tests/integration/tests/run-logging/log-prefix.t index caa6e1c5a3ced..d9af3064fe987 100644 --- a/turborepo-tests/integration/tests/run-logging/log-prefix.t +++ b/turborepo-tests/integration/tests/run-logging/log-prefix.t @@ -6,7 +6,7 @@ Setup \xe2\x80\xa2 Packages in scope: app-a (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - cache miss, executing 6b91fee8d61438d4 + cache miss, executing 612027951a2848ce \> build (re) \> echo build-app-a (re) @@ -30,7 +30,7 @@ Setup \xe2\x80\xa2 Packages in scope: app-a (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - cache hit, replaying logs 6b91fee8d61438d4 + cache hit, replaying logs 612027951a2848ce \> build (re) \> echo build-app-a (re) @@ -46,7 +46,7 @@ Setup \xe2\x80\xa2 Packages in scope: app-a (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - app-a:build: cache hit, replaying logs 6b91fee8d61438d4 + app-a:build: cache hit, replaying logs 612027951a2848ce app-a:build: app-a:build: > build app-a:build: > echo build-app-a diff --git a/turborepo-tests/integration/tests/run-logging/verbosity.t b/turborepo-tests/integration/tests/run-logging/verbosity.t index 65fccf862d684..3c009b31a4d5f 100644 --- a/turborepo-tests/integration/tests/run-logging/verbosity.t +++ b/turborepo-tests/integration/tests/run-logging/verbosity.t @@ -6,7 +6,7 @@ Verbosity level 1 \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache bypass, force executing 1ce33e04f265f95c + util:build: cache bypass, force executing bf1798d3e46e1b48 util:build: util:build: > build util:build: > echo building @@ -21,7 +21,7 @@ Verbosity level 1 \xe2\x80\xa2 Packages in scope: util (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache bypass, force executing 1ce33e04f265f95c + util:build: cache bypass, force executing bf1798d3e46e1b48 util:build: util:build: > build util:build: > echo building diff --git a/turborepo-tests/integration/tests/run-summary/discovery.t b/turborepo-tests/integration/tests/run-summary/discovery.t index 43847dfe85a09..67c430c6b4f77 100644 --- a/turborepo-tests/integration/tests/run-summary/discovery.t +++ b/turborepo-tests/integration/tests/run-summary/discovery.t @@ -6,7 +6,7 @@ Setup \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache miss, executing f5b905676d8a275c + my-app:build: cache miss, executing 0555ce94ca234049 my-app:build: my-app:build: > build my-app:build: > echo building diff --git a/turborepo-tests/integration/tests/run-summary/error.t b/turborepo-tests/integration/tests/run-summary/error.t index fe04ff7d3877c..9867b44d74141 100644 --- a/turborepo-tests/integration/tests/run-summary/error.t +++ b/turborepo-tests/integration/tests/run-summary/error.t @@ -32,7 +32,7 @@ Validate that we got a full task summary for the failed task with an error in .e "taskId": "my-app#maybefails", "task": "maybefails", "package": "my-app", - "hash": "9626dfcd1fbbdc68", + "hash": "9f05a7188fdf4e93", "inputs": { ".env.local": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "package.json": "1746e0db2361085b5953a6a3beab08c24af5bc08" @@ -57,16 +57,15 @@ Validate that we got a full task summary for the failed task with an error in .e "cache": true, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": null, "interactive": false }, "expandedOutputs": [], "framework": "", - "envMode": "loose", + "envMode": "strict", "environmentVariables": { "specified": { "env": [], @@ -76,7 +75,6 @@ Validate that we got a full task summary for the failed task with an error in .e "inferred": [], "passthrough": null }, - "dotEnv": null, "execution": { "startTime": [0-9]+, (re) "endTime": [0-9]+, (re) diff --git a/turborepo-tests/integration/tests/run-summary/single-package.t b/turborepo-tests/integration/tests/run-summary/single-package.t index 462b3a4694739..f3f21463e6191 100644 --- a/turborepo-tests/integration/tests/run-summary/single-package.t +++ b/turborepo-tests/integration/tests/run-summary/single-package.t @@ -72,7 +72,6 @@ Check "command", "dependencies", "dependents", - "dotEnv", "envMode", "environmentVariables", "excludedOutputs", diff --git a/turborepo-tests/integration/tests/run-summary/strict-env.t b/turborepo-tests/integration/tests/run-summary/strict-env.t index bb4cba1621bce..9a2522b8889ad 100644 --- a/turborepo-tests/integration/tests/run-summary/strict-env.t +++ b/turborepo-tests/integration/tests/run-summary/strict-env.t @@ -13,9 +13,9 @@ Run as `infer` $ rm -rf .turbo/runs $ ${TURBO} run build --summarize > /dev/null $ cat .turbo/runs/*.json | jq -r '.envMode' - infer + strict $ cat .turbo/runs/*.json | jq -r '.tasks[0].envMode' - loose + strict $ cat .turbo/runs/*.json | jq -r '.tasks[0].environmentVariables | {passthrough, globalPassthrough}' { "passthrough": null, @@ -141,7 +141,7 @@ Task passthrough specified empty array + infer $ ${TESTDIR}/../../../helpers/replace_turbo_json.sh $(pwd) "strict_env_vars/task_pt-empty.json" $ ${TURBO} run build --summarize > /dev/null $ cat .turbo/runs/*.json | jq -r '.envMode' - infer + strict $ cat .turbo/runs/*.json | jq -r '.tasks[0].envMode' strict $ cat .turbo/runs/*.json | jq -r '.tasks[0].environmentVariables | {passthrough, globalPassthrough}' @@ -155,7 +155,7 @@ Task passthrough specified value + infer $ ${TESTDIR}/../../../helpers/replace_turbo_json.sh $(pwd) "strict_env_vars/task_pt.json" $ ${TURBO} run build --summarize > /dev/null $ cat .turbo/runs/*.json | jq -r '.envMode' - infer + strict $ cat .turbo/runs/*.json | jq -r '.tasks[0].envMode' strict $ cat .turbo/runs/*.json | jq -r '.tasks[0].environmentVariables | {passthrough, globalPassthrough}' diff --git a/turborepo-tests/integration/tests/run/continue.t b/turborepo-tests/integration/tests/run/continue.t index 102a4322514c8..d35ffac9b2655 100644 --- a/turborepo-tests/integration/tests/run/continue.t +++ b/turborepo-tests/integration/tests/run/continue.t @@ -5,7 +5,7 @@ Run without --continue \xe2\x80\xa2 Packages in scope: my-app, other-app, some-lib (esc) \xe2\x80\xa2 Running build in 3 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - some-lib:build: cache miss, executing 768adc25648baff5 + some-lib:build: cache miss, executing ab8c4a02e3facf55 some-lib:build: some-lib:build: > build some-lib:build: > exit 2 @@ -31,7 +31,7 @@ Run without --continue, and with only errors. \xe2\x80\xa2 Packages in scope: my-app, other-app, some-lib (esc) \xe2\x80\xa2 Running build in 3 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - some-lib:build: cache miss, executing 768adc25648baff5 + some-lib:build: cache miss, executing ab8c4a02e3facf55 some-lib:build: some-lib:build: > build some-lib:build: > exit 2 @@ -56,7 +56,7 @@ Run with --continue \xe2\x80\xa2 Packages in scope: my-app, other-app, some-lib (esc) \xe2\x80\xa2 Running build in 3 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - some-lib:build: cache miss, executing 768adc25648baff5 + some-lib:build: cache miss, executing ab8c4a02e3facf55 some-lib:build: some-lib:build: > build some-lib:build: > exit 2 @@ -66,7 +66,7 @@ Run with --continue some-lib:build: npm ERR! in workspace: some-lib some-lib:build: npm ERR! at location: (.*)(\/|\\)apps(\/|\\)some-lib (re) some-lib:build: command finished with error, but continuing... - other-app:build: cache miss, executing a40a9e67334d0ae6 + other-app:build: cache miss, executing babf2f6b1d6ace47 other-app:build: other-app:build: > build other-app:build: > exit 3 @@ -86,4 +86,3 @@ Run with --continue ERROR run failed: command exited (1) [1] - diff --git a/turborepo-tests/integration/tests/run/force.t b/turborepo-tests/integration/tests/run/force.t index ea7c24fb95ef6..264d1d2fd16fc 100644 --- a/turborepo-tests/integration/tests/run/force.t +++ b/turborepo-tests/integration/tests/run/force.t @@ -24,7 +24,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache miss, executing f5b905676d8a275c + my-app:build: cache miss, executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -36,7 +36,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache bypass, force executing f5b905676d8a275c + my-app:build: cache bypass, force executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -47,7 +47,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache bypass, force executing f5b905676d8a275c + my-app:build: cache bypass, force executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -58,7 +58,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache hit, suppressing logs f5b905676d8a275c + my-app:build: cache hit, suppressing logs 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -69,7 +69,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache bypass, force executing f5b905676d8a275c + my-app:build: cache bypass, force executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -81,7 +81,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache hit, suppressing logs f5b905676d8a275c + my-app:build: cache hit, suppressing logs 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -92,7 +92,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache bypass, force executing f5b905676d8a275c + my-app:build: cache bypass, force executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -103,7 +103,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache hit, suppressing logs f5b905676d8a275c + my-app:build: cache hit, suppressing logs 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -114,7 +114,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache bypass, force executing f5b905676d8a275c + my-app:build: cache bypass, force executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -126,7 +126,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache hit, suppressing logs f5b905676d8a275c + my-app:build: cache hit, suppressing logs 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -137,7 +137,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache bypass, force executing f5b905676d8a275c + my-app:build: cache bypass, force executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total @@ -148,7 +148,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache hit, suppressing logs f5b905676d8a275c + my-app:build: cache hit, suppressing logs 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -159,7 +159,7 @@ baseline to generate cache \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:build: cache bypass, force executing f5b905676d8a275c + my-app:build: cache bypass, force executing 0555ce94ca234049 Tasks: 1 successful, 1 total Cached: 0 cached, 1 total diff --git a/turborepo-tests/integration/tests/run/gitignored-inputs.t b/turborepo-tests/integration/tests/run/gitignored-inputs.t index b9cc43db657e9..5c2f835fe4230 100644 --- a/turborepo-tests/integration/tests/run/gitignored-inputs.t +++ b/turborepo-tests/integration/tests/run/gitignored-inputs.t @@ -16,7 +16,7 @@ Some helper functions to parse the summary file Just run the util package, it's simpler $ ${TURBO} run build --filter=util --output-logs=hash-only --summarize | grep "util:build: cache" - util:build: cache miss, executing 2f6ab59379ddcb93 + util:build: cache miss, executing 11cff3dd389fdfed $ FIRST=$(/bin/ls .turbo/runs/*.json | head -n1) $ echo $(getSummaryTaskId $FIRST "util#build") | jq -r '.inputs."internal.txt"' @@ -30,7 +30,7 @@ Change the content of internal.txt Hash does not change, because it is gitignored $ ${TURBO} run build --filter=util --output-logs=hash-only --summarize | grep "util:build: cache" - util:build: cache miss, executing a26c95f27f26f89c + util:build: cache miss, executing a489883a3c7cd307 The internal.txt hash should be different from the one before $ SECOND=$(/bin/ls .turbo/runs/*.json | head -n1) diff --git a/turborepo-tests/integration/tests/run/globs.t b/turborepo-tests/integration/tests/run/globs.t new file mode 100644 index 0000000000000..b4878ff6891b4 --- /dev/null +++ b/turborepo-tests/integration/tests/run/globs.t @@ -0,0 +1,39 @@ +Setup + $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh dir_globs +Verify that input directory change causes cache miss + $ ${TURBO} build --filter=util --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache miss, executing 5af1a9188f522439 + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + + $ touch packages/util/src/oops.txt + $ ${TURBO} build --filter=util --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache miss, executing 1b809be951dcbf2e + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + + $ cat packages/util/dist/hello.txt + world + $ rm packages/util/dist/hello.txt + $ ${TURBO} build --filter=util --output-logs=hash-only + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache hit, suppressing logs 1b809be951dcbf2e + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) + + $ cat packages/util/dist/hello.txt + world diff --git a/turborepo-tests/integration/tests/run/one-script-error.t b/turborepo-tests/integration/tests/run/one-script-error.t index e4c7c1db63e4a..77de8eff33d5b 100644 --- a/turborepo-tests/integration/tests/run/one-script-error.t +++ b/turborepo-tests/integration/tests/run/one-script-error.t @@ -7,13 +7,13 @@ Note that npm reports any failed script as exit code 1, even though we "exit 2" \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running error in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:okay: cache miss, executing ffe52e38e68be53e + my-app:okay: cache miss, executing 61545c7738a28273 my-app:okay: my-app:okay: > okay my-app:okay: > echo working my-app:okay: my-app:okay: working - my-app:error: cache miss, executing 8d3be716599fe376 + my-app:error: cache miss, executing fe9f1118e6072fce my-app:error: my-app:error: > error my-app:error: > exit 2 @@ -38,13 +38,13 @@ Make sure error isn't cached \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running error in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:okay: cache hit, replaying logs ffe52e38e68be53e + my-app:okay: cache hit, replaying logs 61545c7738a28273 my-app:okay: my-app:okay: > okay my-app:okay: > echo working my-app:okay: my-app:okay: working - my-app:error: cache miss, executing 8d3be716599fe376 + my-app:error: cache miss, executing fe9f1118e6072fce my-app:error: my-app:error: > error my-app:error: > exit 2 @@ -69,13 +69,13 @@ Make sure error code isn't swallowed with continue \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running okay2 in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - my-app:okay: cache hit, replaying logs ffe52e38e68be53e + my-app:okay: cache hit, replaying logs 61545c7738a28273 my-app:okay: my-app:okay: > okay my-app:okay: > echo working my-app:okay: my-app:okay: working - my-app:error: cache miss, executing 8d3be716599fe376 + my-app:error: cache miss, executing fe9f1118e6072fce my-app:error: my-app:error: > error my-app:error: > exit 2 @@ -85,7 +85,7 @@ Make sure error code isn't swallowed with continue my-app:error: npm ERR! in workspace: my-app my-app:error: npm ERR! at location: .*apps(\/|\\)my-app (re) my-app:error: command finished with error, but continuing... - my-app:okay2: cache miss, executing 13c728e793c08f30 + my-app:okay2: cache miss, executing a24768ab20e24dd3 my-app:okay2: my-app:okay2: > okay2 my-app:okay2: > echo working 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..2efd36a1e454c 100644 --- a/turborepo-tests/integration/tests/run/single-package/dry-run.t +++ b/turborepo-tests/integration/tests/run/single-package/dry-run.t @@ -7,18 +7,18 @@ Check Global Hash Inputs Global Files = 3 External Dependencies Hash = - Global Cache Key = HEY STELLLLLLLAAAAAAAAAAAAA - Global .env Files Considered = 0 + Global Cache Key = I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here (esc) Global Env Vars = Global Env Vars Values = Inferred Global Env Vars Values = Global Passed Through Env Vars = Global Passed Through Env Vars Values = + Engines Values = Tasks to Run build Task = build\s* (re) - Hash = f09bf783beacf5c9\s* (re) + Hash = 7ece7b62aad25615 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = echo building > foo.txt\s* (re) @@ -27,11 +27,10 @@ Check Dependencies =\s* (re) Dependents =\s* (re) Inputs Files Considered = 5\s* (re) - .env Files Considered = 0\s* (re) - Env Vars =\s* (re) - Env Vars Values =\s* (re) - Inferred Env Vars Values =\s* (re) - Passed Through Env Vars =\s* (re) - Passed Through Env Vars Values =\s* (re) - Resolved Task Definition = {"outputs":["foo.txt"],"cache":true,"dependsOn":[],"inputs":[],"outputMode":"full","persistent":false,"env":[],"passThroughEnv":null,"dotEnv":null,"interactive":false} - Framework =\s* (re) + Env Vars = + Env Vars Values = + Inferred Env Vars Values = + Passed Through Env Vars = + Passed Through Env Vars Values = + Resolved Task Definition = {"outputs":["foo.txt"],"cache":true,"dependsOn":[],"inputs":[],"outputLogs":"full","persistent":false,"env":[],"passThroughEnv":null,"interactive":false} + Framework = 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..a50efedaa974c 100644 --- a/turborepo-tests/integration/tests/run/single-package/no-config.t +++ b/turborepo-tests/integration/tests/run/single-package/no-config.t @@ -9,18 +9,18 @@ Check Global Hash Inputs Global Files = 2\s* (re) External Dependencies Hash =\s* (re) - Global Cache Key = HEY STELLLLLLLAAAAAAAAAAAAA\s* (re) - Global .env Files Considered = 0\s* (re) - Global Env Vars =\s* (re) - Global Env Vars Values =\s* (re) - Inferred Global Env Vars Values =\s* (re) - Global Passed Through Env Vars =\s* (re) - Global Passed Through Env Vars Values =\s* (re) + Global Cache Key = I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here (esc) + Global Env Vars = + Global Env Vars Values = + Inferred Global Env Vars Values = + Global Passed Through Env Vars = + Global Passed Through Env Vars Values = + Engines Values = Tasks to Run build Task = build\s* (re) - Hash = e46d6df5143cae99\s* (re) + Hash = e2b99dad85a4ff66 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = echo building > foo.txt\s* (re) @@ -29,14 +29,13 @@ Check Dependencies =\s* (re) Dependents =\s* (re) Inputs Files Considered = 4\s* (re) - .env Files Considered = 0\s* (re) - Env Vars =\s* (re) - Env Vars Values =\s* (re) - Inferred Env Vars Values =\s* (re) - Passed Through Env Vars =\s* (re) - Passed Through Env Vars Values =\s* (re) - Resolved Task Definition = {"outputs":[],"cache":false,"dependsOn":[],"inputs":[],"outputMode":"full","persistent":false,"env":[],"passThroughEnv":null,"dotEnv":null,"interactive":false} - Framework =\s* (re) + Env Vars = + Env Vars Values = + Inferred Env Vars Values = + Passed Through Env Vars = + Passed Through Env Vars Values = + Resolved Task Definition = {"outputs":[],"cache":false,"dependsOn":[],"inputs":[],"outputLogs":"full","persistent":false,"env":[],"passThroughEnv":null,"interactive":false} + Framework = $ ${TURBO} run build --graph @@ -52,7 +51,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 e2b99dad85a4ff66 build: build: > build build: > echo building > foo.txt @@ -66,7 +65,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 e2b99dad85a4ff66 build: build: > build build: > echo building > foo.txt diff --git a/turborepo-tests/integration/tests/run/single-package/run-yarn.t b/turborepo-tests/integration/tests/run/single-package/run-yarn.t index 8e457e1ba021f..7c304c4f084a7 100644 --- a/turborepo-tests/integration/tests/run/single-package/run-yarn.t +++ b/turborepo-tests/integration/tests/run/single-package/run-yarn.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 c1d6153f4a6d83b5 + build: cache miss, executing a6fef17cc2efc81c build: yarn run v1.22.17 build: warning package.json: No license field build: $ echo building > foo.txt @@ -18,7 +18,7 @@ Check $ ${TURBO} run build \xe2\x80\xa2 Running build (esc) \xe2\x80\xa2 Remote caching disabled (esc) - build: cache hit, replaying logs c1d6153f4a6d83b5 + build: cache hit, replaying logs a6fef17cc2efc81c build: yarn run v1.22.17 build: warning package.json: No license field build: $ echo building > foo.txt @@ -27,4 +27,4 @@ Check Tasks: 1 successful, 1 total Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) - \ No newline at end of file + diff --git a/turborepo-tests/integration/tests/run/single-package/run.t b/turborepo-tests/integration/tests/run/single-package/run.t index 65ab3cddf1d8d..26e7e3b09e7d8 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 7ece7b62aad25615 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 7ece7b62aad25615 build: build: > build build: > echo building > foo.txt @@ -31,4 +31,4 @@ Run a second time, verify caching works because there is a config Tasks: 1 successful, 1 total Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) - \ No newline at end of file + 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..3c5e504cfd537 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 @@ -7,18 +7,18 @@ Check Global Hash Inputs Global Files = 3 External Dependencies Hash = - Global Cache Key = HEY STELLLLLLLAAAAAAAAAAAAA - Global .env Files Considered = 0 + Global Cache Key = I can\xe2\x80\x99t see ya, but I know you\xe2\x80\x99re here (esc) Global Env Vars = Global Env Vars Values = Inferred Global Env Vars Values = Global Passed Through Env Vars = Global Passed Through Env Vars Values = + Engines Values = Tasks to Run build Task = build\s* (re) - Hash = f09bf783beacf5c9\s* (re) + Hash = 7ece7b62aad25615 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = echo building > foo.txt\s* (re) @@ -27,17 +27,16 @@ Check Dependencies =\s* (re) Dependents = test\s* (re) Inputs Files Considered = 5\s* (re) - .env Files Considered = 0\s* (re) - Env Vars =\s* (re) - Env Vars Values =\s* (re) - Inferred Env Vars Values =\s* (re) - Passed Through Env Vars =\s* (re) - Passed Through Env Vars Values =\s* (re) - Resolved Task Definition = {"outputs":["foo.txt"],"cache":true,"dependsOn":[],"inputs":[],"outputMode":"full","persistent":false,"env":[],"passThroughEnv":null,"dotEnv":null,"interactive":false} - Framework =\s* (re) + Env Vars = + Env Vars Values = + Inferred Env Vars Values = + Passed Through Env Vars = + Passed Through Env Vars Values = + Resolved Task Definition = {"outputs":["foo.txt"],"cache":true,"dependsOn":[],"inputs":[],"outputLogs":"full","persistent":false,"env":[],"passThroughEnv":null,"interactive":false} + Framework = test Task = test\s* (re) - Hash = 8bfab5dc6b4ccb3b\s* (re) + Hash = cb5839f7284aa5f3 Cached \(Local\) = false\s* (re) Cached \(Remote\) = false\s* (re) Command = cat foo.txt\s* (re) @@ -46,11 +45,10 @@ Check Dependencies = build\s* (re) Dependents =\s* (re) Inputs Files Considered = 5\s* (re) - .env Files Considered = 0\s* (re) - Env Vars =\s* (re) - Env Vars Values =\s* (re) - Inferred Env Vars Values =\s* (re) - Passed Through Env Vars =\s* (re) - Passed Through Env Vars Values =\s* (re) - Resolved Task Definition = {"outputs":[],"cache":true,"dependsOn":["build"],"inputs":[],"outputMode":"full","persistent":false,"env":[],"passThroughEnv":null,"dotEnv":null,"interactive":false} - Framework =\s* (re) + Env Vars = + Env Vars Values = + Inferred Env Vars Values = + Passed Through Env Vars = + Passed Through Env Vars Values = + Resolved Task Definition = {"outputs":[],"cache":true,"dependsOn":["build"],"inputs":[],"outputLogs":"full","persistent":false,"env":[],"passThroughEnv":null,"interactive":false} + Framework = 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..0050f76b42fcf 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 7ece7b62aad25615 build: build: > build build: > echo building > foo.txt build: - test: cache miss, executing 8bfab5dc6b4ccb3b + test: cache miss, executing cb5839f7284aa5f3 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 7ece7b62aad25615 build: build: > build build: > echo building > foo.txt build: - test: cache hit, replaying logs 8bfab5dc6b4ccb3b + test: cache hit, replaying logs cb5839f7284aa5f3 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 7ece7b62aad25615 + test: cache hit, suppressing logs cb5839f7284aa5f3 Tasks: 2 successful, 2 total Cached: 2 cached, 2 total diff --git a/turborepo-tests/integration/tests/strict-env-vars/usage-infer.t b/turborepo-tests/integration/tests/strict-env-vars/usage-infer.t deleted file mode 100644 index f9dcb5180115f..0000000000000 --- a/turborepo-tests/integration/tests/strict-env-vars/usage-infer.t +++ /dev/null @@ -1,44 +0,0 @@ -Setup - $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh strict_env_vars - -With --env-mode=infer - -Set the env vars - $ export GLOBAL_VAR_PT=higlobalpt - $ export GLOBAL_VAR_DEP=higlobaldep - $ export LOCAL_VAR_PT=hilocalpt - $ export LOCAL_VAR_DEP=hilocaldep - $ export OTHER_VAR=hiother - -Set the output file with the right path separator for the OS - $ if [[ "$OSTYPE" == "msys" ]]; then OUTPUT="apps\\my-app\\out.txt"; else OUTPUT="apps/my-app/out.txt"; fi - -Conditionally set these vars if they aren't already there for the purpose of the test. -The test doesn't care about the values, it just checks that the var is available to the task -so we just have to make sure the parent process has them set. In Github CI, for example SHELL -isn't already set. - $ export SYSTEMROOT="${SYSTEMROOT:=hisysroot}" - $ export PATH="${PATH:=hipath}" - -Inferred mode as loose because no pass through configs, all vars are available - $ ${TURBO} build -vv --env-mode=infer > /dev/null 2>&1 - $ cat "$OUTPUT" - globalpt: 'higlobalpt', localpt: 'hilocalpt', globaldep: 'higlobaldep', localdep: 'hilocaldep', other: 'hiother', sysroot set: 'yes', path set: 'yes' - -Inferred mode as strict, because global pass through config, no vars available - $ ${TESTDIR}/../../../helpers/replace_turbo_json.sh $(pwd) "strict_env_vars/global_pt-empty.json" - $ ${TURBO} build -vv --env-mode=infer > /dev/null 2>&1 - $ cat "$OUTPUT" - globalpt: '', localpt: '', globaldep: '', localdep: '', other: '', sysroot set: 'yes', path set: 'yes' - -Inferred mode as strict, because task pass through config, no vars available - $ ${TESTDIR}/../../../helpers/replace_turbo_json.sh $(pwd) "strict_env_vars/task_pt-empty.json" - $ ${TURBO} build -vv --env-mode=infer > /dev/null 2>&1 - $ cat "$OUTPUT" - globalpt: '', localpt: '', globaldep: '', localdep: '', other: '', sysroot set: 'yes', path set: 'yes' - -Inferred mode as strict, with declared deps and pass through. all declared available, other is not available - $ ${TESTDIR}/../../../helpers/replace_turbo_json.sh $(pwd) "strict_env_vars/all.json" - $ ${TURBO} build -vv --env-mode=infer > /dev/null 2>&1 - $ cat "$OUTPUT" - globalpt: 'higlobalpt', localpt: 'hilocalpt', globaldep: 'higlobaldep', localdep: 'hilocaldep', other: '', sysroot set: 'yes', path set: 'yes' diff --git a/turborepo-tests/integration/tests/task-dependencies/overwriting.t b/turborepo-tests/integration/tests/task-dependencies/overwriting.t index 963551aad0ace..555833f1733f6 100644 --- a/turborepo-tests/integration/tests/task-dependencies/overwriting.t +++ b/turborepo-tests/integration/tests/task-dependencies/overwriting.t @@ -11,7 +11,7 @@ Test # workspace-a#generate ran $ cat tmp.log | grep "workspace-a:generate" - workspace-a:generate: cache miss, executing b876a84c09681ba1 + workspace-a:generate: cache miss, executing 9177da2f682aeeb7 workspace-a:generate: workspace-a:generate: > generate workspace-a:generate: > echo generate-workspace-a @@ -19,7 +19,7 @@ Test workspace-a:generate: generate-workspace-a workspace-a#build ran $ cat tmp.log | grep "workspace-a:build" - workspace-a:build: cache miss, executing 264da930a689be4e + workspace-a:build: cache miss, executing f6fe0ec4a3ecb04b workspace-a:build: workspace-a:build: > build workspace-a:build: > echo build-workspace-a @@ -32,7 +32,7 @@ workspace-b#generate DID NOT run workspace-b#build ran $ cat tmp.log | grep "workspace-b:build" - workspace-b:build: cache miss, executing 36137fdec800ec2e + workspace-b:build: cache miss, executing b0cbf81d4cce38a4 workspace-b:build: workspace-b:build: > build workspace-b:build: > echo build-workspace-b diff --git a/turborepo-tests/integration/tests/task-dependencies/root-worksapce.t b/turborepo-tests/integration/tests/task-dependencies/root-workspace.t similarity index 85% rename from turborepo-tests/integration/tests/task-dependencies/root-worksapce.t rename to turborepo-tests/integration/tests/task-dependencies/root-workspace.t index 48ece27d58c76..7ee31d3c99a52 100644 --- a/turborepo-tests/integration/tests/task-dependencies/root-worksapce.t +++ b/turborepo-tests/integration/tests/task-dependencies/root-workspace.t @@ -5,13 +5,13 @@ This tests asserts that root tasks can depend on workspace#task \xe2\x80\xa2 Packages in scope: //, lib-a (esc) \xe2\x80\xa2 Running mytask in 2 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - lib-a:build: cache miss, executing 5f3e63ff10e1a66a + lib-a:build: cache miss, executing eddc59f63124ca26 lib-a:build: lib-a:build: > build 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 82474628cac2e34c //:mytask: //:mytask: > mytask //:mytask: > echo root-mytask @@ -21,4 +21,4 @@ This tests asserts that root tasks can depend on workspace#task Tasks: 2 successful, 2 total Cached: 0 cached, 2 total Time:\s*[\.0-9ms]+ (re) - \ No newline at end of file + diff --git a/turborepo-tests/integration/tests/task-dependencies/topological.t b/turborepo-tests/integration/tests/task-dependencies/topological.t index ff70327105e2c..41543406c3ab3 100644 --- a/turborepo-tests/integration/tests/task-dependencies/topological.t +++ b/turborepo-tests/integration/tests/task-dependencies/topological.t @@ -6,13 +6,13 @@ Check my-app#build output \xe2\x80\xa2 Packages in scope: //, my-app, util (esc) \xe2\x80\xa2 Running build in 3 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - util:build: cache miss, executing d8a403c3594c01e7 + util:build: cache miss, executing 3d1f83b683510099 util:build: util:build: > build util:build: > echo building util:build: util:build: building - my-app:build: cache miss, executing 6f5a797f7b88130e + my-app:build: cache miss, executing a24fb33a97cce572 my-app:build: my-app:build: > build my-app:build: > echo building diff --git a/turborepo-tests/integration/tests/turbo-help.t b/turborepo-tests/integration/tests/turbo-help.t index 2757b18eb130d..5f7dc4661101a 100644 --- a/turborepo-tests/integration/tests/turbo-help.t +++ b/turborepo-tests/integration/tests/turbo-help.t @@ -28,7 +28,6 @@ Test help flag --no-update-notifier Disable the turbo update notification --api Override the endpoint for API calls --color Force color usage in the terminal - --cpuprofile Specify a file to save a cpu profile --cwd The directory in which to run turbo --heap Specify a file to save a pprof heap profile --login Override the login endpoint @@ -77,19 +76,9 @@ Test help flag --global-deps Specify glob of global filesystem dependencies to be hashed. Useful for .env and files --env-mode [] - Environment variable mode. Use "loose" to pass the entire existing environment. Use "strict" to use an allowlist specified in turbo.json. Use "infer" to defer to existence of "passThroughEnv" or "globalPassThroughEnv" in turbo.json. (default infer) [default: infer] [possible values: infer, loose, strict] + Environment variable mode. Use "loose" to pass the entire existing environment. Use "strict" to use an allowlist specified in turbo.json [default: strict] [possible values: loose, strict] -F, --filter Use the given selector to specify package(s) to act as entry points. The syntax mirrors pnpm's syntax, and additional documentation and examples can be found in turbo's documentation https://turbo.build/repo/docs/reference/command-line-reference/run#--filter - --scope - DEPRECATED: Specify package(s) to act as entry points for task execution. Supports globs - --ignore - Files to ignore when calculating changed files from '--filter'. Supports globs - --since - DEPRECATED: Limit/Set scope to changed packages since a mergebase. This uses the git diff ${target_branch}... mechanism to identify which packages have changed - --include-dependencies - DEPRECATED: Include the dependencies of tasks in execution - --no-deps - DEPRECATED: Exclude dependent task consumers from execution --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only] --log-order @@ -132,7 +121,6 @@ Test help flag --no-update-notifier Disable the turbo update notification --api Override the endpoint for API calls --color Force color usage in the terminal - --cpuprofile Specify a file to save a cpu profile --cwd The directory in which to run turbo --heap Specify a file to save a pprof heap profile --login Override the login endpoint @@ -181,19 +169,9 @@ Test help flag --global-deps Specify glob of global filesystem dependencies to be hashed. Useful for .env and files --env-mode [] - Environment variable mode. Use "loose" to pass the entire existing environment. Use "strict" to use an allowlist specified in turbo.json. Use "infer" to defer to existence of "passThroughEnv" or "globalPassThroughEnv" in turbo.json. (default infer) [default: infer] [possible values: infer, loose, strict] + Environment variable mode. Use "loose" to pass the entire existing environment. Use "strict" to use an allowlist specified in turbo.json [default: strict] [possible values: loose, strict] -F, --filter Use the given selector to specify package(s) to act as entry points. The syntax mirrors pnpm's syntax, and additional documentation and examples can be found in turbo's documentation https://turbo.build/repo/docs/reference/command-line-reference/run#--filter - --scope - DEPRECATED: Specify package(s) to act as entry points for task execution. Supports globs - --ignore - Files to ignore when calculating changed files from '--filter'. Supports globs - --since - DEPRECATED: Limit/Set scope to changed packages since a mergebase. This uses the git diff ${target_branch}... mechanism to identify which packages have changed - --include-dependencies - DEPRECATED: Include the dependencies of tasks in execution - --no-deps - DEPRECATED: Exclude dependent task consumers from execution --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only] --log-order @@ -219,7 +197,6 @@ Test help flag for link command --no-update-notifier Disable the turbo update notification --api Override the endpoint for API calls --color Force color usage in the terminal - --cpuprofile Specify a file to save a cpu profile --cwd The directory in which to run turbo --heap Specify a file to save a pprof heap profile --login Override the login endpoint @@ -245,7 +222,6 @@ Test help flag for unlink command --no-update-notifier Disable the turbo update notification --api Override the endpoint for API calls --color Force color usage in the terminal - --cpuprofile Specify a file to save a cpu profile --cwd The directory in which to run turbo --heap Specify a file to save a pprof heap profile --login Override the login endpoint @@ -272,7 +248,6 @@ Test help flag for login command --no-update-notifier Disable the turbo update notification --api Override the endpoint for API calls --color Force color usage in the terminal - --cpuprofile Specify a file to save a cpu profile --cwd The directory in which to run turbo --heap Specify a file to save a pprof heap profile --login Override the login endpoint @@ -298,7 +273,6 @@ Test help flag for logout command --no-update-notifier Disable the turbo update notification --api Override the endpoint for API calls --color Force color usage in the terminal - --cpuprofile Specify a file to save a cpu profile --cwd The directory in which to run turbo --heap Specify a file to save a pprof heap profile --login Override the login endpoint diff --git a/turborepo-tests/integration/tests/workspace-configs/add-keys.t b/turborepo-tests/integration/tests/workspace-configs/add-keys.t index 2781e27a04dc5..db2141c3e5d2c 100644 --- a/turborepo-tests/integration/tests/workspace-configs/add-keys.t +++ b/turborepo-tests/integration/tests/workspace-configs/add-keys.t @@ -4,7 +4,7 @@ Setup # The add-keys-task in the root turbo.json has no config. This test: # [x] Tests dependsOn works by asserting that another task runs first # [x] Tests outputs works by asserting that the right directory is cached -# [x] Tests outputMode by asserting output logs on a second run +# [x] Tests outputLogs by asserting output logs on a second run # [x] Tests inputs works by changing a file and testing there was a cache miss # [x] Tests env works by setting an env var and asserting there was a cache miss @@ -14,13 +14,13 @@ Setup \xe2\x80\xa2 Packages in scope: add-keys (esc) \xe2\x80\xa2 Running add-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - add-keys:add-keys-underlying-task: cache miss, executing 55e98f0525c841a1 + add-keys:add-keys-underlying-task: cache miss, executing 1ce848eeaff2dbd4 add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: > add-keys-underlying-task add-keys:add-keys-underlying-task: > echo running-add-keys-underlying-task add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: running-add-keys-underlying-task - add-keys:add-keys-task: cache miss, executing e3ec4997fd41f641 + add-keys:add-keys-task: cache miss, executing b16339834937fd9e add-keys:add-keys-task: add-keys:add-keys-task: > add-keys-task add-keys:add-keys-task: > echo running-add-keys-task > out/foo.min.txt @@ -31,24 +31,24 @@ Setup Time:\s*[\.0-9]+m?s (re) $ HASH=$(cat tmp.log | grep -E "add-keys:add-keys-task.* executing .*" | awk '{print $5}') - $ tar -tf $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ tar -tf $TARGET_DIR/.turbo/cache/$HASH.tar.zst; apps/add-keys/.turbo/turbo-add-keys-task.log apps/add-keys/out/ apps/add-keys/out/.keep apps/add-keys/out/foo.min.txt -# 2. Second run, test there was a cache hit (`cache` config`) and `output` was suppressed (`outputMode`) +# 2. Second run, test there was a cache hit (`cache` config`) and `output` was suppressed (`outputLogs`) $ ${TURBO} run add-keys-task --filter=add-keys \xe2\x80\xa2 Packages in scope: add-keys (esc) \xe2\x80\xa2 Running add-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - add-keys:add-keys-underlying-task: cache hit, replaying logs 55e98f0525c841a1 + add-keys:add-keys-underlying-task: cache hit, replaying logs 1ce848eeaff2dbd4 add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: > add-keys-underlying-task add-keys:add-keys-underlying-task: > echo running-add-keys-underlying-task add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: running-add-keys-underlying-task - add-keys:add-keys-task: cache hit, suppressing logs e3ec4997fd41f641 + add-keys:add-keys-task: cache hit, suppressing logs b16339834937fd9e Tasks: 2 successful, 2 total Cached: 2 cached, 2 total @@ -60,13 +60,13 @@ Setup \xe2\x80\xa2 Packages in scope: add-keys (esc) \xe2\x80\xa2 Running add-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - add-keys:add-keys-underlying-task: cache miss, executing ba55d98f67b27080 + add-keys:add-keys-underlying-task: cache miss, executing 8a894e7cb2c0a1ea add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: > add-keys-underlying-task add-keys:add-keys-underlying-task: > echo running-add-keys-underlying-task add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: running-add-keys-underlying-task - add-keys:add-keys-task: cache miss, executing bca4da3171622882 + add-keys:add-keys-task: cache miss, executing df66730da80eec8e add-keys:add-keys-task: add-keys:add-keys-task: > add-keys-task add-keys:add-keys-task: > echo running-add-keys-task > out/foo.min.txt @@ -81,13 +81,13 @@ Setup \xe2\x80\xa2 Packages in scope: add-keys (esc) \xe2\x80\xa2 Running add-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - add-keys:add-keys-underlying-task: cache hit, replaying logs ba55d98f67b27080 + add-keys:add-keys-underlying-task: cache hit, replaying logs 8a894e7cb2c0a1ea add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: > add-keys-underlying-task add-keys:add-keys-underlying-task: > echo running-add-keys-underlying-task add-keys:add-keys-underlying-task: add-keys:add-keys-underlying-task: running-add-keys-underlying-task - add-keys:add-keys-task: cache miss, executing 2249c12778c3ef7b + add-keys:add-keys-task: cache miss, executing 96c5e85515972df5 add-keys:add-keys-task: add-keys:add-keys-task: > add-keys-task add-keys:add-keys-task: > echo running-add-keys-task > out/foo.min.txt diff --git a/turborepo-tests/integration/tests/workspace-configs/add-tasks.t b/turborepo-tests/integration/tests/workspace-configs/add-tasks.t index 8728b21349f9e..a01e287e71d08 100644 --- a/turborepo-tests/integration/tests/workspace-configs/add-tasks.t +++ b/turborepo-tests/integration/tests/workspace-configs/add-tasks.t @@ -5,7 +5,7 @@ Setup \xe2\x80\xa2 Packages in scope: add-tasks (esc) \xe2\x80\xa2 Running added-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - add-tasks:added-task: cache miss, executing 79780b288549784d + add-tasks:added-task: cache miss, executing 0c8333ca7685d45f add-tasks:added-task: add-tasks:added-task: > added-task add-tasks:added-task: > echo running-added-task > out/foo.min.txt @@ -14,4 +14,4 @@ Setup Tasks: 1 successful, 1 total Cached: 0 cached, 1 total Time:\s+[.0-9]+m?s (re) - \ No newline at end of file + diff --git a/turborepo-tests/integration/tests/workspace-configs/bad-json.t b/turborepo-tests/integration/tests/workspace-configs/bad-json.t index 73a547ae5790e..7081aa1dfb632 100644 --- a/turborepo-tests/integration/tests/workspace-configs/bad-json.t +++ b/turborepo-tests/integration/tests/workspace-configs/bad-json.t @@ -2,7 +2,7 @@ Setup $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh composable_config # Put some bad JSON into the turbo.json in this app - $ echo '{"pipeline": {"trailing-comma": {},}}' > "$TARGET_DIR/apps/bad-json/turbo.json" + $ echo '{"tasks": {"trailing-comma": {},}}' > "$TARGET_DIR/apps/bad-json/turbo.json" # The test is greping from a logfile because the list of errors can appear in any order # Errors are shown if we run across a malformed turbo.json diff --git a/turborepo-tests/integration/tests/workspace-configs/cache.t b/turborepo-tests/integration/tests/workspace-configs/cache.t index 22076afe2135f..6674829b25d04 100644 --- a/turborepo-tests/integration/tests/workspace-configs/cache.t +++ b/turborepo-tests/integration/tests/workspace-configs/cache.t @@ -13,7 +13,7 @@ This test covers: \xe2\x80\xa2 Packages in scope: cached (esc) \xe2\x80\xa2 Running cached-task-1 in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - cached:cached-task-1: cache miss, executing 21346f9dc1d8f091 + cached:cached-task-1: cache miss, executing da2166fcfd7b56bd cached:cached-task-1: cached:cached-task-1: > cached-task-1 cached:cached-task-1: > echo cached-task-1 > out/foo.min.txt @@ -26,7 +26,7 @@ This test covers: $ HASH=$(cat tmp.log | grep -E "cached:cached-task-1.* executing .*" | awk '{print $5}') $ echo $HASH [a-z0-9]{16} (re) - $ tar -tf $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ tar -tf $TARGET_DIR/.turbo/cache/$HASH.tar.zst; apps/cached/.turbo/turbo-cached-task-1.log apps/cached/out/ apps/cached/out/.keep @@ -38,7 +38,7 @@ This test covers: \xe2\x80\xa2 Packages in scope: cached (esc) \xe2\x80\xa2 Running cached-task-2 in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - cached:cached-task-2: cache bypass, force executing bf7e4ca31119a2ca + cached:cached-task-2: cache bypass, force executing e42e6c8e2ae6a672 cached:cached-task-2: cached:cached-task-2: > cached-task-2 cached:cached-task-2: > echo cached-task-2 > out/foo.min.txt @@ -51,7 +51,7 @@ This test covers: $ HASH=$(cat tmp.log | grep -E "cached:cached-task-2.* executing .*" | awk '{print $6}') $ echo $HASH [a-z0-9]{16} (re) - $ test -f $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ test -f $TARGET_DIR/.turbo/cache/$HASH.tar.zst; [1] no `cache` config in root, cache:false in workspace @@ -60,7 +60,7 @@ no `cache` config in root, cache:false in workspace \xe2\x80\xa2 Packages in scope: cached (esc) \xe2\x80\xa2 Running cached-task-3 in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - cached:cached-task-3: cache bypass, force executing 5a6c15882980e64c + cached:cached-task-3: cache bypass, force executing 86ce94afb18567d7 cached:cached-task-3: cached:cached-task-3: > cached-task-3 cached:cached-task-3: > echo cached-task-3 > out/foo.min.txt @@ -73,7 +73,7 @@ no `cache` config in root, cache:false in workspace $ HASH=$(cat tmp.log | grep -E "cached:cached-task-3.* executing .*" | awk '{print $6}') $ echo $HASH [a-z0-9]{16} (re) - $ test -f $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ test -f $TARGET_DIR/.turbo/cache/$HASH.tar.zst; [1] cache:false in root, no turbo.json in workspace. @@ -84,7 +84,7 @@ we already have a workspace that doesn't have a config \xe2\x80\xa2 Packages in scope: missing-workspace-config (esc) \xe2\x80\xa2 Running cached-task-4 in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - missing-workspace-config:cached-task-4: cache bypass, force executing 0876b71b756eb6da + missing-workspace-config:cached-task-4: cache bypass, force executing f164838b2fe93185 missing-workspace-config:cached-task-4: missing-workspace-config:cached-task-4: > cached-task-4 missing-workspace-config:cached-task-4: > echo cached-task-4 > out/foo.min.txt @@ -97,5 +97,5 @@ we already have a workspace that doesn't have a config $ HASH=$(cat tmp.log | grep -E "missing-workspace-config:cached-task-4.* executing .*" | awk '{print $6}') $ echo $HASH [a-z0-9]{16} (re) - $ test -f $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ test -f $TARGET_DIR/.turbo/cache/$HASH.tar.zst; [1] diff --git a/turborepo-tests/integration/tests/workspace-configs/config-change.t b/turborepo-tests/integration/tests/workspace-configs/config-change.t index 4312c38045cb6..0ebb2528ea4cd 100644 --- a/turborepo-tests/integration/tests/workspace-configs/config-change.t +++ b/turborepo-tests/integration/tests/workspace-configs/config-change.t @@ -3,13 +3,13 @@ Setup # 1. First run, check the hash $ ${TURBO} run config-change-task --filter=config-change --dry=json | jq .tasks[0].hash - "58fafdfda3030039" + "4fbfb44c77d14468" 2. Run again and assert task hash stays the same $ ${TURBO} run config-change-task --filter=config-change --dry=json | jq .tasks[0].hash - "58fafdfda3030039" + "4fbfb44c77d14468" 3. Change turbo.json and assert that hash changes $ cp $TARGET_DIR/apps/config-change/turbo-changed.json $TARGET_DIR/apps/config-change/turbo.json $ ${TURBO} run config-change-task --filter=config-change --dry=json | jq .tasks[0].hash - "5c193e0718f3a05b" + "01e59b7f88f8a211" diff --git a/turborepo-tests/integration/tests/workspace-configs/cross-workspace.t b/turborepo-tests/integration/tests/workspace-configs/cross-workspace.t index 9b2592839bad4..17af56d6dabe9 100644 --- a/turborepo-tests/integration/tests/workspace-configs/cross-workspace.t +++ b/turborepo-tests/integration/tests/workspace-configs/cross-workspace.t @@ -4,13 +4,13 @@ Setup \xe2\x80\xa2 Packages in scope: cross-workspace (esc) \xe2\x80\xa2 Running cross-workspace-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - blank-pkg:cross-workspace-underlying-task: cache miss, executing 13256295c40d6836 + blank-pkg:cross-workspace-underlying-task: cache miss, executing 39566f6362976823 blank-pkg:cross-workspace-underlying-task: blank-pkg:cross-workspace-underlying-task: > cross-workspace-underlying-task blank-pkg:cross-workspace-underlying-task: > echo cross-workspace-underlying-task from blank-pkg blank-pkg:cross-workspace-underlying-task: blank-pkg:cross-workspace-underlying-task: cross-workspace-underlying-task from blank-pkg - cross-workspace:cross-workspace-task: cache miss, executing f386c2eceecb7035 + cross-workspace:cross-workspace-task: cache miss, executing bce507a110930f07 cross-workspace:cross-workspace-task: cross-workspace:cross-workspace-task: > cross-workspace-task cross-workspace:cross-workspace-task: > echo cross-workspace-task diff --git a/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config-deps.t b/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config-deps.t index 1ae76b8d680f5..5f7f521c27028 100644 --- a/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config-deps.t +++ b/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config-deps.t @@ -15,14 +15,14 @@ Setup \xe2\x80\xa2 Remote caching disabled (esc) $ cat tmp.log | grep "missing-workspace-config:missing-workspace-config-task-with-deps" - missing-workspace-config:missing-workspace-config-task-with-deps: cache miss, executing cb5a7b7c7ef29b91 + missing-workspace-config:missing-workspace-config-task-with-deps: cache miss, executing 27111702ff2c516b missing-workspace-config:missing-workspace-config-task-with-deps: missing-workspace-config:missing-workspace-config-task-with-deps: > missing-workspace-config-task-with-deps missing-workspace-config:missing-workspace-config-task-with-deps: > echo running-missing-workspace-config-task-with-deps > out/foo.min.txt missing-workspace-config:missing-workspace-config-task-with-deps: $ cat tmp.log | grep "missing-workspace-config:missing-workspace-config-underlying-task" - missing-workspace-config:missing-workspace-config-underlying-task: cache miss, executing 26878c99d9f1f2ad + missing-workspace-config:missing-workspace-config-underlying-task: cache miss, executing abd612282d80ada6 missing-workspace-config:missing-workspace-config-underlying-task: missing-workspace-config:missing-workspace-config-underlying-task: > missing-workspace-config-underlying-task missing-workspace-config:missing-workspace-config-underlying-task: > echo running-missing-workspace-config-underlying-task @@ -30,7 +30,7 @@ Setup missing-workspace-config:missing-workspace-config-underlying-task: running-missing-workspace-config-underlying-task $ cat tmp.log | grep "blank-pkg:missing-workspace-config-underlying-topo-task" - blank-pkg:missing-workspace-config-underlying-topo-task: cache miss, executing 86d7535cfbce352a + blank-pkg:missing-workspace-config-underlying-topo-task: cache miss, executing 9cc1b75893929720 blank-pkg:missing-workspace-config-underlying-topo-task: blank-pkg:missing-workspace-config-underlying-topo-task: > missing-workspace-config-underlying-topo-task blank-pkg:missing-workspace-config-underlying-topo-task: > echo missing-workspace-config-underlying-topo-task from blank-pkg diff --git a/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config.t b/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config.t index c4cbae18966ac..2b914c0b42bcc 100644 --- a/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config.t +++ b/turborepo-tests/integration/tests/workspace-configs/missing-workspace-config.t @@ -11,7 +11,7 @@ Setup \xe2\x80\xa2 Packages in scope: missing-workspace-config (esc) \xe2\x80\xa2 Running missing-workspace-config-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - missing-workspace-config:missing-workspace-config-task: cache miss, executing fa2b3189d6b42055 + missing-workspace-config:missing-workspace-config-task: cache miss, executing 924463dcfeefce9e missing-workspace-config:missing-workspace-config-task: missing-workspace-config:missing-workspace-config-task: > missing-workspace-config-task missing-workspace-config:missing-workspace-config-task: > echo running-missing-workspace-config-task > out/foo.min.txt @@ -22,7 +22,7 @@ Setup Time:\s*[\.0-9]+m?s (re) $ HASH=$(cat tmp.log | grep -E "missing-workspace-config:missing-workspace-config-task.* executing .*" | awk '{print $5}') - $ tar -tf $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ tar -tf $TARGET_DIR/.turbo/cache/$HASH.tar.zst; apps/missing-workspace-config/.turbo/turbo-missing-workspace-config-task.log apps/missing-workspace-config/out/ apps/missing-workspace-config/out/.keep @@ -33,7 +33,7 @@ Setup \xe2\x80\xa2 Packages in scope: missing-workspace-config (esc) \xe2\x80\xa2 Running missing-workspace-config-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - missing-workspace-config:missing-workspace-config-task: cache hit, suppressing logs fa2b3189d6b42055 + missing-workspace-config:missing-workspace-config-task: cache hit, suppressing logs 924463dcfeefce9e Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -45,7 +45,7 @@ Setup \xe2\x80\xa2 Packages in scope: missing-workspace-config (esc) \xe2\x80\xa2 Running missing-workspace-config-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - missing-workspace-config:missing-workspace-config-task: cache miss, executing 2fcb67955fb2c7b7 + missing-workspace-config:missing-workspace-config-task: cache miss, executing 6393b168ee1654c5 missing-workspace-config:missing-workspace-config-task: missing-workspace-config:missing-workspace-config-task: > missing-workspace-config-task missing-workspace-config:missing-workspace-config-task: > echo running-missing-workspace-config-task > out/foo.min.txt @@ -62,7 +62,7 @@ Setup \xe2\x80\xa2 Packages in scope: missing-workspace-config (esc) \xe2\x80\xa2 Running missing-workspace-config-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - missing-workspace-config:missing-workspace-config-task: cache hit, suppressing logs 2fcb67955fb2c7b7 + missing-workspace-config:missing-workspace-config-task: cache hit, suppressing logs 6393b168ee1654c5 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -73,7 +73,7 @@ Setup \xe2\x80\xa2 Packages in scope: missing-workspace-config (esc) \xe2\x80\xa2 Running missing-workspace-config-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - missing-workspace-config:missing-workspace-config-task: cache miss, executing 3ad30dba93a44cfc + missing-workspace-config:missing-workspace-config-task: cache miss, executing e70657c42c4e2edb missing-workspace-config:missing-workspace-config-task: missing-workspace-config:missing-workspace-config-task: > missing-workspace-config-task missing-workspace-config:missing-workspace-config-task: > echo running-missing-workspace-config-task > out/foo.min.txt @@ -89,7 +89,7 @@ Setup \xe2\x80\xa2 Packages in scope: missing-workspace-config (esc) \xe2\x80\xa2 Running cached-task-4 in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - missing-workspace-config:cached-task-4: cache bypass, force executing a3402b79e54983c6 + missing-workspace-config:cached-task-4: cache bypass, force executing 95ba5489441bdc13 missing-workspace-config:cached-task-4: missing-workspace-config:cached-task-4: > cached-task-4 missing-workspace-config:cached-task-4: > echo cached-task-4 > out/foo.min.txt @@ -102,5 +102,5 @@ Setup $ HASH=$(cat tmp.log | grep -E "missing-workspace-config:cached-task-4.* executing .*" | awk '{print $6}') $ echo $HASH [a-z0-9]{16} (re) - $ test -f $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ test -f $TARGET_DIR/.turbo/cache/$HASH.tar.zst; [1] diff --git a/turborepo-tests/integration/tests/workspace-configs/omit-keys-deps.t b/turborepo-tests/integration/tests/workspace-configs/omit-keys-deps.t index c229c3bc5a125..1486678c3ab0b 100644 --- a/turborepo-tests/integration/tests/workspace-configs/omit-keys-deps.t +++ b/turborepo-tests/integration/tests/workspace-configs/omit-keys-deps.t @@ -15,14 +15,14 @@ Setup \xe2\x80\xa2 Running omit-keys-task-with-deps in 1 packages (esc) $ cat tmp.log | grep "omit-keys:omit-keys-task-with-deps" - omit-keys:omit-keys-task-with-deps: cache miss, executing 9a01368558ebb03f + omit-keys:omit-keys-task-with-deps: cache miss, executing bbb54c4130d16663 omit-keys:omit-keys-task-with-deps: omit-keys:omit-keys-task-with-deps: > omit-keys-task-with-deps omit-keys:omit-keys-task-with-deps: > echo running-omit-keys-task-with-deps > out/foo.min.txt omit-keys:omit-keys-task-with-deps: $ cat tmp.log | grep "omit-keys:omit-keys-underlying-task" - omit-keys:omit-keys-underlying-task: cache miss, executing a2db581d4cbbd3d6 + omit-keys:omit-keys-underlying-task: cache miss, executing 1aa42011f41a10f1 omit-keys:omit-keys-underlying-task: omit-keys:omit-keys-underlying-task: > omit-keys-underlying-task omit-keys:omit-keys-underlying-task: > echo running-omit-keys-underlying-task @@ -30,7 +30,7 @@ Setup omit-keys:omit-keys-underlying-task: running-omit-keys-underlying-task $ cat tmp.log | grep "blank-pkg:omit-keys-underlying-topo-task" - blank-pkg:omit-keys-underlying-topo-task: cache miss, executing e14022a5380dbf76 + blank-pkg:omit-keys-underlying-topo-task: cache miss, executing 4510d84de8b1d9b7 blank-pkg:omit-keys-underlying-topo-task: blank-pkg:omit-keys-underlying-topo-task: > omit-keys-underlying-topo-task blank-pkg:omit-keys-underlying-topo-task: > echo omit-keys-underlying-topo-task from blank-pkg @@ -43,7 +43,7 @@ Setup Time:\s*[\.0-9]+m?s (re) $ HASH=$(cat tmp.log | grep -E "omit-keys:omit-keys-task-with-deps.* executing .*" | awk '{print $5}') - $ tar -tf $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ tar -tf $TARGET_DIR/.turbo/cache/$HASH.tar.zst; apps/omit-keys/.turbo/turbo-omit-keys-task-with-deps.log apps/omit-keys/out/ apps/omit-keys/out/.keep diff --git a/turborepo-tests/integration/tests/workspace-configs/omit-keys.t b/turborepo-tests/integration/tests/workspace-configs/omit-keys.t index 939676a78a083..aae9c5c4ec646 100644 --- a/turborepo-tests/integration/tests/workspace-configs/omit-keys.t +++ b/turborepo-tests/integration/tests/workspace-configs/omit-keys.t @@ -14,7 +14,7 @@ Setup \xe2\x80\xa2 Packages in scope: omit-keys (esc) \xe2\x80\xa2 Running omit-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - omit-keys:omit-keys-task: cache miss, executing 0e2764d66f4e31cb + omit-keys:omit-keys-task: cache miss, executing 3494dd1d95d1479e omit-keys:omit-keys-task: omit-keys:omit-keys-task: > omit-keys-task omit-keys:omit-keys-task: > echo running-omit-keys-task > out/foo.min.txt @@ -25,7 +25,7 @@ Setup Time:\s*[\.0-9]+m?s (re) $ HASH=$(cat tmp.log | grep -E "omit-keys:omit-keys-task.* executing .*" | awk '{print $5}') - $ tar -tf $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ tar -tf $TARGET_DIR/.turbo/cache/$HASH.tar.zst; apps/omit-keys/.turbo/turbo-omit-keys-task.log apps/omit-keys/out/ apps/omit-keys/out/.keep @@ -36,7 +36,7 @@ Setup \xe2\x80\xa2 Packages in scope: omit-keys (esc) \xe2\x80\xa2 Running omit-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - omit-keys:omit-keys-task: cache hit, suppressing logs 0e2764d66f4e31cb + omit-keys:omit-keys-task: cache hit, suppressing logs 3494dd1d95d1479e Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -48,7 +48,7 @@ Setup \xe2\x80\xa2 Packages in scope: omit-keys (esc) \xe2\x80\xa2 Running omit-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - omit-keys:omit-keys-task: cache miss, executing 610b5c185bcefc0c + omit-keys:omit-keys-task: cache miss, executing dc03a583d6fdaaf2 omit-keys:omit-keys-task: omit-keys:omit-keys-task: > omit-keys-task omit-keys:omit-keys-task: > echo running-omit-keys-task > out/foo.min.txt @@ -65,7 +65,7 @@ Setup \xe2\x80\xa2 Packages in scope: omit-keys (esc) \xe2\x80\xa2 Running omit-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - omit-keys:omit-keys-task: cache hit, suppressing logs 610b5c185bcefc0c + omit-keys:omit-keys-task: cache hit, suppressing logs dc03a583d6fdaaf2 Tasks: 1 successful, 1 total Cached: 1 cached, 1 total @@ -76,7 +76,7 @@ Setup \xe2\x80\xa2 Packages in scope: omit-keys (esc) \xe2\x80\xa2 Running omit-keys-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - omit-keys:omit-keys-task: cache miss, executing f4229f7e07a5c9b1 + omit-keys:omit-keys-task: cache miss, executing 56670bf5aef6bb90 omit-keys:omit-keys-task: omit-keys:omit-keys-task: > omit-keys-task omit-keys:omit-keys-task: > echo running-omit-keys-task > out/foo.min.txt diff --git a/turborepo-tests/integration/tests/workspace-configs/override-values-deps.t b/turborepo-tests/integration/tests/workspace-configs/override-values-deps.t index 15a50a06ca099..6bba3588cfb2a 100644 --- a/turborepo-tests/integration/tests/workspace-configs/override-values-deps.t +++ b/turborepo-tests/integration/tests/workspace-configs/override-values-deps.t @@ -12,7 +12,7 @@ Setup \xe2\x80\xa2 Packages in scope: override-values (esc) \xe2\x80\xa2 Running override-values-task-with-deps in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - override-values:override-values-task-with-deps: cache miss, executing 596194c40fbbbca4 + override-values:override-values-task-with-deps: cache miss, executing 9b51bda96ea87896 override-values:override-values-task-with-deps: override-values:override-values-task-with-deps: > override-values-task-with-deps override-values:override-values-task-with-deps: > echo running-override-values-task-with-deps > out/foo.min.txt @@ -30,11 +30,10 @@ Setup "cache": true, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": null, "interactive": false } @@ -46,10 +45,9 @@ Setup "cache": true, "dependsOn": [], "inputs": [], - "outputMode": "full", + "outputLogs": "full", "persistent": false, "env": [], "passThroughEnv": null, - "dotEnv": null, "interactive": false } diff --git a/turborepo-tests/integration/tests/workspace-configs/override-values.t b/turborepo-tests/integration/tests/workspace-configs/override-values.t index 3388bb7ed1e30..def339396457e 100644 --- a/turborepo-tests/integration/tests/workspace-configs/override-values.t +++ b/turborepo-tests/integration/tests/workspace-configs/override-values.t @@ -3,7 +3,7 @@ Setup # The override-values-task task in the root turbo.json has ALL the config. The workspace config # defines the task and overrides all the keys. The tests below use `override-values-task` to assert that: -# - `outputs`, `inputs`, `env`, and `outputMode` are overriden from the root config. +# - `outputs`, `inputs`, `env`, and `outputLogs` are overriden from the root config. # 1. First run, assert that the right `outputs` are cached. $ ${TURBO} run override-values-task --filter=override-values > tmp.log @@ -11,7 +11,7 @@ Setup \xe2\x80\xa2 Packages in scope: override-values (esc) \xe2\x80\xa2 Running override-values-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - override-values:override-values-task: cache miss, executing 24dfa2ce8f15d263 + override-values:override-values-task: cache miss, executing ca440a0f61cee7ea override-values:override-values-task: override-values:override-values-task: > override-values-task override-values:override-values-task: > echo running-override-values-task > lib/bar.min.txt @@ -22,7 +22,7 @@ Setup Time:\s*[\.0-9]+m?s (re) $ HASH=$(cat tmp.log | grep -E "override-values:override-values-task.* executing .*" | awk '{print $5}') - $ tar -tf $TARGET_DIR/node_modules/.cache/turbo/$HASH.tar.zst; + $ tar -tf $TARGET_DIR/.turbo/cache/$HASH.tar.zst; apps/override-values/.turbo/turbo-override-values-task.log apps/override-values/lib/ apps/override-values/lib/.keep @@ -33,7 +33,7 @@ Setup \xe2\x80\xa2 Packages in scope: override-values (esc) \xe2\x80\xa2 Running override-values-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - override-values:override-values-task: cache hit, replaying logs 24dfa2ce8f15d263 + override-values:override-values-task: cache hit, replaying logs ca440a0f61cee7ea override-values:override-values-task: override-values:override-values-task: > override-values-task override-values:override-values-task: > echo running-override-values-task > lib/bar.min.txt @@ -49,7 +49,7 @@ Setup \xe2\x80\xa2 Packages in scope: override-values (esc) \xe2\x80\xa2 Running override-values-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - override-values:override-values-task: cache miss, executing 558b071339618227 + override-values:override-values-task: cache miss, executing 41f4985cf22b4f8e override-values:override-values-task: override-values:override-values-task: > override-values-task override-values:override-values-task: > echo running-override-values-task > lib/bar.min.txt @@ -65,7 +65,7 @@ Setup \xe2\x80\xa2 Packages in scope: override-values (esc) \xe2\x80\xa2 Running override-values-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - override-values:override-values-task: cache hit, replaying logs 558b071339618227 + override-values:override-values-task: cache hit, replaying logs 41f4985cf22b4f8e override-values:override-values-task: override-values:override-values-task: > override-values-task override-values:override-values-task: > echo running-override-values-task > lib/bar.min.txt @@ -80,7 +80,7 @@ Setup \xe2\x80\xa2 Packages in scope: override-values (esc) \xe2\x80\xa2 Running override-values-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - override-values:override-values-task: cache miss, executing c13b940a3427bd1c + override-values:override-values-task: cache miss, executing e78785787e17e37e override-values:override-values-task: override-values:override-values-task: > override-values-task override-values:override-values-task: > echo running-override-values-task > lib/bar.min.txt @@ -95,7 +95,7 @@ Setup \xe2\x80\xa2 Packages in scope: override-values (esc) \xe2\x80\xa2 Running override-values-task in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - override-values:override-values-task: cache hit, replaying logs c13b940a3427bd1c + override-values:override-values-task: cache hit, replaying logs e78785787e17e37e override-values:override-values-task: override-values:override-values-task: > override-values-task override-values:override-values-task: > echo running-override-values-task > lib/bar.min.txt diff --git a/turborepo-tests/integration/tests/workspace-configs/persistent.t b/turborepo-tests/integration/tests/workspace-configs/persistent.t index d28c1702a3908..c6ead0abd6909 100644 --- a/turborepo-tests/integration/tests/workspace-configs/persistent.t +++ b/turborepo-tests/integration/tests/workspace-configs/persistent.t @@ -14,12 +14,12 @@ This test covers: Error: x "persistent#persistent-task-1" is a persistent task, | "persistent#persistent-task-1-parent" cannot depend on it - ,-[turbo.json:69:1] - 69 | "persistent-task-1-parent": { - 70 | "dependsOn": ["persistent-task-1"] - : ^^^^^^^^^|^^^^^^^^^ - : `-- persistent task - 71 | }, + ,-[turbo.json:88:1] + 88 | "dependsOn": [ + 89 | "persistent-task-1" + : ^^^^^^^^^|^^^^^^^^^ + : `-- persistent task + 90 | ] `---- [1] @@ -30,13 +30,13 @@ This test covers: \xe2\x80\xa2 Packages in scope: persistent (esc) \xe2\x80\xa2 Running persistent-task-2-parent in 1 packages (esc) \xe2\x80\xa2 Remote caching disabled (esc) - persistent:persistent-task-2: cache miss, executing 37375b286d724c01 + persistent:persistent-task-2: cache miss, executing 7f08cefb45c613d2 persistent:persistent-task-2: persistent:persistent-task-2: > persistent-task-2 persistent:persistent-task-2: > echo persistent-task-2 persistent:persistent-task-2: persistent:persistent-task-2: persistent-task-2 - persistent:persistent-task-2-parent: cache miss, executing dfc8c20283d7826a + persistent:persistent-task-2-parent: cache miss, executing affde90eaca06703 persistent:persistent-task-2-parent: persistent:persistent-task-2-parent: > persistent-task-2-parent persistent:persistent-task-2-parent: > echo persistent-task-2-parent @@ -55,13 +55,13 @@ This test covers: Error: x "persistent#persistent-task-3" is a persistent task, | "persistent#persistent-task-3-parent" cannot depend on it - ,-[turbo.json:75:1] - 75 | "persistent-task-3-parent": { - 76 | "dependsOn": ["persistent-task-3"] - : ^^^^^^^^^|^^^^^^^^^ - : `-- persistent task - 77 | }, - `---- + ,-[turbo.json:98:1] + 98 | "dependsOn": [ + 99 | "persistent-task-3" + : ^^^^^^^^^|^^^^^^^^^ + : `-- persistent task + 100 | ] + `---- [1] @@ -72,12 +72,12 @@ This test covers: Error: x "persistent#persistent-task-4" is a persistent task, | "persistent#persistent-task-4-parent" cannot depend on it - ,-[turbo.json:78:1] - 78 | "persistent-task-4-parent": { - 79 | "dependsOn": ["persistent-task-4"] - : ^^^^^^^^^|^^^^^^^^^ - : `-- persistent task - 80 | }, - `---- + ,-[turbo.json:103:1] + 103 | "dependsOn": [ + 104 | "persistent-task-4" + : ^^^^^^^^^|^^^^^^^^^ + : `-- persistent task + 105 | ] + `---- [1] diff --git a/version.txt b/version.txt index 60d25b9e9edbb..dfd63b8a160e3 100644 --- a/version.txt +++ b/version.txt @@ -1,2 +1,2 @@ -1.13.4 -latest +2.0.0-canary.4 +canary