git-next/crates/git/src/reset.rs
Paul Campbell 1e38330914
All checks were successful
ci/woodpecker/tag/cron-docker-builder Pipeline was successful
ci/woodpecker/tag/push-next Pipeline was successful
ci/woodpecker/tag/tag-created Pipeline was successful
ci/woodpecker/push/cron-docker-builder Pipeline was successful
ci/woodpecker/push/push-next Pipeline was successful
ci/woodpecker/push/tag-created Pipeline was successful
feat(git): add git_dir value to error when reset fails
2024-05-13 19:09:11 +01:00

80 lines
2.3 KiB
Rust

use std::ops::Deref;
use git_next_config::BranchName;
use secrecy::ExposeSecret;
use tracing::{info, warn};
use super::{GitRef, RepoDetails, Repository};
#[derive(Debug)]
pub enum Force {
No,
From(GitRef),
}
impl std::fmt::Display for Force {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::No => write!(f, "fast-foward"),
Self::From(from) => write!(f, "force-if-from:{}", from),
}
}
}
// TODO: (#72) reimplement using `gix`
#[tracing::instrument(skip_all, fields(branch = %branch_name, to = %to_commit, force = %force))]
pub fn reset(
repository: &Repository,
repo_details: &RepoDetails,
branch_name: BranchName,
to_commit: GitRef,
force: Force,
) -> Result {
let origin = repo_details.origin();
let force = match force {
Force::No => "".to_string(),
Force::From(old_ref) => format!("--force-with-lease={branch_name}:{old_ref}"),
};
// INFO: never log the command as it contains the API token within the 'origin'
let command: secrecy::Secret<String> = format!(
"/usr/bin/git push {} {to_commit}:{branch_name} {force}",
origin.expose_secret()
)
.into();
let git_dir = repository.deref().git_dir();
let ctx = gix::diff::command::Context {
git_dir: Some(git_dir.to_path_buf()),
..Default::default()
};
match gix::command::prepare(command.expose_secret())
.with_context(ctx)
.with_shell_allow_argument_splitting()
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()
{
Ok(mut child) => match child.wait() {
Ok(_) => {
info!("Branch updated");
Ok(())
}
Err(err) => {
warn!(?err, ?git_dir, "Failed (wait)");
Err(BranchResetError::Push)
}
},
Err(err) => {
warn!(?err, ?git_dir, "Failed (spawn)");
Err(BranchResetError::Push)
}
}
}
#[derive(Debug, derive_more::From, derive_more::Display)]
pub enum BranchResetError {
Open(Box<gix::open::Error>),
Fetch(super::fetch::Error),
Push,
}
impl std::error::Error for BranchResetError {}
pub type Result = core::result::Result<(), BranchResetError>;