diff --git a/crates/cli/src/commands/apply.rs b/crates/cli/src/commands/apply.rs index 684005541..e916f8507 100644 --- a/crates/cli/src/commands/apply.rs +++ b/crates/cli/src/commands/apply.rs @@ -99,7 +99,7 @@ pub(crate) async fn run_apply( .await; if let Some(custom_workflow) = custom_workflow { - return run_apply_migration( + run_apply_migration( custom_workflow, paths, ranges, @@ -113,7 +113,9 @@ pub(crate) async fn run_apply( "grit_marzano.run_workflow", "execution_id" = execution_id.as_str(), )) - .await; + .await?; + + return Ok(()); } } diff --git a/crates/cli/src/commands/apply_migration.rs b/crates/cli/src/commands/apply_migration.rs index ee0547eec..03c90b189 100644 --- a/crates/cli/src/commands/apply_migration.rs +++ b/crates/cli/src/commands/apply_migration.rs @@ -8,6 +8,7 @@ use anyhow::Result; use clap::Args; use marzano_gritmodule::searcher::WorkflowInfo; use marzano_messenger::emit::Messager; +use marzano_messenger::workflows::PackagedWorkflowOutcome; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -69,7 +70,7 @@ pub(crate) async fn run_apply_migration( flags: &GlobalFormatFlags, min_level: marzano_messenger::emit::VisibilityLevels, execution_id: String, -) -> Result<()> { +) -> Result { use crate::error::GoodError; let input = arg.get_payload()?; @@ -104,13 +105,13 @@ pub(crate) async fn run_apply_migration( emitter.flush().await?; // Get the final workflow status from the emitter - if let Some(workflow_status) = emitter.get_workflow_status()? { - if !workflow_status.success { - anyhow::bail!(GoodError::new()); - } - } else { + let Some(workflow_status) = emitter.get_workflow_status()? else { anyhow::bail!("Final workflow status not found"); + }; + + if !workflow_status.success { + anyhow::bail!(GoodError::new()); } - Ok(()) + Ok(workflow_status.clone()) } diff --git a/crates/cli/src/commands/mod.rs b/crates/cli/src/commands/mod.rs index 85f854275..9ed243acf 100644 --- a/crates/cli/src/commands/mod.rs +++ b/crates/cli/src/commands/mod.rs @@ -30,6 +30,8 @@ pub(crate) mod workflows; #[cfg(feature = "workflows_v2")] pub(crate) mod workflows_list; #[cfg(feature = "workflows_v2")] +pub(crate) mod workflows_upload; +#[cfg(feature = "workflows_v2")] pub(crate) mod workflows_watch; use crate::error::GoodError; @@ -100,6 +102,8 @@ use crate::commands::workflows::{WorkflowCommands, Workflows}; #[cfg(feature = "workflows_v2")] use workflows_list::run_list_workflows; #[cfg(feature = "workflows_v2")] +use workflows_upload::run_upload_workflows; +#[cfg(feature = "workflows_v2")] use workflows_watch::run_watch_workflow; #[cfg(feature = "docgen")] @@ -196,6 +200,7 @@ impl fmt::Display for Commands { Commands::Workflows(arg) => match arg.workflows_commands { WorkflowCommands::List(_) => write!(f, "workflows list"), WorkflowCommands::Watch(_) => write!(f, "workflows watch"), + WorkflowCommands::Upload(_) => write!(f, "workflows upload"), }, Commands::Plumbing(_) => write!(f, "plumbing"), Commands::Version(_) => write!(f, "version"), @@ -416,6 +421,9 @@ async fn run_command(_use_tracing: bool) -> Result<()> { Commands::Workflows(arg) => match arg.workflows_commands { WorkflowCommands::List(arg) => run_list_workflows(&arg, &app.format_flags).await, WorkflowCommands::Watch(arg) => run_watch_workflow(&arg, &app.format_flags).await, + WorkflowCommands::Upload(arg) => { + run_upload_workflows(&arg, &app.format_flags).await + } }, Commands::Plumbing(arg) => { run_plumbing(arg, multi, &mut apply_details, app.format_flags).await diff --git a/crates/cli/src/commands/plumbing.rs b/crates/cli/src/commands/plumbing.rs index bb5479a15..d4ef82fd5 100644 --- a/crates/cli/src/commands/plumbing.rs +++ b/crates/cli/src/commands/plumbing.rs @@ -344,7 +344,9 @@ pub(crate) async fn run_plumbing( "grit_marzano.run_workflow", "execution_id" = execution_id.as_str(), )) - .await + .await?; + + Ok(()) } }; // We want plumbing to always return a success code, even for "good" errors (failed checks, etc) diff --git a/crates/cli/src/commands/workflows.rs b/crates/cli/src/commands/workflows.rs index d93b8d0f0..2cfcd8f02 100644 --- a/crates/cli/src/commands/workflows.rs +++ b/crates/cli/src/commands/workflows.rs @@ -1,7 +1,7 @@ use clap::{Parser, Subcommand}; use serde::Serialize; -use super::{workflows_list::WorkflowsListArgs, workflows_watch::WorkflowWatchArgs}; +use super::{workflows_list::WorkflowsListArgs, workflows_watch::WorkflowWatchArgs, workflows_upload::WorkflowsUploadArgs}; #[derive(Parser, Debug, Serialize)] pub struct Workflows { @@ -16,4 +16,6 @@ pub enum WorkflowCommands { /// Watch an existing workflow #[clap(hide = true)] Watch(WorkflowWatchArgs), + /// Upload a workflow + Upload(WorkflowsUploadArgs), } diff --git a/crates/cli/src/commands/workflows_upload.rs b/crates/cli/src/commands/workflows_upload.rs new file mode 100644 index 000000000..bfd54d614 --- /dev/null +++ b/crates/cli/src/commands/workflows_upload.rs @@ -0,0 +1,60 @@ +use anyhow::{bail, Result}; +use clap::Args; +use serde::Serialize; +use std::path::PathBuf; + +use crate::flags::GlobalFormatFlags; + +use crate::commands::apply_migration::{run_apply_migration, ApplyMigrationArgs}; +use crate::workflows::fetch_remote_workflow; +use marzano_messenger::emit::VisibilityLevels; + +#[derive(Args, Debug, Serialize)] +pub struct WorkflowsUploadArgs { + #[clap(index = 1)] + workflow_path: String, +} + +pub async fn run_upload_workflows( + _arg: &WorkflowsUploadArgs, + parent: &GlobalFormatFlags, +) -> Result<()> { + if parent.json || parent.jsonl { + bail!("JSON output not supported for workflows"); + } + + let workflow_path = PathBuf::from(&_arg.workflow_path); + let workflow_info = fetch_remote_workflow( + "https://storage.googleapis.com/grit-workflows-dev-workflow_definitions/upload_workflow.js", + None, + ) + .await?; + + let apply_migration_args = ApplyMigrationArgs { + input: Some(format!(r#"{{"workflow": "{}"}}"#, workflow_path.display())), + ..Default::default() + }; + + let execution_id = + std::env::var("GRIT_EXECUTION_ID").unwrap_or_else(|_| uuid::Uuid::new_v4().to_string()); + + let result = run_apply_migration( + workflow_info, + vec![], + None, + apply_migration_args, + parent, + VisibilityLevels::default(), + execution_id, + ) + .await?; + + if let Some(data) = result.data.and_then(|v| v.get("id").cloned()) { + if let Some(data_str) = data.as_str() { + println!("Uploaded Workflow ID: {}", data_str); + return Ok(()); + } + } + + bail!("Failed to upload workflow: URL not returned") +} diff --git a/crates/cli/src/workflows.rs b/crates/cli/src/workflows.rs index ee6baa230..c83c71ca1 100644 --- a/crates/cli/src/workflows.rs +++ b/crates/cli/src/workflows.rs @@ -339,7 +339,7 @@ pub async fn run_remote_workflow( Ok(()) } -async fn fetch_remote_workflow( +pub async fn fetch_remote_workflow( workflow_path_or_name: &str, auth: Option, ) -> Result {