Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 48 additions & 6 deletions src/commands/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,35 +35,77 @@ impl Command for CloneCommand {
format!("Cloning {} repositories...", repositories.len()).green()
);

let mut errors = Vec::new();
let mut successful = 0;

if context.parallel {
let tasks: Vec<_> = repositories
.into_iter()
.map(|repo| {
let repo_name = repo.name.clone();
tokio::spawn(async move {
tokio::task::spawn_blocking(move || git::clone_repository(&repo)).await?
let result =
tokio::task::spawn_blocking(move || git::clone_repository(&repo))
.await?;
Ok::<_, anyhow::Error>((repo_name, result))
})
})
.collect();

for task in tasks {
if let Err(e) = task.await? {
eprintln!("{}", format!("Error: {e}").red());
match task.await? {
Ok((_, Ok(_))) => successful += 1,
Ok((repo_name, Err(e))) => {
eprintln!("{}", format!("Error: {e}").red());
errors.push((repo_name, e));
}
Err(e) => {
eprintln!("{}", format!("Task error: {e}").red());
errors.push(("unknown".to_string(), e));
}
}
}
} else {
for repo in repositories {
if let Err(e) = tokio::task::spawn_blocking({
let repo_name = repo.name.clone();
match tokio::task::spawn_blocking({
let repo = repo.clone();
move || git::clone_repository(&repo)
})
.await?
{
eprintln!("{}", format!("Error: {e}").red());
Ok(_) => successful += 1,
Err(e) => {
eprintln!("{}", format!("Error: {e}").red());
errors.push((repo_name, e));
}
}
}
}

println!("{}", "Done cloning repositories".green());
// Report summary
if errors.is_empty() {
println!("{}", "Done cloning repositories".green());
} else {
println!(
"{}",
format!(
"Completed with {} successful, {} failed",
successful,
errors.len()
)
.yellow()
);

// If all operations failed, return an error to propagate to main
if successful == 0 {
return Err(anyhow::anyhow!(
"All clone operations failed. First error: {}",
errors[0].1
));
}
}

Ok(())
}
}
59 changes: 49 additions & 10 deletions src/commands/pr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,33 +59,72 @@ impl Command for PrCommand {
create_only: self.create_only,
};

let mut errors = Vec::new();
let mut successful = 0;

if context.parallel {
let tasks: Vec<_> = repositories
.into_iter()
.map(|repo| {
let pr_options = pr_options.clone();
async move { github::create_pull_request(&repo, &pr_options).await }
async move {
(
repo.name.clone(),
github::create_pull_request(&repo, &pr_options).await,
)
}
})
.collect();

for task in tasks {
if let Err(e) = task.await {
eprintln!("{}", format!("Error: {e}").red());
let (repo_name, result) = task.await;
match result {
Ok(_) => successful += 1,
Err(e) => {
eprintln!("{}", format!("Error: {e}").red());
errors.push((repo_name, e));
}
}
}
} else {
for repo in repositories {
if let Err(e) = github::create_pull_request(&repo, &pr_options).await {
eprintln!(
"{} | {}",
repo.name.cyan().bold(),
format!("Error: {e}").red()
);
match github::create_pull_request(&repo, &pr_options).await {
Ok(_) => successful += 1,
Err(e) => {
eprintln!(
"{} | {}",
repo.name.cyan().bold(),
format!("Error: {e}").red()
);
errors.push((repo.name.clone(), e));
}
}
}
}

println!("{}", "Done processing pull requests".green());
// Report summary
if errors.is_empty() {
println!("{}", "Done processing pull requests".green());
} else {
println!(
"{}",
format!(
"Completed with {} successful, {} failed",
successful,
errors.len()
)
.yellow()
);

// If all operations failed, return an error to propagate to main
if successful == 0 {
return Err(anyhow::anyhow!(
"All pull request operations failed. First error: {}",
errors[0].1
));
}
}

Ok(())
}
}
67 changes: 54 additions & 13 deletions src/commands/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,50 +35,91 @@ impl Command for RemoveCommand {
format!("Removing {} repositories...", repositories.len()).green()
);

let mut errors = Vec::new();
let mut successful = 0;

if context.parallel {
let tasks: Vec<_> = repositories
.into_iter()
.map(|repo| {
let repo_name = repo.name.clone();
tokio::spawn(async move {
let target_dir = repo.get_target_dir();
tokio::task::spawn_blocking(move || {
let result = tokio::task::spawn_blocking(move || {
if std::path::Path::new(&target_dir).exists() {
fs::remove_dir_all(&target_dir).map_err(anyhow::Error::from)
} else {
println!("{} | Directory does not exist", repo.name.cyan().bold());
Ok(())
}
})
.await?
.await?;
Ok::<_, anyhow::Error>((repo_name, result))
})
})
.collect();

for task in tasks {
if let Err(e) = task.await? {
eprintln!("{}", format!("Error: {e}").red());
match task.await? {
Ok((_, Ok(_))) => successful += 1,
Ok((repo_name, Err(e))) => {
eprintln!("{}", format!("Error: {e}").red());
errors.push((repo_name, e));
}
Err(e) => {
eprintln!("{}", format!("Task error: {e}").red());
errors.push(("unknown".to_string(), e));
}
}
}
} else {
for repo in repositories {
let target_dir = repo.get_target_dir();
if std::path::Path::new(&target_dir).exists() {
if let Err(e) = fs::remove_dir_all(&target_dir) {
eprintln!(
"{} | {}",
repo.name.cyan().bold(),
format!("Error: {e}").red()
);
} else {
println!("{} | {}", repo.name.cyan().bold(), "Removed".green());
match fs::remove_dir_all(&target_dir) {
Ok(_) => {
println!("{} | {}", repo.name.cyan().bold(), "Removed".green());
successful += 1;
}
Err(e) => {
eprintln!(
"{} | {}",
repo.name.cyan().bold(),
format!("Error: {e}").red()
);
errors.push((repo.name.clone(), e.into()));
}
}
} else {
println!("{} | Directory does not exist", repo.name.cyan().bold());
successful += 1; // Count as success since the desired state is achieved
}
}
}

println!("{}", "Done removing repositories".green());
// Report summary
if errors.is_empty() {
println!("{}", "Done removing repositories".green());
} else {
println!(
"{}",
format!(
"Completed with {} successful, {} failed",
successful,
errors.len()
)
.yellow()
);

// If all operations failed, return an error to propagate to main
if successful == 0 {
return Err(anyhow::anyhow!(
"All removal operations failed. First error: {}",
errors[0].1
));
}
}

Ok(())
}
}
59 changes: 49 additions & 10 deletions src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,38 +45,77 @@ impl Command for RunCommand {

let runner = CommandRunner::new();

let mut errors = Vec::new();
let mut successful = 0;

if context.parallel {
let tasks: Vec<_> = repositories
.into_iter()
.map(|repo| {
let runner = &runner;
let command = self.command.clone();
let log_dir = self.log_dir.clone();
async move { runner.run_command(&repo, &command, Some(&log_dir)).await }
async move {
(
repo.name.clone(),
runner.run_command(&repo, &command, Some(&log_dir)).await,
)
}
})
.collect();

for task in tasks {
if let Err(e) = task.await {
eprintln!("{}", format!("Error: {e}").red());
let (repo_name, result) = task.await;
match result {
Ok(_) => successful += 1,
Err(e) => {
eprintln!("{}", format!("Error: {e}").red());
errors.push((repo_name, e));
}
}
}
} else {
for repo in repositories {
if let Err(e) = runner
match runner
.run_command(&repo, &self.command, Some(&self.log_dir))
.await
{
eprintln!(
"{} | {}",
repo.name.cyan().bold(),
format!("Error: {e}").red()
);
Ok(_) => successful += 1,
Err(e) => {
eprintln!(
"{} | {}",
repo.name.cyan().bold(),
format!("Error: {e}").red()
);
errors.push((repo.name.clone(), e));
}
}
}
}

println!("{}", "Done running commands".green());
// Report summary
if errors.is_empty() {
println!("{}", "Done running commands".green());
} else {
println!(
"{}",
format!(
"Completed with {} successful, {} failed",
successful,
errors.len()
)
.yellow()
);

// If all operations failed, return an error to propagate to main
if successful == 0 {
return Err(anyhow::anyhow!(
"All command executions failed. First error: {}",
errors[0].1
));
}
}

Ok(())
}
}
Loading