use std::process::Stdio;
use indoc::formatdoc;
use crate::{
error::{add_error, Error, Result},
git::PreparedCommit,
github::{PullRequestState, PullRequestUpdate},
message::MessageSection,
output::{output, write_commit_title},
};
#[derive(Debug, clap::Parser)]
pub struct CloseOptions {
#[clap(long)]
all: bool,
}
pub async fn close(
opts: CloseOptions,
git: &crate::git::Git,
gh: &mut crate::github::GitHub,
config: &crate::config::Config,
) -> Result<()> {
let mut result = Ok(());
let mut prepared_commits = git.get_prepared_commits(config)?;
if prepared_commits.is_empty() {
output("👋", "Branch is empty - nothing to do. Good bye!")?;
return result;
};
if !opts.all {
prepared_commits.drain(0..prepared_commits.len() - 1);
}
for prepared_commit in prepared_commits.iter_mut() {
if result.is_err() {
break;
}
write_commit_title(prepared_commit)?;
result = close_impl(gh, config, prepared_commit).await;
}
add_error(
&mut result,
git.rewrite_commit_messages(prepared_commits.as_mut_slice(), None),
);
result
}
async fn close_impl(
gh: &mut crate::github::GitHub,
config: &crate::config::Config,
prepared_commit: &mut PreparedCommit,
) -> Result<()> {
let pull_request_number =
if let Some(number) = prepared_commit.pull_request_number {
output("#️⃣ ", &format!("Pull Request #{}", number))?;
number
} else {
return Err(Error::new(
"This commit does not refer to a Pull Request.",
));
};
let pull_request = gh.clone().get_pull_request(pull_request_number).await?;
if pull_request.state != PullRequestState::Open {
return Err(Error::new(formatdoc!(
"This Pull Request is already closed!",
)));
}
output("📖", "Getting started...")?;
let base_is_master = pull_request.base.is_master_branch();
let result = gh
.update_pull_request(
pull_request_number,
PullRequestUpdate {
state: Some(PullRequestState::Closed),
..Default::default()
},
)
.await;
match result {
Ok(()) => (),
Err(error) => {
output("❌", "GitHub Pull Request close failed")?;
return Err(error);
}
};
output("📕", "Closed!")?;
prepared_commit.message.remove(&MessageSection::PullRequest);
prepared_commit.message.remove(&MessageSection::ReviewedBy);
let mut remove_old_branch_child_process =
tokio::process::Command::new("git")
.arg("push")
.arg("--no-verify")
.arg("--delete")
.arg("--")
.arg(&config.remote_name)
.arg(pull_request.head.on_github())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()?;
let remove_old_base_branch_child_process = if base_is_master {
None
} else {
Some(
tokio::process::Command::new("git")
.arg("push")
.arg("--no-verify")
.arg("--delete")
.arg("--")
.arg(&config.remote_name)
.arg(pull_request.base.on_github())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()?,
)
};
remove_old_branch_child_process.wait().await?;
if let Some(mut proc) = remove_old_base_branch_child_process {
proc.wait().await?;
}
Ok(())
}