From ccf1c2fd62aa08a956bc2260a9bb7d0c71fed509 Mon Sep 17 00:00:00 2001 From: Nicholas Yang Date: Tue, 19 Nov 2024 15:15:19 -0500 Subject: [PATCH] feat(link): add `--yes` and `--scope` flags to `link` (#9466) ### Description Adds `--yes` and `--scope` flags ### Testing Instructions Added tests for parsing those flags --- crates/turborepo-lib/src/cli/error.rs | 4 +- crates/turborepo-lib/src/cli/mod.rs | 106 +++++++++++++++++- crates/turborepo-lib/src/commands/link.rs | 20 +++- crates/turborepo-lib/src/diagnostics.rs | 9 +- docs/repo-docs/reference/link.mdx | 10 +- .../integration/tests/command-link.t | 8 ++ .../integration/tests/turbo-help.t | 8 +- 7 files changed, 152 insertions(+), 13 deletions(-) diff --git a/crates/turborepo-lib/src/cli/error.rs b/crates/turborepo-lib/src/cli/error.rs index a85e0103573f4..99631493ca74d 100644 --- a/crates/turborepo-lib/src/cli/error.rs +++ b/crates/turborepo-lib/src/cli/error.rs @@ -8,7 +8,7 @@ use turborepo_telemetry::events::command::CommandEventBuilder; use turborepo_ui::{color, BOLD, GREY}; use crate::{ - commands::{bin, generate, ls, prune, run::get_signal, CommandBase}, + commands::{bin, generate, link, ls, prune, run::get_signal, CommandBase}, daemon::DaemonError, query, rewrite_json::RewriteError, @@ -45,6 +45,8 @@ pub enum Error { #[diagnostic(transparent)] Ls(#[from] ls::Error), #[error(transparent)] + Link(#[from] link::Error), + #[error(transparent)] #[diagnostic(transparent)] Prune(#[from] prune::Error), #[error(transparent)] diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index b857bd34b8f6c..d4025503d2bf1 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -569,6 +569,13 @@ pub enum Command { #[clap(long)] no_gitignore: bool, + /// The scope, i.e. Vercel team, to which you are linking + #[clap(long)] + scope: Option, + + /// Answer yes to all prompts (default false) + #[clap(long, short)] + yes: bool, /// Specify what should be linked (default "remote cache") #[clap(long, value_enum, default_value_t = LinkTarget::RemoteCache)] target: LinkTarget, @@ -1299,11 +1306,18 @@ pub async fn run( } Command::Link { no_gitignore, + scope, + yes, target, } => { CommandEventBuilder::new("link") .with_parent(&root_telemetry) .track_call(); + + if cli_args.team.is_some() { + warn!("team flag does not set the scope for linking. Use --scope instead."); + } + if cli_args.test_run { println!("Link test run successful"); return Ok(0); @@ -1311,11 +1325,11 @@ pub async fn run( let modify_gitignore = !*no_gitignore; let to = *target; + let yes = *yes; + let scope = scope.clone(); let mut base = CommandBase::new(cli_args, repo_root, version, color_config); - if let Err(err) = link::link(&mut base, modify_gitignore, to).await { - error!("error: {}", err.to_string()) - } + link::link(&mut base, scope, modify_gitignore, yes, to).await?; Ok(0) } @@ -1469,7 +1483,7 @@ mod test { use itertools::Itertools; use pretty_assertions::assert_eq; - use crate::cli::{ExecutionArgs, RunArgs}; + use crate::cli::{ExecutionArgs, LinkTarget, RunArgs}; struct CommandTestCase { command: &'static str, @@ -2300,6 +2314,90 @@ mod test { .test(); } + #[test] + fn test_parse_link() { + assert_eq!( + Args::try_parse_from(["turbo", "link"]).unwrap(), + Args { + command: Some(Command::Link { + no_gitignore: false, + scope: None, + yes: false, + target: LinkTarget::RemoteCache, + }), + ..Args::default() + } + ); + + CommandTestCase { + command: "link", + command_args: vec![], + global_args: vec![vec!["--cwd", "../examples/with-yarn"]], + expected_output: Args { + command: Some(Command::Link { + no_gitignore: false, + scope: None, + yes: false, + target: LinkTarget::RemoteCache, + }), + cwd: Some(Utf8PathBuf::from("../examples/with-yarn")), + ..Args::default() + }, + } + .test(); + + CommandTestCase { + command: "link", + command_args: vec![vec!["--yes"]], + global_args: vec![vec!["--cwd", "../examples/with-yarn"]], + expected_output: Args { + command: Some(Command::Link { + yes: true, + no_gitignore: false, + scope: None, + target: LinkTarget::RemoteCache, + }), + cwd: Some(Utf8PathBuf::from("../examples/with-yarn")), + ..Args::default() + }, + } + .test(); + + CommandTestCase { + command: "link", + command_args: vec![vec!["--scope", "foo"]], + global_args: vec![vec!["--cwd", "../examples/with-yarn"]], + expected_output: Args { + command: Some(Command::Link { + yes: false, + no_gitignore: false, + scope: Some("foo".to_string()), + target: LinkTarget::RemoteCache, + }), + cwd: Some(Utf8PathBuf::from("../examples/with-yarn")), + ..Args::default() + }, + } + .test(); + + CommandTestCase { + command: "link", + command_args: vec![vec!["--no-gitignore"]], + global_args: vec![vec!["--cwd", "../examples/with-yarn"]], + expected_output: Args { + command: Some(Command::Link { + yes: false, + no_gitignore: true, + scope: None, + target: LinkTarget::RemoteCache, + }), + cwd: Some(Utf8PathBuf::from("../examples/with-yarn")), + ..Args::default() + }, + } + .test(); + } + #[test] fn test_parse_login() { assert_eq!( diff --git a/crates/turborepo-lib/src/commands/link.rs b/crates/turborepo-lib/src/commands/link.rs index 721c3a07458a4..e52a42e653ea1 100644 --- a/crates/turborepo-lib/src/commands/link.rs +++ b/crates/turborepo-lib/src/commands/link.rs @@ -163,7 +163,9 @@ pub(crate) async fn verify_caching_enabled<'a>( pub async fn link( base: &mut CommandBase, + scope: Option, modify_gitignore: bool, + yes: bool, target: LinkTarget, ) -> Result<(), Error> { let homedir_path = home_dir().ok_or_else(|| Error::HomeDirectoryNotFound)?; @@ -183,7 +185,7 @@ pub async fn link( REMOTE_CACHING_URL ); - if !should_link_remote_cache(base, &repo_root_with_tilde)? { + if !yes && !should_link_remote_cache(base, &repo_root_with_tilde)? { return Err(Error::NotLinking); } @@ -203,7 +205,17 @@ pub async fn link( .await .map_err(Error::TeamsRequest)?; - let selected_team = select_team(base, &teams_response.teams)?; + let selected_team = if let Some(team_slug) = scope { + SelectedTeam::Team( + teams_response + .teams + .iter() + .find(|team| team.slug == team_slug) + .ok_or_else(|| Error::TeamNotFound(team_slug.to_string()))?, + ) + } else { + select_team(base, &teams_response.teams)? + }; let team_id = match selected_team { SelectedTeam::User => user_response.user.id.as_str(), @@ -632,7 +644,7 @@ mod test { ) .unwrap(); - link::link(&mut base, false, LinkTarget::RemoteCache) + link::link(&mut base, None, false, false, LinkTarget::RemoteCache) .await .unwrap(); @@ -707,7 +719,7 @@ mod test { ) .unwrap(); - link::link(&mut base, false, LinkTarget::Spaces) + link::link(&mut base, None, false, false, LinkTarget::Spaces) .await .unwrap(); diff --git a/crates/turborepo-lib/src/diagnostics.rs b/crates/turborepo-lib/src/diagnostics.rs index 04f1c989b2c45..c8297f56f32d1 100644 --- a/crates/turborepo-lib/src/diagnostics.rs +++ b/crates/turborepo-lib/src/diagnostics.rs @@ -429,7 +429,14 @@ impl Diagnostic for RemoteCacheDiagnostic { return; }; stopped.await.unwrap(); - let link_res = link(&mut base, false, crate::cli::LinkTarget::RemoteCache).await; + let link_res = link( + &mut base, + None, + false, + false, + crate::cli::LinkTarget::RemoteCache, + ) + .await; resume.send(()).unwrap(); link_res }; diff --git a/docs/repo-docs/reference/link.mdx b/docs/repo-docs/reference/link.mdx index c9a2712182f15..a71997207f18e 100644 --- a/docs/repo-docs/reference/link.mdx +++ b/docs/repo-docs/reference/link.mdx @@ -13,6 +13,14 @@ The selected owner (either a user or an organization) will be able to share [cac Specifies the URL of your Remote Cache provider. +### `--yes` + +Answer yes to all prompts + +### `--scope ` + +The scope, i.e. Vercel team, to which you are linking + ```bash title="Terminal" turbo link --api https://acme.com -``` \ No newline at end of file +``` diff --git a/turborepo-tests/integration/tests/command-link.t b/turborepo-tests/integration/tests/command-link.t index bd0e882f85f32..d3ba844b0b743 100644 --- a/turborepo-tests/integration/tests/command-link.t +++ b/turborepo-tests/integration/tests/command-link.t @@ -6,3 +6,11 @@ Link Test Run $ ${TURBO} link --__test-run Link test run successful + $ ${TURBO} link --__test-run --yes + Link test run successful + + $ ${TURBO} link --__test-run --team=my-team + WARNING team flag does not set the scope for linking. Use --scope instead. + Link test run successful + + diff --git a/turborepo-tests/integration/tests/turbo-help.t b/turborepo-tests/integration/tests/turbo-help.t index b9c7d73bc70af..c484db0230c7a 100644 --- a/turborepo-tests/integration/tests/turbo-help.t +++ b/turborepo-tests/integration/tests/turbo-help.t @@ -329,14 +329,18 @@ Test help flag for link command Do not create or modify .gitignore (default false) --version + --scope + The scope, i.e. Vercel team, to which you are linking --skip-infer Skip any attempts to infer which version of Turbo the project is configured to use - --target - Specify what should be linked (default "remote cache") [default: remote-cache] [possible values: remote-cache, spaces] --no-update-notifier Disable the turbo update notification + -y, --yes + Answer yes to all prompts (default false) --api Override the endpoint for API calls + --target + Specify what should be linked (default "remote cache") [default: remote-cache] [possible values: remote-cache, spaces] --color Force color usage in the terminal --cwd