diff --git a/radicle-cli/examples/rad-patch.md b/radicle-cli/examples/rad-patch.md index 4a3951ba..f92ae7cb 100644 --- a/radicle-cli/examples/rad-patch.md +++ b/radicle-cli/examples/rad-patch.md @@ -25,27 +25,21 @@ $ git commit -v -m "Define power requirements" Once the code is ready, we open (or create) a patch with our changes for the project. ``` -$ rad patch open --message "define power requirements" --no-confirm - -🌱 Creating patch for heartwood - +$ rad patch open --message "Define power requirements" --message "See details." βœ“ Pushing HEAD to storage... βœ“ Analyzing remotes... -z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master (f2de534) <- z6MknSL…StBU8Vi/flux-capacitor-power (3e674d1) +z6MknSL…StBU8Vi/master (f2de534) <- z6MknSL…StBU8Vi/flux-capacitor-power (3e674d1) + 1 commit(s) ahead, 0 commit(s) behind 3e674d1 Define power requirements +βœ“ Patch d8584d098142d774211ac5cdc8d1df4a113875dd created 🌱 -╭─ define power requirements ─────── +To publish your patch to the network, run: + rad push -No description provided. - -╰─────────────────────────────────── - - -βœ“ Patch f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd created 🌱 ``` It will now be listed as one of the project's open patches. @@ -55,23 +49,19 @@ $ rad patch ❲YOU PROPOSED❳ -define power requirements f504e78d71e R0 3e674d1 (flux-capacitor-power) ahead 1, behind 0 +Define power requirements d8584d09814 R0 3e674d1 (flux-capacitor-power) ahead 1, behind 0 └─ * opened by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [..] -└─ * patch id f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd +└─ * patch id d8584d098142d774211ac5cdc8d1df4a113875dd ❲OTHERS PROPOSED❳ Nothing to show. -$ rad patch show f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd +$ rad patch show d8584d098142d774211ac5cdc8d1df4a113875dd -patch f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd +Define power requirements -╭─ define power requirements ─────── - -No description provided. - -╰─────────────────────────────────── +See details. commit 3e674d1a1df90807e934f9ae5da2591dd6848a33 Author: radicle @@ -94,34 +84,34 @@ $ git commit --message "Add README, just for the fun" [flux-capacitor-power 27857ec] Add README, just for the fun 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md -$ rad patch update --message "Add README, just for the fun" --no-confirm f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd +$ rad patch update --message "Add README, just for the fun" d8584d098142d774211ac5cdc8d1df4a113875dd 🌱 Updating patch for heartwood βœ“ Pushing HEAD to storage... βœ“ Analyzing remotes... -f504e78d71e R0 (3e674d1) -> R1 (27857ec) +d8584d09814 R0 (3e674d1) -> R1 (27857ec) 1 commit(s) ahead, 0 commit(s) behind -βœ“ Patch f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd updated 🌱 +βœ“ Patch d8584d098142d774211ac5cdc8d1df4a113875dd updated 🌱 ``` And lets leave a quick comment for our team: ``` -$ rad comment f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd --message 'I cannot wait to get back to the 90s!' +$ rad comment d8584d098142d774211ac5cdc8d1df4a113875dd --message 'I cannot wait to get back to the 90s!' 84ef44764de73695cf30e6b284585d2c50d6d0e5 -$ rad comment f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd --message 'I cannot wait to get back to the 90s!' --reply-to 84ef44764de73695cf30e6b284585d2c50d6d0e5 +$ rad comment d8584d098142d774211ac5cdc8d1df4a113875dd --message 'I cannot wait to get back to the 90s!' --reply-to 84ef44764de73695cf30e6b284585d2c50d6d0e5 2fa3ac18d82ebdafe73484a15fa9823355c4664b ``` Now, let's checkout the patch that we just created: ``` -$ rad patch checkout f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd +$ rad patch checkout d8584d098142d774211ac5cdc8d1df4a113875dd βœ“ Performing patch checkout... -βœ“ Switched to branch patch/f504e78d71e +βœ“ Switched to branch patch/d8584d09814 ``` diff --git a/radicle-cli/src/commands/patch.rs b/radicle-cli/src/commands/patch.rs index c6a5d6f6..2676f3c1 100644 --- a/radicle-cli/src/commands/patch.rs +++ b/radicle-cli/src/commands/patch.rs @@ -42,8 +42,7 @@ Usage Create/Update options - --[no-]confirm Don't ask for confirmation during clone - --[no-]sync Sync patch to seed (default: sync) + --[no-]announce Announce patch to network (default: false) --[no-]push Push patch head to storage (default: true) -m, --message [] Provide a comment message to the patch or revision (default: prompt) --no-message Leave the patch or revision comment message blank @@ -89,7 +88,6 @@ pub enum Operation { #[derive(Debug)] pub struct Options { pub op: Operation, - pub confirm: bool, pub fetch: bool, pub announce: bool, pub push: bool, @@ -101,11 +99,10 @@ impl Args for Options { use lexopt::prelude::*; let mut parser = lexopt::Parser::from_args(args); - let mut confirm = true; let mut op: Option = None; let mut verbose = false; let mut fetch = false; - let mut announce = true; + let mut announce = false; let mut patch_id = None; let mut message = Message::default(); let mut push = true; @@ -113,12 +110,6 @@ impl Args for Options { while let Some(arg) = parser.next()? { match arg { // Options. - Long("confirm") => { - confirm = true; - } - Long("no-confirm") => { - confirm = false; - } Long("message") | Short('m') => { if message != Message::Blank { // We skip this code when `no-message` is specified. @@ -174,6 +165,9 @@ impl Args for Options { Value(val) if op == Some(OperationName::Checkout) && patch_id.is_none() => { patch_id = Some(term::cob::parse_patch_id(val)?); } + Value(val) if op == Some(OperationName::Delete) && patch_id.is_none() => { + patch_id = Some(term::cob::parse_patch_id(val)?); + } _ => return Err(anyhow::anyhow!(arg.unexpected())), } } @@ -196,7 +190,6 @@ impl Args for Options { Ok(( Options { op, - confirm, fetch, push, verbose, diff --git a/radicle-cli/src/commands/patch/common.rs b/radicle-cli/src/commands/patch/common.rs index 2d805e79..b684997b 100644 --- a/radicle-cli/src/commands/patch/common.rs +++ b/radicle-cli/src/commands/patch/common.rs @@ -1,4 +1,3 @@ -use std::fmt; use std::path::Path; use anyhow::anyhow; @@ -34,11 +33,6 @@ pub fn branch_oid(branch: &git::raw::Branch) -> anyhow::Result { Ok(oid.into()) } -#[inline] -pub fn confirm(prompt: D, options: &Options) -> bool { - !options.confirm || term::confirm(prompt) -} - /// List of merge targets. #[derive(Debug, Default)] pub struct MergeTargets { diff --git a/radicle-cli/src/commands/patch/create.rs b/radicle-cli/src/commands/patch/create.rs index ee12e9f7..fc9f0cf8 100644 --- a/radicle-cli/src/commands/patch/create.rs +++ b/radicle-cli/src/commands/patch/create.rs @@ -42,10 +42,6 @@ pub fn handle_patch_message( anyhow::bail!("a title must be given"); } - term::blank(); - term::patch::print_title_desc(title, description); - term::blank(); - Ok((title.to_string(), description.to_owned())) } @@ -65,13 +61,14 @@ fn show_patch_commit_info( term::blank(); term::info!( "{}/{} ({}) <- {}/{} ({})", - term::format::dim(target_peer.id), + term::format::dim(term::format::node(&target_peer.id)), term::format::highlight(project.default_branch().to_string()), term::format::secondary(term::format::oid(*target_oid)), term::format::dim(term::format::node(node_id)), term::format::highlight(branch_name(head_branch)?), term::format::secondary(term::format::oid(head_oid)), ); + term::blank(); // TODO: Test case where the target branch has been re-written passed the merge-base, since the fork was created // This can also happen *after* the patch is created. @@ -81,7 +78,6 @@ fn show_patch_commit_info( // List commits in patch that aren't in the target branch. term::blank(); term::patch::list_commits(&commits)?; - term::blank(); Ok(()) } @@ -100,12 +96,6 @@ pub fn run( storage.id ))?; let head_branch = try_branch(workdir.head()?)?; - - term::headline(format!( - "🌱 Creating patch for {}", - term::format::highlight(project.name()) - )); - push_to_storage(storage, &head_branch, &options)?; let (target_peer, target_oid) = get_merge_target(&project, storage, &head_branch)?; @@ -123,16 +113,14 @@ pub fn run( target_oid, )?; + term::blank(); + // TODO: List matching working copy refs for all targets. let (title, description) = handle_patch_message(message, workdir, &head_branch)?; - - if !confirm("Continue?", &options) { - anyhow::bail!("patch proposal aborted by user"); - } - let head_oid = branch_oid(&head_branch)?; let base_oid = workdir.merge_base(*target_oid, *head_oid)?; + let signer = term::signer(profile)?; let patch = patches.create( title, &description, @@ -140,14 +128,18 @@ pub fn run( base_oid, head_oid, &[], - &term::signer(profile)?, + &signer, )?; - term::blank(); term::success!("Patch {} created 🌱", term::format::highlight(patch.id)); + term::blank(); if options.announce { // TODO + } else { + term::info!("To publish your patch to the network, run:"); + term::indented(term::format::secondary("rad push")); + term::blank(); } Ok(()) diff --git a/radicle-cli/src/commands/patch/show.rs b/radicle-cli/src/commands/patch/show.rs index 539a83bb..54ebe71e 100644 --- a/radicle-cli/src/commands/patch/show.rs +++ b/radicle-cli/src/commands/patch/show.rs @@ -1,3 +1,5 @@ +use std::process; + use super::common::*; use super::*; @@ -16,8 +18,14 @@ fn show_patch_diff( let base_oid = workdir.merge_base(target_head, **patch.head())?; let diff = format!("{}..{}", base_oid, patch.head()); - let output = git::run::<_, _, &str, &str>(workdir.path(), ["log", "--patch", &diff], [])?; - term::blob(output); + process::Command::new("git") + .current_dir(workdir.path()) + .args(["log", "--patch", &diff]) + .stdout(process::Stdio::inherit()) + .stderr(process::Stdio::inherit()) + .spawn()? + .wait()?; + Ok(()) } @@ -32,11 +40,13 @@ pub fn run( }; term::blank(); - term::print(format!("patch {patch_id}")); + term::info!("{}", term::format::bold(patch.title())); term::blank(); - term::patch::print_title_desc(patch.title(), patch.description().unwrap_or("")); - term::blank(); + if let Some(desc) = patch.description() { + term::blob(desc.trim()); + term::blank(); + } show_patch_diff(&patch, storage, workdir)?; term::blank(); diff --git a/radicle-cli/src/commands/patch/update.rs b/radicle-cli/src/commands/patch/update.rs index a6906b06..8d6638ba 100644 --- a/radicle-cli/src/commands/patch/update.rs +++ b/radicle-cli/src/commands/patch/update.rs @@ -115,10 +115,6 @@ pub fn run( anyhow::bail!("Patch `{patch_id}` not found"); }; - if !confirm("Update patch?", options) { - anyhow::bail!("Patch update aborted by user"); - } - // TODO(cloudhead): Handle error. let (_, current_revision) = patch.latest().unwrap(); if *current_revision.oid == *branch_oid(&head_branch)? { @@ -128,10 +124,6 @@ pub fn run( show_update_commit_info(workdir, &patch_id, &patch, current_revision, &head_branch)?; - if !confirm("Continue?", options) { - anyhow::bail!("patch update aborted by user"); - } - let head_oid = branch_oid(&head_branch)?; let base_oid = workdir.merge_base(*target_oid, *head_oid)?; let message = message.get(REVISION_MSG); diff --git a/radicle-cli/src/terminal/patch.rs b/radicle-cli/src/terminal/patch.rs index 39cf0cc5..5af6c9f3 100644 --- a/radicle-cli/src/terminal/patch.rs +++ b/radicle-cli/src/terminal/patch.rs @@ -1,7 +1,6 @@ use radicle::git; use crate::terminal as term; -use crate::terminal::cell::Cell as _; /// The user supplied `Patch` description. #[derive(Clone, Debug, PartialEq, Eq)] @@ -84,22 +83,3 @@ pub fn print_commits_ahead_behind( ); Ok(()) } - -/// Print title and description in a text box. -pub fn print_title_desc(title: &str, description: &str) { - let title_pretty = &term::format::dim(format!("╭─ {title} ───────")); - term::print(title_pretty); - term::blank(); - - if description.is_empty() { - term::print(term::format::italic("No description provided.")); - } else { - term::markdown(description); - } - - term::blank(); - term::print(term::format::dim(format!( - "β•°{}", - "─".repeat(title_pretty.to_string().width() - 1) - ))); -} diff --git a/radicle-tools/src/rad-cli-demo.rs b/radicle-tools/src/rad-cli-demo.rs index 777c39d3..14eee0e5 100644 --- a/radicle-tools/src/rad-cli-demo.rs +++ b/radicle-tools/src/rad-cli-demo.rs @@ -6,6 +6,7 @@ fn main() -> anyhow::Result<()> { let demo = terminal::io::select( "Choose something to try out:", &[ + "confirm", "spinner", "spinner-drop", "spinner-error", @@ -16,6 +17,11 @@ fn main() -> anyhow::Result<()> { )?; match demo { + Some(&"confirm") => { + if terminal::confirm("Would you like to proceed?") { + terminal::success!("You said 'yes'"); + } + } Some(&"editor") => { let output = terminal::editor::Editor::new() .extension("rs")