diff --git a/radicle-cli/examples/rad-patch.md b/radicle-cli/examples/rad-patch.md index 4a9432c6..2a49b5d8 100644 --- a/radicle-cli/examples/rad-patch.md +++ b/radicle-cli/examples/rad-patch.md @@ -29,7 +29,7 @@ $ rad patch open --message "Define power requirements" --message "See details." ✓ Pushing HEAD to storage... ✓ Analyzing remotes... -z6MknSL…StBU8Vi/master (f2de534) <- z6MknSL…StBU8Vi/flux-capacitor-power (3e674d1) +master (f2de534) <- z6MknSL…StBU8Vi/flux-capacitor-power (3e674d1) 1 commit(s) ahead, 0 commit(s) behind diff --git a/radicle-cli/src/commands/patch/common.rs b/radicle-cli/src/commands/patch/common.rs index b684997b..1c426b95 100644 --- a/radicle-cli/src/commands/patch/common.rs +++ b/radicle-cli/src/commands/patch/common.rs @@ -6,9 +6,7 @@ use radicle::cob::patch::{Clock, MergeTarget, Patch, PatchId, Patches}; use radicle::git; use radicle::git::raw::Oid; use radicle::prelude::*; -use radicle::storage; use radicle::storage::git::Repository; -use radicle::storage::Remote; use crate::terminal as term; use crate::terminal::args::Error; @@ -33,68 +31,32 @@ pub fn branch_oid(branch: &git::raw::Branch) -> anyhow::Result { Ok(oid.into()) } -/// List of merge targets. -#[derive(Debug, Default)] -pub struct MergeTargets { - /// Merge targets that have already merged the patch. - pub merged: Vec, - /// Merge targets that haven't merged the patch. - pub not_merged: Vec<(Remote, git::Oid)>, -} - -/// Find potential merge targets for the given head. -pub fn find_merge_targets( - head: &Oid, - branch: &git::RefStr, - storage: &Repository, -) -> anyhow::Result { - let mut targets = MergeTargets::default(); - - for remote in storage.remotes()? { - let (_, remote) = remote?; - let Some(target_oid) = remote.refs.head(branch) else { - continue; - }; - - if is_merged(storage.raw(), target_oid.into(), *head)? { - targets.merged.push(remote); - } else { - targets.not_merged.push((remote, target_oid)); - } - } - Ok(targets) +#[inline] +fn get_branch(git_ref: git::Qualified) -> git::RefString { + let (_, _, head, tail) = git_ref.non_empty_components(); + std::iter::once(head).chain(tail).collect() } /// Determine the merge target for this patch. This can ben any tracked remote's "default" /// branch, as well as your own (eg. `rad/master`). pub fn get_merge_target( - project: &Project, storage: &Repository, head_branch: &git::raw::Branch, -) -> anyhow::Result<(storage::Remote, git::Oid)> { - let head_oid = head_branch - .get() - .target() - .ok_or(anyhow!("invalid HEAD ref; aborting"))?; - let mut spinner = term::spinner("Analyzing remotes..."); - let targets = find_merge_targets(&head_oid, project.default_branch().as_refstr(), storage)?; +) -> anyhow::Result<(git::RefString, git::Oid)> { + let spinner = term::spinner("Analyzing remotes..."); + let (qualified_ref, target_oid) = storage.canonical_head()?; + let head_oid = branch_oid(head_branch)?; + let merge_base = storage.raw().merge_base(*head_oid, *target_oid)?; + + if head_oid == merge_base.into() { + anyhow::bail!("commits are already included in the target branch; nothing to do"); + } - // eg. `refs/namespaces//refs/heads/master` - let (target_peer, target_oid) = match targets.not_merged.as_slice() { - [] => { - spinner.message("All tracked peers are up to date."); - todo!("handle case without target"); - } - [target] => target, - _ => { - // TODO: Let user select which branch to use as a target. - todo!(); - } - }; // TODO: Tell user how many peers don't have this change. spinner.finish(); - Ok((target_peer.clone(), *target_oid)) + let branch = get_branch(qualified_ref); + Ok((branch, (*target_oid).into())) } /// Return the [`Oid`] of the merge target. @@ -265,12 +227,3 @@ pub fn patch_commits<'a>( } Ok(commits) } - -/// Check whether a commit has been merged into a target branch. -pub fn is_merged(repo: &git::raw::Repository, target: Oid, commit: Oid) -> Result { - if let Ok(base) = repo.merge_base(target, commit) { - Ok(base == commit) - } else { - Ok(false) - } -} diff --git a/radicle-cli/src/commands/patch/create.rs b/radicle-cli/src/commands/patch/create.rs index fc9f0cf8..e4f6af42 100644 --- a/radicle-cli/src/commands/patch/create.rs +++ b/radicle-cli/src/commands/patch/create.rs @@ -1,9 +1,8 @@ -use anyhow::{anyhow, Context}; +use anyhow::anyhow; use radicle::cob::patch; use radicle::git; use radicle::prelude::*; -use radicle::storage; use radicle::storage::git::Repository; use crate::terminal as term; @@ -46,11 +45,10 @@ pub fn handle_patch_message( } fn show_patch_commit_info( - project: &Project, workdir: &git::raw::Repository, node_id: &NodeId, head_branch: &git::raw::Branch, - target_peer: &storage::Remote, + target_ref: &git::RefStr, target_oid: git::Oid, ) -> anyhow::Result<()> { let head_oid = branch_oid(head_branch)?; @@ -60,9 +58,8 @@ fn show_patch_commit_info( term::blank(); term::info!( - "{}/{} ({}) <- {}/{} ({})", - term::format::dim(term::format::node(&target_peer.id)), - term::format::highlight(project.default_branch().to_string()), + "{} ({}) <- {}/{} ({})", + term::format::highlight(target_ref), term::format::secondary(term::format::oid(*target_oid)), term::format::dim(term::format::node(node_id)), term::format::highlight(branch_name(head_branch)?), @@ -91,27 +88,16 @@ pub fn run( options: Options, ) -> anyhow::Result<()> { let mut patches = patch::Patches::open(storage)?; - let project = storage.project_of(&profile.public_key).context(format!( - "couldn't load project {} from local state", - storage.id - ))?; let head_branch = try_branch(workdir.head()?)?; push_to_storage(storage, &head_branch, &options)?; - let (target_peer, target_oid) = get_merge_target(&project, storage, &head_branch)?; + let (target_ref, target_oid) = get_merge_target(storage, &head_branch)?; // TODO: Handle case where `rad/master` isn't up to date with the target. // In that case we should warn the user that their master branch is not up // to date, and error out, unless the user specifies manually the merge // base. - show_patch_commit_info( - &project, - workdir, - profile.id(), - &head_branch, - &target_peer, - target_oid, - )?; + show_patch_commit_info(workdir, profile.id(), &head_branch, &target_ref, target_oid)?; term::blank(); diff --git a/radicle-cli/src/commands/patch/update.rs b/radicle-cli/src/commands/patch/update.rs index 8d6638ba..5bfe9c6e 100644 --- a/radicle-cli/src/commands/patch/update.rs +++ b/radicle-cli/src/commands/patch/update.rs @@ -104,7 +104,7 @@ pub fn run( push_to_storage(storage, &head_branch, options)?; - let (_, target_oid) = get_merge_target(&project, storage, &head_branch)?; + let (_, target_oid) = get_merge_target(storage, &head_branch)?; let mut patches = patch::Patches::open(storage)?; let patch_id = match patch_id {