Skip to main content

auths_cli/adapters/
git_config.rs

1use std::path::PathBuf;
2
3use auths_sdk::ports::git_config::{GitConfigError, GitConfigProvider};
4
5/// System adapter for git signing configuration.
6///
7/// Runs `git config <scope> <key> <value>` via `std::process::Command`.
8/// Construct with `SystemGitConfigProvider::global()` or
9/// `SystemGitConfigProvider::local(repo_path)`.
10///
11/// Usage:
12/// ```ignore
13/// let provider = SystemGitConfigProvider::global();
14/// provider.set("gpg.format", "ssh")?;
15/// ```
16pub struct SystemGitConfigProvider {
17    scope_flag: &'static str,
18    working_dir: Option<PathBuf>,
19}
20
21impl SystemGitConfigProvider {
22    /// Creates a provider that sets git config in global scope.
23    pub fn global() -> Self {
24        Self {
25            scope_flag: "--global",
26            working_dir: None,
27        }
28    }
29
30    /// Creates a provider that sets git config in local scope for the given repo.
31    ///
32    /// Args:
33    /// * `repo_path`: Path to the git repository to configure.
34    pub fn local(repo_path: PathBuf) -> Self {
35        Self {
36            scope_flag: "--local",
37            working_dir: Some(repo_path),
38        }
39    }
40}
41
42impl GitConfigProvider for SystemGitConfigProvider {
43    fn set(&self, key: &str, value: &str) -> Result<(), GitConfigError> {
44        let mut cmd = crate::subprocess::git_command(&["config", self.scope_flag, key, value]);
45        if let Some(dir) = &self.working_dir {
46            cmd.current_dir(dir);
47        }
48        let status = cmd
49            .status()
50            .map_err(|e| GitConfigError::CommandFailed(format!("failed to run git config: {e}")))?;
51        if !status.success() {
52            return Err(GitConfigError::CommandFailed(format!(
53                "git config {} = {} failed",
54                key, value
55            )));
56        }
57        Ok(())
58    }
59
60    fn unset(&self, key: &str) -> Result<(), GitConfigError> {
61        let mut cmd = crate::subprocess::git_command(&["config", self.scope_flag, "--unset", key]);
62        if let Some(dir) = &self.working_dir {
63            cmd.current_dir(dir);
64        }
65        let output = cmd
66            .output()
67            .map_err(|e| GitConfigError::CommandFailed(format!("failed to run git config: {e}")))?;
68        // Exit code 5 means the key was not set — treat as success
69        if !output.status.success() && output.status.code() != Some(5) {
70            return Err(GitConfigError::CommandFailed(format!(
71                "git config --unset {} failed",
72                key
73            )));
74        }
75        Ok(())
76    }
77}