2024-05-11 19:46:20 +01:00
|
|
|
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<GitRemote> {
|
|
|
|
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(
|
2024-05-14 07:59:31 +01:00
|
|
|
Hostname::new(host),
|
2024-05-11 19:46:20 +01:00
|
|
|
RepoPath(path.to_string()),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
type Result<T> = core::result::Result<T, Error>;
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
|
|
|
NoDefaultPushRemote,
|
|
|
|
NoUrlForDefaultPushRemote,
|
|
|
|
NoHostnameForDefaultPushRemote,
|
|
|
|
UnableToOpenRepo(String),
|
|
|
|
Io(std::io::Error),
|
|
|
|
MismatchDefaultPushRemote {
|
|
|
|
found: GitRemote,
|
|
|
|
expected: GitRemote,
|
|
|
|
},
|
|
|
|
MismatchDefaultFetchRemote {
|
|
|
|
found: GitRemote,
|
|
|
|
expected: GitRemote,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
impl std::error::Error for Error {}
|
|
|
|
impl std::fmt::Display for Error {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
Self::NoDefaultPushRemote => write!(f, "There is no default push remote"),
|
|
|
|
Self::NoUrlForDefaultPushRemote => write!(f, "The default push remote has no url"),
|
|
|
|
Self::NoHostnameForDefaultPushRemote => {
|
|
|
|
write!(f, "The default push remote has no hostname")
|
|
|
|
}
|
|
|
|
Self::UnableToOpenRepo(err) => write!(f, "Unable to open the git dir: {err}"),
|
|
|
|
Self::Io(err) => write!(f, "IO Error: {err:?}"),
|
|
|
|
Self::MismatchDefaultPushRemote { found, expected } => write!(
|
|
|
|
f,
|
|
|
|
"The default push remote doesn't match: {found}, expected: {expected}"
|
|
|
|
),
|
|
|
|
Self::MismatchDefaultFetchRemote { found, expected } => write!(
|
|
|
|
f,
|
|
|
|
"The default fetch remote doesn't match: {found}, expected: {expected}"
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|