From 59350bf72ccd1ce4aa6fb8a43be524991b8615d8 Mon Sep 17 00:00:00 2001 From: Greg Soltis Date: Thu, 25 Jan 2024 10:23:51 -0800 Subject: [PATCH] chore(Turborepo): Move more CLI stuff out of run code (#7085) ### Description - setup `api_auth` and `api_client` outside of a run - remove the lifetime from `Opts` and related structs - keep a copy of `Opts` on `Run`. This is likely not the final structure, but is an intermediate step. - keep a copy of `api_auth` on `Run` - Move most of the calculations on `Opts` into the constructor for `Run`. This should likely eventually be a `TryFrom` instead of `new`. The goal is to be able to make `Run` itself immutable since all of the config and options will have been resolved ahead of time ### Testing Instructions Existing test suite Closes TURBO-2135 --------- Co-authored-by: Greg Soltis --- crates/turborepo-api-client/src/lib.rs | 6 + crates/turborepo-cache/src/async_cache.rs | 6 +- crates/turborepo-cache/src/lib.rs | 15 +- crates/turborepo-cache/src/multiplexer.rs | 8 +- crates/turborepo-lib/src/cli/mod.rs | 11 +- crates/turborepo-lib/src/commands/run.rs | 22 +-- crates/turborepo-lib/src/opts.rs | 48 +++--- .../turborepo-lib/src/run/graph_visualizer.rs | 2 +- crates/turborepo-lib/src/run/mod.rs | 161 +++++++++--------- crates/turborepo-lib/src/run/summary/mod.rs | 4 +- .../src/run/summary/task_factory.rs | 4 +- .../turborepo-lib/src/task_graph/visitor.rs | 2 +- crates/turborepo-lib/src/task_hash.rs | 4 +- 13 files changed, 149 insertions(+), 144 deletions(-) diff --git a/crates/turborepo-api-client/src/lib.rs b/crates/turborepo-api-client/src/lib.rs index b346ff4118530..85e8b372247e8 100644 --- a/crates/turborepo-api-client/src/lib.rs +++ b/crates/turborepo-api-client/src/lib.rs @@ -96,6 +96,12 @@ pub struct APIAuth { pub team_slug: Option, } +pub fn is_linked(api_auth: &Option) -> bool { + api_auth + .as_ref() + .map_or(false, |api_auth| api_auth.is_linked()) +} + #[async_trait] impl Client for APIClient { async fn get_user(&self, token: &str) -> Result { diff --git a/crates/turborepo-cache/src/async_cache.rs b/crates/turborepo-cache/src/async_cache.rs index 75a1be91d08cf..b3e463c80848f 100644 --- a/crates/turborepo-cache/src/async_cache.rs +++ b/crates/turborepo-cache/src/async_cache.rs @@ -216,7 +216,7 @@ mod tests { skip_filesystem: true, workers: 10, remote_cache_opts: Some(RemoteCacheOpts { - team_id: "my-team".to_string(), + unused_team_id: Some("my-team".to_string()), signature: false, }), }; @@ -290,7 +290,7 @@ mod tests { skip_filesystem: false, workers: 10, remote_cache_opts: Some(RemoteCacheOpts { - team_id: "my-team".to_string(), + unused_team_id: Some("my-team".to_string()), signature: false, }), }; @@ -374,7 +374,7 @@ mod tests { skip_filesystem: false, workers: 10, remote_cache_opts: Some(RemoteCacheOpts { - team_id: "my-team".to_string(), + unused_team_id: Some("my-team".to_string()), signature: false, }), }; diff --git a/crates/turborepo-cache/src/lib.rs b/crates/turborepo-cache/src/lib.rs index b68173e522f3e..8e28a6e644299 100644 --- a/crates/turborepo-cache/src/lib.rs +++ b/crates/turborepo-cache/src/lib.rs @@ -23,7 +23,7 @@ mod test_cases; use std::{backtrace, backtrace::Backtrace}; pub use async_cache::AsyncCache; -use camino::Utf8Path; +use camino::Utf8PathBuf; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -95,8 +95,8 @@ pub struct CacheHitMetadata { } #[derive(Debug, Default)] -pub struct CacheOpts<'a> { - pub override_dir: Option<&'a Utf8Path>, +pub struct CacheOpts { + pub override_dir: Option, pub remote_cache_read_only: bool, pub skip_remote: bool, pub skip_filesystem: bool, @@ -106,12 +106,15 @@ pub struct CacheOpts<'a> { #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct RemoteCacheOpts { - team_id: String, + unused_team_id: Option, signature: bool, } impl RemoteCacheOpts { - pub fn new(team_id: String, signature: bool) -> Self { - Self { team_id, signature } + pub fn new(unused_team_id: Option, signature: bool) -> Self { + Self { + unused_team_id, + signature, + } } } diff --git a/crates/turborepo-cache/src/multiplexer.rs b/crates/turborepo-cache/src/multiplexer.rs index 3f81c49ba569a..33a8bccb359e2 100644 --- a/crates/turborepo-cache/src/multiplexer.rs +++ b/crates/turborepo-cache/src/multiplexer.rs @@ -41,7 +41,13 @@ impl CacheMultiplexer { } let fs_cache = use_fs_cache - .then(|| FSCache::new(opts.override_dir, repo_root, analytics_recorder.clone())) + .then(|| { + FSCache::new( + opts.override_dir.as_deref(), + repo_root, + analytics_recorder.clone(), + ) + }) .transpose()?; let http_cache = use_http_cache diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 0a0976a23e888..6ffdb018f6f0f 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -1196,7 +1196,16 @@ pub async fn run( } else { use crate::commands::run; event.track_run_code_path(CodePath::Rust); - let exit_code = run::run(base, event).await?; + let exit_code = run::run(base, event) + .await + .inspect(|code| { + if *code != 0 { + error!("run failed: command exited ({code})"); + } + }) + .inspect_err(|err| { + error!("run failed: {err}"); + })?; Ok(Payload::Rust(Ok(exit_code))) } } diff --git a/crates/turborepo-lib/src/commands/run.rs b/crates/turborepo-lib/src/commands/run.rs index 77960cc638cb6..653fd924f9826 100644 --- a/crates/turborepo-lib/src/commands/run.rs +++ b/crates/turborepo-lib/src/commands/run.rs @@ -1,4 +1,4 @@ -use tracing::{debug, error}; +use tracing::debug; use turborepo_telemetry::events::command::CommandEventBuilder; use crate::{commands::CommandBase, run, run::Run, signal::SignalHandler}; @@ -30,10 +30,11 @@ pub async fn run(base: CommandBase, telemetry: CommandEventBuilder) -> Result Result { // Run finished so close the signal handler handler.close().await; - match result { - Ok(code) => { - if code != 0 { - error!("run failed: command exited ({code})") - } - Ok(code) - }, - Err(err) => { - error!("run failed: {}", err); - Err(err) - } - } + result }, } } diff --git a/crates/turborepo-lib/src/opts.rs b/crates/turborepo-lib/src/opts.rs index 677170c7840dd..84feffb4789e4 100644 --- a/crates/turborepo-lib/src/opts.rs +++ b/crates/turborepo-lib/src/opts.rs @@ -31,14 +31,14 @@ pub enum Error { } #[derive(Debug)] -pub struct Opts<'a> { - pub cache_opts: CacheOpts<'a>, - pub run_opts: RunOpts<'a>, +pub struct Opts { + pub cache_opts: CacheOpts, + pub run_opts: RunOpts, pub runcache_opts: RunCacheOpts, pub scope_opts: ScopeOpts, } -impl<'a> Opts<'a> { +impl Opts { pub fn synthesize_command(&self) -> String { let mut cmd = format!("turbo run {}", self.run_opts.tasks.join(" ")); for pattern in &self.scope_opts.filter_patterns { @@ -79,7 +79,7 @@ impl<'a> Opts<'a> { } } -impl<'a> TryFrom<&'a Args> for Opts<'a> { +impl<'a> TryFrom<&'a Args> for Opts { type Error = self::Error; fn try_from(args: &'a Args) -> Result { @@ -118,19 +118,19 @@ impl<'a> From<&'a RunArgs> for RunCacheOpts { } #[derive(Debug)] -pub struct RunOpts<'a> { - pub(crate) tasks: &'a [String], +pub struct RunOpts { + pub(crate) tasks: Vec, pub(crate) concurrency: u32, pub(crate) parallel: bool, pub(crate) env_mode: EnvMode, // Whether or not to infer the framework for each workspace. pub(crate) framework_inference: bool, - pub profile: Option<&'a str>, + pub profile: Option, pub(crate) continue_on_error: bool, - pub(crate) pass_through_args: &'a [String], + pub(crate) pass_through_args: Vec, pub(crate) only: bool, pub(crate) dry_run: Option, - pub graph: Option>, + pub graph: Option, pub(crate) daemon: Option, pub(crate) single_package: bool, pub log_prefix: ResolvedLogPrefix, @@ -140,7 +140,7 @@ pub struct RunOpts<'a> { pub is_github_actions: bool, } -impl<'a> RunOpts<'a> { +impl RunOpts { pub fn args_for_task(&self, task_id: &TaskId) -> Option> { if !self.pass_through_args.is_empty() && self @@ -148,7 +148,7 @@ impl<'a> RunOpts<'a> { .iter() .any(|task| task.as_str() == task_id.task()) { - Some(Vec::from(self.pass_through_args)) + Some(self.pass_through_args.clone()) } else { None } @@ -156,9 +156,9 @@ impl<'a> RunOpts<'a> { } #[derive(Debug)] -pub enum GraphOpts<'a> { +pub enum GraphOpts { Stdout, - File(&'a str), + File(String), } #[derive(Debug, Clone, Copy)] @@ -175,7 +175,7 @@ pub enum ResolvedLogPrefix { const DEFAULT_CONCURRENCY: u32 = 10; -impl<'a> TryFrom<&'a RunArgs> for RunOpts<'a> { +impl<'a> TryFrom<&'a RunArgs> for RunOpts { type Error = self::Error; fn try_from(args: &'a RunArgs) -> Result { @@ -188,7 +188,7 @@ impl<'a> TryFrom<&'a RunArgs> for RunOpts<'a> { let graph = args.graph.as_deref().map(|file| match file { "" => GraphOpts::Stdout, - f => GraphOpts::File(f), + f => GraphOpts::File(f.to_string()), }); let (is_github_actions, log_order, log_prefix) = match args.log_order { @@ -209,7 +209,7 @@ impl<'a> TryFrom<&'a RunArgs> for RunOpts<'a> { }; Ok(Self { - tasks: args.tasks.as_slice(), + tasks: args.tasks.clone(), log_prefix, log_order, summarize: args.summarize, @@ -218,9 +218,9 @@ impl<'a> TryFrom<&'a RunArgs> for RunOpts<'a> { env_mode: args.env_mode, concurrency, parallel: args.parallel, - profile: args.profile.as_deref(), + profile: args.profile.clone(), continue_on_error: args.continue_execution, - pass_through_args: args.pass_through_args.as_ref(), + pass_through_args: args.pass_through_args.clone(), only: args.only, daemon: args.daemon(), single_package: args.single_package, @@ -341,10 +341,10 @@ impl<'a> TryFrom<&'a RunArgs> for ScopeOpts { } } -impl<'a> From<&'a RunArgs> for CacheOpts<'a> { +impl<'a> From<&'a RunArgs> for CacheOpts { fn from(run_args: &'a RunArgs) -> Self { CacheOpts { - override_dir: run_args.cache_dir.as_deref(), + override_dir: run_args.cache_dir.clone(), skip_filesystem: run_args.remote_only, remote_cache_read_only: run_args.remote_cache_read_only, workers: run_args.cache_workers, @@ -353,7 +353,7 @@ impl<'a> From<&'a RunArgs> for CacheOpts<'a> { } } -impl<'a> RunOpts<'a> { +impl RunOpts { pub fn should_redirect_stderr_to_stdout(&self) -> bool { // If we're running on Github Actions, force everything to stdout // so as not to have out-of-order log lines @@ -514,14 +514,14 @@ mod test { )] fn test_synthesize_command(opts_input: TestCaseOpts, expected: &str) { let run_opts = RunOpts { - tasks: &opts_input.tasks, + tasks: opts_input.tasks, concurrency: 10, parallel: opts_input.parallel, env_mode: crate::cli::EnvMode::Loose, framework_inference: true, profile: None, continue_on_error: opts_input.continue_on_error, - pass_through_args: &opts_input.pass_through_args, + pass_through_args: opts_input.pass_through_args, only: opts_input.only, dry_run: opts_input.dry_run, graph: None, diff --git a/crates/turborepo-lib/src/run/graph_visualizer.rs b/crates/turborepo-lib/src/run/graph_visualizer.rs index ee64722c41293..1e9c12cb89ea9 100644 --- a/crates/turborepo-lib/src/run/graph_visualizer.rs +++ b/crates/turborepo-lib/src/run/graph_visualizer.rs @@ -26,7 +26,7 @@ pub enum Error { pub(crate) fn write_graph( ui: UI, - graph_opts: GraphOpts<'_>, + graph_opts: &GraphOpts, engine: &Engine, single_package: bool, cwd: &AbsoluteSystemPath, diff --git a/crates/turborepo-lib/src/run/mod.rs b/crates/turborepo-lib/src/run/mod.rs index 99a165de15cbd..6d26149028670 100644 --- a/crates/turborepo-lib/src/run/mod.rs +++ b/crates/turborepo-lib/src/run/mod.rs @@ -60,16 +60,41 @@ use crate::{ turbo_json::TurboJson, }; -#[derive(Debug)] pub struct Run { base: CommandBase, processes: ProcessManager, + opts: Opts, + api_auth: Option, } impl Run { - pub fn new(base: CommandBase) -> Self { + pub fn new(base: CommandBase, api_auth: Option) -> Result { let processes = ProcessManager::new(); - Self { base, processes } + let mut opts: Opts = base.args().try_into()?; + let config = base.config()?; + let is_linked = turborepo_api_client::is_linked(&api_auth); + if !is_linked { + opts.cache_opts.skip_remote = true; + } else if let Some(enabled) = config.enabled { + // We're linked, but if the user has explicitly enabled or disabled, use that + // value + opts.cache_opts.skip_remote = !enabled; + } + // Note that we don't currently use the team_id value here. In the future, we + // should probably verify that we only use the signature value when the + // configured team_id matches the final resolved team_id. + let unused_remote_cache_opts_team_id = config.team_id().map(|team_id| team_id.to_string()); + let signature = config.signature(); + opts.cache_opts.remote_cache_opts = Some(RemoteCacheOpts::new( + unused_remote_cache_opts_team_id, + signature, + )); + Ok(Self { + base, + processes, + opts, + api_auth, + }) } fn connect_process_manager(&self, signal_subscriber: SignalSubscriber) { @@ -84,10 +109,6 @@ impl Run { self.base.args().get_tasks() } - fn opts(&self) -> Result { - Ok(self.base.args().try_into()?) - } - fn initialize_analytics( api_auth: Option, api_client: APIClient, @@ -99,9 +120,9 @@ impl Run { .then(|| start_analytics(api_auth, api_client)) } - fn print_run_prelude(&self, opts: &Opts<'_>, filtered_pkgs: &HashSet) { - let targets_list = opts.run_opts.tasks.join(", "); - if opts.run_opts.single_package { + fn print_run_prelude(&self, filtered_pkgs: &HashSet) { + let targets_list = self.opts.run_opts.tasks.join(", "); + if self.opts.run_opts.single_package { cprint!(self.base.ui, GREY, "{}", "• Running"); cprint!(self.base.ui, BOLD_GREY, " {}\n", targets_list); } else { @@ -121,7 +142,7 @@ impl Run { cprint!(self.base.ui, GREY, " in {} packages\n", filtered_pkgs.len()); } - let use_http_cache = !opts.cache_opts.skip_remote; + let use_http_cache = !self.opts.cache_opts.skip_remote; if use_http_cache { cprintln!(self.base.ui, GREY, "• Remote caching enabled"); } else { @@ -129,11 +150,12 @@ impl Run { } } - #[tracing::instrument(skip(self, signal_handler))] + #[tracing::instrument(skip(self, signal_handler, api_client))] pub async fn run( &mut self, signal_handler: &SignalHandler, telemetry: CommandEventBuilder, + api_client: APIClient, ) -> Result { tracing::trace!( platform = %TurboState::platform_name(), @@ -148,15 +170,12 @@ impl Run { self.connect_process_manager(subscriber); } - let api_auth = self.base.api_auth()?; - let api_client = self.base.api_client()?; let (analytics_sender, analytics_handle) = - Self::initialize_analytics(api_auth.clone(), api_client.clone()).unzip(); + Self::initialize_analytics(self.api_auth.clone(), api_client.clone()).unzip(); let result = self .run_with_analytics( start_at, - api_auth, api_client, analytics_sender, signal_handler, @@ -176,7 +195,6 @@ impl Run { async fn run_with_analytics( &mut self, start_at: DateTime, - api_auth: Option, api_client: APIClient, analytics_sender: Option, signal_handler: &SignalHandler, @@ -184,34 +202,22 @@ impl Run { ) -> Result { let package_json_path = self.base.repo_root.join_component("package.json"); let root_package_json = PackageJson::load(&package_json_path)?; - let mut opts = self.opts()?; let run_telemetry = GenericEventBuilder::new().with_parent(&telemetry); let repo_telemetry = RepoEventBuilder::new(&self.base.repo_root.to_string()).with_parent(&telemetry); - let config = self.base.config()?; - // Pulled from initAnalyticsClient in run.go - let is_linked = api_auth - .as_ref() - .map_or(false, |api_auth| api_auth.is_linked()); - if !is_linked { - opts.cache_opts.skip_remote = true; - } else if let Some(enabled) = config.enabled { - // We're linked, but if the user has explicitly enabled or disabled, use that - // value - opts.cache_opts.skip_remote = !enabled; - } + let is_linked = turborepo_api_client::is_linked(&self.api_auth); run_telemetry.track_is_linked(is_linked); // we only track the remote cache if we're linked because this defaults to // Vercel if is_linked { run_telemetry.track_remote_cache(api_client.base_url()); } - let _is_structured_output = opts.run_opts.graph.is_some() - || matches!(opts.run_opts.dry_run, Some(DryRunMode::Json)); + let _is_structured_output = self.opts.run_opts.graph.is_some() + || matches!(self.opts.run_opts.dry_run, Some(DryRunMode::Json)); - let is_single_package = opts.run_opts.single_package; + let is_single_package = self.opts.run_opts.single_package; repo_telemetry.track_type(if is_single_package { RepoType::SinglePackage } else { @@ -221,7 +227,7 @@ impl Run { let is_ci_or_not_tty = turborepo_ci::is_ci() || !std::io::stdout().is_terminal(); run_telemetry.track_ci(turborepo_ci::Vendor::get_name()); - let mut daemon = match (is_ci_or_not_tty, opts.run_opts.daemon) { + let mut daemon = match (is_ci_or_not_tty, self.opts.run_opts.daemon) { (true, None) => { run_telemetry.track_daemon_init(DaemonInitStatus::Skipped); debug!("skipping turbod since we appear to be in a non-interactive context"); @@ -235,7 +241,7 @@ impl Run { sock_file: self.base.daemon_file_root().join_component("turbod.sock"), }; - match (connector.connect().await, opts.run_opts.daemon) { + match (connector.connect().await, self.opts.run_opts.daemon) { (Ok(client), _) => { run_telemetry.track_daemon_init(DaemonInitStatus::Started); debug!("running in daemon mode"); @@ -262,7 +268,7 @@ impl Run { }; // if we are forcing the daemon, we don't want to fallback to local discovery - let (fallback, duration) = if let Some(true) = opts.run_opts.daemon { + let (fallback, duration) = if let Some(true) = self.opts.run_opts.daemon { (None, Duration::MAX) } else { ( @@ -280,7 +286,7 @@ impl Run { let mut pkg_dep_graph = PackageGraph::builder(&self.base.repo_root, root_package_json.clone()) - .with_single_package_mode(opts.run_opts.single_package) + .with_single_package_mode(self.opts.run_opts.single_package) .with_package_discovery(FallbackPackageDiscovery::new( daemon.as_mut().map(DaemonPackageDiscovery::new), fallback, @@ -291,27 +297,13 @@ impl Run { repo_telemetry.track_package_manager(pkg_dep_graph.package_manager().to_string()); repo_telemetry.track_size(pkg_dep_graph.len()); - run_telemetry.track_run_type(opts.run_opts.dry_run.is_some()); + run_telemetry.track_run_type(self.opts.run_opts.dry_run.is_some()); let root_turbo_json = TurboJson::load(&self.base.repo_root, &root_package_json, is_single_package)?; - let team_id = root_turbo_json - .remote_cache - .as_ref() - .and_then(|configuration_options| configuration_options.team_id.clone()) - .unwrap_or_default(); - - let signature = root_turbo_json - .remote_cache - .as_ref() - .and_then(|configuration_options| configuration_options.signature) - .unwrap_or_default(); - - opts.cache_opts.remote_cache_opts = Some(RemoteCacheOpts::new(team_id, signature)); - - if opts.run_opts.experimental_space_id.is_none() { - opts.run_opts.experimental_space_id = root_turbo_json.space_id.clone(); + if self.opts.run_opts.experimental_space_id.is_none() { + self.opts.run_opts.experimental_space_id = root_turbo_json.space_id.clone(); } pkg_dep_graph.validate()?; @@ -320,7 +312,7 @@ impl Run { let filtered_pkgs = { let (mut filtered_pkgs, is_all_packages) = scope::resolve_packages( - &opts.scope_opts, + &self.opts.scope_opts, &self.base.repo_root, &pkg_dep_graph, &scm, @@ -347,25 +339,24 @@ impl Run { let env_at_execution_start = EnvironmentVariableMap::infer(); let async_cache = AsyncCache::new( - &opts.cache_opts, + &self.opts.cache_opts, &self.base.repo_root, api_client.clone(), - api_auth.clone(), + self.api_auth.clone(), analytics_sender, )?; - let mut engine = - self.build_engine(&pkg_dep_graph, &opts, &root_turbo_json, &filtered_pkgs)?; + let mut engine = self.build_engine(&pkg_dep_graph, &root_turbo_json, &filtered_pkgs)?; - if opts.run_opts.dry_run.is_none() && opts.run_opts.graph.is_none() { - self.print_run_prelude(&opts, &filtered_pkgs); + if self.opts.run_opts.dry_run.is_none() && self.opts.run_opts.graph.is_none() { + self.print_run_prelude(&filtered_pkgs); } let root_workspace = pkg_dep_graph .workspace_info(&WorkspaceName::Root) .expect("must have root workspace"); - let is_monorepo = !opts.run_opts.single_package; + let is_monorepo = !self.opts.run_opts.single_package; let root_external_dependencies_hash = is_monorepo.then(|| get_external_deps_hash(&root_workspace.transitive_dependencies)); @@ -379,8 +370,8 @@ impl Run { &env_at_execution_start, &root_turbo_json.global_env, root_turbo_json.global_pass_through_env.as_deref(), - opts.run_opts.env_mode, - opts.run_opts.framework_inference, + self.opts.run_opts.env_mode, + self.opts.run_opts.framework_inference, root_turbo_json.global_dot_env.as_deref(), )?; @@ -393,11 +384,11 @@ impl Run { let runcache = Arc::new(RunCache::new( async_cache, &self.base.repo_root, - &opts.runcache_opts, + &self.opts.runcache_opts, color_selector, daemon, self.base.ui, - opts.run_opts.dry_run.is_some(), + self.opts.run_opts.dry_run.is_some(), )); if let Some(subscriber) = signal_handler.subscribe() { let runcache = runcache.clone(); @@ -409,7 +400,7 @@ impl Run { }); } - let mut global_env_mode = opts.run_opts.env_mode; + let mut global_env_mode = self.opts.run_opts.env_mode; if matches!(global_env_mode, EnvMode::Infer) && root_turbo_json.global_pass_through_env.is_some() { @@ -426,17 +417,17 @@ impl Run { &run_telemetry, )?; - if opts.run_opts.parallel { + if self.opts.run_opts.parallel { pkg_dep_graph.remove_workspace_dependencies(); - engine = self.build_engine(&pkg_dep_graph, &opts, &root_turbo_json, &filtered_pkgs)?; + engine = self.build_engine(&pkg_dep_graph, &root_turbo_json, &filtered_pkgs)?; } - if let Some(graph_opts) = opts.run_opts.graph { + if let Some(graph_opts) = &self.opts.run_opts.graph { graph_visualizer::write_graph( self.base.ui, graph_opts, &engine, - opts.run_opts.single_package, + self.opts.run_opts.single_package, self.base.cwd(), )?; return Ok(0); @@ -457,14 +448,14 @@ impl Run { let run_tracker = RunTracker::new( start_at, - opts.synthesize_command(), - opts.scope_opts.pkg_inference_root.as_deref(), + self.opts.synthesize_command(), + self.opts.scope_opts.pkg_inference_root.as_deref(), &env_at_execution_start, &self.base.repo_root, self.base.version(), - opts.run_opts.experimental_space_id.clone(), + self.opts.run_opts.experimental_space_id.clone(), api_client, - api_auth, + self.api_auth.clone(), Vendor::get_user(), ); @@ -472,7 +463,7 @@ impl Run { pkg_dep_graph.clone(), runcache, run_tracker, - &opts.run_opts, + &self.opts.run_opts, package_inputs_hashes, &env_at_execution_start, &global_hash, @@ -484,7 +475,7 @@ impl Run { global_env, ); - if opts.run_opts.dry_run.is_some() { + if self.opts.run_opts.dry_run.is_some() { visitor.dry_run(); } @@ -501,7 +492,7 @@ impl Run { // We hit some error, it shouldn't be exit code 0 .unwrap_or(if errors.is_empty() { 0 } else { 1 }); - let error_prefix = if opts.run_opts.is_github_actions { + let error_prefix = if self.opts.run_opts.is_github_actions { "::error::" } else { "" @@ -517,7 +508,7 @@ impl Run { global_hash_inputs, &engine, &env_at_execution_start, - opts.scope_opts.pkg_inference_root.as_deref(), + self.opts.scope_opts.pkg_inference_root.as_deref(), ) .await?; @@ -527,14 +518,13 @@ impl Run { fn build_engine( &self, pkg_dep_graph: &PackageGraph, - opts: &Opts, root_turbo_json: &TurboJson, filtered_pkgs: &HashSet, ) -> Result { let engine = EngineBuilder::new( &self.base.repo_root, pkg_dep_graph, - opts.run_opts.single_package, + self.opts.run_opts.single_package, ) .with_root_tasks(root_turbo_json.pipeline.keys().cloned()) .with_turbo_jsons(Some( @@ -542,19 +532,20 @@ impl Run { .into_iter() .collect(), )) - .with_tasks_only(opts.run_opts.only) + .with_tasks_only(self.opts.run_opts.only) .with_workspaces(filtered_pkgs.clone().into_iter().collect()) .with_tasks( - opts.run_opts + self.opts + .run_opts .tasks .iter() .map(|task| TaskName::from(task.as_str()).into_owned()), ) .build()?; - if !opts.run_opts.parallel { + if !self.opts.run_opts.parallel { engine - .validate(pkg_dep_graph, opts.run_opts.concurrency) + .validate(pkg_dep_graph, self.opts.run_opts.concurrency) .map_err(|errors| { Error::EngineValidation( errors diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index 69952e3d9b46a..ad84f236829c2 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -199,7 +199,7 @@ impl RunTracker { package_inference_root: Option<&'a AnchoredSystemPath>, exit_code: i32, end_time: DateTime, - run_opts: &RunOpts<'a>, + run_opts: &'a RunOpts, packages: HashSet, global_hash_summary: GlobalHashSummary<'a>, global_env_mode: EnvMode, @@ -269,7 +269,7 @@ impl RunTracker { ui: UI, repo_root: &'a AbsoluteSystemPath, package_inference_root: Option<&AnchoredSystemPath>, - run_opts: &RunOpts<'a>, + run_opts: &'a RunOpts, packages: HashSet, global_hash_summary: GlobalHashSummary<'a>, global_env_mode: cli::EnvMode, diff --git a/crates/turborepo-lib/src/run/summary/task_factory.rs b/crates/turborepo-lib/src/run/summary/task_factory.rs index b7170f8ac7745..6e57cf5020c30 100644 --- a/crates/turborepo-lib/src/run/summary/task_factory.rs +++ b/crates/turborepo-lib/src/run/summary/task_factory.rs @@ -22,7 +22,7 @@ pub struct TaskSummaryFactory<'a> { engine: &'a Engine, hash_tracker: TaskHashTracker, env_at_start: &'a EnvironmentVariableMap, - run_opts: &'a RunOpts<'a>, + run_opts: &'a RunOpts, global_env_mode: cli::EnvMode, } @@ -40,7 +40,7 @@ impl<'a> TaskSummaryFactory<'a> { engine: &'a Engine, hash_tracker: TaskHashTracker, env_at_start: &'a EnvironmentVariableMap, - run_opts: &'a RunOpts<'a>, + run_opts: &'a RunOpts, global_env_mode: cli::EnvMode, ) -> Self { Self { diff --git a/crates/turborepo-lib/src/task_graph/visitor.rs b/crates/turborepo-lib/src/task_graph/visitor.rs index 7dbb4f88225e7..1fc182d273252 100644 --- a/crates/turborepo-lib/src/task_graph/visitor.rs +++ b/crates/turborepo-lib/src/task_graph/visitor.rs @@ -48,7 +48,7 @@ pub struct Visitor<'a> { global_env: EnvironmentVariableMap, global_env_mode: EnvMode, manager: ProcessManager, - run_opts: &'a RunOpts<'a>, + run_opts: &'a RunOpts, package_graph: Arc, repo_root: &'a AbsoluteSystemPath, run_cache: Arc, diff --git a/crates/turborepo-lib/src/task_hash.rs b/crates/turborepo-lib/src/task_hash.rs index a394891efc192..799efb17250a6 100644 --- a/crates/turborepo-lib/src/task_hash.rs +++ b/crates/turborepo-lib/src/task_hash.rs @@ -181,7 +181,7 @@ pub struct TaskHashTrackerState { /// Caches package-inputs hashes, and package-task hashes. pub struct TaskHasher<'a> { hashes: HashMap, String>, - run_opts: &'a RunOpts<'a>, + run_opts: &'a RunOpts, env_at_execution_start: &'a EnvironmentVariableMap, global_hash: &'a str, task_hash_tracker: TaskHashTracker, @@ -327,7 +327,7 @@ impl<'a> TaskHasher<'a> { task: task_id.task(), outputs, - pass_through_args: self.run_opts.pass_through_args, + pass_through_args: &self.run_opts.pass_through_args, env: &task_definition.env, resolved_env_vars: hashable_env_pairs, pass_through_env: task_definition