git_hosting_providers.rs

 1mod providers;
 2mod settings;
 3
 4use std::sync::Arc;
 5
 6use anyhow::{Result, anyhow};
 7use git::GitHostingProviderRegistry;
 8use git::repository::GitRepository;
 9use gpui::App;
10use url::Url;
11use util::maybe;
12
13pub use crate::providers::*;
14pub use crate::settings::*;
15
16/// Initializes the Git hosting providers.
17pub fn init(cx: &mut App) {
18    crate::settings::init(cx);
19
20    let provider_registry = GitHostingProviderRegistry::global(cx);
21    provider_registry.register_hosting_provider(Arc::new(Bitbucket::public_instance()));
22    provider_registry.register_hosting_provider(Arc::new(Chromium));
23    provider_registry.register_hosting_provider(Arc::new(Codeberg));
24    provider_registry.register_hosting_provider(Arc::new(Gitee));
25    provider_registry.register_hosting_provider(Arc::new(Github::public_instance()));
26    provider_registry.register_hosting_provider(Arc::new(Gitlab::public_instance()));
27    provider_registry.register_hosting_provider(Arc::new(Sourcehut));
28}
29
30/// Registers additional Git hosting providers.
31///
32/// These require information from the Git repository to construct, so their
33/// registration is deferred until we have a Git repository initialized.
34pub fn register_additional_providers(
35    provider_registry: Arc<GitHostingProviderRegistry>,
36    repository: Arc<dyn GitRepository>,
37) {
38    let Some(origin_url) = repository.remote_url("origin") else {
39        return;
40    };
41
42    if let Ok(gitlab_self_hosted) = Gitlab::from_remote_url(&origin_url) {
43        provider_registry.register_hosting_provider(Arc::new(gitlab_self_hosted));
44    } else if let Ok(github_self_hosted) = Github::from_remote_url(&origin_url) {
45        provider_registry.register_hosting_provider(Arc::new(github_self_hosted));
46    }
47}
48
49pub fn get_host_from_git_remote_url(remote_url: &str) -> Result<String> {
50    maybe!({
51        if let Some(remote_url) = remote_url.strip_prefix("git@") {
52            if let Some((host, _)) = remote_url.trim_start_matches("git@").split_once(':') {
53                return Some(host.to_string());
54            }
55        }
56
57        Url::parse(&remote_url)
58            .ok()
59            .and_then(|remote_url| remote_url.host_str().map(|host| host.to_string()))
60    })
61    .ok_or_else(|| anyhow!("URL has no host"))
62}
63
64#[cfg(test)]
65mod tests {
66    use super::get_host_from_git_remote_url;
67    use pretty_assertions::assert_eq;
68
69    #[test]
70    fn test_get_host_from_git_remote_url() {
71        let tests = [
72            (
73                "https://jlannister@github.com/some-org/some-repo.git",
74                Some("github.com".to_string()),
75            ),
76            (
77                "git@github.com:zed-industries/zed.git",
78                Some("github.com".to_string()),
79            ),
80            (
81                "git@my.super.long.subdomain.com:zed-industries/zed.git",
82                Some("my.super.long.subdomain.com".to_string()),
83            ),
84        ];
85
86        for (remote_url, expected_host) in tests {
87            let host = get_host_from_git_remote_url(remote_url).ok();
88            assert_eq!(host, expected_host);
89        }
90    }
91}