1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
use crate::error::Result; use git2::{Commit, Repository}; use git_url_parse::GitUrl; pub fn get_url(repo: &Repository, remote: &str, commit: Commit) -> Result<String> { let remote = repo.find_remote(remote)?; let remote_url = remote.url().unwrap(); log::debug!("Found remote URL {} for 'origin'", remote_url); let remote_url = GitUrl::parse(remote_url).unwrap(); let forge = Forge::from_url(&remote_url)?; let url = forge.get_url(&remote_url, commit)?; Ok(url) } trait Forger { fn get_url(&self, url: &GitUrl, commit: Commit) -> Result<String>; } enum Forge { #[cfg(feature = "sourcehut")] SourceHut(sourcehut::SourceHut), #[cfg(feature = "github")] GitHub(github::GitHub), } impl Forger for Forge { fn get_url(&self, url: &GitUrl, commit: Commit) -> Result<String> { match self { #[cfg(feature = "sourcehut")] Forge::SourceHut(s) => s.get_url(url, commit), #[cfg(feature = "github")] Forge::GitHub(g) => g.get_url(url, commit), } } } impl Forge { fn from_url(url: &GitUrl) -> Result<Self> { match &url.host { Some(u) => match &u.as_str()[..] { #[cfg(feature = "sourcehut")] "git.sr.ht" => Ok(Forge::SourceHut(sourcehut::SourceHut {})), #[cfg(feature = "github")] "github.com" => Ok(Forge::GitHub(github::GitHub {})), v => unimplemented!("Host {} not handled", v), }, None => unimplemented!("URL {} has no domain", url), } } } #[cfg(feature = "sourcehut")] mod sourcehut { use super::Forger; use crate::error::Result; use git2::Commit; use git_url_parse::GitUrl; pub struct SourceHut {} impl Forger for SourceHut { fn get_url(&self, url: &GitUrl, commit: Commit) -> Result<String> { Ok(format!( "https://git.sr.ht/{}/commit/{}", url.fullname, commit.id() )) } } } #[cfg(feature = "github")] mod github { use super::Forger; use crate::error::Result; use git2::Commit; use git_url_parse::GitUrl; pub struct GitHub {} impl Forger for GitHub { fn get_url(&self, url: &GitUrl, commit: Commit) -> Result<String> { let repo = url.fullname.clone(); let msg = commit.message().unwrap_or_default().to_string(); let re = regex::Regex::new(r#"^Merge pull request #(\d+) from"#).unwrap(); for line in msg.lines() { if let Some(captures) = re.captures(line) { let pr_num = &captures[1]; return Ok(format!("https://github.com/{}/pull/{}", repo, pr_num)); } } Ok(format!( "https://github.com/{}/commit/{}", repo, commit.id() )) } } }