diff --git a/Cargo.lock b/Cargo.lock index 2281589ef27..54470c575d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3511,7 +3511,7 @@ dependencies = [ [[package]] name = "moon_pdk" -version = "0.0.1" +version = "0.0.2" dependencies = [ "clap", "extism-pdk", @@ -3522,7 +3522,7 @@ dependencies = [ [[package]] name = "moon_pdk_api" -version = "0.0.1" +version = "0.0.2" dependencies = [ "serde", "warpgate_api", @@ -3530,7 +3530,7 @@ dependencies = [ [[package]] name = "moon_pdk_test_utils" -version = "0.0.1" +version = "0.0.2" dependencies = [ "extism", "moon_pdk_api", diff --git a/crates/cli/src/commands/migrate/from_turborepo.rs b/crates/cli/src/commands/migrate/from_turborepo.rs index 9d923625a09..4b311916a58 100644 --- a/crates/cli/src/commands/migrate/from_turborepo.rs +++ b/crates/cli/src/commands/migrate/from_turborepo.rs @@ -1,491 +1,11 @@ -use super::check_dirty_repo; -use clap::Args; -use miette::miette; -use moon::generate_project_graph; -use moon_common::{consts, Id}; -use moon_config::{ - InputPath, OutputPath, PartialInheritedTasksConfig, PartialProjectConfig, PartialTaskArgs, - PartialTaskConfig, PartialTaskDependency, PartialTaskOptionsConfig, PlatformType, - ProjectConfig, -}; -use moon_target::Target; -use moon_workspace::Workspace; -use rustc_hash::FxHashMap; -use serde::{Deserialize, Serialize}; -use starbase::{system, AppResult}; -use starbase_utils::{fs, json, yaml}; -use std::collections::BTreeMap; -use std::path::PathBuf; -use std::str::FromStr; -use tracing::{info, warn}; - -#[derive(Args, Clone, Debug)] -pub struct FromTurborepoArgs { - #[arg(long, hide = true)] - pub skip_touched_files_check: bool, -} - -#[derive(Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TurboTask { - pub cache: Option, - pub depends_on: Option>, - pub env: Option>, - pub inputs: Option>, - pub outputs: Option>, - pub persistent: Option, -} - -#[derive(Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TurboJson { - pub global_dependencies: Option>, - pub global_env: Option>, - pub pipeline: FxHashMap, -} - -pub fn extract_project_task_ids(key: &str) -> (Option, Id) { - if key.contains('#') { - let mut parts = key.split('#'); - - return ( - Some(Id::raw(parts.next().unwrap())), - Id::raw(parts.next().unwrap()), - ); - } - - (None, Id::raw(key)) -} - -pub fn convert_globals( - turbo: &TurboJson, - tasks_config: &mut PartialInheritedTasksConfig, -) -> AppResult { - let mut modified = false; - - if let Some(global_deps) = &turbo.global_dependencies { - let implicit_inputs = tasks_config.implicit_inputs.get_or_insert(vec![]); - - for dep in global_deps { - implicit_inputs.push(InputPath::from_str(dep)?); - } - - modified = true; - } - - if let Some(global_env) = &turbo.global_env { - for env in global_env { - tasks_config - .implicit_inputs - .get_or_insert(vec![]) - .push(InputPath::EnvVar(env.to_owned())); - } - - modified = true; - } - - Ok(modified) -} - -pub fn convert_task(name: Id, task: TurboTask) -> AppResult { - let mut config = PartialTaskConfig::default(); - let mut inputs = vec![]; - - config.command = Some(PartialTaskArgs::String(format!( - "moon node run-script {name}" - ))); - - if let Some(turbo_deps) = task.depends_on { - let mut deps: Vec = vec![]; - - for dep in turbo_deps { - if dep.starts_with('^') { - deps.push(Target::parse(&dep.replace('^', "^:"))?); - } else if dep.contains('#') { - deps.push(Target::parse(&dep.replace('#', ":"))?); - } else if dep.starts_with('$') { - inputs.push(InputPath::from_str(&dep)?); - } else { - deps.push(Target::parse(&dep)?); - } - } - - if !deps.is_empty() { - config.deps = Some( - deps.into_iter() - .map(PartialTaskDependency::Target) - .collect(), - ); - } - } - - if let Some(turbo_env) = task.env { - for env in turbo_env { - inputs.push(InputPath::EnvVar(env)); - } - } - - if let Some(turbo_inputs) = task.inputs { - for input in turbo_inputs { - inputs.push(InputPath::from_str(&input)?); - } - } - - if let Some(turbo_outputs) = task.outputs { - let mut outputs = vec![]; - - for output in turbo_outputs { - if output.ends_with("/**") { - outputs.push(OutputPath::ProjectGlob(format!("{output}/*"))); - } else { - outputs.push(OutputPath::from_str(&output)?); - } - } - - if !outputs.is_empty() { - config.outputs = Some(outputs); - } - } - - if !inputs.is_empty() { - config.inputs = Some(inputs); - } - - config.platform = Some(PlatformType::Node); - - if task.persistent == Some(true) { - config.local = task.persistent; - } - - if task.cache == Some(false) { - config - .options - .get_or_insert(PartialTaskOptionsConfig::default()) - .cache = task.cache; - } - - Ok(config) -} +use starbase::system; +use starbase_styles::color; +use tracing::warn; #[system] -pub async fn from_turborepo(args: ArgsRef, workspace: ResourceMut) { - let turbo_file = workspace.root.join("turbo.json"); - - if !turbo_file.exists() { - return Err(miette!( - code = "moon::migrate::from_turborepo", - "No turbo.json was found in the workspace root." - )); - } - - if args.skip_touched_files_check { - info!("Skipping touched files check."); - } else { - check_dirty_repo(workspace).await?; - }; - - let project_graph = generate_project_graph(workspace).await?; - let turbo_json: TurboJson = json::read_file(&turbo_file)?; - let mut node_tasks_config = PartialInheritedTasksConfig::default(); - let mut has_modified_global_tasks = false; - - // Convert globals first - if convert_globals(&turbo_json, &mut node_tasks_config)? { - has_modified_global_tasks = true; - } - - // Convert tasks second - let mut has_warned_root_tasks = false; - let mut modified_projects: FxHashMap = FxHashMap::default(); - - for (id, task) in turbo_json.pipeline { - if id.starts_with("//#") { - if !has_warned_root_tasks { - warn!( - "Unable to migrate root-level `//#` tasks. Create a root-level project manually to support similar functionality: https://moonrepo.dev/docs/guides/root-project" - ); - has_warned_root_tasks = true; - } - - continue; - } - - match extract_project_task_ids(&id) { - (Some(project_id), task_id) => { - let project = project_graph.get(&project_id)?; - let task_config = convert_task(task_id.clone(), task)?; - - if let Some(project_config) = modified_projects.get_mut(&project.root) { - project_config - .tasks - .get_or_insert(BTreeMap::new()) - .insert(task_id, task_config); - } else { - let mut project_config = ProjectConfig::load_partial(&project.root)?; - - project_config - .tasks - .get_or_insert(BTreeMap::new()) - .insert(task_id, task_config); - - modified_projects.insert(project.root.clone(), project_config); - } - } - (None, task_id) => { - node_tasks_config - .tasks - .get_or_insert(BTreeMap::new()) - .insert(task_id.clone(), convert_task(task_id, task)?); - has_modified_global_tasks = true; - } - } - } - - if has_modified_global_tasks { - let tasks_dir = workspace.root.join(consts::CONFIG_DIRNAME).join("tasks"); - - if !tasks_dir.exists() { - fs::create_dir_all(&tasks_dir)?; - } - - yaml::write_file_with_config(tasks_dir.join("node.yml"), &node_tasks_config)?; - } - - for (project_root, project_config) in modified_projects { - yaml::write_file_with_config( - project_root.join(consts::CONFIG_PROJECT_FILENAME), - &project_config, - )?; - } - - fs::remove_file(&turbo_file)?; - - println!("Successfully migrated from Turborepo to moon!"); -} - -#[cfg(test)] -mod tests { - use super::*; - use moon_utils::string_vec; - - mod globals_conversion { - use super::*; - - #[test] - fn converts_deps() { - let mut config = PartialInheritedTasksConfig { - implicit_inputs: Some(vec![InputPath::ProjectFile("existing.txt".into())]), - ..PartialInheritedTasksConfig::default() - }; - - convert_globals( - &TurboJson { - global_dependencies: Some(string_vec!["file.ts", "glob/**/*.js"]), - ..TurboJson::default() - }, - &mut config, - ) - .unwrap(); - - assert_eq!( - config.implicit_inputs, - Some(vec![ - InputPath::ProjectFile("existing.txt".into()), - InputPath::ProjectFile("file.ts".into()), - InputPath::ProjectGlob("glob/**/*.js".into()) - ]) - ); - } - - #[test] - fn converst_env() { - let mut config = PartialInheritedTasksConfig { - implicit_inputs: Some(vec![InputPath::EnvVar("FOO".into())]), - ..PartialInheritedTasksConfig::default() - }; - - convert_globals( - &TurboJson { - global_env: Some(string_vec!["BAR", "BAZ"]), - ..TurboJson::default() - }, - &mut config, - ) - .unwrap(); - - assert_eq!( - config.implicit_inputs, - Some(vec![ - InputPath::EnvVar("FOO".into()), - InputPath::EnvVar("BAR".into()), - InputPath::EnvVar("BAZ".into()) - ]) - ); - } - } - - mod task_conversion { - use super::*; - - #[test] - fn sets_command() { - let config = convert_task("foo".into(), TurboTask::default()).unwrap(); - - assert_eq!( - config.command, - Some(PartialTaskArgs::String("moon node run-script foo".into())) - ); - } - - #[test] - fn converts_deps() { - let config = convert_task( - "foo".into(), - TurboTask { - depends_on: Some(string_vec!["normal", "^parent", "project#normal", "$VAR"]), - ..TurboTask::default() - }, - ) - .unwrap(); - - assert_eq!( - config.deps, - Some(vec![ - PartialTaskDependency::Target(Target::new_self("normal").unwrap()), - PartialTaskDependency::Target(Target::parse("^:parent").unwrap()), - PartialTaskDependency::Target(Target::parse("project:normal").unwrap()), - ]) - ); - assert_eq!( - config.inputs.unwrap(), - vec![InputPath::EnvVar("VAR".into())] - ); - } - - #[test] - fn doesnt_set_deps_if_empty() { - let config = convert_task("foo".into(), TurboTask::default()).unwrap(); - - assert_eq!(config.deps, None); - } - - #[test] - fn converts_env_to_inputs() { - let config = convert_task( - "foo".into(), - TurboTask { - env: Some(string_vec!["FOO", "BAR"]), - ..TurboTask::default() - }, - ) - .unwrap(); - - assert_eq!( - config.inputs.unwrap(), - vec![ - InputPath::EnvVar("FOO".into()), - InputPath::EnvVar("BAR".into()) - ] - ); - } - - #[test] - fn inherits_inputs() { - let config = convert_task( - "foo".into(), - TurboTask { - inputs: Some(string_vec!["file.ts", "some/folder", "some/glob/**/*"]), - ..TurboTask::default() - }, - ) - .unwrap(); - - assert_eq!( - config.inputs.unwrap(), - vec![ - InputPath::ProjectFile("file.ts".into()), - InputPath::ProjectFile("some/folder".into()), - InputPath::ProjectGlob("some/glob/**/*".into()), - ] - ); - } - - #[test] - fn converts_outputs() { - let config = convert_task( - "foo".into(), - TurboTask { - outputs: Some(string_vec![ - "dir", - "dir/**/*", - "dir/**", - "dir/*", - "dir/*/sub" - ]), - ..TurboTask::default() - }, - ) - .unwrap(); - - assert_eq!( - config.outputs.unwrap(), - vec![ - OutputPath::ProjectFile("dir".into()), - OutputPath::ProjectGlob("dir/**/*".into()), - OutputPath::ProjectGlob("dir/**/*".into()), - OutputPath::ProjectGlob("dir/*".into()), - OutputPath::ProjectGlob("dir/*/sub".into()), - ] - ); - } - - #[test] - fn doesnt_set_outputs_if_empty() { - let config = convert_task("foo".into(), TurboTask::default()).unwrap(); - - assert_eq!(config.outputs, None); - } - - #[test] - fn sets_local() { - let config = convert_task( - "foo".into(), - TurboTask { - persistent: Some(true), - ..TurboTask::default() - }, - ) - .unwrap(); - - assert_eq!(config.local, Some(true)); - } - - #[test] - fn sets_cache_if_false() { - let config = convert_task( - "foo".into(), - TurboTask { - cache: Some(false), - ..TurboTask::default() - }, - ) - .unwrap(); - - assert_eq!(config.options.unwrap().cache, Some(false)); - } - - #[test] - fn doesnt_set_cache_if_true() { - let config = convert_task( - "foo".into(), - TurboTask { - cache: Some(true), - ..TurboTask::default() - }, - ) - .unwrap(); - - assert_eq!(config.options, None); - } - } +pub async fn from_turborepo() { + warn!( + "This command is deprecated. Use {} instead.", + color::shell("moon ext migrate-turborepo") + ); } diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index e584bce555c..f5ee7080b8d 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -34,7 +34,6 @@ use crate::helpers::setup_colors; use app::App as CLI; use app_error::ExitCode; use clap::Parser; -use commands::migrate::FromTurborepoArgs; use enums::{CacheMode, LogLevel}; use moon_common::consts::BIN_NAME; use starbase::{tracing::TracingOptions, App, AppResult}; @@ -191,12 +190,7 @@ pub async fn run_cli() -> AppResult { args.skip_touched_files_check = skip_touched_files_check; app.execute_with_args(migrate::from_package_json, args) } - MigrateCommands::FromTurborepo => app.execute_with_args( - migrate::from_turborepo, - FromTurborepoArgs { - skip_touched_files_check, - }, - ), + MigrateCommands::FromTurborepo => app.execute(migrate::from_turborepo), }, Commands::Node { command } => match command { NodeCommands::RunScript(args) => app.execute_with_args(node::run_script, args), diff --git a/crates/cli/tests/ext_test.rs b/crates/cli/tests/ext_test.rs index 71cbaaf0613..1b19b7e35e8 100644 --- a/crates/cli/tests/ext_test.rs +++ b/crates/cli/tests/ext_test.rs @@ -21,6 +21,10 @@ mod ext { "The extension unknown does not exist.", )); } +} + +mod ext_download { + use super::*; #[test] fn errors_if_no_args() { @@ -105,3 +109,24 @@ mod ext { .stdout(predicates::str::contains("Downloaded to")); } } + +mod ext_migrate_turborepo { + use super::*; + + #[test] + fn executes_the_plugin() { + let sandbox = create_sandbox_with_config("base", None, None, None); + sandbox.create_file("turbo.json", "{}"); + + sandbox + .run_moon(|cmd| { + cmd.arg("ext").arg("migrate-turborepo"); + }) + .success() + .stdout(predicates::str::contains( + "Successfully migrated from Turborepo", + )); + + assert!(!sandbox.path().join("turbo.json").exists()); + } +} diff --git a/crates/cli/tests/migrate_test.rs b/crates/cli/tests/migrate_test.rs index f75eea303f8..21f69430490 100644 --- a/crates/cli/tests/migrate_test.rs +++ b/crates/cli/tests/migrate_test.rs @@ -1,4 +1,4 @@ -use moon_config::{InputPath, PartialWorkspaceConfig, PartialWorkspaceProjects}; +use moon_config::{PartialWorkspaceConfig, PartialWorkspaceProjects}; use moon_test_utils::{ assert_snapshot, create_sandbox_with_config, get_default_toolchain, predicates::str::contains, Sandbox, @@ -10,7 +10,6 @@ fn migrate_sandbox() -> Sandbox { let workspace_config = PartialWorkspaceConfig { projects: Some(PartialWorkspaceProjects::Globs(string_vec![ "package-json/*", - "turborepo/*" ])), ..PartialWorkspaceConfig::default() }; @@ -96,184 +95,3 @@ mod from_package_json { assert.success(); } } - -mod from_turborepo { - use super::*; - use moon_cli::commands::migrate::{TurboJson, TurboTask}; - use moon_config::InheritedTasksConfig; - use rustc_hash::FxHashMap; - - #[test] - fn errors_if_no_config() { - let sandbox = migrate_sandbox(); - sandbox.enable_git(); - - let assert = sandbox.run_moon(|cmd| { - cmd.args(["migrate", "from-turborepo"]); - }); - - assert - .failure() - .code(1) - .stdout("") - .stderr(contains("No turbo.json was found in the workspace root.")); - } - - #[test] - fn converts_globals() { - let sandbox = migrate_sandbox(); - sandbox.enable_git(); - - sandbox.create_file( - "turbo.json", - serde_json::to_string_pretty(&TurboJson { - global_dependencies: Some(string_vec!["package.json", "*.json"]), - global_env: Some(string_vec!["FOO", "BAR"]), - ..TurboJson::default() - }) - .unwrap(), - ); - - let assert = sandbox.run_moon(|cmd| { - cmd.args(["migrate", "from-turborepo", "--skipTouchedFilesCheck"]); - }); - - assert.success(); - - let config = InheritedTasksConfig::load_partial( - sandbox.path(), - sandbox.path().join(".moon/tasks/node.yml"), - ) - .unwrap(); - - assert_eq!( - config.implicit_inputs.unwrap(), - vec![ - InputPath::ProjectFile("package.json".into()), - InputPath::ProjectGlob("*.json".into()), - InputPath::EnvVar("FOO".into()), - InputPath::EnvVar("BAR".into()) - ] - ); - } - - #[test] - fn converts_global_tasks() { - let sandbox = migrate_sandbox(); - sandbox.enable_git(); - - sandbox.create_file( - "turbo.json", - serde_json::to_string_pretty(&TurboJson { - pipeline: FxHashMap::from_iter([ - ( - "build".into(), - TurboTask { - depends_on: Some(string_vec!["^build"]), - outputs: Some(string_vec!["build/**"]), - ..TurboTask::default() - }, - ), - ( - "lint".into(), - TurboTask { - cache: Some(false), - env: Some(string_vec!["NODE_ENV"]), - inputs: Some(string_vec!["src/**/*"]), - ..TurboTask::default() - }, - ), - ]), - ..TurboJson::default() - }) - .unwrap(), - ); - - let assert = sandbox.run_moon(|cmd| { - cmd.args(["migrate", "from-turborepo", "--skipTouchedFilesCheck"]); - }); - - assert.success(); - - assert_snapshot!(fs::read_to_string(sandbox.path().join(".moon/tasks/node.yml")).unwrap()); - } - - #[test] - fn converts_project_tasks() { - let sandbox = migrate_sandbox(); - sandbox.enable_git(); - - sandbox.create_file( - "turbo.json", - serde_json::to_string_pretty(&TurboJson { - pipeline: FxHashMap::from_iter([ - ( - // via package.json name - "turborepo-app#build".into(), - TurboTask { - depends_on: Some(string_vec!["^build"]), - outputs: Some(string_vec!["build/**"]), - ..TurboTask::default() - }, - ), - ( - // via project id - "library#lint".into(), - TurboTask { - cache: Some(false), - env: Some(string_vec!["NODE_ENV"]), - inputs: Some(string_vec!["src/**/*"]), - ..TurboTask::default() - }, - ), - ]), - ..TurboJson::default() - }) - .unwrap(), - ); - - let assert = sandbox.run_moon(|cmd| { - cmd.args(["migrate", "from-turborepo", "--skipTouchedFilesCheck"]); - }); - - assert.success(); - - assert_snapshot!( - fs::read_to_string(sandbox.path().join("turborepo/app/moon.yml")).unwrap() - ); - - assert_snapshot!( - fs::read_to_string(sandbox.path().join("turborepo/library/moon.yml")).unwrap() - ); - } - - #[test] - fn ignores_root_tasks() { - let sandbox = migrate_sandbox(); - sandbox.enable_git(); - - sandbox.create_file( - "turbo.json", - serde_json::to_string_pretty(&TurboJson { - pipeline: FxHashMap::from_iter([( - "//#build".into(), - TurboTask { - depends_on: Some(string_vec!["^build"]), - outputs: Some(string_vec!["build/**"]), - ..TurboTask::default() - }, - )]), - ..TurboJson::default() - }) - .unwrap(), - ); - - let assert = sandbox.run_moon(|cmd| { - cmd.args(["migrate", "from-turborepo", "--skipTouchedFilesCheck"]); - }); - - assert - .success() - .stderr(contains("Unable to migrate root-level `//#` tasks.")); - } -} diff --git a/nextgen/config/src/workspace/plugins_config.rs b/nextgen/config/src/workspace/plugins_config.rs index c27f893b380..c384fb4b4f2 100644 --- a/nextgen/config/src/workspace/plugins_config.rs +++ b/nextgen/config/src/workspace/plugins_config.rs @@ -21,11 +21,20 @@ impl ExtensionConfig { } pub(crate) fn default_extensions() -> FxHashMap { - FxHashMap::from_iter([( - Id::raw("download"), - ExtensionConfig { - plugin: Some(PluginLocator::SourceUrl { url: "https://github.com/moonrepo/moon-extensions/releases/download/moon_download_extension-v0.0.1/moon_download_extension.wasm".into() }), - config: BTreeMap::new(), - }, - )]) + FxHashMap::from_iter([ + ( + Id::raw("download"), + ExtensionConfig { + plugin: Some(PluginLocator::SourceUrl { url: "https://github.com/moonrepo/moon-extensions/releases/download/moon_download_extension-v0.0.2/moon_download_extension.wasm".into() }), + config: BTreeMap::new(), + }, + ), + ( + Id::raw("migrate-turborepo"), + ExtensionConfig { + plugin: Some(PluginLocator::SourceUrl { url: "https://github.com/moonrepo/moon-extensions/releases/download/moon_migrate_turborepo_extension-v0.0.2/moon_migrate_turborepo_extension.wasm".into() }), + config: BTreeMap::new(), + }, + ), + ]) } diff --git a/nextgen/extension-plugin/src/lib.rs b/nextgen/extension-plugin/src/lib.rs index 009928f1fd4..7d16eb53309 100644 --- a/nextgen/extension-plugin/src/lib.rs +++ b/nextgen/extension-plugin/src/lib.rs @@ -1,4 +1,4 @@ -use moon_pdk_api::extension::*; +use moon_pdk_api::*; use moon_plugin::{Plugin, PluginContainer, PluginId, PluginType}; pub struct ExtensionPlugin { diff --git a/nextgen/pdk-api/Cargo.toml b/nextgen/pdk-api/Cargo.toml index bfc480ac640..f727274f32d 100644 --- a/nextgen/pdk-api/Cargo.toml +++ b/nextgen/pdk-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moon_pdk_api" -version = "0.0.1" +version = "0.0.2" edition = "2021" license = "MIT" description = "Core APIs for creating moon WASM plugins." diff --git a/nextgen/pdk-api/src/extension.rs b/nextgen/pdk-api/src/extension.rs index cd4258af4d7..9721d5a5642 100644 --- a/nextgen/pdk-api/src/extension.rs +++ b/nextgen/pdk-api/src/extension.rs @@ -1,7 +1,6 @@ +use crate::MoonContext; use warpgate_api::*; -pub use crate::MoonContext; - api_struct!( /// Input passed to the `execute_extension` function. pub struct ExecuteExtensionInput { diff --git a/nextgen/pdk-api/src/lib.rs b/nextgen/pdk-api/src/lib.rs index c26efea522d..ddd9d23b79a 100644 --- a/nextgen/pdk-api/src/lib.rs +++ b/nextgen/pdk-api/src/lib.rs @@ -1,9 +1,10 @@ -pub mod extension; - -use std::path::Path; +mod extension; +pub use extension::*; pub use warpgate_api::*; +use std::path::Path; + api_struct!( /// Information about the current moon workspace. pub struct MoonContext { diff --git a/nextgen/pdk-test-utils/Cargo.toml b/nextgen/pdk-test-utils/Cargo.toml index 826533fdfb9..a0fe7d8a4b9 100644 --- a/nextgen/pdk-test-utils/Cargo.toml +++ b/nextgen/pdk-test-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moon_pdk_test_utils" -version = "0.0.1" +version = "0.0.2" edition = "2021" license = "MIT" description = "Utilities for testing moon WASM plugins." @@ -8,7 +8,7 @@ homepage = "https://moonrepo.dev/moon" repository = "https://github.com/moonrepo/moon" [dependencies] -moon_pdk_api = { version = "0.0.1", path = "../pdk-api" } +moon_pdk_api = { version = "0.0.2", path = "../pdk-api" } warpgate = { workspace = true } extism = { workspace = true } serde = { workspace = true } diff --git a/nextgen/pdk-test-utils/src/lib.rs b/nextgen/pdk-test-utils/src/lib.rs index e54d6c4ce70..ea83c915114 100644 --- a/nextgen/pdk-test-utils/src/lib.rs +++ b/nextgen/pdk-test-utils/src/lib.rs @@ -4,28 +4,17 @@ mod wrappers; use serde::Serialize; use std::collections::{BTreeMap, HashMap}; -use std::fs; +use std::fs::{self, OpenOptions}; +use std::io::Write; use std::path::{Path, PathBuf}; use warpgate::host_funcs::{create_host_functions, HostData}; use warpgate::{ inject_default_manifest_config, test_utils, Id, PluginContainer, PluginManifest, Wasm, }; -pub use moon_pdk_api::extension::*; pub use moon_pdk_api::*; pub use wrappers::*; -pub fn find_wasm_file(sandbox: &Path) -> PathBuf { - let wasm_file = test_utils::find_wasm_file(); - - // Folders must exists for WASM to compile correctly! - fs::create_dir_all(sandbox.join(".home")).unwrap(); - fs::create_dir_all(sandbox.join(".moon")).unwrap(); - fs::create_dir_all(sandbox.join(".proto")).unwrap(); - - wasm_file -} - pub fn create_plugin_container_with_config( id: &str, sandbox: &Path, @@ -41,7 +30,16 @@ pub fn create_plugin_container_with_config( (sandbox.join(".proto"), "/proto".into()), ]); - let mut manifest = PluginManifest::new([Wasm::file(find_wasm_file(sandbox))]); + // Folders must exists for WASM to compile correctly! + fs::create_dir_all(sandbox.join(".home")).unwrap(); + fs::create_dir_all(sandbox.join(".moon")).unwrap(); + fs::create_dir_all(sandbox.join(".proto")).unwrap(); + + let wasm_file = test_utils::find_wasm_file(); + let mut log_file = wasm_file.clone(); + log_file.set_extension("log"); + + let mut manifest = PluginManifest::new([Wasm::file(wasm_file)]); manifest.timeout_ms = None; manifest = manifest.with_allowed_host("*"); manifest = manifest.with_allowed_paths(virtual_paths.clone().into_iter()); @@ -55,6 +53,25 @@ pub fn create_plugin_container_with_config( working_dir: sandbox.to_path_buf(), }); + // Remove the file otherwise it keeps growing + if log_file.exists() { + let _ = fs::remove_file(&log_file); + } + + // TODO redo + let _ = extism::set_log_callback( + move |line| { + let mut file = OpenOptions::new() + .create(true) + .append(true) + .open(&log_file) + .unwrap(); + + file.write_all(line.as_bytes()).unwrap(); + }, + "trace", + ); + PluginContainer::new(id, manifest, funcs).unwrap() } diff --git a/nextgen/pdk-test-utils/src/wrappers.rs b/nextgen/pdk-test-utils/src/wrappers.rs index 5b3cad1e68f..3290cf28670 100644 --- a/nextgen/pdk-test-utils/src/wrappers.rs +++ b/nextgen/pdk-test-utils/src/wrappers.rs @@ -1,5 +1,4 @@ -use moon_pdk_api::extension::ExecuteExtensionInput; -use moon_pdk_api::MoonContext; +use moon_pdk_api::{ExecuteExtensionInput, MoonContext}; use std::path::Path; use warpgate::PluginContainer; @@ -15,16 +14,7 @@ impl ExtensionTestWrapper { } } - pub fn prepare_context(&self, context: MoonContext) -> MoonContext { - MoonContext { - working_dir: self.plugin.to_virtual_path(context.working_dir), - workspace_root: self.plugin.to_virtual_path(context.workspace_root), - } - } - - pub fn execute_extension(&self, mut input: ExecuteExtensionInput) { - input.context = self.prepare_context(input.context); - + pub fn execute_extension(&self, input: ExecuteExtensionInput) { self.plugin .call_func_without_output("execute_extension", input) .unwrap(); diff --git a/nextgen/pdk/Cargo.toml b/nextgen/pdk/Cargo.toml index ded8909d4ea..9eb83911bae 100644 --- a/nextgen/pdk/Cargo.toml +++ b/nextgen/pdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moon_pdk" -version = "0.0.1" +version = "0.0.2" edition = "2021" license = "MIT" description = "A plugin development kit for creating moon WASM plugins." @@ -8,7 +8,7 @@ homepage = "https://moonrepo.dev/moon" repository = "https://github.com/moonrepo/moon" [dependencies] -moon_pdk_api = { version = "0.0.1", path = "../pdk-api" } +moon_pdk_api = { version = "0.0.2", path = "../pdk-api" } clap = { workspace = true, features = ["derive"] } extism-pdk = { workspace = true } serde = { workspace = true } diff --git a/nextgen/pdk/src/extension.rs b/nextgen/pdk/src/extension.rs index ec69128b770..cb7c07d435a 100644 --- a/nextgen/pdk/src/extension.rs +++ b/nextgen/pdk/src/extension.rs @@ -2,8 +2,6 @@ use extism_pdk::{config, json}; use serde::de::DeserializeOwned; use warpgate_pdk::AnyResult; -pub use moon_pdk_api::extension::*; - /// Get configuration for the current extension plugin. pub fn get_extension_config() -> AnyResult { let config: T = if let Some(value) = config::get("moon_extension_config")? { diff --git a/nextgen/pdk/src/lib.rs b/nextgen/pdk/src/lib.rs index dbd37c38971..6a52736e32b 100644 --- a/nextgen/pdk/src/lib.rs +++ b/nextgen/pdk/src/lib.rs @@ -1,5 +1,12 @@ -pub mod args; -pub mod extension; +mod args; +mod extension; +pub use args::*; +pub use extension::*; pub use moon_pdk_api::*; pub use warpgate_pdk::*; + +/// Map a `miette` (or similar error) to an `extism` Error. +pub fn map_miette_error(error: impl std::fmt::Display) -> extism_pdk::Error { + anyhow!("{error}") +} diff --git a/nextgen/plugin/Cargo.toml b/nextgen/plugin/Cargo.toml index 377fab62d1f..180b92aef36 100644 --- a/nextgen/plugin/Cargo.toml +++ b/nextgen/plugin/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/moonrepo/moon" [dependencies] moon_env = { path = "../env" } -moon_pdk_api = { version = "0.0.1", path = "../pdk-api" } +moon_pdk_api = { version = "0.0.2", path = "../pdk-api" } convert_case = "0.6.0" dashmap = "5.5.3" miette = { workspace = true } diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index cfd46fc4d26..8bd46dafd30 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -21,6 +21,12 @@ - Added a `deno.version` setting to `.moon/toolchain.yml`. - Added a `toolchain.deno` setting to `moon.yml`. - Updated `moon bin` and `moon docker` commands to support Deno. +- Added a new built-in extension, `migrate-turborepo`, with new functionality. + - Replaces the previous `moon migrate from-turborepo` command. + - Added Bun support behind a new `--bun` flag. + - Added support for `globalDotEnv`, `dotEnv`, and `outputMode`. + - Scripts now run through a package manager, instead of `moon node run-script`. + - Root-level tasks will now create a root `moon.yml`, instead of warning. - Added `unixShell` and `windowsShell` task options, so that the underlying shell can be configured per task. - Implemented a new console layer for writing to stdout/stderr. @@ -30,7 +36,7 @@ #### 🐞 Fixes -- Fixed an issue where the action graph would create incorrect nodes when a tool utilizes +- Fixed an issue where the action graph would create incorrect nodes when a tool utilizes dependency workspaces, and a project is not within the workspace. ## 1.20.1 diff --git a/tests/fixtures/migrate/turborepo/app/package.json b/tests/fixtures/migrate/turborepo/app/package.json deleted file mode 100644 index 2ea736bee8c..00000000000 --- a/tests/fixtures/migrate/turborepo/app/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "turborepo-app", - "scripts": { - "build": "next build" - } -} diff --git a/tests/fixtures/migrate/turborepo/library/package.json b/tests/fixtures/migrate/turborepo/library/package.json deleted file mode 100644 index 2e8fa61ae07..00000000000 --- a/tests/fixtures/migrate/turborepo/library/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "turborepo-library", - "scripts": { - "lint": "eslint ." - } -} diff --git a/website/blog/2024-02-07_moon-v1.21.mdx b/website/blog/2024-02-07_moon-v1.21.mdx new file mode 100644 index 00000000000..87fa1e5038a --- /dev/null +++ b/website/blog/2024-02-07_moon-v1.21.mdx @@ -0,0 +1,57 @@ +--- +slug: moon-v1.21 +title: moon v1.21 - ??? +authors: [milesj] +tags: [task, options, extensions, plugins] +# image: ./img/moon/v1.20.png +--- + +In this release, we're excited to introduce extensions, our first type of plugin! + + + +## New `migrate-turborepo` extension + +In our previous release, we added support for [extensions, a new kind of WASM plugin](./moon-v1.20). +Since this is a new experimental feature, we really wanted to show off what it can do, and stress +test its boundaries. To do that, we chose to migrate the old `moon migrate from-turborepo` command +into an extension +([source can be found here](https://github.com/moonrepo/moon-extensions/tree/master/crates/migrate-turborepo)). +This is our most complex extension so far, as it: + +- Loads and parses files on the file system. +- Reads and writes JSON and YAML files. +- Supports deserializing data into structs. +- Extracts project graph information by executing `moon project-graph`. + +Do you currently have a Turborepo powered repository? And want to migrate to moon? Then simply +execute the extension as such. View our +[guide for more information](/docs/guides/extensions#migrate-turborepo)! + +```shell +$ moon ext migrate-turborepo +``` + +As part of the migration from moon's Rust core into a WASM plugin, we've added support for the +following new features: + +- Added Bun support behind a new `--bun` flag. +- Added support for Turbo's `globalDotEnv`, `dotEnv`, and `outputMode`. +- Added support for root-level tasks (`//#`) through a root `moon.yml`, instead of logging a + warning. +- Updated migrated task commands to run through a package manager, instead of + `moon node run-script`. + +:::info + +Based on the success of this extension, we plan to support a `migrate-nx` extension in the future! +If you'd like to help in this endeavor, let us know! + +::: + +## Other changes + +View the [official release](https://github.com/moonrepo/moon/releases/tag/v1.21.0) for a full list +of changes. + +- Implemented a new buffered console layer for writing to stdout/stderr. diff --git a/website/docs/commands/migrate/from-turborepo.mdx b/website/docs/commands/migrate/from-turborepo.mdx index bf1a2b05a13..27f50e2287d 100644 --- a/website/docs/commands/migrate/from-turborepo.mdx +++ b/website/docs/commands/migrate/from-turborepo.mdx @@ -3,29 +3,5 @@ title: migrate from-turborepo sidebar_label: from-turborepo --- -Use the `moon migrate from-turborepo` command to migrate a Turborepo powered repository to moon. -This process will convert the root `turbo.json` file to moon applicable configuration files: - -- Migrates `pipeline` global tasks to [`.moon/tasks/node.yml`](../../config/tasks#tasks) and project - scoped tasks to [`moon.yml`](../../config/project#tasks). -- Migrates `globalDependencies` and `globalEnv` to - [`.moon/tasks/node.yml`](../../config/tasks#implicitinputs) (via `implicitInputs`). - -```shell -$ moon migrate from-turborepo -``` - -:::caution - -moon must be [initialized](../init) and [`node`](../../config/toolchain#node) must be configured in -the toolchain before this command is ran! - -Furthermore, this process does not change existing `package.json` scripts, so if you're looking to -migrate them as well, use the [`moon migrate from-package-json`](./from-package-json) command. - -::: - -## Caveats - -- This process _will not_ migrate root-level Turborepo tasks (those starting with `//#`). You'll - need to manually create a moon [root-level project](../../guides/root-project) and migrate tasks. +This command has been deprecated, use the +[`moon ext migrate-turborepo`](../../guides/extensions#migrate-turborepo) command instead. diff --git a/website/docs/guides/extensions.mdx b/website/docs/guides/extensions.mdx index 32b3523b552..70299c80fb3 100644 --- a/website/docs/guides/extensions.mdx +++ b/website/docs/guides/extensions.mdx @@ -65,6 +65,34 @@ $ moon ext download --\ - `--dest` - Destination folder to save the file. Defaults to the current working directory. - `--name` - Override the file name. Defaults to the file name in the URL. +### `migrate-turborepo` + +The `migrate-turborepo` extension can be used to migrate a Turborepo powered repository to moon. +This process will convert the root `turbo.json` file, and any `turbo.json` files found within +packages (must be configured as projects in moon). The following changes are made: + +- Migrates `pipeline` global tasks to [`.moon/tasks/node.yml`](../config/tasks#tasks) (or `bun.yml`) + and project scoped tasks to [`moon.yml`](../config/project#tasks). Task commands will execute + `package.json` scripts through a package manager. +- Migrates root `global*` settings to [`.moon/tasks/node.yml`](../config/tasks#implicitinputs) (or + `bun.yml`) as `implicitInputs`. + +```shell +$ moon ext migrate-turborepo +``` + +:::info + +moon must be [initialized](../commands/init) and [`node`](../config/toolchain#node) or +[`bun`](../config/toolchain#bun) must be configured in the toolchain before this command is ran! +This is required for extracting `package.json` information. + +::: + +#### Arguments + +- `--bun` - Migrate to Bun based commands instead of Node.js. + ## Creating an extension Refer to our [official WASM guide](./wasm-plugins) for more information on how our WASM plugins