diff --git a/crates/octopush_cli/src/commands/execute.rs b/crates/octopush_cli/src/commands/execute.rs index 999a751..86c5ac4 100644 --- a/crates/octopush_cli/src/commands/execute.rs +++ b/crates/octopush_cli/src/commands/execute.rs @@ -66,6 +66,15 @@ pub fn execute_cmd() -> Command { .default_value("true") .required(false), ) + .arg( + Arg::new("interactive") + .long("interactive") + .short('i') + .action(ArgAction::Set) + .env("OCTOPUSH_INTERACTIVE") + .default_value("false") + .required(false), + ) } pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { @@ -84,6 +93,11 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { .ok_or(eyre::anyhow!("--dry-run is required"))? .parse()?; + let interactive: bool = args + .get_one::("interactive") + .ok_or(eyre::anyhow!("--interactive is required"))? + .parse()?; + if dryrun { tracing::info!("running in dry-run mode"); } @@ -123,21 +137,21 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { if let Some(git) = &select.git { service_register .git_selector - .run(git, &action_path, &action, dryrun) + .run(git, &action_path, &action, dryrun, interactive) .await?; } if let Some(gitea) = &select.gitea { service_register .gitea_selector - .run(gitea, &action_path, &action, dryrun) + .run(gitea, &action_path, &action, dryrun, interactive) .await?; } if let Some(github) = &select.github { service_register .github_selector - .run(github, &action_path, &action, dryrun) + .run(github, &action_path, &action, dryrun, interactive) .await?; } } diff --git a/crates/octopush_core/src/lib.rs b/crates/octopush_core/src/lib.rs index 07c1e0c..7e3e7e4 100644 --- a/crates/octopush_core/src/lib.rs +++ b/crates/octopush_core/src/lib.rs @@ -5,3 +5,4 @@ pub mod schema; pub mod selectors; mod shell; pub mod storage; +pub mod ui; diff --git a/crates/octopush_core/src/selectors/git_selector.rs b/crates/octopush_core/src/selectors/git_selector.rs index 0a6a7de..f48fa5e 100644 --- a/crates/octopush_core/src/selectors/git_selector.rs +++ b/crates/octopush_core/src/selectors/git_selector.rs @@ -6,18 +6,21 @@ use crate::{ executor::executor::DynExecutor, git::DynGitProvider, schema::models::{Action, Git}, + ui::DynUI, }; pub struct GitSelector { git_provider: DynGitProvider, executor: DynExecutor, + ui: DynUI, } impl GitSelector { - pub fn new(git_provider: DynGitProvider, executor: DynExecutor) -> Self { + pub fn new(git_provider: DynGitProvider, executor: DynExecutor, ui: DynUI) -> Self { Self { git_provider, executor, + ui, } } @@ -27,6 +30,7 @@ impl GitSelector { action_path: &PathBuf, action: &Action, dryrun: bool, + interactive: bool, ) -> eyre::Result<()> { tracing::info!("fetching repos"); for repo in &git.repositories { @@ -46,6 +50,10 @@ impl GitSelector { continue; } + if interactive { + self.ui.confirm().await?; + } + if let Some(push) = &git.push { self.git_provider .push_branch(repo, &push.branch.name) diff --git a/crates/octopush_core/src/selectors/gitea_selector.rs b/crates/octopush_core/src/selectors/gitea_selector.rs index 2071d74..08681b3 100644 --- a/crates/octopush_core/src/selectors/gitea_selector.rs +++ b/crates/octopush_core/src/selectors/gitea_selector.rs @@ -6,12 +6,14 @@ use crate::{ executor::executor::DynExecutor, git::{gitea::DynGiteaProvider, DynGitProvider}, schema::models::{Action, Gitea}, + ui::DynUI, }; pub struct GiteaSelector { gitea_provider: DynGiteaProvider, git_provider: DynGitProvider, executor: DynExecutor, + ui: DynUI, } impl GiteaSelector { @@ -19,11 +21,13 @@ impl GiteaSelector { gitea_provider: DynGiteaProvider, git_provider: DynGitProvider, executor: DynExecutor, + ui: DynUI, ) -> Self { Self { gitea_provider, git_provider, executor, + ui, } } @@ -33,6 +37,7 @@ impl GiteaSelector { action_path: &PathBuf, action: &Action, dryrun: bool, + interactive: bool, ) -> eyre::Result<()> { tracing::info!("fetching repos"); for repo in &git.repositories { @@ -52,6 +57,10 @@ impl GiteaSelector { continue; } + if interactive { + self.ui.confirm().await?; + } + if let Some(push) = &git.push { self.git_provider .push_branch(repo, &push.pull_request.name) diff --git a/crates/octopush_core/src/selectors/github_selector.rs b/crates/octopush_core/src/selectors/github_selector.rs index af6dd26..ef81b3b 100644 --- a/crates/octopush_core/src/selectors/github_selector.rs +++ b/crates/octopush_core/src/selectors/github_selector.rs @@ -6,12 +6,14 @@ use crate::{ executor::executor::DynExecutor, git::{github::DynGitHubProvider, DynGitProvider}, schema::models::{Action, GitHub}, + ui::DynUI, }; pub struct GitHubSelector { github_provider: DynGitHubProvider, git_provider: DynGitProvider, executor: DynExecutor, + ui: DynUI, } impl GitHubSelector { @@ -19,11 +21,13 @@ impl GitHubSelector { github_provider: DynGitHubProvider, git_provider: DynGitProvider, executor: DynExecutor, + ui: DynUI, ) -> Self { Self { github_provider, git_provider, executor, + ui, } } @@ -33,6 +37,7 @@ impl GitHubSelector { action_path: &PathBuf, action: &Action, dryrun: bool, + interactive: bool, ) -> eyre::Result<()> { tracing::info!("fetching repos"); for repo in &git.repositories { @@ -52,6 +57,10 @@ impl GitHubSelector { continue; } + if interactive { + self.ui.confirm().await?; + } + if let Some(push) = &git.push { self.git_provider .push_branch(repo, &push.pull_request.name) diff --git a/crates/octopush_core/src/ui/mod.rs b/crates/octopush_core/src/ui/mod.rs new file mode 100644 index 0000000..c4bd615 --- /dev/null +++ b/crates/octopush_core/src/ui/mod.rs @@ -0,0 +1,12 @@ +pub mod terminal_ui; + +use std::sync::Arc; + +use async_trait::async_trait; + +#[async_trait] +pub trait UI { + async fn confirm(&self) -> eyre::Result<()>; +} + +pub type DynUI = Arc; diff --git a/crates/octopush_core/src/ui/terminal_ui.rs b/crates/octopush_core/src/ui/terminal_ui.rs new file mode 100644 index 0000000..3fc9ae2 --- /dev/null +++ b/crates/octopush_core/src/ui/terminal_ui.rs @@ -0,0 +1,47 @@ +use std::{ + io::{self, Write}, + process::exit, +}; + +use async_trait::async_trait; + +use super::UI; + +pub struct TerminalUI {} + +impl TerminalUI { + pub fn new() -> Self { + Self {} + } + + pub async fn query_console(&self) -> eyre::Result<()> { + print!("Continue? ([Y]es/[N]o): "); + std::io::stdout().lock().flush()?; + let mut input = String::new(); + let _ = io::stdin().read_line(&mut input)?; + + if input.to_lowercase().starts_with("y") { + return Ok(()); + } else if input.to_lowercase().starts_with("n") { + exit(0) + } else { + Err(eyre::anyhow!("input not valid")) + } + } +} + +#[async_trait] +impl UI for TerminalUI { + async fn confirm(&self) -> eyre::Result<()> { + match self.query_console().await { + Ok(_) => Ok(()), + Err(e) => { + if e.to_string().starts_with("input not valid") { + self.query_console().await + } else { + Err(e) + } + } + } + } +} diff --git a/crates/octopush_infra/src/service_register.rs b/crates/octopush_infra/src/service_register.rs index d21f266..1098abe 100644 --- a/crates/octopush_infra/src/service_register.rs +++ b/crates/octopush_infra/src/service_register.rs @@ -22,6 +22,7 @@ use octopush_core::{ git_selector::GitSelector, gitea_selector::GiteaSelector, github_selector::GitHubSelector, }, storage::{local::LocalStorageEngine, DynStorageEngine}, + ui::{terminal_ui::TerminalUI, DynUI}, }; pub struct ServiceRegister { @@ -35,6 +36,7 @@ pub struct ServiceRegister { pub gitea_selector: Arc, pub github_provider: DynGitHubProvider, pub github_selector: Arc, + pub ui: DynUI, } impl ServiceRegister { @@ -57,11 +59,19 @@ impl ServiceRegister { storage_engine.clone(), gitea_client.clone(), )); - let git_selector = Arc::new(GitSelector::new(git_provider.clone(), executor.clone())); + + let ui = Arc::new(TerminalUI::new()); + + let git_selector = Arc::new(GitSelector::new( + git_provider.clone(), + executor.clone(), + ui.clone(), + )); let gitea_selector = Arc::new(GiteaSelector::new( gitea_provider.clone(), git_provider.clone(), executor.clone(), + ui.clone(), )); let github_client = Arc::new(DefaultGitHubClient::new(&github_client_options)?); let github_provider = Arc::new(DefaultGitHubProvider::new( @@ -73,6 +83,7 @@ impl ServiceRegister { github_provider.clone(), git_provider.clone(), executor.clone(), + ui.clone(), )); Ok(Self { @@ -86,6 +97,7 @@ impl ServiceRegister { gitea_selector, github_provider, github_selector, + ui, }) }