rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwoodb243aa8a0661e879f4e61060cf916ab0dd98df51
{
"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:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
"did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
]
},
"action": "Updated",
"patch": {
"id": "fd6784135ec9bf317cfd9c824841b547e36a2718",
"author": {
"id": "did:key:z6MkwGoyYxt6A2VE3fvZyH2rgiWdsXHBeV7jm7GSByS2aagA",
"alias": "ade"
},
"title": "Patches: Add support for custom merge destination",
"state": {
"status": "open",
"conflicts": []
},
"before": "90aaec1c9eee77a0beebece48f460c1424c1c8bd",
"after": "b243aa8a0661e879f4e61060cf916ab0dd98df51",
"commits": [
"b243aa8a0661e879f4e61060cf916ab0dd98df51",
"3a3cec905ddc50602d8dff10dec27ba4fdb48289",
"23519ce5bddfd8a038db9e2c21e8af4ef42d206e",
"688ba43adb10f924c290304f0fe54008caa8611a",
"eec61e4a9ee956aeac151762133cf6df69856dc4",
"807d84712ac96215ef15fcd15cde25f3fe763671",
"78b5a964890d9d32cb4b9d1a97b7180f98a64d40"
],
"target": "90aaec1c9eee77a0beebece48f460c1424c1c8bd",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "fd6784135ec9bf317cfd9c824841b547e36a2718",
"author": {
"id": "did:key:z6MkwGoyYxt6A2VE3fvZyH2rgiWdsXHBeV7jm7GSByS2aagA",
"alias": "ade"
},
"description": "This patch introduces the ability to specify a target branch for patches using\nthe `patch.destination` push option. Previously patches implicitly targeted the \nrepository's default branch. Furthermore this patch introduces strict isolation \nfor merges and reverts: a patch will now only be marked as merged or reverted \nif the commits are pushed to its explicitly intended destination branch.",
"base": "caee776c388ffac2ea55cc9d1e3d7fa108ca6df5",
"oid": "75d35fa458b3166ccf50e1f945574a8e8c852ac9",
"timestamp": 1778683486
},
{
"id": "c6bc2c718da5e039f27c0b57a02c5cd6d143001d",
"author": {
"id": "did:key:z6MkwGoyYxt6A2VE3fvZyH2rgiWdsXHBeV7jm7GSByS2aagA",
"alias": "ade"
},
"description": "Replaces `patch.destination` with `patch.target` and breaks forwards compatibility.",
"base": "caee776c388ffac2ea55cc9d1e3d7fa108ca6df5",
"oid": "d31ef1e6d051a73f11a472b8b6b8747c2e7f12f4",
"timestamp": 1778770594
},
{
"id": "2fb8f3455c8e9d2cf1f2ef894fbbb0372c7d2d07",
"author": {
"id": "did:key:z6MkwGoyYxt6A2VE3fvZyH2rgiWdsXHBeV7jm7GSByS2aagA",
"alias": "ade"
},
"description": "- Update wording of the CHANGELOG\n- Rename all instances of 'destination' with 'target'\n- Enforce branches only for `MergeTarget::Branch` via prefix check `refs/heads/`\n- Add magic push ref `refs/for/<branch>`\n- Add git configuration override `rad.magicPushPrefix` to change magic push ref",
"base": "1f40b32b6aedaaff2016cb20f9e2a3d9c681c651",
"oid": "45284c0fa11f23a9dbb58934499946e1d225c1f4",
"timestamp": 1779203854
},
{
"id": "f161555dabe6502b83ab692462ea51d2bafbd11b",
"author": {
"id": "did:key:z6MkwGoyYxt6A2VE3fvZyH2rgiWdsXHBeV7jm7GSByS2aagA",
"alias": "ade"
},
"description": "Adds magic push prefix to changelog",
"base": "1f40b32b6aedaaff2016cb20f9e2a3d9c681c651",
"oid": "936f7ab3fe258eb5f2769189a64cafe19ddb4ff8",
"timestamp": 1779204667
},
{
"id": "9a37acf5764157f61e12eafd410a81f308e4c263",
"author": {
"id": "did:key:z6MkwGoyYxt6A2VE3fvZyH2rgiWdsXHBeV7jm7GSByS2aagA",
"alias": "ade"
},
"description": "Review Changes\n\nThe first thing I did was reorganise the commits.\nPersonally, I was trying to figure out what the changes were, but the\nprevious `destination` changes were confusing me, so I squashed all\nrelevant changes to `cob/patch` into a single change. I then did the\nsame for the `radicle-remote-helper` changes. However, I left the\nmagic push changes isolated for the time being \u2013 they were cleanly\nseparated from the story and the changes are clear.\n\nThe notable changes I made during the refactoring:\n- I made `TargetBranch` hold a `Qualified` so that we always guarantee\n on construction that it is a `refs/heads` reference name. This\n pushes the parsing to the construction, and getting back the\n `Qualified` reference is trivial.\n- I created a new `TargetBranchError` enum so that the errors are\n scoped to that enum, and `Error` reuses that.\n- For the `MergeTarget::head` method, I don't think it needs to go\n through calculating the quorum to get the `Oid` of a reference.\n There are points where the quorum is calculated and set, and in this\n should simply be a lookup of the reference, if it exists.",
"base": "1f40b32b6aedaaff2016cb20f9e2a3d9c681c651",
"oid": "4340039a1673e3bfbda0cde6c35dbde346a2b4f2",
"timestamp": 1779349487
},
{
"id": "708948c2e7687005e8c07a89a9d70675c379f85b",
"author": {
"id": "did:key:z6MkwGoyYxt6A2VE3fvZyH2rgiWdsXHBeV7jm7GSByS2aagA",
"alias": "ade"
},
"description": "- Drop configurable magic ref\n- Add patch target to `rad patch show`",
"base": "90aaec1c9eee77a0beebece48f460c1424c1c8bd",
"oid": "b243aa8a0661e879f4e61060cf916ab0dd98df51",
"timestamp": 1780414700
}
]
}
}
{
"response": "triggered",
"run_id": {
"id": "a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4"
},
"info_url": "https://cci.rad.levitte.org//a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4.html"
}
Started at: 2026-06-02 17:38:30.911963+02:00
Commands:
$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 .
✓ Creating checkout in ./...
✓ Remote cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT added
✓ Remote-tracking branch cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/master created for z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT
✓ Remote cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW added
✓ Remote-tracking branch cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW/master created for z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW
✓ Remote fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM added
✓ Remote-tracking branch fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM/master created for z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM
✓ Remote erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz added
✓ Remote-tracking branch erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz/master created for z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz
✓ 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/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 176 issues · 41 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ rad patch checkout fd6784135ec9bf317cfd9c824841b547e36a2718
✓ Switched to branch patch/fd67841 at revision 708948c
✓ Branch patch/fd67841 setup to track rad/patches/fd6784135ec9bf317cfd9c824841b547e36a2718
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout b243aa8a0661e879f4e61060cf916ab0dd98df51
HEAD is now at b243aa8a cli/examples: Introduce a suite of merge and revert tests for patch.destination
Exit code: 0
$ rad patch show fd6784135ec9bf317cfd9c824841b547e36a2718 -p
╭─────────────────────────────────────────────────────────────────────────────────────────╮
│ Title Patches: Add support for custom merge destination │
│ Patch fd6784135ec9bf317cfd9c824841b547e36a2718 │
│ Author ade z6MkwGo…yS2aagA │
│ Head b243aa8a0661e879f4e61060cf916ab0dd98df51 │
│ Base 90aaec1c9eee77a0beebece48f460c1424c1c8bd │
│ Branches patch/fd67841 │
│ Commits ahead 7, behind 0 │
│ Status open │
│ │
│ This patch introduces the ability to specify a target branch for patches using │
│ the `patch.destination` push option. Previously patches implicitly targeted the │
│ repository's default branch. Furthermore this patch introduces strict isolation │
│ for merges and reverts: a patch will now only be marked as merged or reverted │
│ if the commits are pushed to its explicitly intended destination branch. │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ b243aa8 cli/examples: Introduce a suite of merge and revert tests for patch.destination │
│ 3a3cec9 radicle-cli/terminal: Add patch target ref to rad patch show │
│ 23519ce radicle: Add magic push prefix to changelog │
│ 688ba43 remote-helper: Introduce magic push ref 'refs/for/' │
│ eec61e4 remote-helper: Add 'patch.target' push option │
│ 807d847 radicle/cob/patch: Extend MergeTarget │
│ 78b5a96 cob: Replace 'git2::Oid' -> 'git::raw::Oid' │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ ● Revision fd67841 @ caee776..75d35fa by ade z6MkwGo…yS2aagA 2 weeks ago │
│ ↑ Revision c6bc2c7 @ caee776..d31ef1e by ade z6MkwGo…yS2aagA 2 weeks ago │
│ ↑ Revision 2fb8f34 @ 1f40b32..45284c0 by ade z6MkwGo…yS2aagA 2 weeks ago │
│ ↑ Revision f161555 @ 1f40b32..936f7ab by ade z6MkwGo…yS2aagA 2 weeks ago │
│ ↑ Revision 9a37acf @ 1f40b32..4340039 by fintohaps z6Mkire…SQZ3voM 1 week ago │
│ ↑ Revision 708948c @ 90aaec1..b243aa8 by ade z6MkwGo…yS2aagA 12 seconds ago │
╰─────────────────────────────────────────────────────────────────────────────────────────╯
commit b243aa8a0661e879f4e61060cf916ab0dd98df51
Author: Adrian Duke <adrian.duke@gmail.com>
Date: Thu May 7 16:42:42 2026 +0100
cli/examples: Introduce a suite of merge and revert tests for patch.destination
diff --git a/crates/radicle-cli/examples/rad-patch-merge-default-branch.md b/crates/radicle-cli/examples/rad-patch-merge-default-branch.md
new file mode 100644
index 000000000..59a1dae83
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-merge-default-branch.md
@@ -0,0 +1,55 @@
+# Merging patches into the default branch
+
+We create a feature branch and open a patch without specifying a target branch.
+
+``` (stderr)
+$ git checkout -b feature/1
+Switched to a new branch 'feature/1'
+$ touch FEATURE.md
+$ git add FEATURE.md
+```
+```
+$ git commit -m "Add new feature"
+[feature/1 [..]] Add new feature
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push -o patch.message="Add new feature" rad HEAD:refs/patches
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/patches
+```
+
+Now, Alice merges the feature into the `master` branch and pushes it.
+
+``` (stderr)
+$ git checkout master
+Switched to branch 'master'
+```
+```
+$ git merge feature/1
+Updating [..]
+Fast-forward
+ FEATURE.md | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push rad master
+✓ Patch [..] merged
+✓ Canonical reference refs/heads/master updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ [..]..[..] master -> master
+```
+
+Finally, we verify that the patch has been successfully marked as merged.
+
+```
+$ rad patch list --merged
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ✓ [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/crates/radicle-cli/examples/rad-patch-merge-into-canonical-ref-branch.md b/crates/radicle-cli/examples/rad-patch-merge-into-canonical-ref-branch.md
new file mode 100644
index 000000000..1b1ff1253
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-merge-into-canonical-ref-branch.md
@@ -0,0 +1,96 @@
+# Merging patches into non-default canonical branches
+
+First, we update the identity document to add a canonical reference rule for a new `accepted` branch, allowing delegates to merge into it.
+
+```
+$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+[..]
+```
+
+Now, let's create the `accepted` branch and push it to the repository so it becomes a tracked canonical reference:
+
+``` (stderr)
+$ git checkout -b accepted
+Switched to a new branch 'accepted'
+```
+
+```
+$ git commit --allow-empty -m "Initialize accepted branch"
+[accepted [..]] Initialize accepted branch
+```
+
+``` (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new branch] accepted -> accepted
+```
+
+Next, we create a feature branch and open a patch. We use the `patch.target` push option to explicitly state that this patch is intended for `refs/heads/accepted` rather than the default branch (`master`).
+
+``` (stderr)
+$ git checkout -b feature/1
+Switched to a new branch 'feature/1'
+$ touch FEATURE.md
+$ git add FEATURE.md
+```
+
+```
+$ git commit -m "Add new feature"
+[feature/1 [..]] Add new feature
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+
+``` (stderr)
+$ git push -o patch.message="Add new feature" -o patch.target="refs/heads/accepted" rad HEAD:refs/patches
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/patches
+```
+
+We can verify the patch is open:
+
+```
+$ rad patch
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ● [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
+
+Now, Alice merges the feature into the `accepted` branch and pushes it. Because `accepted` is a valid canonical reference and Alice is a delegate, the remote helper should detect the merge and update the patch status.
+
+``` (stderr)
+$ git checkout accepted
+Switched to branch 'accepted'
+```
+
+```
+$ git merge feature/1
+Updating [..]
+Fast-forward
+ FEATURE.md | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+
+``` (stderr)
+$ git push rad accepted
+✓ Patch [..] merged
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ [..]..[..] accepted -> accepted
+```
+
+Finally, we verify that the patch has been successfully marked as merged, even though it wasn't merged into the default branch.
+
+```
+$ rad patch list --merged
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ✓ [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/crates/radicle-cli/examples/rad-patch-merge-strict-destination.md b/crates/radicle-cli/examples/rad-patch-merge-strict-destination.md
new file mode 100644
index 000000000..834fd0be0
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-merge-strict-destination.md
@@ -0,0 +1,82 @@
+# Merging patches has a strict destination
+
+First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+
+```
+$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+[..]
+```
+
+Now, let's create the `accepted` branch and push it:
+
+``` (stderr)
+$ git checkout -b accepted
+Switched to a new branch 'accepted'
+```
+```
+$ git commit --allow-empty -m "Initialize accepted branch"
+[accepted [..]] Initialize accepted branch
+```
+``` (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new branch] accepted -> accepted
+```
+
+Next, we create a feature branch and open a patch. We do *not* specify a destination, so it defaults to `master`.
+
+``` (stderr)
+$ git checkout -b feature/1
+Switched to a new branch 'feature/1'
+$ touch FEATURE.md
+$ git add FEATURE.md
+```
+```
+$ git commit -m "Add new feature"
+[feature/1 [..]] Add new feature
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push -o patch.message="Add new feature" rad HEAD:refs/patches
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/patches
+```
+
+Now, Alice merges the feature into the `accepted` branch instead of `master`.
+
+``` (stderr)
+$ git checkout accepted
+Switched to branch 'accepted'
+```
+```
+$ git merge feature/1
+Updating [..]
+Fast-forward
+ FEATURE.md | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ [..]..[..] accepted -> accepted
+```
+
+Because the patch was implicitly targeted for `master`, pushing the commit to `accepted` should not mark it as merged. It should remain open.
+
+```
+$ rad patch list --merged
+Nothing to show.
+```
+```
+$ rad patch list --open
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ● [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/crates/radicle-cli/examples/rad-patch-merge-unauthorized-branch.md b/crates/radicle-cli/examples/rad-patch-merge-unauthorized-branch.md
new file mode 100644
index 000000000..0eb420d4c
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-merge-unauthorized-branch.md
@@ -0,0 +1,97 @@
+# Merging patches into an unauthorized branch
+
+First, we update the identity document to add a canonical reference rule for a new `accepted` branch, but we only allow Alice to merge into it.
+
+``` ~alice
+$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": ["did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi"] } }' -q
+[..]
+```
+
+Now, let's create the `accepted` branch and push it:
+
+``` ~alice (stderr)
+$ git checkout -b accepted
+Switched to a new branch 'accepted'
+```
+``` ~alice
+$ git commit --allow-empty -m "Initialize accepted branch"
+[accepted [..]] Initialize accepted branch
+```
+``` ~alice (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+✓ Synced with 1 seed(s)
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new branch] accepted -> accepted
+```
+
+Next, Bob clones the repository and opens a patch targeting `accepted`.
+
+``` ~bob
+$ rad clone rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
+✓ Creating checkout in ./heartwood..
+✓ Remote alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi added
+✓ Remote-tracking branch alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master created for z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+✓ Repository successfully cloned under [..]
+╭────────────────────────────────────╮
+│ heartwood │
+│ Radicle Heartwood Protocol & Stack │
+│ 0 issues · 0 patches │
+╰────────────────────────────────────╯
+Run `cd ./heartwood` to go to the repository directory.
+```
+``` ~bob (stderr)
+$ cd heartwood
+$ git checkout -b feature/1
+Switched to a new branch 'feature/1'
+$ touch FEATURE.md
+$ git add FEATURE.md
+```
+``` ~bob
+$ git commit -m "Add new feature"
+[feature/1 [..]] Add new feature
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` ~bob (stderr)
+$ git push -o patch.message="Add new feature" -o patch.target="refs/heads/accepted" rad HEAD:refs/patches
+✓ Patch [..] opened
+✓ Synced with 1 seed(s)
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
+ * [new reference] HEAD -> refs/patches
+```
+
+Now, Bob tries to merge the feature into the `accepted` branch and push it.
+
+``` ~bob (stderr)
+$ git checkout -t rad/accepted
+Switched to a new branch 'accepted'
+```
+``` ~bob
+$ git merge feature/1
+Merge made by the 'ort' strategy.
+ FEATURE.md | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` ~bob (stderr)
+$ git push rad accepted
+✓ Synced with 1 seed(s)
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
+ * [new branch] accepted -> accepted
+```
+
+Notice that the canonical reference was *not* updated because Bob is not authorized. The patch should remain open.
+
+``` ~bob
+$ rad patch list --merged
+Nothing to show.
+```
+``` ~bob
+$ rad patch list --open
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ● [..] Add new feature bob (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/crates/radicle-cli/examples/rad-patch-merge-wrong-branch.md b/crates/radicle-cli/examples/rad-patch-merge-wrong-branch.md
new file mode 100644
index 000000000..bf3f34f6c
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-merge-wrong-branch.md
@@ -0,0 +1,82 @@
+# Merging patches into the wrong branch
+
+First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+
+```
+$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+[..]
+```
+
+Now, let's create the `accepted` branch and push it:
+
+``` (stderr)
+$ git checkout -b accepted
+Switched to a new branch 'accepted'
+```
+```
+$ git commit --allow-empty -m "Initialize accepted branch"
+[accepted [..]] Initialize accepted branch
+```
+``` (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new branch] accepted -> accepted
+```
+
+Next, we create a feature branch and open a patch targeting `accepted`.
+
+``` (stderr)
+$ git checkout -b feature/1
+Switched to a new branch 'feature/1'
+$ touch FEATURE.md
+$ git add FEATURE.md
+```
+```
+$ git commit -m "Add new feature"
+[feature/1 [..]] Add new feature
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push -o patch.message="Add new feature" -o patch.target="refs/heads/accepted" rad HEAD:refs/patches
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/patches
+```
+
+Now, Alice accidentally merges the feature into the `master` branch instead of `accepted`.
+
+``` (stderr)
+$ git checkout master
+Switched to branch 'master'
+```
+```
+$ git merge feature/1
+Updating [..]
+Fast-forward
+ FEATURE.md | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push rad master
+✓ Canonical reference refs/heads/master updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ [..]..[..] master -> master
+```
+
+Because the patch was explicitly targeted for `accepted`, it should remain open.
+
+```
+$ rad patch list --merged
+Nothing to show.
+```
+```
+$ rad patch list --open
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ● [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/crates/radicle-cli/examples/rad-patch-revert-custom-branch.md b/crates/radicle-cli/examples/rad-patch-revert-custom-branch.md
new file mode 100644
index 000000000..7a1a137f0
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-revert-custom-branch.md
@@ -0,0 +1,108 @@
+# Reverting a patch on a custom canonical branch
+
+First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+
+```
+$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+[..]
+```
+
+Now, let's create the `accepted` branch and push it:
+
+``` (stderr)
+$ git checkout -b accepted
+Switched to a new branch 'accepted'
+```
+```
+$ git commit --allow-empty -m "Initialize accepted branch"
+[accepted [..]] Initialize accepted branch
+```
+``` (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new branch] accepted -> accepted
+```
+
+Next, we create a feature branch and open a patch targeting `accepted`.
+
+``` (stderr)
+$ git checkout -b feature/1
+Switched to a new branch 'feature/1'
+$ touch FEATURE.md
+$ git add FEATURE.md
+```
+```
+$ git commit -m "Add new feature"
+[feature/1 [..]] Add new feature
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push -o patch.message="Add new feature" -o patch.target="refs/heads/accepted" rad HEAD:refs/patches
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/patches
+```
+
+Alice merges the feature into the `accepted` branch and pushes it.
+
+``` (stderr)
+$ git checkout accepted
+Switched to branch 'accepted'
+```
+```
+$ git merge feature/1
+Updating [..]
+Fast-forward
+ FEATURE.md | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push rad accepted
+✓ Patch [..] merged
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ [..]..[..] accepted -> accepted
+```
+
+We verify the patch is merged.
+
+```
+$ rad patch list --merged
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ✓ [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
+
+Now, Alice realizes she made a mistake and resets the `accepted` branch, dropping the merge commit, and force pushes.
+
+```
+$ git reset --hard HEAD~1
+HEAD is now at [..] Initialize accepted branch
+```
+``` (stderr)
+$ git push rad accepted --force
+! Patch [..] reverted at revision [..]
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ + 27acd3b...f9a3b89 accepted -> accepted (forced update)
+```
+
+The patch should now be open again.
+
+```
+$ rad patch list --merged
+Nothing to show.
+```
+```
+$ rad patch list --open
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ● [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/crates/radicle-cli/examples/rad-patch-revert-isolation.md b/crates/radicle-cli/examples/rad-patch-revert-isolation.md
new file mode 100644
index 000000000..3c3191395
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-revert-isolation.md
@@ -0,0 +1,107 @@
+# Revert isolation (Force-pushing the wrong branch)
+
+First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+
+```
+$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+[..]
+```
+
+Now, let's create the `accepted` branch and push it:
+
+``` (stderr)
+$ git checkout -b accepted
+Switched to a new branch 'accepted'
+```
+```
+$ git commit --allow-empty -m "Initialize accepted branch"
+[accepted [..]] Initialize accepted branch
+```
+``` (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new branch] accepted -> accepted
+```
+
+Next, we create a feature branch and open a patch targeting `accepted`.
+
+``` (stderr)
+$ git checkout -b feature/1
+Switched to a new branch 'feature/1'
+$ touch FEATURE.md
+$ git add FEATURE.md
+```
+```
+$ git commit -m "Add new feature"
+[feature/1 [..]] Add new feature
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push -o patch.message="Add new feature" -o patch.target="refs/heads/accepted" rad HEAD:refs/patches
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/patches
+```
+
+Alice merges the feature into the `accepted` branch and pushes it.
+
+``` (stderr)
+$ git checkout accepted
+Switched to branch 'accepted'
+```
+```
+$ git merge feature/1
+Updating [..]
+Fast-forward
+ FEATURE.md | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 FEATURE.md
+```
+``` (stderr)
+$ git push rad accepted
+✓ Patch [..] merged
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ [..]..[..] accepted -> accepted
+```
+
+We verify the patch is merged.
+
+```
+$ rad patch list --merged
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ✓ [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
+
+Now, Alice switches to `master`, resets it to drop a commit, and force pushes. This simulates a scenario where commits are dropped from a branch *other* than the patch's destination.
+
+``` (stderr)
+$ git checkout master
+Switched to branch 'master'
+```
+```
+$ git reset --hard HEAD~1
+HEAD is now at [..] Initial commit
+```
+``` (stderr)
+$ git push rad master --force
+✓ Canonical reference refs/heads/master updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ + f2de534...08c788d master -> master (forced update)
+```
+
+Because the patch was merged into `accepted`, dropping commits on `master` should not revert the patch. It should remain merged.
+
+```
+$ rad patch list --merged
+╭───────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├───────────────────────────────────────────────────────────────────────────────┤
+│ ✓ [..] Add new feature alice (you) - [..] +0 -0 now │
+╰───────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/crates/radicle-cli/tests/commands/patch.rs b/crates/radicle-cli/tests/commands/patch.rs
index 165a3a493..eb58fb5ef 100644
--- a/crates/radicle-cli/tests/commands/patch.rs
+++ b/crates/radicle-cli/tests/commands/patch.rs
@@ -436,3 +436,75 @@ fn rad_patch_merge_on_first_push() {
fn rad_patch_magic_push() {
Environment::alice(["rad-init", "rad-patch-magic-push"]);
}
+
+#[test]
+fn rad_patch_merge_into_canonical_ref_branch() {
+ Environment::alice(["rad-init", "rad-patch-merge-into-canonical-ref-branch"]);
+}
+
+#[test]
+fn rad_patch_merge_default_branch() {
+ Environment::alice(["rad-init", "rad-patch-merge-default-branch"]);
+}
+
+#[test]
+fn rad_patch_merge_wrong_branch() {
+ Environment::alice(["rad-init", "rad-patch-merge-wrong-branch"]);
+}
+
+#[test]
+fn rad_patch_merge_unauthorized_branch() {
+ let mut environment = Environment::new();
+ let alice = environment.node("alice");
+ let bob = environment.node("bob");
+ let acme = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
+
+ environment.repository(&alice);
+
+ test(
+ "examples/rad-init.md",
+ environment.work(&alice),
+ Some(&alice.home),
+ [],
+ )
+ .unwrap();
+
+ let mut alice = alice.spawn();
+ let mut bob = bob.spawn();
+
+ bob.handle.seed(acme, Scope::All).unwrap();
+ alice.connect(&bob).converge([&bob]);
+
+ formula(
+ &environment.tempdir(),
+ "examples/rad-patch-merge-unauthorized-branch.md",
+ )
+ .unwrap()
+ .home(
+ "alice",
+ environment.work(&alice),
+ [("RAD_HOME", alice.home.path().display())],
+ )
+ .home(
+ "bob",
+ environment.work(&bob),
+ [("RAD_HOME", bob.home.path().display())],
+ )
+ .run()
+ .unwrap();
+}
+
+#[test]
+fn rad_patch_revert_custom_branch() {
+ Environment::alice(["rad-init", "rad-patch-revert-custom-branch"]);
+}
+
+#[test]
+fn rad_patch_revert_isolation() {
+ Environment::alice(["rad-init", "rad-patch-revert-isolation"]);
+}
+
+#[test]
+fn rad_patch_merge_strict_destination() {
+ Environment::alice(["rad-init", "rad-patch-merge-strict-destination"]);
+}
commit 3a3cec905ddc50602d8dff10dec27ba4fdb48289
Author: Adrian Duke <adrian.duke@gmail.com>
Date: Tue Jun 2 15:24:43 2026 +0100
radicle-cli/terminal: Add patch target ref to rad patch show
diff --git a/crates/radicle-cli/examples/rad-merge-via-push.md b/crates/radicle-cli/examples/rad-merge-via-push.md
index 5a82f3f94..4dbe4a46d 100644
--- a/crates/radicle-cli/examples/rad-merge-via-push.md
+++ b/crates/radicle-cli/examples/rad-merge-via-push.md
@@ -89,6 +89,7 @@ $ rad patch show 696ec5508494692899337afe6713fe1796d0315c
│ Author alice (you) │
│ Head 20aa5dde6210796c3a2f04079b42316a31d02689 │
│ Base [.. ] │
+│ Target master │
│ Branches feature/1 │
│ Commits ahead 0, behind 2 │
│ Status merged │
@@ -105,6 +106,7 @@ $ rad patch show 356f73863a8920455ff6e77cd9c805d68910551b
│ Author alice (you) │
│ Head daf349ff76bedf48c5f292290b682ee7be0683cf │
│ Base [.. ] │
+│ Target master │
│ Branches feature/2 │
│ Commits ahead 0, behind 2 │
│ Status merged │
diff --git a/crates/radicle-cli/examples/rad-patch-change-base.md b/crates/radicle-cli/examples/rad-patch-change-base.md
index de6c12cc4..e7a55cdf9 100644
--- a/crates/radicle-cli/examples/rad-patch-change-base.md
+++ b/crates/radicle-cli/examples/rad-patch-change-base.md
@@ -50,6 +50,7 @@ $ rad patch show 183d343ab47d7fe18baf1b24b7209ad033d7fe5c
│ Author alice (you) │
│ Head 27857ec9eb04c69cacab516e8bf4b5fd36090f66 │
│ Base f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │
+│ Target master │
│ Branches add-readme │
│ Commits ahead 2, behind 0 │
│ Status open │
@@ -81,6 +82,7 @@ $ rad patch show 183d343
│ Author alice (you) │
│ Head 27857ec9eb04c69cacab516e8bf4b5fd36090f66 │
│ Base 3e674d1a1df90807e934f9ae5da2591dd6848a33 │
+│ Target master │
│ Branches add-readme │
│ Commits ahead 2, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/rad-patch-checkout-revision.md b/crates/radicle-cli/examples/rad-patch-checkout-revision.md
index 4a0e6f351..f045d3abd 100644
--- a/crates/radicle-cli/examples/rad-patch-checkout-revision.md
+++ b/crates/radicle-cli/examples/rad-patch-checkout-revision.md
@@ -21,6 +21,7 @@ $ rad patch show aa45913
│ Author alice (you) │
│ Head 639f44a25145a37f747f3c84265037a9461e44c5 │
│ Base [.. ] │
+│ Target master │
│ Branches patch/aa45913 │
│ Commits ahead 3, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/rad-patch-delete.md b/crates/radicle-cli/examples/rad-patch-delete.md
index c635d8870..47bcecec7 100644
--- a/crates/radicle-cli/examples/rad-patch-delete.md
+++ b/crates/radicle-cli/examples/rad-patch-delete.md
@@ -39,6 +39,7 @@ $ rad patch show 6c61ef1 -v
│ Author alice (you) │
│ Head 717c900ec17735639587325e0fd9fe09991c9edd │
│ Base f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │
+│ Target refs/heads/master │
│ Branches prepare-license │
│ Commits ahead 1, behind 0 │
│ Status draft │
@@ -90,6 +91,7 @@ $ rad patch show 6c61ef1 -v
│ Author alice z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │
│ Head 1cc8cd9de8ccc44b4fe3876f2dbd2cd1cf9ddc0e │
│ Base f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │
+│ Target refs/heads/master │
│ Commits ahead 2, behind 0 │
│ Status draft │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
@@ -115,6 +117,7 @@ $ rad patch show 6c61ef1 -v
│ Author alice (you) │
│ Head 1cc8cd9de8ccc44b4fe3876f2dbd2cd1cf9ddc0e │
│ Base f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 │
+│ Target refs/heads/master │
│ Branches prepare-license │
│ Commits ahead 2, behind 0 │
│ Status draft │
diff --git a/crates/radicle-cli/examples/rad-patch-draft.md b/crates/radicle-cli/examples/rad-patch-draft.md
index 2ce5200fa..adc502ec8 100644
--- a/crates/radicle-cli/examples/rad-patch-draft.md
+++ b/crates/radicle-cli/examples/rad-patch-draft.md
@@ -24,6 +24,7 @@ $ rad patch show 97e18f8598237a396a1c0ac1509c89028e666c97
│ Author alice (you) │
│ Head 2a465832b5a76abe25be44a3a5d224bbd7741ba7 │
│ Base [.. ] │
+│ Target master │
│ Branches cloudhead/draft │
│ Commits ahead 1, behind 0 │
│ Status draft │
@@ -48,6 +49,7 @@ $ rad patch show 97e18f8598237a396a1c0ac1509c89028e666c97
│ Author alice (you) │
│ Head 2a465832b5a76abe25be44a3a5d224bbd7741ba7 │
│ Base [.. ] │
+│ Target master │
│ Branches cloudhead/draft │
│ Commits ahead 1, behind 0 │
│ Status open │
@@ -70,6 +72,7 @@ $ rad patch show 97e18f8598237a396a1c0ac1509c89028e666c97
│ Author alice (you) │
│ Head 2a465832b5a76abe25be44a3a5d224bbd7741ba7 │
│ Base [.. ] │
+│ Target master │
│ Branches cloudhead/draft │
│ Commits ahead 1, behind 0 │
│ Status draft │
diff --git a/crates/radicle-cli/examples/rad-patch-edit.md b/crates/radicle-cli/examples/rad-patch-edit.md
index 9250ed774..a2cd09d3d 100644
--- a/crates/radicle-cli/examples/rad-patch-edit.md
+++ b/crates/radicle-cli/examples/rad-patch-edit.md
@@ -51,6 +51,7 @@ $ rad patch show 89f7afb
│ Author alice (you) │
│ Head 8945f6189adf027892c85ac57f7e9341049c2537 │
│ Base [.. ] │
+│ Target master │
│ Branches changes │
│ Commits ahead 2, behind 0 │
│ Status open │
@@ -75,6 +76,7 @@ $ rad patch show 89f7afb
│ Author alice (you) │
│ Head 8945f6189adf027892c85ac57f7e9341049c2537 │
│ Base [.. ] │
+│ Target master │
│ Branches changes │
│ Commits ahead 2, behind 0 │
│ Status open │
@@ -104,6 +106,7 @@ $ rad patch show 89f7afb
│ Author alice (you) │
│ Head 8945f6189adf027892c85ac57f7e9341049c2537 │
│ Base [.. ] │
+│ Target master │
│ Branches changes │
│ Commits ahead 2, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/rad-patch-magic-push.md b/crates/radicle-cli/examples/rad-patch-magic-push.md
index 3e50afe32..b4c9ed2bc 100644
--- a/crates/radicle-cli/examples/rad-patch-magic-push.md
+++ b/crates/radicle-cli/examples/rad-patch-magic-push.md
@@ -52,6 +52,7 @@ $ rad patch show 01dad54
│ Author alice (you) │
│ Head 46fd342edc149468ec08b0b25291083aa05d4449 │
│ Base [.. ] │
+│ Target accepted │
│ Branches feature/1 │
│ Commits ahead 1, behind 0 │
│ Status open │
@@ -102,6 +103,7 @@ $ rad patch show 01dad54
│ Author alice (you) │
│ Head 46fd342edc149468ec08b0b25291083aa05d4449 │
│ Base [.. ] │
+│ Target accepted │
│ Branches accepted, feature/1 │
│ Commits up to date │
│ Status merged │
diff --git a/crates/radicle-cli/examples/rad-patch-pull-update.md b/crates/radicle-cli/examples/rad-patch-pull-update.md
index c1cb08baf..8b562488d 100644
--- a/crates/radicle-cli/examples/rad-patch-pull-update.md
+++ b/crates/radicle-cli/examples/rad-patch-pull-update.md
@@ -103,6 +103,7 @@ $ rad patch show 55b9721
│ Author bob z6Mkt67…v4N1tRk │
│ Head cad2666a8a2250e4dee175ed5044be2c251ff08b │
│ Base [.. ] │
+│ Target master │
│ Commits ahead 2, behind 0 │
│ Status open │
├──────────────────────────────────────────────────────────────────┤
diff --git a/crates/radicle-cli/examples/rad-patch-revert-merge.md b/crates/radicle-cli/examples/rad-patch-revert-merge.md
index de89f91ef..a0c58d070 100644
--- a/crates/radicle-cli/examples/rad-patch-revert-merge.md
+++ b/crates/radicle-cli/examples/rad-patch-revert-merge.md
@@ -27,6 +27,7 @@ $ rad patch show 696ec5508494692899337afe6713fe1796d0315c
│ Author alice (you) │
│ Head 20aa5dde6210796c3a2f04079b42316a31d02689 │
│ Base [.. ] │
+│ Target master │
│ Branches feature/1, master │
│ Commits up to date │
│ Status merged │
@@ -66,6 +67,7 @@ $ rad patch show 696ec5508494692899337afe6713fe1796d0315c
│ Author alice (you) │
│ Head 20aa5dde6210796c3a2f04079b42316a31d02689 │
│ Base [.. ] │
+│ Target master │
│ Branches feature/1 │
│ Commits ahead 1, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/rad-patch-update.md b/crates/radicle-cli/examples/rad-patch-update.md
index db7682661..67934e0ba 100644
--- a/crates/radicle-cli/examples/rad-patch-update.md
+++ b/crates/radicle-cli/examples/rad-patch-update.md
@@ -19,6 +19,7 @@ $ rad patch show b6a23eb08656de0ef1fcc0b5fe8820841e5cb2e5
│ Author alice (you) │
│ Head 51b2f0f77b9849bfaa3e9d3ff68ee2f57771d20c │
│ Base [.. ] │
+│ Target master │
│ Branches feature/1 │
│ Commits ahead 1, behind 0 │
│ Status open │
@@ -61,6 +62,7 @@ $ rad patch show b6a23eb08656de0ef1fcc0b5fe8820841e5cb2e5
│ Author alice (you) │
│ Head 4d272148458a17620541555b1f0905c01658aa9f │
│ Base [.. ] │
+│ Target master │
│ Branches feature/1 │
│ Commits ahead 2, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/rad-patch-via-push.md b/crates/radicle-cli/examples/rad-patch-via-push.md
index 73b16427b..707da3367 100644
--- a/crates/radicle-cli/examples/rad-patch-via-push.md
+++ b/crates/radicle-cli/examples/rad-patch-via-push.md
@@ -26,6 +26,7 @@ $ rad patch show 6035d2f582afbe01ff23ea87528ae523d76875b6
│ Author alice (you) │
│ Head 42d894a83c9c356552a57af09ccdbd5587a99045 │
│ Base [.. ] │
+│ Target master │
│ Branches feature/1 │
│ Commits ahead 1, behind 0 │
│ Status open │
@@ -144,6 +145,7 @@ $ rad patch show 9580891
│ Author alice (you) │
│ Head 02bef3fac41b2f98bb3c02b868a53ddfecb55b5f │
│ Base [.. ] │
+│ Target master │
│ Branches feature/2 │
│ Commits ahead 2, behind 0 │
│ Status open │
@@ -225,6 +227,7 @@ $ rad patch show 9580891
│ Author alice (you) │
│ Head 9304dbc445925187994a7a93222a3f8bde73b785 │
│ Base [.. ] │
+│ Target master │
│ Branches feature/2 │
│ Commits ahead 2, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/rad-patch.md b/crates/radicle-cli/examples/rad-patch.md
index 3e5c52e3c..17ca94e6b 100644
--- a/crates/radicle-cli/examples/rad-patch.md
+++ b/crates/radicle-cli/examples/rad-patch.md
@@ -49,6 +49,7 @@ $ rad patch show aa45913e757cacd46972733bddee5472c78fa32a -p
│ Author alice (you) │
│ Head 3e674d1a1df90807e934f9ae5da2591dd6848a33 │
│ Base [.. ] │
+│ Target master │
│ Branches flux-capacitor-power │
│ Commits ahead 1, behind 0 │
│ Status open │
@@ -104,6 +105,7 @@ $ rad patch show aa45913
│ Labels fun │
│ Head 3e674d1a1df90807e934f9ae5da2591dd6848a33 │
│ Base [.. ] │
+│ Target master │
│ Branches flux-capacitor-power │
│ Commits ahead 1, behind 0 │
│ Status open │
@@ -192,6 +194,7 @@ $ rad patch show aa45913
│ Labels fun │
│ Head 27857ec9eb04c69cacab516e8bf4b5fd36090f66 │
│ Base [.. ] │
+│ Target master │
│ Branches flux-capacitor-power, patch/aa45913 │
│ Commits ahead 2, behind 0 │
│ Status open │
@@ -225,6 +228,7 @@ $ rad patch show aa45913
│ Labels fun │
│ Head 27857ec9eb04c69cacab516e8bf4b5fd36090f66 │
│ Base [.. ] │
+│ Target master │
│ Branches flux-capacitor-power, patch/aa45913 │
│ Commits ahead 2, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/workflow/4-patching-contributor.md b/crates/radicle-cli/examples/workflow/4-patching-contributor.md
index c9038e308..e86e45744 100644
--- a/crates/radicle-cli/examples/workflow/4-patching-contributor.md
+++ b/crates/radicle-cli/examples/workflow/4-patching-contributor.md
@@ -47,6 +47,7 @@ $ rad patch show e4934b6d9dbe01ce3c7fbb5b77a80d5f1dacdc46
│ Author bob (you) │
│ Head 3e674d1a1df90807e934f9ae5da2591dd6848a33 │
│ Base [.. ] │
+│ Target master │
│ Branches flux-capacitor-power │
│ Commits ahead 1, behind 0 │
│ Status open │
diff --git a/crates/radicle-cli/examples/workflow/5-patching-maintainer.md b/crates/radicle-cli/examples/workflow/5-patching-maintainer.md
index 2517cf36b..a459df026 100644
--- a/crates/radicle-cli/examples/workflow/5-patching-maintainer.md
+++ b/crates/radicle-cli/examples/workflow/5-patching-maintainer.md
@@ -34,6 +34,7 @@ $ rad patch show e4934b6
│ Author bob z6Mkt67…v4N1tRk │
│ Head 27857ec9eb04c69cacab516e8bf4b5fd36090f66 │
│ Base [.. ] │
+│ Target master │
│ Commits ahead 2, behind 0 │
│ Status open │
│ │
@@ -109,6 +110,7 @@ $ rad patch show e4934b6
│ Author bob z6Mkt67…v4N1tRk │
│ Head 27857ec9eb04c69cacab516e8bf4b5fd36090f66 │
│ Base [.. ] │
+│ Target master │
│ Commits ahead 0, behind 1 │
│ Status merged │
│ │
diff --git a/crates/radicle-cli/src/terminal/patch.rs b/crates/radicle-cli/src/terminal/patch.rs
index 8472accc5..b8d976b2c 100644
--- a/crates/radicle-cli/src/terminal/patch.rs
+++ b/crates/radicle-cli/src/terminal/patch.rs
@@ -14,8 +14,8 @@ use radicle::cob::patch;
use radicle::git;
use radicle::patch::{Patch, PatchId};
use radicle::prelude::Profile;
-use radicle::storage::WriteRepository as _;
use radicle::storage::git::Repository;
+use radicle::storage::{ReadRepository, WriteRepository as _};
use crate::terminal as term;
use crate::terminal::Element;
@@ -373,6 +373,18 @@ pub fn show(
let author = term::format::Author::new(author.id(), profile, verbose);
let labels = patch.labels().map(|l| l.to_string()).collect::<Vec<_>>();
+ let doc = stored.identity_doc()?;
+ let target = patch.merge_target_branch(&doc)?;
+ let target_branch = if verbose {
+ target.to_string()
+ } else {
+ target
+ .as_str()
+ .strip_prefix("refs/heads/")
+ .unwrap_or(target.as_str())
+ .to_string()
+ };
+
let mut attrs = term::Table::<2, term::Line>::new(term::TableOptions {
spacing: 2,
..term::TableOptions::default()
@@ -403,6 +415,10 @@ pub fn show(
term::format::tertiary("Base".to_owned()).into(),
term::format::secondary(revision.base().to_string()).into(),
]);
+ attrs.push([
+ term::format::tertiary("Target".to_owned()).into(),
+ term::format::secondary(target_branch).into(),
+ ]);
if !branches.is_empty() {
attrs.push([
term::format::tertiary("Branches".to_owned()).into(),
commit 23519ce5bddfd8a038db9e2c21e8af4ef42d206e
Author: Adrian Duke <adrian.duke@gmail.com>
Date: Tue May 19 16:30:43 2026 +0100
radicle: Add magic push prefix to changelog
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d835a5a1..da36e1d00 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -71,6 +71,11 @@ COB type names and payload IDs remain unchanged for backwards compatibility.
Furthermore, strict merge and revert isolation is now enforced: patches are
only marked as merged or reverted if the commits are pushed to the target
branch of the patch explicitly.
+- Additionally a magic push reference has been introduced to shortcut the usage
+ of the aforementioned push option `patch.target`. `refs/for/<branch>` can be
+ used to set the `patch.target` when used as a push target e.g.
+ `git push rad HEAD:refs/for/backport`. This will use the `refs/heads/backport`
+ canonical reference as its `patch.target` in place of using the push option.
- Teach `rad patch show` to show the full commit range for each revision.
Previously, it would only show the head of the range, but not the base.
It now shows `<base>..<head>`, where the shortened OID is used when not
commit 688ba43adb10f924c290304f0fe54008caa8611a
Author: Adrian Duke <adrian.duke@gmail.com>
Date: Tue May 19 15:51:32 2026 +0100
remote-helper: Introduce magic push ref 'refs/for/'
Introduces support for Gerrit-style magic push references via
`refs/for/<branch>`. Pushing to this ref automatically extracts the
target branch and opens a patch against it, bypassing the need for the
push option `patch.target`. Example:
```
$ git push rad HEAD:refs/for/accepted
```
Will open a patch with its `patch.target` set to `refs/heads/accepted`.
diff --git a/crates/radicle-cli/examples/rad-patch-magic-push.md b/crates/radicle-cli/examples/rad-patch-magic-push.md
new file mode 100644
index 000000000..3e50afe32
--- /dev/null
+++ b/crates/radicle-cli/examples/rad-patch-magic-push.md
@@ -0,0 +1,145 @@
+# Magic Push Reference
+
+First, we update the identity document to add a canonical reference rule for a new `accepted` branch, allowing delegates to merge into it.
+
+```
+$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+[..]
+```
+
+Now, let's create the `accepted` branch and push it to the repository so it becomes a tracked canonical reference:
+
+``` (stderr)
+$ git checkout -b accepted
+Switched to a new branch 'accepted'
+```
+
+```
+$ git commit --allow-empty -m "Initialize accepted branch"
+[accepted [..]] Initialize accepted branch
+```
+
+``` (stderr)
+$ git push rad accepted
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new branch] accepted -> accepted
+```
+
+We can then use the magic push reference `refs/for/<branch>` to open a patch targeting a specific branch without needing to use push options.
+
+```
+$ git checkout -b feature/1 -q
+$ git commit -m "Add new feature" --allow-empty -q
+```
+
+Pushing to the magic reference:
+
+``` (stderr)
+$ git push rad HEAD:refs/for/accepted
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/for/accepted
+```
+
+We can see the patch is open:
+
+```
+$ rad patch show 01dad54
+╭──────────────────────────────────────────────────────────╮
+│ Title Initialize accepted branch │
+│ Patch 01dad54873ada4efa61541e7d90702266d5ced89 │
+│ Author alice (you) │
+│ Head 46fd342edc149468ec08b0b25291083aa05d4449 │
+│ Base [.. ] │
+│ Branches feature/1 │
+│ Commits ahead 1, behind 0 │
+│ Status open │
+│ │
+│ Add new feature │
+├──────────────────────────────────────────────────────────┤
+│ 46fd342 Add new feature │
+│ f9a3b89 Initialize accepted branch │
+├──────────────────────────────────────────────────────────┤
+│ ● Revision 01dad54 @ f2de534..46fd342 by alice (you) now │
+╰──────────────────────────────────────────────────────────╯
+$ rad patch list --open
+╭──────────────────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├──────────────────────────────────────────────────────────────────────────────────────────┤
+│ ● [.. ] Initialize accepted branch alice (you) - [.. ] +0 -0 now │
+╰──────────────────────────────────────────────────────────────────────────────────────────╯
+```
+
+Now we merge the feature into the `accepted` branch:
+
+``` (stderr)
+$ git checkout accepted
+Switched to branch 'accepted'
+```
+
+```
+$ git merge feature/1
+Updating [..]
+Fast-forward
+```
+
+``` (stderr)
+$ git push rad accepted
+✓ Patch [..] merged
+✓ Canonical reference refs/heads/accepted updated to target commit [..]
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ [..]..[..] accepted -> accepted
+```
+
+We can now verify that the patch has been successfully marked as merged:
+
+```
+$ rad patch show 01dad54
+╭──────────────────────────────────────────────────────────╮
+│ Title Initialize accepted branch │
+│ Patch 01dad54873ada4efa61541e7d90702266d5ced89 │
+│ Author alice (you) │
+│ Head 46fd342edc149468ec08b0b25291083aa05d4449 │
+│ Base [.. ] │
+│ Branches accepted, feature/1 │
+│ Commits up to date │
+│ Status merged │
+│ │
+│ Add new feature │
+├──────────────────────────────────────────────────────────┤
+│ 46fd342 Add new feature │
+│ f9a3b89 Initialize accepted branch │
+├──────────────────────────────────────────────────────────┤
+│ ● Revision 01dad54 @ f2de534..46fd342 by alice (you) now │
+│ └─ ✓ merged by alice (you) │
+╰──────────────────────────────────────────────────────────╯
+$ rad patch list --merged
+╭──────────────────────────────────────────────────────────────────────────────────────────╮
+│ ● ID Title Author Reviews Head + - Updated │
+├──────────────────────────────────────────────────────────────────────────────────────────┤
+│ ✓ [.. ] Initialize accepted branch alice (you) - [.. ] +0 -0 now │
+╰──────────────────────────────────────────────────────────────────────────────────────────╯
+```
+
+Alternative, attempting to provide conflicting targets fails:
+
+``` (fail) (stderr)
+$ git push -o patch.target=master rad HEAD:refs/for/accepted
+error: conflicting merge targets: push option 'refs/heads/master' and magic ref 'refs/heads/accepted' specified
+error: failed to push some refs to 'rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi'
+```
+
+However, if the push option and the magic ref match, it succeeds:
+
+```
+$ git checkout -b feature/2 -q
+$ git commit -m "Add another feature" --allow-empty -q
+```
+
+``` (stderr)
+$ git push -o patch.target=accepted rad HEAD:refs/for/accepted
+✓ Patch [..] opened
+To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+ * [new reference] HEAD -> refs/for/accepted
+```
diff --git a/crates/radicle-cli/tests/commands/patch.rs b/crates/radicle-cli/tests/commands/patch.rs
index f6125aa16..165a3a493 100644
--- a/crates/radicle-cli/tests/commands/patch.rs
+++ b/crates/radicle-cli/tests/commands/patch.rs
@@ -431,3 +431,8 @@ fn rad_patch_merge_on_first_push() {
.run()
.unwrap();
}
+
+#[test]
+fn rad_patch_magic_push() {
+ Environment::alice(["rad-init", "rad-patch-magic-push"]);
+}
diff --git a/crates/radicle-remote-helper/src/push.rs b/crates/radicle-remote-helper/src/push.rs
index fd825311d..2efac2d57 100644
--- a/crates/radicle-remote-helper/src/push.rs
+++ b/crates/radicle-remote-helper/src/push.rs
@@ -31,6 +31,8 @@ use crate::service::GitService;
use crate::service::NodeSession;
use crate::{Options, Verbosity, hint, warn};
+const PATCHES_FOR_PREFIX: &str = "refs/for/";
+
#[derive(Debug, Error)]
pub(super) enum Error {
/// Public key doesn't match the remote namespace we're pushing to.
@@ -114,6 +116,9 @@ pub(super) enum Error {
UnknownObjectType { oid: git::Oid },
#[error(transparent)]
FindObjects(#[from] git::canonical::error::FindObjectsError),
+ /// Conflicting merge targets.
+ #[error("conflicting merge targets: push option '{0}' and magic ref '{1}' specified")]
+ ConflictingTargets(cob::patch::TargetBranch, cob::patch::TargetBranch),
/// Default branch error.
#[error(transparent)]
DefaultBranch(#[from] radicle::identity::doc::DefaultBranchError),
@@ -212,7 +217,9 @@ impl Command {
}
enum PushAction {
- OpenPatch,
+ OpenPatch {
+ target: Option<cob::patch::TargetBranch>,
+ },
UpdatePatch {
dst: git::fmt::Qualified<'static>,
patch: patch::PatchId,
@@ -225,7 +232,17 @@ enum PushAction {
impl PushAction {
fn new(dst: &git::fmt::RefString) -> Result<Self, error::PushAction> {
if dst == &*rad::PATCHES_REFNAME {
- Ok(Self::OpenPatch)
+ Ok(Self::OpenPatch { target: None })
+ } else if let Some(stripped) = dst.as_str().strip_prefix(PATCHES_FOR_PREFIX) {
+ let target = cob::patch::TargetBranch::try_from(stripped).map_err(|_| {
+ error::PushAction::InvalidRef {
+ refname: dst.clone(),
+ }
+ })?;
+
+ Ok(Self::OpenPatch {
+ target: Some(target),
+ })
} else {
let dst = git::fmt::Qualified::from_refstr(dst)
.ok_or_else(|| error::PushAction::InvalidRef {
@@ -326,17 +343,24 @@ pub(super) fn run(
let action = PushAction::new(dst)?;
match action {
- PushAction::OpenPatch => patch_open(
- src,
- &remote,
- &nid,
- &working,
- stored,
- patches,
- profile,
- opts.clone(),
- git,
- ),
+ PushAction::OpenPatch { target } => {
+ let mut push_opts = opts.clone();
+ if let Some(magic_target) = target {
+ if let cob::patch::MergeTarget::Branch(opt_target) = &opts.target
+ && magic_target != *opt_target
+ {
+ return Err(Error::ConflictingTargets(
+ opt_target.clone(),
+ magic_target,
+ ));
+ }
+ push_opts.target = cob::patch::MergeTarget::Branch(magic_target);
+ }
+
+ patch_open(
+ src, &remote, &nid, &working, stored, patches, profile, push_opts, git,
+ )
+ }
PushAction::UpdatePatch { dst, patch } => patch_update(
src,
&dst,
commit eec61e4a9ee956aeac151762133cf6df69856dc4
Author: Adrian Duke <adrian.duke@gmail.com>
Date: Tue May 12 13:36:06 2026 +0100
remote-helper: Add 'patch.target' push option
The remote helper now supports the push option `patch.target`. This
allows users to explicitly specify a target canonical reference when
opening or updating a patch. For example, to open a patch that targets
the branch "backport", use:
```
git push -o patch.target=refs/heads/backport
```
Furthermore, strict merge and revert isolation is now enforced:
patches are only marked as merged or reverted if the commits are
pushed to the target branch of the patch explicitly.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 745729d12..5d835a5a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -64,6 +64,13 @@ COB type names and payload IDs remain unchanged for backwards compatibility.
## New Features
+- The remote helper (`git-remote-rad`) now supports the push option
+ `patch.target`. This allows users to explicitly specify a target canonical
+ reference when opening or updating a patch. For example, to open a patch that
+ targets the branch "backport", use `git push -o patch.target=refs/heads/backport`.
+ Furthermore, strict merge and revert isolation is now enforced: patches are
+ only marked as merged or reverted if the commits are pushed to the target
+ branch of the patch explicitly.
- Teach `rad patch show` to show the full commit range for each revision.
Previously, it would only show the head of the range, but not the base.
It now shows `<base>..<head>`, where the shortened OID is used when not
diff --git a/crates/radicle-remote-helper/src/main.rs b/crates/radicle-remote-helper/src/main.rs
index e3c14b215..5fc451959 100644
--- a/crates/radicle-remote-helper/src/main.rs
+++ b/crates/radicle-remote-helper/src/main.rs
@@ -207,6 +207,8 @@ struct Options {
message: cli::patch::Message,
/// Create a branch and set its upstream when opening a patch.
branch: Branch,
+ /// Patch target to use, when opening or updating a patch.
+ target: cob::patch::MergeTarget,
verbosity: Verbosity,
}
@@ -439,6 +441,12 @@ fn push_option(args: &[&str], opts: &mut Options) -> Result<(), Error> {
"patch.branch" => {
opts.branch = Branch::Provided(git::fmt::RefString::try_from(val)?)
}
+ "patch.target" => {
+ let target = val.parse::<cob::patch::TargetBranch>().map_err(|e| {
+ Error::UnsupportedPushOption(format!("invalid patch.target '{val}': {e}"))
+ })?;
+ opts.target = cob::patch::MergeTarget::Branch(target);
+ }
other => {
return Err(Error::UnsupportedPushOption(other.to_owned()));
}
diff --git a/crates/radicle-remote-helper/src/push.rs b/crates/radicle-remote-helper/src/push.rs
index 61c1f9017..fd825311d 100644
--- a/crates/radicle-remote-helper/src/push.rs
+++ b/crates/radicle-remote-helper/src/push.rs
@@ -11,7 +11,6 @@ use std::{assert_eq, io};
use radicle::cob::store::access::WriteAs;
use thiserror::Error;
-use radicle::Profile;
use radicle::cob;
use radicle::cob::object::ParseObjectId;
use radicle::cob::patch;
@@ -24,6 +23,7 @@ use radicle::node::NodeId;
use radicle::storage;
use radicle::storage::git::transport::local::Url;
use radicle::storage::{ReadRepository, SignRepository as _, WriteRepository};
+use radicle::{Profile, identity};
use radicle::{git, rad};
use radicle_cli::terminal as term;
@@ -114,6 +114,9 @@ pub(super) enum Error {
UnknownObjectType { oid: git::Oid },
#[error(transparent)]
FindObjects(#[from] git::canonical::error::FindObjectsError),
+ /// Default branch error.
+ #[error(transparent)]
+ DefaultBranch(#[from] radicle::identity::doc::DefaultBranchError),
/// Error sending pack from the working copy to storage.
#[error(
@@ -579,23 +582,9 @@ where
term::patch::get_create_message(opts.message, &stored.backend, &base.into(), &head.into())?;
let patch = if opts.draft {
- patches.draft(
- title,
- &description,
- patch::MergeTarget::default(),
- base,
- *head,
- &[],
- )
+ patches.draft(title, &description, opts.target.clone(), base, *head, &[])
} else {
- patches.create(
- title,
- &description,
- patch::MergeTarget::default(),
- base,
- *head,
- &[],
- )
+ patches.create(title, &description, opts.target.clone(), base, *head, &[])
}?;
let action = if patch.is_draft() {
@@ -799,42 +788,47 @@ where
Signer: crypto::signature::Verifier<crypto::Signature>,
{
let head = *src;
- let dst = dst.with_namespace(nid.into());
+ let namespaced_dst = dst.with_namespace(nid.into());
+
+ let old = {
+ // In some rare cases, pushing to the default branch is a new action for a delegate.
+ // If this is the case, use the canonical head before the push to determine the old side.
+ //
+ // Note that this is only important for reverting and merging, but must happen before the push.
+ let old = stored
+ .backend
+ .find_reference(namespaced_dst.as_str())
+ .ok()
+ .map(|old| old.peel_to_commit().map(|c| c.id().into()))
+ .transpose()?
+ .or_else(|| stored.canonical_head().map(|(_, oid)| oid).ok());
- // In some rare cases, pushing to the default branch is a new action for a delegate.
- // If this is the case, use the canonical head before the push to determine the old side.
- //
- // Note that this is only important for reverting and merging, but must happen before the push.
- let old = stored
- .backend
- .find_reference(dst.as_str())
- .ok()
- .map(|old| old.peel_to_commit().map(|c| c.id().into()))
- .transpose()?
- .or_else(|| stored.canonical_head().map(|(_, oid)| oid).ok());
+ push_ref(
+ src,
+ &namespaced_dst,
+ force,
+ stored.raw(),
+ verbosity,
+ expected_refs,
+ git,
+ )?;
- push_ref(
- src,
- &dst,
- force,
- stored.raw(),
- verbosity,
- expected_refs,
- git,
- )?;
+ old
+ };
if let Some(old) = old {
- let proj = stored.project()?;
- let master = &*git::fmt::Qualified::from(git::fmt::lit::refs_heads(proj.default_branch()));
+ let identity = stored.identity()?;
+ let crefs = identity.doc().canonical_refs()?;
+ let rules = crefs.rules();
+ let me = Did::from(nid);
- // If we're pushing to the project's default branch, we want to see if any patches got
+ // If we're pushing to a valid canonical branch, we want to see if any patches got
// merged or reverted, and if so, update the patch COB.
- if &*dst.strip_namespace() == master {
- // Only delegates affect the merge state of the COB.
- if stored.delegates()?.contains(&nid.into()) {
- patch_revert_all(old, head, &stored.backend, &mut patches)?;
- patch_merge_all(old, head, working, &mut patches, signer)?;
- }
+ if let Some((_, rule)) = rules.matches(dst).next()
+ && rule.allowed().contains(&me)
+ {
+ patch_revert_all(old, head, dst, &stored.backend, &mut patches, &identity)?;
+ patch_merge_all(old, head, dst, working, &mut patches, signer, &identity)?;
}
}
Ok(Some(ExplorerResource::Tree { oid: head }))
@@ -844,6 +838,7 @@ where
fn patch_revert_all<Signer>(
old: git::Oid,
new: git::Oid,
+ pushed_dst: &git::fmt::Qualified,
stored: &git::raw::Repository,
patches: &mut patch::Cache<
'_,
@@ -851,6 +846,7 @@ fn patch_revert_all<Signer>(
WriteAs<'_, Signer>,
cob::cache::StoreWriter,
>,
+ identity: &radicle::identity::Identity,
) -> Result<(), Error>
where
Signer: crypto::signature::Keypair<VerifyingKey = crypto::PublicKey>,
@@ -869,11 +865,15 @@ where
return Ok(());
}
+ let identity_doc = identity.doc();
+
// Get the list of merged patches.
let merged = patches
.merged()?
// Skip patches that failed to load.
.filter_map(|patch| patch.ok())
+ // Only consider patches that target the destination branch
+ .filter(|(id, patch)| merge_targets_match(pushed_dst, identity_doc, id, patch))
.collect::<Vec<_>>();
for (id, patch) in merged {
@@ -907,10 +907,25 @@ where
Ok(())
}
+fn merge_targets_match(
+ pushed_target: &git::fmt::Qualified,
+ doc: &identity::Doc,
+ id: &patch::PatchId,
+ patch: &patch::Patch,
+) -> bool {
+ patch
+ .is_targeted_by(doc, pushed_target)
+ .unwrap_or_else(|e| {
+ log::warn!("Failed to resolve merge target for patch {}: {}", id, e);
+ false
+ })
+}
+
/// Merge all patches that have been included in the base branch.
fn patch_merge_all<Signer>(
old: git::Oid,
new: git::Oid,
+ pushed_dst: &git::fmt::Qualified,
working: &git::raw::Repository,
patches: &mut patch::Cache<
'_,
@@ -919,6 +934,7 @@ fn patch_merge_all<Signer>(
cob::cache::StoreWriter,
>,
signer: &Signer,
+ identity: &radicle::identity::Identity,
) -> Result<(), Error>
where
Signer: crypto::signature::Keypair<VerifyingKey = crypto::PublicKey>,
@@ -937,12 +953,17 @@ where
return Ok(());
}
+ let identity_doc = identity.doc();
+
let open = patches
.opened()?
.chain(patches.drafted()?)
// Skip patches that failed to load.
.filter_map(|patch| patch.ok())
+ // Only consider patches that target the destination branch
+ .filter(|(id, patch)| merge_targets_match(pushed_dst, identity_doc, id, patch))
.collect::<Vec<_>>();
+
for (id, patch) in open {
// Later revisions are more likely to be merged, so we build the list backwards.
let revisions = patch
commit 807d84712ac96215ef15fcd15cde25f3fe763671
Author: Adrian Duke <adrian.duke@gmail.com>
Date: Tue May 12 13:36:06 2026 +0100
radicle/cob/patch: Extend MergeTarget
Extend `enum MergeTarget` to include a new variant, `Branch`.
The intended use of this new variant is to allow a `Patch` to have a
target branch other than the default branch.
The `Branch` variant holds a `TargetBranch` which, in turn, is ensured
to be a `Qualified` reference that begins with `refs/heads`, i.e. a
Git branch.
diff --git a/crates/radicle-cli/src/commands/patch/edit.rs b/crates/radicle-cli/src/commands/patch/edit.rs
index ccaa32ed7..5f495195d 100644
--- a/crates/radicle-cli/src/commands/patch/edit.rs
+++ b/crates/radicle-cli/src/commands/patch/edit.rs
@@ -57,7 +57,7 @@ where
}
let (root, _) = patch.root();
- let target = patch.target();
+ let target = patch.target().clone();
let embeds = patch.embeds().to_owned();
patch.transaction("Edit root", |tx| {
diff --git a/crates/radicle/CHANGELOG.md b/crates/radicle/CHANGELOG.md
index 08b1bb126..667a71df2 100644
--- a/crates/radicle/CHANGELOG.md
+++ b/crates/radicle/CHANGELOG.md
@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- Introduce a new variant to `radicle::cob::patch::MergeTarget`, `Branch`.
+ The `Branch` variant holds a `TargetBranch`, which must either be a qualified
+ `refs/heads` reference, or a references not beginning with `refs`; as a
+ `refs/heads` will then be prepended to it.
+
### Changed
### Removed
diff --git a/crates/radicle/src/cob/patch.rs b/crates/radicle/src/cob/patch.rs
index aef44798f..62f78fcf0 100644
--- a/crates/radicle/src/cob/patch.rs
+++ b/crates/radicle/src/cob/patch.rs
@@ -30,9 +30,10 @@ use crate::cob::{ActorId, Embed, EntryId, ObjectId, TypeName, Uri, op, store};
use crate::crypto::PublicKey;
use crate::git;
use crate::identity::PayloadError;
-use crate::identity::doc::{DocAt, DocError};
+use crate::identity::doc::{DefaultBranchError, DocAt, DocError};
use crate::prelude::*;
use crate::storage;
+use crate::storage::git::Repository;
pub use cache::Cache;
@@ -119,6 +120,10 @@ pub enum Error {
/// Identity document is missing.
#[error("missing identity document")]
MissingIdentity,
+ #[error(transparent)]
+ DefaultBranch(#[from] DefaultBranchError),
+ #[error(transparent)]
+ TargetBranch(#[from] TargetBranchError),
/// Review is empty.
#[error("empty review; verdict or summary not provided")]
EmptyReview,
@@ -398,8 +403,91 @@ impl<R: WriteRepository> Merged<'_, R> {
}
}
+/// A valid target branch for a [`Patch`].
+///
+/// The construction of a [`TargetBranch`] ensures that the reference is a Git
+/// branch, i.e. the reference name begins with `refs/heads`.
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
+#[serde(try_from = "git::fmt::RefString", into = "git::fmt::RefString")]
+pub struct TargetBranch(git::fmt::Qualified<'static>);
+
+#[derive(Debug, Error)]
+pub enum TargetBranchError {
+ /// Invalid merge target.
+ #[error("invalid merge target '{0}': must be a branch")]
+ InvalidMergeTarget(git::fmt::RefString),
+ /// Invalid reference format.
+ #[error(transparent)]
+ InvalidReference(#[from] git::fmt::Error),
+}
+
+impl TryFrom<git::fmt::RefString> for TargetBranch {
+ type Error = TargetBranchError;
+
+ fn try_from(refname: git::fmt::RefString) -> Result<Self, Self::Error> {
+ Self::new(refname)
+ }
+}
+
+impl From<TargetBranch> for git::fmt::RefString {
+ fn from(tb: TargetBranch) -> Self {
+ tb.0.to_ref_string()
+ }
+}
+
+impl TryFrom<&str> for TargetBranch {
+ type Error = TargetBranchError;
+
+ fn try_from(s: &str) -> Result<Self, Self::Error> {
+ let refstr = git::fmt::RefString::try_from(s)?;
+ Self::try_from(refstr)
+ }
+}
+
+impl std::str::FromStr for TargetBranch {
+ type Err = TargetBranchError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Self::try_from(s)
+ }
+}
+
+impl std::fmt::Display for TargetBranch {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl TargetBranch {
+ fn new<R>(refname: R) -> Result<Self, TargetBranchError>
+ where
+ R: AsRef<git::fmt::RefStr>,
+ {
+ let refname = refname.as_ref();
+ match git::fmt::Qualified::from_refstr(refname).to_owned() {
+ None => Ok(Self(git::fmt::lit::refs_heads(refname).into())),
+ Some(branch) if branch.as_str().starts_with("refs/heads/") => {
+ Ok(Self(branch.clone().to_owned()))
+ }
+ Some(_) => Err(TargetBranchError::InvalidMergeTarget(
+ refname.to_ref_string(),
+ )),
+ }
+ }
+
+ /// Return the [`str`] representation of the [`TargetBranch`].
+ pub fn as_str(&self) -> &str {
+ self.0.as_str()
+ }
+
+ /// Return the fully qualified branch reference.
+ pub fn into_qualified(self) -> git::fmt::Qualified<'static> {
+ self.0
+ }
+}
+
/// Where a patch is intended to be merged.
-#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
+#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum MergeTarget {
/// Intended for the default branch of the project delegates.
@@ -408,16 +496,19 @@ pub enum MergeTarget {
/// If it were otherwise, patches could become un-mergeable.
#[default]
Delegates,
+ /// Intended for a specific branch.
+ Branch(TargetBranch),
}
impl MergeTarget {
/// Get the head of the target branch.
- pub fn head<R: ReadRepository>(&self, repo: &R) -> Result<git::Oid, RepositoryError> {
+ pub fn head(&self, repo: &Repository) -> Result<git::Oid, RepositoryError> {
match self {
MergeTarget::Delegates => {
let (_, target) = repo.head()?;
Ok(target)
}
+ MergeTarget::Branch(branch) => Ok(repo.backend.refname_to_id(branch.as_str())?.into()),
}
}
}
@@ -490,8 +581,36 @@ impl Patch {
}
/// Target this patch is meant to be merged in.
- pub fn target(&self) -> MergeTarget {
- self.target
+ pub fn target(&self) -> &MergeTarget {
+ &self.target
+ }
+
+ /// Resolves the intended target branch for this patch.
+ ///
+ /// If a custom target was specified, it returns that branch.
+ /// Otherwise, it falls back to the project's default branch.
+ pub fn merge_target_branch<'a>(
+ &'a self,
+ doc: &'a Doc,
+ ) -> Result<git::fmt::Qualified<'a>, DefaultBranchError> {
+ match &self.target {
+ MergeTarget::Delegates => Ok(doc.default_branch()?),
+ MergeTarget::Branch(branch) => Ok(branch.clone().into_qualified()),
+ }
+ }
+
+ /// Check the [`MergeTarget`] of the [`Patch`], and return `true` if the
+ /// given `branch` is the same.
+ ///
+ /// Note that the [`Doc`] is used to resolve the default branch of the
+ /// project.
+ pub fn is_targeted_by(
+ &self,
+ doc: &Doc,
+ branch: &git::fmt::Qualified,
+ ) -> Result<bool, DefaultBranchError> {
+ let target = self.merge_target_branch(doc)?;
+ Ok(target == *branch)
}
/// Timestamp of the first revision of the patch.
@@ -698,9 +817,17 @@ impl Patch {
}
}
Action::Assign { .. } => Authorization::Deny,
- Action::Merge { .. } => match self.target() {
- MergeTarget::Delegates => Authorization::Deny,
- },
+ Action::Merge { .. } => {
+ let expected_dest = self.merge_target_branch(doc)?;
+
+ if let Ok(crefs) = doc.canonical_refs()
+ && let Some((_, rule)) = crefs.rules().matches(&expected_dest).next()
+ {
+ return Ok(Authorization::from(rule.allowed().contains(&actor.into())));
+ }
+
+ Authorization::Deny
+ }
// Anyone can submit a review.
Action::Review { .. } => Authorization::Allow,
Action::ReviewRedact { review, .. } => {
@@ -1084,25 +1211,22 @@ impl Patch {
if lookup::revision_mut(self, &revision)?.is_none() {
return Ok(());
};
- match self.target() {
- MergeTarget::Delegates => {
- let proj = identity.project()?;
- let branch = git::refs::branch(proj.default_branch());
-
- // Nb. We don't return an error in case the merge commit is not an
- // ancestor of the default branch. The default branch can change
- // *after* the merge action is created, which is out of the control
- // of the merge author. We simply skip it, which allows archiving in
- // case of a rebase off the master branch, or a redaction of the
- // merge.
- let Ok(head) = repo.reference_oid(&author, &branch) else {
- return Ok(());
- };
- if commit != head && !repo.is_ancestor_of(commit, head)? {
- return Ok(());
- }
- }
+
+ let expected_branch = self.merge_target_branch(identity)?;
+
+ // Nb. We don't return an error in case the merge commit is not an
+ // ancestor of the default branch. The default branch can change
+ // *after* the merge action is created, which is out of the control
+ // of the merge author. We simply skip it, which allows archiving in
+ // case of a rebase off the master branch, or a redaction of the
+ // merge.
+ let Ok(head) = repo.reference_oid(&author, &expected_branch) else {
+ return Ok(());
+ };
+ if commit != head && !repo.is_ancestor_of(commit, head)? {
+ return Ok(());
}
+
self.merges.insert(
author,
Merge {
@@ -2874,7 +2998,10 @@ mod test {
use crate::cob::common::CodeRange;
use crate::cob::test::Actor;
use crate::crypto::test::signer::MockSigner;
+ use crate::git::BranchName;
use crate::identity;
+ use crate::identity::doc::RawDoc;
+ use crate::identity::project::{Project, ProjectName};
use crate::patch::cache::Patches as _;
use crate::profile::env;
use crate::test;
@@ -2884,6 +3011,339 @@ mod test {
use cob::migrate;
+ fn revision() -> (RevisionId, Revision) {
+ let author = arbitrary::r#gen::<Did>(1);
+ let description = arbitrary::r#gen::<String>(1);
+ let base = arbitrary::oid();
+ let oid = arbitrary::oid();
+ let timestamp = env::local_time();
+ let resolves = BTreeSet::new();
+ let id = RevisionId::from(arbitrary::oid());
+ let mut revision = Revision::new(
+ id,
+ Author { id: author },
+ description,
+ base,
+ oid,
+ timestamp.into(),
+ resolves,
+ );
+ let comment = Comment::new(
+ *author,
+ "#1 comment".to_string(),
+ None,
+ None,
+ vec![],
+ timestamp.into(),
+ );
+ let thread = Thread::new(arbitrary::oid(), comment);
+ revision.discussion = thread;
+ (id, revision)
+ }
+
+ #[test]
+ fn test_target_branch() {
+ let unqualified = TargetBranch::try_from("master").unwrap();
+ assert_eq!(unqualified.as_str(), "refs/heads/master");
+
+ let qualified = TargetBranch::try_from("refs/heads/feature/1").unwrap();
+ assert_eq!(qualified.as_str(), "refs/heads/feature/1");
+
+ assert!(matches!(
+ TargetBranch::try_from("refs/tags/v1.0"),
+ Err(TargetBranchError::InvalidMergeTarget(refname)) if refname.as_str() == "refs/tags/v1.0"
+ ));
+
+ assert!(matches!(
+ TargetBranch::try_from("refs/remotes/origin/master"),
+ Err(TargetBranchError::InvalidMergeTarget(refname)) if refname.as_str() == "refs/remotes/origin/master"
+ ));
+
+ assert!(matches!(
+ TargetBranch::try_from("invalid branch name"),
+ Err(TargetBranchError::InvalidReference(_))
+ ));
+ }
+
+ #[test]
+ fn test_json_serialisation_target() {
+ let edit_none = Action::Edit {
+ title: cob::Title::new("My patch").unwrap(),
+ target: MergeTarget::Delegates,
+ };
+ assert_eq!(
+ serde_json::to_string(&edit_none).unwrap(),
+ String::from(r#"{"type":"edit","title":"My patch","target":"delegates"}"#)
+ );
+
+ let edit_some = Action::Edit {
+ title: cob::Title::new("My patch").unwrap(),
+ target: MergeTarget::Branch(TargetBranch::try_from("refs/heads/accepted").unwrap()),
+ };
+ assert_eq!(
+ serde_json::to_string(&edit_some).unwrap(),
+ String::from(
+ r#"{"type":"edit","title":"My patch","target":{"branch":"refs/heads/accepted"}}"#
+ )
+ );
+ }
+
+ #[test]
+ fn test_merge_target_resolution() {
+ let alice = Actor::<MockSigner>::default();
+ let project = Project::new(
+ ProjectName::from_str("test_merge_target_resolution").unwrap(),
+ String::from(""),
+ BranchName::from(git::fmt::RefString::try_from("master").unwrap()),
+ );
+
+ let doc = RawDoc::new(
+ project.unwrap(),
+ vec![alice.did()],
+ 1,
+ identity::Visibility::Public,
+ )
+ .verified()
+ .unwrap();
+
+ let patch_none = Patch::new(
+ cob::Title::new("My patch").unwrap(),
+ MergeTarget::Delegates,
+ revision(),
+ );
+ assert_eq!(
+ patch_none.merge_target_branch(&doc).unwrap().as_str(),
+ "refs/heads/master"
+ );
+
+ let patch_unqualified = Patch::new(
+ cob::Title::new("My patch").unwrap(),
+ MergeTarget::Branch(TargetBranch::try_from("accepted").unwrap()),
+ revision(),
+ );
+ assert_eq!(
+ patch_unqualified
+ .merge_target_branch(&doc)
+ .unwrap()
+ .as_str(),
+ "refs/heads/accepted"
+ );
+
+ let patch_qualified_branch = Patch::new(
+ cob::Title::new("My patch").unwrap(),
+ MergeTarget::Branch(TargetBranch::try_from("refs/heads/accepted").unwrap()),
+ revision(),
+ );
+ assert_eq!(
+ patch_qualified_branch
+ .merge_target_branch(&doc)
+ .unwrap()
+ .as_str(),
+ "refs/heads/accepted"
+ );
+ }
+
+ #[test]
+ fn test_patch_merge_authorization_ref_formats() {
+ let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
+ let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
+ let alice = Actor::<MockSigner>::default();
+
+ let mut raw_doc = RawDoc::new(
+ r#gen::<Project>(1),
+ vec![alice.did()],
+ 1,
+ identity::Visibility::Public,
+ );
+
+ let rules = serde_json::json!({
+ "refs/heads/accepted": {
+ "allow": "delegates",
+ "threshold": 1
+ },
+ "refs/tags/v1.0": {
+ "allow": "delegates",
+ "threshold": 1
+ }
+ });
+ let crefs = serde_json::json!({ "rules": rules });
+ raw_doc.payload.insert(
+ identity::doc::PayloadId::canonical_refs(),
+ identity::doc::Payload::from(crefs),
+ );
+
+ let doc = raw_doc.verified().unwrap();
+
+ let merge_action = Action::Merge {
+ revision: RevisionId(arbitrary::entry_id()),
+ commit: oid,
+ };
+
+ let patch_unqualified = Patch::new(
+ cob::Title::new("My Patch").unwrap(),
+ MergeTarget::Branch(TargetBranch::try_from("accepted").unwrap()),
+ (
+ RevisionId(arbitrary::entry_id()),
+ Revision::new(
+ RevisionId(arbitrary::entry_id()),
+ Author::new(alice.did()),
+ String::new(),
+ base,
+ oid,
+ env::local_time().into(),
+ Default::default(),
+ ),
+ ),
+ );
+ assert_eq!(
+ patch_unqualified
+ .authorization(&merge_action, &alice.did().into(), &doc)
+ .unwrap(),
+ Authorization::Allow
+ );
+
+ let patch_qualified_branch = Patch::new(
+ cob::Title::new("My Patch").unwrap(),
+ MergeTarget::Branch(TargetBranch::try_from("refs/heads/accepted").unwrap()),
+ (
+ RevisionId(arbitrary::entry_id()),
+ Revision::new(
+ RevisionId(arbitrary::entry_id()),
+ Author::new(alice.did()),
+ String::new(),
+ base,
+ oid,
+ env::local_time().into(),
+ Default::default(),
+ ),
+ ),
+ );
+ assert_eq!(
+ patch_qualified_branch
+ .authorization(&merge_action, &alice.did().into(), &doc)
+ .unwrap(),
+ Authorization::Allow
+ );
+ }
+
+ #[test]
+ fn test_patch_merge_custom_destination_authorized() {
+ let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
+ let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
+ let alice = Actor::<MockSigner>::default();
+ let bob = Actor::<MockSigner>::default();
+
+ let mut raw_doc = RawDoc::new(
+ r#gen::<Project>(1),
+ vec![bob.did()],
+ 1,
+ identity::Visibility::Public,
+ );
+
+ let rules = serde_json::json!({
+ "refs/heads/accepted": {
+ "allow": [alice.did()],
+ "threshold": 1
+ }
+ });
+ let crefs = serde_json::json!({
+ "rules": rules
+ });
+ raw_doc.payload.insert(
+ identity::doc::PayloadId::canonical_refs(),
+ identity::doc::Payload::from(crefs),
+ );
+
+ let doc = raw_doc.verified().unwrap();
+ let patch = Patch::new(
+ cob::Title::new("My Patch").unwrap(),
+ MergeTarget::Branch(TargetBranch::try_from("accepted").unwrap()),
+ (
+ RevisionId(arbitrary::entry_id()),
+ Revision::new(
+ RevisionId(arbitrary::entry_id()),
+ Author::new(bob.did()),
+ String::new(),
+ base,
+ oid,
+ env::local_time().into(),
+ Default::default(),
+ ),
+ ),
+ );
+
+ let merge_action = Action::Merge {
+ revision: RevisionId(arbitrary::entry_id()),
+ commit: oid,
+ };
+
+ assert_eq!(
+ patch
+ .authorization(&merge_action, &alice.did().into(), &doc)
+ .unwrap(),
+ Authorization::Allow,
+ );
+ }
+
+ #[test]
+ fn test_patch_merge_custom_destination_unauthorized() {
+ let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
+ let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
+ let alice = Actor::<MockSigner>::default();
+ let bob = Actor::<MockSigner>::default();
+
+ let mut raw_doc = RawDoc::new(
+ r#gen::<Project>(1),
+ vec![alice.did()],
+ 1,
+ identity::Visibility::Public,
+ );
+
+ let rules = serde_json::json!({
+ "refs/heads/accepted": {
+ "allow": [alice.did()],
+ "threshold": 1
+ }
+ });
+ let crefs = serde_json::json!({
+ "rules": rules
+ });
+ raw_doc.payload.insert(
+ identity::doc::PayloadId::canonical_refs(),
+ identity::doc::Payload::from(crefs),
+ );
+
+ let doc = raw_doc.verified().unwrap();
+ let patch = Patch::new(
+ cob::Title::new("My Patch").unwrap(),
+ MergeTarget::Branch(TargetBranch::try_from("accepted").unwrap()),
+ (
+ RevisionId(arbitrary::entry_id()),
+ Revision::new(
+ RevisionId(arbitrary::entry_id()),
+ Author::new(alice.did()),
+ String::new(),
+ base,
+ oid,
+ env::local_time().into(),
+ Default::default(),
+ ),
+ ),
+ );
+
+ let merge_action = Action::Merge {
+ revision: RevisionId(arbitrary::entry_id()),
+ commit: oid,
+ };
+
+ assert_eq!(
+ patch
+ .authorization(&merge_action, &bob.did().into(), &doc)
+ .unwrap(),
+ Authorization::Deny,
+ );
+ }
+
#[test]
fn test_json_serialization() {
let edit = Action::Label {
@@ -2949,7 +3409,7 @@ mod test {
.create(
cob::Title::new("My first patch").unwrap(),
"Blah blah blah.",
- target,
+ target.clone(),
branch.base,
branch.oid,
&[],
@@ -2963,7 +3423,7 @@ mod test {
assert_eq!(patch.description(), "Blah blah blah.");
assert_eq!(patch.author().id(), &author);
assert_eq!(patch.state(), &State::Open { conflicts: vec![] });
- assert_eq!(patch.target(), target);
+ assert_eq!(patch.target(), &target);
assert_eq!(patch.version(), 0);
let (rev_id, revision) = patch.latest();
commit 78b5a964890d9d32cb4b9d1a97b7180f98a64d40
Author: Adrian Duke <adrian.duke@gmail.com>
Date: Tue May 12 13:41:11 2026 +0100
cob: Replace 'git2::Oid' -> 'git::raw::Oid'
diff --git a/crates/radicle/src/cob/test.rs b/crates/radicle/src/cob/test.rs
index b2c50a933..e976cbb0a 100644
--- a/crates/radicle/src/cob/test.rs
+++ b/crates/radicle/src/cob/test.rs
@@ -11,7 +11,7 @@ use crate::cob::store::encoding;
use crate::cob::{Entry, History, Manifest, Timestamp, Version};
use crate::cob::{Title, patch};
use crate::crypto::Signer;
-use crate::git::Oid;
+use crate::git::{self, Oid};
use crate::node::device::Device;
use crate::prelude::Did;
use crate::profile::env;
@@ -267,7 +267,7 @@ fn encoded<T: Cob, G: Signer>(
email: signer.public_key().to_human(),
time: Time::new(timestamp.as_secs() as i64, 0),
};
- let commit = CommitData::<git2::Oid, git2::Oid>::new::<_, _, OwnedTrailer>(
+ let commit = CommitData::<git::raw::Oid, git::raw::Oid>::new::<_, _, OwnedTrailer>(
oid,
parents,
author.clone(),
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 --all-features cargo test --workspace --no-fail-fast '
Commands:
$ podman run --name a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4 -v /opt/radcis/ci.rad.levitte.org/cci/state/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/s:/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w:/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w -w /a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:trixie bash /a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/s/script.sh
+ export 'RUSTDOCFLAGS=-D warnings'
+ RUSTDOCFLAGS='-D warnings'
+ cargo --version
info: syncing channel updates for '1.95-x86_64-unknown-linux-gnu'
info: latest update on 2026-04-16, rust version 1.95.0 (59807616e 2026-04-14)
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.95.0 (f2d3ce0bd 2026-03-21)
+ rustc --version
rustc 1.95.0 (59807616e 2026-04-14)
+ cargo fmt --check
+ cargo clippy --all-targets --workspace -- --deny warnings
Updating crates.io index
Downloading crates ...
Downloaded adler2 v2.0.1
Downloaded borrow-or-share v0.2.4
Downloaded errno v0.3.14
Downloaded dunce v1.0.5
Downloaded cypheraddr v0.4.1
Downloaded derive_more v2.1.1
Downloaded escargot v0.5.15
Downloaded anyhow v1.0.102
Downloaded bit-vec v0.8.0
Downloaded amplify_num v0.5.3
Downloaded aes v0.8.4
Downloaded equivalent v1.0.2
Downloaded indicatif v0.18.4
Downloaded fastrand v2.3.0
Downloaded data-encoding-macro v0.1.19
Downloaded clap v4.6.0
Downloaded litrs v1.0.0
Downloaded cyphergraphy v0.3.1
Downloaded gix-tempfile v23.0.0
Downloaded icu_properties v2.1.2
Downloaded group v0.13.0
Downloaded email_address v0.2.9
Downloaded jiff-static v0.2.23
Downloaded litemap v0.8.1
Downloaded jsonschema v0.30.0
Downloaded maybe-async v0.2.10
Downloaded poly1305 v0.8.0
Downloaded gix-glob v0.26.0
Downloaded bytecount v0.6.9
Downloaded p256 v0.13.2
Downloaded gix-refspec v0.41.0
Downloaded normalize-line-endings v0.3.0
Downloaded keccak v0.1.6
Downloaded itoa v1.0.17
Downloaded match-lookup v0.1.2
Downloaded num-bigint-dig v0.8.6
Downloaded num-integer v0.1.46
Downloaded gix-sec v0.14.0
Downloaded icu_provider v2.1.1
Downloaded form_urlencoded v1.2.2
Downloaded gix-packetline v0.21.3
Downloaded ppv-lite86 v0.2.21
Downloaded multibase v0.9.2
Downloaded rand_core v0.9.5
Downloaded gix-quote v0.7.1
Downloaded proc-macro2 v1.0.106
Downloaded pem-rfc7468 v0.7.0
Downloaded noise-framework v0.4.1
Downloaded gix-revwalk v0.31.0
Downloaded gix-hash v0.25.0
Downloaded lock_api v0.4.14
Downloaded radicle-std-ext v0.2.0
Downloaded num v0.4.3
Downloaded parking_lot_core v0.9.12
Downloaded num-bigint v0.4.6
Downloaded serde_spanned v1.0.4
Downloaded ff v0.13.1
Downloaded pkcs8 v0.10.2
Downloaded num-cmp v0.1.0
Downloaded qcheck-macros v1.0.0
Downloaded phf_shared v0.11.3
Downloaded percent-encoding v2.3.2
Downloaded num-complex v0.4.6
Downloaded schemars_derive v1.2.1
Downloaded semver v1.0.27
Downloaded gix-odb v0.80.0
Downloaded ref-cast v1.0.25
Downloaded rfc6979 v0.4.0
Downloaded ref-cast-impl v1.0.25
Downloaded pkg-config v0.3.32
Downloaded serde_fmt v1.1.0
Downloaded radicle-git-ext v0.12.0
Downloaded rustc_version v0.4.1
Downloaded timeago v0.4.2
Downloaded secrecy v0.10.3
Downloaded rand_chacha v0.9.0
Downloaded signal-hook-mio v0.2.5
Downloaded p384 v0.13.1
Downloaded strsim v0.11.1
Downloaded sem_safe v0.2.1
Downloaded siphasher v0.3.11
Downloaded signature v2.2.0
Downloaded scrypt v0.11.0
Downloaded siphasher v1.0.2
Downloaded spki v0.7.3
Downloaded flate2 v1.1.9
Downloaded sval_fmt v2.17.0
Downloaded ssh-agent-lib v0.6.0
Downloaded ssh-cipher v0.2.0
Downloaded sval_json v2.17.0
Downloaded sval_dynamic v2.17.0
Downloaded tree-sitter-html v0.23.2
Downloaded tree-sitter-language v0.1.7
Downloaded systemd-journal-logger v2.2.2
Downloaded toml_datetime v0.7.5+spec-1.1.0
Downloaded sqlite v0.37.0
Downloaded version_check v0.9.5
Downloaded tracing-log v0.2.0
Downloaded tempfile v3.27.0
Downloaded tracing-core v0.1.36
Downloaded xattr v1.6.1
Downloaded tinyvec_macros v0.1.1
Downloaded snapbox v0.4.17
Downloaded yoke-derive v0.8.1
Downloaded utf8parse v0.2.2
Downloaded tree-sitter-json v0.24.8
Downloaded zerofrom v0.1.6
Downloaded yoke v0.8.1
Downloaded toml_writer v1.0.7+spec-1.1.0
Downloaded value-bag-sval2 v1.12.0
Downloaded tree-sitter-highlight v0.24.7
Downloaded unit-prefix v0.5.2
Downloaded writeable v0.6.2
Downloaded rsa v0.9.10
Downloaded walkdir v2.5.0
Downloaded hashbrown v0.16.1
Downloaded zeroize v1.8.2
Downloaded vsimd v0.8.0
Downloaded zmij v1.0.21
Downloaded libm v0.2.16
Downloaded zerovec-derive v0.11.2
Downloaded zerotrie v0.2.3
Downloaded ssh-key v0.6.7
Downloaded unicode-segmentation v1.12.0
Downloaded yansi v1.0.1
Downloaded url v2.5.8
Downloaded unicode-width v0.2.2
Downloaded tree-sitter-python v0.23.6
Downloaded git2 v0.20.4
Downloaded vcpkg v0.2.15
Downloaded zerovec v0.11.5
Downloaded tree-sitter-md v0.3.2
Downloaded tree-sitter v0.24.7
Downloaded tree-sitter-rust v0.23.3
Downloaded zlib-rs v0.6.3
Downloaded tree-sitter-c v0.23.4
Downloaded syn v1.0.109
Downloaded sha3 v0.10.8
Downloaded regex-syntax v0.8.10
Downloaded tracing-subscriber v0.3.23
Downloaded proptest v1.10.0
Downloaded tracing v0.1.44
Downloaded syn v2.0.117
Downloaded portable-atomic v1.13.1
Downloaded rustix v1.1.4
Downloaded zerocopy v0.8.42
Downloaded tree-sitter-bash v0.23.3
Downloaded tree-sitter-go v0.23.4
Downloaded sysinfo v0.37.2
Downloaded typenum v1.19.0
Downloaded tree-sitter-ruby v0.23.1
Downloaded unicode-normalization v0.1.25
Downloaded tree-sitter-css v0.23.2
Downloaded regex-automata v0.4.14
Downloaded value-bag v1.12.0
Downloaded tree-sitter-typescript v0.23.2
Downloaded unicode-ident v1.0.24
Downloaded toml v0.9.12+spec-1.1.0
Downloaded sval v2.17.0
Downloaded jiff v0.2.23
Downloaded socket2 v0.5.10
Downloaded zerofrom-derive v0.1.6
Downloaded libc v0.2.183
Downloaded value-bag-serde1 v1.12.0
Downloaded sha1-checked v0.10.0
Downloaded tree-sitter-toml-ng v0.6.0
Downloaded utf8_iter v1.0.4
Downloaded tar v0.4.45
Downloaded libz-sys v1.1.25
Downloaded smallvec v1.15.1
Downloaded uuid v1.22.0
Downloaded tokio v1.50.0
Downloaded icu_properties_data v2.1.2
Downloaded serde_core v1.0.228
Downloaded thread_local v1.1.9
Downloaded thiserror-impl v2.0.18
Downloaded thiserror-impl v1.0.69
Downloaded synstructure v0.13.2
Downloaded streaming-iterator v0.1.9
Downloaded wait-timeout v0.2.1
Downloaded uuid-simd v0.8.0
Downloaded universal-hash v0.5.1
Downloaded unarray v0.1.4
Downloaded typeid v1.0.3
Downloaded structured-logger v1.0.5
Downloaded serde_derive v1.0.228
Downloaded unicode-display-width v0.3.0
Downloaded spin v0.9.8
Downloaded schemars v1.2.1
Downloaded idna v1.1.0
Downloaded thiserror v2.0.18
Downloaded thiserror v1.0.69
Downloaded test-log-macros v0.2.19
Downloaded sval_nested v2.17.0
Downloaded inquire v0.9.4
Downloaded gix-transport v0.57.0
Downloaded tinyvec v1.11.0
Downloaded test-log v0.2.19
Downloaded sval_ref v2.17.0
Downloaded tinystr v0.8.2
Downloaded sval_serde v2.17.0
Downloaded sval_buffer v2.17.0
Downloaded signal-hook v0.3.18
Downloaded sqlite3-sys v0.18.0
Downloaded serde_json v1.0.149
Downloaded serde v1.0.228
Downloaded regex v1.12.3
Downloaded sha2 v0.10.9
Downloaded rusty-fork v0.3.1
Downloaded object v0.37.3
Downloaded mio v1.1.1
Downloaded signal-hook-registry v1.4.8
Downloaded rand_xorshift v0.4.0
Downloaded rand v0.8.5
Downloaded subtle v2.6.1
Downloaded stable_deref_trait v1.2.1
Downloaded ssh-encoding v0.2.0
Downloaded socks5-client v0.4.3
Downloaded libgit2-sys v0.18.3+1.9.2
Downloaded snapbox-macros v0.3.10
Downloaded similar v2.7.0
Downloaded simd-adler32 v0.3.8
Downloaded sharded-slab v0.1.7
Downloaded serde_derive_internals v0.29.1
Downloaded rustc-demangle v0.1.27
Downloaded curve25519-dalek v4.1.3
Downloaded sec1 v0.7.3
Downloaded serde-untagged v0.1.9
Downloaded referencing v0.30.0
Downloaded rand_chacha v0.3.1
Downloaded shell-words v1.1.1
Downloaded ryu v1.0.23
Downloaded radicle-surf v0.27.1
Downloaded quick-error v1.2.3
Downloaded pkcs1 v0.7.5
Downloaded bloomy v1.2.0
Downloaded signature v1.6.4
Downloaded signals_receipts v0.2.5
Downloaded shlex v1.3.0
Downloaded sha1 v0.10.6
Downloaded scopeguard v1.2.0
Downloaded rustversion v1.0.22
Downloaded qcheck v1.0.0
Downloaded prodash v31.0.0
Downloaded num-traits v0.2.19
Downloaded gix-path v0.12.0
Downloaded bstr v1.12.1
Downloaded same-file v1.0.6
Downloaded quote v1.0.45
Downloaded pretty_assertions v1.4.1
Downloaded p521 v0.13.3
Downloaded gix-object v0.60.0
Downloaded gix-features v0.48.0
Downloaded potential_utf v0.1.4
Downloaded salsa20 v0.10.2
Downloaded rand_core v0.6.4
Downloaded proc-macro-error2 v2.0.1
Downloaded primeorder v0.13.6
Downloaded polyval v0.6.2
Downloaded phf v0.11.3
Downloaded parking_lot v0.12.5
Downloaded rand v0.9.2
Downloaded gix-protocol v0.61.0
Downloaded getrandom v0.3.4
Downloaded proc-macro-error-attr2 v2.0.0
Downloaded pin-project-lite v0.2.17
Downloaded once_cell v1.21.4
Downloaded linux-raw-sys v0.12.1
Downloaded num-rational v0.4.2
Downloaded icu_collections v2.1.1
Downloaded sqlite3-src v0.7.0
Downloaded heapless v0.8.0
Downloaded chrono v0.4.44
Downloaded emojis v0.6.4
Downloaded gix-ref v0.63.0
Downloaded humantime v2.3.0
Downloaded filetime v0.2.27
Downloaded clap_builder v4.6.0
Downloaded aho-corasick v1.1.4
Downloaded gix-fs v0.21.1
Downloaded derive_more-impl v2.1.1
Downloaded aes-gcm v0.10.3
Downloaded pastey v0.2.1
Downloaded outref v0.5.2
Downloaded log v0.4.29
Downloaded icu_normalizer v2.1.1
Downloaded crossterm v0.29.0
Downloaded gix-utils v0.3.2
Downloaded gix-trace v0.1.19
Downloaded gix-pack v0.70.0
Downloaded elliptic-curve v0.13.8
Downloaded nonempty v0.12.0
Downloaded memchr v2.8.0
Downloaded gix-commitgraph v0.37.0
Downloaded backtrace v0.3.76
Downloaded gix-config-value v0.18.0
Downloaded gix-error v0.2.3
Downloaded gix-actor v0.41.0
Downloaded git-ref-format-macro v0.6.0
Downloaded ghash v0.5.1
Downloaded generic-array v0.14.7
Downloaded fnv v1.0.7
Downloaded cyphernet v0.5.4
Downloaded console v0.16.3
Downloaded colored v2.2.0
Downloaded pbkdf2 v0.12.2
Downloaded opaque-debug v0.3.1
Downloaded nu-ansi-term v0.50.3
Downloaded gix-command v0.9.0
Downloaded find-msvc-tools v0.1.9
Downloaded num-iter v0.1.45
Downloaded gix-shallow v0.12.0
Downloaded fancy-regex v0.14.0
Downloaded nonempty v0.9.0
Downloaded env_logger v0.11.9
Downloaded env_filter v1.0.0
Downloaded diff v0.1.13
Downloaded cbc v0.1.2
Downloaded jobserver v0.1.34
Downloaded icu_locale_core v2.1.1
Downloaded fast-glob v0.3.3
Downloaded ctr v0.9.2
Downloaded git-ref-format v0.6.0
Downloaded crossbeam-channel v0.5.15
Downloaded bytes v1.11.1
Downloaded anstream v0.6.21
Downloaded gix-credentials v0.38.0
Downloaded aead v0.5.2
Downloaded gix-date v0.15.3
Downloaded fluent-uri v0.3.2
Downloaded chacha20poly1305 v0.10.1
Downloaded arc-swap v1.9.1
Downloaded anstyle-parse v1.0.0
Downloaded miniz_oxide v0.8.9
Downloaded idna_adapter v1.2.1
Downloaded icu_normalizer_data v2.1.1
Downloaded human-panic v2.0.6
Downloaded heck v0.5.0
Downloaded gix-url v0.36.0
Downloaded gix-prompt v0.15.0
Downloaded gix-hashtable v0.15.0
Downloaded git-ref-format-core v0.6.0
Downloaded getrandom v0.2.17
Downloaded cc v1.2.57
Downloaded autocfg v1.5.0
Downloaded matchers v0.2.0
Downloaded indexmap v2.13.0
Downloaded der v0.7.10
Downloaded crypto-common v0.1.7
Downloaded clap_derive v4.6.0
Downloaded gix-negotiate v0.31.0
Downloaded clap_complete v4.6.0
Downloaded ascii v1.1.0
Downloaded hash32 v0.3.1
Downloaded digest v0.10.7
Downloaded curve25519-dalek-derive v0.1.1
Downloaded crossbeam-utils v0.8.21
Downloaded blowfish v0.9.1
Downloaded amplify v4.9.0
Downloaded lazy_static v1.5.0
Downloaded ed25519-dalek v2.2.0
Downloaded bitflags v2.11.0
Downloaded gimli v0.32.3
Downloaded fraction v0.15.3
Downloaded document-features v0.2.12
Downloaded memmap2 v0.9.10
Downloaded data-encoding-macro-internal v0.1.17
Downloaded base64ct v1.8.3
Downloaded anstyle-query v1.1.5
Downloaded gix-diff v0.63.0
Downloaded faster-hex v0.10.0
Downloaded anstyle v1.0.14
Downloaded is_terminal_polyfill v1.70.2
Downloaded inout v0.1.4
Downloaded iana-time-zone v0.1.65
Downloaded gix-traverse v0.57.0
Downloaded ed25519 v1.5.3
Downloaded ec25519 v0.1.0
Downloaded displaydoc v0.2.5
Downloaded byteorder v1.5.0
Downloaded amplify_syn v2.0.1
Downloaded addr2line v0.25.1
Downloaded gix-validate v0.11.1
Downloaded gix-lock v23.0.0
Downloaded ed25519 v2.2.3
Downloaded ct-codecs v1.1.6
Downloaded cpufeatures v0.2.17
Downloaded bytesize v2.3.1
Downloaded base64 v0.21.7
Downloaded base256emoji v1.0.2
Downloaded dyn-clone v1.0.20
Downloaded getrandom v0.4.2
Downloaded block-buffer v0.10.4
Downloaded base-x v0.2.11
Downloaded gix-revision v0.45.0
Downloaded gix-chunk v0.7.1
Downloaded either v1.15.0
Downloaded ecdsa v0.16.9
Downloaded hmac v0.12.1
Downloaded anstream v1.0.0
Downloaded ahash v0.8.12
Downloaded lexopt v0.3.2
Downloaded itertools v0.14.0
Downloaded data-encoding v2.10.0
Downloaded crypto-bigint v0.5.5
Downloaded block-padding v0.3.3
Downloaded anstyle-parse v0.2.7
Downloaded amplify_derive v4.0.1
Downloaded cipher v0.4.4
Downloaded crc32fast v1.5.0
Downloaded const-oid v0.9.6
Downloaded colorchoice v1.0.5
Downloaded chacha20 v0.9.1
Downloaded convert_case v0.10.0
Downloaded clap_lex v1.1.0
Downloaded cfg-if v1.0.4
Downloaded erased-serde v0.4.10
Downloaded bit-set v0.8.0
Downloaded base32 v0.4.0
Downloaded base16ct v0.2.0
Downloaded const-str v0.4.3
Downloaded bcrypt-pbkdf v0.10.0
Downloaded base64 v0.22.1
Compiling libc v0.2.183
Compiling proc-macro2 v1.0.106
Compiling quote v1.0.45
Compiling unicode-ident v1.0.24
Checking cfg-if v1.0.4
Checking zeroize v1.8.2
Compiling version_check v0.9.5
Compiling typenum v1.19.0
Compiling generic-array v0.14.7
Compiling syn v2.0.117
Checking getrandom v0.2.17
Checking rand_core v0.6.4
Checking memchr v2.8.0
Compiling shlex v1.3.0
Compiling jobserver v0.1.34
Compiling find-msvc-tools v0.1.9
Checking crypto-common v0.1.7
Compiling cc v1.2.57
Checking subtle v2.6.1
Compiling serde_core v1.0.228
Checking regex-syntax v0.8.10
Checking aho-corasick v1.1.4
Checking const-oid v0.9.6
Checking smallvec v1.15.1
Checking block-buffer v0.10.4
Checking digest v0.10.7
Checking cpufeatures v0.2.17
Checking stable_deref_trait v1.2.1
Compiling thiserror v2.0.18
Checking fastrand v2.3.0
Checking regex-automata v0.4.14
Compiling parking_lot_core v0.9.12
Checking scopeguard v1.2.0
Checking lock_api v0.4.14
Checking bitflags v2.11.0
Checking parking_lot v0.12.5
Compiling typeid v1.0.3
Compiling erased-serde v0.4.10
Checking tinyvec_macros v0.1.1
Compiling crc32fast v1.5.0
Checking gix-trace v0.1.19
Checking tinyvec v1.11.0
Compiling serde v1.0.228
Checking unicode-normalization v0.1.25
Checking byteorder v1.5.0
Checking itoa v1.0.17
Checking gix-utils v0.3.2
Checking serde_fmt v1.1.0
Checking hashbrown v0.16.1
Checking value-bag-serde1 v1.12.0
Compiling synstructure v0.13.2
Compiling thiserror-impl v2.0.18
Checking bstr v1.12.1
Compiling serde_derive v1.0.228
Checking value-bag v1.12.0
Checking gix-validate v0.11.1
Checking log v0.4.29
Compiling zerofrom-derive v0.1.6
Checking same-file v1.0.6
Checking walkdir v2.5.0
Compiling yoke-derive v0.8.1
Checking gix-path v0.12.0
Checking prodash v31.0.0
Checking zerofrom v0.1.6
Checking zlib-rs v0.6.3
Compiling rustix v1.1.4
Checking yoke v0.8.1
Compiling heapless v0.8.0
Compiling pkg-config v0.3.32
Compiling zerovec-derive v0.11.2
Checking hash32 v0.3.1
Checking linux-raw-sys v0.12.1
Checking gix-features v0.48.0
Compiling autocfg v1.5.0
Compiling libm v0.2.16
Compiling num-traits v0.2.19
Checking zerovec v0.11.5
Compiling displaydoc v0.2.5
Compiling getrandom v0.4.2
Checking faster-hex v0.10.0
Checking block-padding v0.3.3
Compiling zerocopy v0.8.42
Checking inout v0.1.4
Checking sha2 v0.10.9
Checking sha1 v0.10.6
Checking sha1-checked v0.10.0
Checking cipher v0.4.4
Checking tinystr v0.8.2
Checking percent-encoding v2.3.2
Checking once_cell v1.21.4
Checking litemap v0.8.1
Checking writeable v0.6.2
Checking gix-hash v0.25.0
Checking icu_locale_core v2.1.1
Checking zerotrie v0.2.3
Checking potential_utf v0.1.4
Compiling icu_properties_data v2.1.2
Compiling zmij v1.0.21
Compiling icu_normalizer_data v2.1.1
Checking icu_provider v2.1.1
Checking icu_collections v2.1.1
Checking der v0.7.10
Compiling serde_json v1.0.149
Checking equivalent v1.0.2
Checking indexmap v2.13.0
Compiling ref-cast v1.0.25
Compiling vcpkg v0.2.15
Compiling thiserror v1.0.69
Compiling syn v1.0.109
Checking icu_properties v2.1.2
Compiling libz-sys v1.1.25
Checking icu_normalizer v2.1.1
Checking tempfile v3.27.0
Checking ppv-lite86 v0.2.21
Compiling ref-cast-impl v1.0.25
Compiling thiserror-impl v1.0.69
Checking spin v0.9.8
Checking idna_adapter v1.2.1
Checking lazy_static v1.5.0
Checking num-integer v0.1.46
Checking hmac v0.12.1
Checking universal-hash v0.5.1
Checking utf8_iter v1.0.4
Checking dyn-clone v1.0.20
Checking opaque-debug v0.3.1
Compiling tree-sitter-language v0.1.7
Checking idna v1.1.0
Checking spki v0.7.3
Compiling libgit2-sys v0.18.3+1.9.2
Checking signature v2.2.0
Checking ff v0.13.1
Checking base16ct v0.2.0
Checking group v0.13.0
Checking sec1 v0.7.3
Checking rand_chacha v0.3.1
Checking form_urlencoded v1.2.2
Compiling serde_derive_internals v0.29.1
Checking crypto-bigint v0.5.5
Compiling schemars_derive v1.2.1
Checking elliptic-curve v0.13.8
Compiling amplify_syn v2.0.1
Checking rand v0.8.5
Checking url v2.5.8
Checking num-iter v0.1.45
Checking aead v0.5.2
Compiling semver v1.0.27
Checking signature v1.6.4
Checking ed25519 v1.5.3
Compiling amplify_derive v4.0.1
Compiling rustc_version v0.4.1
Checking schemars v1.2.1
Checking poly1305 v0.8.0
Checking rfc6979 v0.4.0
Checking chacha20 v0.9.1
Checking ascii v1.1.0
Checking amplify_num v0.5.3
Checking ct-codecs v1.1.6
Checking ec25519 v0.1.0
Checking ecdsa v0.16.9
Compiling curve25519-dalek v4.1.3
Checking git-ref-format-core v0.6.0
Checking amplify v4.9.0
Checking primeorder v0.13.6
Checking polyval v0.6.2
Compiling num-bigint-dig v0.8.6
Checking base64ct v1.8.3
Checking ghash v0.5.1
Checking cyphergraphy v0.3.1
Checking pkcs8 v0.10.2
Checking pem-rfc7468 v0.7.0
Checking pbkdf2 v0.12.2
Checking aes v0.8.4
Checking ctr v0.9.2
Compiling sqlite3-src v0.7.0
Checking gix-error v0.2.3
Compiling curve25519-dalek-derive v0.1.1
Checking keccak v0.1.6
Checking aes-gcm v0.10.3
Checking sha3 v0.10.8
Checking ssh-encoding v0.2.0
Checking pkcs1 v0.7.5
Checking ed25519 v2.2.3
Checking cbc v0.1.2
Checking blowfish v0.9.1
Compiling crossbeam-utils v0.8.21
Compiling data-encoding v2.10.0
Checking base32 v0.4.0
Checking cypheraddr v0.4.1
Checking rsa v0.9.10
Compiling data-encoding-macro-internal v0.1.17
Checking bcrypt-pbkdf v0.10.0
Checking ssh-cipher v0.2.0
Checking ed25519-dalek v2.2.0
Checking p521 v0.13.3
Checking p384 v0.13.1
Checking p256 v0.13.2
Checking chacha20poly1305 v0.10.1
Checking qcheck v1.0.0
Compiling match-lookup v0.1.2
Checking const-str v0.4.3
Checking base256emoji v1.0.2
Checking data-encoding-macro v0.1.19
Checking ssh-key v0.6.7
Checking noise-framework v0.4.1
Checking socks5-client v0.4.3
Checking secrecy v0.10.3
Checking base-x v0.2.11
Checking ssh-agent-lib v0.6.0
Checking multibase v0.9.2
Checking cyphernet v0.5.4
Checking crossbeam-channel v0.5.15
Checking anstyle-query v1.1.5
Checking errno v0.3.14
Checking utf8parse v0.2.2
Checking jiff v0.2.23
Checking nonempty v0.9.0
Checking siphasher v1.0.2
Checking radicle-localtime v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-localtime)
Checking radicle-git-metadata v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-metadata)
Checking radicle-dag v0.10.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-dag)
Checking anstyle v1.0.14
Checking is_terminal_polyfill v1.70.2
Checking colorchoice v1.0.5
Checking radicle-git-ref-format v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-ref-format)
Checking gix-hashtable v0.15.0
Compiling signal-hook v0.3.18
Compiling radicle v0.24.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle)
Checking base64 v0.21.7
Compiling unicode-segmentation v1.12.0
Compiling convert_case v0.10.0
Checking signal-hook-registry v1.4.8
Checking gix-date v0.15.3
Checking serde-untagged v0.1.9
Checking gix-actor v0.41.0
Checking bytesize v2.3.1
Checking gix-object v0.60.0
Checking memmap2 v0.9.10
Checking fast-glob v0.3.3
Checking nonempty v0.12.0
Checking dunce v1.0.5
Compiling derive_more-impl v2.1.1
Checking gix-chunk v0.7.1
Checking mio v1.1.1
Checking regex v1.12.3
Checking sem_safe v0.2.1
Compiling portable-atomic v1.13.1
Checking unicode-width v0.2.2
Compiling litrs v1.0.0
Checking signals_receipts v0.2.5
Checking derive_more v2.1.1
Checking signal-hook-mio v0.2.5
Checking gix-commitgraph v0.37.0
Compiling document-features v0.2.12
Checking anstyle-parse v0.2.7
Checking crossterm v0.29.0
Checking anstream v0.6.21
Checking gix-revwalk v0.31.0
Checking console v0.16.3
Checking gix-fs v0.21.1
Checking unit-prefix v0.5.2
Checking indicatif v0.18.4
Checking gix-tempfile v23.0.0
Checking inquire v0.9.4
Checking unicode-display-width v0.3.0
Checking radicle-signals v0.11.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-signals)
Checking gix-quote v0.7.1
Checking iana-time-zone v0.1.65
Checking shell-words v1.1.1
Checking either v1.15.0
Checking gix-command v0.9.0
Checking chrono v0.4.44
Checking colored v2.2.0
Compiling object v0.37.3
Compiling rustversion v1.0.22
Checking gix-lock v23.0.0
Checking gix-url v0.36.0
Checking gix-config-value v0.18.0
Checking gix-sec v0.14.0
Checking gimli v0.32.3
Checking adler2 v2.0.1
Checking miniz_oxide v0.8.9
Checking gix-prompt v0.15.0
Checking addr2line v0.25.1
Checking gix-revision v0.45.0
Checking gix-traverse v0.57.0
Checking gix-diff v0.63.0
Checking gix-packetline v0.21.3
Checking gix-glob v0.26.0
Compiling tree-sitter v0.24.7
Compiling anyhow v1.0.102
Checking rustc-demangle v0.1.27
Checking backtrace v0.3.76
Checking gix-refspec v0.41.0
Checking gix-transport v0.57.0
Checking gix-pack v0.70.0
Checking arc-swap v1.9.1
Checking gix-credentials v0.38.0
Checking gix-shallow v0.12.0
Checking gix-ref v0.63.0
Checking gix-negotiate v0.31.0
Compiling maybe-async v0.2.10
Compiling proc-macro-error-attr2 v2.0.0
Compiling getrandom v0.3.4
Compiling simd-adler32 v0.3.8
Checking gix-protocol v0.61.0
Compiling proc-macro-error2 v2.0.1
Checking gix-odb v0.80.0
Compiling xattr v1.6.1
Compiling filetime v0.2.27
Checking anstyle-parse v1.0.0
Checking uuid v1.22.0
Checking bytes v1.11.1
Checking anstream v1.0.0
Compiling tar v0.4.45
Compiling flate2 v1.1.9
Compiling git-ref-format-macro v0.6.0
Checking snapbox-macros v0.3.10
Checking salsa20 v0.10.2
Checking siphasher v0.3.11
Checking clap_lex v1.1.0
Checking similar v2.7.0
Compiling heck v0.5.0
Checking normalize-line-endings v0.3.0
Checking strsim v0.11.1
Checking streaming-iterator v0.1.9
Checking clap_builder v4.6.0
Checking snapbox v0.4.17
Compiling clap_derive v4.6.0
Checking bloomy v1.2.0
Compiling radicle-surf v0.27.1
Checking scrypt v0.11.0
Checking git-ref-format v0.6.0
Checking systemd-journal-logger v2.2.2
Checking serde_spanned v1.0.4
Checking toml_datetime v0.7.5+spec-1.1.0
Compiling tree-sitter-rust v0.23.3
Compiling tree-sitter-toml-ng v0.6.0
Compiling tree-sitter-json v0.24.8
Compiling tree-sitter-bash v0.23.3
Compiling tree-sitter-ruby v0.23.1
Compiling tree-sitter-md v0.3.2
Compiling tree-sitter-python v0.23.6
Compiling tree-sitter-c v0.23.4
Compiling tree-sitter-css v0.23.2
Compiling tree-sitter-typescript v0.23.2
Compiling tree-sitter-html v0.23.2
Compiling tree-sitter-go v0.23.4
Checking pin-project-lite v0.2.17
Checking toml_writer v1.0.7+spec-1.1.0
Checking radicle-std-ext v0.2.0
Checking tokio v1.50.0
Checking toml v0.9.12+spec-1.1.0
Checking sqlite3-sys v0.18.0
Checking sqlite v0.37.0
Checking radicle-crypto v0.17.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-crypto)
Checking clap v4.6.0
Checking sysinfo v0.37.2
Checking yansi v1.0.1
Checking diff v0.1.13
Compiling radicle-node v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-node)
Compiling radicle-cli v0.21.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cli)
Checking pretty_assertions v1.4.1
Checking human-panic v2.0.6
Checking clap_complete v4.6.0
Checking structured-logger v1.0.5
Checking radicle-systemd v0.13.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-systemd)
Checking tree-sitter-highlight v0.24.7
Checking itertools v0.14.0
Compiling qcheck-macros v1.0.0
Checking socket2 v0.5.10
Checking lexopt v0.3.2
Checking humantime v2.3.0
Checking timeago v0.4.2
Compiling escargot v0.5.15
Checking bit-vec v0.8.0
Checking bit-set v0.8.0
Checking rand_core v0.9.5
Checking num-bigint v0.4.6
Compiling ahash v0.8.12
Checking num-complex v0.4.6
Checking env_filter v1.0.0
Checking borrow-or-share v0.2.4
Checking fluent-uri v0.3.2
Checking env_logger v0.11.9
Checking phf_shared v0.11.3
Checking num-rational v0.4.2
Compiling test-log-macros v0.2.19
Checking wait-timeout v0.2.1
Compiling radicle-remote-helper v0.17.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-remote-helper)
Checking num v0.4.3
Checking outref v0.5.2
Checking quick-error v1.2.3
Checking fnv v1.0.7
Checking vsimd v0.8.0
Checking rusty-fork v0.3.1
Checking fraction v0.15.3
Checking test-log v0.2.19
Checking phf v0.11.3
Checking uuid-simd v0.8.0
Checking referencing v0.30.0
Checking rand v0.9.2
Checking rand_chacha v0.9.0
Checking rand_xorshift v0.4.0
Checking fancy-regex v0.14.0
Checking email_address v0.2.9
Checking bytecount v0.6.9
Checking unarray v0.1.4
Checking num-cmp v0.1.0
Checking base64 v0.22.1
Checking proptest v1.10.0
Checking emojis v0.6.4
Checking jsonschema v0.30.0
Compiling pastey v0.2.1
Checking radicle-windows v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-windows)
Checking git2 v0.20.4
Checking radicle-oid v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-oid)
Checking radicle-term v0.18.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-term)
Checking radicle-git-ext v0.12.0
Checking radicle-core v0.3.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-core)
Checking radicle-cob v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cob)
Checking radicle-log v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-log)
Checking radicle-fetch v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-fetch)
Checking radicle-cli-test v0.13.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cli-test)
Checking radicle-schemars v0.8.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-schemars)
Checking radicle-protocol v0.8.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-protocol)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 42.54s
+ cargo build --all-targets --workspace
Compiling libc v0.2.183
Compiling cfg-if v1.0.4
Compiling zeroize v1.8.2
Compiling typenum v1.19.0
Compiling memchr v2.8.0
Compiling shlex v1.3.0
Compiling subtle v2.6.1
Compiling regex-syntax v0.8.10
Compiling generic-array v0.14.7
Compiling aho-corasick v1.1.4
Compiling getrandom v0.2.17
Compiling rand_core v0.6.4
Compiling jobserver v0.1.34
Compiling crypto-common v0.1.7
Compiling serde_core v1.0.228
Compiling cc v1.2.57
Compiling const-oid v0.9.6
Compiling regex-automata v0.4.14
Compiling smallvec v1.15.1
Compiling block-buffer v0.10.4
Compiling cpufeatures v0.2.17
Compiling digest v0.10.7
Compiling stable_deref_trait v1.2.1
Compiling fastrand v2.3.0
Compiling bitflags v2.11.0
Compiling thiserror v2.0.18
Compiling scopeguard v1.2.0
Compiling parking_lot_core v0.9.12
Compiling lock_api v0.4.14
Compiling tinyvec_macros v0.1.1
Compiling gix-trace v0.1.19
Compiling tinyvec v1.11.0
Compiling parking_lot v0.12.5
Compiling typeid v1.0.3
Compiling erased-serde v0.4.10
Compiling unicode-normalization v0.1.25
Compiling byteorder v1.5.0
Compiling itoa v1.0.17
Compiling serde v1.0.228
Compiling gix-utils v0.3.2
Compiling crc32fast v1.5.0
Compiling serde_fmt v1.1.0
Compiling hashbrown v0.16.1
Compiling value-bag-serde1 v1.12.0
Compiling value-bag v1.12.0
Compiling same-file v1.0.6
Compiling walkdir v2.5.0
Compiling log v0.4.29
Compiling zerofrom v0.1.6
Compiling prodash v31.0.0
Compiling zlib-rs v0.6.3
Compiling yoke v0.8.1
Compiling hash32 v0.3.1
Compiling linux-raw-sys v0.12.1
Compiling bstr v1.12.1
Compiling gix-validate v0.11.1
Compiling gix-path v0.12.0
Compiling rustix v1.1.4
Compiling zerovec v0.11.5
Compiling heapless v0.8.0
Compiling faster-hex v0.10.0
Compiling libm v0.2.16
Compiling block-padding v0.3.3
Compiling inout v0.1.4
Compiling getrandom v0.4.2
Compiling sha2 v0.10.9
Compiling num-traits v0.2.19
Compiling sha1 v0.10.6
Compiling sha1-checked v0.10.0
Compiling cipher v0.4.4
Compiling gix-features v0.48.0
Compiling zerocopy v0.8.42
Compiling tinystr v0.8.2
Compiling writeable v0.6.2
Compiling percent-encoding v2.3.2
Compiling litemap v0.8.1
Compiling once_cell v1.21.4
Compiling gix-hash v0.25.0
Compiling icu_locale_core v2.1.1
Compiling zerotrie v0.2.3
Compiling potential_utf v0.1.4
Compiling icu_collections v2.1.1
Compiling der v0.7.10
Compiling icu_provider v2.1.1
Compiling equivalent v1.0.2
Compiling icu_properties_data v2.1.2
Compiling indexmap v2.13.0
Compiling icu_normalizer_data v2.1.1
Compiling zmij v1.0.21
Compiling libz-sys v1.1.25
Compiling icu_normalizer v2.1.1
Compiling serde_json v1.0.149
Compiling icu_properties v2.1.2
Compiling tempfile v3.27.0
Compiling ppv-lite86 v0.2.21
Compiling spin v0.9.8
Compiling lazy_static v1.5.0
Compiling ref-cast v1.0.25
Compiling idna_adapter v1.2.1
Compiling num-integer v0.1.46
Compiling hmac v0.12.1
Compiling universal-hash v0.5.1
Compiling utf8_iter v1.0.4
Compiling dyn-clone v1.0.20
Compiling opaque-debug v0.3.1
Compiling idna v1.1.0
Compiling thiserror v1.0.69
Compiling spki v0.7.3
Compiling libgit2-sys v0.18.3+1.9.2
Compiling signature v2.2.0
Compiling ff v0.13.1
Compiling base16ct v0.2.0
Compiling group v0.13.0
Compiling sec1 v0.7.3
Compiling rand_chacha v0.3.1
Compiling form_urlencoded v1.2.2
Compiling crypto-bigint v0.5.5
Compiling url v2.5.8
Compiling rand v0.8.5
Compiling num-iter v0.1.45
Compiling aead v0.5.2
Compiling signature v1.6.4
Compiling ed25519 v1.5.3
Compiling schemars v1.2.1
Compiling elliptic-curve v0.13.8
Compiling poly1305 v0.8.0
Compiling rfc6979 v0.4.0
Compiling chacha20 v0.9.1
Compiling ascii v1.1.0
Compiling ct-codecs v1.1.6
Compiling amplify_num v0.5.3
Compiling ec25519 v0.1.0
Compiling ecdsa v0.16.9
Compiling primeorder v0.13.6
Compiling amplify v4.9.0
Compiling git-ref-format-core v0.6.0
Compiling polyval v0.6.2
Compiling base64ct v1.8.3
Compiling cyphergraphy v0.3.1
Compiling ghash v0.5.1
Compiling pkcs8 v0.10.2
Compiling pem-rfc7468 v0.7.0
Compiling pbkdf2 v0.12.2
Compiling aes v0.8.4
Compiling ctr v0.9.2
Compiling gix-error v0.2.3
Compiling sqlite3-src v0.7.0
Compiling keccak v0.1.6
Compiling curve25519-dalek v4.1.3
Compiling sha3 v0.10.8
Compiling aes-gcm v0.10.3
Compiling ssh-encoding v0.2.0
Compiling pkcs1 v0.7.5
Compiling num-bigint-dig v0.8.6
Compiling ed25519 v2.2.3
Compiling cbc v0.1.2
Compiling blowfish v0.9.1
Compiling base32 v0.4.0
Compiling cypheraddr v0.4.1
Compiling rsa v0.9.10
Compiling bcrypt-pbkdf v0.10.0
Compiling ssh-cipher v0.2.0
Compiling ed25519-dalek v2.2.0
Compiling p384 v0.13.1
Compiling p256 v0.13.2
Compiling p521 v0.13.3
Compiling chacha20poly1305 v0.10.1
Compiling qcheck v1.0.0
Compiling const-str v0.4.3
Compiling data-encoding v2.10.0
Compiling base256emoji v1.0.2
Compiling data-encoding-macro v0.1.19
Compiling ssh-key v0.6.7
Compiling noise-framework v0.4.1
Compiling crossbeam-utils v0.8.21
Compiling socks5-client v0.4.3
Compiling secrecy v0.10.3
Compiling base-x v0.2.11
Compiling multibase v0.9.2
Compiling ssh-agent-lib v0.6.0
Compiling cyphernet v0.5.4
Compiling crossbeam-channel v0.5.15
Compiling anstyle-query v1.1.5
Compiling errno v0.3.14
Compiling utf8parse v0.2.2
Compiling jiff v0.2.23
Compiling nonempty v0.9.0
Compiling siphasher v1.0.2
Compiling radicle-localtime v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-localtime)
Compiling radicle-git-metadata v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-metadata)
Compiling radicle-dag v0.10.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-dag)
Compiling colorchoice v1.0.5
Compiling anstyle v1.0.14
Compiling unicode-segmentation v1.12.0
Compiling is_terminal_polyfill v1.70.2
Compiling radicle-git-ref-format v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-ref-format)
Compiling gix-hashtable v0.15.0
Compiling radicle v0.24.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle)
Compiling base64 v0.21.7
Compiling convert_case v0.10.0
Compiling signal-hook-registry v1.4.8
Compiling gix-date v0.15.3
Compiling gix-actor v0.41.0
Compiling gix-object v0.60.0
Compiling tree-sitter-language v0.1.7
Compiling serde-untagged v0.1.9
Compiling bytesize v2.3.1
Compiling memmap2 v0.9.10
Compiling nonempty v0.12.0
Compiling dunce v1.0.5
Compiling fast-glob v0.3.3
Compiling signal-hook v0.3.18
Compiling derive_more-impl v2.1.1
Compiling gix-chunk v0.7.1
Compiling regex v1.12.3
Compiling mio v1.1.1
Compiling sem_safe v0.2.1
Compiling unicode-width v0.2.2
Compiling signal-hook-mio v0.2.5
Compiling signals_receipts v0.2.5
Compiling derive_more v2.1.1
Compiling gix-commitgraph v0.37.0
Compiling anstyle-parse v0.2.7
Compiling adler2 v2.0.1
Compiling gix-revwalk v0.31.0
Compiling anstream v0.6.21
Compiling crossterm v0.29.0
Compiling portable-atomic v1.13.1
Compiling console v0.16.3
Compiling gix-fs v0.21.1
Compiling unit-prefix v0.5.2
Compiling gix-tempfile v23.0.0
Compiling indicatif v0.18.4
Compiling inquire v0.9.4
Compiling radicle-signals v0.11.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-signals)
Compiling unicode-display-width v0.3.0
Compiling gix-quote v0.7.1
Compiling either v1.15.0
Compiling iana-time-zone v0.1.65
Compiling shell-words v1.1.1
Compiling gix-command v0.9.0
Compiling chrono v0.4.44
Compiling colored v2.2.0
Compiling gix-lock v23.0.0
Compiling gix-url v0.36.0
Compiling gix-config-value v0.18.0
Compiling gix-sec v0.14.0
Compiling gimli v0.32.3
Compiling gix-prompt v0.15.0
Compiling object v0.37.3
Compiling addr2line v0.25.1
Compiling gix-traverse v0.57.0
Compiling gix-revision v0.45.0
Compiling miniz_oxide v0.8.9
Compiling gix-diff v0.63.0
Compiling gix-glob v0.26.0
Compiling gix-packetline v0.21.3
Compiling tree-sitter v0.24.7
Compiling rustc-demangle v0.1.27
Compiling backtrace v0.3.76
Compiling gix-transport v0.57.0
Compiling sqlite3-sys v0.18.0
Compiling sqlite v0.37.0
Compiling radicle-crypto v0.17.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-crypto)
Compiling gix-refspec v0.41.0
Compiling gix-pack v0.70.0
Compiling arc-swap v1.9.1
Compiling gix-credentials v0.38.0
Compiling gix-shallow v0.12.0
Compiling gix-ref v0.63.0
Compiling gix-negotiate v0.31.0
Compiling gix-protocol v0.61.0
Compiling gix-odb v0.80.0
Compiling xattr v1.6.1
Compiling anstyle-parse v1.0.0
Compiling uuid v1.22.0
Compiling filetime v0.2.27
Compiling bytes v1.11.1
Compiling tar v0.4.45
Compiling git-ref-format-macro v0.6.0
Compiling anstream v1.0.0
Compiling flate2 v1.1.9
Compiling getrandom v0.3.4
Compiling anyhow v1.0.102
Compiling snapbox-macros v0.3.10
Compiling salsa20 v0.10.2
Compiling normalize-line-endings v0.3.0
Compiling clap_lex v1.1.0
Compiling similar v2.7.0
Compiling siphasher v0.3.11
Compiling streaming-iterator v0.1.9
Compiling strsim v0.11.1
Compiling snapbox v0.4.17
Compiling clap_builder v4.6.0
Compiling bloomy v1.2.0
Compiling radicle-surf v0.27.1
Compiling scrypt v0.11.0
Compiling git-ref-format v0.6.0
Compiling systemd-journal-logger v2.2.2
Compiling serde_spanned v1.0.4
Compiling toml_datetime v0.7.5+spec-1.1.0
Compiling tree-sitter-json v0.24.8
Compiling tree-sitter-c v0.23.4
Compiling tree-sitter-typescript v0.23.2
Compiling tree-sitter-css v0.23.2
Compiling tree-sitter-python v0.23.6
Compiling tree-sitter-md v0.3.2
Compiling tree-sitter-bash v0.23.3
Compiling tree-sitter-rust v0.23.3
Compiling tree-sitter-go v0.23.4
Compiling tree-sitter-html v0.23.2
Compiling tree-sitter-toml-ng v0.6.0
Compiling tree-sitter-ruby v0.23.1
Compiling toml_writer v1.0.7+spec-1.1.0
Compiling radicle-std-ext v0.2.0
Compiling pin-project-lite v0.2.17
Compiling tokio v1.50.0
Compiling toml v0.9.12+spec-1.1.0
Compiling clap v4.6.0
Compiling sysinfo v0.37.2
Compiling yansi v1.0.1
Compiling radicle-node v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-node)
Compiling diff v0.1.13
Compiling radicle-cli v0.21.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cli)
Compiling pretty_assertions v1.4.1
Compiling human-panic v2.0.6
Compiling clap_complete v4.6.0
Compiling structured-logger v1.0.5
Compiling radicle-systemd v0.13.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-systemd)
Compiling tree-sitter-highlight v0.24.7
Compiling itertools v0.14.0
Compiling socket2 v0.5.10
Compiling timeago v0.4.2
Compiling humantime v2.3.0
Compiling lexopt v0.3.2
Compiling bit-vec v0.8.0
Compiling escargot v0.5.15
Compiling bit-set v0.8.0
Compiling rand_core v0.9.5
Compiling num-bigint v0.4.6
Compiling num-complex v0.4.6
Compiling env_filter v1.0.0
Compiling borrow-or-share v0.2.4
Compiling fluent-uri v0.3.2
Compiling num-rational v0.4.2
Compiling num v0.4.3
Compiling env_logger v0.11.9
Compiling ahash v0.8.12
Compiling phf_shared v0.11.3
Compiling wait-timeout v0.2.1
Compiling quick-error v1.2.3
Compiling radicle-remote-helper v0.17.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-remote-helper)
Compiling fnv v1.0.7
Compiling outref v0.5.2
Compiling vsimd v0.8.0
Compiling rusty-fork v0.3.1
Compiling test-log v0.2.19
Compiling phf v0.11.3
Compiling referencing v0.30.0
Compiling uuid-simd v0.8.0
Compiling fraction v0.15.3
Compiling rand v0.9.2
Compiling rand_chacha v0.9.0
Compiling rand_xorshift v0.4.0
Compiling fancy-regex v0.14.0
Compiling email_address v0.2.9
Compiling num-cmp v0.1.0
Compiling unarray v0.1.4
Compiling bytecount v0.6.9
Compiling base64 v0.22.1
Compiling proptest v1.10.0
Compiling jsonschema v0.30.0
Compiling emojis v0.6.4
Compiling git2 v0.20.4
Compiling radicle-oid v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-oid)
Compiling radicle-core v0.3.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-core)
Compiling radicle-cob v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cob)
Compiling radicle-term v0.18.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-term)
Compiling radicle-git-ext v0.12.0
Compiling radicle-log v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-log)
Compiling radicle-windows v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-windows)
Compiling radicle-fetch v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-fetch)
Compiling radicle-protocol v0.8.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-protocol)
Compiling radicle-cli-test v0.13.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cli-test)
Compiling radicle-schemars v0.8.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-schemars)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 56.88s
+ cargo doc --workspace --no-deps --all-features
Downloading crates ...
Downloaded thousands v0.2.0
Downloaded dhat v0.3.3
Downloaded rustc-hash v1.1.0
Downloaded mintex v0.1.4
Checking regex-automata v0.4.14
Compiling num-traits v0.2.19
Checking once_cell v1.21.4
Compiling syn v1.0.109
Checking tempfile v3.27.0
Checking idna v1.1.0
Checking url v2.5.8
Checking num-integer v0.1.46
Checking git2 v0.20.4
Checking num-iter v0.1.45
Checking num-bigint-dig v0.8.6
Compiling amplify_syn v2.0.1
Checking bstr v1.12.1
Checking gix-validate v0.11.1
Checking gix-path v0.12.0
Checking git-ref-format-core v0.6.0
Compiling amplify_derive v4.0.1
Checking gix-features v0.48.0
Checking gix-error v0.2.3
Checking gix-hash v0.25.0
Checking rsa v0.9.10
Checking radicle-git-ref-format v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-ref-format)
Checking gix-date v0.15.3
Checking radicle-oid v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-oid)
Checking rusty-fork v0.3.1
Checking gix-actor v0.41.0
Checking ssh-key v0.6.7
Checking gix-hashtable v0.15.0
Checking proptest v1.10.0
Checking gix-object v0.60.0
Checking radicle-localtime v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-localtime)
Checking ssh-agent-lib v0.6.0
Checking radicle-git-metadata v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-metadata)
Checking amplify v4.9.0
Checking radicle-dag v0.10.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-dag)
Checking gix-chunk v0.7.1
Checking gix-fs v0.21.1
Checking gix-commitgraph v0.37.0
Checking cyphergraphy v0.3.1
Checking gix-tempfile v23.0.0
Checking gix-revwalk v0.31.0
Checking gix-quote v0.7.1
Checking cypheraddr v0.4.1
Checking noise-framework v0.4.1
Checking regex v1.12.3
Checking inquire v0.9.4
Checking radicle-signals v0.11.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-signals)
Checking socks5-client v0.4.3
Checking gix-command v0.9.0
Checking cyphernet v0.5.4
Checking chrono v0.4.44
Checking radicle-crypto v0.17.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-crypto)
Checking gix-lock v23.0.0
Checking gix-url v0.36.0
Checking radicle-core v0.3.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-core)
Checking radicle-cob v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cob)
Checking radicle-term v0.18.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-term)
Checking gix-config-value v0.18.0
Checking gix-prompt v0.15.0
Checking gix-traverse v0.57.0
Checking gix-revision v0.45.0
Checking gix-diff v0.63.0
Checking radicle v0.24.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle)
Checking gix-glob v0.26.0
Checking gix-packetline v0.21.3
Checking tree-sitter v0.24.7
Checking gix-transport v0.57.0
Checking gix-refspec v0.41.0
Checking gix-pack v0.70.0
Checking gix-credentials v0.38.0
Checking radicle-log v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-log)
Checking git-ref-format v0.6.0
Checking gix-ref v0.63.0
Checking gix-shallow v0.12.0
Checking gix-negotiate v0.31.0
Checking radicle-git-ext v0.12.0
Checking uuid v1.22.0
Checking gix-protocol v0.61.0
Compiling radicle-cli v0.21.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cli)
Checking human-panic v2.0.6
Checking radicle-surf v0.27.1
Checking gix-odb v0.80.0
Checking tree-sitter-toml-ng v0.6.0
Checking tree-sitter-highlight v0.24.7
Checking rustc-hash v1.1.0
Checking mintex v0.1.4
Compiling radicle-node v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-node)
Checking thousands v0.2.0
Checking dhat v0.3.3
Checking radicle-systemd v0.13.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-systemd)
Documenting radicle-systemd v0.13.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-systemd)
Documenting radicle v0.24.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle)
Documenting radicle-log v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-log)
Documenting radicle-term v0.18.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-term)
Documenting radicle-cob v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cob)
Documenting radicle-core v0.3.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-core)
Documenting radicle-crypto v0.17.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-crypto)
Documenting radicle-signals v0.11.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-signals)
Documenting radicle-oid v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-oid)
Documenting radicle-git-ref-format v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-ref-format)
Documenting radicle-localtime v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-localtime)
Documenting radicle-git-metadata v0.2.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-git-metadata)
Documenting radicle-dag v0.10.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-dag)
Documenting radicle-windows v0.1.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-windows)
Checking radicle-fetch v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-fetch)
Documenting radicle-cli v0.21.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cli)
Documenting radicle-schemars v0.8.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-schemars)
Checking radicle-protocol v0.8.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-protocol)
Documenting radicle-protocol v0.8.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-protocol)
Documenting radicle-node v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-node)
Documenting radicle-fetch v0.20.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-fetch)
Documenting radicle-remote-helper v0.17.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-remote-helper)
Documenting radicle-cli-test v0.13.0 (/a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/crates/radicle-cli-test)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 10.92s
Generated /a0584126-fd7e-4b89-a1aa-b85a2dfe3ce4/w/target/doc/radicle/index.html and 21 other files
+ cargo test --workspace --no-fail-fast
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.19s
Running unittests src/lib.rs (target/debug/deps/radicle-f47a7c2ba456ab00)
running 383 tests
test canonical::formatter::test::ascii_control_characters ... ok
test canonical::formatter::test::ordered_nested_object ... ok
test canonical::formatter::test::securesystemslib_asserts ... ok
test cob::cache::migrations::_2::tests::test_migration_2 ... ok
test cob::common::test::test_color ... ok
test cob::common::test::test_emojis ... ok
test cob::cache::tests::test_check_version ... ok
test cob::cache::migrations::_2::tests::test_patch_json_deserialization ... ok
test cob::cache::tests::test_migrate_to ... ok
test cob::common::test::test_title ... ok
test cob::identity::test::prop_json_eq_str ... ok
test cob::identity::test::test_identity_redact_revision ... ok
test cob::identity::test::test_identity_remove_delegate_concurrent ... ok
test cob::identity::test::test_identity_reject_concurrent ... ok
test cob::identity::test::test_identity_update_rejected ... ok
test cob::identity::test::test_identity_updates ... ok
test cob::issue::cache::tests::test_counts ... ok
test cob::issue::cache::tests::test_get ... ok
test cob::issue::cache::tests::test_is_empty ... ok
test cob::issue::cache::tests::test_list ... ok
test cob::issue::cache::tests::test_list_by_status ... ok
test cob::issue::cache::tests::test_remove ... ok
test cob::identity::test::test_valid_identity ... ok
test cob::identity::test::test_identity_updates_concurrent ... ok
test cob::issue::test::test_embeds_edit ... ok
test cob::issue::test::test_embeds ... ok
test cob::identity::test::test_identity_updates_concurrent_outdated ... ok
test cob::issue::test::test_invalid_actions ... ok
test cob::issue::test::test_invalid_cob ... ok
test cob::issue::test::test_invalid_tx ... ok
test cob::issue::test::test_invalid_tx_reference ... ok
test cob::issue::test::test_issue_all ... ok
test cob::issue::test::test_concurrency ... ok
test cob::issue::test::test_issue_comment ... ok
test cob::issue::test::test_issue_comment_redact ... ok
test cob::issue::test::test_issue_create_and_assign ... ok
test cob::issue::test::test_issue_create_and_change_state ... ok
test cob::issue::test::test_issue_create_and_get ... ok
test cob::issue::test::test_issue_create_and_unassign ... ok
test cob::issue::test::test_issue_create_and_reassign ... ok
test cob::issue::test::test_issue_edit ... ok
test cob::issue::test::test_issue_edit_description ... ok
test cob::issue::test::test_issue_multilines ... ok
test cob::issue::test::test_issue_state_serde ... ok
test cob::issue::test::test_ordering ... ok
test cob::patch::actions::test::test_review_edit ... ok
test cob::issue::test::test_issue_label ... ok
test cob::issue::test::test_issue_react ... ok
test cob::issue::test::test_issue_reply ... ok
test cob::patch::cache::tests::test_is_empty ... ok
test cob::patch::cache::tests::test_list ... ok
test cob::patch::cache::tests::test_list_by_status ... ok
test cob::patch::cache::tests::test_get ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_migration_null_summary ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_migration_with_summary ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_migration_without_summary ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_v2 ... ok
test cob::patch::encoding::review::test::test_review_summary ... ok
test cob::patch::test::test_json ... ok
test cob::patch::test::test_json_serialisation_target ... ok
test cob::patch::test::test_json_serialization ... ok
test cob::patch::test::test_merge_target_resolution ... ok
test cob::patch::cache::tests::test_remove ... ok
test cob::patch::test::test_patch_create_and_get ... ok
test cob::patch::cache::tests::test_counts ... ok
test cob::patch::test::test_patch_merge_authorization_ref_formats ... ok
test cob::patch::test::test_patch_merge_custom_destination_authorized ... ok
test cob::patch::test::test_patch_merge_custom_destination_unauthorized ... ok
test cob::patch::test::test_patch_discussion ... ok
test cob::patch::test::test_patch_merge ... ok
test cob::patch::test::test_patch_redact ... ok
test cob::patch::test::test_patch_review ... ok
test cob::patch::test::test_patch_review_comment ... ok
test cob::patch::test::test_patch_review_duplicate ... ok
test cob::patch::test::test_patch_review_edit ... ok
test cob::patch::test::test_patch_review_edit_comment ... ok
test cob::patch::test::test_patch_review_remove_summary ... ok
test cob::patch::test::test_reactions_json_serialization ... ok
test cob::patch::test::test_revision_edit_redact ... ok
test cob::patch::test::test_revision_reaction ... ok
test cob::patch::test::test_revision_review_merge_redacted ... ok
test cob::patch::test::test_target_branch ... ok
test cob::stream::tests::test_all_from ... ok
test cob::stream::tests::test_all_from_until ... ok
test cob::patch::test::test_patch_review_revision_redact ... ok
test cob::stream::tests::test_all_until ... ok
test cob::stream::tests::test_from_until ... ok
test cob::stream::tests::test_regression_from_until ... ok
test cob::thread::tests::test_comment_edit_missing ... ok
test cob::thread::tests::test_comment_edit_redacted ... ok
test cob::thread::tests::test_comment_redact_missing ... ok
test cob::thread::tests::test_duplicate_comments ... ok
test cob::thread::tests::test_edit_comment ... ok
test cob::thread::tests::test_redact_comment ... ok
test cob::thread::tests::test_timeline ... ok
test git::canonical::protect::tests::refs_rad ... ok
test git::canonical::protect::tests::refs_rad_id ... ok
test git::canonical::protect::tests::refs_radieschen ... ok
test git::canonical::quorum::test::merge_base_commutative ... ok
test git::canonical::quorum::test::test_merge_bases ... ok
test cob::patch::test::test_patch_update ... ok
test git::canonical::rules::test::deserialization ... ok
test git::canonical::rules::test::deserialize_extensions ... ok
test git::canonical::rules::test::matches_exactly_curly_braces ... ok
test git::canonical::rules::test::matches_expands_globs_appropriately ... ok
test git::canonical::rules::test::ordering ... ok
test git::canonical::rules::test::property::identity ... ok
test git::canonical::rules::test::property::prefix ... ok
test git::canonical::rules::test::canonical ... ok
test git::canonical::rules::test::property::prefix_negative ... ok
test git::canonical::rules::test::property::suffix_negative ... ok
test git::canonical::rules::test::property::suffix ... ok
test git::canonical::rules::test::roundtrip ... ok
test git::canonical::rules::test::property::trailing_asterisk_partial_component ... ok
test git::canonical::rules::test::rule_validate_success ... ok
test git::canonical::rules::test::special_branches ... ok
test git::canonical::symbolic::test::deserialize_infinite ... ok
test git::canonical::symbolic::test::deserialize_order ... ok
test git::canonical::symbolic::test::deserialize_valid ... ok
test git::canonical::symbolic::test::infinite_extend ... ok
test git::canonical::symbolic::test::infinite_multi ... ok
test git::canonical::symbolic::test::infinite_single ... ok
test git::canonical::symbolic::test::reclassification_combine ... ok
test git::canonical::symbolic::test::reclassification_combine_reverse ... ok
test git::canonical::symbolic::test::reclassification_diamond ... ok
test git::canonical::symbolic::test::reclassification_order_invariant ... ok
test git::canonical::symbolic::test::reclassification_reverse_chain ... ok
test git::canonical::symbolic::test::resolve_two_hop_chain ... ok
test git::canonical::symbolic::test::target_classification ... ok
test git::canonical::symbolic::test::target_classification_symbolic ... ok
test git::canonical::symbolic::test::target_reclassification ... ok
test git::canonical::symbolic::test::target_reclassification_commutative ... ok
test git::canonical::tests::test_commit_quorum_fork_of_a_fork ... ok
test git::canonical::tests::test_commit_quorum_forked_merge_commits ... ok
test git::canonical::tests::test_commit_quorum_groups ... ok
test git::canonical::tests::test_commit_quorum_linear ... ok
test git::canonical::tests::test_commit_quorum_merges ... ok
test git::canonical::tests::test_commit_quorum_single ... ok
test git::canonical::tests::test_commit_quorum_three_way_fork ... ok
test git::canonical::tests::test_commit_quorum_two_way_fork ... ok
test git::canonical::tests::test_quorum_different_types ... ok
test git::canonical::rules::test::rule_validate_failures ... ok
test git::canonical::tests::test_tag_quorum ... ok
test git::test::test_version_from_str ... ok
test git::test::test_version_ord ... ok
test identity::crefs::tests::invalid_clash ... ok
test identity::crefs::tests::invalid_clash_asterisk_name ... ok
test identity::crefs::tests::invalid_dangling ... ok
test identity::crefs::tests::omit_symbolic ... ok
test identity::crefs::tests::valid ... ok
test identity::crefs::tests::valid_asterisk_target ... ok
test identity::did::test::test_did_encode_decode ... ok
test identity::did::test::test_did_vectors ... ok
test identity::doc::test::default_branch_clash ... ok
test identity::doc::test::default_branch_without_project ... ok
test git::canonical::tests::test_quorum_properties ... ok
test cob::thread::tests::prop_ordering ... ok
test identity::doc::test::test_canonical_doc ... ok
test identity::doc::test::test_duplicate_dids ... ok
test identity::doc::test::test_future_version_error ... ok
test identity::doc::test::test_is_valid_version ... ok
test identity::doc::test::test_canonical_example ... ok
test identity::doc::test::test_not_found ... ok
test identity::doc::test::test_parse_version ... ok
test identity::doc::test::test_visibility_json ... ok
test identity::doc::update::test::test_can_update_crefs ... ok
test identity::doc::update::test::test_cannot_include_default_branch_rule ... ok
test identity::doc::update::test::test_default_branch_rule_exists_after_verification ... ok
test identity::project::test::test_project_name ... ok
test node::address::store::test::skip_invalid_address_type ... ok
test node::address::store::test::skip_mismatched_address_type ... ok
test node::address::store::test::test_alias ... ok
test node::address::store::test::test_disconnected ... ok
test node::address::store::test::test_disconnected_ban ... ok
test node::address::store::test::test_empty ... ok
test node::address::store::test::test_entries ... ok
test node::address::store::test::test_entries_skips_unparsable_address ... ok
test node::address::store::test::test_get_none ... ok
test node::address::store::test::test_insert_and_get ... ok
test node::address::store::test::test_insert_and_remove ... ok
test node::address::store::test::test_insert_and_update ... ok
test node::address::store::test::test_insert_duplicate ... ok
test identity::doc::test::test_max_delegates ... ok
test node::address::store::test::test_remove_nothing ... ok
test node::command::test::command_result ... ok
test node::config::test::deserialize_migrating_scope ... ok
test node::address::store::test::test_node_aliases ... ok
test node::config::test::fetch_level_min ... ok
test node::config::test::onion_absent ... ok
test node::config::test::onion_null ... ok
test node::config::test::partial ... ok
test node::config::test::regression_ipv6_address_brackets ... ok
test node::config::test::regression_ipv6_address_no_brackets ... ok
test node::config::test::serialize_migrating_scope ... ok
test node::config::test::user_agent_default ... ok
test node::config::test::user_agent_custom ... ok
test node::config::test::user_agent_default_explicit ... ok
test node::config::test::user_agent_opt_out ... ok
test node::db::config::test::database_config_valid_combinations ... ok
test node::db::config::test::invalid ... ok
test node::db::test::migration_8::all_ipv6_formatted_dns_addresses_are_retyped ... ok
test node::db::test::migration_8::dns_address_starting_with_bracket_but_missing_closing_bracket_colon_is_unaffected ... ok
test node::db::test::migration_8::dns_address_with_bracket_not_at_start_is_unaffected ... ok
test node::db::test::migration_8::ipv4_address_is_unaffected ... ok
test node::db::test::migration_8::ipv6_formatted_dns_address_is_retyped_to_ipv6 ... ok
test node::db::test::migration_8::ipv6_formatted_dns_address_is_deleted_when_correct_ipv6_row_already_exists ... ok
test node::db::test::migration_8::migration_applies_to_all_nodes ... ok
test node::db::test::migration_8::plain_dns_hostname_without_brackets_is_unaffected ... ok
test node::db::test::migration_8::retype_preserves_address_metadata ... ok
test node::db::test::migration_9::bracketed_non_ipv6_garbage_is_deleted ... ok
test node::db::test::migration_9::dns_row_is_unaffected_even_when_inner_part_has_no_colon ... ok
test node::db::test::migration_9::empty_brackets_ipv6_row_is_deleted ... ok
test node::db::test::migration_9::full_ipv6_address_is_kept ... ok
test node::db::test::migration_9::ipv4_row_is_unaffected ... ok
test node::db::test::migration_9::loopback_address_is_kept ... ok
test node::db::test::migration_9::unspecified_address_is_kept ... ok
test node::features::test::test_operations ... ok
test node::notifications::store::test::test_branch_notifications ... ok
test node::notifications::store::test::test_clear ... ok
test node::notifications::store::test::test_cob_notifications ... ok
test node::db::test::test_version ... ok
test node::notifications::store::test::test_counts_by_repo ... ok
test node::notifications::store::test::test_duplicate_notifications ... ok
test node::notifications::store::test::test_notification_status ... ok
test node::policy::store::test::test_follow_and_unfollow_node ... ok
test node::policy::store::test::test_node_policies ... ok
test node::policy::store::test::test_node_policy ... ok
test node::policy::store::test::test_node_aliases ... ok
test node::policy::store::test::test_repo_policies ... ok
test node::policy::store::test::test_repo_policy ... ok
test node::policy::store::test::test_seed_and_unseed_repo ... ok
test node::policy::store::test::test_update_scope ... ok
test node::policy::store::test::test_update_alias ... ok
test node::refs::store::test::test_count ... ok
test node::refs::store::test::test_set_and_delete ... ok
test node::refs::store::test::test_set_and_get ... ok
test node::routing::test::test_count ... ok
test node::routing::test::test_entries ... ok
test node::routing::test::test_insert_and_get ... ok
test node::routing::test::test_insert_and_remove ... ok
test node::routing::test::test_insert_and_get_resources ... ok
test node::routing::test::test_insert_existing_updated_time ... ok
test node::routing::test::test_insert_duplicate ... ok
test node::routing::test::test_len ... ok
test node::routing::test::test_remove_many ... ok
test node::routing::test::test_remove_redundant ... ok
test node::routing::test::test_update_existing_multi ... ok
test node::sync::announce::test::all_synced_nodes_are_preferred_seeds ... ok
test node::sync::announce::test::announcer_adapts_target_to_reach ... ok
test node::routing::test::test_prune ... ok
test node::sync::announce::test::announcer_preferred_seeds_or_replica_factor ... ok
test node::sync::announce::test::announcer_reached_max_replication_target ... ok
test node::sync::announce::test::announcer_reached_min_replication_target ... ok
test node::sync::announce::test::announcer_reached_preferred_seeds ... ok
test node::sync::announce::test::announcer_synced_with_unknown_node ... ok
test node::sync::announce::test::announcer_with_replication_factor_zero_and_preferred_seeds ... ok
test node::sync::announce::test::announcer_timed_out ... ok
test node::sync::announce::test::construct_node_appears_in_multiple_input_sets ... ok
test node::sync::announce::test::construct_only_preferred_seeds_provided ... ok
test node::sync::announce::test::cannot_construct_announcer ... ok
test node::sync::announce::test::invariant_progress_should_match_state ... ok
test node::sync::announce::test::local_node_in_multiple_sets ... ok
test node::sync::announce::test::local_node_in_preferred_seeds ... ok
test node::sync::announce::test::local_node_in_synced_set ... ok
test node::sync::announce::test::local_node_only_in_all_sets_results_in_no_seeds_error ... ok
test node::sync::announce::test::local_node_in_unsynced_set ... ok
test node::sync::announce::test::synced_with_local_node_is_ignored ... ok
test node::sync::announce::test::preferred_seeds_already_synced ... ok
test node::sync::announce::test::synced_with_same_node_multiple_times ... ok
test node::sync::announce::test::timed_out_after_reaching_success ... ok
test node::sync::fetch::test::all_nodes_are_candidates ... ok
test node::sync::fetch::test::could_not_reach_target ... ok
test node::sync::fetch::test::all_nodes_are_fetchable ... ok
test node::sync::fetch::test::ignores_duplicates_and_local_node ... ok
test node::sync::fetch::test::preferred_seeds_target_returned_over_replicas ... ok
test node::sync::fetch::test::reaches_target_of_max_replicas ... ok
test node::sync::fetch::test::reaches_target_of_replicas ... ok
test node::sync::test::ensure_replicas_construction ... ok
test node::sync::test::replicas_constrain_to ... ok
test node::test::test_address ... ok
test node::test::test_alias ... ok
test node::test::test_command_result ... ok
test node::test::test_user_agent ... ok
test node::timestamp::tests::test_timestamp_max ... ok
test node::sync::fetch::test::reaches_target_of_preferred_seeds ... ok
test profile::test::canonicalize_home ... ok
test profile::test::test_config ... ok
test rad::tests::test_checkout ... ok
test rad::tests::test_fork ... ok
test profile::config::test::schema ... ok
test rad::tests::test_init ... ok
test storage::git::tests::test_sign_refs ... ok
test storage::git::transport::local::url::test::test_url_parse ... ok
test storage::git::transport::local::url::test::test_url_to_string ... ok
test storage::git::transport::remote::url::test::test_url_parse ... ok
test storage::git::tests::test_references_of ... ok
test cob::patch::cache::tests::test_find_by_revision ... ok
test identity::doc::test::prop_encode_decode ... ok
test storage::refs::sigrefs::git::properties::idempotent_write ... ok
test storage::refs::sigrefs::property::idempotent ... ok
test storage::refs::sigrefs::read::test::commit_reader::identity_root_error ... ok
test storage::refs::sigrefs::read::test::commit_reader::missing_commit ... ok
test storage::refs::sigrefs::read::test::commit_reader::read_ok ... ok
test storage::refs::sigrefs::read::test::commit_reader::too_many_parents ... ok
test storage::refs::sigrefs::read::test::commit_reader::tree_error ... ok
test storage::refs::sigrefs::read::test::identity_root_reader::doc_blob_error ... ok
test storage::refs::sigrefs::read::test::identity_root_reader::missing_identity ... ok
test storage::refs::sigrefs::read::test::identity_root_reader::read_ok_none ... ok
test storage::refs::sigrefs::read::test::identity_root_reader::read_ok_some ... ok
test storage::refs::sigrefs::read::test::resolve_tip::find_reference_error ... ok
test storage::refs::sigrefs::read::test::resolve_tip::missing_sigrefs ... ok
test storage::refs::sigrefs::read::test::resolve_tip::resolve_tip_ok ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::detect_parent::root_without_parent ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::detect_parent::root_without_root ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::downgrade::parent ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::downgrade::restore ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::downgrade::root ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::downgrade::root_with_parent ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::head_commit_error ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::head_verify_mismatched_identity_error ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::head_verify_signature_error ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::invalid_parent ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::read_ok_no_parent ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::read_ok_parent ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::read_ok_root ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::replay::alternating ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::replay::chain ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::replay::multiple ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::replay::root_at_head ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::single_commit ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::two_commits ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::walk_commit_error ... ok
test storage::refs::sigrefs::read::test::signed_refs_reader::walk_verify_error ... ok
test storage::refs::sigrefs::read::test::tree_reader::missing_both ... ok
test storage::refs::sigrefs::read::test::tree_reader::missing_refs ... ok
test storage::refs::sigrefs::read::test::tree_reader::missing_signature ... ok
test storage::refs::sigrefs::read::test::tree_reader::parse_refs_error ... ok
test storage::refs::sigrefs::read::test::tree_reader::parse_signature_error ... ok
test storage::refs::sigrefs::read::test::tree_reader::read_ok ... ok
test storage::refs::sigrefs::read::test::tree_reader::read_refs_error ... ok
test storage::refs::sigrefs::read::test::tree_reader::read_signature_error ... ok
test storage::refs::sigrefs::write::test::commit_writer::tree_error ... ok
test storage::refs::sigrefs::write::test::commit_writer::write_commit_error ... ok
test storage::refs::sigrefs::write::test::commit_writer::write_empty_refs ... ok
test storage::refs::sigrefs::write::test::commit_writer::write_root_ok ... ok
test storage::refs::sigrefs::write::test::commit_writer::write_with_parent_ok ... ok
test storage::refs::sigrefs::write::test::head_reader::no_head ... ok
test storage::refs::sigrefs::write::test::head_reader::read_ok ... ok
test storage::refs::sigrefs::write::test::head_reader::reference_error ... ok
test storage::refs::sigrefs::write::test::head_reader::refs_blob_error ... ok
test storage::refs::sigrefs::write::test::head_reader::refs_blob_missing ... ok
test storage::refs::sigrefs::write::test::head_reader::refs_parse_error ... ok
test storage::refs::sigrefs::write::test::head_reader::signature_blob_error ... ok
test storage::refs::sigrefs::write::test::head_reader::signature_blob_missing ... ok
test storage::refs::sigrefs::write::test::head_reader::signature_parse_error ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::commit_error ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::head_error ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::never_write_rad_sigrefs ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::reference_error ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::unchanged ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::unchanged_force_writes_new_commit ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::write_empty_refs ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::write_root_ok ... ok
test storage::refs::sigrefs::write::test::signed_refs_writer::write_with_parent_ok ... ok
test storage::refs::sigrefs::write::test::tree_writer::sign_error ... ok
test storage::refs::sigrefs::write::test::tree_writer::write_ok ... ok
test storage::refs::sigrefs::write::test::tree_writer::write_tree_error ... ok
test storage::refs::tests::prop_canonical_roundtrip ... ok
test storage::refs::sigrefs::git::properties::initial_commit_roundtrip ... ok
test storage::tests::test_storage ... ok
test test::assert::test::assert_with_message ... ok
test test::assert::test::test_assert_no_move ... ok
test test::assert::test::test_assert_panic_0 - should panic ... ok
test test::assert::test::test_assert_panic_1 - should panic ... ok
test test::assert::test::test_assert_panic_2 - should panic ... ok
test test::assert::test::test_assert_succeed ... ok
test test::assert::test::test_panic_message ... ok
test version::test::test_version ... ok
test web::test::description_only ... ok
test web::test::pinned_empty ... ok
test storage::refs::tests::test_rid_verification ... ok
test storage::refs::sigrefs::property::roundtrip ... ok
test storage::refs::sigrefs::git::properties::chain_roundtrip ... ok
test result: ok. 383 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.39s
Running unittests src/lib.rs (target/debug/deps/radicle_cli-0c161f4fcbeacd74)
running 46 tests
test commands::block::args::test::should_parse_rid ... ok
test commands::block::args::test::should_parse_nid ... ok
test commands::block::args::test::should_not_parse ... ok
test commands::clone::args::test::should_parse_rid_non_urn ... ok
test commands::clone::args::test::should_parse_rid_url ... ok
test commands::clone::args::test::should_parse_rid_urn ... ok
test commands::cob::args::test::should_allow_log_json_format ... ok
test commands::cob::args::test::should_allow_log_pretty_format ... ok
test commands::cob::args::test::should_allow_show_json_format ... ok
test commands::cob::args::test::should_allow_update_json_format ... ok
test commands::cob::args::test::should_not_allow_update_pretty_format ... ok
test commands::cob::args::test::should_not_allow_show_pretty_format ... ok
test commands::fork::args::test::should_not_parse_rid_url ... ok
test commands::fork::args::test::should_parse_rid_non_urn ... ok
test commands::fork::args::test::should_parse_rid_urn ... ok
test commands::id::args::test::should_not_clobber_payload_args ... ok
test commands::id::args::test::should_not_parse_into_payload - should panic ... ok
test commands::id::args::test::should_not_parse_single_payload ... ok
test commands::id::args::test::should_parse_into_payload ... ok
test commands::id::args::test::should_not_parse_single_payloads ... ok
test commands::init::args::test::should_not_parse_rid_url ... ok
test commands::id::args::test::should_parse_single_payload ... ok
test commands::id::args::test::should_parse_multiple_payloads ... ok
test commands::inspect::test::test_tree ... ok
test commands::init::args::test::should_parse_rid_non_urn ... ok
test commands::patch::review::builder::tests::test_review_comments_basic ... ok
test commands::patch::review::builder::tests::test_review_comments_before ... ok
test commands::patch::review::builder::tests::test_review_comments_multiline ... ok
test commands::patch::review::builder::tests::test_review_comments_split_hunk ... ok
test commands::publish::args::test::should_not_parse_rid_url ... ok
test commands::publish::args::test::should_parse_rid_non_urn ... ok
test commands::init::args::test::should_parse_rid_urn ... ok
test commands::publish::args::test::should_parse_rid_urn ... ok
test git::pretty_diff::test::test_pretty ... ignored
test git::ddiff::tests::diff_encode_decode_ddiff_hunk ... ok
test commands::watch::args::test::should_parse_ref_str ... ok
test git::unified_diff::test::test_diff_content_encode_decode_content ... ok
test git::unified_diff::test::test_diff_encode_decode_diff ... ok
test terminal::args::test::should_not_parse ... ok
test terminal::args::test::should_parse_nid ... ok
test terminal::args::test::should_parse_rid ... ok
test terminal::format::test::test_strip_comments ... ok
test terminal::format::test::test_bytes ... ok
test terminal::patch::test::test_edit_display_message ... ok
test terminal::patch::test::test_create_display_message ... ok
test terminal::patch::test::test_update_display_message ... ok
test result: ok. 45 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s
Running unittests src/main.rs (target/debug/deps/rad-bd06360b420d767c)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/commands.rs (target/debug/deps/commands-fc66af7f1a19c65c)
running 129 tests
test commands::checkout::rad_checkout ... ok
test commands::clone::rad_clone_bare ... ok
test commands::clone::rad_clone ... ok
test commands::clone::rad_clone_all ... ok
test commands::clone::rad_clone_scope ... ok
test commands::clone::rad_clone_unknown ... ok
test commands::clone::rad_clone_directory ... ok
test commands::clone::rad_clone_connect ... ok
test commands::clone::rad_clone_partial_fail ... ok
test commands::cob::rad_cob_multiset ... ok
test commands::clone::test_clone_without_seeds ... ok
test commands::cob::rad_cob_log ... ok
test commands::cob::rad_cob_migrate ... ok
test commands::cob::rad_cob_operations ... ok
test commands::cob::rad_cob_show ... ok
test commands::cob::rad_cob_update ... ok
test commands::cob::rad_cob_update_identity ... ok
test commands::cob::test_cob_deletion ... ok
test commands::cob::test_cob_replication ... ok
test commands::git::git_push_amend ... ok
test commands::git::git_push_and_fetch ... ok
test commands::git::git_push_canonical_lightweight_tags ... ok
test commands::git::git_push_diverge ... ok
test commands::git::git_push_force_with_lease ... ok
test commands::git::git_push_canonical ... ok
test commands::git::git_push_converge ... ok
test commands::id::rad_id_collaboration ... ignored, slow
test commands::git::git_push_rollback ... ok
test commands::id::rad_id ... ok
test commands::git::git_tag ... ok
test commands::id::rad_id_private ... ok
test commands::id::rad_id_conflict ... ok
test commands::id::rad_id_threshold_soft_fork ... ok
test commands::id::rad_id_threshold ... ok
test commands::id::rad_id_unknown_field ... ok
test commands::id::rad_id_update_delete_field ... ok
test commands::init::rad_init ... ignored, part of many other tests
test commands::id::rad_id_unauthorized_delegate ... ok
test commands::init::rad_init_detached_head ... ok
test commands::init::rad_init_bare ... ok
test commands::id::rad_id_multi_delegate ... ok
test commands::init::rad_init_existing ... ok
test commands::init::rad_init_existing_bare ... ok
test commands::init::rad_init_no_git ... ok
test commands::init::rad_init_no_seed ... ok
test commands::init::rad_init_private ... ok
test commands::init::rad_init_private_no_seed ... ok
test commands::init::rad_init_private_clone ... ok
test commands::inbox::rad_inbox ... ok
test commands::init::rad_init_private_clone_seed ... ok
test commands::init::rad_init_private_seed ... ok
test commands::init::rad_init_sync_not_connected ... ok
test commands::init::rad_init_sync_preferred ... ok
test commands::init::rad_init_with_existing_remote ... ok
test commands::init::rad_publish ... ok
test commands::issue::rad_issue ... ok
test commands::jj::rad_jj_bare ... ignored, the bare repository does not have a `rad` remote, and so it cannot determine the RID of the repository
test commands::jj::rad_jj_colocated_patch ... ok
test commands::issue::rad_issue_list ... ok
test commands::node::rad_node_connect ... ok
test commands::node::rad_node_connect_without_address ... ok
test commands::patch::rad_merge_after_update ... ok
test commands::node::rad_node ... ok
test commands::patch::rad_merge_no_ff ... ok
test commands::patch::rad_merge_via_push ... ok
test commands::patch::rad_patch_ahead_behind ... FAILED
test commands::patch::rad_patch ... ok
test commands::patch::rad_patch_change_base ... ok
test commands::patch::rad_patch_checkout ... ok
test commands::init::rad_init_sync_and_clone ... ok
test commands::init::rad_init_sync_timeout ... ok
test commands::patch::rad_patch_checkout_revision ... ok
test commands::patch::rad_patch_detached_head ... ok
test commands::patch::rad_patch_checkout_force ... ok
test commands::patch::rad_patch_diff ... ok
test commands::patch::rad_patch_draft ... ok
test commands::patch::rad_patch_edit ... ok
test commands::patch::rad_patch_fetch_2 ... ok
test commands::patch::rad_patch_fetch_1 ... ok
test commands::patch::rad_patch_merge_default_branch ... ok
test commands::patch::rad_patch_magic_push ... ok
test commands::patch::rad_patch_merge_draft ... ok
test commands::patch::rad_patch_delete ... ok
test commands::patch::rad_patch_merge_into_canonical_ref_branch ... ok
test commands::patch::rad_patch_merge_strict_destination ... ok
test commands::patch::rad_patch_merge_wrong_branch ... ok
test commands::patch::rad_patch_merge_on_first_push ... ok
test commands::patch::rad_patch_merge_unauthorized_branch ... ok
test commands::patch::rad_patch_open_explore ... ok
test commands::patch::rad_patch_revert_custom_branch ... ok
test commands::patch::rad_patch_revert_isolation ... ok
test commands::patch::rad_patch_revert_merge ... ok
test commands::patch::rad_patch_update ... ok
test commands::patch::rad_patch_review_no_options ... ok
test commands::patch::rad_patch_via_push ... ok
test commands::policy::rad_block ... ok
test commands::policy::rad_seed_and_follow ... ok
test commands::patch::rad_review_by_hunk ... ok
test commands::policy::rad_seed_policy_allow_no_scope ... ok
test commands::policy::rad_seed_scope ... ok
test commands::policy::rad_unseed ... ok
test commands::policy::rad_unseed_many ... ok
test commands::policy::rad_seed_many ... ok
test commands::sigpipe::config ... ok
test commands::sigpipe::help ... ok
test commands::sigpipe::rad_self ... ok
test commands::patch::rad_push_and_pull_patches ... ok
test commands::remote::rad_remote ... ok
test commands::sync::rad_sync_without_node ... ok
test commands::sync::rad_sync ... ok
test commands::utility::framework_home ... ok
test commands::utility::rad_auth ... ok
test commands::utility::rad_auth_errors ... ok
test commands::patch::rad_patch_pull_update ... ok
test commands::utility::rad_config ... ok
test commands::utility::rad_diff ... ok
test commands::utility::rad_clean ... ok
test commands::utility::rad_help ... ok
test commands::utility::rad_inspect ... ok
test commands::utility::rad_key_mismatch ... ok
test commands::utility::rad_self ... ok
test commands::utility::rad_warn_ipv6 ... ok
test commands::utility::rad_warn_old_nodes ... ok
test commands::sync::rad_fetch ... ok
test commands::watch::rad_watch ... ok
test rad_remote ... ok
test commands::sync::test_replication_via_seed ... ok
test commands::workflow::rad_workflow ... ok
test commands::utility::rad_fork ... ok
failures:
---- commands::patch::rad_patch_ahead_behind stdout ----
1780414893 test: rad-init:6: `rad init --name heartwood --description Radicle Heartwood Protocol & Stack --no-confirm --public -v` @ /tmp/.tmpHkXJUY/alice/work
1780414893 test: rad-init:28: `rad init` @ /tmp/.tmpHkXJUY/alice/work
1780414893 test: rad-init:35: `rad ls` @ /tmp/.tmpHkXJUY/alice/work
1780414893 test: rad-init:46: `rad node inventory` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:6: `git checkout -q master` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:7: `git add CONTRIBUTORS` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:8: `git commit -a -q -m Add contributors` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:9: `git push rad master` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:10: `cat CONTRIBUTORS` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:16: `git checkout -q -b feature/1` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:17: `sed -i $a Alan K CONTRIBUTORS` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:18: `git commit -a -q -m Add Alan` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:24: `git checkout -q master` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:25: `sed -i $a Jason Bourne CONTRIBUTORS` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:26: `git commit -a -q -m Add Jason` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:27: `git push rad master` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:28: `git log --graph --decorate --abbrev-commit --pretty=oneline --all` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:39: `git push rad feature/1:refs/patches` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:47: `rad patch list` @ /tmp/.tmpHkXJUY/alice/work
1780414894 test: rad-patch-ahead-behind:58: `rad patch show -v -p 217f050` @ /tmp/.tmpHkXJUY/alice/work
thread 'commands::patch::rad_patch_ahead_behind' (33128) panicked at crates/radicle-cli-test/src/lib.rs:502:36:
--- Expected
++++ actual: stdout
1 1 | ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
2 2 | │ Title Add Alan │
3 3 | │ Patch 217f050f8891def8fb863f7c0b4f85c89f97299d │
4 4 | │ Author alice (you) │
5 5 | │ Head 5c88a79d75f5c2b4cc51ee6f163d2db91ee198d7 │
6 6 | │ Base f64fb2c8fe28f7c458c72ec8d700373924794943 │
7 + │ Target refs/heads/master │
7 8 | │ Branches feature/1 │
8 9 | │ Commits ahead 1, behind 1 │
9 10 | │ Status open │
10 11 | ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
11 12 | │ 5c88a79 Add Alan │
⋮
25 26 | +++ b/CONTRIBUTORS
26 27 | @@ -1 +1,2 @@
27 28 | Alice Jones
28 29 | +Alan K
29 30 |
Exit status: 0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
commands::patch::rad_patch_ahead_behind
test result: FAILED. 125 passed; 1 failed; 3 ignored; 0 measured; 0 filtered out; finished in 75.44s
error: test failed, to rerun pass `-p radicle-cli --test commands`
Running unittests src/lib.rs (target/debug/deps/radicle_cli_test-840c41f4d04ff03d)
running 3 tests
test tests::test_parse ... ok
test tests::test_run ... ok
test tests::test_example_spaced_brackets ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_cob-1ff8ee99f73a113c)
running 9 tests
test object::tests::test_serde ... ok
test tests::git::roundtrip ... ok
test tests::git::list_cobs ... ok
test tests::git::traverse_cobs ... ok
test type_name::test::invalid_typenames ... ok
test type_name::test::valid_typenames ... ok
test tests::invalid_parse_refstr ... ok
test tests::git::update_cob ... ok
test tests::parse_refstr ... ok
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
Running unittests src/lib.rs (target/debug/deps/radicle_core-f9d12dcddf722a8f)
running 4 tests
test repo::test::valid ... ok
test repo::test::invalid ... ok
test repo::test::assert_prop_roundtrip_parse ... ok
test repo::serde_impls::test::assert_prop_roundtrip_serde_json ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_crypto-296ceac40b7fe69b)
running 11 tests
test ssh::agent::test::test_agent_encoding_remove ... ok
test ssh::agent::test::test_agent_encoding_sign ... ok
test ssh::fmt::test::test_fingerprint ... ok
test ssh::fmt::test::test_key ... ok
test ssh::keystore::tests::test_init_no_passphrase ... ok
test tests::prop_encode_decode ... ok
test tests::test_e25519_dh ... ok
test tests::test_encode_decode ... ok
test tests::prop_key_equality ... ok
test ssh::keystore::tests::test_signer ... ok
test ssh::keystore::tests::test_init_passphrase ... ok
test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.82s
Running unittests src/lib.rs (target/debug/deps/radicle_dag-e10cdde88570a8e0)
running 20 tests
test tests::test_contains ... ok
test tests::test_cycle ... ok
test tests::test_dependencies ... ok
test tests::test_fold_diamond ... ok
test tests::test_fold_multiple_roots ... ok
test tests::test_fold_sorting_1 ... ok
test tests::test_diamond ... ok
test tests::test_fold_reject ... ok
test tests::test_fold_sorting_2 ... ok
test tests::test_get ... ok
test tests::test_len ... ok
test tests::test_complex ... ok
test tests::test_is_empty ... ok
test tests::test_merge_1 ... ok
test tests::test_merge_2 ... ok
test tests::test_prune_1 ... ok
test tests::test_prune_2 ... ok
test tests::test_prune_by_sorting ... ok
test tests::test_remove ... ok
test tests::test_siblings ... ok
test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_fetch-92b111a684cd2a9a)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_git_metadata-41b02b9ef3e2236d)
running 24 tests
test commit::parse::test::error::invalid_parent ... ok
test commit::parse::test::error::invalid_committer ... ok
test commit::parse::test::error::invalid_author ... ok
test commit::parse::test::error::invalid_format_continuation_without_preceding_header ... ok
test commit::parse::test::error::invalid_tree ... ok
test commit::parse::test::error::missing_author ... ok
test commit::parse::test::error::missing_committer ... ok
test commit::parse::test::error::missing_header_body_separator ... ok
test commit::parse::test::error::missing_tree_empty_header ... ok
test commit::parse::test::error::missing_tree_wrong_first_line ... ok
test commit::parse::test::success::commit_gpgsig_is_preserved_and_strip_removes_it ... ok
test commit::parse::test::success::commit_last_paragraph_kept_in_message_when_not_all_trailers ... ok
test commit::parse::test::success::commit_with_extra_headers ... ok
test commit::parse::test::success::commit_with_multiline_gpgsig ... ok
test commit::parse::test::success::commit_with_single_parent ... ok
test commit::parse::test::success::merge_commit ... ok
test commit::parse::test::success::commit_with_trailers ... ok
test commit::parse::test::success::root_commit ... ok
test commit::parse::test::success::roundtrip ... ok
test commit::parse::test::unit::body_last_paragraph_not_trailers_stays_in_message ... ok
test commit::parse::test::unit::body_no_paragraph_separator_means_no_trailers ... ok
test commit::parse::test::unit::trailers_accepts_empty_input ... ok
test commit::parse::test::unit::trailers_rejects_invalid_token_chars ... ok
test commit::parse::test::unit::trailers_rejects_line_without_separator ... ok
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_git_ref_format-2868a65b3ff2c590)
running 9 tests
test test::component ... ok
test test::pattern ... ok
test test::qualified ... ok
test test::component_invalid - should panic ... ok
test test::qualified_pattern ... ok
test test::qualified_invalid - should panic ... ok
test test::qualified_pattern_invalid - should panic ... ok
test test::refname ... ok
test test::refname_invalid - should panic ... ok
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_localtime-ec55a7767b981c91)
running 1 test
test serde_impls::test::test_localtime ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_log-aa8a5607eeb05b0d)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_node-d1668eea4de6589f)
running 80 tests
test reactor::timer::tests::test_next ... ok
test reactor::timer::tests::test_wake ... ok
test reactor::timer::tests::test_wake_exact ... ok
test control::tests::test_control_socket ... ok
test control::tests::test_seed_unseed ... ok
test fingerprint::tests::matching ... ok
test tests::e2e::fetch_does_not_contain_rad_sigrefs_parent ... ok
test tests::e2e::missing_default_branch ... ok
test tests::e2e::missing_delegate_default_branch ... ok
test tests::e2e::test_background_foreground_fetch ... ok
test tests::e2e::test_block_prevents_connection ... ok
test tests::e2e::test_block_active_connection ... ok
test tests::e2e::test_block_prevents_fetch ... ok
test tests::e2e::test_channel_reader_limit ... ok
test tests::e2e::test_catchup_on_refs_announcements ... ok
test tests::e2e::test_clone ... ok
test tests::e2e::test_connection_crossing ... ok
test tests::e2e::test_dont_fetch_owned_refs ... ok
test tests::e2e::test_fetch_emits_canonical_ref_update_partial_glob ... ok
test tests::e2e::test_fetch_followed_remotes ... ok
test tests::e2e::test_fetch_preserve_owned_refs ... ok
test tests::e2e::test_concurrent_fetches ... ok
test tests::e2e::test_fetch_unseeded ... ok
test tests::e2e::test_fetch_up_to_date ... ok
test tests::e2e::test_inventory_sync_basic ... ok
test tests::e2e::test_fetch_emits_canonical_ref_update ... ok
test tests::e2e::test_large_fetch ... ok
test tests::e2e::test_migrated_clone ... ok
test tests::e2e::test_missing_remote ... ok
test tests::e2e::test_multiple_offline_inits ... ok
test tests::e2e::test_non_fast_forward_identity_doc ... ok
test tests::e2e::test_non_fast_forward_sigrefs ... ok
test tests::e2e::test_outdated_delegate_sigrefs ... ok
test tests::e2e::test_outdated_sigrefs ... ok
test tests::e2e::test_inventory_sync_bridge ... ok
test tests::e2e::test_replication ... ok
test tests::e2e::test_inventory_sync_ring ... ok
test tests::e2e::test_inventory_sync_star ... ok
test tests::e2e::test_replication_invalid ... ok
test tests::e2e::test_replication_ref_in_sigrefs ... ok
test tests::test_announcement_rebroadcast ... ok
test tests::test_announcement_rebroadcast_duplicates ... ok
test tests::test_announcement_rebroadcast_timestamp_filtered ... ok
test tests::test_connection_kept_alive ... ok
test tests::test_announcement_relay ... ok
test tests::test_disconnecting_unresponsive_peer ... ok
test tests::test_fetch_missing_inventory_on_gossip ... ok
test tests::test_fetch_missing_inventory_on_schedule ... ok
test tests::test_inbound_connection ... ok
test tests::test_inventory_decode ... ok
test tests::test_init_and_seed ... ok
test tests::test_inventory_relay ... ok
test tests::test_inventory_relay_bad_timestamp ... ok
test tests::test_inventory_sync ... ok
test tests::test_maintain_connections ... ok
test tests::test_maintain_connections_failed_attempt ... ok
test tests::test_maintain_connections_transient ... ok
test tests::test_outbound_connection ... ok
test tests::test_inventory_pruning ... ok
test tests::test_persistent_peer_connect ... ok
test tests::test_persistent_peer_reconnect_success ... ok
test tests::test_persistent_peer_reconnect_attempt ... ok
test tests::test_ping_response ... ok
test tests::test_queued_fetch_from_ann_same_rid ... ok
test tests::test_queued_fetch_from_command_same_rid ... ok
test tests::test_queued_fetch_max_capacity ... ok
test tests::test_redundant_connect ... ok
test tests::test_refs_announcement_fetch_trusted_no_inventory ... ok
test tests::test_refs_announcement_followed ... ok
test tests::test_refs_announcement_no_subscribe ... ok
test tests::test_refs_announcement_offline ... ok
test tests::test_refs_announcement_relay_private ... ok
test tests::test_announcement_message_amplification ... ok
test tests::prop_inventory_exchange_dense ... ok
test tests::test_refs_announcement_relay_public ... ok
test wire::test::test_inventory_ann_with_extension ... ok
test wire::test::test_pong_message_with_extension ... ok
test tests::test_seeding ... ok
test tests::test_seed_repo_subscribe ... ok
test tests::test_refs_synced_event ... ok
test result: ok. 80 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 16.11s
Running unittests src/main.rs (target/debug/deps/radicle_node-19fd5db942ff136f)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_oid-f350725ba9f62eb5)
running 10 tests
test fmt::test::zero ... ok
test fmt::test::fixture ... ok
test fmt::test::git2 ... ok
test fmt::test::gix ... ok
test git2::test::zero ... ok
test gix::test::zero ... ok
test str::test::fixture ... ok
test str::test::git2_roundtrip ... ok
test str::test::gix_roundtrip ... ok
test str::test::zero ... ok
test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_protocol-d984e15bcd2f38e3)
running 99 tests
test deserializer::test::test_decode_next ... ok
test deserializer::test::test_unparsed ... ok
test deserializer::test::prop_decode_next ... ok
test fetcher::service::tests::test_fetch_coalescing_different_refs ... ok
test fetcher::test::queue::properties::capacity::bounded ... ok
test fetcher::test::queue::properties::capacity::rejection ... ok
test fetcher::test::queue::properties::dequeue::empty_queue_returns_none ... ok
test fetcher::test::queue::properties::dequeue::enables_reenqueue ... ok
test fetcher::test::queue::properties::dequeue::drained_queue_returns_none ... ok
test fetcher::test::queue::properties::capacity::restored_after_dequeue ... ok
test fetcher::test::queue::properties::capacity::capacity_reached_returns_same_item ... ok
test fetcher::test::queue::properties::fifo::interleaved_operations ... ok
test fetcher::test::queue::properties::equality::reflexive ... ok
test fetcher::test::queue::properties::fifo::ordering ... ok
test fetcher::test::queue::properties::merge::different_rid_accepted ... ok
test fetcher::test::queue::properties::equality::symmetric ... ok
test fetcher::test::queue::properties::merge::combines_refs ... ok
test fetcher::test::queue::properties::merge::longer_timeout_preserved ... ok
test fetcher::test::queue::properties::merge::does_not_increase_queue_length ... ok
test fetcher::test::queue::properties::equality::transitive ... ok
test fetcher::test::queue::unit::capacity_takes_precedence_over_merge_for_new_items ... ok
test fetcher::test::queue::unit::empty_refs_items_can_be_equal ... ok
test fetcher::test::queue::unit::max_timeout_accepted ... ok
test fetcher::test::queue::unit::merge_preserves_position_in_queue ... ok
test fetcher::test::queue::unit::zero_timeout_accepted ... ok
test fetcher::test::state::command::cancel::cancellation_is_isolated ... ok
test fetcher::test::state::command::cancel::non_existent_returns_unexpected ... ok
test fetcher::test::state::command::cancel::ongoing_and_queued ... ok
test fetcher::test::state::command::cancel::single_ongoing ... ok
test fetcher::test::state::command::fetch::fetch_after_previous_completed ... ok
test fetcher::test::state::command::fetch::fetch_at_capacity_enqueues ... ok
test fetcher::test::state::command::fetch::fetch_different_repo_same_node_within_capacity ... ok
test fetcher::test::state::command::fetch::fetch_duplicate_returns_already_fetching ... ok
test fetcher::test::state::command::fetch::fetch_queue_merge_empty_refs_fetches_all ... ok
test fetcher::test::state::command::fetch::fetch_queue_merge_takes_longer_timeout ... ok
test fetcher::test::state::command::fetch::fetch_queue_merges_already_queued ... ok
test fetcher::test::state::command::fetch::fetch_queue_rejected_capacity_reached ... ok
test fetcher::test::state::command::fetch::fetch_same_repo_different_nodes_queues_second ... ok
test fetcher::test::state::command::fetch::fetch_same_repo_different_refs_enqueues ... ok
test fetcher::test::state::command::fetch::fetch_start_first_fetch_for_node ... ok
test fetcher::test::queue::properties::merge::empty_refs_fetches_all ... ok
test fetcher::test::state::command::fetched::complete_single_ongoing ... ok
test fetcher::test::state::command::fetched::complete_one_of_multiple ... ok
test fetcher::test::state::command::fetched::non_existent_returns_not_found ... ok
test fetcher::test::state::command::fetched::complete_then_dequeue_fifo ... ok
test fetcher::test::state::concurrent::fetched_then_cancel ... ok
test fetcher::test::state::concurrent::interleaved_operations ... ok
test fetcher::test::state::config::min_queue_size ... ok
test fetcher::test::state::dequeue::cannot_dequeue_while_node_at_capacity ... ok
test fetcher::test::state::dequeue::empty_queue_returns_none ... ok
test fetcher::test::state::dequeue::maintains_fifo_order ... ok
test fetcher::test::state::invariant::queue_integrity_after_merge ... ok
test fetcher::test::queue::properties::merge::succeed_when_at_capacity ... ok
test fetcher::test::state::multinode::independent_queues ... ok
test service::filter::test::compatible ... ok
test service::filter::test::test_parameters ... ok
test service::filter::test::test_sizes ... ok
test service::gossip::store::test::test_announced ... ok
test service::limiter::test::test_limiter_different_rates ... ok
test service::limiter::test::test_limiter_multi ... ok
test service::limiter::test::test_limiter_refill ... ok
test fetcher::test::queue::properties::merge::same_rid_merges_anywhere_in_queue ... ok
test fetcher::test::state::config::high_concurrency ... ok
test service::message::tests::test_inventory_limit ... ok
test service::message::tests::test_ref_remote_limit ... ok
test wire::frame::test::test_encode_git_large ... ok
test wire::frame::test::test_stream_id ... ok
test fetcher::test::state::multinode::high_count ... ok
test wire::message::tests::prop_roundtrip_address ... ok
test service::message::tests::prop_refs_announcement_signing ... ok
test wire::message::tests::prop_zero_bytes_encode_decode ... ok
test wire::message::tests::test_inv_ann_max_size ... ok
test wire::message::tests::test_node_ann_max_size ... ok
test wire::message::tests::test_ping_encode_size_overflow - should panic ... ok
test wire::message::tests::test_pingpong_encode_max_size ... ok
test wire::message::tests::test_pong_encode_size_overflow - should panic ... ok
test service::message::tests::test_node_announcement_validate ... ok
test wire::tests::prop_oid ... ok
test wire::tests::prop_roundtrip_filter ... ok
test wire::tests::prop_roundtrip_publickey ... ok
test wire::tests::prop_roundtrip_refs ... ok
test wire::tests::prop_roundtrip_repoid ... ok
test wire::tests::prop_roundtrip_tuple ... ok
test wire::tests::prop_roundtrip_u16 ... ok
test wire::tests::prop_roundtrip_u32 ... ok
test wire::tests::prop_roundtrip_u64 ... ok
test wire::tests::prop_roundtrip_vec ... ok
test wire::tests::prop_signature ... ok
test wire::tests::prop_string ... ok
test wire::tests::test_alias ... ok
test wire::tests::test_bounded_vec_limit ... ok
test wire::tests::test_filter_invalid ... ok
test wire::tests::test_string ... ok
test wire::varint::test::prop_roundtrip_varint ... ok
test wire::varint::test::test_encode_overflow - should panic ... ok
test wire::varint::test::test_encoding ... ok
test wire::message::tests::prop_roundtrip_message ... ok
test wire::message::tests::test_refs_ann_max_size ... ok
test wire::message::tests::prop_message_decoder ... ok
test result: ok. 99 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.99s
Running unittests src/main.rs (target/debug/deps/git_remote_rad-ec460ed6e139fb1e)
running 12 tests
test protocol::tests::test_capabilities ... ok
test protocol::tests::test_empty ... ok
test protocol::tests::test_fetch ... ok
test protocol::tests::test_fetch_whitespace ... ok
test protocol::tests::test_invalid ... ok
test protocol::tests::test_list ... ok
test protocol::tests::test_list_for_push ... ok
test protocol::tests::test_option ... ok
test protocol::tests::test_option_whitespace_preservation ... ok
test protocol::tests::test_push_force ... ok
test protocol::tests::test_push_delete ... ok
test protocol::tests::test_push ... ok
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/main.rs (target/debug/deps/radicle_schemars-dd3c5e3b8cead261)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_signals-e91beff5378165d8)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_systemd-77e26f6a607513aa)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_term-afa03b1828121040)
running 21 tests
test cell::test::test_width ... ok
test ansi::tests::colors_disabled ... ok
test ansi::tests::colors_enabled ... ok
test ansi::tests::wrapping ... ok
test element::test::test_spaced ... ok
test element::test::test_width ... ok
test element::test::test_truncate ... ok
test table::test::test_table ... ok
test table::test::test_table_border_maximized ... ok
test table::test::test_table_border_truncated ... ok
test table::test::test_table_border ... ok
test table::test::test_table_truncate ... ok
test table::test::test_table_unicode ... ok
test table::test::test_truncate ... ok
test table::test::test_table_unicode_truncate ... ok
test textarea::test::test_wrapping ... ok
test textarea::test::test_wrapping_code_block ... ok
test textarea::test::test_wrapping_fenced_block ... ok
test textarea::test::test_wrapping_paragraphs ... ok
test vstack::test::test_vstack ... ok
test vstack::test::test_vstack_maximize ... ok
test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_windows-942926f7348a8563)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle
running 1 test
test crates/radicle/src/cob/patch/encoding/review.rs - cob::patch::encoding::review::Review (line 23) ... ignored
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_cli
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_cli_test
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_cob
running 1 test
test crates/radicle-cob/src/backend/stable.rs - backend::stable::with_advanced_timestamp (line 56) ... ignored
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
all doctests ran in 0.08s; merged doctests compilation took 0.08s
Doc-tests radicle_core
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_crypto
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_dag
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_fetch
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_git_metadata
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_git_ref_format
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_localtime
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_log
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_node
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_oid
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_protocol
running 6 tests
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::collect_from (line 30) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::max (line 96) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::push (line 122) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::truncate (line 50) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::with_capacity (line 66) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::unbound (line 149) ... ok
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
all doctests ran in 0.39s; merged doctests compilation took 0.37s
Doc-tests radicle_signals
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_systemd
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_term
running 1 test
test crates/radicle-term/src/table.rs - table (line 4) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
all doctests ran in 0.18s; merged doctests compilation took 0.18s
Doc-tests radicle_windows
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: 1 target failed:
`-p radicle-cli --test commands`
Exit code: 101
{
"response": "finished",
"result": "failure"
}