codeberg.rs

  1use std::sync::Arc;
  2
  3use anyhow::Result;
  4use async_trait::async_trait;
  5use url::Url;
  6use util::codeberg;
  7use util::http::HttpClient;
  8
  9use crate::{
 10    BuildCommitPermalinkParams, BuildPermalinkParams, GitHostingProvider, Oid, ParsedGitRemote,
 11};
 12
 13pub struct Codeberg;
 14
 15#[async_trait]
 16impl GitHostingProvider for Codeberg {
 17    fn name(&self) -> String {
 18        "Codeberg".to_string()
 19    }
 20
 21    fn base_url(&self) -> Url {
 22        Url::parse("https://codeberg.org").unwrap()
 23    }
 24
 25    fn supports_avatars(&self) -> bool {
 26        true
 27    }
 28
 29    fn format_line_number(&self, line: u32) -> String {
 30        format!("L{line}")
 31    }
 32
 33    fn format_line_numbers(&self, start_line: u32, end_line: u32) -> String {
 34        format!("L{start_line}-L{end_line}")
 35    }
 36
 37    fn parse_remote_url<'a>(&self, url: &'a str) -> Option<ParsedGitRemote<'a>> {
 38        if url.starts_with("git@codeberg.org:") || url.starts_with("https://codeberg.org/") {
 39            let repo_with_owner = url
 40                .trim_start_matches("git@codeberg.org:")
 41                .trim_start_matches("https://codeberg.org/")
 42                .trim_end_matches(".git");
 43
 44            let (owner, repo) = repo_with_owner.split_once('/')?;
 45
 46            return Some(ParsedGitRemote { owner, repo });
 47        }
 48
 49        None
 50    }
 51
 52    fn build_commit_permalink(
 53        &self,
 54        remote: &ParsedGitRemote,
 55        params: BuildCommitPermalinkParams,
 56    ) -> Url {
 57        let BuildCommitPermalinkParams { sha } = params;
 58        let ParsedGitRemote { owner, repo } = remote;
 59
 60        self.base_url()
 61            .join(&format!("{owner}/{repo}/commit/{sha}"))
 62            .unwrap()
 63    }
 64
 65    fn build_permalink(&self, remote: ParsedGitRemote, params: BuildPermalinkParams) -> Url {
 66        let ParsedGitRemote { owner, repo } = remote;
 67        let BuildPermalinkParams {
 68            sha,
 69            path,
 70            selection,
 71        } = params;
 72
 73        let mut permalink = self
 74            .base_url()
 75            .join(&format!("{owner}/{repo}/src/commit/{sha}/{path}"))
 76            .unwrap();
 77        permalink.set_fragment(
 78            selection
 79                .map(|selection| self.line_fragment(&selection))
 80                .as_deref(),
 81        );
 82        permalink
 83    }
 84
 85    async fn commit_author_avatar_url(
 86        &self,
 87        repo_owner: &str,
 88        repo: &str,
 89        commit: Oid,
 90        http_client: Arc<dyn HttpClient>,
 91    ) -> Result<Option<Url>> {
 92        let commit = commit.to_string();
 93        let avatar_url =
 94            codeberg::fetch_codeberg_commit_author(repo_owner, repo, &commit, &http_client)
 95                .await?
 96                .map(|author| Url::parse(&author.avatar_url))
 97                .transpose()?;
 98        Ok(avatar_url)
 99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_build_codeberg_permalink_from_ssh_url() {
108        let remote = ParsedGitRemote {
109            owner: "rajveermalviya",
110            repo: "zed",
111        };
112        let permalink = Codeberg.build_permalink(
113            remote,
114            BuildPermalinkParams {
115                sha: "faa6f979be417239b2e070dbbf6392b909224e0b",
116                path: "crates/editor/src/git/permalink.rs",
117                selection: None,
118            },
119        );
120
121        let expected_url = "https://codeberg.org/rajveermalviya/zed/src/commit/faa6f979be417239b2e070dbbf6392b909224e0b/crates/editor/src/git/permalink.rs";
122        assert_eq!(permalink.to_string(), expected_url.to_string())
123    }
124
125    #[test]
126    fn test_build_codeberg_permalink_from_ssh_url_single_line_selection() {
127        let remote = ParsedGitRemote {
128            owner: "rajveermalviya",
129            repo: "zed",
130        };
131        let permalink = Codeberg.build_permalink(
132            remote,
133            BuildPermalinkParams {
134                sha: "faa6f979be417239b2e070dbbf6392b909224e0b",
135                path: "crates/editor/src/git/permalink.rs",
136                selection: Some(6..6),
137            },
138        );
139
140        let expected_url = "https://codeberg.org/rajveermalviya/zed/src/commit/faa6f979be417239b2e070dbbf6392b909224e0b/crates/editor/src/git/permalink.rs#L7";
141        assert_eq!(permalink.to_string(), expected_url.to_string())
142    }
143
144    #[test]
145    fn test_build_codeberg_permalink_from_ssh_url_multi_line_selection() {
146        let remote = ParsedGitRemote {
147            owner: "rajveermalviya",
148            repo: "zed",
149        };
150        let permalink = Codeberg.build_permalink(
151            remote,
152            BuildPermalinkParams {
153                sha: "faa6f979be417239b2e070dbbf6392b909224e0b",
154                path: "crates/editor/src/git/permalink.rs",
155                selection: Some(23..47),
156            },
157        );
158
159        let expected_url = "https://codeberg.org/rajveermalviya/zed/src/commit/faa6f979be417239b2e070dbbf6392b909224e0b/crates/editor/src/git/permalink.rs#L24-L48";
160        assert_eq!(permalink.to_string(), expected_url.to_string())
161    }
162
163    #[test]
164    fn test_build_codeberg_permalink_from_https_url() {
165        let remote = ParsedGitRemote {
166            owner: "rajveermalviya",
167            repo: "zed",
168        };
169        let permalink = Codeberg.build_permalink(
170            remote,
171            BuildPermalinkParams {
172                sha: "faa6f979be417239b2e070dbbf6392b909224e0b",
173                path: "crates/zed/src/main.rs",
174                selection: None,
175            },
176        );
177
178        let expected_url = "https://codeberg.org/rajveermalviya/zed/src/commit/faa6f979be417239b2e070dbbf6392b909224e0b/crates/zed/src/main.rs";
179        assert_eq!(permalink.to_string(), expected_url.to_string())
180    }
181
182    #[test]
183    fn test_build_codeberg_permalink_from_https_url_single_line_selection() {
184        let remote = ParsedGitRemote {
185            owner: "rajveermalviya",
186            repo: "zed",
187        };
188        let permalink = Codeberg.build_permalink(
189            remote,
190            BuildPermalinkParams {
191                sha: "faa6f979be417239b2e070dbbf6392b909224e0b",
192                path: "crates/zed/src/main.rs",
193                selection: Some(6..6),
194            },
195        );
196
197        let expected_url = "https://codeberg.org/rajveermalviya/zed/src/commit/faa6f979be417239b2e070dbbf6392b909224e0b/crates/zed/src/main.rs#L7";
198        assert_eq!(permalink.to_string(), expected_url.to_string())
199    }
200
201    #[test]
202    fn test_build_codeberg_permalink_from_https_url_multi_line_selection() {
203        let remote = ParsedGitRemote {
204            owner: "rajveermalviya",
205            repo: "zed",
206        };
207        let permalink = Codeberg.build_permalink(
208            remote,
209            BuildPermalinkParams {
210                sha: "faa6f979be417239b2e070dbbf6392b909224e0b",
211                path: "crates/zed/src/main.rs",
212                selection: Some(23..47),
213            },
214        );
215
216        let expected_url = "https://codeberg.org/rajveermalviya/zed/src/commit/faa6f979be417239b2e070dbbf6392b909224e0b/crates/zed/src/main.rs#L24-L48";
217        assert_eq!(permalink.to_string(), expected_url.to_string())
218    }
219}