use std::path::Path;
use crate::error::Error;
use crate::git;
use crate::paths::Tree;
use crate::shared;
use crate::state::State;
pub(crate) fn changed(
git_dir: &Path,
reload: &[String],
from: &str,
to: &str,
) -> Result<bool, Error> {
if reload.is_empty() {
return Ok(true);
}
git::changed(git_dir, from, to, reload)
}
pub(crate) async fn nothing_changed(
tree: &Tree,
state: &State,
reload: &[String],
head: &str,
) -> bool {
let Some(deployed) = state.deployed.clone() else {
return false;
};
let (git_dir, reload, head_sha) = (tree.git(), reload.to_vec(), head.to_owned());
let decided =
shared::off_thread(move || changed(&git_dir, &reload, &deployed, &head_sha)).await;
match decided {
Ok(changed) => !changed,
Err(err) => {
eprintln!(
"shep-deploy: {}: could not tell whether {head} touches the reload paths, \
deploying it: {err}",
tree.sheep()
);
false
}
}
}
#[cfg(test)]
mod tests {
use crate::fixtures;
use super::*;
fn voting() -> Vec<String> {
vec!["cmd/voting".to_owned(), "assets/*.png".to_owned()]
}
fn pushed(files: &[(&str, &str)]) -> (tempfile::TempDir, String, String) {
let repo = fixtures::checkout(&[
("cmd/voting/main.go", "1"),
("cmd/bot/main.go", "1"),
("assets/logo.png", "1"),
]);
let from = fixtures::head_of(repo.path());
fixtures::commit(repo.path(), files, "push");
let to = fixtures::head_of(repo.path());
(repo, from, to)
}
fn decide(reload: &[String], repo: &tempfile::TempDir, from: &str, to: &str) -> bool {
changed(repo.path(), reload, from, to).expect("decides")
}
#[test]
fn a_push_outside_the_paths_is_unchanged() {
let (repo, from, to) = pushed(&[("cmd/bot/main.go", "2")]);
assert!(!decide(&voting(), &repo, &from, &to));
}
#[test]
fn a_push_inside_a_path_is_changed() {
let (repo, from, to) = pushed(&[("cmd/voting/main.go", "2")]);
assert!(
decide(&voting(), &repo, &from, &to),
"a directory name matches its contents"
);
let (repo, from, to) = pushed(&[("assets/logo.png", "2")]);
assert!(decide(&voting(), &repo, &from, &to), "a glob");
}
#[test]
fn an_edit_to_the_flockfile_is_not_a_declared_path() {
let (repo, from, to) = pushed(&[("Flockfile.toml", "edited")]);
assert!(!decide(&voting(), &repo, &from, &to));
}
#[test]
fn an_empty_list_means_deploy() {
let (repo, from, to) = pushed(&[("cmd/bot/main.go", "2")]);
assert!(decide(&[], &repo, &from, &to));
}
#[test]
fn a_pathspec_git_rejects_is_an_error() {
let (repo, from, to) = pushed(&[("cmd/bot/main.go", "2")]);
let err = changed(repo.path(), &[":(bogus)cmd".to_owned()], &from, &to)
.expect_err("git refuses it");
assert!(matches!(err, Error::Git { .. }), "{err}");
}
}