repo_backup/
gitlab_provider.rs

1use failure::{Error, ResultExt};
2use gitlab::{Gitlab as Client, Project};
3
4use config::GitLabConfig;
5use {Provider, Repo, SyncResult};
6
7/// A provider which queries the GitLab API.
8#[derive(Debug)]
9pub struct GitLab {
10    client: Client,
11    cfg: GitLabConfig,
12}
13
14impl GitLab {
15    /// Create a new `GitLab` provider using its config.
16    pub fn with_config(cfg: GitLabConfig) -> Result<GitLab, Error> {
17        let client = Client::new(&cfg.host, cfg.api_key.reveal_str())
18            .sync()
19            .context("Invalid API key")?;
20
21        Ok(GitLab { client, cfg })
22    }
23
24    fn get_owned(&self) -> Result<Vec<Repo>, Error> {
25        debug!("Fetching owned repos");
26        let owned = self.client.owned_projects().sync()?;
27
28        let repos: Vec<Repo> = owned
29            .into_iter()
30            .map(|p| self.gitlab_project_to_repo(p))
31            .collect();
32
33        debug!("Found {} owned projects", repos.len());
34
35        Ok(repos)
36    }
37
38    fn get_organisation_repos(&self) -> Result<Vec<Repo>, Error> {
39        debug!("Fetching organisation repos");
40
41        let current_user = self
42            .client
43            .current_user()
44            .sync()
45            .context("Unable to get the name of the current user")?
46            .username;
47        trace!("Current GitLab user is {}", current_user);
48
49        let all_repos = self.client.projects().sync()?;
50
51        let org_repos: Vec<Repo> = all_repos
52            .into_iter()
53            .map(|p| self.gitlab_project_to_repo(p))
54            .filter(|r| r.owner != current_user)
55            .collect();
56
57        debug!(
58            "Found {} repos owned by organisations you are a part of",
59            org_repos.len()
60        );
61        Ok(org_repos)
62    }
63
64    fn gitlab_project_to_repo(&self, project: Project) -> Repo {
65        let mut split = project.path_with_namespace.split("/");
66        let owner = split.next().expect("Namespaces always have an owner");
67        let name = split.next().expect("unreachable");
68
69        Repo {
70            owner: owner.to_string(),
71            name: name.to_string(),
72            url: project.ssh_url_to_repo,
73            provider: self.name().to_string(),
74        }
75    }
76}
77
78impl Provider for GitLab {
79    fn name(&self) -> &str {
80        "gitlab"
81    }
82
83    fn repositories(&self) -> Result<Vec<Repo>, Error> {
84        let mut repos = Vec::new();
85
86        if self.cfg.owned {
87            let owned =
88                self.get_owned().context("Unable to get owned repos")?;
89            repos.extend(owned);
90        }
91
92        if self.cfg.organisations {
93            let org_repos = self.get_organisation_repos().context(
94                "Unable to get repos owned by organisations you are a part of",
95            )?;
96            repos.extend(org_repos);
97        }
98
99        Ok(repos)
100    }
101}