cli: Improve `patch` command

Cleanup and simplify output of patch command.
This commit is contained in:
Alexis Sellier 2023-03-07 18:19:26 +01:00
parent db38f2df76
commit adbf6f5bf5
No known key found for this signature in database
8 changed files with 55 additions and 98 deletions

View File

@ -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. 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 $ rad patch open --message "Define power requirements" --message "See details."
🌱 Creating patch for heartwood
✓ Pushing HEAD to storage... ✓ Pushing HEAD to storage...
✓ Analyzing remotes... ✓ Analyzing remotes...
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master (f2de534) <- z6MknSLStBU8Vi/flux-capacitor-power (3e674d1) z6MknSL…StBU8Vi/master (f2de534) <- z6MknSLStBU8Vi/flux-capacitor-power (3e674d1)
1 commit(s) ahead, 0 commit(s) behind 1 commit(s) ahead, 0 commit(s) behind
3e674d1 Define power requirements 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. It will now be listed as one of the project's open patches.
@ -55,23 +49,19 @@ $ rad patch
YOU PROPOSED 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) [..] └─ * opened by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [..]
└─ * patch id f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd └─ * patch id d8584d098142d774211ac5cdc8d1df4a113875dd
OTHERS PROPOSED OTHERS PROPOSED
Nothing to show. Nothing to show.
$ rad patch show f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd $ rad patch show d8584d098142d774211ac5cdc8d1df4a113875dd
patch f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd Define power requirements
╭─ define power requirements ─────── See details.
No description provided.
╰───────────────────────────────────
commit 3e674d1a1df90807e934f9ae5da2591dd6848a33 commit 3e674d1a1df90807e934f9ae5da2591dd6848a33
Author: radicle <radicle@localhost> Author: radicle <radicle@localhost>
@ -94,34 +84,34 @@ $ git commit --message "Add README, just for the fun"
[flux-capacitor-power 27857ec] Add README, just for the fun [flux-capacitor-power 27857ec] Add README, just for the fun
1 file changed, 0 insertions(+), 0 deletions(-) 1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md 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 🌱 Updating patch for heartwood
✓ Pushing HEAD to storage... ✓ Pushing HEAD to storage...
✓ Analyzing remotes... ✓ Analyzing remotes...
f504e78d71e R0 (3e674d1) -> R1 (27857ec) d8584d09814 R0 (3e674d1) -> R1 (27857ec)
1 commit(s) ahead, 0 commit(s) behind 1 commit(s) ahead, 0 commit(s) behind
✓ Patch f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd updated 🌱 ✓ Patch d8584d098142d774211ac5cdc8d1df4a113875dd updated 🌱
``` ```
And lets leave a quick comment for our team: 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 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 2fa3ac18d82ebdafe73484a15fa9823355c4664b
``` ```
Now, let's checkout the patch that we just created: Now, let's checkout the patch that we just created:
``` ```
$ rad patch checkout f504e78d71e7c2d70569976ef9f6b37b6a3d0bfd $ rad patch checkout d8584d098142d774211ac5cdc8d1df4a113875dd
✓ Performing patch checkout... ✓ Performing patch checkout...
✓ Switched to branch patch/f504e78d71e ✓ Switched to branch patch/d8584d09814
``` ```

View File

@ -42,8 +42,7 @@ Usage
Create/Update options Create/Update options
--[no-]confirm Don't ask for confirmation during clone --[no-]announce Announce patch to network (default: false)
--[no-]sync Sync patch to seed (default: sync)
--[no-]push Push patch head to storage (default: true) --[no-]push Push patch head to storage (default: true)
-m, --message [<string>] Provide a comment message to the patch or revision (default: prompt) -m, --message [<string>] Provide a comment message to the patch or revision (default: prompt)
--no-message Leave the patch or revision comment message blank --no-message Leave the patch or revision comment message blank
@ -89,7 +88,6 @@ pub enum Operation {
#[derive(Debug)] #[derive(Debug)]
pub struct Options { pub struct Options {
pub op: Operation, pub op: Operation,
pub confirm: bool,
pub fetch: bool, pub fetch: bool,
pub announce: bool, pub announce: bool,
pub push: bool, pub push: bool,
@ -101,11 +99,10 @@ impl Args for Options {
use lexopt::prelude::*; use lexopt::prelude::*;
let mut parser = lexopt::Parser::from_args(args); let mut parser = lexopt::Parser::from_args(args);
let mut confirm = true;
let mut op: Option<OperationName> = None; let mut op: Option<OperationName> = None;
let mut verbose = false; let mut verbose = false;
let mut fetch = false; let mut fetch = false;
let mut announce = true; let mut announce = false;
let mut patch_id = None; let mut patch_id = None;
let mut message = Message::default(); let mut message = Message::default();
let mut push = true; let mut push = true;
@ -113,12 +110,6 @@ impl Args for Options {
while let Some(arg) = parser.next()? { while let Some(arg) = parser.next()? {
match arg { match arg {
// Options. // Options.
Long("confirm") => {
confirm = true;
}
Long("no-confirm") => {
confirm = false;
}
Long("message") | Short('m') => { Long("message") | Short('m') => {
if message != Message::Blank { if message != Message::Blank {
// We skip this code when `no-message` is specified. // 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() => { Value(val) if op == Some(OperationName::Checkout) && patch_id.is_none() => {
patch_id = Some(term::cob::parse_patch_id(val)?); 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())), _ => return Err(anyhow::anyhow!(arg.unexpected())),
} }
} }
@ -196,7 +190,6 @@ impl Args for Options {
Ok(( Ok((
Options { Options {
op, op,
confirm,
fetch, fetch,
push, push,
verbose, verbose,

View File

@ -1,4 +1,3 @@
use std::fmt;
use std::path::Path; use std::path::Path;
use anyhow::anyhow; use anyhow::anyhow;
@ -34,11 +33,6 @@ pub fn branch_oid(branch: &git::raw::Branch) -> anyhow::Result<git::Oid> {
Ok(oid.into()) Ok(oid.into())
} }
#[inline]
pub fn confirm<D: fmt::Display>(prompt: D, options: &Options) -> bool {
!options.confirm || term::confirm(prompt)
}
/// List of merge targets. /// List of merge targets.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct MergeTargets { pub struct MergeTargets {

View File

@ -42,10 +42,6 @@ pub fn handle_patch_message(
anyhow::bail!("a title must be given"); 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())) Ok((title.to_string(), description.to_owned()))
} }
@ -65,13 +61,14 @@ fn show_patch_commit_info(
term::blank(); term::blank();
term::info!( 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::highlight(project.default_branch().to_string()),
term::format::secondary(term::format::oid(*target_oid)), term::format::secondary(term::format::oid(*target_oid)),
term::format::dim(term::format::node(node_id)), term::format::dim(term::format::node(node_id)),
term::format::highlight(branch_name(head_branch)?), term::format::highlight(branch_name(head_branch)?),
term::format::secondary(term::format::oid(head_oid)), 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 // 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. // 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. // List commits in patch that aren't in the target branch.
term::blank(); term::blank();
term::patch::list_commits(&commits)?; term::patch::list_commits(&commits)?;
term::blank();
Ok(()) Ok(())
} }
@ -100,12 +96,6 @@ pub fn run(
storage.id storage.id
))?; ))?;
let head_branch = try_branch(workdir.head()?)?; 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)?; push_to_storage(storage, &head_branch, &options)?;
let (target_peer, target_oid) = get_merge_target(&project, storage, &head_branch)?; let (target_peer, target_oid) = get_merge_target(&project, storage, &head_branch)?;
@ -123,16 +113,14 @@ pub fn run(
target_oid, target_oid,
)?; )?;
term::blank();
// TODO: List matching working copy refs for all targets. // TODO: List matching working copy refs for all targets.
let (title, description) = handle_patch_message(message, workdir, &head_branch)?; 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 head_oid = branch_oid(&head_branch)?;
let base_oid = workdir.merge_base(*target_oid, *head_oid)?; let base_oid = workdir.merge_base(*target_oid, *head_oid)?;
let signer = term::signer(profile)?;
let patch = patches.create( let patch = patches.create(
title, title,
&description, &description,
@ -140,14 +128,18 @@ pub fn run(
base_oid, base_oid,
head_oid, head_oid,
&[], &[],
&term::signer(profile)?, &signer,
)?; )?;
term::blank();
term::success!("Patch {} created 🌱", term::format::highlight(patch.id)); term::success!("Patch {} created 🌱", term::format::highlight(patch.id));
term::blank();
if options.announce { if options.announce {
// TODO // TODO
} else {
term::info!("To publish your patch to the network, run:");
term::indented(term::format::secondary("rad push"));
term::blank();
} }
Ok(()) Ok(())

View File

@ -1,3 +1,5 @@
use std::process;
use super::common::*; use super::common::*;
use super::*; use super::*;
@ -16,8 +18,14 @@ fn show_patch_diff(
let base_oid = workdir.merge_base(target_head, **patch.head())?; let base_oid = workdir.merge_base(target_head, **patch.head())?;
let diff = format!("{}..{}", base_oid, patch.head()); let diff = format!("{}..{}", base_oid, patch.head());
let output = git::run::<_, _, &str, &str>(workdir.path(), ["log", "--patch", &diff], [])?; process::Command::new("git")
term::blob(output); .current_dir(workdir.path())
.args(["log", "--patch", &diff])
.stdout(process::Stdio::inherit())
.stderr(process::Stdio::inherit())
.spawn()?
.wait()?;
Ok(()) Ok(())
} }
@ -32,11 +40,13 @@ pub fn run(
}; };
term::blank(); term::blank();
term::print(format!("patch {patch_id}")); term::info!("{}", term::format::bold(patch.title()));
term::blank(); term::blank();
term::patch::print_title_desc(patch.title(), patch.description().unwrap_or("")); if let Some(desc) = patch.description() {
term::blank(); term::blob(desc.trim());
term::blank();
}
show_patch_diff(&patch, storage, workdir)?; show_patch_diff(&patch, storage, workdir)?;
term::blank(); term::blank();

View File

@ -115,10 +115,6 @@ pub fn run(
anyhow::bail!("Patch `{patch_id}` not found"); anyhow::bail!("Patch `{patch_id}` not found");
}; };
if !confirm("Update patch?", options) {
anyhow::bail!("Patch update aborted by user");
}
// TODO(cloudhead): Handle error. // TODO(cloudhead): Handle error.
let (_, current_revision) = patch.latest().unwrap(); let (_, current_revision) = patch.latest().unwrap();
if *current_revision.oid == *branch_oid(&head_branch)? { 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)?; 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 head_oid = branch_oid(&head_branch)?;
let base_oid = workdir.merge_base(*target_oid, *head_oid)?; let base_oid = workdir.merge_base(*target_oid, *head_oid)?;
let message = message.get(REVISION_MSG); let message = message.get(REVISION_MSG);

View File

@ -1,7 +1,6 @@
use radicle::git; use radicle::git;
use crate::terminal as term; use crate::terminal as term;
use crate::terminal::cell::Cell as _;
/// The user supplied `Patch` description. /// The user supplied `Patch` description.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -84,22 +83,3 @@ pub fn print_commits_ahead_behind(
); );
Ok(()) 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)
)));
}

View File

@ -6,6 +6,7 @@ fn main() -> anyhow::Result<()> {
let demo = terminal::io::select( let demo = terminal::io::select(
"Choose something to try out:", "Choose something to try out:",
&[ &[
"confirm",
"spinner", "spinner",
"spinner-drop", "spinner-drop",
"spinner-error", "spinner-error",
@ -16,6 +17,11 @@ fn main() -> anyhow::Result<()> {
)?; )?;
match demo { match demo {
Some(&"confirm") => {
if terminal::confirm("Would you like to proceed?") {
terminal::success!("You said 'yes'");
}
}
Some(&"editor") => { Some(&"editor") => {
let output = terminal::editor::Editor::new() let output = terminal::editor::Editor::new()
.extension("rs") .extension("rs")