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/<short-id>` format.

This change includes returning early for setting the upstream branch,
if the upstream already existed.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2023-11-16 15:32:20 +00:00 committed by cloudhead
parent 30ad7e4d67
commit 81dc849bce
No known key found for this signature in database
4 changed files with 54 additions and 23 deletions

View File

@ -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

View File

@ -87,6 +87,7 @@ Ready options
Checkout options
--name <string> 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<Rev> = 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::<PatchId>(&repository.backend)?;
delete::run(&patch_id, &profile, &repository)?;
}
Operation::Checkout { revision_id, force } => {
Operation::Checkout { revision_id, opts } => {
let revision_id = revision_id.resolve::<radicle::git::Oid>(&repository.backend)?;
checkout::run(
&patch::RevisionId::from(revision_id),
&repository,
&workdir,
force,
opts,
)?;
}
Operation::Comment {

View File

@ -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<RefString>,
pub force: bool,
}
impl Options {
fn branch(&self, id: PatchId) -> anyhow::Result<RefString> {
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)?;
}

View File

@ -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<git::RefString> = branch.name()?.and_then(|b| b.try_into().ok());
let remote_branch = git::refs::workdir::patch_upstream(patch);
let remote_branch = working.reference(