fluentci_ext/
git.rs

1use std::{path::Path, process::ExitStatus, sync::mpsc::Sender};
2
3use crate::{exec, pkgx::Pkgx, Extension};
4use anyhow::Error;
5use fluentci_types::Output;
6
7#[derive(Default)]
8pub struct Git {}
9
10impl Git {
11    pub fn validate_url(&self, url: &str) -> Result<(), Error> {
12        if url.is_empty() {
13            return Err(Error::msg("URL is empty"));
14        }
15        if !regex::Regex::new(
16            r"^(?:https:\/\/([^\/]+)\/([^\/]+)\/([^\/]+)|git@([^:]+):([^\/]+)\/([^\/]+))$",
17        )
18        .unwrap()
19        .is_match(url)
20        {
21            return Err(Error::msg("Invalid URL"));
22        }
23        Ok(())
24    }
25}
26
27impl Extension for Git {
28    fn exec(
29        &mut self,
30        url: &str,
31        tx: Sender<String>,
32        out: Output,
33        last_cmd: bool,
34        work_dir: &str,
35    ) -> Result<ExitStatus, Error> {
36        self.setup()?;
37
38        if self.validate_url(url).is_err() {
39            return Err(Error::msg("Invalid URL"));
40        }
41
42        let repo = url.split('/').last().unwrap().replace(".git", "");
43        let git_dir = format!("{}/{}/.git", work_dir, repo);
44        if Path::new(&git_dir).exists() {
45            let cmd = format!("git pull {}", url);
46            let work_dir = format!("{}/{}", work_dir, repo);
47            return exec(&cmd, tx, out, last_cmd, &work_dir);
48        }
49
50        let cmd = format!("git clone {}", url);
51        exec(&cmd, tx, out, last_cmd, work_dir)
52    }
53
54    fn setup(&self) -> Result<(), Error> {
55        Pkgx::default().install(vec!["git"])?;
56        Ok(())
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_validate_url() {
66        let git = Git::default();
67        assert!(git.validate_url("https://github.com/tsirysndr/me").is_ok());
68        assert!(git.validate_url("git@github.com:tsirysndr/me").is_ok());
69        assert!(git.validate_url("github.com:tsirysndr/me").is_err());
70    }
71}