diff --git a/Cargo.lock b/Cargo.lock
index a0a5c7e27cf76822a3f7f985332d6c59a3871806..5276a9eac963964531e7e03dceac2713d361443b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -7008,6 +7008,7 @@ dependencies = [
"gpui",
"http_client",
"indoc",
+ "itertools 0.14.0",
"pretty_assertions",
"regex",
"serde",
diff --git a/crates/git_hosting_providers/Cargo.toml b/crates/git_hosting_providers/Cargo.toml
index 851556151e285975cb1eb7d3d33244d7e11b5663..9480e0ec28c0ffa61c1126b2a627f22dc445d7d3 100644
--- a/crates/git_hosting_providers/Cargo.toml
+++ b/crates/git_hosting_providers/Cargo.toml
@@ -18,6 +18,7 @@ futures.workspace = true
git.workspace = true
gpui.workspace = true
http_client.workspace = true
+itertools.workspace = true
regex.workspace = true
serde.workspace = true
serde_json.workspace = true
diff --git a/crates/git_hosting_providers/src/git_hosting_providers.rs b/crates/git_hosting_providers/src/git_hosting_providers.rs
index 98ea301ec984298df54ec8bca7e28f9474e373bd..37cf5882059d7a274661f5a083a23e3f25e676ff 100644
--- a/crates/git_hosting_providers/src/git_hosting_providers.rs
+++ b/crates/git_hosting_providers/src/git_hosting_providers.rs
@@ -26,7 +26,7 @@ pub fn init(cx: &mut App) {
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));
+ provider_registry.register_hosting_provider(Arc::new(SourceHut::public_instance()));
}
/// Registers additional Git hosting providers.
@@ -51,6 +51,8 @@ pub async fn register_additional_providers(
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));
}
}
diff --git a/crates/git_hosting_providers/src/providers/bitbucket.rs b/crates/git_hosting_providers/src/providers/bitbucket.rs
index 0c30a13758a8339087ebb146f0029baee0d3ea7e..07c6898d4e0affc3bdde4d8290607897cf2cd5be 100644
--- a/crates/git_hosting_providers/src/providers/bitbucket.rs
+++ b/crates/git_hosting_providers/src/providers/bitbucket.rs
@@ -1,8 +1,14 @@
-use std::str::FromStr;
use std::sync::LazyLock;
-
-use anyhow::{Result, bail};
+use std::{str::FromStr, sync::Arc};
+
+use anyhow::{Context as _, Result, bail};
+use async_trait::async_trait;
+use futures::AsyncReadExt;
+use gpui::SharedString;
+use http_client::{AsyncBody, HttpClient, HttpRequestExt, Request};
+use itertools::Itertools as _;
use regex::Regex;
+use serde::Deserialize;
use url::Url;
use git::{
@@ -20,6 +26,42 @@ fn pull_request_regex() -> &'static Regex {
&PULL_REQUEST_REGEX
}
+#[derive(Debug, Deserialize)]
+struct CommitDetails {
+ author: Author,
+}
+
+#[derive(Debug, Deserialize)]
+struct Author {
+ user: Account,
+}
+
+#[derive(Debug, Deserialize)]
+struct Account {
+ links: AccountLinks,
+}
+
+#[derive(Debug, Deserialize)]
+struct AccountLinks {
+ avatar: Option,
+}
+
+#[derive(Debug, Deserialize)]
+struct Link {
+ href: String,
+}
+
+#[derive(Debug, Deserialize)]
+struct CommitDetailsSelfHosted {
+ author: AuthorSelfHosted,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct AuthorSelfHosted {
+ avatar_url: Option,
+}
+
pub struct Bitbucket {
name: String,
base_url: Url,
@@ -61,8 +103,60 @@ impl Bitbucket {
.host_str()
.is_some_and(|host| host != "bitbucket.org")
}
+
+ async fn fetch_bitbucket_commit_author(
+ &self,
+ repo_owner: &str,
+ repo: &str,
+ commit: &str,
+ client: &Arc,
+ ) -> Result