hosting_provider.rs

  1use core::fmt;
  2use std::{ops::Range, sync::Arc};
  3
  4use anyhow::Result;
  5use url::Url;
  6use util::{github, http::HttpClient};
  7
  8use crate::Oid;
  9
 10#[derive(Clone, Debug, Hash)]
 11pub enum HostingProvider {
 12    Github,
 13    Gitlab,
 14    Gitee,
 15    Bitbucket,
 16    Sourcehut,
 17    Codeberg,
 18}
 19
 20impl HostingProvider {
 21    pub(crate) fn base_url(&self) -> Url {
 22        let base_url = match self {
 23            Self::Github => "https://github.com",
 24            Self::Gitlab => "https://gitlab.com",
 25            Self::Gitee => "https://gitee.com",
 26            Self::Bitbucket => "https://bitbucket.org",
 27            Self::Sourcehut => "https://git.sr.ht",
 28            Self::Codeberg => "https://codeberg.org",
 29        };
 30
 31        Url::parse(&base_url).unwrap()
 32    }
 33
 34    /// Returns the fragment portion of the URL for the selected lines in
 35    /// the representation the [`GitHostingProvider`] expects.
 36    pub(crate) fn line_fragment(&self, selection: &Range<u32>) -> String {
 37        if selection.start == selection.end {
 38            let line = selection.start + 1;
 39
 40            match self {
 41                Self::Github | Self::Gitlab | Self::Gitee | Self::Sourcehut | Self::Codeberg => {
 42                    format!("L{}", line)
 43                }
 44                Self::Bitbucket => format!("lines-{}", line),
 45            }
 46        } else {
 47            let start_line = selection.start + 1;
 48            let end_line = selection.end + 1;
 49
 50            match self {
 51                Self::Github | Self::Codeberg => format!("L{}-L{}", start_line, end_line),
 52                Self::Gitlab | Self::Gitee | Self::Sourcehut => {
 53                    format!("L{}-{}", start_line, end_line)
 54                }
 55                Self::Bitbucket => format!("lines-{}:{}", start_line, end_line),
 56            }
 57        }
 58    }
 59
 60    pub fn supports_avatars(&self) -> bool {
 61        match self {
 62            HostingProvider::Github => true,
 63            _ => false,
 64        }
 65    }
 66
 67    pub async fn commit_author_avatar_url(
 68        &self,
 69        repo_owner: &str,
 70        repo: &str,
 71        commit: Oid,
 72        client: Arc<dyn HttpClient>,
 73    ) -> Result<Option<Url>> {
 74        match self {
 75            HostingProvider::Github => {
 76                let commit = commit.to_string();
 77
 78                let author =
 79                    github::fetch_github_commit_author(repo_owner, repo, &commit, &client).await?;
 80
 81                let url = if let Some(author) = author {
 82                    let mut url = Url::parse(&author.avatar_url)?;
 83                    url.set_query(Some("size=128"));
 84                    Some(url)
 85                } else {
 86                    None
 87                };
 88                Ok(url)
 89            }
 90            _ => Ok(None),
 91        }
 92    }
 93}
 94
 95impl fmt::Display for HostingProvider {
 96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 97        let name = match self {
 98            HostingProvider::Github => "GitHub",
 99            HostingProvider::Gitlab => "GitLab",
100            HostingProvider::Gitee => "Gitee",
101            HostingProvider::Bitbucket => "Bitbucket",
102            HostingProvider::Sourcehut => "Sourcehut",
103            HostingProvider::Codeberg => "Codeberg",
104        };
105        write!(f, "{}", name)
106    }
107}