git-spawn 0.2.0

Async wrapper around the git CLI: builder commands, typed parsers, high-level workflow helpers
Documentation
//! Shared helpers for the real-git integration tests.
//!
//! Compiled into each integration binary via `mod common;`. Not every binary
//! uses every helper, so a crate-level `dead_code` allowance keeps the unused
//! ones from tripping `-D warnings`.
#![allow(dead_code)]

use git_spawn::{GitCommand, Repository};

/// Configure a local identity and deterministic settings so commits work in
/// clean CI environments. `core.autocrlf=false` keeps Windows from rewriting
/// `\n` to `\r\n` on checkout, which would break byte-for-byte assertions.
pub fn configure_identity(repo: &Repository) {
    for (k, v) in [
        ("user.email", "test@example.com"),
        ("user.name", "Test"),
        ("commit.gpgsign", "false"),
        ("core.autocrlf", "false"),
    ] {
        let status = std::process::Command::new("git")
            .args(["config", "--local", k, v])
            .current_dir(repo.path())
            .status()
            .expect("git config");
        assert!(status.success(), "git config {k} failed");
    }
}

/// Create an empty repository on `main` in a fresh tempdir, with identity
/// configured. Returns the tempdir guard (dropping it deletes the repo) and
/// the [`Repository`].
pub async fn init_repo() -> (tempfile::TempDir, Repository) {
    let tmp = tempfile::tempdir().unwrap();
    let path = tmp.path().join("repo");
    std::fs::create_dir_all(&path).unwrap();
    let mut init = git_spawn::InitCommand::in_directory(&path);
    init.initial_branch("main").quiet();
    let repo = init.execute().await.expect("init");
    configure_identity(&repo);
    (tmp, repo)
}