git_hosting_providers: Refactor constructors (#26919)

Marshall Bowers created

This PR refactors the constructors for the various Git hosting providers
to facilitate adding support for more self-hosted variants.

Release Notes:

- N/A

Change summary

crates/collab/src/tests/test_server.rs                    |  2 
crates/git_hosting_providers/src/git_hosting_providers.rs |  6 
crates/git_hosting_providers/src/providers/bitbucket.rs   | 34 ++++++--
crates/git_hosting_providers/src/providers/github.rs      | 35 +++++---
crates/git_hosting_providers/src/providers/gitlab.rs      | 28 ++++---
5 files changed, 65 insertions(+), 40 deletions(-)

Detailed changes

crates/collab/src/tests/test_server.rs 🔗

@@ -271,7 +271,7 @@ impl TestServer {
 
         let git_hosting_provider_registry = cx.update(GitHostingProviderRegistry::default_global);
         git_hosting_provider_registry
-            .register_hosting_provider(Arc::new(git_hosting_providers::Github::new()));
+            .register_hosting_provider(Arc::new(git_hosting_providers::Github::public_instance()));
 
         let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
         let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx));

crates/git_hosting_providers/src/git_hosting_providers.rs 🔗

@@ -14,12 +14,12 @@ pub use crate::providers::*;
 /// Initializes the Git hosting providers.
 pub fn init(cx: &App) {
     let provider_registry = GitHostingProviderRegistry::global(cx);
-    provider_registry.register_hosting_provider(Arc::new(Bitbucket));
+    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(Codeberg));
     provider_registry.register_hosting_provider(Arc::new(Gitee));
-    provider_registry.register_hosting_provider(Arc::new(Github::new()));
-    provider_registry.register_hosting_provider(Arc::new(Gitlab::new()));
+    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));
 }
 

crates/git_hosting_providers/src/providers/bitbucket.rs 🔗

@@ -7,15 +7,31 @@ use git::{
     RemoteUrl,
 };
 
-pub struct Bitbucket;
+pub struct Bitbucket {
+    name: String,
+    base_url: Url,
+}
+
+impl Bitbucket {
+    pub fn new(name: impl Into<String>, base_url: Url) -> Self {
+        Self {
+            name: name.into(),
+            base_url,
+        }
+    }
+
+    pub fn public_instance() -> Self {
+        Self::new("Bitbucket", Url::parse("https://bitbucket.org").unwrap())
+    }
+}
 
 impl GitHostingProvider for Bitbucket {
     fn name(&self) -> String {
-        "Bitbucket".to_string()
+        self.name.clone()
     }
 
     fn base_url(&self) -> Url {
-        Url::parse("https://bitbucket.org").unwrap()
+        self.base_url.clone()
     }
 
     fn supports_avatars(&self) -> bool {
@@ -90,7 +106,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_ssh_url() {
-        let parsed_remote = Bitbucket
+        let parsed_remote = Bitbucket::public_instance()
             .parse_remote_url("git@bitbucket.org:zed-industries/zed.git")
             .unwrap();
 
@@ -105,7 +121,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_https_url() {
-        let parsed_remote = Bitbucket
+        let parsed_remote = Bitbucket::public_instance()
             .parse_remote_url("https://bitbucket.org/zed-industries/zed.git")
             .unwrap();
 
@@ -120,7 +136,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_https_url_with_username() {
-        let parsed_remote = Bitbucket
+        let parsed_remote = Bitbucket::public_instance()
             .parse_remote_url("https://thorstenballzed@bitbucket.org/zed-industries/zed.git")
             .unwrap();
 
@@ -135,7 +151,7 @@ mod tests {
 
     #[test]
     fn test_build_bitbucket_permalink() {
-        let permalink = Bitbucket.build_permalink(
+        let permalink = Bitbucket::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),
@@ -153,7 +169,7 @@ mod tests {
 
     #[test]
     fn test_build_bitbucket_permalink_with_single_line_selection() {
-        let permalink = Bitbucket.build_permalink(
+        let permalink = Bitbucket::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),
@@ -171,7 +187,7 @@ mod tests {
 
     #[test]
     fn test_build_bitbucket_permalink_with_multi_line_selection() {
-        let permalink = Bitbucket.build_permalink(
+        let permalink = Bitbucket::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),

crates/git_hosting_providers/src/providers/github.rs 🔗

@@ -45,19 +45,24 @@ struct User {
     pub avatar_url: String,
 }
 
+#[derive(Debug)]
 pub struct Github {
     name: String,
     base_url: Url,
 }
 
 impl Github {
-    pub fn new() -> Self {
+    pub fn new(name: impl Into<String>, base_url: Url) -> Self {
         Self {
-            name: "GitHub".to_string(),
-            base_url: Url::parse("https://github.com").unwrap(),
+            name: name.into(),
+            base_url,
         }
     }
 
+    pub fn public_instance() -> Self {
+        Self::new("GitHub", Url::parse("https://github.com").unwrap())
+    }
+
     pub fn from_remote_url(remote_url: &str) -> Result<Self> {
         let host = get_host_from_git_remote_url(remote_url)?;
         if host == "github.com" {
@@ -71,10 +76,10 @@ impl Github {
             bail!("not a GitHub URL");
         }
 
-        Ok(Self {
-            name: "GitHub Self-Hosted".to_string(),
-            base_url: Url::parse(&format!("https://{}", host))?,
-        })
+        Ok(Self::new(
+            "GitHub Self-Hosted",
+            Url::parse(&format!("https://{}", host))?,
+        ))
     }
 
     async fn fetch_github_commit_author(
@@ -308,7 +313,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_ssh_url() {
-        let parsed_remote = Github::new()
+        let parsed_remote = Github::public_instance()
             .parse_remote_url("git@github.com:zed-industries/zed.git")
             .unwrap();
 
@@ -323,7 +328,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_https_url() {
-        let parsed_remote = Github::new()
+        let parsed_remote = Github::public_instance()
             .parse_remote_url("https://github.com/zed-industries/zed.git")
             .unwrap();
 
@@ -338,7 +343,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_https_url_with_username() {
-        let parsed_remote = Github::new()
+        let parsed_remote = Github::public_instance()
             .parse_remote_url("https://jlannister@github.com/some-org/some-repo.git")
             .unwrap();
 
@@ -357,7 +362,7 @@ mod tests {
             owner: "zed-industries".into(),
             repo: "zed".into(),
         };
-        let permalink = Github::new().build_permalink(
+        let permalink = Github::public_instance().build_permalink(
             remote,
             BuildPermalinkParams {
                 sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7",
@@ -372,7 +377,7 @@ mod tests {
 
     #[test]
     fn test_build_github_permalink() {
-        let permalink = Github::new().build_permalink(
+        let permalink = Github::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),
@@ -390,7 +395,7 @@ mod tests {
 
     #[test]
     fn test_build_github_permalink_with_single_line_selection() {
-        let permalink = Github::new().build_permalink(
+        let permalink = Github::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),
@@ -408,7 +413,7 @@ mod tests {
 
     #[test]
     fn test_build_github_permalink_with_multi_line_selection() {
-        let permalink = Github::new().build_permalink(
+        let permalink = Github::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),
@@ -431,7 +436,7 @@ mod tests {
             repo: "zed".into(),
         };
 
-        let github = Github::new();
+        let github = Github::public_instance();
         let message = "This does not contain a pull request";
         assert!(github.extract_pull_request(&remote, message).is_none());
 

crates/git_hosting_providers/src/providers/gitlab.rs 🔗

@@ -17,13 +17,17 @@ pub struct Gitlab {
 }
 
 impl Gitlab {
-    pub fn new() -> Self {
+    pub fn new(name: impl Into<String>, base_url: Url) -> Self {
         Self {
-            name: "GitLab".to_string(),
-            base_url: Url::parse("https://gitlab.com").unwrap(),
+            name: name.into(),
+            base_url,
         }
     }
 
+    pub fn public_instance() -> Self {
+        Self::new("GitLab", Url::parse("https://gitlab.com").unwrap())
+    }
+
     pub fn from_remote_url(remote_url: &str) -> Result<Self> {
         let host = get_host_from_git_remote_url(remote_url)?;
         if host == "gitlab.com" {
@@ -37,10 +41,10 @@ impl Gitlab {
             bail!("not a GitLab URL");
         }
 
-        Ok(Self {
-            name: "GitLab Self-Hosted".to_string(),
-            base_url: Url::parse(&format!("https://{}", host))?,
-        })
+        Ok(Self::new(
+            "GitLab Self-Hosted",
+            Url::parse(&format!("https://{}", host))?,
+        ))
     }
 }
 
@@ -135,7 +139,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_ssh_url() {
-        let parsed_remote = Gitlab::new()
+        let parsed_remote = Gitlab::public_instance()
             .parse_remote_url("git@gitlab.com:zed-industries/zed.git")
             .unwrap();
 
@@ -150,7 +154,7 @@ mod tests {
 
     #[test]
     fn test_parse_remote_url_given_https_url() {
-        let parsed_remote = Gitlab::new()
+        let parsed_remote = Gitlab::public_instance()
             .parse_remote_url("https://gitlab.com/zed-industries/zed.git")
             .unwrap();
 
@@ -200,7 +204,7 @@ mod tests {
 
     #[test]
     fn test_build_gitlab_permalink() {
-        let permalink = Gitlab::new().build_permalink(
+        let permalink = Gitlab::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),
@@ -218,7 +222,7 @@ mod tests {
 
     #[test]
     fn test_build_gitlab_permalink_with_single_line_selection() {
-        let permalink = Gitlab::new().build_permalink(
+        let permalink = Gitlab::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),
@@ -236,7 +240,7 @@ mod tests {
 
     #[test]
     fn test_build_gitlab_permalink_with_multi_line_selection() {
-        let permalink = Gitlab::new().build_permalink(
+        let permalink = Gitlab::public_instance().build_permalink(
             ParsedGitRemote {
                 owner: "zed-industries".into(),
                 repo: "zed".into(),