diff --git a/crates/radicle-remote-helper/src/push.rs b/crates/radicle-remote-helper/src/push.rs index 968ad378..044dbf32 100644 --- a/crates/radicle-remote-helper/src/push.rs +++ b/crates/radicle-remote-helper/src/push.rs @@ -1,4 +1,7 @@ #![allow(clippy::too_many_arguments)] + +mod error; + use std::collections::HashMap; use std::io::IsTerminal; use std::path::{Path, PathBuf}; @@ -66,9 +69,6 @@ pub enum Error { /// Invalid reference name. #[error("invalid ref: {0}")] InvalidRef(#[from] radicle::git::fmt::Error), - /// Invalid reference name. - #[error("invalid qualified ref: {0}")] - InvalidQualifiedRef(git::RefString), /// Git error. #[error("git: {0}")] Git(#[from] git::raw::Error), @@ -119,6 +119,8 @@ pub enum Error { Quorum(#[from] radicle::git::canonical::QuorumError), #[error(transparent)] CanonicalRefs(#[from] radicle::identity::doc::CanonicalRefsError), + #[error(transparent)] + PushAction(#[from] error::PushAction), } /// Push command. @@ -196,6 +198,43 @@ impl Command { } } +enum PushAction { + OpenPatch, + UpdatePatch { + dst: git::Qualified<'static>, + patch: patch::PatchId, + }, + PushRef { + dst: git::Qualified<'static>, + }, +} + +impl PushAction { + fn new(dst: &git::RefString) -> Result { + if dst == &*rad::PATCHES_REFNAME { + Ok(Self::OpenPatch) + } else { + let dst = git::Qualified::from_refstr(dst) + .ok_or_else(|| error::PushAction::InvalidRef { + refname: dst.clone(), + })? + .to_owned(); + + if let Some(oid) = dst.strip_prefix(git::refname!("refs/heads/patches")) { + let patch = git::Oid::from_str(oid) + .map_err(|err| error::PushAction::InvalidPatchId { + suffix: oid.to_string(), + err, + }) + .map(patch::PatchId::from)?; + Ok(Self::UpdatePatch { dst, patch }) + } else { + Ok(Self::PushRef { dst }) + } + } + } +} + /// Run a git push command. pub fn run( mut specs: Vec, @@ -268,9 +307,10 @@ pub fn run( } Command::Push(git::Refspec { src, dst, force }) => { let patches = crate::patches_mut(profile, stored)?; + let action = PushAction::new(dst)?; - if dst == &*rad::PATCHES_REFNAME { - patch_open( + match action { + PushAction::OpenPatch => patch_open( src, &remote, &nid, @@ -280,27 +320,20 @@ pub fn run( &signer, profile, opts.clone(), - ) - } else { - let dst = git::Qualified::from_refstr(dst) - .ok_or_else(|| Error::InvalidQualifiedRef(dst.clone()))?; - - if let Some(oid) = dst.strip_prefix(git::refname!("refs/heads/patches")) { - let oid = git::Oid::from_str(oid)?; - - patch_update( - src, - &dst, - *force, - &oid, - &nid, - &working, - stored, - patches, - &signer, - opts.clone(), - ) - } else { + ), + PushAction::UpdatePatch { dst, patch } => patch_update( + src, + &dst, + *force, + patch, + &nid, + &working, + stored, + patches, + &signer, + opts.clone(), + ), + PushAction::PushRef { dst } => { let identity = stored.identity()?; let crefs = identity.canonical_refs_or_default(|| { let rule = identity.doc().default_branch_rule()?; @@ -573,7 +606,7 @@ fn patch_update( src: &git::Oid, dst: &git::Qualified, force: bool, - oid: &git::Oid, + patch_id: patch::PatchId, nid: &NodeId, working: &git::raw::Repository, stored: &storage::git::Repository, @@ -588,7 +621,6 @@ where G: crypto::signature::Signer, { let commit = *src; - let patch_id = radicle::cob::ObjectId::from(oid); let dst = dst.with_namespace(nid.into()); push_ref(src, &dst, force, working, stored.raw())?; diff --git a/crates/radicle-remote-helper/src/push/error.rs b/crates/radicle-remote-helper/src/push/error.rs new file mode 100644 index 00000000..924c226b --- /dev/null +++ b/crates/radicle-remote-helper/src/push/error.rs @@ -0,0 +1,14 @@ +use radicle::storage::git; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum PushAction { + #[error("invalid reference {refname}, expected qualified reference starting with `refs/`")] + InvalidRef { refname: git::RefString }, + #[error("found refs/heads/patches/{suffix} where {suffix} was an invalid Patch ID")] + InvalidPatchId { + suffix: String, + #[source] + err: git::raw::Error, + }, +}