diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index a5e7cd9b2a337..0185d73f2adfa 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -22,8 +22,8 @@ use turborepo_ui::{ColorConfig, GREY}; use crate::{ cli::error::print_potential_tasks, commands::{ - bin, config, daemon, generate, link, login, logout, ls, prune, query, run, scan, telemetry, - unlink, CommandBase, + bin, config, daemon, generate, info, link, login, logout, ls, prune, query, run, scan, + telemetry, unlink, CommandBase, }, get_version, run::watch::WatchClient, @@ -474,9 +474,7 @@ impl Args { } } -/// Defines the subcommands for CLI. NOTE: If we change the commands in Go, -/// we must change these as well to avoid accidentally passing the -/// --single-package flag into non-build commands. +/// Defines the subcommands for CLI #[derive(Subcommand, Clone, Debug, PartialEq)] pub enum Command { /// Get the path to the Turbo binary @@ -569,6 +567,8 @@ pub enum Command { #[clap(long)] invalidate: bool, }, + /// Print debugging information + Info, /// Prepare a subset of your monorepo. Prune { #[clap(hide = true, long)] @@ -1223,6 +1223,15 @@ pub async fn run( generate::run(tag, command, &args, child_event)?; Ok(0) } + Command::Info => { + CommandEventBuilder::new("info") + .with_parent(&root_telemetry) + .track_call(); + let base = CommandBase::new(cli_args.clone(), repo_root, version, color_config); + + info::run(base).await; + Ok(0) + } Command::Telemetry { command } => { let event = CommandEventBuilder::new("telemetry").with_parent(&root_telemetry); event.track_call(); diff --git a/crates/turborepo-lib/src/commands/info.rs b/crates/turborepo-lib/src/commands/info.rs new file mode 100644 index 0000000000000..d0e7ccfd9c448 --- /dev/null +++ b/crates/turborepo-lib/src/commands/info.rs @@ -0,0 +1,75 @@ +use std::{env, io}; + +use sysinfo::{System, SystemExt}; +use thiserror::Error; +use turborepo_repository::{package_json::PackageJson, package_manager::PackageManager}; + +use super::CommandBase; +use crate::{DaemonConnector, DaemonConnectorError}; + +#[derive(Debug, Error)] +pub enum Error { + #[error("could not get path to turbo binary: {0}")] + NoCurrentExe(#[from] io::Error), +} + +pub async fn run(base: CommandBase) { + let system = System::new_all(); + let connector = DaemonConnector::new(false, false, &base.repo_root); + let daemon_status = match connector.connect().await { + Ok(_status) => "Running", + Err(DaemonConnectorError::NotRunning) => "Not running", + Err(_e) => "Error getting status", + }; + let package_manager = PackageJson::load(&base.repo_root.join_component("package.json")) + .ok() + .and_then(|package_json| { + PackageManager::read_or_detect_package_manager(&package_json, &base.repo_root).ok() + }) + .map_or_else(|| "Not found".to_owned(), |pm| pm.to_string()); + + println!("CLI:"); + println!(" Version: {}", base.version); + + let exe_path = std::env::current_exe().map_or_else( + |e| format!("Cannot determine current binary: {e}").to_owned(), + |path| path.to_string_lossy().into_owned(), + ); + + println!(" Path to executable: {}", exe_path); + println!(" Daemon status: {}", daemon_status); + println!(" Package manager: {}", package_manager); + println!(); + + println!("Platform:"); + println!(" Architecture: {}", std::env::consts::ARCH); + println!(" Operating system: {}", std::env::consts::OS); + println!( + " Available memory (MB): {}", + system.available_memory() / 1024 / 1024 + ); + println!(" Available CPU cores: {}", num_cpus::get()); + println!(); + + println!("Environment:"); + println!(" CI: {:#?}", turborepo_ci::Vendor::get_name()); + println!( + " Terminal (TERM): {}", + env::var("TERM").unwrap_or_else(|_| "unknown".to_owned()) + ); + + println!( + " Terminal program (TERM_PROGRAM): {}", + env::var("TERM_PROGRAM").unwrap_or_else(|_| "unknown".to_owned()) + ); + println!( + " Terminal program version (TERM_PROGRAM_VERSION): {}", + env::var("TERM_PROGRAM_VERSION").unwrap_or_else(|_| "unknown".to_owned()) + ); + println!( + " Shell (SHELL): {}", + env::var("SHELL").unwrap_or_else(|_| "unknown".to_owned()) + ); + println!(" stdin: {}", turborepo_ci::is_ci()); + println!(); +} diff --git a/crates/turborepo-lib/src/commands/mod.rs b/crates/turborepo-lib/src/commands/mod.rs index 439be0cd13ae4..d23574cb2f32d 100644 --- a/crates/turborepo-lib/src/commands/mod.rs +++ b/crates/turborepo-lib/src/commands/mod.rs @@ -15,6 +15,7 @@ pub(crate) mod bin; pub(crate) mod config; pub(crate) mod daemon; pub(crate) mod generate; +pub(crate) mod info; pub(crate) mod link; pub(crate) mod login; pub(crate) mod logout; diff --git a/turborepo-tests/integration/tests/no-args.t b/turborepo-tests/integration/tests/no-args.t index 7236297d88e32..e64f56b790bae 100644 --- a/turborepo-tests/integration/tests/no-args.t +++ b/turborepo-tests/integration/tests/no-args.t @@ -18,6 +18,7 @@ Make sure exit code is 2 when no args are passed link Link your local directory to a Vercel organization and enable remote caching login Login to your Vercel account logout Logout to your Vercel account + info Print debugging information prune Prepare a subset of your monorepo run Run tasks across projects in your monorepo query Query your monorepo using GraphQL. If no query is provided, spins up a GraphQL server with GraphiQL diff --git a/turborepo-tests/integration/tests/turbo-help.t b/turborepo-tests/integration/tests/turbo-help.t index 78f2ce5208156..b9c7d73bc70af 100644 --- a/turborepo-tests/integration/tests/turbo-help.t +++ b/turborepo-tests/integration/tests/turbo-help.t @@ -18,6 +18,7 @@ Test help flag link Link your local directory to a Vercel organization and enable remote caching login Login to your Vercel account logout Logout to your Vercel account + info Print debugging information prune Prepare a subset of your monorepo run Run tasks across projects in your monorepo query Query your monorepo using GraphQL. If no query is provided, spins up a GraphQL server with GraphiQL @@ -141,6 +142,7 @@ Test help flag link Link your local directory to a Vercel organization and enable remote caching login Login to your Vercel account logout Logout to your Vercel account + info Print debugging information prune Prepare a subset of your monorepo run Run tasks across projects in your monorepo query Query your monorepo using GraphQL. If no query is provided, spins up a GraphQL server with GraphiQL