cli: Show timeline in `patch show`

This commit is contained in:
Alexis Sellier 2023-04-03 16:55:54 +02:00
parent ed4c266a51
commit 6b44955cd9
No known key found for this signature in database
6 changed files with 93 additions and 66 deletions

View File

@ -51,14 +51,16 @@ $ rad patch
``` ```
``` ```
$ rad patch show 191a14e520f2eeff7c0e3ee0a5523c5217eecb89 $ rad patch show 191a14e520f2eeff7c0e3ee0a5523c5217eecb89
╭──────────────────────────────────────────────────────────────────╮ ╭─────────────────────────────────────────────────────────────────────────────────────────
│ Title Define power requirements │ │ Title Define power requirements │
│ Patch 191a14e520f2eeff7c0e3ee0a5523c5217eecb89 │ │ Patch 191a14e520f2eeff7c0e3ee0a5523c5217eecb89 │
│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │ │ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │
│ Status open │ │ Status open │
│ │ │ │
│ See details. │ │ See details. │
╰──────────────────────────────────────────────────────────────────╯ ├─────────────────────────────────────────────────────────────────────────────────────────┤
│ ● opened by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) 3 months ago │
╰─────────────────────────────────────────────────────────────────────────────────────────╯
commit 3e674d1a1df90807e934f9ae5da2591dd6848a33 commit 3e674d1a1df90807e934f9ae5da2591dd6848a33
Author: radicle <radicle@localhost> Author: radicle <radicle@localhost>

View File

@ -49,14 +49,16 @@ $ rad patch
│ ● opened by did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (you) 3 months ago │ │ ● opened by did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (you) 3 months ago │
╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╰─────────────────────────────────────────────────────────────────────────────────────────╯
$ rad patch show a07ef7743a32a2e902672ea3526d1db6ee08108a $ rad patch show a07ef7743a32a2e902672ea3526d1db6ee08108a
╭──────────────────────────────────────────────────────────────────╮ ╭─────────────────────────────────────────────────────────────────────────────────────────
│ Title Define power requirements │ │ Title Define power requirements │
│ Patch a07ef7743a32a2e902672ea3526d1db6ee08108a │ │ Patch a07ef7743a32a2e902672ea3526d1db6ee08108a │
│ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │ │ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │
│ Status open │ │ Status open │
│ │ │ │
│ See details. │ │ See details. │
╰──────────────────────────────────────────────────────────────────╯ ├─────────────────────────────────────────────────────────────────────────────────────────┤
│ ● opened by did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (you) 3 months ago │
╰─────────────────────────────────────────────────────────────────────────────────────────╯
commit 3e674d1a1df90807e934f9ae5da2591dd6848a33 commit 3e674d1a1df90807e934f9ae5da2591dd6848a33
Author: radicle <radicle@localhost> Author: radicle <radicle@localhost>

View File

@ -215,7 +215,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
} }
Operation::Show { patch_id } => { Operation::Show { patch_id } => {
let patch_id = patch_id.resolve(&repository.backend)?; let patch_id = patch_id.resolve(&repository.backend)?;
show::run(&repository, &workdir, &patch_id)?; show::run(&profile, &repository, &workdir, &patch_id)?;
} }
Operation::Update { Operation::Update {
ref patch_id, ref patch_id,

View File

@ -96,7 +96,7 @@ pub fn pretty_sync_status(
/// For example '<oid> (branch1[, branch2])'. /// For example '<oid> (branch1[, branch2])'.
pub fn pretty_commit_version( pub fn pretty_commit_version(
revision_oid: &Oid, revision_oid: &Oid,
repo: &Option<git::raw::Repository>, repo: Option<&git::raw::Repository>,
) -> anyhow::Result<term::Line> { ) -> anyhow::Result<term::Line> {
let oid = term::format::secondary(term::format::oid(*revision_oid)); let oid = term::format::secondary(term::format::oid(*revision_oid));
let mut line = term::Line::new(oid); let mut line = term::Line::new(oid);

View File

@ -1,6 +1,6 @@
use anyhow::anyhow; use anyhow::anyhow;
use radicle::cob::patch::{Patch, PatchId, Patches, Verdict}; use radicle::cob::patch::{Patch, PatchId, Patches, Revision, Verdict};
use radicle::git; use radicle::git;
use radicle::prelude::*; use radicle::prelude::*;
use radicle::profile::Profile; use radicle::profile::Profile;
@ -40,47 +40,24 @@ pub fn run(
} }
for (id, patch) in &mut own { for (id, patch) in &mut own {
print(&me, id, patch, &workdir, repository)?; widget(&me, id, patch, workdir.as_ref(), repository)?.print();
} }
for (id, patch) in &mut other { for (id, patch) in &mut other {
print(profile.id(), id, patch, &workdir, repository)?; widget(profile.id(), id, patch, workdir.as_ref(), repository)?.print();
} }
Ok(()) Ok(())
} }
/// Print patch details. pub fn header(
fn print(
whoami: &PublicKey,
patch_id: &PatchId, patch_id: &PatchId,
patch: &Patch, patch: &Patch,
workdir: &Option<git::raw::Repository>, workdir: Option<&git::raw::Repository>,
repository: &Repository, repository: &Repository,
) -> anyhow::Result<()> { revision: &Revision,
) -> anyhow::Result<term::Line> {
let target_head = common::patch_merge_target_oid(patch.target(), repository)?; let target_head = common::patch_merge_target_oid(patch.target(), repository)?;
let header = term::Line::spaced([
let you = patch.author().id().as_key() == whoami;
let mut author_info = term::Line::spaced([
term::format::positive("").into(),
term::format::default("opened by").into(),
term::format::tertiary(patch.author().id()).into(),
]);
if you {
author_info.push(term::Label::space());
author_info.push(term::format::primary("(you)"));
}
author_info.push(term::Label::space());
author_info.push(term::format::dim(term::format::timestamp(
&patch.timestamp(),
)));
let (_, revision) = patch
.latest()
.ok_or_else(|| anyhow!("patch is malformed: no revisions found"))?;
let mut widget = term::VStack::default()
.child(
term::Line::spaced([
term::format::bold(patch.title()).into(), term::format::bold(patch.title()).into(),
term::format::highlight(term::format::cob(patch_id)).into(), term::format::highlight(term::format::cob(patch_id)).into(),
term::format::dim(format!("R{}", patch.version())).into(), term::format::dim(format!("R{}", patch.version())).into(),
@ -92,13 +69,53 @@ fn print(
repository.raw(), repository.raw(),
revision.head().into(), revision.head().into(),
target_head, target_head,
)?), )?);
)
Ok(header)
}
/// Patch widget.
pub fn widget<'a>(
whoami: &PublicKey,
patch_id: &PatchId,
patch: &Patch,
workdir: Option<&git::raw::Repository>,
repository: &Repository,
) -> anyhow::Result<term::VStack<'a>> {
let (_, revision) = patch
.latest()
.ok_or_else(|| anyhow!("patch is malformed: no revisions found"))?;
let header = header(patch_id, patch, workdir, repository, revision)?;
let mut widget = term::VStack::default()
.child(header)
.divider() .divider()
.child(author_info)
.border(Some(term::colors::FAINT)); .border(Some(term::colors::FAINT));
let mut timeline = Vec::new(); for line in timeline(whoami, patch_id, patch, repository)? {
widget.push(line);
}
Ok(widget)
}
pub fn timeline(
whoami: &PublicKey,
patch_id: &PatchId,
patch: &Patch,
repository: &Repository,
) -> anyhow::Result<Vec<term::Line>> {
let you = patch.author().id().as_key() == whoami;
let mut open = term::Line::spaced([
term::format::positive("").into(),
term::format::default("opened by").into(),
term::format::tertiary(patch.author().id()).into(),
]);
if you {
open.push(term::Label::space());
open.push(term::format::primary("(you)"));
}
let mut timeline = vec![(patch.timestamp(), open)];
for (revision_id, revision) in patch.revisions() { for (revision_id, revision) in patch.revisions() {
// Don't show an "update" line for the first revision. // Don't show an "update" line for the first revision.
if **revision_id != **patch_id { if **revision_id != **patch_id {
@ -176,12 +193,12 @@ fn print(
} }
timeline.sort_by_key(|(t, _)| *t); timeline.sort_by_key(|(t, _)| *t);
let mut lines = Vec::new();
for (time, mut line) in timeline.into_iter() { for (time, mut line) in timeline.into_iter() {
line.push(term::Label::space()); line.push(term::Label::space());
line.push(term::format::dim(term::format::timestamp(&time))); line.push(term::format::dim(term::format::timestamp(&time)));
widget.push(line); lines.push(line);
} }
widget.print();
Ok(()) Ok(lines)
} }

View File

@ -35,11 +35,13 @@ fn show_patch_diff(
} }
pub fn run( pub fn run(
storage: &Repository, profile: &Profile,
stored: &Repository,
// TODO: Should be optional.
workdir: &git::raw::Repository, workdir: &git::raw::Repository,
patch_id: &PatchId, patch_id: &PatchId,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let patches = patch::Patches::open(storage)?; let patches = patch::Patches::open(stored)?;
let Some(patch) = patches.get(patch_id)? else { let Some(patch) = patches.get(patch_id)? else {
anyhow::bail!("Patch `{patch_id}` not found"); anyhow::bail!("Patch `{patch_id}` not found");
}; };
@ -66,7 +68,7 @@ pub fn run(
]); ]);
let description = patch.description().trim(); let description = patch.description().trim();
let meta = VStack::default() let mut widget = VStack::default()
.border(Some(term::colors::FAINT)) .border(Some(term::colors::FAINT))
.child(attrs) .child(attrs)
.children(if !description.is_empty() { .children(if !description.is_empty() {
@ -76,12 +78,16 @@ pub fn run(
] ]
} else { } else {
vec![] vec![]
}); })
.divider();
meta.print(); for line in list::timeline(profile.id(), patch_id, &patch, stored)? {
widget.push(line);
}
widget.print();
term::blank(); term::blank();
show_patch_diff(&patch, storage, workdir)?; show_patch_diff(&patch, stored, workdir)?;
term::blank(); term::blank();
Ok(()) Ok(())