cli: Add verbose printing of authors

To allow users to see the full DID of authors of issues, introduce a
boolean to the `Author` struct and wire it through.

While doing that, also remove `--debug` options from `rad issue` and
`rad patch` as they have been obsolete since the introduction of `rad
cob [log|show]` for quite some time.

See:
 - https://radicle.zulipchat.com/#narrow/channel/369873-support/topic/help.20with.20seeing.20full.20nid/with/531390047
This commit is contained in:
Lorenz Leutgeb 2025-07-28 17:17:28 +02:00 committed by Fintan Halpenny
parent c8b6a13d64
commit de78cf7874
15 changed files with 85 additions and 93 deletions

View File

@ -33,14 +33,14 @@ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found 1 potential s
✓ Target met: 1 seed(s)
🌱 Fetched from z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
$ rad id list
╭─────────────────────────────────────────────────────────────────────────────────╮
│ ● ID Title Author Status Created │
├─────────────────────────────────────────────────────────────────────────────────┤
│ ● 89b2623 Edit project name bob z6Mkt67v4N1tRk active now │
│ ● 12d7300 Edit project name alice (you) active now │
│ ● 0ca42d3 Add Bob alice (you) accepted now │
│ ● 0656c21 Initial revision alice (you) accepted now │
╰─────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● ID Title Author Status Created │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● 89b2623 Edit project name bob z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk active now │
│ ● 12d7300 Edit project name alice (you) active now │
│ ● 0ca42d3 Add Bob alice (you) accepted now │
│ ● 0656c21 Initial revision alice (you) accepted now │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
```
This isn't a problem as long as we don't try to accept both. So let's accept
@ -49,14 +49,14 @@ Bob's:
``` ~alice
$ rad id accept 89b2623 -q
$ rad id list
╭─────────────────────────────────────────────────────────────────────────────────╮
│ ● ID Title Author Status Created │
├─────────────────────────────────────────────────────────────────────────────────┤
│ ● 89b2623 Edit project name bob z6Mkt67v4N1tRk accepted now │
│ ● 12d7300 Edit project name alice (you) stale now │
│ ● 0ca42d3 Add Bob alice (you) accepted now │
│ ● 0656c21 Initial revision alice (you) accepted now │
╰─────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● ID Title Author Status Created │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● 89b2623 Edit project name bob z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk accepted now │
│ ● 12d7300 Edit project name alice (you) stale now │
│ ● 0ca42d3 Add Bob alice (you) accepted now │
│ ● 0656c21 Initial revision alice (you) accepted now │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
```
Doing so voided the other conflicting revision, and it can no longer be

View File

@ -10,12 +10,12 @@ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found 1 potential s
✓ Target met: 1 seed(s)
🌱 Fetched from z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
$ rad id --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji
╭────────────────────────────────────────────────────────────────────────────────╮
│ ● ID Title Author Status Created │
├────────────────────────────────────────────────────────────────────────────────┤
│ ● 069e7d5 Add Bob alice z6MknSLStBU8Vi accepted now │
│ ● 0656c21 Initial revision alice z6MknSLStBU8Vi accepted now │
╰────────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● ID Title Author Status Created │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● 069e7d5 Add Bob alice z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi accepted now │
│ ● 0656c21 Initial revision alice z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi accepted now │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
$ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --sigrefs
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi [..]
z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk [..]
@ -93,14 +93,14 @@ We can list all revisions:
``` ~alice
$ rad id list
╭────────────────────────────────────────────────────────────────────────────────╮
│ ● ID Title Author Status Created │
├────────────────────────────────────────────────────────────────────────────────┤
│ ● e6bf105 Make private alice (you) active now │
│ ● 3cd3c7f Add Eve bob z6Mkt67v4N1tRk accepted now │
│ ● 069e7d5 Add Bob alice (you) accepted now │
│ ● 0656c21 Initial revision alice (you) accepted now │
╰────────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● ID Title Author Status Created │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● e6bf105 Make private alice (you) active now │
│ ● 3cd3c7f Add Eve bob z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk accepted now │
│ ● 069e7d5 Add Bob alice (you) accepted now │
│ ● 0656c21 Initial revision alice (you) accepted now │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
```
Despite being a delegate, Bob can't edit or redact Alice's revision:

View File

@ -88,7 +88,7 @@ $ rad patch show 6c61ef1 -v
╭─────────────────────────────────────────────────────────────────────╮
│ Title Define LICENSE for project │
│ Patch 6c61ef1716ad8a5c11e04dd7a3fec51e01fba70b │
│ Author alice z6MknSL…StBU8Vi
│ Author alice z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
│ Head 1cc8cd9de8ccc44b4fe3876f2dbd2cd1cf9ddc0e │
│ Base f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │
│ Commits ahead 2, behind 0 │

View File

@ -480,7 +480,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let id = term::format::oid(r.id).into();
let title = term::label(r.title.to_string());
let (alias, author) =
term::format::Author::new(r.author.public_key(), &profile).labels();
term::format::Author::new(r.author.public_key(), &profile, true).labels();
let timestamp = term::format::timestamp(r.timestamp).into();
revisions.push([icon, id, title, alias, author, state, timestamp]);
@ -586,7 +586,7 @@ fn print_meta(revision: &Revision, previous: &Doc, profile: &Profile) -> anyhow:
let mut signatures = term::Table::<4, _>::default();
for id in accepted {
let author = term::format::Author::new(&id, profile);
let author = term::format::Author::new(&id, profile, true);
signatures.push([
term::PREFIX_SUCCESS.into(),
id.to_string().into(),
@ -595,7 +595,7 @@ fn print_meta(revision: &Revision, previous: &Doc, profile: &Profile) -> anyhow:
]);
}
for id in rejected {
let author = term::format::Author::new(&id, profile);
let author = term::format::Author::new(&id, profile, true);
signatures.push([
term::PREFIX_ERROR.into(),
id.to_string().into(),
@ -604,7 +604,7 @@ fn print_meta(revision: &Revision, previous: &Doc, profile: &Profile) -> anyhow:
]);
}
for id in unknown {
let author = term::format::Author::new(id, profile);
let author = term::format::Author::new(id, profile, true);
signatures.push([
term::format::dim("?").into(),
id.to_string().into(),

View File

@ -291,7 +291,7 @@ where
let author = n
.remote
.map(|r| {
let (alias, _) = term::format::Author::new(&r, profile).labels();
let (alias, _) = term::format::Author::new(&r, profile, false).labels();
alias
})
.unwrap_or_default();
@ -542,6 +542,7 @@ fn show(
&issue,
&typed_id.id,
term::issue::Format::default(),
false,
profile,
)?;
}

View File

@ -67,7 +67,7 @@ Label options
Show options
--debug Show the issue as Rust debug output
-v, --verbose Show additional information about the issue
Options
@ -119,7 +119,7 @@ pub enum Operation {
Show {
id: Rev,
format: Format,
debug: bool,
verbose: bool,
},
CommentEdit {
id: Rev,
@ -202,7 +202,7 @@ impl Args for Options {
let mut edit_comment = None;
let mut announce = true;
let mut quiet = false;
let mut debug = false;
let mut verbose = false;
let mut assign_opts = AssignOptions::default();
let mut label_opts = LabelOptions::default();
let mut repo = None;
@ -295,8 +295,8 @@ impl Args for Options {
_ => anyhow::bail!("unknown format '{val}'"),
}
}
Long("debug") if op == Some(OperationName::Show) => {
debug = true;
Long("verbose") | Short('v') if op == Some(OperationName::Show) => {
verbose = true;
}
// Comment options.
@ -430,7 +430,7 @@ impl Args for Options {
OperationName::Show => Operation::Show {
id: id.ok_or_else(|| anyhow!("an issue must be provided"))?,
format,
debug,
verbose,
},
OperationName::State => Operation::State {
id: id.ok_or_else(|| anyhow!("an issue must be provided"))?,
@ -502,7 +502,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let signer = term::signer(&profile)?;
let issue = edit(&mut issues, &repo, id, title, description, &signer)?;
if !options.quiet {
term::issue::show(&issue, issue.id(), Format::Header, &profile)?;
term::issue::show(&issue, issue.id(), Format::Header, false, &profile)?;
}
}
Operation::Open {
@ -514,7 +514,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let signer = term::signer(&profile)?;
let issue = issues.create(title, description, &labels, &assignees, [], &signer)?;
if !options.quiet {
term::issue::show(&issue, issue.id(), Format::Header, &profile)?;
term::issue::show(&issue, issue.id(), Format::Header, false, &profile)?;
}
}
Operation::Comment {
@ -572,7 +572,11 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
term::comment::widget(&comment_id, comment, &profile).print();
}
}
Operation::Show { id, format, debug } => {
Operation::Show {
id,
format,
verbose,
} => {
let id = id.resolve(&repo.backend)?;
let issue = issues
.get(&id)
@ -581,11 +585,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
hint: "reset the cache with `rad issue cache` and try again",
})?
.context("No issue with the given ID exists")?;
if debug {
println!("{issue:#?}");
} else {
term::issue::show(&issue, &id, format, &profile)?;
}
term::issue::show(&issue, &id, format, verbose, &profile)?;
}
Operation::State { id, state } => {
let signer = term::signer(&profile)?;
@ -783,7 +783,7 @@ where
let assigned: String = issue
.assignees()
.map(|did| {
let (alias, _) = Author::new(did.as_key(), profile).labels();
let (alias, _) = Author::new(did.as_key(), profile, false).labels();
alias.content().to_owned()
})
@ -794,7 +794,7 @@ where
labels.sort();
let author = issue.author().id;
let (alias, did) = Author::new(&author, profile).labels();
let (alias, did) = Author::new(&author, profile, false).labels();
table.push([
match issue.state() {
@ -855,7 +855,7 @@ where
)?;
if !options.quiet {
term::issue::show(&issue, issue.id(), Format::Header, profile)?;
term::issue::show(&issue, issue.id(), Format::Header, false, profile)?;
}
Ok(())
}

View File

@ -83,7 +83,6 @@ Show options
-p, --patch Show the actual patch diff
-v, --verbose Show additional information about the patch
--debug Show the patch as Rust debug output
Diff options
@ -231,7 +230,7 @@ pub enum Operation {
Show {
patch_id: Rev,
diff: bool,
debug: bool,
verbose: bool,
},
Diff {
patch_id: Rev,
@ -356,7 +355,6 @@ pub struct Options {
pub op: Operation,
pub repo: Option<RepoId>,
pub announce: bool,
pub verbose: bool,
pub quiet: bool,
pub authored: bool,
pub authors: Vec<Did>,
@ -380,7 +378,6 @@ impl Args for Options {
let mut message = Message::default();
let mut filter = Some(patch::Status::Open);
let mut diff = false;
let mut debug = false;
let mut undo = false;
let mut reaction: Option<Reaction> = None;
let mut reply_to: Option<Rev> = None;
@ -418,8 +415,8 @@ impl Args for Options {
Long("patch") | Short('p') if op == Some(OperationName::Show) => {
diff = true;
}
Long("debug") if op == Some(OperationName::Show) => {
debug = true;
Long("verbose") | Short('v') if op == Some(OperationName::Show) => {
verbose = true;
}
// Ready options.
@ -666,9 +663,6 @@ impl Args for Options {
}
// Common.
Long("verbose") | Short('v') => {
verbose = true;
}
Long("quiet") | Short('q') => {
quiet = true;
}
@ -742,7 +736,7 @@ impl Args for Options {
OperationName::Show => Operation::Show {
patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
diff,
debug,
verbose,
},
OperationName::Diff => Operation::Diff {
patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
@ -848,7 +842,6 @@ impl Args for Options {
Options {
op,
repo,
verbose,
quiet,
announce,
authored,
@ -885,14 +878,13 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Operation::Show {
patch_id,
diff,
debug,
verbose,
} => {
let patch_id = patch_id.resolve(&repository.backend)?;
show::run(
&patch_id,
diff,
debug,
options.verbose,
verbose,
&profile,
&repository,
workdir.as_ref(),

View File

@ -109,7 +109,7 @@ pub fn row(
let (from, to) = revision.range();
let stats = common::diff_stats(repository.raw(), &from, &to)?;
let author = patch.author().id;
let (alias, did) = Author::new(&author, profile).labels();
let (alias, did) = Author::new(&author, profile, false).labels();
let mut delegates = repository
.delegates()?
.into_iter()

View File

@ -26,7 +26,6 @@ fn show_patch_diff(patch: &patch::Patch, stored: &Repository) -> anyhow::Result<
pub fn run(
patch_id: &PatchId,
diff: bool,
debug: bool,
verbose: bool,
profile: &Profile,
stored: &Repository,
@ -41,10 +40,6 @@ pub fn run(
anyhow::bail!("Patch `{patch_id}` not found");
};
if debug {
println!("{patch:#?}");
return Ok(());
}
term::patch::show(&patch, patch_id, verbose, stored, workdir, profile)?;
if diff {

View File

@ -393,7 +393,8 @@ fn sync_status(
),
None => continue,
};
let (alias, nid) = Author::new(&seed.nid, profile).labels();
let (alias, nid) = Author::new(&seed.nid, profile, options.verbose).labels();
table.push([
nid,

View File

@ -11,7 +11,7 @@ pub fn header<T>(
profile: &Profile,
) -> term::hstack::HStack<'static> {
let author = comment.author();
let author = Author::new(&author, profile);
let author = Author::new(&author, profile, false);
let (alias, nid) = author.labels();
term::hstack::HStack::default()

View File

@ -223,16 +223,18 @@ pub struct Author<'a> {
nid: &'a NodeId,
alias: Option<Alias>,
you: bool,
verbose: bool,
}
impl<'a> Author<'a> {
pub fn new(nid: &'a NodeId, profile: &Profile) -> Author<'a> {
pub fn new(nid: &'a NodeId, profile: &Profile, verbose: bool) -> Author<'a> {
let alias = profile.alias(nid);
Self {
nid,
alias,
you: nid == profile.id(),
verbose,
}
}
@ -255,20 +257,20 @@ impl<'a> Author<'a> {
/// * `(<alias>, <did>)` -- the `Author` is another peer and has an alias
/// * `(<blank>, <did>)` -- the `Author` is another peer and has no alias
pub fn labels(self) -> (term::Label, term::Label) {
let node_id = if self.verbose {
term::format::node_id_human(self.nid)
} else {
term::format::node_id_human_compact(self.nid)
};
let alias = match self.alias.as_ref() {
Some(alias) => term::format::primary(alias).into(),
None if self.you => {
term::format::primary(term::format::node_id_human_compact(self.nid))
.dim()
.into()
}
None if self.you => term::format::primary(node_id.clone()).dim().into(),
None => term::Label::blank(),
};
let author = self.you().unwrap_or_else(|| {
term::format::primary(term::format::node_id_human_compact(self.nid))
.dim()
.into()
});
let author = self
.you()
.unwrap_or_else(move || term::format::primary(node_id).dim().into());
(alias, author)
}

View File

@ -42,6 +42,7 @@ pub fn show(
issue: &issue::Issue,
id: &cob::ObjectId,
format: Format,
verbose: bool,
profile: &Profile,
) -> anyhow::Result<()> {
let labels: Vec<String> = issue.labels().cloned().map(|t| t.into()).collect();
@ -51,7 +52,7 @@ pub fn show(
.collect();
let author = issue.author();
let did = author.id();
let author = Author::new(did, profile);
let author = Author::new(did, profile, verbose);
let mut attrs = Table::<2, term::Line>::new(TableOptions {
spacing: 2,

View File

@ -363,7 +363,7 @@ pub fn show(
*patch.target().head(stored)?,
)?;
let author = patch.author();
let author = term::format::Author::new(author.id(), profile);
let author = term::format::Author::new(author.id(), profile, verbose);
let labels = patch.labels().map(|l| l.to_string()).collect::<Vec<_>>();
let mut attrs = term::Table::<2, term::Line>::new(term::TableOptions {

View File

@ -86,7 +86,7 @@ impl<'a> Opened<'a> {
Some((
merge.timestamp,
Update::Merged {
author: Author::new(nid, profile),
author: Author::new(nid, profile, false),
merge: merge.clone(),
},
))
@ -96,7 +96,7 @@ impl<'a> Opened<'a> {
}));
updates.sort_by_key(|(t, _)| *t);
Opened {
author: Author::new(&patch.author().id, profile),
author: Author::new(&patch.author().id, profile, false),
timestamp: patch.timestamp(),
head: revision.head(),
updates: updates.into_iter().map(|(_, up)| up).collect(),
@ -176,7 +176,7 @@ impl<'a> RevisionEntry<'a> {
Some((
merge.timestamp,
Update::Merged {
author: Author::new(nid, profile),
author: Author::new(nid, profile, false),
merge: merge.clone(),
},
))
@ -195,7 +195,7 @@ impl<'a> RevisionEntry<'a> {
}
} else {
RevisionEntry::Revised {
author: Author::new(&revision.author().id, profile),
author: Author::new(&revision.author().id, profile, false),
timestamp: revision.timestamp(),
id,
head: revision.head(),
@ -305,7 +305,7 @@ impl Update<'_> {
term::format::default("by").into(),
])
.space()
.extend(Author::new(&review.author().id.into(), profile).line())
.extend(Author::new(&review.author().id.into(), profile, false).line())
}
Update::Merged { author, merge } => {
let (alias, nid) = author.labels();