radicle: update radicle-git-ext
This change updates to the latest radicle-git-ext, which required a few changes within the radicle family of crates. One set of changes is that the radicle-git-ext crate subsumes git-commit, git-trailers, and git-ref-format -- so all those imports go through radicle-git-ext. The commit code requires that parent `Oid`s point to commits, which made some tests fail. One of the reasons for these failures is that the patch tests used fabricated `Oid`s and so the verification would fail. This is fixed by allowing the test context code to create `PatchRequest`s that create valid commits. The other reason for failure was that the identity `Action` passed an `Oid` that pointed to a blob. This is fixed by removing that code and making a note of it in documentation. The final major change was moving the Refspec type into git-ref-format and removing the AsRefspecs trait. The trait was not required and could its usage could be replaced by simpler code. Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com> X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
parent
293a76948f
commit
8508eab8fa
|
|
@ -912,22 +912,11 @@ dependencies = [
|
|||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git-commit"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42480682cb6d05a34304eaea858ff0008fe3ac8167e31eda360931c0b51a35c1"
|
||||
dependencies = [
|
||||
"git-trailers",
|
||||
"git2",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git-ref-format"
|
||||
version = "0.2.0"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c0eb2e3e4837359b843ab8cc5ad482bb84d4aa528153dc882dbbba44a2f4f47"
|
||||
checksum = "dee7296543085890905b49ee720902b25133a8d878b7221488d0450bbd965741"
|
||||
dependencies = [
|
||||
"git-ref-format-core",
|
||||
"git-ref-format-macro",
|
||||
|
|
@ -935,19 +924,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "git-ref-format-core"
|
||||
version = "0.2.0"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cbf4ccf1d4cd0ac87a1461d6e59be34aec975bc2097850d7c3e164e3ff66436"
|
||||
checksum = "54d2d2c6b5f0b38d20c51883abe9ee5879fb50e56a8255bb35ac0b0c679504c5"
|
||||
dependencies = [
|
||||
"minicbor",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git-ref-format-macro"
|
||||
version = "0.2.0"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3058716dac23a95ef68bd44c855c8e8368ee36feefc875bd8bdcb42ae582d98e"
|
||||
checksum = "f6b7367435d968adc55ba8cd0bb3c12a3cb517270f110b5300df9c6f0726c762"
|
||||
dependencies = [
|
||||
"git-ref-format-core",
|
||||
"proc-macro-error",
|
||||
|
|
@ -955,21 +945,11 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git-trailers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0934f57135449b88bea0e28efd80aab0c1b53692f8207c7e232086db824c7a8"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.16.1"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc"
|
||||
checksum = "8b7905cdfe33d31a88bb2e8419ddd054451f5432d1da9eaf2ac7804ee1ea12d5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
|
|
@ -1345,9 +1325,9 @@ checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
|||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.14.2+1.5.1"
|
||||
version = "0.15.1+1.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4"
|
||||
checksum = "fb4577bde8cdfc7d6a2a4bcb7b049598597de33ffd337276e9c7db6cd4a2cee7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -1437,10 +1417,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
name = "minicbor"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
checksum = "124d887cb82f0b1469bdac3d1b65764a381eed1a54fdab0070e5772b13114521"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
|
|
@ -1508,16 +1488,6 @@ dependencies = [
|
|||
"cyphergraphy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nonempty"
|
||||
version = "0.5.0"
|
||||
|
|
@ -1872,7 +1842,6 @@ dependencies = [
|
|||
"crossbeam-channel",
|
||||
"cyphernet",
|
||||
"fastrand",
|
||||
"git-ref-format",
|
||||
"git2",
|
||||
"localtime",
|
||||
"log",
|
||||
|
|
@ -1912,6 +1881,7 @@ dependencies = [
|
|||
"radicle-cli-test",
|
||||
"radicle-cob",
|
||||
"radicle-crypto",
|
||||
"radicle-git-ext",
|
||||
"radicle-node",
|
||||
"radicle-term",
|
||||
"serde",
|
||||
|
|
@ -1941,9 +1911,6 @@ name = "radicle-cob"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"git-commit",
|
||||
"git-ref-format",
|
||||
"git-trailers",
|
||||
"git2",
|
||||
"log",
|
||||
"nonempty 0.8.1",
|
||||
|
|
@ -1980,10 +1947,10 @@ dependencies = [
|
|||
"cyphernet",
|
||||
"ec25519",
|
||||
"fastrand",
|
||||
"git-ref-format",
|
||||
"multibase",
|
||||
"qcheck",
|
||||
"qcheck-macros",
|
||||
"radicle-git-ext",
|
||||
"radicle-ssh",
|
||||
"serde",
|
||||
"sqlite",
|
||||
|
|
@ -2002,9 +1969,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "radicle-git-ext"
|
||||
version = "0.2.1"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c68edd5604b96b0ede289513ce523b9cef82a9c4ab07f9e059a24036fc77a2da"
|
||||
checksum = "69d38277eb376789c3ed50a673c99b7fead98c172dd976060b029b527e605148"
|
||||
dependencies = [
|
||||
"git-ref-format",
|
||||
"git2",
|
||||
|
|
@ -2060,7 +2027,6 @@ dependencies = [
|
|||
"crossbeam-channel",
|
||||
"cyphernet",
|
||||
"fastrand",
|
||||
"git-ref-format",
|
||||
"io-reactor",
|
||||
"lexopt",
|
||||
"libc",
|
||||
|
|
@ -2072,6 +2038,7 @@ dependencies = [
|
|||
"qcheck-macros",
|
||||
"radicle",
|
||||
"radicle-crypto",
|
||||
"radicle-git-ext",
|
||||
"radicle-term",
|
||||
"scrypt",
|
||||
"serde",
|
||||
|
|
@ -2110,14 +2077,13 @@ checksum = "db20136bbc9ae63f3fec8e5a6c369f4902fac2244501b5dfc6d668e43475aaa4"
|
|||
|
||||
[[package]]
|
||||
name = "radicle-surf"
|
||||
version = "0.9.0"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10168a9ee60ee17511fe0062cc2fa3115654f0c1f2d1692d8109a3f254c855de"
|
||||
checksum = "7607a6c93d4cc399479cc0da0d259a42a0ed0b7ae2b051ed80ea8ed35f1246b1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"flate2",
|
||||
"git-ref-format",
|
||||
"git2",
|
||||
"log",
|
||||
"nonempty 0.5.0",
|
||||
|
|
@ -2149,9 +2115,9 @@ name = "radicle-tools"
|
|||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"git-ref-format",
|
||||
"radicle",
|
||||
"radicle-cli",
|
||||
"radicle-git-ext",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ json-color = { version = "0.7" }
|
|||
lexopt = { version = "0.2" }
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
nonempty = { version = "0.8" }
|
||||
# N.b. this is required to use macros, even though it's re-exported
|
||||
# through radicle
|
||||
radicle-git-ext = { version = "0", features = ["serde"] }
|
||||
serde = { version = "1.0" }
|
||||
serde_json = { version = "1" }
|
||||
serde_yaml = { version = "0.8" }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ delegates creating proposals concurrently.
|
|||
|
||||
```
|
||||
$ rad id edit --title "Add Alice" --description "Add Alice as a delegate" --delegates did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn --no-confirm
|
||||
✓ Identity proposal 'f4579d0a9a068453cb24da1ad048ca1bfdcb6d98' created
|
||||
✓ Identity proposal '04603c0d3ea4d137487024a51c9360adfc511114' created
|
||||
title: Add Alice
|
||||
description: Add Alice as a delegate
|
||||
status: ❲open❳
|
||||
|
|
@ -48,7 +48,7 @@ Quorum Reached
|
|||
|
||||
```
|
||||
$ rad id edit --title "Add Bob" --description "Add Bob as a delegate" --delegates did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG --no-confirm
|
||||
✓ Identity proposal '5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f' created
|
||||
✓ Identity proposal '3f6ae4f8645c8b0cbcd35ea924df7b13aca52774' created
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
status: ❲open❳
|
||||
|
|
@ -93,7 +93,7 @@ second proposal, then the identity would be out of date. So let's run
|
|||
through that and see what happens.
|
||||
|
||||
```
|
||||
$ rad id accept f4579d0a9a068453cb24da1ad048ca1bfdcb6d98 --no-confirm
|
||||
$ rad id accept 04603c0d3ea4d137487024a51c9360adfc511114 --no-confirm
|
||||
✓ Accepted proposal ✓
|
||||
title: Add Alice
|
||||
description: Add Alice as a delegate
|
||||
|
|
@ -137,7 +137,7 @@ Quorum Reached
|
|||
```
|
||||
|
||||
```
|
||||
$ rad id commit f4579d0a9a068453cb24da1ad048ca1bfdcb6d98 --no-confirm
|
||||
$ rad id commit 04603c0d3ea4d137487024a51c9360adfc511114 --no-confirm
|
||||
✓ Committed new identity '29ae4b72f5a315328f06fbd68dc1c396a2d5c45e'
|
||||
title: Add Alice
|
||||
description: Add Alice as a delegate
|
||||
|
|
@ -183,7 +183,7 @@ Quorum Reached
|
|||
Now, when we go to accept the second proposal:
|
||||
|
||||
```
|
||||
$ rad id accept 5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f --no-confirm
|
||||
$ rad id accept 3f6ae4f8645c8b0cbcd35ea924df7b13aca52774 --no-confirm
|
||||
! Warning: Revision is out of date
|
||||
! Warning: d96f425412c9f8ad5d9a9a05c9831d0728e2338d =/= 475cdfbc8662853dd132ec564e4f5eb0f152dd7f
|
||||
👉 Consider using 'rad id rebase' to update the proposal to the latest identity
|
||||
|
|
@ -238,19 +238,19 @@ Note that a warning was emitted:
|
|||
If we attempt to commit this revision, the command will fail:
|
||||
|
||||
```
|
||||
$ rad id commit 5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f --no-confirm
|
||||
$ rad id commit 3f6ae4f8645c8b0cbcd35ea924df7b13aca52774 --no-confirm
|
||||
! Warning: Revision is out of date
|
||||
! Warning: d96f425412c9f8ad5d9a9a05c9831d0728e2338d =/= 475cdfbc8662853dd132ec564e4f5eb0f152dd7f
|
||||
👉 Consider using 'rad id rebase' to update the proposal to the latest identity
|
||||
✗ Id failed: the identity hashes do match 'd96f425412c9f8ad5d9a9a05c9831d0728e2338d =/= 475cdfbc8662853dd132ec564e4f5eb0f152dd7f' for the revision '5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f'
|
||||
✗ Id failed: the identity hashes do match 'd96f425412c9f8ad5d9a9a05c9831d0728e2338d =/= 475cdfbc8662853dd132ec564e4f5eb0f152dd7f' for the revision '3f6ae4f8645c8b0cbcd35ea924df7b13aca52774'
|
||||
```
|
||||
|
||||
So, let's fix this by running a rebase on the proposal's revision:
|
||||
|
||||
```
|
||||
$ rad id rebase 5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f --no-confirm
|
||||
✓ Identity proposal '5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f' rebased
|
||||
✓ Revision '45477572abd02ea6fc3d3e710e034bb60c74038b'
|
||||
$ rad id rebase 3f6ae4f8645c8b0cbcd35ea924df7b13aca52774 --no-confirm
|
||||
✓ Identity proposal '3f6ae4f8645c8b0cbcd35ea924df7b13aca52774' rebased
|
||||
✓ Revision '42b9428df59ad349f706b1397750b75ea3b42574'
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
status: ❲open❳
|
||||
|
|
@ -293,9 +293,9 @@ Quorum Reached
|
|||
We can now update the proposal to have both keys in the delegates set:
|
||||
|
||||
```
|
||||
$ rad id update 5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f --rev 45477572abd02ea6fc3d3e710e034bb60c74038b --delegates did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn --no-confirm
|
||||
✓ Identity proposal '5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f' updated
|
||||
✓ Revision '66f68597d031f9678e704204bea5ce7f020c98e7'
|
||||
$ rad id update 3f6ae4f8645c8b0cbcd35ea924df7b13aca52774 --rev 42b9428df59ad349f706b1397750b75ea3b42574 --delegates did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn --no-confirm
|
||||
✓ Identity proposal '3f6ae4f8645c8b0cbcd35ea924df7b13aca52774' updated
|
||||
✓ Revision '1b4ded759249e4f76d19c3e580b4736bf2a2d1c4'
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
status: ❲open❳
|
||||
|
|
@ -338,10 +338,10 @@ Quorum Reached
|
|||
Finally, we can accept and commit this proposal, creating the final
|
||||
state of our new Radicle identity:
|
||||
|
||||
$ rad id show 5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f --revisions
|
||||
$ rad id show 3f6ae4f8645c8b0cbcd35ea924df7b13aca52774 --revisions
|
||||
|
||||
```
|
||||
$ rad id accept 5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f --rev 66f68597d031f9678e704204bea5ce7f020c98e7 --no-confirm
|
||||
$ rad id accept 3f6ae4f8645c8b0cbcd35ea924df7b13aca52774 --rev 1b4ded759249e4f76d19c3e580b4736bf2a2d1c4 --no-confirm
|
||||
✓ Accepted proposal ✓
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
|
|
@ -385,7 +385,7 @@ Quorum Reached
|
|||
```
|
||||
|
||||
```
|
||||
$ rad id commit 5d6c0faeeb5ed5e0d66c72d853a6131a35228d3f --rev 66f68597d031f9678e704204bea5ce7f020c98e7 --no-confirm
|
||||
$ rad id commit 3f6ae4f8645c8b0cbcd35ea924df7b13aca52774 --rev 1b4ded759249e4f76d19c3e580b4736bf2a2d1c4 --no-confirm
|
||||
✓ Committed new identity '60de897bc24898f6908fd1272633c0b15aa4096f'
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Let's add Bob as a delegate using their DID
|
|||
|
||||
```
|
||||
$ rad id edit --title "Add Bob" --description "Add Bob as a delegate" --delegates did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn --no-confirm
|
||||
✓ Identity proposal 'c2fe23ff387d5e040d0ed8eb2651942f5d0c2aa5' created
|
||||
✓ Identity proposal '0d396a83a5e1dda2b8929f7dc401d19dd1a79fb8' created
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
status: ❲open❳
|
||||
|
|
@ -89,7 +89,7 @@ Finally, we can see whether the `Quorum` was reached:
|
|||
Let's see what happens when we reject the change:
|
||||
|
||||
```
|
||||
$ rad id reject c2fe23ff387d5e040d0ed8eb2651942f5d0c2aa5 --no-confirm
|
||||
$ rad id reject 0d396a --no-confirm
|
||||
✓ Rejected proposal 👎
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
|
|
@ -145,7 +145,7 @@ increased to `1`.
|
|||
Instead, let's accept the proposal:
|
||||
|
||||
```
|
||||
$ rad id accept c2fe23f --no-confirm
|
||||
$ rad id accept 0d396a --no-confirm
|
||||
✓ Accepted proposal ✓
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
|
|
@ -207,7 +207,7 @@ As well as that, the `Quorum` has now been reached:
|
|||
At this point, we can commit the proposal and update the identity:
|
||||
|
||||
```
|
||||
$ rad id commit c2fe23ff387d5e040d0ed8eb2651942f5d0c2aa5 --no-confirm
|
||||
$ rad id commit 0d396a --no-confirm
|
||||
✓ Committed new identity 'c96e764965aaeff1c6ea3e5b97e2b9828773c8b0'
|
||||
title: Add Bob
|
||||
description: Add Bob as a delegate
|
||||
|
|
@ -255,7 +255,7 @@ the `--threshold` option:
|
|||
|
||||
```
|
||||
$ rad id edit --title "Update threshold" --description "Update to safer threshold" --threshold 2 --no-confirm
|
||||
✓ Identity proposal '27864167e392d63e77df2a7413c988857bd32839' created
|
||||
✓ Identity proposal 'f435d6e89c8f922ede691287c0d8b7f82afa591e' created
|
||||
title: Update threshold
|
||||
description: Update to safer threshold
|
||||
status: ❲open❳
|
||||
|
|
@ -298,8 +298,8 @@ Quorum Reached
|
|||
But we change our minds and decide to close the proposal instead:
|
||||
|
||||
```
|
||||
$ rad id close 27864167e392d63e77df2a7413c988857bd32839 --no-confirm
|
||||
✓ Closed identity proposal '27864167e392d63e77df2a7413c988857bd32839'
|
||||
$ rad id close f435d6 --no-confirm
|
||||
✓ Closed identity proposal 'f435d6e89c8f922ede691287c0d8b7f82afa591e'
|
||||
title: Update threshold
|
||||
description: Update to safer threshold
|
||||
status: ❲closed❳
|
||||
|
|
@ -348,15 +348,15 @@ Radicle identity, then we can use the list command:
|
|||
|
||||
```
|
||||
$ rad id list
|
||||
27864167e392d63e77df2a7413c988857bd32839 "Update threshold" ❲closed❳
|
||||
c2fe23ff387d5e040d0ed8eb2651942f5d0c2aa5 "Add Bob" ❲committed❳
|
||||
0d396a83a5e1dda2b8929f7dc401d19dd1a79fb8 "Add Bob" ❲committed❳
|
||||
f435d6e89c8f922ede691287c0d8b7f82afa591e "Update threshold" ❲closed❳
|
||||
```
|
||||
|
||||
And if we want to view the latest state of any proposal we can use the
|
||||
show command:
|
||||
|
||||
```
|
||||
$ rad id show 27864167e392d63e77df2a7413c988857bd32839
|
||||
$ rad id show f435d6
|
||||
title: Update threshold
|
||||
description: Update to safer threshold
|
||||
status: ❲closed❳
|
||||
|
|
|
|||
|
|
@ -513,6 +513,8 @@ fn test_clone_without_seeds() {
|
|||
|
||||
#[test]
|
||||
fn test_cob_replication() {
|
||||
logger::init(log::Level::Debug);
|
||||
|
||||
let mut environment = Environment::new();
|
||||
let working = tempfile::tempdir().unwrap();
|
||||
let mut alice = environment.node("alice");
|
||||
|
|
|
|||
|
|
@ -14,17 +14,14 @@ keywords = ["radicle", "collaborative objects", "cob", "cobs"]
|
|||
|
||||
[dependencies]
|
||||
fastrand = { version = "1.9.0" }
|
||||
git-commit = { version = "0.3" }
|
||||
git-ref-format = { version = "0.2" }
|
||||
git-trailers = { version = "0.1" }
|
||||
log = { version = "0.4.17" }
|
||||
nonempty = { version = "0.8.1", features = ["serialize"] }
|
||||
radicle-git-ext = { version = "0" }
|
||||
radicle-git-ext = { version = "0", features = ["serde"] }
|
||||
serde_json = { version = "1.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
|
||||
[dependencies.git2]
|
||||
version = "0.16.1"
|
||||
version = "0.17.0"
|
||||
default-features = false
|
||||
features = ["vendored-libgit2"]
|
||||
|
||||
|
|
@ -43,7 +40,6 @@ features = ["derive"]
|
|||
|
||||
[dev-dependencies]
|
||||
fastrand = { version = "1.9.0", default-features = false }
|
||||
git-ref-format = { version = "0.2", features = ["macro"] }
|
||||
tempfile = { version = "3" }
|
||||
qcheck = { version = "1", default-features = false }
|
||||
qcheck-macros = { version = "1", default-features = false }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use git_commit::{self as commit, Commit};
|
||||
use git_ext::author;
|
||||
use git_ext::author::Author;
|
||||
use git_ext::commit::{headers::Headers, Commit};
|
||||
use git_ext::Oid;
|
||||
use git_trailers::OwnedTrailer;
|
||||
use nonempty::NonEmpty;
|
||||
use radicle_git_ext::commit::trailers::OwnedTrailer;
|
||||
|
||||
use crate::history::entry::Timestamp;
|
||||
use crate::signatures;
|
||||
|
|
@ -23,14 +25,16 @@ pub mod error {
|
|||
use std::str::Utf8Error;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use git_ext::commit;
|
||||
use git_ext::Oid;
|
||||
use git_trailers::Error as TrailerError;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::signatures::error::Signatures;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Create {
|
||||
#[error(transparent)]
|
||||
WriteCommit(#[from] commit::error::Write),
|
||||
#[error(transparent)]
|
||||
FromUtf8(#[from] FromUtf8Error),
|
||||
#[error(transparent)]
|
||||
|
|
@ -46,7 +50,7 @@ pub mod error {
|
|||
#[derive(Debug, Error)]
|
||||
pub enum Load {
|
||||
#[error(transparent)]
|
||||
Read(#[from] git_commit::error::Read),
|
||||
Read(#[from] commit::error::Read),
|
||||
#[error(transparent)]
|
||||
Signatures(#[from] Signatures),
|
||||
#[error(transparent)]
|
||||
|
|
@ -73,8 +77,6 @@ pub mod error {
|
|||
ResourceTrailer(#[from] super::trailers::error::InvalidResourceTrailer),
|
||||
#[error("non utf-8 characters in commit message")]
|
||||
Utf8(#[from] FromUtf8Error),
|
||||
#[error(transparent)]
|
||||
Trailer(#[from] TrailerError),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +264,7 @@ where
|
|||
let author = repo.signature()?;
|
||||
let timestamp = author.when().seconds();
|
||||
|
||||
let mut headers = commit::Headers::new();
|
||||
let mut headers = Headers::new();
|
||||
headers.push(
|
||||
"gpgsig",
|
||||
signature
|
||||
|
|
@ -270,13 +272,13 @@ where
|
|||
.map_err(signatures::error::Signatures::from)?
|
||||
.as_str(),
|
||||
);
|
||||
let author = commit::Author::try_from(&author)?;
|
||||
let author = Author::try_from(&author)?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let (author, timestamp) = if let Ok(s) = std::env::var(crate::git::RAD_COMMIT_TIME) {
|
||||
let timestamp = s.trim().parse::<i64>().unwrap();
|
||||
let author = commit::Author {
|
||||
time: git_commit::author::Time::new(timestamp, 0),
|
||||
let author = Author {
|
||||
time: author::Time::new(timestamp, 0),
|
||||
..author
|
||||
};
|
||||
(author, timestamp)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use std::{convert::TryFrom as _, fmt, ops::Deref, str::FromStr};
|
||||
|
||||
use git_ext::ref_format::{Component, RefString};
|
||||
use git_ext::Oid;
|
||||
use git_ref_format::{Component, RefString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ impl CollaborativeObject {
|
|||
/// * The parsing of the [`TypeName`] fails
|
||||
pub fn parse_refstr<R>(name: &R) -> Option<(TypeName, ObjectId)>
|
||||
where
|
||||
R: AsRef<git_ref_format::RefStr>,
|
||||
R: AsRef<git_ext::ref_format::RefStr>,
|
||||
{
|
||||
use git_ref_format::Qualified;
|
||||
use git_ext::ref_format::Qualified;
|
||||
let name = name.as_ref();
|
||||
let refs_cobs = match name.to_namespaced() {
|
||||
None => Qualified::from_refstr(name)?,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use std::{collections::HashMap, error::Error};
|
||||
|
||||
use git_ext::ref_format::RefString;
|
||||
use git_ext::Oid;
|
||||
use git_ref_format::RefString;
|
||||
|
||||
use crate::change::Change;
|
||||
use crate::{ObjectId, TypeName};
|
||||
|
|
@ -95,7 +95,7 @@ pub trait Storage {
|
|||
pub mod convert {
|
||||
use std::str;
|
||||
|
||||
use git_ref_format::RefString;
|
||||
use git_ext::ref_format::RefString;
|
||||
use thiserror::Error;
|
||||
|
||||
use super::{Commit, Reference};
|
||||
|
|
@ -109,7 +109,7 @@ pub mod convert {
|
|||
err: git2::Error,
|
||||
},
|
||||
#[error(transparent)]
|
||||
Ref(#[from] git_ref_format::Error),
|
||||
Ref(#[from] git_ext::ref_format::Error),
|
||||
#[error(transparent)]
|
||||
Utf8(#[from] str::Utf8Error),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ use std::{
|
|||
};
|
||||
|
||||
use crypto::{ssh, PublicKey};
|
||||
use git_commit::{
|
||||
use git_ext::commit::{
|
||||
headers::Signature::{Pgp, Ssh},
|
||||
Commit,
|
||||
Signature::{Pgp, Ssh},
|
||||
};
|
||||
|
||||
pub use ssh::ExtendedSignature;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub mod error {
|
|||
#[error(transparent)]
|
||||
Git(#[from] git2::Error),
|
||||
#[error(transparent)]
|
||||
Format(#[from] git_ref_format::Error),
|
||||
Format(#[from] git_ext::ref_format::Error),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use crypto::test::signer::MockSigner;
|
||||
use git_ref_format::{refname, Component, RefString};
|
||||
use git_ext::ref_format::{refname, Component, RefString};
|
||||
use nonempty::nonempty;
|
||||
use qcheck::Arbitrary;
|
||||
use radicle_crypto::Signer;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright © 2019-2020 The Radicle Foundation <hello@radicle.foundation>
|
||||
|
||||
use git_trailers::{OwnedTrailer, Token, Trailer};
|
||||
use radicle_git_ext as ext;
|
||||
use git_ext::commit::trailers::{OwnedTrailer, Token, Trailer};
|
||||
use std::ops::Deref as _;
|
||||
|
||||
pub mod error {
|
||||
use thiserror::Error;
|
||||
|
|
@ -30,11 +30,10 @@ impl ResourceCommitTrailer {
|
|||
impl TryFrom<&Trailer<'_>> for ResourceCommitTrailer {
|
||||
type Error = error::InvalidResourceTrailer;
|
||||
|
||||
fn try_from(Trailer { values, token }: &Trailer<'_>) -> Result<Self, Self::Error> {
|
||||
let val = values.first().ok_or(Self::Error::NoValue)?;
|
||||
fn try_from(Trailer { value, token }: &Trailer<'_>) -> Result<Self, Self::Error> {
|
||||
let ext_oid =
|
||||
radicle_git_ext::Oid::try_from(val.as_ref()).map_err(|_| Self::Error::InvalidOid)?;
|
||||
if Some(token) == Token::try_from("Rad-Resource").ok().as_ref() {
|
||||
git_ext::Oid::try_from(value.as_ref()).map_err(|_| Self::Error::InvalidOid)?;
|
||||
if token.deref() == "Rad-Resource" {
|
||||
Ok(ResourceCommitTrailer(ext_oid.into()))
|
||||
} else {
|
||||
Err(Self::Error::WrongToken)
|
||||
|
|
@ -60,7 +59,7 @@ impl From<ResourceCommitTrailer> for Trailer<'_> {
|
|||
fn from(containing: ResourceCommitTrailer) -> Self {
|
||||
Trailer {
|
||||
token: Token::try_from("Rad-Resource").unwrap(),
|
||||
values: vec![containing.0.to_string().into()],
|
||||
value: containing.0.to_string().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -71,8 +70,8 @@ impl From<ResourceCommitTrailer> for OwnedTrailer {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ext::Oid> for ResourceCommitTrailer {
|
||||
fn from(oid: ext::Oid) -> Self {
|
||||
impl From<git_ext::Oid> for ResourceCommitTrailer {
|
||||
fn from(oid: git_ext::Oid) -> Self {
|
||||
Self(oid.into())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use git_ref_format::{Component, RefString};
|
||||
use git_ext::ref_format::{Component, RefString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ version = "1.8.0"
|
|||
default-features = false
|
||||
optional = true
|
||||
|
||||
[dependencies.git-ref-format]
|
||||
version = "0.2"
|
||||
[dependencies.radicle-git-ext]
|
||||
version = "0.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.ssh-key]
|
||||
|
|
|
|||
|
|
@ -360,13 +360,16 @@ impl PublicKey {
|
|||
multibase::encode(multibase::Base::Base58Btc, buf)
|
||||
}
|
||||
|
||||
#[cfg(feature = "git-ref-format")]
|
||||
pub fn to_namespace(&self) -> git_ref_format::RefString {
|
||||
git_ref_format::refname!("refs/namespaces").join(git_ref_format::Component::from(self))
|
||||
#[cfg(feature = "radicle-git-ext")]
|
||||
pub fn to_namespace(&self) -> radicle_git_ext::ref_format::RefString {
|
||||
use radicle_git_ext::ref_format::{refname, Component};
|
||||
refname!("refs/namespaces").join(Component::from(self))
|
||||
}
|
||||
|
||||
#[cfg(feature = "git-ref-format")]
|
||||
pub fn from_namespaced(refstr: &git_ref_format::Namespaced) -> Result<Self, PublicKeyError> {
|
||||
#[cfg(feature = "radicle-git-ext")]
|
||||
pub fn from_namespaced(
|
||||
refstr: &radicle_git_ext::ref_format::Namespaced,
|
||||
) -> Result<Self, PublicKeyError> {
|
||||
let name = refstr.namespace().into_inner();
|
||||
|
||||
Self::from_str(name.deref().as_str())
|
||||
|
|
@ -405,10 +408,10 @@ impl Deref for PublicKey {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "git-ref-format")]
|
||||
impl<'a> From<&PublicKey> for git_ref_format::Component<'a> {
|
||||
#[cfg(feature = "radicle-git-ext")]
|
||||
impl<'a> From<&PublicKey> for radicle_git_ext::ref_format::Component<'a> {
|
||||
fn from(id: &PublicKey) -> Self {
|
||||
use git_ref_format::{Component, RefString};
|
||||
use radicle_git_ext::ref_format::{Component, RefString};
|
||||
let refstr =
|
||||
RefString::try_from(id.to_string()).expect("encoded public keys are valid ref strings");
|
||||
Component::from_refstr(refstr).expect("encoded public keys are valid refname components")
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ flate2 = { version = "1" }
|
|||
hyper = { version = "0.14.17", default-features = false }
|
||||
lexopt = { version = "0.2.1" }
|
||||
nonempty = { version = "0.8.1", features = ["serialize"] }
|
||||
radicle-surf = { version = "0.9.0", default-features = false, features = ["serde"] }
|
||||
radicle-surf = { version = "0.10.3", default-features = false, features = ["serde"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["preserve_order"] }
|
||||
thiserror = { version = "1" }
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ colored = { version = "1.9.0" }
|
|||
crossbeam-channel = { version = "0.5.6" }
|
||||
cyphernet = { version = "0.2.0", features = ["tor", "dns", "ed25519", "p2p-ed25519"] }
|
||||
fastrand = { version = "1.9.0" }
|
||||
git-ref-format = { version = "0.2", features = ["serde", "macro"] }
|
||||
io-reactor = { version = "0.1.2", features = ["popol"] }
|
||||
lexopt = { version = "0.2.1" }
|
||||
libc = { version = "0.2.137" }
|
||||
|
|
@ -28,6 +27,9 @@ localtime = { version = "1.2.0" }
|
|||
netservices = { version = "0.2.2", features = ["io-reactor", "socket2"] }
|
||||
nonempty = { version = "0.8.1", features = ["serialize"] }
|
||||
qcheck = { version = "1", default-features = false, optional = true }
|
||||
# N.b. this is required to use macros, even though it's re-exported
|
||||
# through radicle
|
||||
radicle-git-ext = { version = "0", features = ["serde"] }
|
||||
sqlite = { version = "0.30.3" }
|
||||
sqlite3-src = { version = "0.4.0", features = ["bundled"] } # Ensures static linking
|
||||
scrypt = { version = "0.10.0", default-features = false }
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ impl Worker {
|
|||
channels: &mut Channels,
|
||||
) -> Result<(), FetchError>
|
||||
where
|
||||
S: fetch::AsRefspecs,
|
||||
S: IntoIterator<Item = fetch::Refspec>,
|
||||
{
|
||||
let mut tunnel = Tunnel::with(channels, stream, self.nid, remote, self.handle.clone())?;
|
||||
let tunnel_addr = tunnel.local_addr();
|
||||
|
|
@ -498,7 +498,6 @@ impl Worker {
|
|||
|
||||
let namespace = self.nid.to_namespace();
|
||||
let mut fetchspecs = specs
|
||||
.into_refspecs()
|
||||
.into_iter()
|
||||
// Filter out our own refs, if we aren't cloning.
|
||||
.filter(|fs| is_cloning || !fs.dst.starts_with(namespace.as_str()))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
mod refspecs;
|
||||
pub use refspecs::{AsRefspecs, Refspec, SpecialRefs};
|
||||
pub use refspecs::SpecialRefs;
|
||||
|
||||
pub mod error;
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ use std::collections::{BTreeMap, BTreeSet, HashSet};
|
|||
use std::ops::Deref;
|
||||
|
||||
use radicle::crypto::{PublicKey, Unverified, Verified};
|
||||
use radicle::git::refspec;
|
||||
use radicle::git::{url, Namespaced};
|
||||
use radicle::prelude::{Doc, Id, NodeId};
|
||||
use radicle::storage::git::Repository;
|
||||
|
|
@ -15,6 +16,8 @@ use radicle::storage::{Namespaces, RefUpdate, Remote, RemoteId};
|
|||
use radicle::storage::{ReadRepository, ReadStorage, WriteRepository, WriteStorage};
|
||||
use radicle::{git, Storage};
|
||||
|
||||
pub type Refspec = refspec::Refspec<git::PatternString, git::PatternString>;
|
||||
|
||||
/// The initial phase of staging a fetch from a remote.
|
||||
///
|
||||
/// The [`StagingPhaseInitial::refpsecs`] generated are to fetch the
|
||||
|
|
@ -146,15 +149,14 @@ impl<'a> StagingPhaseInitial<'a> {
|
|||
|
||||
/// Return the fetch refspecs for fetching the necessary `rad`
|
||||
/// references.
|
||||
pub fn refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
pub fn refspecs(&self) -> Vec<Refspec> {
|
||||
let id = git::PatternString::from(IDENTITY_BRANCH.clone().into_refstring());
|
||||
match self.repo {
|
||||
StagedRepository::Cloning(_) => Refspec {
|
||||
StagedRepository::Cloning(_) => vec![Refspec {
|
||||
src: id.clone(),
|
||||
dst: id,
|
||||
force: false,
|
||||
}
|
||||
.into_refspecs(),
|
||||
}],
|
||||
StagedRepository::Fetching(_) => SpecialRefs(self.namespaces.clone()).into_refspecs(),
|
||||
}
|
||||
}
|
||||
|
|
@ -229,7 +231,7 @@ impl<'a> StagingPhaseInitial<'a> {
|
|||
// don't need to be re-fetched from the remote.
|
||||
let mut remote = copy.remote_anonymous(&url)?;
|
||||
let refspecs: Vec<_> = Namespaces::All
|
||||
.into_refspecs()
|
||||
.to_refspecs()
|
||||
.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
|
|
@ -256,12 +258,19 @@ impl<'a> StagingPhaseInitial<'a> {
|
|||
impl<'a> StagingPhaseFinal<'a> {
|
||||
/// Return the fetch refspecs for fetching the necessary
|
||||
/// references.
|
||||
pub fn refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
pub fn refspecs(&self) -> Vec<Refspec> {
|
||||
match &self.repo {
|
||||
FinalStagedRepository::Cloning { trusted, .. } => {
|
||||
Namespaces::Trusted(trusted.clone()).as_refspecs()
|
||||
Namespaces::Trusted(trusted.clone()).to_refspecs()
|
||||
}
|
||||
FinalStagedRepository::Fetching { refs, .. } => refs.as_refspecs(),
|
||||
FinalStagedRepository::Fetching { refs, .. } => refs
|
||||
.iter()
|
||||
.map(|r| Refspec {
|
||||
src: r.clone().to_ref_string().into(),
|
||||
dst: r.clone().to_ref_string().into(),
|
||||
force: true,
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -358,8 +367,8 @@ impl<'a> StagingPhaseFinal<'a> {
|
|||
refspecs.push((
|
||||
remote.id,
|
||||
Refspec {
|
||||
src: id.clone(),
|
||||
dst: id,
|
||||
src: id.clone().into(),
|
||||
dst: id.into(),
|
||||
// Nb. The identity branch is allowed to be force-updated.
|
||||
force: true,
|
||||
}
|
||||
|
|
@ -368,8 +377,8 @@ impl<'a> StagingPhaseFinal<'a> {
|
|||
refspecs.push((
|
||||
remote.id,
|
||||
Refspec {
|
||||
src: sigrefs.clone(),
|
||||
dst: sigrefs,
|
||||
src: sigrefs.clone().into(),
|
||||
dst: sigrefs.into(),
|
||||
// Nb. Sigrefs are never force-updated.
|
||||
force: false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,16 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use radicle::crypto::PublicKey;
|
||||
use radicle::git;
|
||||
use radicle::git::refs::storage::{IDENTITY_BRANCH, SIGREFS_BRANCH};
|
||||
use radicle::storage;
|
||||
use radicle::storage::git::NAMESPACES_GLOB;
|
||||
use radicle::storage::{Namespaces, Remote};
|
||||
use radicle::storage::Namespaces;
|
||||
|
||||
/// A Git [refspec].
|
||||
///
|
||||
/// [refspec]: https://git-scm.com/book/en/v2/Git-Internals-The-Refspec
|
||||
// TODO(finto): this should go into radicle-git-ext/git-ref-format
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Refspec<T, U> {
|
||||
pub src: T,
|
||||
pub dst: U,
|
||||
pub force: bool,
|
||||
}
|
||||
|
||||
impl<T, U> fmt::Display for Refspec<T, U>
|
||||
where
|
||||
T: fmt::Display,
|
||||
U: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.force {
|
||||
f.write_char('+')?;
|
||||
}
|
||||
write!(f, "{}:{}", self.src, self.dst)
|
||||
}
|
||||
}
|
||||
use super::Refspec;
|
||||
|
||||
/// Radicle special refs, i.e. `refs/rad/*`.
|
||||
pub struct SpecialRefs(pub(super) Namespaces);
|
||||
|
||||
impl AsRefspecs for SpecialRefs {
|
||||
fn as_refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
impl SpecialRefs {
|
||||
pub fn into_refspecs(self) -> Vec<Refspec> {
|
||||
match &self.0 {
|
||||
Namespaces::All => {
|
||||
let id = NAMESPACES_GLOB.join(&*IDENTITY_BRANCH);
|
||||
|
|
@ -55,13 +28,9 @@ impl AsRefspecs for SpecialRefs {
|
|||
Namespaces::Trusted(pks) => pks.iter().flat_map(rad_refs).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_refspecs(self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
self.as_refspecs()
|
||||
}
|
||||
}
|
||||
|
||||
fn rad_refs(pk: &PublicKey) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
fn rad_refs(pk: &PublicKey) -> Vec<Refspec> {
|
||||
let ns = pk.to_namespace();
|
||||
let id = git::PatternString::from(ns.join(&*IDENTITY_BRANCH));
|
||||
let id = Refspec {
|
||||
|
|
@ -77,95 +46,3 @@ fn rad_refs(pk: &PublicKey) -> Vec<Refspec<git::PatternString, git::PatternStrin
|
|||
};
|
||||
vec![id, sigrefs]
|
||||
}
|
||||
|
||||
/// A conversion trait for producing a set of Git [`Refspec`]s.
|
||||
pub trait AsRefspecs
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// Convert the borrowed data into a set of [`Refspec`]s.
|
||||
fn as_refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>>;
|
||||
|
||||
/// Convert the owned data into a set of [`Refspec`]s.
|
||||
///
|
||||
/// Nb. The default implementation uses
|
||||
/// [`AsRefspecs::as_refspecs`], which may clone data.
|
||||
fn into_refspecs(self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
self.as_refspecs()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRefspecs for Namespaces {
|
||||
fn as_refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
match self {
|
||||
Namespaces::All => vec![Refspec {
|
||||
src: (*storage::git::NAMESPACES_GLOB).clone(),
|
||||
dst: (*storage::git::NAMESPACES_GLOB).clone(),
|
||||
force: true,
|
||||
}],
|
||||
Namespaces::Trusted(pks) => pks
|
||||
.iter()
|
||||
.map(|pk| {
|
||||
let ns = pk.to_namespace().with_pattern(git::refspec::STAR);
|
||||
Refspec {
|
||||
src: ns.clone(),
|
||||
dst: ns,
|
||||
force: true,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRefspecs for Refspec<git::PatternString, git::PatternString> {
|
||||
fn as_refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
vec![self.clone()]
|
||||
}
|
||||
|
||||
fn into_refspecs(self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
vec![self]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRefspecs> AsRefspecs for Vec<T> {
|
||||
fn as_refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
self.iter().flat_map(AsRefspecs::as_refspecs).collect()
|
||||
}
|
||||
|
||||
fn into_refspecs(self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
self.into_iter()
|
||||
.flat_map(AsRefspecs::into_refspecs)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRefspecs for Remote {
|
||||
fn as_refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
let ns = self.id.to_namespace();
|
||||
// Nb. the references in Refs are expected to be Qualified
|
||||
self.refs
|
||||
.iter()
|
||||
.map(|(name, _)| {
|
||||
let name = git::PatternString::from(ns.join(name));
|
||||
Refspec {
|
||||
src: name.clone(),
|
||||
dst: name,
|
||||
force: true,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRefspecs for BTreeSet<git::Namespaced<'a>> {
|
||||
fn as_refspecs(&self) -> Vec<Refspec<git::PatternString, git::PatternString>> {
|
||||
self.iter()
|
||||
.map(|r| Refspec {
|
||||
src: r.clone().to_ref_string().into(),
|
||||
dst: r.clone().to_ref_string().into(),
|
||||
force: true,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = { version = "1" }
|
||||
git-ref-format = { version = "0", features = ["serde", "macro"] }
|
||||
# N.b. this is required to use macros, even though it's re-exported
|
||||
# through radicle
|
||||
radicle-git-ext = { version = "0", features = ["serde"] }
|
||||
|
||||
[dependencies.radicle]
|
||||
version = "0"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ amplify = { version = "4.0.0-beta.7", default-features = false, features = ["std
|
|||
crossbeam-channel = { version = "0.5.6" }
|
||||
cyphernet = { version = "0.2.0", features = ["tor", "dns", "ed25519"] }
|
||||
fastrand = { version = "1.9.0" }
|
||||
git-ref-format = { version = "0", features = ["serde", "macro"] }
|
||||
multibase = { version = "0.9.1" }
|
||||
localtime = { version = "1.2.0" }
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
|
|
@ -30,7 +29,7 @@ thiserror = { version = "1" }
|
|||
unicode-normalization = { version = "0.1" }
|
||||
|
||||
[dependencies.git2]
|
||||
version = "0.16.1"
|
||||
version = "0.17.0"
|
||||
default-features = false
|
||||
features = ["vendored-libgit2"]
|
||||
|
||||
|
|
@ -45,7 +44,7 @@ version = "0"
|
|||
[dependencies.radicle-crypto]
|
||||
path = "../radicle-crypto"
|
||||
version = "0"
|
||||
features = ["git-ref-format", "ssh", "sqlite", "cyphernet"]
|
||||
features = ["radicle-git-ext", "ssh", "sqlite", "cyphernet"]
|
||||
|
||||
[dependencies.radicle-ssh]
|
||||
path = "../radicle-ssh"
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ pub enum Action {
|
|||
revision: RevisionId,
|
||||
},
|
||||
Revision {
|
||||
// N.b. the `Oid` is a blob identifier and not a commit, so we
|
||||
// do not need to propagate it via HistoryAction.
|
||||
current: Oid,
|
||||
proposed: Doc<Verified>,
|
||||
},
|
||||
|
|
@ -68,16 +70,7 @@ pub enum Action {
|
|||
},
|
||||
}
|
||||
|
||||
impl HistoryAction for Action {
|
||||
fn parents(&self) -> Vec<Oid> {
|
||||
match self {
|
||||
Self::Revision { current, .. } => {
|
||||
vec![*current]
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
impl HistoryAction for Action {}
|
||||
|
||||
/// Error applying an operation onto a state.
|
||||
#[derive(Error, Debug)]
|
||||
|
|
|
|||
|
|
@ -575,7 +575,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_create_and_assign() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
|
||||
let assignee: ActorId = arbitrary::gen(1);
|
||||
|
|
@ -612,7 +614,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_create_and_reassign() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
|
||||
let assignee: ActorId = arbitrary::gen(1);
|
||||
|
|
@ -642,7 +646,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_create_and_get() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let created = issues
|
||||
.create("My first issue", "Blah blah blah.", &[], &[], &signer)
|
||||
|
|
@ -664,7 +670,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_create_and_change_state() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let mut issue = issues
|
||||
.create("My first issue", "Blah blah blah.", &[], &[], &signer)
|
||||
|
|
@ -698,7 +706,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_create_and_unassign() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
|
||||
let assignee: ActorId = arbitrary::gen(1);
|
||||
|
|
@ -726,7 +736,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_edit_title() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let mut issue = issues
|
||||
.create("My first issue", "Blah blah blah.", &[], &[], &signer)
|
||||
|
|
@ -744,7 +756,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_react() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let mut issue = issues
|
||||
.create("My first issue", "Blah blah blah.", &[], &[], &signer)
|
||||
|
|
@ -767,7 +781,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_reply() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let mut issue = issues
|
||||
.create("My first issue", "Blah blah blah.", &[], &[], &signer)
|
||||
|
|
@ -805,7 +821,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_tag() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let bug_tag = Tag::new("bug").unwrap();
|
||||
let ux_tag = Tag::new("ux").unwrap();
|
||||
|
|
@ -835,7 +853,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_comment() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let author = *signer.public_key();
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let mut issue = issues
|
||||
|
|
@ -886,7 +906,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_all() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
|
||||
issues.create("First", "Blah", &[], &[], &signer).unwrap();
|
||||
|
|
@ -910,7 +932,9 @@ mod test {
|
|||
#[test]
|
||||
fn test_issue_multilines() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let test::setup::Context {
|
||||
signer, project, ..
|
||||
} = test::setup::Context::new(&tmp);
|
||||
let mut issues = Issues::open(&project).unwrap();
|
||||
let created = issues
|
||||
.create(
|
||||
|
|
|
|||
|
|
@ -1391,21 +1391,21 @@ mod test {
|
|||
#[test]
|
||||
fn test_patch_create_and_get() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let author: Did = signer.public_key().into();
|
||||
let target = MergeTarget::Delegates;
|
||||
let oid = git::Oid::from_str("e2a85016a458cd809c0ecee81f8c99613b0b0945").unwrap();
|
||||
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
target,
|
||||
base,
|
||||
oid,
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1426,8 +1426,8 @@ mod test {
|
|||
assert_eq!(revision.author.id(), &author);
|
||||
assert_eq!(revision.description(), "");
|
||||
assert_eq!(revision.discussion.len(), 0);
|
||||
assert_eq!(revision.oid, oid);
|
||||
assert_eq!(revision.base, base);
|
||||
assert_eq!(revision.oid, pr.oid);
|
||||
assert_eq!(revision.base, pr.base);
|
||||
|
||||
let (id, _, _) = patches.find_by_revision(rev_id).unwrap().unwrap();
|
||||
assert_eq!(id, patch_id);
|
||||
|
|
@ -1436,17 +1436,19 @@ mod test {
|
|||
#[test]
|
||||
fn test_patch_discussion() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
MergeTarget::Delegates,
|
||||
git::Oid::try_from("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap(),
|
||||
git::Oid::try_from("e2a85016a458cd809c0ecee81f8c99613b0b0945").unwrap(),
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1455,7 +1457,7 @@ mod test {
|
|||
let (revision_id, _) = patch.revisions().last().unwrap();
|
||||
assert!(
|
||||
patch
|
||||
.comment(*revision_id, "patch comment", None, &signer)
|
||||
.comment(*revision_id, "patch comment", None, signer)
|
||||
.is_ok(),
|
||||
"can comment on patch"
|
||||
);
|
||||
|
|
@ -1468,25 +1470,25 @@ mod test {
|
|||
#[test]
|
||||
fn test_patch_merge() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let oid = git::Oid::from_str("e2a85016a458cd809c0ecee81f8c99613b0b0945").unwrap();
|
||||
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let mut patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
MergeTarget::Delegates,
|
||||
base,
|
||||
oid,
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let id = patch.id;
|
||||
let (rid, _) = patch.revisions().next().unwrap();
|
||||
let _merge = patch.merge(*rid, base, &signer).unwrap();
|
||||
let _merge = patch.merge(*rid, pr.base, signer).unwrap();
|
||||
|
||||
let patch = patches.get(&id).unwrap().unwrap();
|
||||
|
||||
|
|
@ -1496,25 +1498,25 @@ mod test {
|
|||
|
||||
let merge = merges.first().unwrap();
|
||||
assert_eq!(merge.node, *signer.public_key());
|
||||
assert_eq!(merge.commit, base);
|
||||
assert_eq!(merge.commit, pr.base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_patch_review() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let mut patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
MergeTarget::Delegates,
|
||||
base,
|
||||
oid,
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1525,7 +1527,7 @@ mod test {
|
|||
Some(Verdict::Accept),
|
||||
Some("LGTM".to_owned()),
|
||||
vec![],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1626,20 +1628,20 @@ mod test {
|
|||
#[test]
|
||||
fn test_patch_review_edit() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let blob = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d133999").unwrap();
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let mut patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
MergeTarget::Delegates,
|
||||
base,
|
||||
oid,
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1650,7 +1652,7 @@ mod test {
|
|||
location: CodeLocation {
|
||||
blob,
|
||||
path: Path::new("file.rs").to_path_buf(),
|
||||
commit: oid,
|
||||
commit: pr.oid,
|
||||
lines: 1..3,
|
||||
},
|
||||
comment: "Nice!".to_owned(),
|
||||
|
|
@ -1662,7 +1664,7 @@ mod test {
|
|||
Some(Verdict::Accept),
|
||||
Some("LGTM".to_owned()),
|
||||
inline.clone(),
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
patch
|
||||
|
|
@ -1671,7 +1673,7 @@ mod test {
|
|||
Some(Verdict::Reject),
|
||||
Some("LGTM".to_owned()),
|
||||
vec![],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap(); // Overwrite the verdict.
|
||||
|
||||
|
|
@ -1691,7 +1693,7 @@ mod test {
|
|||
Some(Verdict::Reject),
|
||||
Some("Whoops!".to_owned()),
|
||||
vec![],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap(); // Overwrite the comment.
|
||||
let (_, revision) = patch.latest().unwrap();
|
||||
|
|
@ -1704,19 +1706,19 @@ mod test {
|
|||
#[test]
|
||||
fn test_patch_reject_to_accept() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let mut patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
MergeTarget::Delegates,
|
||||
base,
|
||||
oid,
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1729,7 +1731,7 @@ mod test {
|
|||
Some(Verdict::Reject),
|
||||
Some("Nah".to_owned()),
|
||||
vec![],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
patch
|
||||
|
|
@ -1738,7 +1740,7 @@ mod test {
|
|||
Some(Verdict::Accept),
|
||||
Some("LGTM".to_owned()),
|
||||
vec![],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1755,19 +1757,19 @@ mod test {
|
|||
#[test]
|
||||
fn test_patch_review_remove_fields() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let base = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let mut patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
MergeTarget::Delegates,
|
||||
base,
|
||||
oid,
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1780,10 +1782,10 @@ mod test {
|
|||
Some(Verdict::Reject),
|
||||
Some("Nah".to_owned()),
|
||||
vec![],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
patch.review(rid, None, None, vec![], &signer).unwrap();
|
||||
patch.review(rid, None, None, vec![], signer).unwrap();
|
||||
|
||||
let id = patch.id;
|
||||
let patch = patches.get_mut(&id).unwrap();
|
||||
|
|
@ -1797,20 +1799,19 @@ mod test {
|
|||
#[test]
|
||||
fn test_patch_update() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, project) = test::setup::context(&tmp);
|
||||
let base = git::Oid::from_str("af08e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let rev0_oid = git::Oid::from_str("518d5069f94c03427f694bb494ac1cd7d1339380").unwrap();
|
||||
let rev1_oid = git::Oid::from_str("cb18e95ada2bb38aadd8e6cef0963ce37a87add3").unwrap();
|
||||
let mut patches = Patches::open(&project).unwrap();
|
||||
let ctx = test::setup::Context::new(&tmp);
|
||||
let signer = &ctx.signer;
|
||||
let pr = ctx.branch_with(test::setup::initial_blobs());
|
||||
let mut patches = Patches::open(&ctx.project).unwrap();
|
||||
let mut patch = patches
|
||||
.create(
|
||||
"My first patch",
|
||||
"Blah blah blah.",
|
||||
MergeTarget::Delegates,
|
||||
base,
|
||||
rev0_oid,
|
||||
pr.base,
|
||||
pr.oid,
|
||||
&[],
|
||||
&signer,
|
||||
signer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1818,8 +1819,9 @@ mod test {
|
|||
assert_eq!(patch.description(), "Blah blah blah.");
|
||||
assert_eq!(patch.version(), 0);
|
||||
|
||||
let update = ctx.branch_with(test::setup::update_blobs());
|
||||
let _ = patch
|
||||
.update("I've made changes.", base, rev1_oid, &signer)
|
||||
.update("I've made changes.", pr.base, update.oid, signer)
|
||||
.unwrap();
|
||||
assert_eq!(patch.clock.get(), 2);
|
||||
|
||||
|
|
@ -1837,7 +1839,7 @@ mod test {
|
|||
let (_, revision) = patch.latest().unwrap();
|
||||
|
||||
assert_eq!(patch.version(), 1);
|
||||
assert_eq!(revision.oid, rev1_oid);
|
||||
assert_eq!(revision.oid, update.oid);
|
||||
assert_eq!(revision.description(), "I've made changes.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -497,7 +497,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_redact_comment() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let (_, signer, _) = radicle::test::setup::context(&tmp);
|
||||
let radicle::test::setup::Context { signer, .. } = radicle::test::setup::Context::new(&tmp);
|
||||
let repo = gen::<MockRepository>(1);
|
||||
let mut alice = Actor::new(signer);
|
||||
let mut thread = Thread::default();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::path::Path;
|
|||
use std::process::Command;
|
||||
use std::str::FromStr;
|
||||
|
||||
use git_ref_format as format;
|
||||
use git_ext::ref_format as format;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::collections::HashMap;
|
||||
|
|
@ -17,8 +17,8 @@ pub use ext::Error;
|
|||
pub use ext::NotFound;
|
||||
pub use ext::Oid;
|
||||
pub use git2 as raw;
|
||||
pub use git_ref_format as fmt;
|
||||
pub use git_ref_format::{
|
||||
pub use git_ext::ref_format as fmt;
|
||||
pub use git_ext::ref_format::{
|
||||
component, lit, name, qualified, refname, refspec,
|
||||
refspec::{PatternStr, PatternString},
|
||||
Component, Namespaced, Qualified, RefStr, RefString,
|
||||
|
|
@ -152,6 +152,7 @@ pub mod refs {
|
|||
|
||||
pub mod storage {
|
||||
use format::{
|
||||
lit,
|
||||
name::component,
|
||||
refspec::{self, PatternString},
|
||||
};
|
||||
|
|
@ -181,7 +182,7 @@ pub mod refs {
|
|||
/// `refs/namespaces/<remote>/refs/heads/<branch>`
|
||||
///
|
||||
pub fn branch<'a>(remote: &RemoteId, branch: &RefStr) -> Namespaced<'a> {
|
||||
Qualified::from(git_ref_format::lit::refs_heads(branch)).with_namespace(remote.into())
|
||||
Qualified::from(lit::refs_heads(branch)).with_namespace(remote.into())
|
||||
}
|
||||
|
||||
/// Get the branch where the project's identity document is stored.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::Deref;
|
||||
use std::{ffi::OsString, fmt, str::FromStr};
|
||||
|
||||
use git_ref_format::{Component, RefString};
|
||||
use git_ext::ref_format::{Component, RefString};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::crypto;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub extern crate radicle_crypto as crypto;
|
|||
|
||||
#[macro_use]
|
||||
extern crate amplify;
|
||||
extern crate radicle_git_ext as git_ext;
|
||||
|
||||
mod canonical;
|
||||
pub mod cob;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ pub use radicle_git_ext::Oid;
|
|||
|
||||
use crate::collections::HashMap;
|
||||
use crate::git::ext as git_ext;
|
||||
use crate::git::{Qualified, RefError, RefString};
|
||||
use crate::git::{refspec::Refspec, PatternString, Qualified, RefError, RefString};
|
||||
use crate::identity;
|
||||
use crate::identity::doc::DocError;
|
||||
use crate::identity::Did;
|
||||
use crate::identity::{Id, IdentityError};
|
||||
use crate::storage::git::NAMESPACES_GLOB;
|
||||
use crate::storage::refs::Refs;
|
||||
|
||||
use self::refs::SignedRefs;
|
||||
|
|
@ -38,6 +39,29 @@ pub enum Namespaces {
|
|||
Trusted(HashSet<PublicKey>),
|
||||
}
|
||||
|
||||
impl Namespaces {
|
||||
pub fn to_refspecs(&self) -> Vec<Refspec<PatternString, PatternString>> {
|
||||
match self {
|
||||
Namespaces::All => vec![Refspec {
|
||||
src: (*NAMESPACES_GLOB).clone(),
|
||||
dst: (*NAMESPACES_GLOB).clone(),
|
||||
force: true,
|
||||
}],
|
||||
Namespaces::Trusted(pks) => pks
|
||||
.iter()
|
||||
.map(|pk| {
|
||||
let ns = pk.to_namespace().with_pattern(git::refspec::STAR);
|
||||
Refspec {
|
||||
src: ns.clone(),
|
||||
dst: ns,
|
||||
force: true,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<PublicKey> for Namespaces {
|
||||
fn from_iter<T: IntoIterator<Item = PublicKey>>(iter: T) -> Self {
|
||||
Self::Trusted(iter.into_iter().collect())
|
||||
|
|
@ -236,6 +260,22 @@ impl Remote<Verified> {
|
|||
refs: self.refs.unverified(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_refspecs(&self) -> Vec<Refspec<PatternString, PatternString>> {
|
||||
let ns = self.id.to_namespace();
|
||||
// Nb. the references in Refs are expected to be Qualified
|
||||
self.refs
|
||||
.iter()
|
||||
.map(|(name, _)| {
|
||||
let name = PatternString::from(ns.join(name));
|
||||
Refspec {
|
||||
src: name.clone(),
|
||||
dst: name,
|
||||
force: true,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Deref for Remote<V> {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::path::{Path, PathBuf};
|
|||
use std::{fs, io};
|
||||
|
||||
use crypto::{Signer, Unverified, Verified};
|
||||
use git_ref_format::refspec;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::git;
|
||||
|
|
@ -25,10 +24,10 @@ pub use crate::storage::Error;
|
|||
|
||||
use super::RemoteId;
|
||||
|
||||
pub static NAMESPACES_GLOB: Lazy<refspec::PatternString> =
|
||||
Lazy::new(|| refspec::pattern!("refs/namespaces/*"));
|
||||
pub static NAMESPACES_GLOB: Lazy<git::refspec::PatternString> =
|
||||
Lazy::new(|| git::refspec::pattern!("refs/namespaces/*"));
|
||||
pub static SIGREFS_GLOB: Lazy<refspec::PatternString> =
|
||||
Lazy::new(|| refspec::pattern!("refs/namespaces/*/rad/sigrefs"));
|
||||
Lazy::new(|| git::refspec::pattern!("refs/namespaces/*/rad/sigrefs"));
|
||||
pub static CANONICAL_IDENTITY: Lazy<git::Qualified> = Lazy::new(|| {
|
||||
git::Qualified::from_components(
|
||||
git::name::component!("rad"),
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub enum TypesError {
|
|||
#[error(transparent)]
|
||||
ParseObjectId(#[from] cob::object::ParseObjectId),
|
||||
#[error(transparent)]
|
||||
RefFormat(#[from] git_ref_format::Error),
|
||||
RefFormat(#[from] git::fmt::Error),
|
||||
}
|
||||
|
||||
impl cob::Store for Repository {}
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ pub mod canonical {
|
|||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
InvalidRef(#[from] git_ref_format::Error),
|
||||
InvalidRef(#[from] git::fmt::Error),
|
||||
#[error("invalid canonical format")]
|
||||
InvalidFormat,
|
||||
#[error(transparent)]
|
||||
|
|
|
|||
|
|
@ -10,20 +10,108 @@ pub mod setup {
|
|||
use crate::crypto::test::signer::MockSigner;
|
||||
use crate::prelude::*;
|
||||
use crate::{
|
||||
git,
|
||||
profile::Home,
|
||||
rad::REMOTE_NAME,
|
||||
test::{fixtures, storage::git::Repository},
|
||||
Storage,
|
||||
};
|
||||
|
||||
pub fn context(tmp: &TempDir) -> (Storage, MockSigner, Repository) {
|
||||
let mut rng = fastrand::Rng::new();
|
||||
let signer = MockSigner::new(&mut rng);
|
||||
let home = tmp.path().join("home");
|
||||
let paths = Home::new(home.as_path()).unwrap();
|
||||
let storage = Storage::open(paths.storage()).unwrap();
|
||||
let (id, _, _, _) = fixtures::project(tmp.path().join("copy"), &storage, &signer).unwrap();
|
||||
let project = storage.repository(id).unwrap();
|
||||
#[derive(Debug)]
|
||||
pub struct BranchWith {
|
||||
pub base: git::Oid,
|
||||
pub oid: git::Oid,
|
||||
}
|
||||
|
||||
(storage, signer, project)
|
||||
pub struct Context {
|
||||
pub storage: Storage,
|
||||
pub signer: MockSigner,
|
||||
pub project: Repository,
|
||||
pub working: git2::Repository,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(tmp: &TempDir) -> Self {
|
||||
let mut rng = fastrand::Rng::new();
|
||||
let signer = MockSigner::new(&mut rng);
|
||||
let home = tmp.path().join("home");
|
||||
let paths = Home::new(home.as_path()).unwrap();
|
||||
let storage = Storage::open(paths.storage()).unwrap();
|
||||
let (id, _, working, _) =
|
||||
fixtures::project(tmp.path().join("copy"), &storage, &signer).unwrap();
|
||||
let project = storage.repository(id).unwrap();
|
||||
|
||||
Self {
|
||||
storage,
|
||||
signer,
|
||||
project,
|
||||
working,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn branch_with(
|
||||
&self,
|
||||
blobs: impl IntoIterator<Item = (String, Vec<u8>)>,
|
||||
) -> BranchWith {
|
||||
let refname = git::Qualified::from(git::lit::refs_heads(git::refname!("master")));
|
||||
let base = self.working.refname_to_id(refname.as_str()).unwrap();
|
||||
let parent = self.working.find_commit(base).unwrap();
|
||||
let oid = commit(&self.working, &refname, blobs, &[&parent]);
|
||||
|
||||
git::push(&self.working, &REMOTE_NAME, [(&refname, &refname)]).unwrap();
|
||||
BranchWith {
|
||||
base: base.into(),
|
||||
oid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initial_blobs() -> Vec<(String, Vec<u8>)> {
|
||||
vec![
|
||||
("README.md".to_string(), b"Hello, World!".to_vec()),
|
||||
(
|
||||
"CONTRIBUTING".to_string(),
|
||||
b"Please follow the rules".to_vec(),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn update_blobs() -> Vec<(String, Vec<u8>)> {
|
||||
vec![
|
||||
("README.md".to_string(), b"Hello, Radicle!".to_vec()),
|
||||
(
|
||||
"CONTRIBUTING".to_string(),
|
||||
b"Please follow the rules".to_vec(),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn commit(
|
||||
repo: &git2::Repository,
|
||||
refname: &git::Qualified,
|
||||
blobs: impl IntoIterator<Item = (String, Vec<u8>)>,
|
||||
parents: &[&git2::Commit<'_>],
|
||||
) -> git::Oid {
|
||||
let tree = {
|
||||
let mut tb = repo.treebuilder(None).unwrap();
|
||||
for (name, blob) in blobs.into_iter() {
|
||||
let oid = repo.blob(&blob).unwrap();
|
||||
tb.insert(name, oid, git2::FileMode::Blob.into()).unwrap();
|
||||
}
|
||||
tb.write().unwrap()
|
||||
};
|
||||
let tree = repo.find_tree(tree).unwrap();
|
||||
let author = git2::Signature::now("anonymous", "anonymous@example.com").unwrap();
|
||||
|
||||
repo.commit(
|
||||
Some(refname.as_str()),
|
||||
&author,
|
||||
&author,
|
||||
"test commit",
|
||||
&tree,
|
||||
parents,
|
||||
)
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ use std::collections::HashMap;
|
|||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use git_ref_format as fmt;
|
||||
use radicle_git_ext as git_ext;
|
||||
use git_ext::ref_format as fmt;
|
||||
|
||||
use crate::crypto::{Signer, Verified};
|
||||
use crate::identity::doc::{Doc, DocError, Id};
|
||||
|
|
|
|||
Loading…
Reference in New Issue