Skip to main content

fluidattacks_core_git/
ops.rs

1use std::path::Path;
2
3use crate::cli;
4
5/// Runs `git reset --hard`, removes symlinks, and returns whether it succeeded.
6pub async fn reset_repo(repo_path: &str) -> bool {
7    if let Err(error) = cli::set_safe_directory().await {
8        tracing::error!(repo_path, error = %error, "failed to add the safe directory");
9    }
10    let root = Path::new(repo_path);
11    if !root.join(".git").exists() {
12        tracing::error!(repo_path, "not the root of a repository");
13        return false;
14    }
15    if let Err(error) = cli::reset_hard(repo_path).await {
16        tracing::error!(repo_path, error = %error, "failed to reset the repository");
17        return false;
18    }
19    super::fs::remove_symlinks(root);
20    true
21}
22
23#[cfg(test)]
24mod tests {
25    use super::reset_repo;
26    use std::path::Path;
27
28    fn git(repo: &Path, args: &[&str]) {
29        let status = std::process::Command::new("git")
30            .arg("-C")
31            .arg(repo)
32            .args(args)
33            .status()
34            .unwrap();
35        assert!(status.success());
36    }
37
38    #[tokio::test]
39    async fn only_the_root_of_the_repository_gets_reset() {
40        let dir = tempfile::tempdir().unwrap();
41        std::env::set_var("GIT_CONFIG_GLOBAL", dir.path().join("gitconfig"));
42
43        let repo = dir.path().join("repo");
44        std::fs::create_dir_all(repo.join("sub/deep")).unwrap();
45        git(&repo, &["init", "-q"]);
46        std::fs::write(repo.join("f.txt"), b"committed").unwrap();
47        git(&repo, &["add", "-A"]);
48        git(
49            &repo,
50            &[
51                "-c",
52                "user.email=dev@fluidattacks.com",
53                "-c",
54                "user.name=dev",
55                "commit",
56                "-q",
57                "-m",
58                "files",
59            ],
60        );
61        std::fs::write(repo.join("f.txt"), b"dirty").unwrap();
62
63        let deep = repo.join("sub/deep");
64        assert!(!reset_repo(deep.to_str().unwrap()).await);
65        assert_eq!(
66            std::fs::read_to_string(repo.join("f.txt")).unwrap(),
67            "dirty"
68        );
69
70        assert!(reset_repo(repo.to_str().unwrap()).await);
71        assert_eq!(
72            std::fs::read_to_string(repo.join("f.txt")).unwrap(),
73            "committed"
74        );
75    }
76}