cli: Add `rad patch set` command

Sets the current branch's upstream to point to the given patch.
This allows for pushes to update the patch.

When opening a patch, if the current branch already has an upstream,
it isn't updated automatically. This is why this command exists.
This commit is contained in:
cloudhead 2023-09-03 20:51:16 +02:00
parent 579ddfe725
commit 287a920d12
No known key found for this signature in database
5 changed files with 34 additions and 3 deletions

View File

@ -22,6 +22,7 @@ rad-patch - Manage radicle patches.
*rad patch* _redact_ <revision-id> [<option>...] + *rad patch* _redact_ <revision-id> [<option>...] +
*rad patch* _ready_ <patch-id> [--undo] [<option>...] + *rad patch* _ready_ <patch-id> [--undo] [<option>...] +
*rad patch* _edit_ <patch-id> [<option>...] + *rad patch* _edit_ <patch-id> [<option>...] +
*rad patch* _set_ <patch-id> [<option>...] +
== Description == Description
@ -79,6 +80,13 @@ to *open*.
*--undo*:: Change a patch back to *draft* *--undo*:: Change a patch back to *draft*
=== set
Set the current branch upstream to a patch reference. This configures your
branch such that pushing will update the specified patch.
*<patch-id>*:: The patch to set this branch's upstream to
=== update === update
Updates a patch to the current repository *HEAD*. This is a low-level command Updates a patch to the current repository *HEAD*. This is a low-level command
@ -166,6 +174,9 @@ upstream set. In the above example, we used the *--force* option, since the
commit was amended. This is common practice when a patch has been reworked commit was amended. This is common practice when a patch has been reworked
after receiving a review. after receiving a review.
If the branch upstream is not set to the patch reference, ie. *rad/patches/<id>*,
you can do so using `rad patch set <id>`.
As with opening a patch, you will be asked to enter a reason for updating the As with opening a patch, you will be asked to enter a reason for updating the
patch, via your editor. Simply save and exit when you're done; or leave it patch, via your editor. Simply save and exit when you're done; or leave it
blank to skip this step. blank to skip this step.

View File

@ -50,6 +50,7 @@ Usage
rad patch redact <revision-id> [<option>...] rad patch redact <revision-id> [<option>...]
rad patch ready <patch-id> [--undo] [<option>...] rad patch ready <patch-id> [--undo] [<option>...]
rad patch edit <patch-id> [<option>...] rad patch edit <patch-id> [<option>...]
rad patch set <patch-id> [<option>...]
Show options Show options
@ -95,6 +96,7 @@ pub enum OperationName {
List, List,
Edit, Edit,
Redact, Redact,
Set,
} }
pub struct Filter(fn(&patch::State) -> bool); pub struct Filter(fn(&patch::State) -> bool);
@ -152,6 +154,9 @@ pub enum Operation {
Redact { Redact {
revision_id: Rev, revision_id: Rev,
}, },
Set {
patch_id: Rev,
},
} }
#[derive(Debug)] #[derive(Debug)]
@ -259,6 +264,7 @@ impl Args for Options {
"y" | "ready" => op = Some(OperationName::Ready), "y" | "ready" => op = Some(OperationName::Ready),
"e" | "edit" => op = Some(OperationName::Edit), "e" | "edit" => op = Some(OperationName::Edit),
"r" | "redact" => op = Some(OperationName::Redact), "r" | "redact" => op = Some(OperationName::Redact),
"set" => op = Some(OperationName::Set),
unknown => anyhow::bail!("unknown operation '{}'", unknown), unknown => anyhow::bail!("unknown operation '{}'", unknown),
}, },
Value(val) if op == Some(OperationName::Redact) => { Value(val) if op == Some(OperationName::Redact) => {
@ -275,6 +281,7 @@ impl Args for Options {
Some(OperationName::Ready), Some(OperationName::Ready),
Some(OperationName::Checkout), Some(OperationName::Checkout),
Some(OperationName::Edit), Some(OperationName::Edit),
Some(OperationName::Set),
] ]
.contains(&op) => .contains(&op) =>
{ {
@ -316,6 +323,9 @@ impl Args for Options {
OperationName::Redact => Operation::Redact { OperationName::Redact => Operation::Redact {
revision_id: revision_id.ok_or_else(|| anyhow!("a revision must be provided"))?, revision_id: revision_id.ok_or_else(|| anyhow!("a revision must be provided"))?,
}, },
OperationName::Set => Operation::Set {
patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
},
}; };
Ok(( Ok((
@ -381,6 +391,15 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Operation::Redact { revision_id } => { Operation::Redact { revision_id } => {
redact::run(&revision_id, &profile, &repository)?; redact::run(&revision_id, &profile, &repository)?;
} }
Operation::Set { patch_id } => {
let patches = radicle::cob::patch::Patches::open(&repository)?;
let patch_id = patch_id.resolve(&repository.backend)?;
let patch = patches
.get(&patch_id)?
.ok_or_else(|| anyhow!("patch {patch_id} not found"))?;
radicle::rad::setup_patch_upstream(&patch_id, *patch.head(), &workdir, true)?;
}
} }
Ok(()) Ok(())
} }

View File

@ -36,7 +36,7 @@ pub fn run(
)); ));
spinner.finish(); spinner.finish();
if let Some(branch) = rad::setup_patch_upstream(patch_id, *patch.head(), working)? { if let Some(branch) = rad::setup_patch_upstream(patch_id, *patch.head(), working, false)? {
let tracking = branch let tracking = branch
.name()? .name()?
.ok_or_else(|| anyhow!("failed to create tracking branch: invalid name"))?; .ok_or_else(|| anyhow!("failed to create tracking branch: invalid name"))?;

View File

@ -327,7 +327,7 @@ fn patch_open<G: Signer>(
)?; )?;
// Setup current branch so that pushing updates the patch. // Setup current branch so that pushing updates the patch.
rad::setup_patch_upstream(&patch, commit.id().into(), working)?; rad::setup_patch_upstream(&patch, commit.id().into(), working, false)?;
Ok(()) Ok(())
} }

View File

@ -324,6 +324,7 @@ pub fn setup_patch_upstream<'a>(
patch: &ObjectId, patch: &ObjectId,
patch_head: git::Oid, patch_head: git::Oid,
working: &'a git::raw::Repository, working: &'a git::raw::Repository,
force: bool,
) -> Result<Option<git::raw::Branch<'a>>, git::ext::Error> { ) -> Result<Option<git::raw::Branch<'a>>, git::ext::Error> {
let head = working.head()?; let head = working.head()?;
@ -347,7 +348,7 @@ pub fn setup_patch_upstream<'a>(
assert!(remote_branch.is_remote()); assert!(remote_branch.is_remote());
if let Some(name) = name { if let Some(name) = name {
if branch.upstream().is_err() { if force || branch.upstream().is_err() {
git::set_upstream( git::set_upstream(
working, working,
&*REMOTE_NAME, &*REMOTE_NAME,