rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwood347f132a18c5b5b83d25c54cf86b7d2c7c7be567
{
"request": "trigger",
"version": 1,
"event_type": "patch",
"repository": {
"id": "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
"name": "heartwood",
"description": "Radicle Heartwood Protocol & Stack",
"private": false,
"default_branch": "master",
"delegates": [
"did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
"did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
]
},
"action": "Created",
"patch": {
"id": "f9f6791c0b080cfe449e2e0cc4d514c1f82f9e59",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"title": "cli/patch: Use clap",
"state": {
"status": "merged",
"conflicts": []
},
"before": "634866889f30736ef07839796ffd3482239121fb",
"after": "347f132a18c5b5b83d25c54cf86b7d2c7c7be567",
"commits": [
"347f132a18c5b5b83d25c54cf86b7d2c7c7be567",
"37d0f88e7e7f25750eda748946d7921249c8c527"
],
"target": "919d5c780c4da0b5b9f18f1549bc59dffd7125af",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "f9f6791c0b080cfe449e2e0cc4d514c1f82f9e59",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Add patch CLI parsing with clap",
"base": "b7a7f55e78f190218370de7538340bfe358d7430",
"oid": "4f8776b772ffdc101d97de5728db3bc603e57f8a",
"timestamp": 1760621123
},
{
"id": "c72c46eea57fbe3529d4e02f56ac82cb42c58b41",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Changes:\n\n- Rebase",
"base": "d9ae29deaa0dc43db4ea0391d6604cde0fc192c5",
"oid": "b62acc378523a758083848dbda35eeadf9a70973",
"timestamp": 1760621268
},
{
"id": "1f367723cc303b9c29a70b5a53a24425a4e2d11a",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Various fixes",
"base": "634866889f30736ef07839796ffd3482239121fb",
"oid": "347f132a18c5b5b83d25c54cf86b7d2c7c7be567",
"timestamp": 1760680739
},
{
"id": "e3531519cc3489acd0cd118e0d1e3fc32a773b1f",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Improve the initial draft\n\nThe non-exhaustive list of changes are:\n- Follow the original copy of the `rad patch` command help\n- Make `MessageArgs` a re-usable struct that converts to `Message`\n- Restructure `ReviewArgs` and remove `ReviewActionArgs` \u2013 the conversion to the `review::Operation` was incorrect, so this was fixed. While I was at it, I also improved the grouping of those parameters, using some `clap` tricks.\n- Ensured the diff of `commands::patch` is easier to read\n- Added `LabelArgs` and `AssignArgs` so that we can mark them as `required`\n- Hide the `[no-]announce` flags, and expose them through `should_announce`\n- Removed some unused fields",
"base": "6cfed884bf37cba1e0d8e97fa8b0e94df4a04b1f",
"oid": "b317f9baa80473710166d7f28ce9e52fe33d06b3",
"timestamp": 1761157116
},
{
"id": "c265e2311bc8ff3de250fab1eadc93f2bf6005a9",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Changes:\n- Resolve TODOs\n- Fixes to visibility",
"base": "6cfed884bf37cba1e0d8e97fa8b0e94df4a04b1f",
"oid": "f4c79ee37fc4fda1ac388b46827076dd99b9bb54",
"timestamp": 1761647135
},
{
"id": "b9e58185f479e18d17ba241b9c1f59b90f046bdf",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Review and rebase",
"base": "9bcdd353c90f42a159b19045d02671198670a05a",
"oid": "695d165dc8b3a45b4e9146a623873fd88df7d1bf",
"timestamp": 1761658417
},
{
"id": "a429e89b02a8d995b9ae298b71ddff8cc7cb3f2e",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Changes:\n- Change formatting of (default: cwd) to [default: cwd]\n- `pub(super)` for `ReviewOptions`",
"base": "9bcdd353c90f42a159b19045d02671198670a05a",
"oid": "de5cbd0f13b9c7e1d317d32e14b41bb961d3ca8c",
"timestamp": 1761669595
},
{
"id": "31e219d82103e1560ef2a62f6e90baf48f83edf7",
"author": {
"id": "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"alias": "erikli"
},
"description": "Rebase",
"base": "e404f1038f461264f9395742ef74f5b710bef54a",
"oid": "d1e19a87b019803cfcac75e2678c15531be34404",
"timestamp": 1761729176
}
]
}
}
{
"response": "triggered",
"run_id": {
"id": "052f6316-93b9-4081-8c8a-40f8be8fc6af"
},
"info_url": "https://cci.rad.levitte.org//052f6316-93b9-4081-8c8a-40f8be8fc6af.html"
}
Started at: 2026-09-07 17:12:05.284291+02:00
Commands:
$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 .
✓ Creating checkout in ./...
✓ Remote cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT added
✓ Remote-tracking branch cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/master created for z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT
✓ Remote fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM added
✓ Remote-tracking branch fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM/master created for z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM
✓ Remote lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz added
✓ Remote-tracking branch lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz/master created for z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz
✓ Repository successfully cloned under /opt/radcis/ci.rad.levitte.org/cci/state/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 189 issues · 37 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ rad patch checkout f9f6791c0b080cfe449e2e0cc4d514c1f82f9e59
✓ Switched to branch patch/f9f6791 at revision 1f36772
✓ Branch patch/f9f6791 setup to track rad/patches/f9f6791c0b080cfe449e2e0cc4d514c1f82f9e59
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout 347f132a18c5b5b83d25c54cf86b7d2c7c7be567
HEAD is now at 347f132a fixup! Continue
Exit code: 0
$ rad patch show f9f6791c0b080cfe449e2e0cc4d514c1f82f9e59 -p
╭──────────────────────────────────────────────────────────────────────────────────╮
│ Title cli/patch: Use clap │
│ Patch f9f6791c0b080cfe449e2e0cc4d514c1f82f9e59 │
│ Author erikli z6MkgFq…FGAnBGz │
│ Head 347f132a18c5b5b83d25c54cf86b7d2c7c7be567 │
│ Base 634866889f30736ef07839796ffd3482239121fb │
│ Target master │
│ Branches patch/f9f6791 │
│ Commits ahead 2, behind 696 │
│ Status merged │
│ │
│ Add patch CLI parsing with clap │
├──────────────────────────────────────────────────────────────────────────────────┤
│ 347f132 fixup! Continue │
│ 37d0f88 Add patch CLI parsing with clap │
├──────────────────────────────────────────────────────────────────────────────────┤
│ ● Revision f9f6791 @ b7a7f55..4f8776b by erikli z6MkgFq…FGAnBGz 10 months ago │
│ ↑ Revision c72c46e @ d9ae29d..b62acc3 by erikli z6MkgFq…FGAnBGz 10 months ago │
│ ↑ Revision 1f36772 @ 6348668..347f132 by erikli z6MkgFq…FGAnBGz 10 months ago │
│ ↑ Revision e353151 @ 6cfed88..b317f9b by fintohaps z6Mkire…SQZ3voM 10 months ago │
│ ↑ Revision c265e23 @ 6cfed88..f4c79ee by fintohaps z6Mkire…SQZ3voM 10 months ago │
│ ↑ Revision b9e5818 @ 9bcdd35..695d165 by lorenz z6MkkPv…WX5sTEz 10 months ago │
│ ↑ Revision a429e89 @ 9bcdd35..de5cbd0 by fintohaps z6Mkire…SQZ3voM 10 months ago │
│ ↑ Revision 31e219d @ e404f10..d1e19a8 by fintohaps z6Mkire…SQZ3voM 10 months ago │
│ └─ ✓ merged by lorenz z6MkkPv…WX5sTEz │
╰──────────────────────────────────────────────────────────────────────────────────╯
commit 347f132a18c5b5b83d25c54cf86b7d2c7c7be567
Author: Erik Kundt <erik@zirkular.io>
Date: Thu Oct 16 12:11:47 2025 +0200
fixup! Continue
diff --git a/crates/radicle-cli/src/commands/help.rs b/crates/radicle-cli/src/commands/help.rs
index 85978690c..d208d4b85 100644
--- a/crates/radicle-cli/src/commands/help.rs
+++ b/crates/radicle-cli/src/commands/help.rs
@@ -79,7 +79,10 @@ const COMMANDS: &[CommandItem] = &[
about: crate::commands::ls::ABOUT,
},
CommandItem::Lexopt(crate::commands::node::HELP),
- CommandItem::Lexopt(crate::commands::patch::HELP),
+ CommandItem::Clap {
+ name: "patch",
+ about: crate::commands::patch::ABOUT,
+ },
CommandItem::Clap {
name: "path",
about: crate::commands::path::ABOUT,
diff --git a/crates/radicle-cli/src/commands/patch.rs b/crates/radicle-cli/src/commands/patch.rs
index 2745b7180..9917b9cf9 100644
--- a/crates/radicle-cli/src/commands/patch.rs
+++ b/crates/radicle-cli/src/commands/patch.rs
@@ -1,4 +1,5 @@
mod archive;
+mod args;
mod assign;
mod cache;
mod checkout;
@@ -16,11 +17,6 @@ mod review;
mod show;
mod update;
-#[path = "patch/args.rs"]
-mod args;
-
-pub use self::args::Args;
-
use std::collections::BTreeSet;
use anyhow::anyhow;
@@ -31,143 +27,15 @@ use radicle::patch::cache::Patches as _;
use radicle::storage::git::transport;
use radicle::{prelude::*, Node};
-use crate::commands::rad_patch::args::{Command, CommentSubcommand};
use crate::git::Rev;
use crate::node;
use crate::terminal as term;
-use crate::terminal::args::{Error, Help};
use crate::terminal::patch::Message;
-pub const HELP: Help = Help {
- name: "patch",
- description: "Manage patches",
- version: env!("RADICLE_VERSION"),
- usage: r#"
-Usage
-
- rad patch [<option>...]
- rad patch list [--all|--merged|--open|--archived|--draft|--authored] [--author <did>]... [<option>...]
- rad patch show <patch-id> [<option>...]
- rad patch diff <patch-id> [<option>...]
- rad patch archive <patch-id> [--undo] [<option>...]
- rad patch update <patch-id> [<option>...]
- rad patch checkout <patch-id> [<option>...]
- rad patch review <patch-id> [--accept | --reject] [-m [<string>]] [-d | --delete] [<option>...]
- rad patch resolve <patch-id> [--review <review-id>] [--comment <comment-id>] [--unresolve] [<option>...]
- rad patch delete <patch-id> [<option>...]
- rad patch redact <revision-id> [<option>...]
- rad patch react <patch-id | revision-id> [--react <emoji>] [<option>...]
- rad patch assign <revision-id> [--add <did>] [--delete <did>] [<option>...]
- rad patch label <revision-id> [--add <label>] [--delete <label>] [<option>...]
- rad patch ready <patch-id> [--undo] [<option>...]
- rad patch edit <patch-id> [<option>...]
- rad patch set <patch-id> [<option>...]
- rad patch comment <patch-id | revision-id> [<option>...]
- rad patch cache [<patch-id>] [--storage] [<option>...]
-
-Show options
-
- -p, --patch Show the actual patch diff
- -v, --verbose Show additional information about the patch
-
-Diff options
-
- -r, --revision <id> The revision to diff (default: latest)
-
-Comment options
-
- -m, --message <string> Provide a comment message via the command-line
- --reply-to <comment> The comment to reply to
- --edit <comment> The comment to edit (use --message to edit with the provided message)
- --react <comment> The comment to react to
- --emoji <char> The emoji to react with when --react is used
- --redact <comment> The comment to redact
-
-Edit options
-
- -m, --message [<string>] Provide a comment message to the patch or revision (default: prompt)
-
-Review options
-
- -r, --revision <id> Review the given revision of the patch
- -p, --patch Review by patch hunks
- --hunk <index> Only review a specific hunk
- --accept Accept a patch or set of hunks
- --reject Reject a patch or set of hunks
- -U, --unified <n> Generate diffs with <n> lines of context instead of the usual three
- -d, --delete Delete a review draft
- -m, --message [<string>] Provide a comment with the review (default: prompt)
-
-Resolve options
-
- --review <id> The review id which the comment is under
- --comment <id> The comment to (un)resolve
- --undo Unresolve the comment
-
-Assign options
-
- -a, --add <did> Add an assignee to the patch (may be specified multiple times).
- Note: --add will take precedence over --delete
-
- -d, --delete <did> Delete an assignee from the patch (may be specified multiple times).
- Note: --add will take precedence over --delete
-
-Archive options
-
- --undo Unarchive a patch
-
-Label options
-
- -a, --add <label> Add a label to the patch (may be specified multiple times).
- Note: --add will take precedence over --delete
-
- -d, --delete <label> Delete a label from the patch (may be specified multiple times).
- Note: --add will take precedence over --delete
-
-Update options
-
- -b, --base <revspec> Provide a Git revision as the base commit
- -m, --message [<string>] Provide a comment message to the patch or revision (default: prompt)
- --no-message Leave the patch or revision comment message blank
-
-List options
-
- --all Show all patches, including merged and archived patches
- --archived Show only archived patches
- --merged Show only merged patches
- --open Show only open patches (default)
- --draft Show only draft patches
- --authored Show only patches that you have authored
- --author <did> Show only patched where the given user is an author
- (may be specified multiple times)
-
-Ready options
+pub use args::Args;
+pub(crate) use args::ABOUT;
- --undo Convert a patch back to a draft
-
-Checkout options
-
- --revision <id> Checkout the given revision of the patch
- --name <string> Provide a name for the branch to checkout
- --remote <string> Provide the git remote to use as the upstream
- -f, --force Checkout the head of the revision, even if the branch already exists
-
-Set options
-
- --remote <string> Provide the git remote to use as the upstream
-
-React options
-
- --emoji <char> The emoji to react to the patch or revision with
-
-Other options
-
- --repo <rid> Operate on the given repository (default: cwd)
- --[no-]announce Announce changes made to the network
- -q, --quiet Quiet output
- --help Print help
-"#,
-};
+use args::{Command, CommentAction};
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
let (workdir, rid) = if let Some(rid) = args.repo {
@@ -180,25 +48,27 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
let profile = ctx.profile()?;
let repository = profile.storage.repository(rid)?;
- let announce = !args.no_announce && args.command.is_some_and(|c| c.is_announce());
+
+ // Fallback to [`Command::List`] if no subcommand is provided.
+ // Construct it using the [`EmptyArgs`] in `args.empty`.
+ let command = args
+ .command
+ .unwrap_or_else(|| Command::List(args.empty.into()));
+ let announce = !args.no_announce && command.should_announce();
transport::local::register(profile.storage.clone());
- match args.command {
- Some(Command::List { filter, options, authors }) => {
- let mut authors: BTreeSet<Did> = authors.iter().cloned().collect();
- if options.authored {
+ match command {
+ Command::List(list_args) => {
+ let mut authors: BTreeSet<Did> = list_args.authors.iter().cloned().collect();
+ if list_args.authored {
authors.insert(profile.did());
}
- list::run(filter.as_ref(), authors, &repository, &profile)?;
+ list::run((&list_args.state).into(), authors, &repository, &profile)?;
}
- Some(Command::Show {
- patch_id,
- patch,
- verbose,
- }) => {
- let patch_id = patch_id.resolve(&repository.backend)?;
+ Command::Show { id, patch, verbose } => {
+ let patch_id = id.resolve(&repository.backend)?;
show::run(
&patch_id,
patch,
@@ -209,25 +79,26 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
)?;
}
- Some(Command::Diff {
- patch_id,
- revision_id,
- }) => {
- let patch_id = patch_id.resolve(&repository.backend)?;
- let revision_id = revision_id
+ Command::Diff { id, revision } => {
+ let patch_id = id.resolve(&repository.backend)?;
+ let revision_id = revision
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
.transpose()?
.map(patch::RevisionId::from);
diff::run(&patch_id, revision_id, &repository, &profile)?;
}
- Some(Command::Update {
- ref patch_id,
- ref base_id,
- message: crate::commands::rad_patch::args::UpdateMessageArg { message, no_message: _ },
- }) => {
- let patch_id = patch_id.resolve(&repository.backend)?;
- let base_id = base_id
+ Command::Update {
+ id,
+ base,
+ message:
+ args::MessageArgs {
+ message,
+ no_message: _,
+ },
+ } => {
+ let patch_id = id.resolve(&repository.backend)?;
+ let base_id = base
.as_ref()
.map(|base| base.resolve(&repository.backend))
.transpose()?;
@@ -245,13 +116,13 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
)?;
}
- Some(Command::Archive { ref patch_id, undo }) => {
- let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
+ Command::Archive { id, undo } => {
+ let patch_id = id.resolve::<PatchId>(&repository.backend)?;
archive::run(&patch_id, undo, &profile, &repository)?;
}
- Some(Command::Ready { ref patch_id, undo }) => {
- let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
+ Command::Ready { id, undo } => {
+ let patch_id = id.resolve::<PatchId>(&repository.backend)?;
if !ready::run(&patch_id, undo, &profile, &repository)? {
if undo {
@@ -262,18 +133,14 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
}
}
- Some(Command::Delete { patch_id }) => {
- let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
+ Command::Delete { id } => {
+ let patch_id = id.resolve::<PatchId>(&repository.backend)?;
delete::run(&patch_id, &profile, &repository)?;
}
- Some(Command::Checkout {
- patch_id,
- revision_id,
- opts,
- }) => {
- let patch_id = patch_id.resolve::<radicle::git::Oid>(&repository.backend)?;
- let revision_id = revision_id
+ Command::Checkout { id, revision, opts } => {
+ let patch_id = id.resolve::<radicle::git::Oid>(&repository.backend)?;
+ let revision_id = revision
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
.transpose()?
.map(patch::RevisionId::from);
@@ -290,70 +157,68 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
)?;
}
- Some(Command::Review {
- patch_id,
- revision_id,
- opts,
- }) => {
- let patch_id = patch_id.resolve(&repository.backend)?;
- let revision_id = revision_id
+ Command::Review {
+ id,
+ revision,
+ options,
+ } => {
+ let patch_id = id.resolve(&repository.backend)?;
+ let revision_id = revision
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
.transpose()?
.map(patch::RevisionId::from);
- review::run(patch_id, revision_id, opts, &profile, &repository)?;
+ review::run(patch_id, revision_id, options.into(), &profile, &repository)?;
}
- Some(Command::Resolve {
- ref patch_id,
- ref review_id,
- ref comment_id,
- undo,
- }) => {
- let patch = patch_id.resolve(&repository.backend)?;
+ Command::Resolve {
+ id,
+ review,
+ comment,
+ unresolve,
+ } => {
+ let patch = id.resolve(&repository.backend)?;
let review = patch::ReviewId::from(
- review_id.resolve::<radicle::cob::EntryId>(&repository.backend)?,
+ review.resolve::<radicle::cob::EntryId>(&repository.backend)?,
);
- let comment = comment_id.resolve(&repository.backend)?;
- if undo {
+ let comment = comment.resolve(&repository.backend)?;
+ if unresolve {
resolve::unresolve(patch, review, comment, &repository, &profile)?;
- term::success!("Unresolved comment {comment_id}");
+ term::success!("Unresolved comment {comment}");
} else {
resolve::resolve(patch, review, comment, &repository, &profile)?;
- term::success!("Resolved comment {comment_id}");
+ term::success!("Resolved comment {comment}");
}
}
- Some(Command::Edit {
- patch_id,
- revision_id,
+ Command::Edit {
+ id,
+ revision,
message,
- }) => {
- let patch_id = patch_id.resolve(&repository.backend)?;
- let revision_id = revision_id
+ } => {
+ let patch_id = id.resolve(&repository.backend)?;
+ let revision_id = revision
.map(|id| id.resolve::<radicle::git::Oid>(&repository.backend))
.transpose()?
.map(patch::RevisionId::from);
+ let message = message.iter().fold(Message::default(), |mut msg, line| {
+ msg.append(&line);
+ msg
+ });
edit::run(&patch_id, revision_id, message, &profile, &repository)?;
}
- Some(Command::Redact { revision_id }) => {
- redact::run(&revision_id, &profile, &repository)?;
+ Command::Redact { id } => {
+ redact::run(&id, &profile, &repository)?;
}
- Some(Command::Assign {
- patch_id,
- opts: self::args::AssignArg { add, delete },
- }) => {
- let patch_id = patch_id.resolve(&repository.backend)?;
+ Command::Assign { id, add, delete } => {
+ let patch_id = id.resolve(&repository.backend)?;
assign::run(&patch_id, add, delete, &profile, &repository)?;
}
- Some(Command::Label {
- patch_id,
- opts: self::args::LabelArg { add, delete },
- }) => {
- let patch_id = patch_id.resolve(&repository.backend)?;
+ Command::Label { id, add, delete } => {
+ let patch_id = id.resolve(&repository.backend)?;
label::run(&patch_id, add, delete, &profile, &repository)?;
}
- Some(Command::Set { patch_id, remote }) => {
+ Command::Set { id, remote } => {
let patches = term::cob::patches(&profile, &repository)?;
- let patch_id = patch_id.resolve(&repository.backend)?;
+ let patch_id = id.resolve(&repository.backend)?;
let patch = patches
.get(&patch_id)?
.ok_or_else(|| anyhow!("patch {patch_id} not found"))?;
@@ -368,13 +233,11 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
true,
)?;
}
- Some(Command::Cache { patch_id, storage }) => {
+ Command::Cache { id, storage } => {
let mode = if storage {
cache::CacheMode::Storage
} else {
- let patch_id = patch_id
- .map(|id| id.resolve(&repository.backend))
- .transpose()?;
+ let patch_id = id.map(|id| id.resolve(&repository.backend)).transpose()?;
patch_id.map_or(
cache::CacheMode::Repository {
repository: &repository,
@@ -387,56 +250,61 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
};
cache::run(mode, &profile)?;
}
- Some(Command::Comment { subcommand: CommentSubcommand::Edit {
- revision_id,
- comment_id,
- message,
- }}) => {
- let comment = comment_id.resolve(&repository.backend)?;
- comment::edit::run(
- revision_id,
+ Command::Comment(c) => match CommentAction::from(c) {
+ CommentAction::Comment {
+ revision,
+ message,
+ reply_to,
+ } => {
+ comment::run(
+ revision,
+ message,
+ reply_to,
+ args.quiet,
+ &repository,
+ &profile,
+ )?;
+ }
+ CommentAction::Edit {
+ revision,
comment,
message,
- args.quiet,
- &repository,
- &profile,
- )?;
- }
- Some(Command::Comment { subcommand: CommentSubcommand::Redact {
- revision_id,
- comment_id,
- }}) => {
- let comment = comment_id.resolve(&repository.backend)?;
- comment::redact::run(revision_id, comment, &repository, &profile)?;
- }
- Some(Command::Comment { subcommand: CommentSubcommand::React {
- revision_id,
- comment_id,
- reaction,
- undo,
- }}) => {
- let comment = comment_id.resolve(&repository.backend)?;
- if undo {
- comment::react::run(revision_id, comment, reaction, false, &repository, &profile)?;
- } else {
- comment::react::run(revision_id, comment, reaction, true, &repository, &profile)?;
+ } => {
+ let comment = comment.resolve(&repository.backend)?;
+ comment::edit::run(
+ revision,
+ comment,
+ message,
+ args.quiet,
+ &repository,
+ &profile,
+ )?;
}
- }
- Some(Command::React {
- revision_id,
- reaction,
- undo,
- }) => {
+ CommentAction::Redact { revision, comment } => {
+ let comment = comment.resolve(&repository.backend)?;
+ comment::redact::run(revision, comment, &repository, &profile)?;
+ }
+ CommentAction::React {
+ revision,
+ comment,
+ emoji,
+ undo,
+ } => {
+ let comment = comment.resolve(&repository.backend)?;
+ if undo {
+ comment::react::run(revision, comment, emoji, false, &repository, &profile)?;
+ } else {
+ comment::react::run(revision, comment, emoji, true, &repository, &profile)?;
+ }
+ }
+ },
+ Command::React { id, react, undo } => {
if undo {
- react::run(&revision_id, reaction, false, &repository, &profile)?;
+ react::run(&id, react, false, &repository, &profile)?;
} else {
- react::run(&revision_id, reaction, true, &repository, &profile)?;
+ react::run(&id, react, true, &repository, &profile)?;
}
}
-
- None => {
- unimplemented!(),
- }
}
if announce {
diff --git a/crates/radicle-cli/src/commands/patch/args.rs b/crates/radicle-cli/src/commands/patch/args.rs
index 8eb49e534..71f4282b7 100644
--- a/crates/radicle-cli/src/commands/patch/args.rs
+++ b/crates/radicle-cli/src/commands/patch/args.rs
@@ -1,349 +1,235 @@
use clap::{Parser, Subcommand};
-use clap_complete::ArgValueCompleter;
-use radicle::prelude::Did;
-
-use crate::git::Rev;
-
-#[derive(Parser, Debug)]
-pub struct Args {
- /// Subcommand for `radicle issue`
- #[command(subcommand)]
- pub(crate) command: Option<Command>,
-
- /// Don't print anything
- #[arg(short, long)]
- #[clap(global = true)]
- pub(crate) quiet: bool,
- /// Don't announce issue to peers
- #[arg(long)]
- #[arg(value_name = "no-announce")]
- #[clap(global = true)]
- pub(crate) no_announce: bool,
-
- /// Show only the issue header, hiding the comments
- #[arg(long)]
- #[clap(global = true)]
- pub(crate) header: bool,
-
- /// Optionally specify the repository to manage issues for
- #[arg(value_name = "RID")]
- #[arg(long, short)]
- #[clap(global = true)]
- pub(crate) repo: Option<radicle::prelude::RepoId>,
-
- /// Verbose output
- #[arg(long, short)]
- #[clap(global = true)]
- pub(crate) verbose: bool,
-}
-
-#[derive(Debug, clap::Args)]
-#[group(required = false, multiple = false)]
-pub struct ListOptions {
- #[arg(long, group = "cmd-list")]
- pub all: bool,
-
- #[arg(long, group = "cmd-list")]
- pub merged: bool,
-
- #[arg(long, group = "cmd-list")]
- pub open: bool,
+use radicle::cob::Label;
+use radicle::git;
+use radicle::git::fmt::RefString;
+use radicle::patch::Status;
+use radicle::patch::Verdict;
+use radicle::prelude::Did;
+use radicle::prelude::RepoId;
- #[arg(long, group = "cmd-list")]
- pub archived: bool,
+use crate::commands::patch::checkout;
+use crate::commands::patch::review;
- #[arg(long, group = "cmd-list")]
- pub draft: bool,
+use crate::git::Rev;
+use crate::terminal::patch::Message;
- #[arg(long, group = "cmd-list")]
- pub authored: bool,
-}
+pub const ABOUT: &str = "Manage patches";
#[derive(Debug, Parser)]
-pub struct ReviewOptions {
- #[clap(long, group = "cmd-review")]
- pub accept: bool,
-
- #[clap(long, group = "cmd-review")]
- pub reject: bool,
-
- #[clap(long, short = 'm', group = "cmd-review")]
- pub message: String,
-
- #[clap(long, short = 'd', group = "cmd-review")]
- pub delete: bool,
-}
-
-impl From<ReviewOptions> for crate::commands::rad_patch::review::Options {
- fn from(value: ReviewOptions) -> Self {
- Self {
- message: value.message.into(),
- op: if value.delete {
- crate::commands::rad_patch::review::Operation::Delete
- } else {
- todo!()
- }
- }
- }
-}
-
-#[derive(Debug, clap::Args)]
-#[group(required = false, multiple = false)]
-pub struct UpdateMessageArg {
- #[clap(long = "message", short = 'm', group = "update-message-arg")]
- pub message: crate::terminal::patch::Message,
-
- #[clap(long = "no-message")]
- pub no_message: bool,
-}
-
-#[derive(Debug, clap::Args)]
-#[group(required = false, multiple = false)]
-pub struct LabelArg {
- #[clap(long, group = "label-arg")]
- pub add: Option<String>,
-
- #[clap(long, group = "label-arg")]
- pub delete: Option<String>,
-}
+#[command(about = ABOUT, disable_version_flag = true)]
+pub struct Args {
+ /// Subcommand for `rad patch`
+ #[command(subcommand)]
+ pub(super) command: Option<Command>,
+ /// Do not print anything
+ #[arg(short, long, global = true)]
+ pub(super) quiet: bool,
-#[derive(Debug, clap::Args)]
-#[group(required = false, multiple = false)]
-pub struct AssignArg {
- #[clap(long, group = "assign-arg")]
- pub add: Option<String>,
+ /// Do not announce to peers
+ #[arg(long, global = true, conflicts_with = "no_announce")]
+ pub(super) announce: bool,
- #[clap(long, group = "assign-arg")]
- pub delete: Option<String>,
-}
+ /// Do not announce to peers
+ #[arg(long, global = true, conflicts_with = "announce")]
+ pub(super) no_announce: bool,
-#[derive(Debug, clap::Args)]
-pub struct CheckoutOptions {
- #[clap(long)]
- pub name: Option<git_ref_format::RefString>,
+ /// Show only the patch header, hiding the comments
+ #[arg(long, global = true)]
+ pub(super) header: bool,
- #[clap(long)]
- pub remote: Option<git_ref_format::RefString>,
+ /// Optionally specify the repository to operate on
+ #[arg(long, global = true, value_name = "RID")]
+ pub(super) repo: Option<RepoId>,
- #[clap(long)]
- pub force: bool,
-}
+ /// Verbose output
+ #[arg(long, short, global = true)]
+ pub(super) verbose: bool,
-impl From<CheckoutOptions> for crate::commands::rad_patch::checkout::Options {
- fn from(value: CheckoutOptions) -> Self {
- Self {
- name: value.name,
- remote: value.remote,
- force: value.force,
- }
- }
+ /// Arguments for the empty subcommand.
+ /// Will fall back to [`Command::List`].
+ #[clap(flatten)]
+ pub(super) empty: EmptyArgs,
}
/// Commands to create, view, and edit Radicle issues
#[derive(Subcommand, Debug)]
-pub enum Command {
- List {
- #[clap(flatten)]
- options: ListOptions,
-
- #[clap(long)]
- authors: Vec<Did>,
-
- #[clap(long)]
- filter: Option<radicle::patch::Status>,
- },
+pub(super) enum Command {
+ #[command(alias = "l")]
+ List(ListArgs),
+ #[command(alias = "s")]
Show {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- // Show the actual patch diff
+ #[arg(long, short)]
patch: bool,
- /// Show additional information about the patch
+ #[arg(long, short)]
verbose: bool,
},
Diff {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- /// The revision of diff (default: latest)
- #[clap(long = "revision", short = 'r')]
- revision_id: Option<Rev>,
+ #[arg(long, short)]
+ revision: Option<Rev>,
},
+ #[command(alias = "a")]
Archive {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
+ #[arg(long)]
undo: bool,
},
+ #[command(alias = "u")]
Update {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- #[clap(long = "base", short = 'n')]
- base_id: Option<Rev>,
+ #[arg(long, short)]
+ base: Option<Rev>,
#[clap(flatten)]
- message: UpdateMessageArg,
+ message: MessageArgs,
},
+ #[command(alias = "c")]
Checkout {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- #[clap(long)]
- revision_id: Option<Rev>,
+ #[arg(long)]
+ revision: Option<Rev>,
#[clap(flatten)]
- opts: CheckoutOptions,
+ opts: CheckoutArgs,
},
Review {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- #[clap(long)]
- revision_id: Option<Rev>,
+ #[arg(long, short)]
+ revision: Option<Rev>,
#[clap(flatten)]
- options: ReviewOptions,
+ options: ReviewArgs,
},
Resolve {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- #[clap(long)]
- review_id: Option<Rev>,
+ #[arg(long, value_name = "REVIEW_ID")]
+ review: Rev,
- #[clap(long)]
- comment_id: Option<Rev>,
+ #[arg(long, value_name = "COMMENT_ID")]
+ comment: Rev,
- #[clap(long)]
- undo: bool,
+ #[arg(long)]
+ unresolve: bool,
},
+ #[command(alias = "d")]
Delete {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
},
+ #[command(alias = "r")]
Redact {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID|REVISION_ID")]
+ id: Rev,
},
React {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID|REVISION_ID")]
+ id: Rev,
- #[clap(long)]
- react: Option<radicle::cob::Reaction>,
+ #[arg(long, value_name = "EMOJI")]
+ react: radicle::cob::Reaction,
+
+ #[arg(long)]
+ undo: bool,
},
Assign {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- #[clap(flatten)]
- opts: AssignArg,
+ #[arg(long, short, value_name = "DID", num_args = 1.., action = clap::ArgAction::Append)]
+ add: Vec<Did>,
+
+ #[clap(long, short, value_name = "DID", num_args = 1.., action = clap::ArgAction::Append)]
+ delete: Vec<Did>,
},
Label {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- #[clap(flatten)]
- opts: LabelArg,
+ #[arg(long, short, value_name = "LABEL", num_args = 1.., action = clap::ArgAction::Append)]
+ add: Vec<Label>,
+
+ #[clap(long, short, value_name = "LABEL", num_args = 1.., action = clap::ArgAction::Append)]
+ delete: Vec<Label>,
},
+ #[command(alias = "y")]
Ready {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
+ #[arg(long)]
undo: bool,
},
+ #[command(alias = "e")]
Edit {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
- },
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- Set {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Rev,
- },
+ #[arg(long, value_name = "REVISION_ID")]
+ revision: Option<Rev>,
- Comment {
- #[command(subcommand)]
- subcommand: CommentSubcommand,
+ #[clap(long, short, value_name = "MESSAGE", num_args = 1.., action = clap::ArgAction::Append)]
+ message: Vec<String>,
},
- Cache {
- #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- patch_id: Option<Rev>,
+ Set {
+ #[arg(value_name = "PATCH_ID")]
+ id: Rev,
- #[arg(long)]
- storage: bool,
+ #[arg(long, value_name = "REF", value_parser = parse_refstr)]
+ remote: Option<RefString>,
},
-}
-#[derive(Subcommand, Debug)]
-pub enum CommentSubcommand {
- Edit {
- #[arg(value_name = "REVISION", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- revision_id: Rev,
- #[arg(value_name = "COMMENT", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- comment_id: Rev,
+ Comment(CommentArgs),
- #[arg(long, short)]
- message: crate::terminal::patch::Message,
- },
- Redact {
- #[arg(value_name = "REVISION", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- revision_id: Rev,
- #[arg(value_name = "COMMENT", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- comment_id: Rev,
- },
- React {
- #[arg(value_name = "REVISION", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- revision_id: Rev,
- #[arg(value_name = "COMMENT", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
- comment_id: Rev,
-
- #[arg(long)]
- reaction: radicle::cob::Reaction,
+ Cache {
+ #[arg(value_name = "PATCH_ID")]
+ id: Option<Rev>,
#[arg(long)]
- undo: bool,
+ storage: bool,
},
}
impl Command {
- pub(super) fn is_announce(&self) -> bool {
+ pub(super) fn should_announce(&self) -> bool {
match self {
Self::Update { .. }
| Self::Archive { .. }
| Self::Ready { .. }
| Self::Delete { .. }
- | Self::Comment {
- subcommand: CommentSubcommand::Edit { .. },
- ..
- }
- | Self::Comment {
- subcommand: CommentSubcommand::Redact { .. },
- ..
- }
- | Self::Comment {
- subcommand: CommentSubcommand::React { .. },
- ..
- }
+ | Self::Comment { .. }
| Self::Review { .. }
| Self::Resolve { .. }
| Self::Assign { .. }
@@ -360,3 +246,315 @@ impl Command {
}
}
}
+
+#[derive(Parser, Debug)]
+pub(super) struct CommentArgs {
+ #[arg(value_name = "REVISION_ID")]
+ revision: Rev,
+
+ #[arg(long, short)]
+ message: Option<Message>,
+
+ #[arg(
+ long,
+ value_name = "COMMENT_ID",
+ conflicts_with = "react",
+ conflicts_with = "redact"
+ )]
+ edit: Option<Rev>,
+
+ #[arg(
+ long,
+ value_name = "COMMENT_ID",
+ conflicts_with = "edit",
+ conflicts_with = "redact",
+ requires = "emoji"
+ )]
+ react: Option<Rev>,
+
+ #[arg(
+ long,
+ value_name = "COMMENT_ID",
+ conflicts_with = "react",
+ conflicts_with = "edit"
+ )]
+ redact: Option<Rev>,
+
+ #[arg(long)]
+ emoji: Option<radicle::cob::Reaction>,
+
+ #[arg(long, value_name = "COMMENT_ID")]
+ reply_to: Option<Rev>,
+
+ #[arg(long)]
+ undo: bool,
+}
+
+#[derive(Debug)]
+pub(super) enum CommentAction {
+ Comment {
+ revision: Rev,
+ message: Message,
+ reply_to: Option<Rev>,
+ },
+ Edit {
+ revision: Rev,
+ comment: Rev,
+ message: Message,
+ },
+ Redact {
+ revision: Rev,
+ comment: Rev,
+ },
+ React {
+ revision: Rev,
+ comment: Rev,
+ emoji: radicle::cob::Reaction,
+ undo: bool,
+ },
+}
+
+impl From<CommentArgs> for CommentAction {
+ fn from(
+ CommentArgs {
+ revision,
+ message,
+ edit,
+ react,
+ redact,
+ reply_to,
+ emoji,
+ undo,
+ }: CommentArgs,
+ ) -> Self {
+ match (edit, react, redact) {
+ (Some(edit), None, None) => CommentAction::Edit {
+ revision,
+ comment: edit,
+ message: message.unwrap_or_default(),
+ },
+ (None, Some(react), None) => CommentAction::React {
+ revision,
+ comment: react,
+ emoji: emoji.unwrap(),
+ undo,
+ },
+ (None, None, Some(redact)) => CommentAction::Redact {
+ revision,
+ comment: redact,
+ },
+ (None, None, None) => Self::Comment {
+ revision,
+ message: message.unwrap_or_default(),
+ reply_to,
+ },
+ _ => unreachable!("the argument cannot be used together'"),
+ }
+ }
+}
+
+#[derive(Parser, Debug, Default)]
+pub(super) struct EmptyArgs {
+ #[arg(long, hide = true, value_name = "DID", num_args = 1.., action = clap::ArgAction::Append)]
+ pub(super) authors: Vec<Did>,
+
+ #[arg(long, hide = true)]
+ pub(super) authored: bool,
+
+ #[clap(flatten)]
+ pub(super) state: EmptyStateArgs,
+}
+
+#[derive(Parser, Debug, Default)]
+#[group(multiple = false)]
+pub(super) struct EmptyStateArgs {
+ #[arg(long, hide = true)]
+ pub(super) all: bool,
+
+ #[arg(long, hide = true)]
+ pub(super) draft: bool,
+
+ #[arg(long, hide = true)]
+ pub(super) open: bool,
+
+ #[arg(long, hide = true)]
+ pub(super) merged: bool,
+
+ #[arg(long, hide = true)]
+ pub(super) archived: bool,
+}
+
+#[derive(Parser, Debug, Default)]
+pub(super) struct ListArgs {
+ #[arg(long, hide = true, value_name = "DID", num_args = 1.., action = clap::ArgAction::Append)]
+ pub(super) authors: Vec<Did>,
+
+ #[arg(long)]
+ pub(super) authored: bool,
+
+ #[clap(flatten)]
+ pub(super) state: ListStateArgs,
+}
+
+impl From<EmptyArgs> for ListArgs {
+ fn from(args: EmptyArgs) -> Self {
+ Self {
+ authors: args.authors,
+ authored: args.authored,
+ state: ListStateArgs::from(args.state),
+ }
+ }
+}
+
+#[derive(Parser, Debug, Default)]
+#[group(multiple = false)]
+pub(crate) struct ListStateArgs {
+ #[arg(long)]
+ pub(crate) all: bool,
+
+ #[arg(long)]
+ pub(crate) draft: bool,
+
+ #[arg(long)]
+ pub(crate) open: bool,
+
+ #[arg(long)]
+ pub(crate) merged: bool,
+
+ #[arg(long)]
+ pub(crate) archived: bool,
+}
+
+impl From<EmptyStateArgs> for ListStateArgs {
+ fn from(args: EmptyStateArgs) -> Self {
+ Self {
+ all: args.all,
+ draft: args.draft,
+ open: args.open,
+ merged: args.merged,
+ archived: args.archived,
+ }
+ }
+}
+
+impl From<&ListStateArgs> for Option<&Status> {
+ fn from(args: &ListStateArgs) -> Self {
+ match (args.all, args.draft, args.open, args.merged, args.archived) {
+ (true, false, false, false, false) => None,
+ (false, true, false, false, false) => Some(&Status::Draft),
+ (false, false, true, false, false) | (false, false, false, false, false) => {
+ Some(&Status::Open)
+ }
+ (false, false, false, true, false) => Some(&Status::Merged),
+ (false, false, false, false, true) => Some(&Status::Archived),
+ _ => unreachable!(),
+ }
+ }
+}
+
+#[derive(Debug, Parser)]
+pub struct ReviewArgs {
+ #[arg(long, short)]
+ pub patch: bool,
+
+ #[arg(long, short = 'U')]
+ pub unified: Option<usize>,
+
+ #[arg(long, value_name = "INDEX")]
+ pub hunk: Option<usize>,
+
+ #[arg(long)]
+ pub by_hunk: bool,
+
+ #[clap(flatten)]
+ message_args: MessageArgs,
+
+ #[clap(flatten)]
+ action_args: ReviewActionsArgs,
+}
+
+#[derive(Debug, Parser)]
+#[group(multiple = false)]
+pub struct ReviewActionsArgs {
+ #[arg(long)]
+ pub accept: bool,
+
+ #[arg(long)]
+ pub reject: bool,
+
+ #[arg(long, short)]
+ pub delete: bool,
+}
+
+impl From<ReviewArgs> for review::Options {
+ fn from(args: ReviewArgs) -> Self {
+ Self {
+ message: args.message_args.message,
+ op: review::Operation::from(args.action_args),
+ }
+ }
+}
+
+impl From<ReviewActionsArgs> for review::Operation {
+ fn from(args: ReviewActionsArgs) -> Self {
+ match (args.accept, args.reject, args.delete) {
+ (false, false, false) => review::Operation::default(),
+ (true, false, false) => review::Operation::Review(review::ReviewOptions {
+ verdict: Some(Verdict::Accept),
+ ..Default::default()
+ }),
+ (false, true, false) => review::Operation::Review(review::ReviewOptions {
+ verdict: Some(Verdict::Reject),
+ ..Default::default()
+ }),
+ (false, false, true) => review::Operation::Delete,
+ _ => unreachable!("`--accept`, `--reject` and `--delete` can not be used together"),
+ }
+ }
+}
+
+#[derive(Debug, clap::Args)]
+#[group(required = false, multiple = false)]
+pub(super) struct MessageArgs {
+ #[arg(long, short)]
+ pub(super) message: Message,
+
+ #[arg(long)]
+ pub(super) no_message: bool,
+}
+
+#[derive(Debug, clap::Args)]
+#[group(required = false, multiple = false)]
+pub(super) struct LabelArgs {
+ #[arg(long, value_name = "LABEL", num_args = 1.., action = clap::ArgAction::Append)]
+ pub(super) add: Option<Label>,
+
+ #[arg(long, value_name = "LABEL", num_args = 1.., action = clap::ArgAction::Append)]
+ pub(super) delete: Option<Label>,
+}
+
+#[derive(Debug, clap::Args)]
+pub(super) struct CheckoutArgs {
+ #[arg(long, value_parser = parse_refstr)]
+ pub(super) name: Option<RefString>,
+
+ #[arg(long, value_parser = parse_refstr)]
+ pub(super) remote: Option<RefString>,
+
+ #[arg(long, short)]
+ pub(super) force: bool,
+}
+
+impl From<CheckoutArgs> for checkout::Options {
+ fn from(value: CheckoutArgs) -> Self {
+ Self {
+ name: value.name,
+ remote: value.remote,
+ force: value.force,
+ }
+ }
+}
+
+fn parse_refstr(refstr: &str) -> Result<RefString, git::fmt::Error> {
+ RefString::try_from(refstr)
+}
diff --git a/crates/radicle-cli/src/commands/patch/assign.rs b/crates/radicle-cli/src/commands/patch/assign.rs
index af8d3bccc..087a1c0ca 100644
--- a/crates/radicle-cli/src/commands/patch/assign.rs
+++ b/crates/radicle-cli/src/commands/patch/assign.rs
@@ -9,8 +9,8 @@ use crate::terminal as term;
pub fn run(
patch_id: &PatchId,
- add: BTreeSet<Did>,
- delete: BTreeSet<Did>,
+ add: Vec<Did>,
+ delete: Vec<Did>,
profile: &Profile,
repository: &Repository,
) -> anyhow::Result<()> {
diff --git a/crates/radicle-cli/src/commands/patch/label.rs b/crates/radicle-cli/src/commands/patch/label.rs
index d2aa7bb1a..ee6b28110 100644
--- a/crates/radicle-cli/src/commands/patch/label.rs
+++ b/crates/radicle-cli/src/commands/patch/label.rs
@@ -6,8 +6,8 @@ use crate::terminal as term;
pub fn run(
patch_id: &PatchId,
- add: BTreeSet<Label>,
- delete: BTreeSet<Label>,
+ add: Vec<Label>,
+ delete: Vec<Label>,
profile: &Profile,
repository: &Repository,
) -> anyhow::Result<()> {
diff --git a/crates/radicle-cli/src/commands/patch/review.rs b/crates/radicle-cli/src/commands/patch/review.rs
index fe4e28eb4..dad74e9f7 100644
--- a/crates/radicle-cli/src/commands/patch/review.rs
+++ b/crates/radicle-cli/src/commands/patch/review.rs
@@ -21,19 +21,16 @@ Markdown supported.
"#;
#[derive(Debug, PartialEq, Eq)]
-pub enum Operation {
- Delete,
- Review {
- by_hunk: bool,
- unified: usize,
- hunk: Option<usize>,
- verdict: Option<Verdict>,
- },
+pub struct ReviewOptions {
+ pub by_hunk: bool,
+ pub unified: usize,
+ pub hunk: Option<usize>,
+ pub verdict: Option<Verdict>,
}
-impl Default for Operation {
+impl Default for ReviewOptions {
fn default() -> Self {
- Self::Review {
+ Self {
by_hunk: false,
unified: 3,
hunk: None,
@@ -42,6 +39,18 @@ impl Default for Operation {
}
}
+#[derive(Debug, PartialEq, Eq)]
+pub enum Operation {
+ Delete,
+ Review(ReviewOptions),
+}
+
+impl Default for Operation {
+ fn default() -> Self {
+ Operation::Review(ReviewOptions::default())
+ }
+}
+
#[derive(Debug, Default)]
pub struct Options {
pub message: Message,
@@ -77,24 +86,19 @@ pub fn run(
let patch_id_pretty = term::format::tertiary(term::format::cob(&patch_id));
match options.op {
- Operation::Review {
- verdict,
- by_hunk,
- unified,
- hunk,
- } if by_hunk => {
+ Operation::Review(review_opts) if review_opts.by_hunk => {
crate::warning::obsolete("rad patch review --patch");
let mut opts = git::raw::DiffOptions::new();
opts.patience(true)
.minimal(true)
- .context_lines(unified as u32);
+ .context_lines(review_opts.unified as u32);
builder::ReviewBuilder::new(patch_id, repository)
- .hunk(hunk)
- .verdict(verdict)
+ .hunk(review_opts.hunk)
+ .verdict(review_opts.verdict)
.run(revision, &mut opts, &signer)?;
}
- Operation::Review { verdict, .. } => {
+ Operation::Review(review_opts) => {
let message = options.message.get(REVIEW_HELP_MSG)?;
let message = message.replace(REVIEW_HELP_MSG.trim(), "");
let message = if message.is_empty() {
@@ -102,9 +106,9 @@ pub fn run(
} else {
Some(message)
};
- patch.review(revision_id, verdict, message, vec![], &signer)?;
+ patch.review(revision_id, review_opts.verdict, message, vec![], &signer)?;
- match verdict {
+ match review_opts.verdict {
Some(Verdict::Accept) => {
term::success!(
"Patch {} {}",
diff --git a/crates/radicle-cli/src/commands/patch/show.rs b/crates/radicle-cli/src/commands/patch/show.rs
index 80d093fda..9b3dc90e6 100644
--- a/crates/radicle-cli/src/commands/patch/show.rs
+++ b/crates/radicle-cli/src/commands/patch/show.rs
@@ -4,7 +4,7 @@ use radicle::cob::patch;
use radicle::git;
use radicle::storage::git::Repository;
-use crate::terminal as term;
+use crate::terminal::{self as term, Error};
use super::*;
diff --git a/crates/radicle-cli/src/main.rs b/crates/radicle-cli/src/main.rs
index b06390271..4a8f3ada9 100644
--- a/crates/radicle-cli/src/main.rs
+++ b/crates/radicle-cli/src/main.rs
@@ -67,6 +67,7 @@ enum Commands {
Init(init::Args),
Issue(issue::Args),
Ls(ls::Args),
+ Patch(patch::Args),
Path(path::Args),
Publish(publish::Args),
Seed(seed::Args),
@@ -283,7 +284,9 @@ pub(crate) fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyho
term::run_command_args::<node::Options, _>(node::HELP, node::run, args.to_vec());
}
"patch" => {
- term::run_command_args::<patch::Options, _>(patch::HELP, patch::run, args.to_vec());
+ if let Some(Commands::Patch(args)) = CliArgs::parse().command {
+ term::run_command_fn(patch::run, args);
+ }
}
"path" => {
if let Some(Commands::Path(args)) = CliArgs::parse().command {
commit 37d0f88e7e7f25750eda748946d7921249c8c527
Author: Matthias Beyer <mail@beyermatthias.de>
Date: Fri Sep 5 16:19:07 2025 +0200
Add patch CLI parsing with clap
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
diff --git a/crates/radicle-cli/src/commands/patch.rs b/crates/radicle-cli/src/commands/patch.rs
index 187abfc93..2745b7180 100644
--- a/crates/radicle-cli/src/commands/patch.rs
+++ b/crates/radicle-cli/src/commands/patch.rs
@@ -16,23 +16,26 @@ mod review;
mod show;
mod update;
+#[path = "patch/args.rs"]
+mod args;
+
+pub use self::args::Args;
+
use std::collections::BTreeSet;
-use std::ffi::OsString;
-use std::str::FromStr as _;
use anyhow::anyhow;
use radicle::cob::patch::PatchId;
-use radicle::cob::{patch, Label, Reaction};
-use radicle::git::fmt::RefString;
+use radicle::cob::{patch, Label};
use radicle::patch::cache::Patches as _;
use radicle::storage::git::transport;
use radicle::{prelude::*, Node};
+use crate::commands::rad_patch::args::{Command, CommentSubcommand};
use crate::git::Rev;
use crate::node;
use crate::terminal as term;
-use crate::terminal::args::{string, Args, Error, Help};
+use crate::terminal::args::{Error, Help};
use crate::terminal::patch::Message;
pub const HELP: Help = Help {
@@ -166,677 +169,8 @@ Other options
"#,
};
-#[derive(Debug, Default, PartialEq, Eq)]
-pub enum OperationName {
- Assign,
- Show,
- Diff,
- Update,
- Archive,
- Delete,
- Checkout,
- Comment,
- React,
- Ready,
- Review,
- Resolve,
- Label,
- #[default]
- List,
- Edit,
- Redact,
- Set,
- Cache,
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub enum CommentOperation {
- Edit,
- React,
- Redact,
-}
-
-#[derive(Debug, Default, PartialEq, Eq)]
-pub struct AssignOptions {
- pub add: BTreeSet<Did>,
- pub delete: BTreeSet<Did>,
-}
-
-#[derive(Debug, Default, PartialEq, Eq)]
-pub struct LabelOptions {
- pub add: BTreeSet<Label>,
- pub delete: BTreeSet<Label>,
-}
-
-#[derive(Debug)]
-pub enum Operation {
- Show {
- patch_id: Rev,
- diff: bool,
- verbose: bool,
- },
- Diff {
- patch_id: Rev,
- revision_id: Option<Rev>,
- },
- Update {
- patch_id: Rev,
- base_id: Option<Rev>,
- message: Message,
- },
- Archive {
- patch_id: Rev,
- undo: bool,
- },
- Ready {
- patch_id: Rev,
- undo: bool,
- },
- Delete {
- patch_id: Rev,
- },
- Checkout {
- patch_id: Rev,
- revision_id: Option<Rev>,
- opts: checkout::Options,
- },
- Comment {
- revision_id: Rev,
- message: Message,
- reply_to: Option<Rev>,
- },
- CommentEdit {
- revision_id: Rev,
- comment_id: Rev,
- message: Message,
- },
- CommentRedact {
- revision_id: Rev,
- comment_id: Rev,
- },
- CommentReact {
- revision_id: Rev,
- comment_id: Rev,
- reaction: Reaction,
- undo: bool,
- },
- React {
- revision_id: Rev,
- reaction: Reaction,
- undo: bool,
- },
- Review {
- patch_id: Rev,
- revision_id: Option<Rev>,
- opts: review::Options,
- },
- Resolve {
- patch_id: Rev,
- review_id: Rev,
- comment_id: Rev,
- undo: bool,
- },
- Assign {
- patch_id: Rev,
- opts: AssignOptions,
- },
- Label {
- patch_id: Rev,
- opts: LabelOptions,
- },
- List {
- filter: Option<patch::Status>,
- },
- Edit {
- patch_id: Rev,
- revision_id: Option<Rev>,
- message: Message,
- },
- Redact {
- revision_id: Rev,
- },
- Set {
- patch_id: Rev,
- remote: Option<RefString>,
- },
- Cache {
- patch_id: Option<Rev>,
- storage: bool,
- },
-}
-
-impl Operation {
- fn is_announce(&self) -> bool {
- match self {
- Operation::Update { .. }
- | Operation::Archive { .. }
- | Operation::Ready { .. }
- | Operation::Delete { .. }
- | Operation::Comment { .. }
- | Operation::CommentEdit { .. }
- | Operation::CommentRedact { .. }
- | Operation::CommentReact { .. }
- | Operation::Review { .. }
- | Operation::Resolve { .. }
- | Operation::Assign { .. }
- | Operation::Label { .. }
- | Operation::Edit { .. }
- | Operation::Redact { .. }
- | Operation::React { .. }
- | Operation::Set { .. } => true,
- Operation::Show { .. }
- | Operation::Diff { .. }
- | Operation::Checkout { .. }
- | Operation::List { .. }
- | Operation::Cache { .. } => false,
- }
- }
-}
-
-#[derive(Debug)]
-pub struct Options {
- pub op: Operation,
- pub repo: Option<RepoId>,
- pub announce: bool,
- pub quiet: bool,
- pub authored: bool,
- pub authors: Vec<Did>,
-}
-
-impl Args for Options {
- fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
- use lexopt::prelude::*;
-
- let mut parser = lexopt::Parser::from_args(args);
- let mut op: Option<OperationName> = None;
- let mut verbose = false;
- let mut quiet = false;
- let mut authored = false;
- let mut authors = vec![];
- let mut announce = true;
- let mut patch_id = None;
- let mut revision_id = None;
- let mut review_id = None;
- let mut comment_id = None;
- let mut message = Message::default();
- let mut filter = Some(patch::Status::Open);
- let mut diff = false;
- let mut undo = false;
- let mut reaction: Option<Reaction> = None;
- let mut reply_to: Option<Rev> = None;
- let mut comment_op: Option<(CommentOperation, Rev)> = None;
- let mut checkout_opts = checkout::Options::default();
- let mut remote: Option<RefString> = None;
- let mut assign_opts = AssignOptions::default();
- let mut label_opts = LabelOptions::default();
- let mut review_op = review::Operation::default();
- let mut base_id = None;
- let mut repo = None;
- let mut cache_storage = false;
-
- while let Some(arg) = parser.next()? {
- match arg {
- // Options.
- Long("message") | Short('m') => {
- if message != Message::Blank {
- // We skip this code when `no-message` is specified.
- let txt: String = term::args::string(&parser.value()?);
- message.append(&txt);
- }
- }
- Long("no-message") => {
- message = Message::Blank;
- }
- Long("announce") => {
- announce = true;
- }
- Long("no-announce") => {
- announce = false;
- }
-
- // Show options.
- Long("patch") | Short('p') if op == Some(OperationName::Show) => {
- diff = true;
- }
- Long("verbose") | Short('v') if op == Some(OperationName::Show) => {
- verbose = true;
- }
-
- // Ready options.
- Long("undo") if op == Some(OperationName::Ready) => {
- undo = true;
- }
-
- // Archive options.
- Long("undo") if op == Some(OperationName::Archive) => {
- undo = true;
- }
-
- // Update options.
- Short('b') | Long("base") if op == Some(OperationName::Update) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- base_id = Some(rev);
- }
-
- // React options.
- Long("emoji") if op == Some(OperationName::React) => {
- if let Some(emoji) = parser.value()?.to_str() {
- reaction =
- Some(Reaction::from_str(emoji).map_err(|_| anyhow!("invalid emoji"))?);
- }
- }
- Long("undo") if op == Some(OperationName::React) => {
- undo = true;
- }
-
- // Comment options.
- Long("reply-to") if op == Some(OperationName::Comment) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- reply_to = Some(rev);
- }
-
- Long("edit") if op == Some(OperationName::Comment) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- comment_op = Some((CommentOperation::Edit, rev));
- }
-
- Long("react") if op == Some(OperationName::Comment) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- comment_op = Some((CommentOperation::React, rev));
- }
- Long("emoji")
- if op == Some(OperationName::Comment)
- && matches!(comment_op, Some((CommentOperation::React, _))) =>
- {
- if let Some(emoji) = parser.value()?.to_str() {
- reaction =
- Some(Reaction::from_str(emoji).map_err(|_| anyhow!("invalid emoji"))?);
- }
- }
- Long("undo")
- if op == Some(OperationName::Comment)
- && matches!(comment_op, Some((CommentOperation::React, _))) =>
- {
- undo = true;
- }
-
- Long("redact") if op == Some(OperationName::Comment) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- comment_op = Some((CommentOperation::Redact, rev));
- }
-
- // Edit options.
- Long("revision") | Short('r') if op == Some(OperationName::Edit) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- revision_id = Some(rev);
- }
-
- // Review/diff options.
- Long("revision") | Short('r')
- if op == Some(OperationName::Review) || op == Some(OperationName::Diff) =>
- {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- revision_id = Some(rev);
- }
- Long("patch") | Short('p') if op == Some(OperationName::Review) => {
- if let review::Operation::Review { by_hunk, .. } = &mut review_op {
- *by_hunk = true;
- } else {
- return Err(arg.unexpected().into());
- }
- }
- Long("unified") | Short('U') if op == Some(OperationName::Review) => {
- if let review::Operation::Review { unified, .. } = &mut review_op {
- let val = parser.value()?;
- *unified = term::args::number(&val)?;
- } else {
- return Err(arg.unexpected().into());
- }
- }
- Long("hunk") if op == Some(OperationName::Review) => {
- if let review::Operation::Review { hunk, .. } = &mut review_op {
- let val = parser.value()?;
- let val = term::args::number(&val)
- .map_err(|e| anyhow!("invalid hunk value: {e}"))?;
-
- *hunk = Some(val);
- } else {
- return Err(arg.unexpected().into());
- }
- }
- Long("delete") | Short('d') if op == Some(OperationName::Review) => {
- review_op = review::Operation::Delete;
- }
- Long("accept") if op == Some(OperationName::Review) => {
- if let review::Operation::Review {
- verdict: verdict @ None,
- ..
- } = &mut review_op
- {
- *verdict = Some(patch::Verdict::Accept);
- } else {
- return Err(arg.unexpected().into());
- }
- }
- Long("reject") if op == Some(OperationName::Review) => {
- if let review::Operation::Review {
- verdict: verdict @ None,
- ..
- } = &mut review_op
- {
- *verdict = Some(patch::Verdict::Reject);
- } else {
- return Err(arg.unexpected().into());
- }
- }
-
- // Resolve options
- Long("undo") if op == Some(OperationName::Resolve) => {
- undo = true;
- }
- Long("review") if op == Some(OperationName::Resolve) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- review_id = Some(rev);
- }
- Long("comment") if op == Some(OperationName::Resolve) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- comment_id = Some(rev);
- }
-
- // Checkout options
- Long("revision") if op == Some(OperationName::Checkout) => {
- let val = parser.value()?;
- let rev = term::args::rev(&val)?;
-
- revision_id = Some(rev);
- }
-
- Long("force") | Short('f') if op == Some(OperationName::Checkout) => {
- checkout_opts.force = true;
- }
-
- Long("name") if op == Some(OperationName::Checkout) => {
- let val = parser.value()?;
- checkout_opts.name = Some(term::args::refstring("name", val)?);
- }
-
- Long("remote") if op == Some(OperationName::Checkout) => {
- let val = parser.value()?;
- checkout_opts.remote = Some(term::args::refstring("remote", val)?);
- }
-
- // Assign options.
- Short('a') | Long("add") if matches!(op, Some(OperationName::Assign)) => {
- assign_opts.add.insert(term::args::did(&parser.value()?)?);
- }
-
- Short('d') | Long("delete") if matches!(op, Some(OperationName::Assign)) => {
- assign_opts
- .delete
- .insert(term::args::did(&parser.value()?)?);
- }
-
- // Label options.
- Short('a') | Long("add") if matches!(op, Some(OperationName::Label)) => {
- let val = parser.value()?;
- let name = term::args::string(&val);
- let label = Label::new(name)?;
-
- label_opts.add.insert(label);
- }
-
- Short('d') | Long("delete") if matches!(op, Some(OperationName::Label)) => {
- let val = parser.value()?;
- let name = term::args::string(&val);
- let label = Label::new(name)?;
-
- label_opts.delete.insert(label);
- }
-
- // Set options.
- Long("remote") if op == Some(OperationName::Set) => {
- let val = parser.value()?;
- remote = Some(term::args::refstring("remote", val)?);
- }
-
- // List options.
- Long("all") => {
- filter = None;
- }
- Long("draft") => {
- filter = Some(patch::Status::Draft);
- }
- Long("archived") => {
- filter = Some(patch::Status::Archived);
- }
- Long("merged") => {
- filter = Some(patch::Status::Merged);
- }
- Long("open") => {
- filter = Some(patch::Status::Open);
- }
- Long("authored") => {
- authored = true;
- }
- Long("author") if op == Some(OperationName::List) => {
- authors.push(term::args::did(&parser.value()?)?);
- }
-
- // Cache options.
- Long("storage") if op == Some(OperationName::Cache) => {
- cache_storage = true;
- }
-
- // Common.
- Long("quiet") | Short('q') => {
- quiet = true;
- }
- Long("repo") => {
- let val = parser.value()?;
- let rid = term::args::rid(&val)?;
-
- repo = Some(rid);
- }
- Long("help") => {
- return Err(Error::HelpManual { name: "rad-patch" }.into());
- }
- Short('h') => {
- return Err(Error::Help.into());
- }
-
- Value(val) if op.is_none() => match val.to_string_lossy().as_ref() {
- "l" | "list" => op = Some(OperationName::List),
- "s" | "show" => op = Some(OperationName::Show),
- "u" | "update" => op = Some(OperationName::Update),
- "d" | "delete" => op = Some(OperationName::Delete),
- "c" | "checkout" => op = Some(OperationName::Checkout),
- "a" | "archive" => op = Some(OperationName::Archive),
- "y" | "ready" => op = Some(OperationName::Ready),
- "e" | "edit" => op = Some(OperationName::Edit),
- "r" | "redact" => op = Some(OperationName::Redact),
- "diff" => op = Some(OperationName::Diff),
- "assign" => op = Some(OperationName::Assign),
- "label" => op = Some(OperationName::Label),
- "comment" => op = Some(OperationName::Comment),
- "review" => op = Some(OperationName::Review),
- "resolve" => op = Some(OperationName::Resolve),
- "set" => op = Some(OperationName::Set),
- "cache" => op = Some(OperationName::Cache),
- unknown => anyhow::bail!("unknown operation '{}'", unknown),
- },
- Value(val) if op == Some(OperationName::Redact) => {
- let rev = term::args::rev(&val)?;
- revision_id = Some(rev);
- }
- Value(val)
- if patch_id.is_none()
- && [
- Some(OperationName::Show),
- Some(OperationName::Diff),
- Some(OperationName::Update),
- Some(OperationName::Delete),
- Some(OperationName::Archive),
- Some(OperationName::Ready),
- Some(OperationName::Checkout),
- Some(OperationName::Comment),
- Some(OperationName::Review),
- Some(OperationName::Resolve),
- Some(OperationName::Edit),
- Some(OperationName::Set),
- Some(OperationName::Assign),
- Some(OperationName::Label),
- Some(OperationName::Cache),
- ]
- .contains(&op) =>
- {
- let val = string(&val);
- patch_id = Some(Rev::from(val));
- }
- _ => anyhow::bail!(arg.unexpected()),
- }
- }
-
- let op = match op.unwrap_or_default() {
- OperationName::List => Operation::List { filter },
- OperationName::Show => Operation::Show {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- diff,
- verbose,
- },
- OperationName::Diff => Operation::Diff {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- revision_id,
- },
- OperationName::Delete => Operation::Delete {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- },
- OperationName::Update => Operation::Update {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- base_id,
- message,
- },
- OperationName::Archive => Operation::Archive {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch id must be provided"))?,
- undo,
- },
- OperationName::Checkout => Operation::Checkout {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- revision_id,
- opts: checkout_opts,
- },
- OperationName::Comment => match comment_op {
- Some((CommentOperation::Edit, comment)) => Operation::CommentEdit {
- revision_id: patch_id
- .ok_or_else(|| anyhow!("a patch or revision must be provided"))?,
- comment_id: comment,
- message,
- },
- Some((CommentOperation::React, comment)) => Operation::CommentReact {
- revision_id: patch_id
- .ok_or_else(|| anyhow!("a patch or revision must be provided"))?,
- comment_id: comment,
- reaction: reaction
- .ok_or_else(|| anyhow!("a reaction emoji must be provided"))?,
- undo,
- },
- Some((CommentOperation::Redact, comment)) => Operation::CommentRedact {
- revision_id: patch_id
- .ok_or_else(|| anyhow!("a patch or revision must be provided"))?,
- comment_id: comment,
- },
- None => Operation::Comment {
- revision_id: patch_id
- .ok_or_else(|| anyhow!("a patch or revision must be provided"))?,
- message,
- reply_to,
- },
- },
- OperationName::React => Operation::React {
- revision_id: patch_id
- .ok_or_else(|| anyhow!("a patch or revision must be provided"))?,
- reaction: reaction.ok_or_else(|| anyhow!("a reaction emoji must be provided"))?,
- undo,
- },
- OperationName::Review => Operation::Review {
- patch_id: patch_id
- .ok_or_else(|| anyhow!("a patch or revision must be provided"))?,
- revision_id,
- opts: review::Options {
- message,
- op: review_op,
- },
- },
- OperationName::Resolve => Operation::Resolve {
- patch_id: patch_id
- .ok_or_else(|| anyhow!("a patch or revision must be provided"))?,
- review_id: review_id.ok_or_else(|| anyhow!("a review must be provided"))?,
- comment_id: comment_id.ok_or_else(|| anyhow!("a comment must be provided"))?,
- undo,
- },
- OperationName::Ready => Operation::Ready {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- undo,
- },
- OperationName::Edit => Operation::Edit {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- revision_id,
- message,
- },
- OperationName::Redact => Operation::Redact {
- revision_id: revision_id.ok_or_else(|| anyhow!("a revision must be provided"))?,
- },
- OperationName::Assign => Operation::Assign {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- opts: assign_opts,
- },
- OperationName::Label => Operation::Label {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- opts: label_opts,
- },
- OperationName::Set => Operation::Set {
- patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
- remote,
- },
- OperationName::Cache => Operation::Cache {
- patch_id,
- storage: cache_storage,
- },
- };
-
- Ok((
- Options {
- op,
- repo,
- quiet,
- announce,
- authored,
- authors,
- },
- vec![],
- ))
- }
-}
-
-pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
- let (workdir, rid) = if let Some(rid) = options.repo {
+pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
+ let (workdir, rid) = if let Some(rid) = args.repo {
(None, rid)
} else {
radicle::rad::cwd()
@@ -846,37 +180,39 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let profile = ctx.profile()?;
let repository = profile.storage.repository(rid)?;
- let announce = options.announce && options.op.is_announce();
+ let announce = !args.no_announce && args.command.is_some_and(|c| c.is_announce());
transport::local::register(profile.storage.clone());
- match options.op {
- Operation::List { filter } => {
- let mut authors: BTreeSet<Did> = options.authors.iter().cloned().collect();
+ match args.command {
+ Some(Command::List { filter, options, authors }) => {
+ let mut authors: BTreeSet<Did> = authors.iter().cloned().collect();
if options.authored {
authors.insert(profile.did());
}
list::run(filter.as_ref(), authors, &repository, &profile)?;
}
- Operation::Show {
+
+ Some(Command::Show {
patch_id,
- diff,
+ patch,
verbose,
- } => {
+ }) => {
let patch_id = patch_id.resolve(&repository.backend)?;
show::run(
&patch_id,
- diff,
+ patch,
verbose,
&profile,
&repository,
workdir.as_ref(),
)?;
}
- Operation::Diff {
+
+ Some(Command::Diff {
patch_id,
revision_id,
- } => {
+ }) => {
let patch_id = patch_id.resolve(&repository.backend)?;
let revision_id = revision_id
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
@@ -884,11 +220,12 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
.map(patch::RevisionId::from);
diff::run(&patch_id, revision_id, &repository, &profile)?;
}
- Operation::Update {
+
+ Some(Command::Update {
ref patch_id,
ref base_id,
- ref message,
- } => {
+ message: crate::commands::rad_patch::args::UpdateMessageArg { message, no_message: _ },
+ }) => {
let patch_id = patch_id.resolve(&repository.backend)?;
let base_id = base_id
.as_ref()
@@ -907,11 +244,13 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
&workdir,
)?;
}
- Operation::Archive { ref patch_id, undo } => {
+
+ Some(Command::Archive { ref patch_id, undo }) => {
let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
archive::run(&patch_id, undo, &profile, &repository)?;
}
- Operation::Ready { ref patch_id, undo } => {
+
+ Some(Command::Ready { ref patch_id, undo }) => {
let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
if !ready::run(&patch_id, undo, &profile, &repository)? {
@@ -922,15 +261,17 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
}
}
}
- Operation::Delete { patch_id } => {
+
+ Some(Command::Delete { patch_id }) => {
let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
delete::run(&patch_id, &profile, &repository)?;
}
- Operation::Checkout {
+
+ Some(Command::Checkout {
patch_id,
revision_id,
opts,
- } => {
+ }) => {
let patch_id = patch_id.resolve::<radicle::git::Oid>(&repository.backend)?;
let revision_id = revision_id
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
@@ -945,28 +286,15 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
&repository,
&workdir,
&profile,
- opts,
- )?;
- }
- Operation::Comment {
- revision_id,
- message,
- reply_to,
- } => {
- comment::run(
- revision_id,
- message,
- reply_to,
- options.quiet,
- &repository,
- &profile,
+ opts.into(),
)?;
}
- Operation::Review {
+
+ Some(Command::Review {
patch_id,
revision_id,
opts,
- } => {
+ }) => {
let patch_id = patch_id.resolve(&repository.backend)?;
let revision_id = revision_id
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
@@ -974,12 +302,13 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
.map(patch::RevisionId::from);
review::run(patch_id, revision_id, opts, &profile, &repository)?;
}
- Operation::Resolve {
+
+ Some(Command::Resolve {
ref patch_id,
ref review_id,
ref comment_id,
undo,
- } => {
+ }) => {
let patch = patch_id.resolve(&repository.backend)?;
let review = patch::ReviewId::from(
review_id.resolve::<radicle::cob::EntryId>(&repository.backend)?,
@@ -993,11 +322,11 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
term::success!("Resolved comment {comment_id}");
}
}
- Operation::Edit {
+ Some(Command::Edit {
patch_id,
revision_id,
message,
- } => {
+ }) => {
let patch_id = patch_id.resolve(&repository.backend)?;
let revision_id = revision_id
.map(|id| id.resolve::<radicle::git::Oid>(&repository.backend))
@@ -1005,24 +334,24 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
.map(patch::RevisionId::from);
edit::run(&patch_id, revision_id, message, &profile, &repository)?;
}
- Operation::Redact { revision_id } => {
+ Some(Command::Redact { revision_id }) => {
redact::run(&revision_id, &profile, &repository)?;
}
- Operation::Assign {
+ Some(Command::Assign {
patch_id,
- opts: AssignOptions { add, delete },
- } => {
+ opts: self::args::AssignArg { add, delete },
+ }) => {
let patch_id = patch_id.resolve(&repository.backend)?;
assign::run(&patch_id, add, delete, &profile, &repository)?;
}
- Operation::Label {
+ Some(Command::Label {
patch_id,
- opts: LabelOptions { add, delete },
- } => {
+ opts: self::args::LabelArg { add, delete },
+ }) => {
let patch_id = patch_id.resolve(&repository.backend)?;
label::run(&patch_id, add, delete, &profile, &repository)?;
}
- Operation::Set { patch_id, remote } => {
+ Some(Command::Set { patch_id, remote }) => {
let patches = term::cob::patches(&profile, &repository)?;
let patch_id = patch_id.resolve(&repository.backend)?;
let patch = patches
@@ -1039,7 +368,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
true,
)?;
}
- Operation::Cache { patch_id, storage } => {
+ Some(Command::Cache { patch_id, storage }) => {
let mode = if storage {
cache::CacheMode::Storage
} else {
@@ -1058,34 +387,34 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
};
cache::run(mode, &profile)?;
}
- Operation::CommentEdit {
+ Some(Command::Comment { subcommand: CommentSubcommand::Edit {
revision_id,
comment_id,
message,
- } => {
+ }}) => {
let comment = comment_id.resolve(&repository.backend)?;
comment::edit::run(
revision_id,
comment,
message,
- options.quiet,
+ args.quiet,
&repository,
&profile,
)?;
}
- Operation::CommentRedact {
+ Some(Command::Comment { subcommand: CommentSubcommand::Redact {
revision_id,
comment_id,
- } => {
+ }}) => {
let comment = comment_id.resolve(&repository.backend)?;
comment::redact::run(revision_id, comment, &repository, &profile)?;
}
- Operation::CommentReact {
+ Some(Command::Comment { subcommand: CommentSubcommand::React {
revision_id,
comment_id,
reaction,
undo,
- } => {
+ }}) => {
let comment = comment_id.resolve(&repository.backend)?;
if undo {
comment::react::run(revision_id, comment, reaction, false, &repository, &profile)?;
@@ -1093,17 +422,21 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
comment::react::run(revision_id, comment, reaction, true, &repository, &profile)?;
}
}
- Operation::React {
+ Some(Command::React {
revision_id,
reaction,
undo,
- } => {
+ }) => {
if undo {
react::run(&revision_id, reaction, false, &repository, &profile)?;
} else {
react::run(&revision_id, reaction, true, &repository, &profile)?;
}
}
+
+ None => {
+ unimplemented!(),
+ }
}
if announce {
diff --git a/crates/radicle-cli/src/commands/patch/args.rs b/crates/radicle-cli/src/commands/patch/args.rs
new file mode 100644
index 000000000..8eb49e534
--- /dev/null
+++ b/crates/radicle-cli/src/commands/patch/args.rs
@@ -0,0 +1,362 @@
+use clap::{Parser, Subcommand};
+use clap_complete::ArgValueCompleter;
+use radicle::prelude::Did;
+
+use crate::git::Rev;
+
+#[derive(Parser, Debug)]
+pub struct Args {
+ /// Subcommand for `radicle issue`
+ #[command(subcommand)]
+ pub(crate) command: Option<Command>,
+
+ /// Don't print anything
+ #[arg(short, long)]
+ #[clap(global = true)]
+ pub(crate) quiet: bool,
+
+ /// Don't announce issue to peers
+ #[arg(long)]
+ #[arg(value_name = "no-announce")]
+ #[clap(global = true)]
+ pub(crate) no_announce: bool,
+
+ /// Show only the issue header, hiding the comments
+ #[arg(long)]
+ #[clap(global = true)]
+ pub(crate) header: bool,
+
+ /// Optionally specify the repository to manage issues for
+ #[arg(value_name = "RID")]
+ #[arg(long, short)]
+ #[clap(global = true)]
+ pub(crate) repo: Option<radicle::prelude::RepoId>,
+
+ /// Verbose output
+ #[arg(long, short)]
+ #[clap(global = true)]
+ pub(crate) verbose: bool,
+}
+
+#[derive(Debug, clap::Args)]
+#[group(required = false, multiple = false)]
+pub struct ListOptions {
+ #[arg(long, group = "cmd-list")]
+ pub all: bool,
+
+ #[arg(long, group = "cmd-list")]
+ pub merged: bool,
+
+ #[arg(long, group = "cmd-list")]
+ pub open: bool,
+
+ #[arg(long, group = "cmd-list")]
+ pub archived: bool,
+
+ #[arg(long, group = "cmd-list")]
+ pub draft: bool,
+
+ #[arg(long, group = "cmd-list")]
+ pub authored: bool,
+}
+
+#[derive(Debug, Parser)]
+pub struct ReviewOptions {
+ #[clap(long, group = "cmd-review")]
+ pub accept: bool,
+
+ #[clap(long, group = "cmd-review")]
+ pub reject: bool,
+
+ #[clap(long, short = 'm', group = "cmd-review")]
+ pub message: String,
+
+ #[clap(long, short = 'd', group = "cmd-review")]
+ pub delete: bool,
+}
+
+impl From<ReviewOptions> for crate::commands::rad_patch::review::Options {
+ fn from(value: ReviewOptions) -> Self {
+ Self {
+ message: value.message.into(),
+ op: if value.delete {
+ crate::commands::rad_patch::review::Operation::Delete
+ } else {
+ todo!()
+ }
+ }
+ }
+}
+
+#[derive(Debug, clap::Args)]
+#[group(required = false, multiple = false)]
+pub struct UpdateMessageArg {
+ #[clap(long = "message", short = 'm', group = "update-message-arg")]
+ pub message: crate::terminal::patch::Message,
+
+ #[clap(long = "no-message")]
+ pub no_message: bool,
+}
+
+#[derive(Debug, clap::Args)]
+#[group(required = false, multiple = false)]
+pub struct LabelArg {
+ #[clap(long, group = "label-arg")]
+ pub add: Option<String>,
+
+ #[clap(long, group = "label-arg")]
+ pub delete: Option<String>,
+}
+
+
+#[derive(Debug, clap::Args)]
+#[group(required = false, multiple = false)]
+pub struct AssignArg {
+ #[clap(long, group = "assign-arg")]
+ pub add: Option<String>,
+
+ #[clap(long, group = "assign-arg")]
+ pub delete: Option<String>,
+}
+
+#[derive(Debug, clap::Args)]
+pub struct CheckoutOptions {
+ #[clap(long)]
+ pub name: Option<git_ref_format::RefString>,
+
+ #[clap(long)]
+ pub remote: Option<git_ref_format::RefString>,
+
+ #[clap(long)]
+ pub force: bool,
+}
+
+impl From<CheckoutOptions> for crate::commands::rad_patch::checkout::Options {
+ fn from(value: CheckoutOptions) -> Self {
+ Self {
+ name: value.name,
+ remote: value.remote,
+ force: value.force,
+ }
+ }
+}
+
+/// Commands to create, view, and edit Radicle issues
+#[derive(Subcommand, Debug)]
+pub enum Command {
+ List {
+ #[clap(flatten)]
+ options: ListOptions,
+
+ #[clap(long)]
+ authors: Vec<Did>,
+
+ #[clap(long)]
+ filter: Option<radicle::patch::Status>,
+ },
+
+ Show {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ // Show the actual patch diff
+ patch: bool,
+
+ /// Show additional information about the patch
+ verbose: bool,
+ },
+
+ Diff {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ /// The revision of diff (default: latest)
+ #[clap(long = "revision", short = 'r')]
+ revision_id: Option<Rev>,
+ },
+
+ Archive {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ undo: bool,
+ },
+
+ Update {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ #[clap(long = "base", short = 'n')]
+ base_id: Option<Rev>,
+
+ #[clap(flatten)]
+ message: UpdateMessageArg,
+ },
+
+ Checkout {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ #[clap(long)]
+ revision_id: Option<Rev>,
+
+ #[clap(flatten)]
+ opts: CheckoutOptions,
+ },
+
+ Review {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ #[clap(long)]
+ revision_id: Option<Rev>,
+
+ #[clap(flatten)]
+ options: ReviewOptions,
+ },
+
+ Resolve {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ #[clap(long)]
+ review_id: Option<Rev>,
+
+ #[clap(long)]
+ comment_id: Option<Rev>,
+
+ #[clap(long)]
+ undo: bool,
+ },
+
+ Delete {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+ },
+
+ Redact {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+ },
+
+ React {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ #[clap(long)]
+ react: Option<radicle::cob::Reaction>,
+ },
+
+ Assign {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ #[clap(flatten)]
+ opts: AssignArg,
+ },
+
+ Label {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ #[clap(flatten)]
+ opts: LabelArg,
+ },
+
+ Ready {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+
+ undo: bool,
+ },
+
+ Edit {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+ },
+
+ Set {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Rev,
+ },
+
+ Comment {
+ #[command(subcommand)]
+ subcommand: CommentSubcommand,
+ },
+
+ Cache {
+ #[arg(value_name = "PATCH_ID", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ patch_id: Option<Rev>,
+
+ #[arg(long)]
+ storage: bool,
+ },
+}
+
+#[derive(Subcommand, Debug)]
+pub enum CommentSubcommand {
+ Edit {
+ #[arg(value_name = "REVISION", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ revision_id: Rev,
+ #[arg(value_name = "COMMENT", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ comment_id: Rev,
+
+ #[arg(long, short)]
+ message: crate::terminal::patch::Message,
+ },
+ Redact {
+ #[arg(value_name = "REVISION", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ revision_id: Rev,
+ #[arg(value_name = "COMMENT", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ comment_id: Rev,
+ },
+ React {
+ #[arg(value_name = "REVISION", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ revision_id: Rev,
+ #[arg(value_name = "COMMENT", add = ArgValueCompleter::new(crate::commands::hints::patch_ids_completer))]
+ comment_id: Rev,
+
+ #[arg(long)]
+ reaction: radicle::cob::Reaction,
+
+ #[arg(long)]
+ undo: bool,
+ },
+}
+
+impl Command {
+ pub(super) fn is_announce(&self) -> bool {
+ match self {
+ Self::Update { .. }
+ | Self::Archive { .. }
+ | Self::Ready { .. }
+ | Self::Delete { .. }
+ | Self::Comment {
+ subcommand: CommentSubcommand::Edit { .. },
+ ..
+ }
+ | Self::Comment {
+ subcommand: CommentSubcommand::Redact { .. },
+ ..
+ }
+ | Self::Comment {
+ subcommand: CommentSubcommand::React { .. },
+ ..
+ }
+ | Self::Review { .. }
+ | Self::Resolve { .. }
+ | Self::Assign { .. }
+ | Self::Label { .. }
+ | Self::Edit { .. }
+ | Self::Redact { .. }
+ | Self::React { .. }
+ | Self::Set { .. } => true,
+ Self::Show { .. }
+ | Self::Diff { .. }
+ | Self::Checkout { .. }
+ | Self::List { .. }
+ | Self::Cache { .. } => false,
+ }
+ }
+}
Exit code: 0
shell: 'export RUSTDOCFLAGS=''-D warnings'' cargo --version rustc --version cargo fmt --check cargo clippy --all-targets --workspace -- --deny warnings cargo build --all-targets --workspace cargo doc --workspace --no-deps cargo test --workspace --no-fail-fast '
Commands:
$ podman run --name 052f6316-93b9-4081-8c8a-40f8be8fc6af -v /opt/radcis/ci.rad.levitte.org/cci/state/052f6316-93b9-4081-8c8a-40f8be8fc6af/s:/052f6316-93b9-4081-8c8a-40f8be8fc6af/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/052f6316-93b9-4081-8c8a-40f8be8fc6af/w:/052f6316-93b9-4081-8c8a-40f8be8fc6af/w -w /052f6316-93b9-4081-8c8a-40f8be8fc6af/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:trixie bash /052f6316-93b9-4081-8c8a-40f8be8fc6af/s/script.sh
+ export 'RUSTDOCFLAGS=-D warnings'
+ RUSTDOCFLAGS='-D warnings'
+ cargo --version
info: syncing channel updates for '1.88-x86_64-unknown-linux-gnu'
info: latest update on 2025-06-26, rust version 1.88.0 (6b00bc388 2025-06-23)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-src'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
info: installing component 'rust-src'
info: installing component 'rust-std'
info: installing component 'rustc'
info: installing component 'rustfmt'
cargo 1.88.0 (873a06493 2025-05-10)
+ rustc --version
rustc 1.88.0 (6b00bc388 2025-06-23)
+ cargo fmt --check
+ cargo clippy --all-targets --workspace -- --deny warnings
Updating crates.io index
Downloading crates ...
Downloaded aead v0.5.2
Downloaded adler2 v2.0.0
Downloaded addr2line v0.24.2
Downloaded nonempty v0.9.0
Downloaded num v0.4.3
Downloaded noise-framework v0.4.0
Downloaded newline-converter v0.3.0
Downloaded normalize-line-endings v0.3.0
Downloaded nu-ansi-term v0.46.0
Downloaded mio v1.0.4
Downloaded poly1305 v0.8.0
Downloaded num-integer v0.1.46
Downloaded amplify_derive v4.0.0
Downloaded regex v1.11.1
Downloaded ghash v0.5.1
Downloaded ref-cast v1.0.24
Downloaded dyn-clone v1.0.17
Downloaded serde_derive_internals v0.29.1
Downloaded bit-set v0.8.0
Downloaded fancy-regex v0.14.0
Downloaded faster-hex v0.10.0
Downloaded radicle-std-ext v0.1.1
Downloaded ref-cast-impl v1.0.24
Downloaded sha1 v0.10.6
Downloaded signature v1.6.4
Downloaded scopeguard v1.2.0
Downloaded gix-prompt v0.11.1
Downloaded gix-date v0.10.5
Downloaded shell-words v1.1.0
Downloaded hash32 v0.3.1
Downloaded itoa v1.0.11
Downloaded salsa20 v0.10.2
Downloaded rustc-demangle v0.1.26
Downloaded ppv-lite86 v0.2.17
Downloaded typeid v1.0.3
Downloaded matchers v0.1.0
Downloaded ryu v1.0.17
Downloaded generic-array v0.14.7
Downloaded signals_receipts v0.2.0
Downloaded pkcs1 v0.7.5
Downloaded thread_local v1.1.9
Downloaded p256 v0.13.2
Downloaded thiserror v2.0.12
Downloaded idna_adapter v1.2.0
Downloaded heck v0.5.0
Downloaded subtle v2.5.0
Downloaded value-bag-serde1 v1.11.1
Downloaded similar v2.5.0
Downloaded strsim v0.11.1
Downloaded structured-logger v1.0.4
Downloaded gix-sec v0.12.0
Downloaded systemd-journal-logger v2.2.2
Downloaded icu_locid_transform_data v1.5.1
Downloaded siphasher v1.0.1
Downloaded synstructure v0.13.1
Downloaded bitflags v2.9.1
Downloaded stable_deref_trait v1.2.0
Downloaded gix-trace v0.1.13
Downloaded tree-sitter-json v0.24.8
Downloaded sval_ref v2.14.1
Downloaded crossbeam-utils v0.8.19
Downloaded gix-fs v0.16.1
Downloaded sval_json v2.14.1
Downloaded gix-commitgraph v0.29.0
Downloaded toml_datetime v0.7.0
Downloaded fxhash v0.2.1
Downloaded yoke v0.7.5
Downloaded git-ref-format-macro v0.5.0
Downloaded gix-actor v0.35.4
Downloaded sqlite3-sys v0.15.2
Downloaded keccak v0.1.5
Downloaded tree-sitter-language v0.1.2
Downloaded smallvec v1.15.1
Downloaded zerovec-derive v0.10.3
Downloaded unicode-display-width v0.3.0
Downloaded test-log v0.2.18
Downloaded sval_serde v2.14.1
Downloaded form_urlencoded v1.2.1
Downloaded gix-quote v0.6.0
Downloaded inout v0.1.3
Downloaded home v0.5.9
Downloaded human-panic v2.0.3
Downloaded ssh-encoding v0.2.0
Downloaded serde_json v1.0.140
Downloaded timeago v0.4.2
Downloaded tinyvec_macros v0.1.1
Downloaded tree-sitter-toml-ng v0.6.0
Downloaded base64 v0.21.7
Downloaded unicode-ident v1.0.12
Downloaded uuid v1.16.0
Downloaded tempfile v3.23.0
Downloaded hmac v0.12.1
Downloaded itertools v0.14.0
Downloaded tinyvec v1.6.0
Downloaded icu_normalizer v1.5.0
Downloaded gix-ref v0.53.1
Downloaded tar v0.4.40
Downloaded jsonschema v0.30.0
Downloaded jiff-static v0.2.15
Downloaded ssh-key v0.6.6
Downloaded inquire v0.7.5
Downloaded heapless v0.8.0
Downloaded hashbrown v0.15.5
Downloaded fraction v0.15.3
Downloaded winnow v0.7.13
Downloaded tree-sitter v0.24.4
Downloaded git2 v0.19.0
Downloaded tree-sitter-python v0.23.4
Downloaded zlib-rs v0.5.2
Downloaded rustix v0.38.34
Downloaded gimli v0.31.1
Downloaded syn v1.0.109
Downloaded regex-syntax v0.8.5
Downloaded rustix v1.0.7
Downloaded syn v2.0.106
Downloaded tree-sitter-md v0.3.2
Downloaded tree-sitter-rust v0.23.2
Downloaded tree-sitter-bash v0.23.3
Downloaded unicode-width v0.2.1
Downloaded object v0.36.7
Downloaded bloomy v1.2.0
Downloaded icu_properties_data v1.5.1
Downloaded vcpkg v0.2.15
Downloaded regex-automata v0.4.9
Downloaded tree-sitter-ruby v0.23.1
Downloaded regex-syntax v0.6.29
Downloaded tracing-subscriber v0.3.19
Downloaded tree-sitter-c v0.23.2
Downloaded p384 v0.13.0
Downloaded chrono v0.4.38
Downloaded unicode-normalization v0.1.23
Downloaded jiff v0.2.15
Downloaded hashbrown v0.14.3
Downloaded idna v1.0.3
Downloaded libc v0.2.174
Downloaded sha1-checked v0.10.0
Downloaded tokio v1.47.1
Downloaded zerocopy v0.7.35
Downloaded tree-sitter-typescript v0.23.2
Downloaded sha3 v0.10.8
Downloaded crossterm v0.29.0
Downloaded clap_builder v4.5.44
Downloaded flate2 v1.1.1
Downloaded unicode-segmentation v1.11.0
Downloaded gix-pack v0.60.0
Downloaded mio v0.8.11
Downloaded emojis v0.6.4
Downloaded indicatif v0.18.0
Downloaded gix-protocol v0.51.0
Downloaded gix-odb v0.70.0
Downloaded tree-sitter-go v0.23.4
Downloaded cyphernet v0.5.2
Downloaded bstr v1.12.0
Downloaded crossterm v0.25.0
Downloaded socket2 v0.5.7
Downloaded miniz_oxide v0.8.8
Downloaded gix-transport v0.48.0
Downloaded icu_provider v1.5.0
Downloaded tracing v0.1.41
Downloaded url v2.5.4
Downloaded zerovec v0.10.4
Downloaded crossbeam-channel v0.5.15
Downloaded cc v1.2.2
Downloaded base64 v0.22.1
Downloaded spin v0.9.8
Downloaded icu_properties v1.5.1
Downloaded toml v0.9.5
Downloaded portable-atomic v1.11.0
Downloaded bytes v1.10.1
Downloaded p521 v0.13.3
Downloaded crypto-bigint v0.5.5
Downloaded tinystr v0.7.6
Downloaded sval_buffer v2.14.1
Downloaded linux-raw-sys v0.4.13
Downloaded sval v2.14.1
Downloaded unicode-width v0.1.11
Downloaded gix-url v0.32.0
Downloaded gix-traverse v0.47.0
Downloaded gix-path v0.10.20
Downloaded gix-packetline v0.19.1
Downloaded spki v0.7.3
Downloaded gix-revision v0.35.0
Downloaded icu_normalizer_data v1.5.1
Downloaded tracing-core v0.1.34
Downloaded indexmap v2.2.6
Downloaded libm v0.2.8
Downloaded radicle-surf v0.25.0
Downloaded der v0.7.9
Downloaded arc-swap v1.7.1
Downloaded sval_nested v2.14.1
Downloaded sval_dynamic v2.14.1
Downloaded utf8_iter v1.0.4
Downloaded unit-prefix v0.5.1
Downloaded gix-command v0.6.2
Downloaded libgit2-sys v0.17.0+1.8.1
Downloaded derive_more-impl v2.0.1
Downloaded utf16_iter v1.0.5
Downloaded chacha20poly1305 v0.10.1
Downloaded gix-negotiate v0.21.0
Downloaded gix-diff v0.53.0
Downloaded derive_more v2.0.1
Downloaded sqlite v0.32.0
Downloaded socks5-client v0.4.1
Downloaded tree-sitter-css v0.23.1
Downloaded toml_writer v1.0.2
Downloaded tree-sitter-html v0.23.2
Downloaded gix-revwalk v0.21.0
Downloaded writeable v0.5.5
Downloaded write16 v1.0.0
Downloaded vsimd v0.8.0
Downloaded gix-chunk v0.4.11
Downloaded git-ref-format v0.5.0
Downloaded clap v4.5.44
Downloaded git-ref-format-core v0.5.0
Downloaded gix-features v0.43.1
Downloaded elliptic-curve v0.13.8
Downloaded linux-raw-sys v0.9.4
Downloaded yansi v0.5.1
Downloaded value-bag v1.11.1
Downloaded sval_fmt v2.14.1
Downloaded siphasher v0.3.11
Downloaded zeroize v1.7.0
Downloaded console v0.16.0
Downloaded memchr v2.7.2
Downloaded fluent-uri v0.3.2
Downloaded clap_derive v4.5.41
Downloaded backtrace v0.3.75
Downloaded ecdsa v0.16.9
Downloaded chacha20 v0.9.1
Downloaded tree-sitter-highlight v0.24.4
Downloaded anyhow v1.0.82
Downloaded walkdir v2.5.0
Downloaded uuid-simd v0.8.0
Downloaded tracing-log v0.2.0
Downloaded snapbox v0.4.17
Downloaded jobserver v0.1.31
Downloaded zerofrom-derive v0.1.6
Downloaded lexopt v0.3.0
Downloaded sqlite3-src v0.5.1
Downloaded icu_collections v1.5.0
Downloaded yoke-derive v0.7.5
Downloaded diff v0.1.13
Downloaded base64ct v1.6.0
Downloaded anstream v0.6.13
Downloaded rand v0.8.5
Downloaded iana-time-zone v0.1.60
Downloaded email_address v0.2.9
Downloaded ed25519 v1.5.3
Downloaded cyphergraphy v0.3.0
Downloaded cbc v0.1.2
Downloaded byteorder v1.5.0
Downloaded streaming-iterator v0.1.9
Downloaded gix-utils v0.3.0
Downloaded test-log-macros v0.2.18
Downloaded schemars v1.0.4
Downloaded pretty_assertions v1.4.0
Downloaded crc32fast v1.5.0
Downloaded version_check v0.9.4
Downloaded utf8parse v0.2.1
Downloaded num-bigint-dig v0.8.4
Downloaded env_logger v0.11.8
Downloaded data-encoding v2.5.0
Downloaded ctr v0.9.2
Downloaded icu_locid_transform v1.5.0
Downloaded zerofrom v0.1.6
Downloaded litrs v0.4.1
Downloaded errno v0.3.13
Downloaded either v1.11.0
Downloaded bytesize v2.0.1
Downloaded anstyle-parse v0.2.3
Downloaded amplify_syn v2.0.1
Downloaded gix-hash v0.19.0
Downloaded icu_provider_macros v1.5.0
Downloaded gix-object v0.50.2
Downloaded sharded-slab v0.1.7
Downloaded prodash v30.0.1
Downloaded digest v0.10.7
Downloaded bit-vec v0.8.0
Downloaded rsa v0.9.6
Downloaded universal-hash v0.5.1
Downloaded ssh-cipher v0.2.0
Downloaded snapbox-macros v0.3.8
Downloaded gix-hashtable v0.9.0
Downloaded xattr v1.3.1
Downloaded value-bag-sval2 v1.11.1
Downloaded convert_case v0.7.1
Downloaded typenum v1.17.0
Downloaded memmap2 v0.9.8
Downloaded libz-rs-sys v0.5.2
Downloaded proc-macro2 v1.0.101
Downloaded once_cell v1.21.3
Downloaded num-traits v0.2.19
Downloaded erased-serde v0.4.6
Downloaded anstyle v1.0.11
Downloaded amplify_num v0.5.2
Downloaded gix-lock v18.0.0
Downloaded thiserror-impl v2.0.12
Downloaded thiserror-impl v1.0.69
Downloaded thiserror v1.0.69
Downloaded log v0.4.27
Downloaded lock_api v0.4.14
Downloaded litemap v0.7.5
Downloaded lazy_static v1.5.0
Downloaded icu_locid v1.5.0
Downloaded gix-validate v0.10.0
Downloaded gix-shallow v0.5.0
Downloaded gix-config-value v0.15.1
Downloaded getrandom v0.3.3
Downloaded getrandom v0.2.15
Downloaded libz-sys v1.1.16
Downloaded serde v1.0.219
Downloaded ct-codecs v1.1.1
Downloaded crypto-common v0.1.6
Downloaded cpufeatures v0.2.12
Downloaded cfg-if v1.0.0
Downloaded maybe-async v0.2.10
Downloaded serde_derive v1.0.219
Downloaded regex-automata v0.1.10
Downloaded anstyle-query v1.0.2
Downloaded data-encoding-macro-internal v0.1.12
Downloaded data-encoding-macro v0.1.14
Downloaded block-buffer v0.10.4
Downloaded signal-hook v0.3.18
Downloaded clap_lex v0.7.5
Downloaded ascii v1.1.0
Downloaded quote v1.0.41
Downloaded ff v0.13.0
Downloaded localtime v1.3.1
Downloaded gix-tempfile v18.0.0
Downloaded rand_core v0.6.4
Downloaded group v0.13.0
Downloaded gix-refspec v0.31.0
Downloaded gix-credentials v0.30.0
Downloaded shlex v1.3.0
Downloaded sha2 v0.10.8
Downloaded serde-untagged v0.1.7
Downloaded proc-macro-error2 v2.0.1
Downloaded pkg-config v0.3.30
Downloaded phf v0.11.3
Downloaded pem-rfc7468 v0.7.0
Downloaded polyval v0.6.2
Downloaded pkcs8 v0.10.2
Downloaded pin-project-lite v0.2.16
Downloaded os_info v3.12.0
Downloaded displaydoc v0.2.5
Downloaded colored v2.1.0
Downloaded proc-macro-error-attr2 v2.0.0
Downloaded phf_shared v0.11.3
Downloaded pbkdf2 v0.12.2
Downloaded num-cmp v0.1.0
Downloaded serde_fmt v1.0.3
Downloaded env_filter v0.1.3
Downloaded signal-hook-mio v0.2.4
Downloaded percent-encoding v2.3.1
Downloaded schemars_derive v1.0.4
Downloaded radicle-git-ext v0.10.0
Downloaded qcheck-macros v1.0.0
Downloaded fast-glob v0.3.3
Downloaded bytecount v0.6.8
Downloaded block-padding v0.3.3
Downloaded bcrypt-pbkdf v0.10.0
Downloaded ec25519 v0.1.0
Downloaded dunce v1.0.5
Downloaded cypheraddr v0.4.0
Downloaded colorchoice v1.0.0
Downloaded blowfish v0.9.1
Downloaded base32 v0.4.0
Downloaded document-features v0.2.11
Downloaded base16ct v0.2.0
Downloaded aho-corasick v1.1.3
Downloaded sem_safe v0.2.0
Downloaded parking_lot_core v0.9.12
Downloaded borrow-or-share v0.2.2
Downloaded base-x v0.2.11
Downloaded autocfg v1.2.0
Downloaded primeorder v0.13.6
Downloaded overload v0.1.1
Downloaded opaque-debug v0.3.1
Downloaded num-iter v0.1.45
Downloaded const-oid v0.9.6
Downloaded signature v2.2.0
Downloaded signal-hook-registry v1.4.5
Downloaded serde_spanned v1.0.0
Downloaded sec1 v0.7.3
Downloaded scrypt v0.11.0
Downloaded same-file v1.0.6
Downloaded rfc6979 v0.4.0
Downloaded referencing v0.30.0
Downloaded rand_chacha v0.3.1
Downloaded qcheck v1.0.0
Downloaded paste v1.0.15
Downloaded parking_lot v0.12.5
Downloaded outref v0.5.2
Downloaded fastrand v2.3.0
Downloaded equivalent v1.0.1
Downloaded cipher v0.4.4
Downloaded bitflags v1.3.2
Downloaded num-rational v0.4.2
Downloaded ahash v0.8.11
Downloaded num-complex v0.4.6
Downloaded aes-gcm v0.10.3
Downloaded num-bigint v0.4.6
Downloaded amplify v4.6.0
Downloaded escargot v0.5.10
Downloaded aes v0.8.4
Downloaded multibase v0.9.1
Downloaded filetime v0.2.23
Compiling libc v0.2.174
Compiling proc-macro2 v1.0.101
Compiling unicode-ident v1.0.12
Compiling quote v1.0.41
Checking cfg-if v1.0.0
Compiling shlex v1.3.0
Compiling version_check v0.9.4
Checking memchr v2.7.2
Compiling typenum v1.17.0
Checking getrandom v0.2.15
Compiling syn v2.0.106
Compiling generic-array v0.14.7
Compiling jobserver v0.1.31
Checking rand_core v0.6.4
Compiling serde v1.0.219
Compiling cc v1.2.2
Checking aho-corasick v1.1.3
Checking crypto-common v0.1.6
Checking regex-syntax v0.8.5
Checking smallvec v1.15.1
Checking subtle v2.5.0
Checking stable_deref_trait v1.2.0
Checking cpufeatures v0.2.12
Checking once_cell v1.21.3
Compiling parking_lot_core v0.9.12
Checking scopeguard v1.2.0
Checking fastrand v2.3.0
Checking lock_api v0.4.14
Checking block-buffer v0.10.4
Compiling thiserror v2.0.12
Checking parking_lot v0.12.5
Checking digest v0.10.7
Compiling crc32fast v1.5.0
Checking byteorder v1.5.0
Checking regex-automata v0.4.9
Checking tinyvec_macros v0.1.1
Compiling typeid v1.0.3
Checking tinyvec v1.6.0
Checking gix-trace v0.1.13
Checking bitflags v2.9.1
Checking unicode-normalization v0.1.23
Checking home v0.5.9
Compiling synstructure v0.13.1
Checking gix-utils v0.3.0
Checking zlib-rs v0.5.2
Checking same-file v1.0.6
Checking walkdir v2.5.0
Checking prodash v30.0.1
Checking itoa v1.0.11
Compiling heapless v0.8.0
Checking bstr v1.12.0
Checking libz-rs-sys v0.5.2
Checking flate2 v1.1.1
Compiling serde_derive v1.0.219
Compiling thiserror-impl v2.0.12
Compiling zerofrom-derive v0.1.6
Compiling yoke-derive v0.7.5
Compiling zerovec-derive v0.10.3
Checking zerofrom v0.1.6
Checking yoke v0.7.5
Compiling displaydoc v0.2.5
Checking gix-validate v0.10.0
Checking gix-path v0.10.20
Checking gix-features v0.43.1
Checking hash32 v0.3.1
Checking zeroize v1.7.0
Compiling pkg-config v0.3.30
Checking zerovec v0.10.4
Checking writeable v0.5.5
Compiling icu_locid_transform_data v1.5.1
Checking litemap v0.7.5
Compiling thiserror v1.0.69
Checking faster-hex v0.10.0
Checking tinystr v0.7.6
Compiling thiserror-impl v1.0.69
Checking icu_locid v1.5.0
Compiling icu_provider_macros v1.5.0
Compiling rustix v1.0.7
Compiling icu_properties_data v1.5.1
Checking icu_provider v1.5.0
Checking sha1 v0.10.6
Checking block-padding v0.3.3
Compiling icu_normalizer_data v1.5.1
Checking linux-raw-sys v0.9.4
Checking inout v0.1.3
Checking sha1-checked v0.10.0
Checking icu_locid_transform v1.5.0
Checking icu_collections v1.5.0
Compiling getrandom v0.3.3
Checking erased-serde v0.4.6
Checking serde_fmt v1.0.3
Compiling syn v1.0.109
Checking icu_properties v1.5.1
Checking value-bag-serde1 v1.11.1
Checking gix-hash v0.19.0
Checking value-bag v1.11.1
Checking cipher v0.4.4
Checking log v0.4.27
Checking utf16_iter v1.0.5
Checking write16 v1.0.0
Checking utf8_iter v1.0.4
Checking percent-encoding v2.3.1
Checking form_urlencoded v1.2.1
Checking icu_normalizer v1.5.0
Checking sha2 v0.10.8
Checking idna_adapter v1.2.0
Checking idna v1.0.3
Compiling vcpkg v0.2.15
Checking url v2.5.4
Checking universal-hash v0.5.1
Checking opaque-debug v0.3.1
Checking tempfile v3.23.0
Compiling autocfg v1.2.0
Compiling libgit2-sys v0.17.0+1.8.1
Compiling libz-sys v1.1.16
Compiling num-traits v0.2.19
Compiling serde_json v1.0.140
Checking hashbrown v0.14.3
Compiling amplify_syn v2.0.1
Checking equivalent v1.0.1
Checking signature v1.6.4
Checking ed25519 v1.5.3
Checking indexmap v2.2.6
Checking aead v0.5.2
Compiling ref-cast v1.0.24
Checking ascii v1.1.0
Checking amplify_num v0.5.2
Checking ct-codecs v1.1.1
Checking ryu v1.0.17
Compiling amplify_derive v4.0.0
Checking ec25519 v0.1.0
Checking poly1305 v0.8.0
Checking git-ref-format-core v0.5.0
Checking chacha20 v0.9.1
Compiling ref-cast-impl v1.0.24
Checking polyval v0.6.2
Compiling sqlite3-src v0.5.1
Checking amplify v4.6.0
Checking hmac v0.12.1
Checking cyphergraphy v0.3.0
Checking base64ct v1.6.0
Checking keccak v0.1.5
Checking dyn-clone v1.0.17
Checking sha3 v0.10.8
Checking pbkdf2 v0.12.2
Checking pem-rfc7468 v0.7.0
Checking ghash v0.5.1
Checking aes v0.8.4
Checking ctr v0.9.2
Checking rand v0.8.5
Compiling crossbeam-utils v0.8.19
Compiling data-encoding v2.5.0
Checking base32 v0.4.0
Checking cypheraddr v0.4.0
Checking qcheck v1.0.0
Compiling data-encoding-macro-internal v0.1.12
Checking aes-gcm v0.10.3
Checking ssh-encoding v0.2.0
Checking chacha20poly1305 v0.10.1
Checking cbc v0.1.2
Checking blowfish v0.9.1
Compiling serde_derive_internals v0.29.1
Checking data-encoding-macro v0.1.14
Checking bcrypt-pbkdf v0.10.0
Checking ssh-cipher v0.2.0
Checking noise-framework v0.4.0
Compiling schemars_derive v1.0.4
Checking socks5-client v0.4.1
Checking base-x v0.2.11
Checking signature v2.2.0
Checking ssh-key v0.6.6
Checking multibase v0.9.1
Checking cyphernet v0.5.2
Checking crossbeam-channel v0.5.15
Checking radicle-ssh v0.10.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-ssh)
Checking schemars v1.0.4
Checking lazy_static v1.5.0
Checking jiff v0.2.15
Checking nonempty v0.9.0
Checking siphasher v1.0.1
Checking radicle-git-metadata v0.1.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-git-metadata)
Checking radicle-dag v0.10.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-dag)
Checking winnow v0.7.13
Checking hashbrown v0.15.5
Checking anstyle-query v1.0.2
Checking gix-hashtable v0.9.0
Checking radicle-git-ref-format v0.1.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-git-ref-format)
Checking utf8parse v0.2.1
Checking base64 v0.21.7
Checking iana-time-zone v0.1.60
Checking chrono v0.4.38
Checking gix-date v0.10.5
Checking gix-actor v0.35.4
Checking gix-object v0.50.2
Checking anstyle-parse v0.2.3
Checking colored v2.1.0
Checking serde-untagged v0.1.7
Checking localtime v1.3.1
Checking bytesize v2.0.1
Checking memmap2 v0.9.8
Checking fast-glob v0.3.3
Checking tree-sitter-language v0.1.2
Checking colorchoice v1.0.0
Checking dunce v1.0.5
Checking anstyle v1.0.11
Checking gix-chunk v0.4.11
Checking gix-commitgraph v0.29.0
Checking anstream v0.6.13
Checking gix-fs v0.16.1
Checking gix-revwalk v0.21.0
Checking gix-tempfile v18.0.0
Checking mio v1.0.4
Checking gix-quote v0.6.0
Checking sem_safe v0.2.0
Checking errno v0.3.13
Checking shell-words v1.1.0
Checking either v1.11.0
Checking gix-command v0.6.2
Checking signals_receipts v0.2.0
Compiling signal-hook v0.3.18
Compiling object v0.36.7
Checking gix-lock v18.0.0
Checking gix-url v0.32.0
Checking gix-config-value v0.15.1
Checking gix-sec v0.12.0
Checking signal-hook-registry v1.4.5
Compiling rustix v0.38.34
Checking adler2 v2.0.0
Checking gimli v0.31.1
Checking miniz_oxide v0.8.8
Checking gix-prompt v0.11.1
Checking addr2line v0.24.2
Checking radicle-signals v0.11.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-signals)
Checking gix-revision v0.35.0
Checking gix-traverse v0.47.0
Checking gix-diff v0.53.0
Checking mio v0.8.11
Checking gix-packetline v0.19.1
Compiling tree-sitter v0.24.4
Compiling unicode-segmentation v1.11.0
Compiling linux-raw-sys v0.4.13
Checking rustc-demangle v0.1.26
Compiling anyhow v1.0.82
Checking backtrace v0.3.75
Compiling convert_case v0.7.1
Checking gix-transport v0.48.0
Checking signal-hook-mio v0.2.4
Checking gix-pack v0.60.0
Checking gix-refspec v0.31.0
Checking gix-credentials v0.30.0
Checking gix-ref v0.53.1
Checking gix-shallow v0.5.0
Checking gix-negotiate v0.21.0
Compiling maybe-async v0.2.10
Checking regex v1.11.1
Compiling proc-macro-error-attr2 v2.0.0
Compiling portable-atomic v1.11.0
Checking arc-swap v1.7.1
Checking gix-odb v0.70.0
Checking gix-protocol v0.51.0
Checking sqlite3-sys v0.15.2
Compiling proc-macro-error2 v2.0.1
Checking sqlite v0.32.0
Compiling xattr v1.3.1
Checking radicle-crypto v0.14.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-crypto)
Compiling derive_more-impl v2.0.1
Compiling filetime v0.2.23
Checking uuid v1.16.0
Compiling litrs v0.4.1
Checking bytes v1.10.1
Checking bitflags v1.3.2
Checking lexopt v0.3.0
Checking unicode-width v0.2.1
Checking crossterm v0.25.0
Checking derive_more v2.0.1
Compiling document-features v0.2.11
Checking console v0.16.0
Compiling tar v0.4.40
Compiling git-ref-format-macro v0.5.0
Checking newline-converter v0.3.0
Checking snapbox-macros v0.3.8
Checking salsa20 v0.10.2
Checking fxhash v0.2.1
Checking siphasher v0.3.11
Checking normalize-line-endings v0.3.0
Checking unicode-width v0.1.11
Checking similar v2.5.0
Checking streaming-iterator v0.1.9
Checking unit-prefix v0.5.1
Checking indicatif v0.18.0
Checking snapbox v0.4.17
Checking inquire v0.7.5
Compiling radicle-surf v0.25.0
Checking bloomy v1.2.0
Checking scrypt v0.11.0
Checking git-ref-format v0.5.0
Checking crossterm v0.29.0
Checking unicode-display-width v0.3.0
Checking systemd-journal-logger v2.2.2
Checking serde_spanned v1.0.0
Checking toml_datetime v0.7.0
Compiling tree-sitter-html v0.23.2
Compiling tree-sitter-python v0.23.4
Compiling tree-sitter-css v0.23.1
Compiling tree-sitter-typescript v0.23.2
Compiling tree-sitter-md v0.3.2
Compiling tree-sitter-c v0.23.2
Compiling tree-sitter-go v0.23.4
Compiling tree-sitter-bash v0.23.3
Compiling tree-sitter-rust v0.23.2
Compiling tree-sitter-toml-ng v0.6.0
Compiling tree-sitter-json v0.24.8
Compiling tree-sitter-ruby v0.23.1
Checking strsim v0.11.1
Checking clap_lex v0.7.5
Compiling heck v0.5.0
Checking toml_writer v1.0.2
Checking radicle-std-ext v0.1.1
Checking pin-project-lite v0.2.16
Compiling clap_derive v4.5.41
Checking toml v0.9.5
Checking tokio v1.47.1
Checking clap_builder v4.5.44
Checking os_info v3.12.0
Checking yansi v0.5.1
Checking diff v0.1.13
Compiling radicle-cli v0.17.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-cli)
Compiling radicle-node v0.16.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-node)
Checking pretty_assertions v1.4.0
Checking human-panic v2.0.3
Checking clap v4.5.44
Checking structured-logger v1.0.4
Checking radicle-systemd v0.11.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-systemd)
Checking tree-sitter-highlight v0.24.4
Checking itertools v0.14.0
Checking num-integer v0.1.46
Compiling qcheck-macros v1.0.0
Checking socket2 v0.5.7
Compiling escargot v0.5.10
Checking timeago v0.4.2
Checking num-bigint v0.4.6
Compiling ahash v0.8.11
Checking num-iter v0.1.45
Checking num-complex v0.4.6
Checking env_filter v0.1.3
Checking bit-vec v0.8.0
Checking num-rational v0.4.2
Checking zerocopy v0.7.35
Checking borrow-or-share v0.2.2
Checking fluent-uri v0.3.2
Checking num v0.4.3
Checking bit-set v0.8.0
Checking env_logger v0.11.8
Checking phf_shared v0.11.3
Compiling test-log-macros v0.2.18
Compiling radicle-remote-helper v0.14.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-remote-helper)
Checking vsimd v0.8.0
Checking outref v0.5.2
Compiling paste v1.0.15
Checking uuid-simd v0.8.0
Checking test-log v0.2.18
Checking phf v0.11.3
Checking referencing v0.30.0
Checking fancy-regex v0.14.0
Checking fraction v0.15.3
Checking email_address v0.2.9
Checking base64 v0.22.1
Checking bytecount v0.6.8
Checking num-cmp v0.1.0
Checking emojis v0.6.4
Checking jsonschema v0.30.0
Checking git2 v0.19.0
Checking radicle-oid v0.1.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-oid)
Checking radicle-git-ext v0.10.0
Checking radicle-term v0.16.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-term)
Checking radicle-cob v0.17.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-cob)
Checking radicle v0.20.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle)
Checking radicle-fetch v0.16.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-fetch)
Checking radicle-cli-test v0.13.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-cli-test)
Checking radicle-protocol v0.4.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-protocol)
Checking radicle-schemars v0.6.0 (/052f6316-93b9-4081-8c8a-40f8be8fc6af/w/crates/radicle-schemars)
error: this expression creates a reference which is immediately dereferenced by the compiler
--> crates/radicle-cli/src/commands/patch.rs:203:28
|
203 | msg.append(&line);
| ^^^^^ help: change this to: `line`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
= note: `-D clippy::needless-borrow` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`
error: could not compile `radicle-cli` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `radicle-cli` (lib test) due to 1 previous error
Exit code: 101
{
"response": "finished",
"result": "failure"
}