From 81dc849bce4ea10387c8c499fc94398608cf0cf7 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Thu, 16 Nov 2023 15:32:20 +0000 Subject: [PATCH] cli: add name option to rad patch checkout Add the `--name` option to `rad patch checkout`. This allows the user to name the branch they are checking out, rather than use the `patch/` format. This change includes returning early for setting the upstream branch, if the upstream already existed. Signed-off-by: Fintan Halpenny X-Clacks-Overhead: GNU Terry Pratchett --- .../examples/rad-patch-checkout-force.md | 15 ++++---- radicle-cli/src/commands/patch.rs | 18 ++++++--- radicle-cli/src/commands/patch/checkout.rs | 38 ++++++++++++++----- radicle/src/rad.rs | 6 +++ 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/radicle-cli/examples/rad-patch-checkout-force.md b/radicle-cli/examples/rad-patch-checkout-force.md index 2e7a237f..2775e3ba 100644 --- a/radicle-cli/examples/rad-patch-checkout-force.md +++ b/radicle-cli/examples/rad-patch-checkout-force.md @@ -26,9 +26,9 @@ $ cd heartwood $ rad sync -f ✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi.. ✓ Fetched repository from 1 seed(s) -$ rad patch checkout 6ff4f09 -✓ Switched to branch patch/6ff4f09 -✓ Branch patch/6ff4f09 setup to track rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae +$ rad patch checkout 6ff4f09 --name alice-init +✓ Switched to branch alice-init +✓ Branch alice-init setup to track rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae ``` Meanwhile, we may see some more changes that we need to make, so we @@ -62,7 +62,7 @@ From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji ``` ~bob $ git status -On branch patch/6ff4f09 +On branch alice-init Your branch is behind 'rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch) @@ -76,11 +76,10 @@ to use the `--force` (`-f`) flag to ensure that they are looking at the latest changes: ``` ~bob -$ rad patch checkout 6ff4f09 -f -✓ Switched to branch patch/6ff4f09 -✓ Branch patch/6ff4f09 setup to track rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae +$ rad patch checkout 6ff4f09 -f --name alice-init +✓ Switched to branch alice-init $ git status -On branch patch/6ff4f09 +On branch alice-init Your branch is up to date with 'rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae'. nothing to commit, working tree clean diff --git a/radicle-cli/src/commands/patch.rs b/radicle-cli/src/commands/patch.rs index eeaf3543..43037df4 100644 --- a/radicle-cli/src/commands/patch.rs +++ b/radicle-cli/src/commands/patch.rs @@ -87,6 +87,7 @@ Ready options Checkout options + --name Provide a name for the branch to checkout -f, --force Checkout the head of the revision, even if the branch already exists Other options @@ -155,7 +156,7 @@ pub enum Operation { }, Checkout { revision_id: Rev, - force: bool, + opts: checkout::Options, }, Comment { revision_id: Rev, @@ -203,7 +204,7 @@ impl Args for Options { let mut diff = false; let mut undo = false; let mut reply_to: Option = None; - let mut force = false; + let mut checkout_opts = checkout::Options::default(); while let Some(arg) = parser.next()? { match arg { @@ -259,7 +260,12 @@ impl Args for Options { // Checkout options Long("force") | Short('f') if op == Some(OperationName::Checkout) => { - force = true; + checkout_opts.force = true; + } + + Long("name") if op == Some(OperationName::Checkout) => { + let val = parser.value()?; + checkout_opts.name = Some(term::args::refstring("name", val)?); } // List options. @@ -351,7 +357,7 @@ impl Args for Options { }, OperationName::Checkout => Operation::Checkout { revision_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?, - force, + opts: checkout_opts, }, OperationName::Comment => Operation::Comment { revision_id: patch_id @@ -431,13 +437,13 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { let patch_id = patch_id.resolve::(&repository.backend)?; delete::run(&patch_id, &profile, &repository)?; } - Operation::Checkout { revision_id, force } => { + Operation::Checkout { revision_id, opts } => { let revision_id = revision_id.resolve::(&repository.backend)?; checkout::run( &patch::RevisionId::from(revision_id), &repository, &workdir, - force, + opts, )?; } Operation::Comment { diff --git a/radicle-cli/src/commands/patch/checkout.rs b/radicle-cli/src/commands/patch/checkout.rs index 5f026e10..3acd146f 100644 --- a/radicle-cli/src/commands/patch/checkout.rs +++ b/radicle-cli/src/commands/patch/checkout.rs @@ -1,19 +1,41 @@ use anyhow::anyhow; +use git_ref_format::Qualified; use radicle::cob::patch; use radicle::cob::patch::RevisionId; use radicle::git::RefString; +use radicle::patch::PatchId; use radicle::storage::git::Repository; use radicle::storage::ReadRepository; use radicle::{git, rad}; use crate::terminal as term; +#[derive(Debug, Default)] +pub struct Options { + pub name: Option, + pub force: bool, +} + +impl Options { + fn branch(&self, id: PatchId) -> anyhow::Result { + match &self.name { + Some(refname) => Ok(Qualified::from_refstr(refname) + .map_or_else(|| refname.clone(), |q| q.to_ref_string())), + // SAFETY: Patch IDs are valid refstrings. + None => { + Ok(git::refname!("patch") + .join(RefString::try_from(term::format::cob(&id)).unwrap())) + } + } + } +} + pub fn run( revision_id: &RevisionId, stored: &Repository, working: &git::raw::Repository, - force: bool, + opts: Options, ) -> anyhow::Result<()> { let patches = patch::Patches::open(stored)?; @@ -32,13 +54,11 @@ pub fn run( }; let mut spinner = term::spinner("Performing checkout..."); - let patch_branch = - // SAFETY: Patch IDs are valid refstrings. - git::refname!("patch").join(RefString::try_from(term::format::cob(&patch_id)).unwrap()); + let patch_branch = opts.branch(patch_id)?; let commit = match working.find_branch(patch_branch.as_str(), radicle::git::raw::BranchType::Local) { - Ok(branch) if !force => branch.get().peel_to_commit()?, + Ok(branch) if !opts.force => branch.get().peel_to_commit()?, Ok(branch) => { let commit = find_patch_commit(revision, stored, working)?; let mut r = branch.into_reference(); @@ -54,10 +74,10 @@ pub fn run( Err(e) => return Err(e.into()), }; - if force { - let mut opts = radicle::git::raw::build::CheckoutBuilder::new(); - opts.force(); - working.checkout_tree(commit.as_object(), Some(&mut opts))?; + if opts.force { + let mut builder = radicle::git::raw::build::CheckoutBuilder::new(); + builder.force(); + working.checkout_tree(commit.as_object(), Some(&mut builder))?; } else { working.checkout_tree(commit.as_object(), None)?; } diff --git a/radicle/src/rad.rs b/radicle/src/rad.rs index 51ad3b75..ee2db9e6 100644 --- a/radicle/src/rad.rs +++ b/radicle/src/rad.rs @@ -325,6 +325,12 @@ pub fn setup_patch_upstream<'a>( }; let branch = git::raw::Branch::wrap(r); + + // Only set the upstream if it's missing or `force` is `true` + if branch.upstream().is_ok() && !force { + return Ok(None); + } + let name: Option = branch.name()?.and_then(|b| b.try_into().ok()); let remote_branch = git::refs::workdir::patch_upstream(patch); let remote_branch = working.reference(