
Release Notes: - Added support for avatars in git blame for repositories hosted on codeberg <img width="1144" alt="Screenshot 2024-04-25 at 16 45 22" src="https://github.com/zed-industries/zed/assets/43210583/d44770d8-44ea-4c6b-a1c0-ac2d1d49408f"> Questions: - Should we move git stuff like `Commit`, `Author`, etc outside of hosting-specific files (I don't think so, as other hostings can have different stuff) - Should we also add support for self hosted forgejo instances or should it be a different PR?
110 lines
3.5 KiB
Rust
110 lines
3.5 KiB
Rust
use core::fmt;
|
|
use std::{ops::Range, sync::Arc};
|
|
|
|
use anyhow::Result;
|
|
use url::Url;
|
|
use util::{codeberg, github, http::HttpClient};
|
|
|
|
use crate::Oid;
|
|
|
|
#[derive(Clone, Debug, Hash)]
|
|
pub enum HostingProvider {
|
|
Github,
|
|
Gitlab,
|
|
Gitee,
|
|
Bitbucket,
|
|
Sourcehut,
|
|
Codeberg,
|
|
}
|
|
|
|
impl HostingProvider {
|
|
pub(crate) fn base_url(&self) -> Url {
|
|
let base_url = match self {
|
|
Self::Github => "https://github.com",
|
|
Self::Gitlab => "https://gitlab.com",
|
|
Self::Gitee => "https://gitee.com",
|
|
Self::Bitbucket => "https://bitbucket.org",
|
|
Self::Sourcehut => "https://git.sr.ht",
|
|
Self::Codeberg => "https://codeberg.org",
|
|
};
|
|
|
|
Url::parse(&base_url).unwrap()
|
|
}
|
|
|
|
/// Returns the fragment portion of the URL for the selected lines in
|
|
/// the representation the [`GitHostingProvider`] expects.
|
|
pub(crate) fn line_fragment(&self, selection: &Range<u32>) -> String {
|
|
if selection.start == selection.end {
|
|
let line = selection.start + 1;
|
|
|
|
match self {
|
|
Self::Github | Self::Gitlab | Self::Gitee | Self::Sourcehut | Self::Codeberg => {
|
|
format!("L{}", line)
|
|
}
|
|
Self::Bitbucket => format!("lines-{}", line),
|
|
}
|
|
} else {
|
|
let start_line = selection.start + 1;
|
|
let end_line = selection.end + 1;
|
|
|
|
match self {
|
|
Self::Github | Self::Codeberg => format!("L{}-L{}", start_line, end_line),
|
|
Self::Gitlab | Self::Gitee | Self::Sourcehut => {
|
|
format!("L{}-{}", start_line, end_line)
|
|
}
|
|
Self::Bitbucket => format!("lines-{}:{}", start_line, end_line),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn supports_avatars(&self) -> bool {
|
|
match self {
|
|
HostingProvider::Github | HostingProvider::Codeberg => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub async fn commit_author_avatar_url(
|
|
&self,
|
|
repo_owner: &str,
|
|
repo: &str,
|
|
commit: Oid,
|
|
client: Arc<dyn HttpClient>,
|
|
) -> Result<Option<Url>> {
|
|
Ok(match self {
|
|
HostingProvider::Github => {
|
|
let commit = commit.to_string();
|
|
github::fetch_github_commit_author(repo_owner, repo, &commit, &client)
|
|
.await?
|
|
.map(|author| -> Result<Url, url::ParseError> {
|
|
let mut url = Url::parse(&author.avatar_url)?;
|
|
url.set_query(Some("size=128"));
|
|
Ok(url)
|
|
})
|
|
.transpose()
|
|
}
|
|
HostingProvider::Codeberg => {
|
|
let commit = commit.to_string();
|
|
codeberg::fetch_codeberg_commit_author(repo_owner, repo, &commit, &client)
|
|
.await?
|
|
.map(|author| Url::parse(&author.avatar_url))
|
|
.transpose()
|
|
}
|
|
_ => Ok(None),
|
|
}?)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for HostingProvider {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let name = match self {
|
|
HostingProvider::Github => "GitHub",
|
|
HostingProvider::Gitlab => "GitLab",
|
|
HostingProvider::Gitee => "Gitee",
|
|
HostingProvider::Bitbucket => "Bitbucket",
|
|
HostingProvider::Sourcehut => "Sourcehut",
|
|
HostingProvider::Codeberg => "Codeberg",
|
|
};
|
|
write!(f, "{}", name)
|
|
}
|
|
}
|