diff --git a/.gitignore b/.gitignore index d787b70..58881e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +/artifacts /target /result diff --git a/nix/load.nix b/nix/load.nix index 3ad4944..39da029 100644 --- a/nix/load.nix +++ b/nix/load.nix @@ -30,9 +30,14 @@ args: let src = toString ( - args.src or (warn - "namaka.load: `flake` and `dir` have been deprecated, use `src` directly instead" - (args.flake + "/${args.dir or "tests"}")) + if args ? src then + args.src + else if args ? flake || args ? dir then + warn + "namaka.load: `flake` and `dir` have been deprecated, use `src` directly instead" + (args.flake + "/${args.dir or "tests"}") + else + throw "namaka.load: missing mandatory `src` argument" ); tests = haumea.load (removeAttrs args [ "flake" "dir" ] // { diff --git a/src/cmd/check.rs b/src/cmd/check.rs index d2cd8d9..da6c01b 100644 --- a/src/cmd/check.rs +++ b/src/cmd/check.rs @@ -1,6 +1,7 @@ use std::{ fs::{self, create_dir_all, remove_dir_all, File}, io::{stderr, BufRead, Write}, + path::Path, process::exit, }; @@ -14,7 +15,7 @@ use crate::{ proto::{TestOutput, TestResult}, }; -pub fn check(opts: Opts, cfg: Option) -> Result<()> { +pub fn check(root: &Path, opts: Opts, cfg: Option) -> Result<()> { let output = nix_check(opts, cfg)?; let success = output.status.success(); @@ -26,13 +27,14 @@ pub fn check(opts: Opts, cfg: Option) -> Result<()> { let output = serde_json::from_str::(line)?; - let pending = output.dir.join("_snapshots").join(".pending"); + let pending = root.join(output.dir).join("_snapshots/.pending"); let _ = remove_dir_all(&pending); create_dir_all(&pending)?; fs::write(pending.join(".gitignore"), "*")?; let total = output.results.len(); let mut failures = 0; + let mut additions = 0; for (name, res) in output.results { let new = pending.join(&name); match res { @@ -41,14 +43,19 @@ pub fn check(opts: Opts, cfg: Option) -> Result<()> { } TestResult::Failure { snapshot, old } => { - failures += 1; - println!("{} {name}", if old { "✘" } else { "🞥" }.red()); + if old { + failures += 1; + println!("{} {name}", "✘".red()); + } else { + additions += 1; + println!("{} {name}", "🞥".blue()); + } snapshot.to_writer(File::create(new)?)?; } } } - if failures == 0 { + if failures == 0 && additions == 0 { if success { eprintln!("All {total} tests succeeded"); return Ok(()); @@ -56,9 +63,15 @@ pub fn check(opts: Opts, cfg: Option) -> Result<()> { break; } } else { - eprintln!("{failures} out of {total} tests failed"); + if failures != 0 { + let existing = total - additions; + eprintln!("{failures} out of {existing} tests failed"); + } + if additions != 0 { + eprintln!("{additions} new tests found"); + } eprintln!("run `namaka review` to review the pending snapshots"); - exit(1); + exit(if failures != 0 { 1 } else { 2 }); } } diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs index 99b45fe..8b378cf 100644 --- a/src/cmd/clean.rs +++ b/src/cmd/clean.rs @@ -1,5 +1,6 @@ use std::{ fs::{read_dir, remove_dir_all, remove_file}, + path::Path, io::{stderr, BufRead, Write}, }; @@ -8,7 +9,7 @@ use owo_colors::OwoColorize; use crate::{cfg::Config, cli::Opts, cmd::run::nix_eval, proto::TestOutput}; -pub fn clean(opts: Opts, cfg: Option) -> Result<()> { +pub fn clean(root: &Path, opts: Opts, cfg: Option) -> Result<()> { let output = nix_eval(opts, cfg)?; for line in output.stderr.lines() { @@ -19,7 +20,7 @@ pub fn clean(opts: Opts, cfg: Option) -> Result<()> { let mut out = stderr().lock(); let output = serde_json::from_str::(line)?; - let snapshots = output.dir.join("_snapshots"); + let snapshots = root.join(output.dir).join("_snapshots"); for entry in read_dir(snapshots)? { let entry = entry?; diff --git a/src/cmd/review.rs b/src/cmd/review.rs index c6d2192..58867b3 100644 --- a/src/cmd/review.rs +++ b/src/cmd/review.rs @@ -20,7 +20,7 @@ use crate::{ proto::{Snapshot, TestOutput}, }; -pub fn review(opts: Opts, cfg: Option) -> Result<()> { +pub fn review(root: &Path, opts: Opts, cfg: Option) -> Result<()> { let output = nix_eval(opts, cfg)?; let _ = ctrlc::set_handler(|| { let mut term = Term::stderr(); @@ -36,7 +36,7 @@ pub fn review(opts: Opts, cfg: Option) -> Result<()> { }; let output = serde_json::from_str::(line)?; - let snapshots = output.dir.join("_snapshots"); + let snapshots = root.join(output.dir).join("_snapshots"); for entry in read_dir(snapshots.join(".pending"))? { use bstr::ByteSlice; diff --git a/src/main.rs b/src/main.rs index 3fb8847..3c0c45d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,9 +23,22 @@ fn main() -> Result<()> { let cfg = cfg::load()?; + let root = repo_root()?; + match opts.subcmd { - Subcommand::Check => check(opts, cfg), - Subcommand::Clean => clean(opts, cfg), - Subcommand::Review => review(opts, cfg), + Subcommand::Check => check(&root, opts, cfg), + Subcommand::Clean => clean(&root, opts, cfg), + Subcommand::Review => review(&root, opts, cfg), } } + +fn repo_root() -> Result { + let mut cmd = std::process::Command::new("git"); + cmd.args(["rev-parse", "--show-toplevel"]); + + let out = cmd.output()?; + let str = std::str::from_utf8(&out.stdout)?; + let str = str.trim_end(); + + Ok(str.to_owned().into()) +}