cli: Test clone failure for unknown repo
This commit is contained in:
parent
69ac8be8fd
commit
b108342fab
|
|
@ -0,0 +1,7 @@
|
||||||
|
Trying to clone a repository that is not in our routing table returns an error:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rad clone rad:zVNuptPuk5XauitpCWSNVCXGGfXW
|
||||||
|
ok Tracking relationship established for rad:zVNuptPuk5XauitpCWSNVCXGGfXW
|
||||||
|
== Clone failed no seeds found for rad:zVNuptPuk5XauitpCWSNVCXGGfXW
|
||||||
|
```
|
||||||
|
|
@ -3,7 +3,7 @@ To create your first radicle project, navigate to a git repository, and run
|
||||||
the `init` command:
|
the `init` command:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm
|
$ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm --no-sync
|
||||||
|
|
||||||
Initializing local 🌱 project in .
|
Initializing local 🌱 project in .
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,8 @@ pub enum CloneError {
|
||||||
Payload(#[from] doc::PayloadError),
|
Payload(#[from] doc::PayloadError),
|
||||||
#[error("project error: {0}")]
|
#[error("project error: {0}")]
|
||||||
Project(#[from] ProjectError),
|
Project(#[from] ProjectError),
|
||||||
|
#[error("no seeds found for {0}")]
|
||||||
|
NotFound(Id),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone<G: Signer>(
|
pub fn clone<G: Signer>(
|
||||||
|
|
@ -149,8 +151,11 @@ pub fn clone<G: Signer>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get seeds.
|
// Get seeds. This consults the local routing table only.
|
||||||
let seeds = node.seeds(id)?;
|
let seeds = node.seeds(id)?;
|
||||||
|
if seeds.is_empty() {
|
||||||
|
return Err(CloneError::NotFound(id));
|
||||||
|
}
|
||||||
// Fetch from all seeds.
|
// Fetch from all seeds.
|
||||||
for seed in seeds {
|
for seed in seeds {
|
||||||
let spinner = term::spinner(format!(
|
let spinner = term::spinner(format!(
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ pub fn help(name: &str, version: &str, description: &str, usage: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn usage(name: &str, usage: &str) {
|
pub fn usage(name: &str, usage: &str) {
|
||||||
eprintln!(
|
println!(
|
||||||
"{} {}\n{}",
|
"{} {}\n{}",
|
||||||
style("==").red(),
|
style("==").red(),
|
||||||
style(format!("Error: rad-{name}: invalid usage")).red(),
|
style(format!("Error: rad-{name}: invalid usage")).red(),
|
||||||
|
|
@ -95,8 +95,8 @@ pub fn usage(name: &str, usage: &str) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eprintln(prefix: impl fmt::Display, msg: impl fmt::Display) {
|
pub fn println(prefix: impl fmt::Display, msg: impl fmt::Display) {
|
||||||
eprintln!("{prefix} {msg}");
|
println!("{prefix} {msg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indented(msg: impl fmt::Display) {
|
pub fn indented(msg: impl fmt::Display) {
|
||||||
|
|
@ -108,7 +108,7 @@ pub fn subcommand(msg: impl fmt::Display) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn warning(warning: &str) {
|
pub fn warning(warning: &str) {
|
||||||
eprintln!(
|
println!(
|
||||||
"{} {} {}",
|
"{} {} {}",
|
||||||
style("**").yellow(),
|
style("**").yellow(),
|
||||||
style("Warning:").yellow().bold(),
|
style("Warning:").yellow().bold(),
|
||||||
|
|
@ -117,7 +117,7 @@ pub fn warning(warning: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(error: impl fmt::Display) {
|
pub fn error(error: impl fmt::Display) {
|
||||||
eprintln!("{} {}", style("==").red(), style(error).red());
|
println!("{} {}", style("==").red(), style(error).red());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fail(header: &str, error: &anyhow::Error) {
|
pub fn fail(header: &str, error: &anyhow::Error) {
|
||||||
|
|
@ -129,7 +129,7 @@ pub fn fail(header: &str, error: &anyhow::Error) {
|
||||||
" "
|
" "
|
||||||
};
|
};
|
||||||
|
|
||||||
eprintln!(
|
println!(
|
||||||
"{} {}{}{}",
|
"{} {}{}{}",
|
||||||
style("==").red(),
|
style("==").red(),
|
||||||
style(header).red().reverse(),
|
style(header).red().reverse(),
|
||||||
|
|
@ -139,7 +139,7 @@ pub fn fail(header: &str, error: &anyhow::Error) {
|
||||||
|
|
||||||
let cause = error.root_cause();
|
let cause = error.root_cause();
|
||||||
if cause.to_string() != error.to_string() {
|
if cause.to_string() != error.to_string() {
|
||||||
eprintln!(
|
println!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
style("==").red().dim(),
|
style("==").red().dim(),
|
||||||
style(error.root_cause()).red().dim()
|
style(error.root_cause()).red().dim()
|
||||||
|
|
@ -148,7 +148,7 @@ pub fn fail(header: &str, error: &anyhow::Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Error::WithHint { hint, .. }) = error.downcast_ref::<Error>() {
|
if let Some(Error::WithHint { hint, .. }) = error.downcast_ref::<Error>() {
|
||||||
eprintln!("{} {}", style("==").yellow(), style(hint).yellow(),);
|
println!("{} {}", style("==").yellow(), style(hint).yellow(),);
|
||||||
blank();
|
blank();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ impl Spinner {
|
||||||
pub fn error(mut self, msg: impl ToString) {
|
pub fn error(mut self, msg: impl ToString) {
|
||||||
let msg = msg.to_string();
|
let msg = msg.to_string();
|
||||||
|
|
||||||
self.message = format!("{} (error: {})", self.message, msg);
|
self.message = format!("{} error: {}", self.message, msg);
|
||||||
self.set_failed();
|
self.set_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ impl Spinner {
|
||||||
|
|
||||||
pub fn set_failed(&mut self) {
|
pub fn set_failed(&mut self) {
|
||||||
self.progress.finish_and_clear();
|
self.progress.finish_and_clear();
|
||||||
term::eprintln(style("!!").red().reverse(), &self.message);
|
term::println(style("!!").red().reverse(), &self.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,25 @@ fn rad_clone() {
|
||||||
test("examples/rad-clone.md", working, Some(&bob.home), []).unwrap();
|
test("examples/rad-clone.md", working, Some(&bob.home), []).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rad_clone_unknown() {
|
||||||
|
logger::init(log::Level::Debug);
|
||||||
|
|
||||||
|
let mut environment = Environment::new();
|
||||||
|
let alice = environment.node("alice");
|
||||||
|
let working = environment.tmp().join("working");
|
||||||
|
|
||||||
|
let alice = alice.spawn(Config::default());
|
||||||
|
|
||||||
|
test(
|
||||||
|
"examples/rad-clone-unknown.md",
|
||||||
|
working,
|
||||||
|
Some(&alice.home),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rad_init_announce_refs() {
|
fn rad_init_announce_refs() {
|
||||||
logger::init(log::Level::Debug);
|
logger::init(log::Level::Debug);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ use snapbox::cmd::{Command, OutputAssert};
|
||||||
use snapbox::{Assert, Substitutions};
|
use snapbox::{Assert, Substitutions};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Error lines in the CLI are prefixed with this string.
|
||||||
|
const ERROR_PREFIX: &str = "==";
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("parsing failed")]
|
#[error("parsing failed")]
|
||||||
|
|
@ -18,6 +21,12 @@ pub enum Error {
|
||||||
Snapbox(#[from] snapbox::Error),
|
Snapbox(#[from] snapbox::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum ExitStatus {
|
||||||
|
Success,
|
||||||
|
Failure,
|
||||||
|
}
|
||||||
|
|
||||||
/// A test which may contain multiple assertions.
|
/// A test which may contain multiple assertions.
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
pub struct Test {
|
pub struct Test {
|
||||||
|
|
@ -36,6 +45,8 @@ pub struct Assertion {
|
||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
/// Expected output (stdout or stderr).
|
/// Expected output (stdout or stderr).
|
||||||
expected: String,
|
expected: String,
|
||||||
|
/// Expected exit status.
|
||||||
|
exit: ExitStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
|
|
@ -112,8 +123,12 @@ impl TestFormula {
|
||||||
command: cmd.to_owned(),
|
command: cmd.to_owned(),
|
||||||
args: args.to_owned(),
|
args: args.to_owned(),
|
||||||
expected: String::new(),
|
expected: String::new(),
|
||||||
|
exit: ExitStatus::Success,
|
||||||
});
|
});
|
||||||
} else if let Some(test) = test.assertions.last_mut() {
|
} else if let Some(test) = test.assertions.last_mut() {
|
||||||
|
if line.starts_with(ERROR_PREFIX) {
|
||||||
|
test.exit = ExitStatus::Failure;
|
||||||
|
}
|
||||||
test.expected.push_str(line.as_str());
|
test.expected.push_str(line.as_str());
|
||||||
test.expected.push('\n');
|
test.expected.push('\n');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -181,7 +196,14 @@ impl TestFormula {
|
||||||
match result {
|
match result {
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
let assert = OutputAssert::new(output).with_assert(assert.clone());
|
let assert = OutputAssert::new(output).with_assert(assert.clone());
|
||||||
assert.stdout_matches(&assertion.expected).success();
|
match assertion.exit {
|
||||||
|
ExitStatus::Success => {
|
||||||
|
assert.stdout_matches(&assertion.expected).success();
|
||||||
|
}
|
||||||
|
ExitStatus::Failure => {
|
||||||
|
assert.stdout_matches(&assertion.expected).failure();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if err.kind() == io::ErrorKind::NotFound {
|
if err.kind() == io::ErrorKind::NotFound {
|
||||||
|
|
@ -246,6 +268,7 @@ $ rad sync
|
||||||
expected: String::from(
|
expected: String::from(
|
||||||
"Tracking relationship established for @dave.\nNothing to do.\n\n",
|
"Tracking relationship established for @dave.\nNothing to do.\n\n",
|
||||||
),
|
),
|
||||||
|
exit: ExitStatus::Success,
|
||||||
},
|
},
|
||||||
Assertion {
|
Assertion {
|
||||||
command: String::from("rad"),
|
command: String::from("rad"),
|
||||||
|
|
@ -253,6 +276,7 @@ $ rad sync
|
||||||
expected: String::from(
|
expected: String::from(
|
||||||
"Tracking relationship established for @sean.\nNothing to do.\n",
|
"Tracking relationship established for @sean.\nNothing to do.\n",
|
||||||
),
|
),
|
||||||
|
exit: ExitStatus::Success,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
@ -262,6 +286,7 @@ $ rad sync
|
||||||
command: String::from("rad"),
|
command: String::from("rad"),
|
||||||
args: vec![String::from("sync")],
|
args: vec![String::from("sync")],
|
||||||
expected: String::new(),
|
expected: String::new(),
|
||||||
|
exit: ExitStatus::Success,
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue