Skip to main content

hematite/tools/
git_onboarding.rs

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