Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
fetch: allow fetch of annotated tags
Fintan Halpenny committed 2 years ago
commit 87d1cb50a0cb59cc0428425d1afb0ccfd889b36e
parent 9950182ee02a5b4db52fe87e0b846c4abe327425
4 files changed +154 -10
added radicle-cli/examples/git/git-tag.md
@@ -0,0 +1,70 @@
+
Alice creates an annotated tag and pushed to her `rad` remote:
+

+
``` ~alice
+
$ touch LICENSE
+
$ git add LICENSE
+
$ git commit -am "Add LICENSE"
+
[master 62d19fd] Add LICENSE
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 LICENSE
+
$ git tag v1.0 -a -m "Release v1.0"
+
```
+

+
``` ~alice (stderr)
+
$ git push rad v1.0 --tags
+
✓ Synced with 1 node(s)
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new tag]         v1.0 -> v1.0
+
```
+

+
Bob fetches the tag from Alice, by adding her as a remote:
+

+
``` ~bob
+
$ cd heartwood
+
$ rad remote add z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --name alice
+
✓ Follow policy updated for z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (alice)
+
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi..
+
✓ Remote alice added
+
✓ Remote-tracking branch alice/master created for z6MknSL…StBU8Vi
+
```
+

+
Bob is able to fetch Alice's tag into his working copy by using the
+
`--tags` flag:
+

+
``` ~bob (stderr)
+
$ git fetch alice --tags
+
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new tag]         v1.0       -> v1.0
+
```
+

+
Alice forcefully creates a new version of the tag (let's say she made
+
a mistake):
+

+
``` ~alice
+
$ git commit --allow-empty -m "Release: v1.0"
+
[master 8260c04] Release: v1.0
+
$ git tag v1.0 -f -a -m "Release v1.0"
+
Updated tag 'v1.0' (was be18ed6)
+
```
+

+
``` ~alice (stderr)
+
$ git push rad v1.0 -f
+
✓ Synced with 1 node(s)
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 + be18ed6...9dbdebc v1.0 -> v1.0 (forced update)
+
```
+

+
We ensure that Bob is still able to fetch from Alice and get the new
+
update of the tag:
+

+
``` ~bob
+
$ rad sync -f
+
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi..
+
✓ Fetched repository from 1 seed(s)
+
```
+

+
``` ~bob (stderr)
+
$ git fetch alice --tags -f
+
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 t [tag update]      v1.0       -> v1.0
+
```
modified radicle-cli/tests/commands.rs
@@ -2318,6 +2318,51 @@ fn git_push_and_fetch() {
}

#[test]
+
fn git_tag() {
+
    let mut environment = Environment::new();
+
    let alice = environment.node(Config::test(Alias::new("alice")));
+
    let bob = environment.node(Config::test(Alias::new("bob")));
+
    let working = environment.tmp().join("working");
+

+
    fixtures::repository(working.join("alice"));
+

+
    test(
+
        "examples/rad-init.md",
+
        working.join("alice"),
+
        Some(&alice.home),
+
        [],
+
    )
+
    .unwrap();
+

+
    let alice = alice.spawn();
+
    let mut bob = bob.spawn();
+

+
    bob.connect(&alice).converge([&alice]);
+

+
    test(
+
        "examples/rad-clone.md",
+
        &working.join("bob"),
+
        Some(&bob.home),
+
        [],
+
    )
+
    .unwrap();
+
    formula(&environment.tmp(), "examples/git/git-tag.md")
+
        .unwrap()
+
        .home(
+
            "alice",
+
            working.join("alice"),
+
            [("RAD_HOME", alice.home.path().display())],
+
        )
+
        .home(
+
            "bob",
+
            working.join("bob"),
+
            [("RAD_HOME", bob.home.path().display())],
+
        )
+
        .run()
+
        .unwrap();
+
}
+

+
#[test]
fn rad_workflow() {
    let mut environment = Environment::new();
    let alice = environment.node(Config::test(Alias::new("alice")));
modified radicle-fetch/src/git/repository.rs
@@ -1,7 +1,7 @@
pub mod error;

use either::Either;
-
use radicle::git::{Namespaced, Oid, Qualified};
+
use radicle::git::{self, Namespaced, Oid, Qualified};
use radicle::storage::git::Repository;

use super::refs::{Applied, Policy, RefUpdate, Update};
@@ -38,10 +38,29 @@ pub fn contains(repo: &Repository, oid: Oid) -> Result<bool, error::Contains> {
        .map_err(error::Contains)
}

-
pub fn ancestry(repo: &Repository, old: Oid, new: Oid) -> Result<Ancestry, error::Ancestry> {
-
    if !contains(repo, old)? || !contains(repo, new)? {
-
        return Err(error::Ancestry::Missing { a: old, b: new });
+
/// Find the object identified by `oid` and peel it to its associated
+
/// commit `Oid`.
+
///
+
/// # Errors
+
///
+
/// - The object was not found
+
/// - The object does not peel to a commit
+
/// - Attempting to find the object fails
+
fn find_and_peel(repo: &Repository, oid: Oid) -> Result<Oid, error::Ancestry> {
+
    match repo.backend.find_object(*oid, None) {
+
        Ok(object) => Ok(object
+
            .peel(git::raw::ObjectType::Commit)
+
            .map_err(|err| error::Ancestry::Peel { oid, err })?
+
            .id()
+
            .into()),
+
        Err(e) if git::is_not_found_err(&e) => Err(error::Ancestry::Missing { oid }),
+
        Err(err) => Err(error::Ancestry::Object { oid, err }),
    }
+
}
+

+
pub fn ancestry(repo: &Repository, old: Oid, new: Oid) -> Result<Ancestry, error::Ancestry> {
+
    let old = find_and_peel(repo, old)?;
+
    let new = find_and_peel(repo, new)?;

    if old == new {
        return Ok(Ancestry::Equal);
@@ -49,7 +68,7 @@ pub fn ancestry(repo: &Repository, old: Oid, new: Oid) -> Result<Ancestry, error

    let (ahead, behind) = repo
        .backend
-
        .graph_ahead_behind(new.into(), old.into())
+
        .graph_ahead_behind(*new, *old)
        .map_err(|err| error::Ancestry::Check { old, new, err })?;

    if ahead > 0 && behind == 0 {
modified radicle-fetch/src/git/repository/error.rs
@@ -7,17 +7,27 @@ pub struct Contains(#[source] pub raw::Error);

#[derive(Debug, Error)]
pub enum Ancestry {
-
    #[error("missing one of {a} or {b} while checking ancestry")]
-
    Missing { a: Oid, b: Oid },
-
    #[error(transparent)]
-
    Contains(#[from] Contains),
-
    #[error("failed to check ancestry for {old} and {new}")]
+
    #[error("missing {oid} while checking ancestry")]
+
    Missing { oid: Oid },
+
    #[error("failed to check ancestry for {old} and {new}: {err}")]
    Check {
        old: Oid,
        new: Oid,
        #[source]
        err: raw::Error,
    },
+
    #[error("failed to peel object to commit {oid}: {err}")]
+
    Peel {
+
        oid: Oid,
+
        #[source]
+
        err: raw::Error,
+
    },
+
    #[error("failed to find object {oid}: {err}")]
+
    Object {
+
        oid: Oid,
+
        #[source]
+
        err: raw::Error,
+
    },
}

#[derive(Debug, Error)]