use std::path::PathBuf;
use anyhow::Context;
use git2::{Remote, Repository};
pub struct OwnerRepo {
pub owner: String,
pub repo: String,
}
pub struct Git {
pub repo: Option<Repository>,
}
impl Git {
pub fn new() -> Self {
Self {
repo: Repository::open("./.").ok(),
}
}
pub fn remotes(&self) -> anyhow::Result<Vec<Remote>> {
let repo = self
.repo
.as_ref()
.context("No repository found in the current path even though one is needed!")?;
let remotes = repo
.remotes()?
.into_iter()
.filter_map(|remote| {
let remote = remote?;
let remote = repo.find_remote(remote).ok()?;
Some(remote)
})
.collect::<Vec<_>>();
Ok(remotes)
}
pub fn owner_repo(&self) -> anyhow::Result<OwnerRepo> {
let remotes = self
.remotes()?
.into_iter()
.filter_map(|remote| {
let mut git_url = remote.url().map(PathBuf::from)?;
let repo = git_url
.file_name()?
.to_str()?
.trim_end_matches(".git")
.to_owned();
git_url.pop();
let owner = git_url
.file_name()?
.to_str()?
.split_once(":")
.map(|(_junk, owner)| owner.to_owned())?;
let remote_name = remote.name()?.to_owned();
Some((remote_name, owner, repo))
})
.inspect(|x| tracing::debug!("{x:?}"))
.collect::<Vec<_>>();
remotes
.iter()
.find_map(|(name, owner, repo)| (*name == "origin").then_some((owner, repo)))
.or_else(|| remotes.first().map(|(_, owner, repo)| (owner, repo)))
.map(|(owner, repo)| OwnerRepo {
owner: owner.clone(),
repo: repo.clone(),
})
.context("Couldn't find owner and repo")
}
}