bitbucket.rs

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