bitbucket.rs

  1use url::Url;
  2
  3use git::{BuildCommitPermalinkParams, BuildPermalinkParams, GitHostingProvider, ParsedGitRemote};
  4
  5pub struct Bitbucket;
  6
  7impl GitHostingProvider for Bitbucket {
  8    fn name(&self) -> String {
  9        "Bitbucket".to_string()
 10    }
 11
 12    fn base_url(&self) -> Url {
 13        Url::parse("https://bitbucket.org").unwrap()
 14    }
 15
 16    fn supports_avatars(&self) -> bool {
 17        false
 18    }
 19
 20    fn format_line_number(&self, line: u32) -> String {
 21        format!("lines-{line}")
 22    }
 23
 24    fn format_line_numbers(&self, start_line: u32, end_line: u32) -> String {
 25        format!("lines-{start_line}:{end_line}")
 26    }
 27
 28    fn parse_remote_url<'a>(&self, url: &'a str) -> Option<ParsedGitRemote<'a>> {
 29        if url.contains("bitbucket.org") {
 30            let (_, repo_with_owner) = url.trim_end_matches(".git").split_once("bitbucket.org")?;
 31            let (owner, repo) = repo_with_owner
 32                .trim_start_matches('/')
 33                .trim_start_matches(':')
 34                .split_once('/')?;
 35
 36            return Some(ParsedGitRemote { owner, repo });
 37        }
 38
 39        None
 40    }
 41
 42    fn build_commit_permalink(
 43        &self,
 44        remote: &ParsedGitRemote,
 45        params: BuildCommitPermalinkParams,
 46    ) -> Url {
 47        let BuildCommitPermalinkParams { sha } = params;
 48        let ParsedGitRemote { owner, repo } = remote;
 49
 50        self.base_url()
 51            .join(&format!("{owner}/{repo}/commits/{sha}"))
 52            .unwrap()
 53    }
 54
 55    fn build_permalink(&self, remote: ParsedGitRemote, params: BuildPermalinkParams) -> Url {
 56        let ParsedGitRemote { owner, repo } = remote;
 57        let BuildPermalinkParams {
 58            sha,
 59            path,
 60            selection,
 61        } = params;
 62
 63        let mut permalink = self
 64            .base_url()
 65            .join(&format!("{owner}/{repo}/src/{sha}/{path}"))
 66            .unwrap();
 67        permalink.set_fragment(
 68            selection
 69                .map(|selection| self.line_fragment(&selection))
 70                .as_deref(),
 71        );
 72        permalink
 73    }
 74}
 75
 76#[cfg(test)]
 77mod tests {
 78    use std::sync::Arc;
 79
 80    use git::{parse_git_remote_url, GitHostingProviderRegistry};
 81
 82    use super::*;
 83
 84    #[test]
 85    fn test_parse_git_remote_url_bitbucket_https_with_username() {
 86        let provider_registry = Arc::new(GitHostingProviderRegistry::new());
 87        provider_registry.register_hosting_provider(Arc::new(Bitbucket));
 88        let url = "https://thorstenballzed@bitbucket.org/thorstenzed/testingrepo.git";
 89        let (provider, parsed) = parse_git_remote_url(provider_registry, url).unwrap();
 90        assert_eq!(provider.name(), "Bitbucket");
 91        assert_eq!(parsed.owner, "thorstenzed");
 92        assert_eq!(parsed.repo, "testingrepo");
 93    }
 94
 95    #[test]
 96    fn test_parse_git_remote_url_bitbucket_https_without_username() {
 97        let provider_registry = Arc::new(GitHostingProviderRegistry::new());
 98        provider_registry.register_hosting_provider(Arc::new(Bitbucket));
 99        let url = "https://bitbucket.org/thorstenzed/testingrepo.git";
100        let (provider, parsed) = parse_git_remote_url(provider_registry, url).unwrap();
101        assert_eq!(provider.name(), "Bitbucket");
102        assert_eq!(parsed.owner, "thorstenzed");
103        assert_eq!(parsed.repo, "testingrepo");
104    }
105
106    #[test]
107    fn test_parse_git_remote_url_bitbucket_git() {
108        let provider_registry = Arc::new(GitHostingProviderRegistry::new());
109        provider_registry.register_hosting_provider(Arc::new(Bitbucket));
110        let url = "git@bitbucket.org:thorstenzed/testingrepo.git";
111        let (provider, parsed) = parse_git_remote_url(provider_registry, url).unwrap();
112        assert_eq!(provider.name(), "Bitbucket");
113        assert_eq!(parsed.owner, "thorstenzed");
114        assert_eq!(parsed.repo, "testingrepo");
115    }
116
117    #[test]
118    fn test_build_bitbucket_permalink_from_ssh_url() {
119        let remote = ParsedGitRemote {
120            owner: "thorstenzed",
121            repo: "testingrepo",
122        };
123        let permalink = Bitbucket.build_permalink(
124            remote,
125            BuildPermalinkParams {
126                sha: "f00b4r",
127                path: "main.rs",
128                selection: None,
129            },
130        );
131
132        let expected_url = "https://bitbucket.org/thorstenzed/testingrepo/src/f00b4r/main.rs";
133        assert_eq!(permalink.to_string(), expected_url.to_string())
134    }
135
136    #[test]
137    fn test_build_bitbucket_permalink_from_ssh_url_single_line_selection() {
138        let remote = ParsedGitRemote {
139            owner: "thorstenzed",
140            repo: "testingrepo",
141        };
142        let permalink = Bitbucket.build_permalink(
143            remote,
144            BuildPermalinkParams {
145                sha: "f00b4r",
146                path: "main.rs",
147                selection: Some(6..6),
148            },
149        );
150
151        let expected_url =
152            "https://bitbucket.org/thorstenzed/testingrepo/src/f00b4r/main.rs#lines-7";
153        assert_eq!(permalink.to_string(), expected_url.to_string())
154    }
155
156    #[test]
157    fn test_build_bitbucket_permalink_from_ssh_url_multi_line_selection() {
158        let remote = ParsedGitRemote {
159            owner: "thorstenzed",
160            repo: "testingrepo",
161        };
162        let permalink = Bitbucket.build_permalink(
163            remote,
164            BuildPermalinkParams {
165                sha: "f00b4r",
166                path: "main.rs",
167                selection: Some(23..47),
168            },
169        );
170
171        let expected_url =
172            "https://bitbucket.org/thorstenzed/testingrepo/src/f00b4r/main.rs#lines-24:48";
173        assert_eq!(permalink.to_string(), expected_url.to_string())
174    }
175}