use crate::{
errors::{Result, RonaError},
git::handle_output,
};
use indicatif::{ProgressBar, ProgressDrawTarget};
use std::io::IsTerminal;
use std::process::Command;
use std::time::Duration;
fn try_get_default_branch() -> Result<String> {
let output = Command::new("git")
.args(["config", "--get", "init.defaultBranch"])
.output()
.map_err(RonaError::Io)?;
if output.status.success() {
let branch = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !branch.is_empty() {
return Ok(branch);
}
}
Ok("main".to_string())
}
pub fn get_current_branch() -> Result<String> {
let output = Command::new("git")
.args(["symbolic-ref", "--short", "HEAD"])
.output()
.map_err(RonaError::Io)?;
if output.status.success() {
let branch = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !branch.is_empty() {
return Ok(branch);
}
}
let output = Command::new("git")
.args(["rev-parse", "--abbrev-ref", "HEAD"])
.output()
.map_err(RonaError::Io)?;
if output.status.success() {
let branch = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !branch.is_empty() {
return Ok(branch);
}
}
try_get_default_branch()
}
#[must_use]
pub fn format_branch_name(commit_types: &[&str], branch: &str) -> String {
let mut formatted_branch = branch.to_owned();
for commit_type in commit_types {
if formatted_branch.contains(commit_type) {
formatted_branch = formatted_branch.replace(&format!("{commit_type}/"), "");
}
}
formatted_branch
}
#[tracing::instrument]
pub fn git_switch(branch_name: &str) -> Result<()> {
tracing::debug!("Switching to branch: {branch_name}");
let output = Command::new("git")
.args(["switch", branch_name])
.output()
.map_err(RonaError::Io)?;
handle_output("switch", &output)
}
#[tracing::instrument]
pub fn git_create_branch(branch_name: &str) -> Result<()> {
tracing::debug!("Creating new branch: {branch_name}");
let output = Command::new("git")
.args(["switch", "-c", branch_name])
.output()
.map_err(RonaError::Io)?;
handle_output("create branch", &output)
}
pub fn git_pull(verbose: bool) -> Result<()> {
tracing::debug!("Pulling latest changes...");
let show_spinner = !verbose && std::io::stderr().is_terminal();
let output = if show_spinner {
let pb = ProgressBar::new_spinner();
pb.set_draw_target(ProgressDrawTarget::stderr());
pb.set_message("Pulling...");
pb.enable_steady_tick(Duration::from_millis(80));
let handle = std::thread::spawn(|| Command::new("git").arg("pull").output());
let result = handle.join().map_err(|_| RonaError::CommandFailed {
command: "git pull".to_string(),
})?;
pb.finish_and_clear();
result?
} else {
Command::new("git").arg("pull").output()?
};
handle_output("pull", &output)
}
pub fn git_merge(branch_name: &str, verbose: bool) -> Result<()> {
tracing::debug!("Merging {branch_name} into current branch...");
let show_spinner = !verbose && std::io::stderr().is_terminal();
let branch_owned = branch_name.to_string();
let output = if show_spinner {
let pb = ProgressBar::new_spinner();
pb.set_draw_target(ProgressDrawTarget::stderr());
pb.set_message(format!("Merging {branch_name}..."));
pb.enable_steady_tick(Duration::from_millis(80));
let handle = std::thread::spawn(move || {
Command::new("git").arg("merge").arg(&branch_owned).output()
});
let result = handle.join().map_err(|_| RonaError::CommandFailed {
command: "git merge".to_string(),
})?;
pb.finish_and_clear();
result?
} else {
Command::new("git").arg("merge").arg(branch_name).output()?
};
handle_output("merge", &output)
}
pub fn git_rebase(branch_name: &str, verbose: bool) -> Result<()> {
tracing::debug!("Rebasing onto {branch_name}...");
let show_spinner = !verbose && std::io::stderr().is_terminal();
let branch_owned = branch_name.to_string();
let output = if show_spinner {
let pb = ProgressBar::new_spinner();
pb.set_draw_target(ProgressDrawTarget::stderr());
pb.set_message(format!("Rebasing onto {branch_name}..."));
pb.enable_steady_tick(Duration::from_millis(80));
let handle = std::thread::spawn(move || {
Command::new("git")
.arg("rebase")
.arg(&branch_owned)
.output()
});
let result = handle.join().map_err(|_| RonaError::CommandFailed {
command: "git rebase".to_string(),
})?;
pb.finish_and_clear();
result?
} else {
Command::new("git")
.arg("rebase")
.arg(branch_name)
.output()?
};
handle_output("rebase", &output)
}