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}