cli: add `rad patch show`

Show patch information with `rad patch show`.

Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
Slack Coder 2023-01-16 12:22:19 -05:00 committed by Alexis Sellier
parent f5cb86dabd
commit 2295bb4ea4
No known key found for this signature in database
5 changed files with 104 additions and 29 deletions

View File

@ -62,4 +62,16 @@ define power requirements b9bb418c6f5 R0 9dad201 (flux-capacitor-power) ahead 1,
Nothing to show.
$ rad patch show b9bb418c6f504ee91e54c555bdc8fc37b4d9b28b
patch b9bb418c6f504ee91e54c555bdc8fc37b4d9b28b
╭─ define power requirements ───────
No description provided.
╰───────────────────────────────────
9dad201 Define power requirements
```

View File

@ -4,6 +4,8 @@ mod common;
mod create;
#[path = "patch/list.rs"]
mod list;
#[path = "patch/show.rs"]
mod show;
use std::ffi::OsString;
use std::str::FromStr;
@ -50,9 +52,19 @@ pub enum OptPatch {
Patch(PatchId),
}
impl From<OptPatch> for Option<PatchId> {
fn from(opt: OptPatch) -> Self {
match opt {
OptPatch::Patch(patch_id) => Some(patch_id),
_ => None,
}
}
}
#[derive(Debug, Default, PartialEq, Eq)]
pub enum OperationName {
Open,
Show,
Update,
#[default]
List,
@ -63,6 +75,9 @@ pub enum Operation {
Open {
message: Comment,
},
Show {
patch_id: PatchId,
},
Update {
patch_id: OptPatch,
message: Comment,
@ -79,6 +94,14 @@ pub struct Options {
pub verbose: bool,
}
fn parse_patch_id(val: OsString) -> Result<OptPatch, anyhow::Error> {
let val = val
.to_str()
.ok_or_else(|| anyhow!("patch id specified is not UTF-8"))?;
let patch_id = PatchId::from_str(val).map_err(|_| anyhow!("invalid patch id '{}'", val))?;
Ok(OptPatch::Patch(patch_id))
}
impl Args for Options {
fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
use lexopt::prelude::*;
@ -88,7 +111,7 @@ impl Args for Options {
let mut op: Option<OperationName> = None;
let mut verbose = false;
let mut sync = true;
let mut id = OptPatch::default();
let mut patch_id = OptPatch::default();
let mut message = Comment::default();
let mut push = true;
@ -137,19 +160,16 @@ impl Args for Options {
Value(val) if op.is_none() => match val.to_string_lossy().as_ref() {
"l" | "list" => op = Some(OperationName::List),
"o" | "open" => op = Some(OperationName::Open),
"s" | "show" => op = Some(OperationName::Show),
"u" | "update" => op = Some(OperationName::Update),
unknown => anyhow::bail!("unknown operation '{}'", unknown),
},
Value(val) if op == Some(OperationName::Update) && id == OptPatch::Any => {
let val = val
.to_str()
.ok_or_else(|| anyhow!("patch id specified is not UTF-8"))?;
id = OptPatch::Patch(
PatchId::from_str(val)
.map_err(|_| anyhow!("invalid patch id '{}'", val))?,
);
Value(val) if op == Some(OperationName::Show) && patch_id == OptPatch::Any => {
patch_id = parse_patch_id(val)?;
}
Value(val) if op == Some(OperationName::Update) && patch_id == OptPatch::Any => {
patch_id = parse_patch_id(val)?;
}
_ => return Err(anyhow::anyhow!(arg.unexpected())),
}
@ -158,10 +178,11 @@ impl Args for Options {
let op = match op.unwrap_or_default() {
OperationName::Open => Operation::Open { message },
OperationName::List => Operation::List,
OperationName::Update => Operation::Update {
patch_id: id,
message,
OperationName::Show => Operation::Show {
patch_id: Option::from(patch_id)
.ok_or_else(|| anyhow!("a patch id must be provided"))?,
},
OperationName::Update => Operation::Update { patch_id, message },
};
Ok((
@ -198,6 +219,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Operation::List => {
list::run(&storage, &profile, Some(workdir), options)?;
}
Operation::Show { ref patch_id } => {
show::run(&storage, &profile, &workdir, patch_id)?;
}
Operation::Update {
ref patch_id,
ref message,

View File

@ -238,23 +238,8 @@ pub fn run(
anyhow::bail!("a title must be given");
}
let title_pretty = &term::format::dim(format!("╭─ {} ───────", title));
term::blank();
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(term::text_width(title_pretty) - 1)
)));
term::patch::print_title_desc(title, &description);
term::blank();
if !confirm("Create patch?", &options) {

View File

@ -0,0 +1,35 @@
use super::common::*;
use super::*;
use crate::terminal as term;
use radicle::cob::patch;
use radicle::git;
use radicle::prelude::*;
use radicle::storage::git::Repository;
pub fn run(
storage: &Repository,
profile: &Profile,
workdir: &git::raw::Repository,
patch_id: &PatchId,
) -> anyhow::Result<()> {
let patches = patch::Patches::open(profile.public_key, storage)?;
let Some(patch) = patches.get(patch_id)? else {
anyhow::bail!("Patch `{}` not found", patch_id);
};
term::blank();
term::print(format!("patch {}", patch_id));
term::blank();
term::patch::print_title_desc(patch.title(), patch.description().unwrap_or(""));
term::blank();
let target_head = patch_merge_target_oid(patch.target(), storage)?;
let base_oid = workdir.merge_base(target_head, **patch.head())?;
let commits = patch_commits(workdir, &base_oid, patch.head())?;
term::patch::list_commits(&commits)?;
term::blank();
Ok(())
}

View File

@ -84,3 +84,22 @@ 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(term::text_width(title_pretty) - 1)
)));
}