use std::ops::Deref as _; use git_next_config::{Hostname, RepoPath}; use gix::remote::Direction; use tracing::info; use super::{GitRemote, RepoDetails, Repository}; #[tracing::instrument(skip_all)] pub fn validate(repository: &Repository, repo_details: &RepoDetails) -> Result<()> { let git_remote = repo_details.git_remote(); let push_remote = find_default_remote(repository, Direction::Push)?; let fetch_remote = find_default_remote(repository, Direction::Fetch)?; info!(config = %git_remote, push = %push_remote, fetch = %fetch_remote, "Check remotes match"); if git_remote != push_remote { return Err(Error::MismatchDefaultPushRemote { found: push_remote, expected: git_remote, }); } if git_remote != fetch_remote { return Err(Error::MismatchDefaultFetchRemote { found: fetch_remote, expected: git_remote, }); } Ok(()) } #[tracing::instrument(skip_all, fields(?direction))] pub fn find_default_remote( repository: &Repository, direction: gix::remote::Direction, ) -> Result { let repository = repository.deref().to_thread_local(); let Some(Ok(remote)) = repository.find_default_remote(gix::remote::Direction::Push) else { return Err(Error::NoDefaultPushRemote); }; let Some(url) = remote.url(direction) else { return Err(Error::NoUrlForDefaultPushRemote); }; let Some(host) = url.host() else { return Err(Error::NoHostnameForDefaultPushRemote); }; let path = url.path.to_string(); let path = path.strip_prefix('/').map_or(path.as_str(), |path| path); let path = path.strip_suffix(".git").map_or(path, |path| path); info!(%host, %path, "found"); Ok(GitRemote::new( Hostname::new(host), RepoPath(path.to_string()), )) } type Result = core::result::Result; #[derive(Debug, derive_more::Display)] pub enum Error { NoDefaultPushRemote, NoUrlForDefaultPushRemote, NoHostnameForDefaultPushRemote, UnableToOpenRepo(String), Io(std::io::Error), #[display("MismatchDefaultPushRemote(found: {found}, expected: {expected})")] MismatchDefaultPushRemote { found: GitRemote, expected: GitRemote, }, #[display("MismatchDefaultFetchRemote(found: {found}, expected: {expected})")] MismatchDefaultFetchRemote { found: GitRemote, expected: GitRemote, }, } impl std::error::Error for Error {}