cli: test canonical tags
Add a test to exercise adding canonical reference rules and pushing new canonical tags. A change in `rad id` was required to allow adding a new payload to the document, i.e. one that does not already exist. Adding rules is also documented in the man page for `rad id`.
This commit is contained in:
parent
ff365e2d8b
commit
8201225166
|
|
@ -0,0 +1,213 @@
|
||||||
|
In this example, we will show how we can make other references become canonical.
|
||||||
|
To illustrate, we will use Git tags as an example. The storage of the repository
|
||||||
|
should look something like this by the end of the example:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
storage/z6cFWeWpnZNHh9rUW8phgA3b5yGt/refs
|
||||||
|
├── heads
|
||||||
|
│ └── main
|
||||||
|
├── namespaces
|
||||||
|
│ ├── z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
|
│ │ └── refs
|
||||||
|
│ │ ├── cobs
|
||||||
|
│ │ │ └── xyz.radicle.id
|
||||||
|
│ │ │ └── 865c48204bd7bb7f088b8db90ffdccb48cfa0a50
|
||||||
|
│ │ ├── heads
|
||||||
|
│ │ │ └── master
|
||||||
|
│ │ ├── tags
|
||||||
|
│ │ │ ├── v1.0-hotfix
|
||||||
|
│ │ │ └── v1.0
|
||||||
|
│ │ └── rad
|
||||||
|
│ │ ├── id
|
||||||
|
│ │ └── sigrefs
|
||||||
|
│ └── z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
|
│ └── refs
|
||||||
|
│ ├── heads
|
||||||
|
│ │ └── master
|
||||||
|
│ ├── tags
|
||||||
|
│ │ ├── v1.0-hotfix
|
||||||
|
│ │ └── v1.0
|
||||||
|
│ └── rad
|
||||||
|
│ ├── id
|
||||||
|
│ └── sigrefs
|
||||||
|
├── rad
|
||||||
|
│ └── id
|
||||||
|
└── tags
|
||||||
|
├── v1.0-hotfix
|
||||||
|
└── v1.0
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Noting that there are tags under `refs/tags` now.
|
||||||
|
|
||||||
|
To start, Alice will add a new payload to the repository identity. The
|
||||||
|
identifier for this payload is `xyz.radicle.crefs`. It contains a single field
|
||||||
|
with the key `rules`, and the value for this key is an array of rules. In this
|
||||||
|
case, we will have two rules: one for `refs/tags/*` and one for `refs/tags/qa/*`
|
||||||
|
(see RIP-0004 for more information on the rules).
|
||||||
|
|
||||||
|
``` ~alice
|
||||||
|
$ rad id update --title "Add canonical reference rules" --payload xyz.radicle.crefs rules '{ "refs/tags/*": { "threshold": 1, "allow": "delegates" }, "refs/tags/qa/*": { "threshold": 1, "allow": "delegates" }}'
|
||||||
|
✓ Identity revision [..] created
|
||||||
|
╭────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ Title Add canonical reference rules │
|
||||||
|
│ Revision c3349f07bfe6a82bbeb2989d2de4a918408f9831 │
|
||||||
|
│ Blob 85fa09e2de93b825d5231778dbb34143004a4bca │
|
||||||
|
│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │
|
||||||
|
│ State accepted │
|
||||||
|
│ Quorum yes │
|
||||||
|
├────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ✓ did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi alice (you) │
|
||||||
|
╰────────────────────────────────────────────────────────────────────────╯
|
||||||
|
|
||||||
|
@@ -1,13 +1,25 @@
|
||||||
|
{
|
||||||
|
"payload": {
|
||||||
|
+ "xyz.radicle.crefs": {
|
||||||
|
+ "rules": {
|
||||||
|
+ "refs/tags/*": {
|
||||||
|
+ "allow": "delegates",
|
||||||
|
+ "threshold": 1
|
||||||
|
+ },
|
||||||
|
+ "refs/tags/qa/*": {
|
||||||
|
+ "allow": "delegates",
|
||||||
|
+ "threshold": 1
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ },
|
||||||
|
"xyz.radicle.project": {
|
||||||
|
"defaultBranch": "master",
|
||||||
|
"description": "Radicle Heartwood Protocol & Stack",
|
||||||
|
"name": "heartwood"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delegates": [
|
||||||
|
"did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi"
|
||||||
|
],
|
||||||
|
"threshold": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, Alice will create a tag and push it:
|
||||||
|
|
||||||
|
``` ~alice
|
||||||
|
$ git tag v1.0-hotfix
|
||||||
|
```
|
||||||
|
|
||||||
|
``` ~alice (stderr)
|
||||||
|
$ git push rad --tags
|
||||||
|
✓ Canonical reference refs/tags/v1.0-hotfix updated to f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354
|
||||||
|
✓ Synced with 1 seed(s)
|
||||||
|
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
|
* [new tag] v1.0-hotfix -> v1.0-hotfix
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that the output included a message about a canonical reference being
|
||||||
|
updated:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
✓ Canonical reference refs/tags/v1.0-hotfix updated to f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354
|
||||||
|
~~~
|
||||||
|
|
||||||
|
On the other side, Bob performs a fetch and now has the tags locally:
|
||||||
|
|
||||||
|
``` ~bob (stderr)
|
||||||
|
$ cd heartwood
|
||||||
|
$ git fetch rad
|
||||||
|
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
|
||||||
|
* [new tag] v1.0-hotfix -> rad/tags/v1.0-hotfix
|
||||||
|
* [new tag] v1.0-hotfix -> v1.0-hotfix
|
||||||
|
```
|
||||||
|
|
||||||
|
In the next portion of this example, we want to show that using a `threshold` of
|
||||||
|
`2` requires both delegates. To do this, Bob creates a `master` reference, Alice
|
||||||
|
adds him as a remote, and adds him to the identity delegates, as well as setting
|
||||||
|
the `threshold` to `2` for the `refs/tags/*` rule:
|
||||||
|
|
||||||
|
``` ~bob
|
||||||
|
$ rad remote add z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --name alice
|
||||||
|
✓ Follow policy updated for z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (alice)
|
||||||
|
Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found 1 potential seed(s).
|
||||||
|
✓ Target met: 1 seed(s)
|
||||||
|
✓ Remote alice added
|
||||||
|
✓ Remote-tracking branch alice/master created for z6MknSL…StBU8Vi
|
||||||
|
$ git push rad master
|
||||||
|
```
|
||||||
|
|
||||||
|
``` ~alice
|
||||||
|
$ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob
|
||||||
|
✓ Follow policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (bob)
|
||||||
|
Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found 1 potential seed(s).
|
||||||
|
✓ Target met: 1 seed(s)
|
||||||
|
✓ Remote bob added
|
||||||
|
✓ Remote-tracking branch bob/master created for z6Mkt67…v4N1tRk
|
||||||
|
$ rad id update --title "Add Bob" --delegate did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --no-confirm -q
|
||||||
|
27ab0d77a95581c59ca9d30e679ceb06a9f758db
|
||||||
|
$ rad id update --title "Update canonical reference rules" --payload xyz.radicle.crefs rules '{ "refs/tags/*": { "threshold": 2, "allow": "delegates" }, "refs/tags/qa/*": { "threshold": 1, "allow": "delegates" } }' -q
|
||||||
|
dace164ba43fa51802697ec28d0b1965a9d7808b
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** here we have to specify all the rules again to update the `threshold`.
|
||||||
|
In reality, you can use `rad id update --edit` and edit the payload in your
|
||||||
|
editor instead.
|
||||||
|
|
||||||
|
``` ~bob
|
||||||
|
$ rad sync -f
|
||||||
|
Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found 1 potential seed(s).
|
||||||
|
✓ Target met: 1 seed(s)
|
||||||
|
🌱 Fetched from z6MknSL…StBU8Vi
|
||||||
|
$ rad id accept dace164ba43fa51802697ec28d0b1965a9d7808b -q
|
||||||
|
```
|
||||||
|
|
||||||
|
When Bob creates a new tag and pushes it, we see that there's a warning that
|
||||||
|
no quorum was found for the new tag:
|
||||||
|
|
||||||
|
``` ~bob (stderr)
|
||||||
|
$ git tag v2.0
|
||||||
|
$ git push rad --tags
|
||||||
|
warn: could not determine commit for canonical reference 'refs/tags/v2.0', no commit with at least 2 vote(s) found (threshold not met)
|
||||||
|
warn: it is recommended to find a commit to agree upon
|
||||||
|
✓ Synced with 1 seed(s)
|
||||||
|
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
|
* [new tag] v1.0-hotfix -> v1.0-hotfix
|
||||||
|
* [new tag] v2.0 -> v2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Alice can then fetch and checkout the new tag, create one on her side, and push
|
||||||
|
it:
|
||||||
|
|
||||||
|
``` ~alice (stderr)
|
||||||
|
$ git fetch bob
|
||||||
|
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
|
* [new tag] v1.0-hotfix -> bob/tags/v1.0-hotfix
|
||||||
|
* [new tag] v2.0 -> bob/tags/v2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
``` ~alice
|
||||||
|
$ git checkout bob/tags/v2.0
|
||||||
|
$ git tag v2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
``` ~alice (stderr)
|
||||||
|
$ git push rad --tags
|
||||||
|
✓ Canonical reference refs/tags/v2.0 updated to f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354
|
||||||
|
✓ Synced with 1 seed(s)
|
||||||
|
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
|
* [new tag] v2.0 -> v2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that Bob has also pushed this tag, we can see that the tag was made
|
||||||
|
canonical.
|
||||||
|
|
||||||
|
For the final portion of the example, we will show that both delegates aren't
|
||||||
|
required for pushing tags that match the rule `refs/tags/qa/*`. To show this,
|
||||||
|
Bob will create a tag and push it, and we should see that the canonical
|
||||||
|
reference is created:
|
||||||
|
|
||||||
|
``` ~bob (stderr)
|
||||||
|
$ git tag qa/v2.1
|
||||||
|
$ git push rad --tags
|
||||||
|
✓ Canonical reference refs/tags/qa/v2.1 updated to f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354
|
||||||
|
✓ Synced with 1 seed(s)
|
||||||
|
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
|
* [new tag] qa/v2.1 -> qa/v2.1
|
||||||
|
```
|
||||||
|
|
@ -2517,6 +2517,48 @@ fn git_tag() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn git_push_canonical_tags() {
|
||||||
|
let mut environment = Environment::new();
|
||||||
|
let alice = environment.node("alice");
|
||||||
|
let bob = environment.node("bob");
|
||||||
|
|
||||||
|
let rid = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
|
||||||
|
|
||||||
|
fixtures::repository(environment.work(&alice));
|
||||||
|
|
||||||
|
test(
|
||||||
|
"examples/rad-init.md",
|
||||||
|
environment.work(&alice),
|
||||||
|
Some(&alice.home),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let alice = alice.spawn();
|
||||||
|
let mut bob = bob.spawn();
|
||||||
|
|
||||||
|
bob.connect(&alice).converge([&alice]);
|
||||||
|
bob.clone(rid, environment.work(&bob)).unwrap();
|
||||||
|
formula(
|
||||||
|
&environment.tempdir(),
|
||||||
|
"examples/git/git-push-canonical-tags.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]
|
#[test]
|
||||||
fn rad_workflow() {
|
fn rad_workflow() {
|
||||||
let mut environment = Environment::new();
|
let mut environment = Environment::new();
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ rad-id - Manage changes to a Radicle repository's identity.
|
||||||
*rad id* _edit_ <revision-id> [--title <string>] [--description <string>] [<option>...] +
|
*rad id* _edit_ <revision-id> [--title <string>] [--description <string>] [<option>...] +
|
||||||
*rad id* _show_ <revision-id> [<option>...] +
|
*rad id* _show_ <revision-id> [<option>...] +
|
||||||
*rad id* _accept_ | _reject_ <revision-id> [<option>...] +
|
*rad id* _accept_ | _reject_ <revision-id> [<option>...] +
|
||||||
*rad id* _redact_ <revision-id> [<option>...]
|
*rad id* _redact_ <revision-id> [<option>...] +
|
||||||
|
|
||||||
== Description
|
== Description
|
||||||
|
|
||||||
|
|
@ -176,3 +176,49 @@ To remove a delegate and update the threshold, use the *--rescind* option:
|
||||||
As with adding a delegate, this change will require approval from the remaining
|
As with adding a delegate, this change will require approval from the remaining
|
||||||
delegates. Make sure you set an appropriate new threshold when removing
|
delegates. Make sure you set an appropriate new threshold when removing
|
||||||
delegates!
|
delegates!
|
||||||
|
|
||||||
|
=== Adding Canonical References Rules
|
||||||
|
|
||||||
|
To update the canonical reference rules of the project, use the `--payload
|
||||||
|
xyz.radicle.crefs` option while updating, `rules` as the key, and the rules
|
||||||
|
object as the value. Here is an example below:
|
||||||
|
|
||||||
|
$ rad id update --title "Update canonical reference rules" \
|
||||||
|
--payload xyz.radicle.crefs rules '{
|
||||||
|
"refs/heads/master": { "threshold": 1, "allow": "delegates" },
|
||||||
|
"refs/tags/*": { "threshold": 2, "allow": "delegates" },
|
||||||
|
"refs/tags/qa/*": { "threshold": 1, "allow": "delegates" }
|
||||||
|
}'
|
||||||
|
|
||||||
|
Alternatively, you can use the `--edit` option for the `update` command and edit
|
||||||
|
the payload directly. Here is an example of what that may look like:
|
||||||
|
|
||||||
|
{
|
||||||
|
"payload": {
|
||||||
|
"xyz.radicle.crefs": {
|
||||||
|
"rules": {
|
||||||
|
"refs/heads/master": {
|
||||||
|
"allow": "delegates",
|
||||||
|
"threshold": 1
|
||||||
|
},
|
||||||
|
"refs/tags/*": {
|
||||||
|
"allow": "delegates",
|
||||||
|
"threshold": 1
|
||||||
|
},
|
||||||
|
"refs/tags/qa/*": {
|
||||||
|
"allow": "delegates",
|
||||||
|
"threshold": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xyz.radicle.project": {
|
||||||
|
"defaultBranch": "master",
|
||||||
|
"description": "Radicle Heartwood Protocol & Stack",
|
||||||
|
"name": "heartwood"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delegates": [
|
||||||
|
"did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi"
|
||||||
|
],
|
||||||
|
"threshold": 1
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue