diff --git a/radicle-cli/examples/rad-patch-edit.md b/radicle-cli/examples/rad-patch-edit.md new file mode 100644 index 00000000..e1b99be7 --- /dev/null +++ b/radicle-cli/examples/rad-patch-edit.md @@ -0,0 +1,116 @@ +If you ever want to change the title and descriptions associated with +a patch and its revisions, we can always use the `rad patch edit` +command. + +First off, we'll have to set up a patch and an updated revision: + +``` +$ git checkout -b changes +$ touch README.md +$ git add README.md +$ git commit --message "Add README, just for the fun" +[changes 03c02af] Add README, just for the fun + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 README.md +``` + +``` (stderr) +$ git push rad -o patch.message="Add README, just for the fun" HEAD:refs/patches +✓ Patch 0631b2d1b5cd4ae44e92732ff3929528354a8405 opened +To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi + * [new reference] HEAD -> refs/patches +``` + +``` +$ touch LICENSE +$ git add LICENSE +$ git commit -v -m "Define the LICENSE" +[changes 8945f61] Define the LICENSE + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 LICENSE +``` + +``` (stderr) +$ git push -f -o patch.message="Add License" +✓ Patch 0631b2d updated to revision bbc91fd4c74bfbbb162ec4b97cd8cefe623814d7 +To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi + 03c02af..8945f61 changes -> patches/0631b2d1b5cd4ae44e92732ff3929528354a8405 +``` + +Let's look at the patch, to see what it looks like before editing it: + +``` +$ rad patch show 0631b2d +╭─────────────────────────────────────────────────────────────────────╮ +│ Title Add README, just for the fun │ +│ Patch 0631b2d1b5cd4ae44e92732ff3929528354a8405 │ +│ Author z6MknSL…StBU8Vi (you) │ +│ Head 8945f6189adf027892c85ac57f7e9341049c2537 │ +│ Branches changes │ +│ Commits ahead 2, behind 0 │ +│ Status open │ +├─────────────────────────────────────────────────────────────────────┤ +│ 8945f61 Define the LICENSE │ +│ 03c02af Add README, just for the fun │ +├─────────────────────────────────────────────────────────────────────┤ +│ ● opened by z6MknSL…StBU8Vi (you) now │ +│ ↑ updated to bbc91fd4c74bfbbb162ec4b97cd8cefe623814d7 (8945f61) now │ +╰─────────────────────────────────────────────────────────────────────╯ +``` + +We can change the title and description of the patch itself by using a +multi-line message (using two `--message` options here): + +``` +$ rad patch edit 0631b2d --message "Add Metadata" --message "Add README & LICENSE" --no-announce +$ rad patch show 0631b2d +╭─────────────────────────────────────────────────────────────────────╮ +│ Title Add Metadata │ +│ Patch 0631b2d1b5cd4ae44e92732ff3929528354a8405 │ +│ Author z6MknSL…StBU8Vi (you) │ +│ Head 8945f6189adf027892c85ac57f7e9341049c2537 │ +│ Branches changes │ +│ Commits ahead 2, behind 0 │ +│ Status open │ +│ │ +│ Add README & LICENSE │ +├─────────────────────────────────────────────────────────────────────┤ +│ 8945f61 Define the LICENSE │ +│ 03c02af Add README, just for the fun │ +├─────────────────────────────────────────────────────────────────────┤ +│ ● opened by z6MknSL…StBU8Vi (you) now │ +│ ↑ updated to bbc91fd4c74bfbbb162ec4b97cd8cefe623814d7 (8945f61) now │ +╰─────────────────────────────────────────────────────────────────────╯ +``` + +Notice that the `Title` is now `Add Metadata`, and the patch now has a +description `Add README & LICENSE`. + +If we want to change a specific revision's description, we can use the +`--revision` option: + +``` +$ rad patch edit 0631b2d --revision bbc91fd --message "Changes: Adds LICENSE file" --no-announce +$ rad patch show 0631b2d +╭─────────────────────────────────────────────────────────────────────╮ +│ Title Add Metadata │ +│ Patch 0631b2d1b5cd4ae44e92732ff3929528354a8405 │ +│ Author z6MknSL…StBU8Vi (you) │ +│ Head 8945f6189adf027892c85ac57f7e9341049c2537 │ +│ Branches changes │ +│ Commits ahead 2, behind 0 │ +│ Status open │ +│ │ +│ Add README & LICENSE │ +├─────────────────────────────────────────────────────────────────────┤ +│ 8945f61 Define the LICENSE │ +│ 03c02af Add README, just for the fun │ +├─────────────────────────────────────────────────────────────────────┤ +│ ● opened by z6MknSL…StBU8Vi (you) now │ +│ ↑ updated to bbc91fd4c74bfbbb162ec4b97cd8cefe623814d7 (8945f61) now │ +╰─────────────────────────────────────────────────────────────────────╯ +``` + +We can see that this didn't affect the patch's description, but +currently there's no way of seeing a revision's description in the +CLI. diff --git a/radicle-cli/src/commands/patch.rs b/radicle-cli/src/commands/patch.rs index 927947a5..ffed2b54 100644 --- a/radicle-cli/src/commands/patch.rs +++ b/radicle-cli/src/commands/patch.rs @@ -256,6 +256,7 @@ pub enum Operation { }, Edit { patch_id: Rev, + revision_id: Option, message: Message, }, Redact { @@ -372,6 +373,14 @@ impl Args for Options { reply_to = Some(rev); } + // Edit options. + Long("revision") | Short('r') if op == Some(OperationName::Edit) => { + let val = parser.value()?; + let rev = term::args::rev(&val)?; + + revision_id = Some(rev); + } + // Review/diff options. Long("revision") | Short('r') if op == Some(OperationName::Review) || op == Some(OperationName::Diff) => @@ -611,6 +620,7 @@ impl Args for Options { }, OperationName::Edit => Operation::Edit { patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?, + revision_id, message, }, OperationName::Redact => Operation::Redact { @@ -763,9 +773,17 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { .map(patch::RevisionId::from); review::run(patch_id, revision_id, opts, &profile, &repository)?; } - Operation::Edit { patch_id, message } => { + Operation::Edit { + patch_id, + revision_id, + message, + } => { let patch_id = patch_id.resolve(&repository.backend)?; - edit::run(&patch_id, message, &profile, &repository)?; + let revision_id = revision_id + .map(|id| id.resolve::(&repository.backend)) + .transpose()? + .map(patch::RevisionId::from); + edit::run(&patch_id, revision_id, message, &profile, &repository)?; } Operation::Redact { revision_id } => { redact::run(&revision_id, &profile, &repository)?; diff --git a/radicle-cli/src/commands/patch/edit.rs b/radicle-cli/src/commands/patch/edit.rs index e033f935..3bd660e7 100644 --- a/radicle-cli/src/commands/patch/edit.rs +++ b/radicle-cli/src/commands/patch/edit.rs @@ -1,6 +1,7 @@ use super::*; use radicle::cob::{patch, resolve_embed}; +use radicle::crypto; use radicle::prelude::*; use radicle::storage::git::Repository; @@ -8,18 +9,35 @@ use crate::terminal as term; pub fn run( patch_id: &PatchId, + revision_id: Option, message: term::patch::Message, profile: &Profile, repository: &Repository, ) -> anyhow::Result<()> { let signer = term::signer(profile)?; let mut patches = patch::Patches::open(repository)?; - let Ok(mut patch) = patches.get_mut(patch_id) else { + let Ok(patch) = patches.get_mut(patch_id) else { anyhow::bail!("Patch `{patch_id}` not found"); }; let (title, description) = term::patch::get_edit_message(message, &patch)?; + match revision_id { + Some(id) => edit_revision(patch, id, title, description, repository, &signer), + None => edit_root(patch, title, description, repository, &signer), + } +} + +fn edit_root( + mut patch: patch::PatchMut<'_, '_, Repository>, + title: String, + description: String, + repository: &Repository, + signer: &G, +) -> anyhow::Result<()> +where + G: crypto::Signer, +{ let title = if title != patch.title() { Some(title) } else { @@ -44,7 +62,7 @@ pub fn run( .filter_map(|embed| resolve_embed(repository, embed.clone())) .collect::>(); - patch.transaction("Edit", &signer, |tx| { + patch.transaction("Edit root", signer, |tx| { if let Some(t) = title { tx.edit(t, target)?; } @@ -56,3 +74,33 @@ pub fn run( Ok(()) } + +fn edit_revision( + mut patch: patch::PatchMut<'_, '_, Repository>, + revision: patch::RevisionId, + mut title: String, + description: String, + repository: &Repository, + signer: &G, +) -> anyhow::Result<()> +where + G: crypto::Signer, +{ + let embeds = patch + .embeds() + .iter() + .filter_map(|embed| resolve_embed(repository, embed.clone())) + .collect::>(); + let description = if description.is_empty() { + title + } else { + title.push('\n'); + title.push_str(&description); + title + }; + patch.transaction("Edit revision", signer, |tx| { + tx.edit_revision(revision, description, embeds)?; + Ok(()) + })?; + Ok(()) +} diff --git a/radicle-cli/tests/commands.rs b/radicle-cli/tests/commands.rs index 8b95f558..f2b530a4 100644 --- a/radicle-cli/tests/commands.rs +++ b/radicle-cli/tests/commands.rs @@ -496,6 +496,20 @@ fn rad_patch_diff() { test("examples/rad-patch-diff.md", working.path(), Some(home), []).unwrap(); } +#[test] +fn rad_patch_edit() { + let mut environment = Environment::new(); + let profile = environment.profile(config::profile("alice")); + let working = tempfile::tempdir().unwrap(); + let home = &profile.home; + + // Setup a test repository. + fixtures::repository(working.path()); + + test("examples/rad-init.md", working.path(), Some(home), []).unwrap(); + test("examples/rad-patch-edit.md", working.path(), Some(home), []).unwrap(); +} + #[test] fn rad_patch_checkout() { let mut environment = Environment::new();