diff --git a/.yarn/versions/d3fb7bae.yml b/.yarn/versions/d3fb7bae.yml index 28fac241db0..c676bb95f79 100644 --- a/.yarn/versions/d3fb7bae.yml +++ b/.yarn/versions/d3fb7bae.yml @@ -1,9 +1,16 @@ releases: - "@moonrepo/cli": minor - "@moonrepo/core-linux-arm64-gnu": minor - "@moonrepo/core-linux-arm64-musl": minor - "@moonrepo/core-linux-x64-gnu": minor - "@moonrepo/core-linux-x64-musl": minor - "@moonrepo/core-macos-arm64": minor - "@moonrepo/core-macos-x64": minor - "@moonrepo/core-windows-x64-msvc": minor + '@moonrepo/cli': minor + '@moonrepo/core-linux-arm64-gnu': minor + '@moonrepo/core-linux-arm64-musl': minor + '@moonrepo/core-linux-x64-gnu': minor + '@moonrepo/core-linux-x64-musl': minor + '@moonrepo/core-macos-arm64': minor + '@moonrepo/core-macos-x64': minor + '@moonrepo/core-windows-x64-msvc': minor + '@moonrepo/types': patch + +declined: + - '@moonrepo/nx-compat' + - '@moonrepo/report' + - '@moonrepo/runtime' + - website diff --git a/Cargo.lock b/Cargo.lock index d4b370d2b4c..9b712b84d1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3046,11 +3046,11 @@ name = "moon_action" version = "0.0.1" dependencies = [ "miette", - "moon_action_graph", "moon_common", "moon_platform_runtime", "moon_target", - "moon_utils", + "moon_time", + "rustc-hash", "serde", ] @@ -3074,10 +3074,10 @@ version = "0.0.1" dependencies = [ "graph-cycles", "miette", + "moon_action", "moon_common", "moon_config", "moon_platform", - "moon_platform_runtime", "moon_project", "moon_project_graph", "moon_query", diff --git a/crates/core/action-pipeline/Cargo.toml b/crates/core/action-pipeline/Cargo.toml index 0d94940975a..483802c7798 100644 --- a/crates/core/action-pipeline/Cargo.toml +++ b/crates/core/action-pipeline/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -moon_action = { path = "../action" } +moon_action = { path = "../../../nextgen/action" } moon_action_context = { path = "../../../nextgen/action-context" } moon_action_graph = { path = "../../../nextgen/action-graph" } moon_actions = { path = "../actions" } diff --git a/crates/core/action-pipeline/src/estimator.rs b/crates/core/action-pipeline/src/estimator.rs index 24dc5f23dec..c09328741ba 100644 --- a/crates/core/action-pipeline/src/estimator.rs +++ b/crates/core/action-pipeline/src/estimator.rs @@ -63,13 +63,13 @@ impl Estimator { } match &*result.node { - ActionNode::SetupTool { .. } - | ActionNode::InstallDeps { .. } - | ActionNode::InstallProjectDeps { .. } => { + ActionNode::SetupTool(_) + | ActionNode::InstallDeps(_) + | ActionNode::InstallProjectDeps(_) => { install_duration += task_duration; } - ActionNode::RunTask { target, .. } => { - let task_id = target.task_id.to_string(); + ActionNode::RunTask(inner) => { + let task_id = inner.target.task_id.to_string(); if let Some(task) = tasks.get_mut(&task_id) { task.count += 1; diff --git a/crates/core/action-pipeline/src/pipeline.rs b/crates/core/action-pipeline/src/pipeline.rs index 2e0fd2b36a2..c527b0eda41 100644 --- a/crates/core/action-pipeline/src/pipeline.rs +++ b/crates/core/action-pipeline/src/pipeline.rs @@ -365,7 +365,7 @@ impl Pipeline { console.out.print_checkpoint( Checkpoint::RunFailed, match &*result.node { - ActionNode::RunTask { target, .. } => target.as_str(), + ActionNode::RunTask(inner) => inner.target.as_str(), _ => &result.label, }, )?; diff --git a/crates/core/action-pipeline/src/processor.rs b/crates/core/action-pipeline/src/processor.rs index 924bc96cbff..32c4aa66e95 100644 --- a/crates/core/action-pipeline/src/processor.rs +++ b/crates/core/action-pipeline/src/processor.rs @@ -33,11 +33,7 @@ pub async fn process_action( let node = Arc::clone(&action.node); let log_action_label = color::muted_light(&action.label); - trace!( - target: &action.log_target, - "Processing action {}", - log_action_label - ); + trace!("Processing action {}", log_action_label); emitter .emit(Event::ActionStarted { @@ -50,15 +46,19 @@ pub async fn process_action( ActionNode::None => Ok(ActionStatus::Skipped), // Setup and install the specific tool - ActionNode::SetupTool { runtime } => { - emitter.emit(Event::ToolInstalling { runtime }).await?; + ActionNode::SetupTool(inner) => { + emitter + .emit(Event::ToolInstalling { + runtime: &inner.runtime, + }) + .await?; - let setup_result = setup_tool(&mut action, context, workspace, runtime).await; + let setup_result = setup_tool(&mut action, context, workspace, &inner.runtime).await; emitter .emit(Event::ToolInstalled { error: extract_error(&setup_result), - runtime, + runtime: &inner.runtime, }) .await?; @@ -66,21 +66,22 @@ pub async fn process_action( } // Install dependencies in the workspace root - ActionNode::InstallDeps { runtime } => { + ActionNode::InstallDeps(inner) => { emitter .emit(Event::DependenciesInstalling { project: None, - runtime, + runtime: &inner.runtime, }) .await?; - let install_result = install_deps(&mut action, context, workspace, runtime, None).await; + let install_result = + install_deps(&mut action, context, workspace, &inner.runtime, None).await; emitter .emit(Event::DependenciesInstalled { error: extract_error(&install_result), project: None, - runtime, + runtime: &inner.runtime, }) .await?; @@ -88,27 +89,30 @@ pub async fn process_action( } // Install dependencies in the project root - ActionNode::InstallProjectDeps { - runtime, - project: project_id, - } => { - let project = project_graph.get(project_id)?; + ActionNode::InstallProjectDeps(inner) => { + let project = project_graph.get(&inner.project)?; emitter .emit(Event::DependenciesInstalling { project: Some(&project), - runtime, + runtime: &inner.runtime, }) .await?; - let install_result = - install_deps(&mut action, context, workspace, runtime, Some(&project)).await; + let install_result = install_deps( + &mut action, + context, + workspace, + &inner.runtime, + Some(&project), + ) + .await; emitter .emit(Event::DependenciesInstalled { error: extract_error(&install_result), project: Some(&project), - runtime, + runtime: &inner.runtime, }) .await?; @@ -116,16 +120,13 @@ pub async fn process_action( } // Sync a project within the graph - ActionNode::SyncProject { - runtime, - project: project_id, - } => { - let project = project_graph.get(project_id)?; + ActionNode::SyncProject(inner) => { + let project = project_graph.get(&inner.project)?; emitter .emit(Event::ProjectSyncing { project: &project, - runtime, + runtime: &inner.runtime, }) .await?; @@ -135,7 +136,7 @@ pub async fn process_action( workspace, project_graph, &project, - runtime, + &inner.runtime, ) .await; @@ -143,7 +144,7 @@ pub async fn process_action( .emit(Event::ProjectSynced { error: extract_error(&sync_result), project: &project, - runtime, + runtime: &inner.runtime, }) .await?; @@ -166,12 +167,14 @@ pub async fn process_action( } // Run a task within a project - ActionNode::RunTask { - runtime, target, .. - } => { - let project = project_graph.get(target.get_project_id().unwrap())?; + ActionNode::RunTask(inner) => { + let project = project_graph.get(inner.target.get_project_id().unwrap())?; - emitter.emit(Event::TargetRunning { target }).await?; + emitter + .emit(Event::TargetRunning { + target: &inner.target, + }) + .await?; let run_result = run_task( &mut action, @@ -180,15 +183,15 @@ pub async fn process_action( workspace, console, &project, - target, - runtime, + &inner.target, + &inner.runtime, ) .await; emitter .emit(Event::TargetRan { error: extract_error(&run_result), - target, + target: &inner.target, }) .await?; @@ -227,14 +230,12 @@ pub async fn process_action( if action.has_failed() { trace!( - target: &action.log_target, "Failed to process action {} in {:?}", log_action_label, action.duration.unwrap() ); } else { trace!( - target: &action.log_target, "Processed action {} in {:?}", log_action_label, action.duration.unwrap() diff --git a/crates/core/action-pipeline/src/subscribers/moonbase.rs b/crates/core/action-pipeline/src/subscribers/moonbase.rs index d3b5d4baae2..41670a7abc6 100644 --- a/crates/core/action-pipeline/src/subscribers/moonbase.rs +++ b/crates/core/action-pipeline/src/subscribers/moonbase.rs @@ -1,5 +1,5 @@ use ci_env::get_environment; -use moon_action::{ActionNode, ActionStatus}; +use moon_action::{ActionNode, ActionStatus, RunTaskNode}; use moon_api::{ endpoints::ArtifactWriteInput, graphql::{ @@ -461,14 +461,10 @@ impl Subscriber for MoonbaseSubscriber { let archive_path = archive_path.to_owned(); // Create a fake action label so that we can check the CI cache - let action_label = ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, - runtime: Runtime::system(), - target: (*target).to_owned(), - } + let action_label = ActionNode::run_task(RunTaskNode::new( + (*target).to_owned(), + Runtime::system(), + )) .label(); let job_id = self.job_ids.get(&action_label).cloned(); diff --git a/crates/core/action-pipeline/tests/estimator_test.rs b/crates/core/action-pipeline/tests/estimator_test.rs index aa41db7e5f8..e64934764ce 100644 --- a/crates/core/action-pipeline/tests/estimator_test.rs +++ b/crates/core/action-pipeline/tests/estimator_test.rs @@ -1,4 +1,4 @@ -use moon_action::{Action, ActionNode, ActionStatus}; +use moon_action::*; use moon_action_pipeline::estimator::{Estimator, TaskEstimate}; use moon_platform::Runtime; use rustc_hash::FxHashMap; @@ -9,14 +9,10 @@ const NANOS_PER_MILLI: u32 = 1_000_000; const HALF_SECOND: u32 = NANOS_PER_MILLI * 500; fn create_run_task_action(runtime: Runtime, target: &str) -> Arc { - Arc::new(ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, + Arc::new(ActionNode::run_task(RunTaskNode::new( + target.into(), runtime, - target: target.into(), - }) + ))) } mod estimator { @@ -125,16 +121,16 @@ mod estimator { &[ Action { duration: Some(Duration::new(10, 0)), - node: Arc::new(ActionNode::SetupTool { + node: Arc::new(ActionNode::setup_tool(SetupToolNode { runtime: Runtime::system(), - }), + })), ..Action::default() }, Action { duration: Some(Duration::new(25, 0)), - node: Arc::new(ActionNode::InstallDeps { + node: Arc::new(ActionNode::install_deps(InstallDepsNode { runtime: Runtime::system(), - }), + })), ..Action::default() }, Action { @@ -197,16 +193,16 @@ mod estimator { &[ Action { duration: Some(Duration::new(10, 0)), - node: Arc::new(ActionNode::SetupTool { + node: Arc::new(ActionNode::setup_tool(SetupToolNode { runtime: Runtime::system(), - }), + })), ..Action::default() }, Action { duration: Some(Duration::new(25, 0)), - node: Arc::new(ActionNode::InstallDeps { + node: Arc::new(ActionNode::install_deps(InstallDepsNode { runtime: Runtime::system(), - }), + })), ..Action::default() }, Action { @@ -270,16 +266,16 @@ mod estimator { &[ Action { duration: Some(Duration::new(10, 0)), - node: Arc::new(ActionNode::SetupTool { + node: Arc::new(ActionNode::setup_tool(SetupToolNode { runtime: Runtime::system(), - }), + })), ..Action::default() }, Action { duration: Some(Duration::new(25, 0)), - node: Arc::new(ActionNode::InstallDeps { + node: Arc::new(ActionNode::install_deps(InstallDepsNode { runtime: Runtime::system(), - }), + })), ..Action::default() }, Action { diff --git a/crates/core/action/Cargo.toml b/crates/core/action/Cargo.toml deleted file mode 100644 index cdcca64997d..00000000000 --- a/crates/core/action/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "moon_action" -version = "0.0.1" -edition = "2021" -publish = false - -[dependencies] -moon_action_graph = { path = "../../../nextgen/action-graph" } -moon_common = { path = "../../../nextgen/common" } -moon_platform_runtime = { path = "../../../nextgen/platform-runtime" } -moon_target = { path = "../../../nextgen/target" } -moon_utils = { path = "../utils" } -miette = { workspace = true } -serde = { workspace = true } diff --git a/crates/core/action/src/lib.rs b/crates/core/action/src/lib.rs deleted file mode 100644 index 4a5e97f1cc3..00000000000 --- a/crates/core/action/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod action; - -pub use action::*; -pub use moon_action_graph::ActionNode; diff --git a/crates/core/emitter/Cargo.toml b/crates/core/emitter/Cargo.toml index 0458ff6b28e..e90a389c41c 100644 --- a/crates/core/emitter/Cargo.toml +++ b/crates/core/emitter/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -moon_action = { path = "../action" } +moon_action = { path = "../../../nextgen/action" } moon_action_context = { path = "../../../nextgen/action-context" } moon_platform_runtime = { path = "../../../nextgen/platform-runtime" } moon_project = { path = "../../../nextgen/project" } diff --git a/crates/core/runner/Cargo.toml b/crates/core/runner/Cargo.toml index f181708d71a..a0a200baff5 100644 --- a/crates/core/runner/Cargo.toml +++ b/crates/core/runner/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -moon_action = { path = "../action" } +moon_action = { path = "../../../nextgen/action" } moon_action_context = { path = "../../../nextgen/action-context" } moon_cache_item = { path = "../../../nextgen/cache-item" } moon_common = { path = "../../../nextgen/common" } diff --git a/crates/core/runner/src/runner.rs b/crates/core/runner/src/runner.rs index 93afeb003e9..f5b7e35886d 100644 --- a/crates/core/runner/src/runner.rs +++ b/crates/core/runner/src/runner.rs @@ -319,9 +319,9 @@ impl<'a> Runner<'a> { } // Dependency specific args/env - if let ActionNode::RunTask { args, env, .. } = &*self.node { - command.args(args); - command.envs(env.to_owned()); + if let ActionNode::RunTask(inner) = &*self.node { + command.args(inner.args.clone()); + command.envs(inner.env.clone()); } // Affected files (must be last args) @@ -726,7 +726,7 @@ impl<'a> Runner<'a> { match possible_output { // zero and non-zero exit codes Ok(out) => { - attempt.done(if out.status.success() { + attempt.finish(if out.status.success() { ActionStatus::Passed } else { ActionStatus::Failed @@ -775,7 +775,7 @@ impl<'a> Runner<'a> { } // process itself failed Err(error) => { - attempt.done(ActionStatus::Failed); + attempt.finish(ActionStatus::Failed); attempts.push(attempt); interval_handle.abort(); diff --git a/nextgen/action-graph/Cargo.toml b/nextgen/action-graph/Cargo.toml index 29a88ef87d7..f4976d79997 100644 --- a/nextgen/action-graph/Cargo.toml +++ b/nextgen/action-graph/Cargo.toml @@ -9,11 +9,11 @@ repository = "https://github.com/moonrepo/moon" publish = false [dependencies] +moon_action = { path = "../action" } moon_common = { path = "../common" } moon_config = { path = "../config" } # TODO remove moon_platform = { path = "../../crates/core/platform" } -moon_platform_runtime = { path = "../platform-runtime" } moon_project = { path = "../project" } moon_project_graph = { path = "../project-graph" } moon_task = { path = "../task" } diff --git a/nextgen/action-graph/src/action_graph.rs b/nextgen/action-graph/src/action_graph.rs index 506ca79a98c..a5502388066 100644 --- a/nextgen/action-graph/src/action_graph.rs +++ b/nextgen/action-graph/src/action_graph.rs @@ -1,6 +1,6 @@ use crate::action_graph_error::ActionGraphError; -use crate::action_node::ActionNode; use graph_cycles::Cycles; +use moon_action::ActionNode; use moon_common::{color, is_test_env}; use petgraph::dot::{Config, Dot}; use petgraph::prelude::*; diff --git a/nextgen/action-graph/src/action_graph_builder.rs b/nextgen/action-graph/src/action_graph_builder.rs index dced41bac7c..5f36e5771e3 100644 --- a/nextgen/action-graph/src/action_graph_builder.rs +++ b/nextgen/action-graph/src/action_graph_builder.rs @@ -1,5 +1,8 @@ use crate::action_graph::ActionGraph; -use crate::action_node::ActionNode; +use moon_action::{ + ActionNode, InstallDepsNode, InstallProjectDepsNode, RunTaskNode, SetupToolNode, + SyncProjectNode, +}; use moon_common::Id; use moon_common::{color, path::WorkspaceRelativePathBuf}; use moon_config::{PlatformType, TaskDependencyConfig}; @@ -135,14 +138,14 @@ impl<'app> ActionGraphBuilder<'app> { } let node = if in_project { - ActionNode::InstallProjectDeps { + ActionNode::install_project_deps(InstallProjectDepsNode { project: project.id.to_owned(), runtime: self.get_runtime(project, platform_type, true), - } + }) } else { - ActionNode::InstallDeps { + ActionNode::install_deps(InstallDepsNode { runtime: self.get_runtime(project, platform_type, false), - } + }) }; if node.get_runtime().platform.is_system() { @@ -190,21 +193,21 @@ impl<'app> ActionGraphBuilder<'app> { } let mut args = vec![]; - let mut env = vec![]; + let mut env = FxHashMap::default(); if let Some(config) = config { args.extend(parse_task_args(&config.args)?); - env.extend(config.env.clone().into_iter().collect::>()); + env.extend(config.env.clone()); } - let node = ActionNode::RunTask { + let node = ActionNode::run_task(RunTaskNode { args, env, interactive: task.is_interactive() || reqs.interactive, persistent: task.is_persistent(), runtime: self.get_runtime(project, task.platform, true), target: task.target.to_owned(), - }; + }); if let Some(index) = self.get_index_from_node(&node) { return Ok(Some(*index)); @@ -445,9 +448,9 @@ impl<'app> ActionGraphBuilder<'app> { } pub fn setup_tool(&mut self, runtime: &Runtime) -> NodeIndex { - let node = ActionNode::SetupTool { + let node = ActionNode::setup_tool(SetupToolNode { runtime: runtime.to_owned(), - }; + }); if let Some(index) = self.get_index_from_node(&node) { return *index; @@ -470,10 +473,10 @@ impl<'app> ActionGraphBuilder<'app> { project: &Project, cycle: &mut FxHashSet, ) -> miette::Result { - let node = ActionNode::SyncProject { + let node = ActionNode::sync_project(SyncProjectNode { project: project.id.clone(), runtime: self.get_runtime(project, project.platform, true), - }; + }); if let Some(index) = self.get_index_from_node(&node) { return Ok(*index); @@ -506,7 +509,7 @@ impl<'app> ActionGraphBuilder<'app> { } pub fn sync_workspace(&mut self) -> NodeIndex { - let node = ActionNode::SyncWorkspace; + let node = ActionNode::sync_workspace(); if let Some(index) = self.get_index_from_node(&node) { return *index; diff --git a/nextgen/action-graph/src/action_node.rs b/nextgen/action-graph/src/action_node.rs deleted file mode 100644 index 6225d6eeaa6..00000000000 --- a/nextgen/action-graph/src/action_node.rs +++ /dev/null @@ -1,119 +0,0 @@ -use moon_common::Id; -use moon_platform_runtime::Runtime; -use moon_task::Target; -use serde::Serialize; -use std::hash::Hash; - -#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize)] -#[serde(tag = "action", content = "params")] -pub enum ActionNode { - #[default] - None, - - /// Install tool dependencies in the workspace root. - InstallDeps { runtime: Runtime }, - - /// Install tool dependencies in the project root. - InstallProjectDeps { project: Id, runtime: Runtime }, - - /// Run a project's task. - RunTask { - args: Vec, - env: Vec<(String, String)>, - interactive: bool, // Interactive with stdin - persistent: bool, // Never terminates - runtime: Runtime, - target: Target, - }, - - /// Setup a tool + version for the provided platform. - SetupTool { runtime: Runtime }, - - /// Sync a project with language specific semantics. - SyncProject { project: Id, runtime: Runtime }, - - /// Sync the entire moon workspace. - /// Install system dependencies. - SyncWorkspace, -} - -impl ActionNode { - pub fn get_runtime(&self) -> &Runtime { - match self { - Self::InstallDeps { runtime } => runtime, - Self::InstallProjectDeps { runtime, .. } => runtime, - Self::RunTask { runtime, .. } => runtime, - Self::SetupTool { runtime } => runtime, - Self::SyncProject { runtime, .. } => runtime, - _ => unreachable!(), - } - } - - pub fn is_interactive(&self) -> bool { - match self { - Self::RunTask { interactive, .. } => *interactive, - _ => false, - } - } - - pub fn is_persistent(&self) -> bool { - match self { - Self::RunTask { persistent, .. } => *persistent, - _ => false, - } - } - - pub fn is_standard(&self) -> bool { - match self { - Self::RunTask { - interactive, - persistent, - .. - } => !interactive && !persistent, - _ => true, - } - } - - pub fn label(&self) -> String { - match self { - Self::InstallDeps { runtime } => { - format!("Install{runtime}Deps({})", runtime.requirement) - } - Self::InstallProjectDeps { runtime, project } => { - format!( - "Install{runtime}DepsInProject({}, {project})", - runtime.requirement - ) - } - Self::RunTask { - interactive, - persistent, - target, - .. - } => { - format!( - "Run{}Task({target})", - if *persistent { - "Persistent" - } else if *interactive { - "Interactive" - } else { - "" - } - ) - } - Self::SetupTool { runtime } => { - if runtime.platform.is_system() { - "SetupSystemTool".into() - } else { - format!("Setup{runtime}Tool({})", runtime.requirement) - } - } - Self::SyncProject { runtime, project } => { - format!("Sync{runtime}Project({project})") - } - Self::SyncWorkspace => "SyncWorkspace".into(), - Self::None => "None".into(), - } - } -} diff --git a/nextgen/action-graph/src/lib.rs b/nextgen/action-graph/src/lib.rs index 913205c5436..8a8e59997ea 100644 --- a/nextgen/action-graph/src/lib.rs +++ b/nextgen/action-graph/src/lib.rs @@ -1,9 +1,7 @@ mod action_graph; mod action_graph_builder; mod action_graph_error; -mod action_node; pub use action_graph::*; pub use action_graph_builder::*; pub use action_graph_error::*; -pub use action_node::*; diff --git a/nextgen/action-graph/tests/action_graph_test.rs b/nextgen/action-graph/tests/action_graph_test.rs index 81a45acccd7..0098d978375 100644 --- a/nextgen/action-graph/tests/action_graph_test.rs +++ b/nextgen/action-graph/tests/action_graph_test.rs @@ -2,11 +2,12 @@ mod utils; +use moon_action::*; use moon_action_graph::*; use moon_common::path::WorkspaceRelativePathBuf; use moon_common::Id; -use moon_config::{TaskArgs, TaskDependencyConfig}; -use moon_platform_runtime::*; +use moon_config::{PlatformType, TaskArgs, TaskDependencyConfig}; +use moon_platform::*; use moon_project_graph::ProjectGraph; use moon_task::{Target, TargetLocator, Task}; use moon_test_utils2::generate_project_graph; @@ -109,13 +110,13 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - } + }) ] ); } @@ -136,13 +137,13 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - } + }) ] ); } @@ -165,17 +166,17 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::InstallProjectDeps { + }), + ActionNode::install_project_deps(InstallProjectDepsNode { project: Id::raw("out"), runtime: create_node_runtime() - }, + }), ] ); } @@ -204,13 +205,13 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - } + }) ] ); @@ -226,13 +227,13 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - } + }) ] ); } @@ -262,25 +263,18 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target - } + }), + ActionNode::run_task(RunTaskNode::new(task.target, create_node_runtime())) ] ); } @@ -311,25 +305,18 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target - } + }), + ActionNode::run_task(RunTaskNode::new(task.target, create_node_runtime())) ] ); } @@ -418,29 +405,22 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_rust_runtime() - }, - ActionNode::InstallProjectDeps { + }), + ActionNode::install_project_deps(InstallProjectDepsNode { project: Id::raw("bar"), runtime: create_rust_runtime() - }, - ActionNode::SetupTool { + }), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, - runtime: create_rust_runtime(), - target: task.target - } + }), + ActionNode::run_task(RunTaskNode::new(task.target, create_rust_runtime())) ] ); } @@ -464,14 +444,11 @@ mod action_graph { assert_eq!( topo(graph).last().unwrap(), - &ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: true, - persistent: false, - runtime: Runtime::system(), - target: task.target - } + &ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, Runtime::system()); + node.interactive = true; + node + }) ); } @@ -499,14 +476,11 @@ mod action_graph { assert_eq!( topo(graph).last().unwrap(), - &ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: true, - persistent: false, - runtime: Runtime::system(), - target: task.target - } + &ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, Runtime::system()); + node.interactive = true; + node + }) ); } @@ -529,14 +503,11 @@ mod action_graph { assert_eq!( topo(graph).last().unwrap(), - &ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: true, - runtime: Runtime::system(), - target: task.target - } + &ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, Runtime::system()); + node.persistent = true; + node + }) ); } @@ -587,41 +558,31 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, - ActionNode::RunTask { - args: vec!["a".into(), "b".into(), "c".into()], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, - ActionNode::RunTask { - args: vec!["x".into(), "y".into(), "z".into()], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target - } + }), + ActionNode::run_task(RunTaskNode::new( + task.target.clone(), + create_node_runtime() + )), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target.clone(), create_node_runtime()); + node.args = vec!["a".into(), "b".into(), "c".into()]; + node + }), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, create_node_runtime()); + node.args = vec!["x".into(), "y".into(), "z".into()]; + node + }) ] ); } @@ -664,25 +625,22 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec!["a".into(), "b".into(), "c".into()], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, + }), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, create_node_runtime()); + node.args = vec!["a".into(), "b".into(), "c".into()]; + node + }), ] ); } @@ -725,25 +683,22 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec!["a".into(), "b".into(), "c".into()], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, + }), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, create_node_runtime()); + node.args = vec!["a".into(), "b".into(), "c".into()]; + node + }), ] ); } @@ -795,41 +750,31 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, - ActionNode::RunTask { - args: vec![], - env: vec![("FOO".into(), "1".into())], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, - ActionNode::RunTask { - args: vec![], - env: vec![("BAR".into(), "2".into())], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target - } + }), + ActionNode::run_task(RunTaskNode::new( + task.target.clone(), + create_node_runtime() + )), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target.clone(), create_node_runtime()); + node.env = FxHashMap::from_iter([("FOO".into(), "1".into())]); + node + }), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, create_node_runtime()); + node.env = FxHashMap::from_iter([("BAR".into(), "2".into())]); + node + }) ] ); } @@ -872,25 +817,22 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec![], - env: vec![("FOO".into(), "1".into())], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, + }), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, create_node_runtime()); + node.env = FxHashMap::from_iter([("FOO".into(), "1".into())]); + node + }), ] ); } @@ -956,49 +898,39 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::InstallDeps { + }), + ActionNode::install_deps(InstallDepsNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::RunTask { - args: vec![], - env: vec![], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, - ActionNode::RunTask { - args: vec!["a".into(), "b".into(), "c".into()], - env: vec![("FOO".into(), "1".into())], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, - ActionNode::RunTask { - args: vec!["a".into(), "b".into(), "c".into()], - env: vec![("BAR".into(), "2".into())], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target.clone() - }, - ActionNode::RunTask { - args: vec!["x".into(), "y".into(), "z".into()], - env: vec![("BAR".into(), "2".into())], - interactive: false, - persistent: false, - runtime: create_node_runtime(), - target: task.target - }, + }), + ActionNode::run_task(RunTaskNode::new( + task.target.clone(), + create_node_runtime() + )), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target.clone(), create_node_runtime()); + node.args = vec!["a".into(), "b".into(), "c".into()]; + node.env = FxHashMap::from_iter([("FOO".into(), "1".into())]); + node + }), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target.clone(), create_node_runtime()); + node.args = vec!["a".into(), "b".into(), "c".into()]; + node.env = FxHashMap::from_iter([("BAR".into(), "2".into())]); + node + }), + ActionNode::run_task({ + let mut node = RunTaskNode::new(task.target, create_node_runtime()); + node.args = vec!["x".into(), "y".into(), "z".into()]; + node.env = FxHashMap::from_iter([("BAR".into(), "2".into())]); + node + }), ] ); } @@ -1485,9 +1417,9 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { runtime: system }, - ActionNode::SetupTool { runtime: node }, + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: system }), + ActionNode::setup_tool(SetupToolNode { runtime: node }), ] ); } @@ -1517,10 +1449,10 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { runtime: node1 }, - ActionNode::SetupTool { runtime: node2 }, - ActionNode::SetupTool { runtime: node3 }, + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: node1 }), + ActionNode::setup_tool(SetupToolNode { runtime: node2 }), + ActionNode::setup_tool(SetupToolNode { runtime: node3 }), ] ); } @@ -1539,8 +1471,8 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { runtime: system }, + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: system }), ] ); } @@ -1563,14 +1495,14 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: Runtime::system() - } + }) ] ); } @@ -1589,18 +1521,18 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("foo"), runtime: Runtime::system() - } + }) ] ); } @@ -1625,22 +1557,22 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("foo"), runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("qux"), runtime: Runtime::system() - }, + }), ] ); } @@ -1661,18 +1593,18 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: Runtime::system() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("foo"), runtime: Runtime::system() - } + }) ] ); } @@ -1695,21 +1627,21 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::SetupTool { + }), + ActionNode::setup_tool(SetupToolNode { runtime: create_rust_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("qux"), runtime: create_rust_runtime() - }, + }), ] ); } @@ -1732,27 +1664,27 @@ mod action_graph { assert_eq!( topo(graph), vec![ - ActionNode::SyncWorkspace, - ActionNode::SetupTool { + ActionNode::sync_workspace(), + ActionNode::setup_tool(SetupToolNode { runtime: create_node_runtime() - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("bar"), runtime: create_node_runtime() - }, - ActionNode::SetupTool { + }), + ActionNode::setup_tool(SetupToolNode { runtime: Runtime::new_override( PlatformType::Node, RuntimeReq::with_version(Version::new(18, 0, 0)) ) - }, - ActionNode::SyncProject { + }), + ActionNode::sync_project(SyncProjectNode { project: Id::raw("baz"), runtime: Runtime::new_override( PlatformType::Node, RuntimeReq::with_version(Version::new(18, 0, 0)) ) - }, + }), ] ); } @@ -1771,7 +1703,7 @@ mod action_graph { let graph = builder.build().unwrap(); assert_snapshot!(graph.to_dot()); - assert_eq!(topo(graph), vec![ActionNode::SyncWorkspace]); + assert_eq!(topo(graph), vec![ActionNode::sync_workspace()]); } #[tokio::test] @@ -1785,7 +1717,7 @@ mod action_graph { let graph = builder.build().unwrap(); - assert_eq!(topo(graph), vec![ActionNode::SyncWorkspace]); + assert_eq!(topo(graph), vec![ActionNode::sync_workspace()]); } } } diff --git a/nextgen/action/Cargo.toml b/nextgen/action/Cargo.toml new file mode 100644 index 00000000000..9c52078c5c7 --- /dev/null +++ b/nextgen/action/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "moon_action" +version = "0.0.1" +edition = "2021" +publish = false + +[dependencies] +moon_common = { path = "../common" } +moon_platform_runtime = { path = "../platform-runtime" } +moon_target = { path = "../target" } +moon_time = { path = "../time" } +miette = { workspace = true } +rustc-hash = { workspace = true } +serde = { workspace = true, features = ["rc"] } diff --git a/crates/core/action/src/action.rs b/nextgen/action/src/action.rs similarity index 68% rename from crates/core/action/src/action.rs rename to nextgen/action/src/action.rs index 35bbd363557..e7aee9edc61 100644 --- a/crates/core/action/src/action.rs +++ b/nextgen/action/src/action.rs @@ -1,14 +1,12 @@ -use moon_action_graph::ActionNode; +use crate::action_node::ActionNode; +use crate::attempt::Attempt; use moon_common::color; -use moon_utils::time::{chrono::prelude::*, now_timestamp}; +use moon_time::chrono::NaiveDateTime; +use moon_time::now_timestamp; use serde::{Deserialize, Serialize}; use std::sync::Arc; use std::time::{Duration, Instant}; -fn has_failed(status: &ActionStatus) -> bool { - matches!(status, ActionStatus::Failed) || matches!(status, ActionStatus::FailedAndAbort) -} - #[derive(Copy, Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] pub enum ActionStatus { @@ -23,59 +21,7 @@ pub enum ActionStatus { Skipped, // When nothing happened } -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Attempt { - pub duration: Option, - - pub exit_code: Option, - - pub finished_at: Option, - - pub index: u8, - - pub started_at: NaiveDateTime, - - #[serde(skip)] - pub start_time: Option, - - pub status: ActionStatus, - - pub stderr: Option, - - pub stdout: Option, -} - -impl Attempt { - pub fn new(index: u8) -> Self { - Attempt { - duration: None, - exit_code: None, - finished_at: None, - index, - started_at: now_timestamp(), - start_time: Some(Instant::now()), - status: ActionStatus::Running, - stderr: None, - stdout: None, - } - } - - pub fn done(&mut self, status: ActionStatus) { - self.finished_at = Some(now_timestamp()); - self.status = status; - - if let Some(start) = &self.start_time { - self.duration = Some(start.elapsed()); - } - } - - pub fn has_failed(&self) -> bool { - has_failed(&self.status) - } -} - -#[derive(Debug, Default, Deserialize, Serialize)] +#[derive(Debug, Default, Serialize)] #[serde(rename_all = "camelCase")] pub struct Action { pub allow_failure: bool, @@ -97,13 +43,8 @@ pub struct Action { pub label: String, - #[serde(skip)] - pub log_target: String, - - #[serde(skip)] pub node: Arc, - #[serde(skip)] pub node_index: usize, pub started_at: Option, @@ -126,7 +67,6 @@ impl Action { finished_at: None, flaky: false, label: node.label(), - log_target: String::new(), node: Arc::new(node), node_index: 0, started_at: None, @@ -160,7 +100,10 @@ impl Action { } pub fn has_failed(&self) -> bool { - has_failed(&self.status) + matches!( + &self.status, + ActionStatus::Failed | ActionStatus::FailedAndAbort + ) } pub fn get_error(&mut self) -> miette::Report { @@ -176,7 +119,7 @@ impl Action { } pub fn set_attempts(&mut self, attempts: Vec, command: &str) -> bool { - let some_failed = attempts.iter().any(|a| has_failed(&a.status)); + let some_failed = attempts.iter().any(|attempt| attempt.has_failed()); let mut passed = false; if let Some(last) = attempts.last() { diff --git a/nextgen/action/src/action_node.rs b/nextgen/action/src/action_node.rs new file mode 100644 index 00000000000..6196bbe70cd --- /dev/null +++ b/nextgen/action/src/action_node.rs @@ -0,0 +1,190 @@ +use moon_common::Id; +use moon_platform_runtime::Runtime; +use moon_target::Target; +use rustc_hash::FxHashMap; +use serde::Serialize; +use std::hash::{Hash, Hasher}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct RuntimeNode { + pub runtime: Runtime, +} + +pub type InstallDepsNode = RuntimeNode; +pub type SetupToolNode = RuntimeNode; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct ScopedRuntimeNode { + pub project: Id, + pub runtime: Runtime, +} + +pub type InstallProjectDepsNode = ScopedRuntimeNode; +pub type SyncProjectNode = ScopedRuntimeNode; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct RunTaskNode { + pub args: Vec, + pub env: FxHashMap, + pub interactive: bool, // Interactive with stdin + pub persistent: bool, // Never terminates + pub runtime: Runtime, + pub target: Target, +} + +impl RunTaskNode { + pub fn new(target: Target, runtime: Runtime) -> Self { + Self { + args: vec![], + env: FxHashMap::default(), + interactive: false, + persistent: false, + runtime, + target, + } + } +} + +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)] +#[serde(tag = "action", content = "params", rename_all = "kebab-case")] +pub enum ActionNode { + #[default] + None, + + /// Install tool dependencies in the workspace root. + InstallDeps(Box), + + /// Install tool dependencies in the project root. + InstallProjectDeps(Box), + + /// Run a project's task. + RunTask(Box), + + /// Setup a tool + version for the provided platform. + SetupTool(Box), + + /// Sync a project with language specific semantics. + SyncProject(Box), + + /// Sync the entire moon workspace and install system dependencies. + SyncWorkspace, +} + +impl ActionNode { + pub fn install_deps(node: InstallDepsNode) -> Self { + Self::InstallDeps(Box::new(node)) + } + + pub fn install_project_deps(node: InstallProjectDepsNode) -> Self { + Self::InstallProjectDeps(Box::new(node)) + } + + pub fn run_task(node: RunTaskNode) -> Self { + Self::RunTask(Box::new(node)) + } + + pub fn setup_tool(node: SetupToolNode) -> Self { + Self::SetupTool(Box::new(node)) + } + + pub fn sync_project(node: SyncProjectNode) -> Self { + Self::SyncProject(Box::new(node)) + } + + pub fn sync_workspace() -> Self { + Self::SyncWorkspace + } + + pub fn get_runtime(&self) -> &Runtime { + match self { + Self::InstallDeps(inner) => &inner.runtime, + Self::InstallProjectDeps(inner) => &inner.runtime, + Self::RunTask(inner) => &inner.runtime, + Self::SetupTool(inner) => &inner.runtime, + Self::SyncProject(inner) => &inner.runtime, + _ => unreachable!(), + } + } + + pub fn is_interactive(&self) -> bool { + match self { + Self::RunTask(inner) => inner.interactive, + _ => false, + } + } + + pub fn is_persistent(&self) -> bool { + match self { + Self::RunTask(inner) => inner.persistent, + _ => false, + } + } + + pub fn is_standard(&self) -> bool { + match self { + Self::RunTask(inner) => !inner.interactive && !inner.persistent, + _ => true, + } + } + + pub fn label(&self) -> String { + match self { + Self::InstallDeps(inner) => { + format!( + "Install{}Deps({})", + inner.runtime, inner.runtime.requirement + ) + } + Self::InstallProjectDeps(inner) => { + format!( + "Install{}DepsInProject({}, {})", + inner.runtime, inner.runtime.requirement, inner.project + ) + } + Self::RunTask(inner) => { + format!( + "Run{}Task({})", + if inner.persistent { + "Persistent" + } else if inner.interactive { + "Interactive" + } else { + "" + }, + inner.target + ) + } + Self::SetupTool(inner) => { + if inner.runtime.platform.is_system() { + "SetupSystemTool".into() + } else { + format!("Setup{}Tool({})", inner.runtime, inner.runtime.requirement) + } + } + Self::SyncProject(inner) => { + format!("Sync{}Project({})", inner.runtime, inner.project) + } + Self::SyncWorkspace => "SyncWorkspace".into(), + Self::None => "None".into(), + } + } +} + +impl Hash for ActionNode { + fn hash(&self, state: &mut H) { + state.write(self.label().as_bytes()); + + // For tasks with passthrough arguments and environment variables, + // we need to ensure the hash is more unique in the graph + if let Self::RunTask(node) = self { + for arg in &node.args { + state.write(arg.as_bytes()); + } + + for (key, value) in &node.env { + state.write(key.as_bytes()); + state.write(value.as_bytes()); + } + } + } +} diff --git a/nextgen/action/src/attempt.rs b/nextgen/action/src/attempt.rs new file mode 100644 index 00000000000..c767cb7dbdf --- /dev/null +++ b/nextgen/action/src/attempt.rs @@ -0,0 +1,60 @@ +use crate::action::ActionStatus; +use moon_time::chrono::NaiveDateTime; +use moon_time::now_timestamp; +use serde::{Deserialize, Serialize}; +use std::time::{Duration, Instant}; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Attempt { + pub duration: Option, + + pub exit_code: Option, + + pub finished_at: Option, + + pub index: u8, + + pub started_at: NaiveDateTime, + + #[serde(skip)] + pub start_time: Option, + + pub status: ActionStatus, + + pub stderr: Option, + + pub stdout: Option, +} + +impl Attempt { + pub fn new(index: u8) -> Self { + Attempt { + duration: None, + exit_code: None, + finished_at: None, + index, + started_at: now_timestamp(), + start_time: Some(Instant::now()), + status: ActionStatus::Running, + stderr: None, + stdout: None, + } + } + + pub fn finish(&mut self, status: ActionStatus) { + self.finished_at = Some(now_timestamp()); + self.status = status; + + if let Some(start) = &self.start_time { + self.duration = Some(start.elapsed()); + } + } + + pub fn has_failed(&self) -> bool { + matches!( + &self.status, + ActionStatus::Failed | ActionStatus::FailedAndAbort + ) + } +} diff --git a/nextgen/action/src/lib.rs b/nextgen/action/src/lib.rs new file mode 100644 index 00000000000..97eaa02beea --- /dev/null +++ b/nextgen/action/src/lib.rs @@ -0,0 +1,7 @@ +mod action; +mod action_node; +mod attempt; + +pub use action::*; +pub use action_node::*; +pub use attempt::*; diff --git a/nextgen/vcs/src/process_cache.rs b/nextgen/vcs/src/process_cache.rs index 3c3c0813744..6fbcbc61871 100644 --- a/nextgen/vcs/src/process_cache.rs +++ b/nextgen/vcs/src/process_cache.rs @@ -1,4 +1,5 @@ use moon_process::{output_to_string, Command}; +use scc::hash_cache::Entry; use scc::HashCache; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -82,13 +83,18 @@ impl ProcessCache { } // Otherwise acquire an entry to lock the row - let entry = self.cache.entry_async(cache_key).await; + let cache = match self.cache.entry_async(cache_key).await { + Entry::Occupied(o) => o.get().clone(), + Entry::Vacant(v) => { + let output = executor.exec_capture_output().await?; + let value = output_to_string(&output.stdout); + let cache = Arc::new(format(if trim { value.trim().to_owned() } else { value })); - let output = executor.exec_capture_output().await?; - let value = output_to_string(&output.stdout); - let cache = Arc::new(format(if trim { value.trim().to_owned() } else { value })); + v.put_entry(Arc::clone(&cache)); - entry.put_entry(Arc::clone(&cache)); + cache + } + }; Ok(cache) } diff --git a/packages/report/tests/action.test.ts b/packages/report/tests/action.test.ts index e2fb01aff8b..f7968856f44 100644 --- a/packages/report/tests/action.test.ts +++ b/packages/report/tests/action.test.ts @@ -12,6 +12,11 @@ const action: Action = { error: null, flaky: false, label: 'RunTask(app:build)', + node: { + action: 'sync-workspace', + params: {}, + }, + nodeIndex: 0, status: 'passed', finishedAt: '2022-09-12T22:50:12.932311Z', startedAt: '2022-09-12T22:50:12.932311Z', diff --git a/packages/report/tests/report.test.ts b/packages/report/tests/report.test.ts index ea2f3436e73..de0819822c1 100644 --- a/packages/report/tests/report.test.ts +++ b/packages/report/tests/report.test.ts @@ -15,6 +15,11 @@ function mockReport(): RunReport { error: null, flaky: false, label: 'RunTask(types:build)', + node: { + action: 'sync-workspace', + params: {}, + }, + nodeIndex: 0, status: 'cached', finishedAt: '2022-09-12T22:50:12.932311Z', startedAt: '2022-09-12T22:50:12.932311Z', @@ -30,6 +35,11 @@ function mockReport(): RunReport { error: null, flaky: true, label: 'RunTask(runtime:typecheck)', + node: { + action: 'sync-workspace', + params: {}, + }, + nodeIndex: 1, status: 'passed', finishedAt: '2022-09-12T22:50:12.932311Z', startedAt: '2022-09-12T22:50:12.932311Z', @@ -45,6 +55,11 @@ function mockReport(): RunReport { error: null, flaky: false, label: 'RunTask(types:typecheck)', + node: { + action: 'sync-workspace', + params: {}, + }, + nodeIndex: 2, status: 'passed', finishedAt: '2022-09-12T22:50:12.932311Z', startedAt: '2022-09-12T22:50:12.932311Z', @@ -60,6 +75,11 @@ function mockReport(): RunReport { error: null, flaky: false, label: 'RunTask(website:typecheck)', + node: { + action: 'sync-workspace', + params: {}, + }, + nodeIndex: 3, status: 'passed', finishedAt: '2022-09-12T22:50:12.932311Z', startedAt: '2022-09-12T22:50:12.932311Z', diff --git a/packages/types/src/pipeline.ts b/packages/types/src/pipeline.ts index 05926aeffbe..ed15507e779 100644 --- a/packages/types/src/pipeline.ts +++ b/packages/types/src/pipeline.ts @@ -29,7 +29,9 @@ export interface Action { error: string | null; finishedAt: string | null; flaky: boolean; - label: string | null; + label: string; + node: ActionNode; + nodeIndex: number; startedAt: string | null; status: ActionStatus; } @@ -83,14 +85,14 @@ export type ActionNode = | ActionNodeSyncWorkspace; export interface ActionNodeInstallDeps { - action: 'InstallDeps'; + action: 'install-deps'; params: { runtime: Runtime; }; } export interface ActionNodeInstallProjectDeps { - action: 'InstallProjectDeps'; + action: 'install-project-deps'; params: { runtime: Runtime; project: string; @@ -98,8 +100,10 @@ export interface ActionNodeInstallProjectDeps { } export interface ActionNodeRunTask { - action: 'RunTask'; + action: 'run-task'; params: { + args: string[]; + env: [string, string][]; interactive: boolean; persistent: boolean; runtime: Runtime; @@ -108,14 +112,14 @@ export interface ActionNodeRunTask { } export interface ActionNodeSetupTool { - action: 'SetupTool'; + action: 'setup-tool'; params: { runtime: Runtime; }; } export interface ActionNodeSyncProject { - action: 'SyncProject'; + action: 'sync-project'; params: { runtime: Runtime; project: string; @@ -123,7 +127,7 @@ export interface ActionNodeSyncProject { } export interface ActionNodeSyncWorkspace { - action: 'SyncWorkspace'; + action: 'sync-workspace'; params: {}; }