Files
oak-gpui/crates/git_hosting_providers/src/git_hosting_providers.rs
T
ᴀᴍᴛᴏᴀᴇʀ b948d8b9e7 git: Improve self-hosted provider support and Bitbucket integration (#42343)
This PR includes several minor modifications and improvements related to
Git hosting providers, covering the following areas:

1. Bitbucket Owner Parsing Fix: Remove the common `scm` prefix from the
remote URL of self-hosted Bitbucket instances to prevent incorrect owner
parsing.
[Reference](https://github.com/gitkraken/vscode-gitlens/blob/a6e3c6fbb255116507eaabaa9940c192ed7bb0e1/src/git/remotes/bitbucket-server.ts#L72-L74)
2. Bitbucket Avatars in Blame: Add support for displaying Bitbucket
avatars in the Git blame view.
<img width="2750" height="1994" alt="CleanShot 2025-11-10 at 20 34
40@2x"
src="https://github.com/user-attachments/assets/9e26abdf-7880-4085-b636-a1f99ebeeb97"
/>
3. Self-hosted SourceHut Support: Add support for self-hosted SourceHut
instances.
4. Configuration: Add recently introduced self-hosted Git providers
(Gitea, Forgejo, and SourceHut) to the `git_hosting_providers` setting
option.
<img width="2750" height="1994" alt="CleanShot 2025-11-10 at 20 33
48@2x"
src="https://github.com/user-attachments/assets/44ffc799-182d-4145-9b89-e509bbc08843"
/>


Closes #11043

Release Notes:

- Improved self-hosted git provider support and Bitbucket integration
2025-12-08 13:32:14 -05:00

102 lines
3.8 KiB
Rust

mod providers;
mod settings;
use std::sync::Arc;
use anyhow::Context as _;
use anyhow::Result;
use git::GitHostingProviderRegistry;
use git::repository::GitRepository;
use gpui::App;
use url::Url;
use util::maybe;
pub use crate::providers::*;
pub use crate::settings::*;
/// Initializes the Git hosting providers.
pub fn init(cx: &mut App) {
crate::settings::init(cx);
let provider_registry = GitHostingProviderRegistry::global(cx);
provider_registry.register_hosting_provider(Arc::new(Bitbucket::public_instance()));
provider_registry.register_hosting_provider(Arc::new(Chromium));
provider_registry.register_hosting_provider(Arc::new(Forgejo::public_instance()));
provider_registry.register_hosting_provider(Arc::new(Gitea::public_instance()));
provider_registry.register_hosting_provider(Arc::new(Gitee));
provider_registry.register_hosting_provider(Arc::new(Github::public_instance()));
provider_registry.register_hosting_provider(Arc::new(Gitlab::public_instance()));
provider_registry.register_hosting_provider(Arc::new(SourceHut::public_instance()));
}
/// Registers additional Git hosting providers.
///
/// These require information from the Git repository to construct, so their
/// registration is deferred until we have a Git repository initialized.
pub async fn register_additional_providers(
provider_registry: Arc<GitHostingProviderRegistry>,
repository: Arc<dyn GitRepository>,
) {
let Some(origin_url) = repository.remote_url("origin").await else {
return;
};
if let Ok(gitlab_self_hosted) = Gitlab::from_remote_url(&origin_url) {
provider_registry.register_hosting_provider(Arc::new(gitlab_self_hosted));
} else if let Ok(github_self_hosted) = Github::from_remote_url(&origin_url) {
provider_registry.register_hosting_provider(Arc::new(github_self_hosted));
} else if let Ok(forgejo_self_hosted) = Forgejo::from_remote_url(&origin_url) {
provider_registry.register_hosting_provider(Arc::new(forgejo_self_hosted));
} else if let Ok(gitea_self_hosted) = Gitea::from_remote_url(&origin_url) {
provider_registry.register_hosting_provider(Arc::new(gitea_self_hosted));
} else if let Ok(bitbucket_self_hosted) = Bitbucket::from_remote_url(&origin_url) {
provider_registry.register_hosting_provider(Arc::new(bitbucket_self_hosted));
} else if let Ok(sourcehut_self_hosted) = SourceHut::from_remote_url(&origin_url) {
provider_registry.register_hosting_provider(Arc::new(sourcehut_self_hosted));
}
}
pub fn get_host_from_git_remote_url(remote_url: &str) -> Result<String> {
maybe!({
if let Some(remote_url) = remote_url.strip_prefix("git@")
&& let Some((host, _)) = remote_url.trim_start_matches("git@").split_once(':')
{
return Some(host.to_string());
}
Url::parse(remote_url)
.ok()
.and_then(|remote_url| remote_url.host_str().map(|host| host.to_string()))
})
.context("URL has no host")
}
#[cfg(test)]
mod tests {
use super::get_host_from_git_remote_url;
use pretty_assertions::assert_eq;
#[test]
fn test_get_host_from_git_remote_url() {
let tests = [
(
"https://jlannister@github.com/some-org/some-repo.git",
Some("github.com".to_string()),
),
(
"git@github.com:zed-industries/zed.git",
Some("github.com".to_string()),
),
(
"git@my.super.long.subdomain.com:zed-industries/zed.git",
Some("my.super.long.subdomain.com".to_string()),
),
];
for (remote_url, expected_host) in tests {
let host = get_host_from_git_remote_url(remote_url).ok();
assert_eq!(host, expected_host);
}
}
}