Skip to content

Commit

Permalink
feat: add run command (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
fioncat authored Aug 8, 2023
1 parent 649bf8b commit 413f71f
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 40 deletions.
1 change: 1 addition & 0 deletions src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ where
handler.join().unwrap();
}

println!();
println!(
"{desc} done, with {} successed, {} failed",
style(suc_count).green(),
Expand Down
3 changes: 3 additions & 0 deletions src/cmd/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::cmd::run::rebase::RebaseArgs;
use crate::cmd::run::release::ReleaseArgs;
use crate::cmd::run::remove::RemoveArgs;
use crate::cmd::run::reset::ResetArgs;
use crate::cmd::run::run::RunArgs;
use crate::cmd::run::squash::SquashArgs;
use crate::cmd::run::tag::TagArgs;
use crate::cmd::run::update::UpdateArgs;
Expand Down Expand Up @@ -51,6 +52,7 @@ pub enum Commands {
Update(UpdateArgs),
Clear(ClearArgs),
Import(ImportArgs),
Run(RunArgs),
}

impl Run for App {
Expand Down Expand Up @@ -79,6 +81,7 @@ impl Run for App {
Commands::Update(args) => args.run(),
Commands::Clear(args) => args.run(),
Commands::Import(args) => args.run(),
Commands::Run(args) => args.run(),
}
}
}
1 change: 1 addition & 0 deletions src/cmd/complete/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod home;
pub mod owner;
pub mod release;
pub mod remote;
pub mod run;
pub mod tag;

pub struct Complete {
Expand Down
21 changes: 21 additions & 0 deletions src/cmd/complete/run.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use anyhow::Result;

use crate::cmd::complete::home;
use crate::cmd::complete::Complete;
use crate::config;

pub fn complete(args: &[&str]) -> Result<Complete> {
if args.is_empty() {
return Ok(Complete::empty());
}
if args.len() == 1 {
let mut names: Vec<String> = config::base()
.workflows
.iter()
.map(|(key, _)| key.clone())
.collect();
names.sort();
return Ok(Complete::from(names));
}
home::complete(&args[1..])
}
2 changes: 2 additions & 0 deletions src/cmd/run/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::cmd::complete::home;
use crate::cmd::complete::owner;
use crate::cmd::complete::release;
use crate::cmd::complete::remote;
use crate::cmd::complete::run;
use crate::cmd::complete::tag;
use crate::cmd::complete::Complete;
use crate::cmd::Run;
Expand Down Expand Up @@ -58,6 +59,7 @@ impl CompleteArgs {
"update" => no_complete,
"clear" => owner::complete,
"import" => owner::complete,
"run" => run::complete,
}
}

Expand Down
19 changes: 5 additions & 14 deletions src/cmd/run/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use std::io::ErrorKind;
use std::path::PathBuf;
use std::rc::Rc;

use anyhow::{bail, Context, Result};
use anyhow::{Context, Result};
use clap::Args;

use crate::cmd::Run;
use crate::config::types::Remote;
use crate::repo::database::Database;
use crate::repo::types::{NameLevel, Repo};
use crate::shell::Shell;
use crate::{api, info, shell};
use crate::shell::{Shell, Workflow};
use crate::{api, shell};
use crate::{config, confirm, utils};

/// Print the home path of a repo, recommand to use `zz` command instead.
Expand Down Expand Up @@ -158,17 +158,8 @@ impl HomeArgs {
if let Some(owner) = remote.owners.get(repo.owner.as_str()) {
if let Some(workflow_names) = &owner.on_create {
for workflow_name in workflow_names.iter() {
let maybe_workflow = config::base().workflows.get(workflow_name);
if let None = maybe_workflow {
bail!(
"Could not find workeflow {} for owner {}, please check your config",
workflow_name,
repo.owner.as_str(),
);
}
let workflow = maybe_workflow.unwrap();
info!("Execute on_create workflow {}", workflow_name);
shell::execute_workflow(workflow, repo)?;
let wf = Workflow::new(workflow_name)?;
wf.execute_repo(repo)?;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/cmd/run/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod rebase;
pub mod release;
pub mod remove;
pub mod reset;
pub mod run;
pub mod squash;
pub mod tag;
pub mod update;
171 changes: 171 additions & 0 deletions src/cmd/run/run.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
use std::collections::HashSet;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;

use anyhow::{bail, Result};
use clap::Args;
use console::style;

use crate::batch::{self, Reporter, Task};
use crate::cmd::Run;
use crate::repo::database::Database;
use crate::repo::types::{NameLevel, Repo};
use crate::shell::Workflow;
use crate::{config, confirm, utils};

/// Run workflow
#[derive(Args)]
pub struct RunArgs {
/// The workflow name.
pub workflow: String,

/// The remote name.
pub remote: Option<String>,

/// The repo query.
pub query: Option<String>,

/// If true, filter repos.
#[clap(long, short)]
pub filter: bool,

/// If true, run workflow for current repo.
#[clap(long, short)]
pub current: bool,
}

struct RunTask {
workflow: Arc<Workflow>,
name_level: Arc<NameLevel>,
dir: PathBuf,

remote: String,
owner: String,
name: String,

show_name: String,
}

impl Task<()> for RunTask {
fn run(&self, rp: &Reporter<()>) -> Result<()> {
self.workflow.execute_task(
&self.name_level,
rp,
&self.dir,
&self.remote,
&self.owner,
&self.name,
)
}

fn message_done(&self, result: &Result<()>) -> String {
match result {
Ok(_) => format!("Run workflow for {} done", self.show_name),
Err(_) => {
let msg = format!("Run workflow for {} failed", self.show_name);
format!("{}", style(msg).red())
}
}
}
}

impl Run for RunArgs {
fn run(&self) -> Result<()> {
let workflow = Workflow::new(self.workflow.as_str())?;
let workflow = Arc::new(workflow);
let (mut repos, level) = self.select_repos()?;
if repos.is_empty() {
println!("No repo to run");
return Ok(());
}
if repos.len() == 1 {
let repo = repos.into_iter().next().unwrap();
confirm!(
"Run workflow {} for repo {}",
self.workflow,
repo.full_name()
);
workflow.execute_repo(&repo)?;
return Ok(());
}
if self.filter {
let items: Vec<String> = repos.iter().map(|repo| repo.as_string(&level)).collect();
let items = utils::edit_items(items)?;
let filter_set: HashSet<String> = items.into_iter().collect();
repos = repos
.into_iter()
.filter(|repo| filter_set.contains(&repo.as_string(&level)))
.collect();
if repos.is_empty() {
println!("No repo to run after filter");
return Ok(());
}
}

println!("About to run:");
for repo in repos.iter() {
let name = repo.as_string(&level);
println!(" * {}", name);
}
let repo_word = if repos.len() == 1 {
String::from("1 repo")
} else {
format!("{} repos", repos.len())
};
confirm!(
"Do you want to run workflow {} for {}",
self.workflow,
repo_word
);

let level = Arc::new(level);
let mut tasks = Vec::with_capacity(repos.len());
for repo in repos {
let dir = repo.get_path();
let show_name = repo.as_string(&level);
tasks.push(RunTask {
workflow: workflow.clone(),
name_level: level.clone(),
dir,
remote: format!("{}", repo.remote),
owner: format!("{}", repo.owner),
name: format!("{}", repo.name),
show_name,
})
}

let desc = format!("Run workflow {}", self.workflow);
let _ = batch::run(desc.as_str(), tasks);
Ok(())
}
}

impl RunArgs {
fn select_repos(&self) -> Result<(Vec<Rc<Repo>>, NameLevel)> {
let db = Database::read()?;
if self.current {
let repo = db.must_current()?;
return Ok((vec![repo], NameLevel::Name));
}
if let None = &self.remote {
return Ok((db.list_all(), NameLevel::Full));
}
let remote = self.remote.as_ref().unwrap().as_str();
if let None = &self.query {
return Ok((db.list_by_remote(remote), NameLevel::Owner));
}
let query = self.query.as_ref().unwrap().as_str();
let query = query.trim_matches('/');
if query.is_empty() {
bail!("Invalid query {}", self.query.as_ref().unwrap());
}
if !query.contains("/") {
return Ok((db.list_by_owner(remote, query), NameLevel::Name));
}
let remote = config::must_get_remote(remote)?;
let (owner, name) = utils::parse_query(&remote, query);
let repo = db.must_get(&remote.name, &owner, &name)?;
Ok((vec![repo], NameLevel::Name))
}
}
Loading

0 comments on commit 413f71f

Please sign in to comment.