Skip to main content

hematite/tools/
git_onboarding.rs

1use serde_json::Value;
2use std::fmt::Write as _;
3use std::process::Command;
4
5/// tool: git_onboarding
6///
7/// Action: Configures or updates a Git remote (usually 'origin') and optionally performs an initial push.
8pub async fn execute(args: &Value) -> Result<String, String> {
9    let url = args
10        .get("url")
11        .and_then(|v| v.as_str())
12        .ok_or("Missing 'url' argument")?;
13    let name = args
14        .get("name")
15        .and_then(|v| v.as_str())
16        .unwrap_or("origin");
17    let do_push = args.get("push").and_then(|v| v.as_bool()).unwrap_or(false);
18
19    // Security Audit
20    if !url.starts_with("https://") && !url.starts_with("git@") {
21        return Err("Invalid remote URL. Must be HTTPS or SSH.".into());
22    }
23
24    // 1. Check if remote exists
25    let check = Command::new("git")
26        .args(["remote", "get-url", name])
27        .output()
28        .map_err(|e| e.to_string())?;
29
30    if check.status.success() {
31        // Already exists, update it
32        let set_url = Command::new("git")
33            .args(["remote", "set-url", name, url])
34            .output()
35            .map_err(|e| e.to_string())?;
36        if !set_url.status.success() {
37            return Err(format!(
38                "Failed to update remote: {}",
39                String::from_utf8_lossy(&set_url.stderr)
40            ));
41        }
42    } else {
43        // New remote
44        let add = Command::new("git")
45            .args(["remote", "add", name, url])
46            .output()
47            .map_err(|e| e.to_string())?;
48        if !add.status.success() {
49            return Err(format!(
50                "Failed to add remote: {}",
51                String::from_utf8_lossy(&add.stderr)
52            ));
53        }
54    }
55
56    let mut status = format!("Successfully configured remote '{}' to {}.", name, url);
57
58    // 2. Optional initial push
59    if do_push {
60        let push = Command::new("git")
61            .args(["push", "-u", name, "HEAD"])
62            .output()
63            .map_err(|e| e.to_string())?;
64
65        if push.status.success() {
66            status.push_str("\nInitial push complete. Branch tracking established.");
67        } else {
68            let _ = write!(status, "\nWarning: Push failed: {}. You may need to authenticate or handle branch conflicts manually.", String::from_utf8_lossy(&push.stderr));
69        }
70    }
71
72    Ok(status)
73}