Compare commits
No commits in common. "95a1526cde87afe492ea57523d594fcf871c0692" and "b5c0f5bd36d828879a761d8642ed3c33f9fa4093" have entirely different histories.
95a1526cde
...
b5c0f5bd36
14 changed files with 319 additions and 230 deletions
|
@ -20,6 +20,10 @@ impl GitDir {
|
||||||
pub const fn pathbuf(&self) -> &PathBuf {
|
pub const fn pathbuf(&self) -> &PathBuf {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_string(self) -> String {
|
||||||
|
self.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for GitDir {
|
impl std::fmt::Display for GitDir {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
|
|
@ -724,7 +724,8 @@ mod given {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
server::{Http, ServerConfig, ServerStorage, Webhook},
|
server::{Http, ServerConfig, ServerStorage, Webhook},
|
||||||
ForgeAlias, ForgeConfig, ForgeType, RepoAlias, RepoBranches, ServerRepoConfig, WebhookId,
|
BranchName, ForgeAlias, ForgeConfig, ForgeType, RepoAlias, RepoBranches, ServerRepoConfig,
|
||||||
|
WebhookId,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn a_name() -> String {
|
pub fn a_name() -> String {
|
||||||
|
|
37
crates/git/src/branch.rs
Normal file
37
crates/git/src/branch.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
use crate as git;
|
||||||
|
use git_next_config as config;
|
||||||
|
|
||||||
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("network: {0}")]
|
||||||
|
Network(#[from] kxio::network::NetworkError),
|
||||||
|
|
||||||
|
#[error("fetch: {0}")]
|
||||||
|
Fetch(#[from] git::fetch::Error),
|
||||||
|
|
||||||
|
#[error("push: {0}")]
|
||||||
|
Push(#[from] git::push::Error),
|
||||||
|
|
||||||
|
#[error("lock")]
|
||||||
|
Lock,
|
||||||
|
|
||||||
|
#[error("gix iter: {0}")]
|
||||||
|
GixIter(#[from] gix::reference::iter::Error),
|
||||||
|
|
||||||
|
#[error("gix iter init: {0}")]
|
||||||
|
GixIterInit(#[from] gix::reference::iter::init::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(
|
||||||
|
repository: &git::OpenRepository,
|
||||||
|
repo_details: &git::RepoDetails,
|
||||||
|
branch_name: config::BranchName,
|
||||||
|
to_commit: git::GitRef,
|
||||||
|
force: git::push::Force,
|
||||||
|
) -> Result<()> {
|
||||||
|
repository.fetch()?;
|
||||||
|
Ok(repository.push(repo_details, branch_name, to_commit, force)?)
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
//
|
//
|
||||||
|
pub mod branch;
|
||||||
pub mod commit;
|
pub mod commit;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod fetch;
|
pub mod fetch;
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use super::GitRef;
|
use super::GitRef;
|
||||||
use crate as git;
|
|
||||||
use git_next_config as config;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Force {
|
pub enum Force {
|
||||||
|
@ -16,39 +14,16 @@ impl std::fmt::Display for Force {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("io")]
|
|
||||||
Io(#[from] std::io::Error),
|
|
||||||
|
|
||||||
#[error("network: {0}")]
|
|
||||||
Network(#[from] kxio::network::NetworkError),
|
|
||||||
|
|
||||||
#[error("fetch: {0}")]
|
|
||||||
Fetch(#[from] git::fetch::Error),
|
|
||||||
|
|
||||||
#[error("lock")]
|
|
||||||
Lock,
|
|
||||||
|
|
||||||
#[error("gix open: {0}")]
|
#[error("gix open: {0}")]
|
||||||
Open(#[from] Box<gix::open::Error>),
|
Open(#[from] Box<gix::open::Error>),
|
||||||
|
|
||||||
#[error("gix iter: {0}")]
|
#[error("io: {0}")]
|
||||||
GixIter(#[from] gix::reference::iter::Error),
|
Push(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error("gix iter init: {0}")]
|
#[error("lock")]
|
||||||
GixIterInit(#[from] gix::reference::iter::init::Error),
|
Lock,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
repository: &git::OpenRepository,
|
|
||||||
repo_details: &git::RepoDetails,
|
|
||||||
branch_name: &config::BranchName,
|
|
||||||
to_commit: &git::GitRef,
|
|
||||||
force: &git::push::Force,
|
|
||||||
) -> Result<()> {
|
|
||||||
repository.fetch()?;
|
|
||||||
repository.push(repo_details, branch_name, to_commit, force)
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,43 +6,42 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{self as git, Repository};
|
use super::Error;
|
||||||
|
use crate as git;
|
||||||
use crate::{
|
use crate::{
|
||||||
repository::{
|
repository::{
|
||||||
open::{OpenRepository, OpenRepositoryLike},
|
open::{OpenRepository, OpenRepositoryLike},
|
||||||
Direction, RepositoryLike,
|
Direction, RepositoryLike, Result,
|
||||||
},
|
},
|
||||||
GitRemote, RepoDetails,
|
GitRemote, RepoDetails,
|
||||||
};
|
};
|
||||||
use git_next_config as config;
|
use git_next_config as config;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct MockRepository {
|
pub struct MockRepository(Arc<Mutex<Reality>>);
|
||||||
open_repos: Arc<Mutex<HashMap<config::GitDir, MockOpenRepository>>>,
|
|
||||||
}
|
|
||||||
impl MockRepository {
|
impl MockRepository {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self(Arc::new(Mutex::new(Reality::default())))
|
||||||
open_repos: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
pub fn can_open_repo(&mut self, gitdir: &config::GitDir) -> Result<MockOpenRepository> {
|
||||||
|
self.0
|
||||||
pub fn given_can_be_opened(&mut self, gitdir: &config::GitDir) -> MockOpenRepository {
|
|
||||||
let open_repo = MockOpenRepository::new();
|
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
self.open_repos
|
|
||||||
.lock()
|
.lock()
|
||||||
.map(|mut or| or.insert(gitdir.clone(), open_repo.clone()))
|
.map_err(|_| Error::MockLock)
|
||||||
.unwrap();
|
.map(|mut r| r.can_open_repo(gitdir))
|
||||||
open_repo
|
|
||||||
}
|
}
|
||||||
|
fn open_repository(
|
||||||
pub fn seal(self) -> (Repository, Self) {
|
&self,
|
||||||
(Repository::Mock(self.clone()), self)
|
gitdir: &config::GitDir,
|
||||||
|
) -> std::result::Result<MockOpenRepository, crate::repository::Error> {
|
||||||
|
self.0.lock().map_err(|_| Error::MockLock).and_then(|r| {
|
||||||
|
r.open_repository(gitdir)
|
||||||
|
.ok_or_else(|| Error::Open(format!("mock - could not open: {}", gitdir)))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn unseal(self, _repository: Repository) -> Self {
|
fn clone_repository(
|
||||||
// drop repository to allow same mutable access to mock repository
|
&self,
|
||||||
self
|
) -> std::result::Result<MockOpenRepository, crate::repository::Error> {
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl RepositoryLike for MockRepository {
|
impl RepositoryLike for MockRepository {
|
||||||
|
@ -50,101 +49,149 @@ impl RepositoryLike for MockRepository {
|
||||||
&self,
|
&self,
|
||||||
gitdir: &config::GitDir,
|
gitdir: &config::GitDir,
|
||||||
) -> std::result::Result<OpenRepository, crate::repository::Error> {
|
) -> std::result::Result<OpenRepository, crate::repository::Error> {
|
||||||
#[allow(clippy::unwrap_used)]
|
Ok(OpenRepository::Mock(self.open_repository(gitdir)?))
|
||||||
self.open_repos
|
|
||||||
.lock()
|
|
||||||
.map_err(|_| crate::repository::Error::MockLock)
|
|
||||||
.map(|or| or.get(gitdir).cloned())
|
|
||||||
.transpose()
|
|
||||||
.unwrap_or_else(|| Err(crate::repository::Error::InvalidGitDir(gitdir.clone())))
|
|
||||||
.map(|mor| mor.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn git_clone(
|
fn git_clone(
|
||||||
&self,
|
&self,
|
||||||
_repo_details: &RepoDetails,
|
_repo_details: &RepoDetails,
|
||||||
) -> std::result::Result<OpenRepository, crate::repository::Error> {
|
) -> std::result::Result<OpenRepository, crate::repository::Error> {
|
||||||
todo!("MockRepository::git_clone")
|
Ok(OpenRepository::Mock(self.clone_repository()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Reality {
|
||||||
|
openable_repos: HashMap<config::GitDir, MockOpenRepository>,
|
||||||
|
}
|
||||||
|
impl Reality {
|
||||||
|
pub fn can_open_repo(&mut self, gitdir: &config::GitDir) -> MockOpenRepository {
|
||||||
|
let mor = self.openable_repos.get(gitdir);
|
||||||
|
match mor {
|
||||||
|
Some(mor) => mor.clone(),
|
||||||
|
None => {
|
||||||
|
let mor = MockOpenRepository::default();
|
||||||
|
self.openable_repos.insert(gitdir.clone(), mor.clone());
|
||||||
|
mor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn open_repository(&self, gitdir: &config::GitDir) -> Option<MockOpenRepository> {
|
||||||
|
self.openable_repos.get(gitdir).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct InnerMockOpenRepository {
|
||||||
|
default_push_remote: Option<GitRemote>,
|
||||||
|
default_fetch_remote: Option<GitRemote>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct MockOpenRepository {
|
pub struct MockOpenRepository {
|
||||||
default_push_remote: Arc<Mutex<Option<GitRemote>>>,
|
inner: Arc<Mutex<InnerMockOpenRepository>>,
|
||||||
default_fetch_remote: Arc<Mutex<Option<GitRemote>>>,
|
|
||||||
}
|
}
|
||||||
impl MockOpenRepository {
|
impl std::ops::Deref for MockOpenRepository {
|
||||||
pub fn new() -> Self {
|
type Target = Arc<Mutex<InnerMockOpenRepository>>;
|
||||||
Self::default()
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
}
|
}
|
||||||
pub fn given_has_default_remote(&mut self, direction: Direction, remote: Option<GitRemote>) {
|
}
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
|
impl InnerMockOpenRepository {
|
||||||
|
pub fn has_default_remote(&mut self, direction: Direction, git_remote: GitRemote) {
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Push => self
|
Direction::Push => self.default_push_remote.replace(git_remote),
|
||||||
.default_push_remote
|
Direction::Fetch => self.default_fetch_remote.replace(git_remote),
|
||||||
.lock()
|
|
||||||
.map(|mut o| match remote {
|
|
||||||
Some(gr) => o.replace(gr),
|
|
||||||
None => o.take(),
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
Direction::Fetch => self
|
|
||||||
.default_fetch_remote
|
|
||||||
.lock()
|
|
||||||
.map(|mut o| match remote {
|
|
||||||
Some(gr) => o.replace(gr),
|
|
||||||
None => o.take(),
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<MockOpenRepository> for OpenRepository {
|
|
||||||
fn from(value: MockOpenRepository) -> Self {
|
|
||||||
Self::Mock(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
impl OpenRepositoryLike for MockOpenRepository {
|
impl OpenRepositoryLike for MockOpenRepository {
|
||||||
fn remote_branches(&self) -> git::push::Result<Vec<config::BranchName>> {
|
fn remote_branches(&self) -> git::branch::Result<Vec<config::BranchName>> {
|
||||||
todo!("MockOpenRepository::remote_branched")
|
self.inner
|
||||||
|
.lock()
|
||||||
|
.map(|inner| inner.remote_branches())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
fn find_default_remote(&self, direction: Direction) -> Option<GitRemote> {
|
||||||
|
self.inner
|
||||||
|
.lock()
|
||||||
|
.map(|inner| inner.find_default_remote(direction))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch(&self) -> core::result::Result<(), crate::fetch::Error> {
|
||||||
|
self.inner.lock().map(|inner| inner.fetch()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(
|
||||||
|
&self,
|
||||||
|
repo_details: &RepoDetails,
|
||||||
|
branch_name: git_next_config::BranchName,
|
||||||
|
to_commit: crate::GitRef,
|
||||||
|
force: crate::push::Force,
|
||||||
|
) -> core::result::Result<(), crate::push::Error> {
|
||||||
|
self.inner
|
||||||
|
.lock()
|
||||||
|
.map(|inner| inner.push(repo_details, branch_name, to_commit, force))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit_log(
|
||||||
|
&self,
|
||||||
|
branch_name: &git_next_config::BranchName,
|
||||||
|
find_commits: &[git::Commit],
|
||||||
|
) -> core::result::Result<Vec<crate::Commit>, git::commit::log::Error> {
|
||||||
|
self.inner
|
||||||
|
.lock()
|
||||||
|
.map(|inner| inner.commit_log(branch_name, find_commits))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_file(
|
||||||
|
&self,
|
||||||
|
branch_name: &git_next_config::BranchName,
|
||||||
|
file_name: &str,
|
||||||
|
) -> git::file::Result<String> {
|
||||||
|
self.inner
|
||||||
|
.lock()
|
||||||
|
.map(|inner| inner.read_file(branch_name, file_name))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl OpenRepositoryLike for InnerMockOpenRepository {
|
||||||
|
fn remote_branches(&self) -> git::branch::Result<Vec<config::BranchName>> {
|
||||||
|
todo!();
|
||||||
}
|
}
|
||||||
fn find_default_remote(&self, direction: Direction) -> Option<GitRemote> {
|
fn find_default_remote(&self, direction: Direction) -> Option<GitRemote> {
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Push => self
|
Direction::Push => self.default_push_remote.clone(),
|
||||||
.default_push_remote
|
Direction::Fetch => self.default_fetch_remote.clone(),
|
||||||
.lock()
|
|
||||||
.map(|r| r.clone())
|
|
||||||
.unwrap_or(None),
|
|
||||||
Direction::Fetch => self
|
|
||||||
.default_fetch_remote
|
|
||||||
.lock()
|
|
||||||
.map(|r| r.clone())
|
|
||||||
.unwrap_or(None),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(&self) -> core::result::Result<(), crate::fetch::Error> {
|
fn fetch(&self) -> core::result::Result<(), crate::fetch::Error> {
|
||||||
todo!("MockOpenRepository::fetch")
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(
|
fn push(
|
||||||
&self,
|
&self,
|
||||||
_repo_details: &RepoDetails,
|
_repo_details: &RepoDetails,
|
||||||
_branch_name: &git_next_config::BranchName,
|
_branch_name: git_next_config::BranchName,
|
||||||
_to_commit: &crate::GitRef,
|
_to_commit: crate::GitRef,
|
||||||
_force: &crate::push::Force,
|
_force: crate::push::Force,
|
||||||
) -> core::result::Result<(), crate::push::Error> {
|
) -> core::result::Result<(), crate::push::Error> {
|
||||||
todo!("MockOpenRepository::push")
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit_log(
|
fn commit_log(
|
||||||
&self,
|
&self,
|
||||||
_branch_name: &git_next_config::BranchName,
|
_branch_name: &git_next_config::BranchName,
|
||||||
_find_commits: &[git::Commit],
|
_find_commits: &[git::Commit],
|
||||||
) -> core::result::Result<Vec<crate::Commit>, git::commit::log::Error> {
|
) -> core::result::Result<Vec<crate::Commit>, crate::commit::log::Error> {
|
||||||
todo!("MockOpenRepository::commit_log")
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file(
|
fn read_file(
|
||||||
|
@ -152,6 +199,6 @@ impl OpenRepositoryLike for MockOpenRepository {
|
||||||
_branch_name: &git_next_config::BranchName,
|
_branch_name: &git_next_config::BranchName,
|
||||||
_file_name: &str,
|
_file_name: &str,
|
||||||
) -> git::file::Result<String> {
|
) -> git::file::Result<String> {
|
||||||
todo!("MockOpenRepository::read_file")
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,10 @@ mod tests;
|
||||||
use git_next_config as config;
|
use git_next_config as config;
|
||||||
use git_next_config::GitDir;
|
use git_next_config::GitDir;
|
||||||
|
|
||||||
pub use mock::MockRepository;
|
|
||||||
pub use open::OpenRepository;
|
pub use open::OpenRepository;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::validation::repo::validate_repo;
|
use crate::{repository::mock::MockRepository, validation::repo::validate_repo};
|
||||||
|
|
||||||
use super::RepoDetails;
|
use super::RepoDetails;
|
||||||
|
|
||||||
|
@ -25,9 +24,9 @@ pub enum Repository {
|
||||||
pub const fn new() -> Repository {
|
pub const fn new() -> Repository {
|
||||||
Repository::Real
|
Repository::Real
|
||||||
}
|
}
|
||||||
pub fn mock() -> MockRepository {
|
pub fn mock() -> (Repository, MockRepository) {
|
||||||
MockRepository::new()
|
let mock_repository = MockRepository::new();
|
||||||
// (Repository::Mock(mock_repository.clone()), mock_repository)
|
(Repository::Mock(mock_repository.clone()), mock_repository)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a repository, cloning if necessary
|
/// Opens a repository, cloning if necessary
|
||||||
|
|
|
@ -28,15 +28,15 @@ impl OpenRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub trait OpenRepositoryLike {
|
pub trait OpenRepositoryLike {
|
||||||
fn remote_branches(&self) -> git::push::Result<Vec<config::BranchName>>;
|
fn remote_branches(&self) -> git::branch::Result<Vec<config::BranchName>>;
|
||||||
fn find_default_remote(&self, direction: Direction) -> Option<git::GitRemote>;
|
fn find_default_remote(&self, direction: Direction) -> Option<git::GitRemote>;
|
||||||
fn fetch(&self) -> Result<(), git::fetch::Error>;
|
fn fetch(&self) -> Result<(), git::fetch::Error>;
|
||||||
fn push(
|
fn push(
|
||||||
&self,
|
&self,
|
||||||
repo_details: &git::RepoDetails,
|
repo_details: &git::RepoDetails,
|
||||||
branch_name: &config::BranchName,
|
branch_name: config::BranchName,
|
||||||
to_commit: &git::GitRef,
|
to_commit: git::GitRef,
|
||||||
force: &git::push::Force,
|
force: git::push::Force,
|
||||||
) -> git::push::Result<()>;
|
) -> git::push::Result<()>;
|
||||||
|
|
||||||
/// List of commits in a branch, optionally up-to any specified commit.
|
/// List of commits in a branch, optionally up-to any specified commit.
|
||||||
|
|
|
@ -10,11 +10,11 @@ use tracing::{info, warn};
|
||||||
#[derive(Clone, Debug, derive_more::Constructor)]
|
#[derive(Clone, Debug, derive_more::Constructor)]
|
||||||
pub struct RealOpenRepository(Arc<Mutex<gix::Repository>>);
|
pub struct RealOpenRepository(Arc<Mutex<gix::Repository>>);
|
||||||
impl super::OpenRepositoryLike for RealOpenRepository {
|
impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
fn remote_branches(&self) -> git::push::Result<Vec<config::BranchName>> {
|
fn remote_branches(&self) -> git::branch::Result<Vec<config::BranchName>> {
|
||||||
let refs = self
|
let refs = self
|
||||||
.0
|
.0
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|_| git::push::Error::Lock)
|
.map_err(|_| git::branch::Error::Lock)
|
||||||
.and_then(|repo| {
|
.and_then(|repo| {
|
||||||
Ok(repo.references()?).and_then(|refs| {
|
Ok(repo.references()?).and_then(|refs| {
|
||||||
Ok(refs.remote_branches().map(|rb| {
|
Ok(refs.remote_branches().map(|rb| {
|
||||||
|
@ -73,9 +73,9 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
fn push(
|
fn push(
|
||||||
&self,
|
&self,
|
||||||
repo_details: &git::RepoDetails,
|
repo_details: &git::RepoDetails,
|
||||||
branch_name: &config::BranchName,
|
branch_name: config::BranchName,
|
||||||
to_commit: &git::GitRef,
|
to_commit: git::GitRef,
|
||||||
force: &git::push::Force,
|
force: git::push::Force,
|
||||||
) -> Result<(), git::push::Error> {
|
) -> Result<(), git::push::Error> {
|
||||||
let origin = repo_details.origin();
|
let origin = repo_details.origin();
|
||||||
let force = match force {
|
let force = match force {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use crate as git;
|
|
||||||
|
|
||||||
mod validate {
|
mod validate {
|
||||||
use crate::{validation::repo::validate_repo, GitRemote, RepoDetails};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
use git_next_config::{ForgeDetails, GitDir, Hostname, RepoPath};
|
use git_next_config::{ForgeDetails, GitDir, Hostname, RepoPath};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
repository,
|
||||||
|
validation::{self, repo::validate_repo},
|
||||||
|
GitRemote, RepoDetails,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_ok_a_valid_repo() {
|
fn should_ok_a_valid_repo() {
|
||||||
let repo_details = RepoDetails::default()
|
let repo_details = RepoDetails::default()
|
||||||
|
@ -20,17 +22,25 @@ mod validate {
|
||||||
RepoPath::new("kemitix/test".to_string()),
|
RepoPath::new("kemitix/test".to_string()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut mock_repository = git::repository::mock();
|
let (repository, mut reality) = repository::mock();
|
||||||
{
|
let_assert!(
|
||||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
Ok(_) = reality.can_open_repo(&gitdir).map(
|
||||||
mock_open_repo
|
#[allow(clippy::significant_drop_tightening)]
|
||||||
.given_has_default_remote(git::repository::Direction::Push, Some(remote.clone()));
|
|open_repo| {
|
||||||
mock_open_repo
|
let_assert!(
|
||||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
Ok(_) = open_repo.lock().map(|mut open_repo| {
|
||||||
|
open_repo
|
||||||
|
.has_default_remote(repository::Direction::Push, remote.clone());
|
||||||
|
open_repo.has_default_remote(repository::Direction::Fetch, remote);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let (repository, _mock_repository) = mock_repository.seal();
|
)
|
||||||
|
);
|
||||||
|
|
||||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||||
let_assert!(Ok(_) = validate_repo(&open_repository, &repo_details));
|
|
||||||
|
let_assert!(Ok(_) = validation::repo::validate_repo(&open_repository, &repo_details));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -46,15 +56,23 @@ mod validate {
|
||||||
RepoPath::new("kemitix/test".to_string()),
|
RepoPath::new("kemitix/test".to_string()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut mock_repository = git::repository::mock();
|
let (repository, mut reality) = repository::mock();
|
||||||
{
|
let_assert!(
|
||||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
Ok(_) = reality.can_open_repo(&gitdir).map(
|
||||||
mock_open_repo.given_has_default_remote(git::repository::Direction::Push, None);
|
#[allow(clippy::significant_drop_tightening)]
|
||||||
mock_open_repo
|
|open_repo| {
|
||||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
let_assert!(
|
||||||
|
Ok(_) = open_repo.lock().map(|mut open_repo| {
|
||||||
|
// INFO: open_repo.has_default_remote(Direction::Push, remote.clone());
|
||||||
|
open_repo.has_default_remote(repository::Direction::Fetch, remote);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let (repository, _mock_repository) = mock_repository.seal();
|
)
|
||||||
|
);
|
||||||
|
|
||||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||||
|
|
||||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -70,15 +88,23 @@ mod validate {
|
||||||
RepoPath::new("kemitix/test".to_string()),
|
RepoPath::new("kemitix/test".to_string()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut mock_repository = git::repository::mock();
|
let (repository, mut reality) = repository::mock();
|
||||||
{
|
let_assert!(
|
||||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
Ok(_) = reality.can_open_repo(&gitdir).map(
|
||||||
mock_open_repo.given_has_default_remote(git::repository::Direction::Push, None);
|
#[allow(clippy::significant_drop_tightening)]
|
||||||
mock_open_repo
|
|open_repo| {
|
||||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
let_assert!(
|
||||||
|
Ok(_) = open_repo.lock().map(|mut open_repo| {
|
||||||
|
open_repo.has_default_remote(repository::Direction::Push, remote);
|
||||||
|
// INFO: open_repo.has_default_remote(Direction::Fetch, remote);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let (repository, _mock_repository) = mock_repository.seal();
|
)
|
||||||
|
);
|
||||||
|
|
||||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||||
|
|
||||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -98,16 +124,23 @@ mod validate {
|
||||||
RepoPath::new("kemitix/other".to_string()),
|
RepoPath::new("kemitix/other".to_string()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut mock_repository = git::repository::mock();
|
let (repository, mut reality) = repository::mock();
|
||||||
{
|
let_assert!(
|
||||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
Ok(_) = reality.can_open_repo(&gitdir).map(
|
||||||
mock_open_repo
|
#[allow(clippy::significant_drop_tightening)]
|
||||||
.given_has_default_remote(git::repository::Direction::Push, Some(other_remote));
|
|open_repo| {
|
||||||
mock_open_repo
|
let_assert!(
|
||||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
Ok(_) = open_repo.lock().map(|mut open_repo| {
|
||||||
|
open_repo.has_default_remote(repository::Direction::Push, other_remote);
|
||||||
|
open_repo.has_default_remote(repository::Direction::Fetch, remote);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let (repository, _mock_repository) = mock_repository.seal();
|
)
|
||||||
|
);
|
||||||
|
|
||||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||||
|
|
||||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -127,25 +160,33 @@ mod validate {
|
||||||
RepoPath::new("kemitix/other".to_string()),
|
RepoPath::new("kemitix/other".to_string()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut mock_repository = git::repository::mock();
|
let (repository, mut reality) = repository::mock();
|
||||||
{
|
let_assert!(
|
||||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
Ok(_) = reality.can_open_repo(&gitdir).map(
|
||||||
mock_open_repo.given_has_default_remote(git::repository::Direction::Push, Some(remote));
|
#[allow(clippy::significant_drop_tightening)]
|
||||||
mock_open_repo
|
|open_repo| {
|
||||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(other_remote));
|
let_assert!(
|
||||||
|
Ok(_) = open_repo.lock().map(|mut open_repo| {
|
||||||
|
open_repo.has_default_remote(repository::Direction::Push, remote);
|
||||||
|
open_repo
|
||||||
|
.has_default_remote(repository::Direction::Fetch, other_remote);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let (repository, _mock_repository) = mock_repository.seal();
|
)
|
||||||
|
);
|
||||||
|
|
||||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||||
|
|
||||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod git_clone {
|
mod git_clone {
|
||||||
use super::*;
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
use git_next_config::{ForgeDetails, GitDir, Hostname, RepoPath};
|
use git_next_config::{ForgeDetails, GitDir, Hostname, RepoPath};
|
||||||
|
|
||||||
use crate::{GitRemote, RepoDetails};
|
use crate::{repository, GitRemote, RepoDetails};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore] // slow test ~1.5 seconds
|
#[ignore] // slow test ~1.5 seconds
|
||||||
|
@ -159,9 +200,7 @@ mod git_clone {
|
||||||
.with_gitdir(GitDir::new(fs.base()))
|
.with_gitdir(GitDir::new(fs.base()))
|
||||||
.with_repo_path(RepoPath::new("kemitix/git-next".to_string()));
|
.with_repo_path(RepoPath::new("kemitix/git-next".to_string()));
|
||||||
let_assert!(Ok(open_repo) = r.git_clone(&repo_details));
|
let_assert!(Ok(open_repo) = r.git_clone(&repo_details));
|
||||||
let_assert!(
|
let_assert!(Some(remote) = open_repo.find_default_remote(repository::Direction::Fetch));
|
||||||
Some(remote) = open_repo.find_default_remote(git::repository::Direction::Fetch)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
remote,
|
remote,
|
||||||
GitRemote::new(
|
GitRemote::new(
|
||||||
|
|
|
@ -81,7 +81,9 @@ mod gitremote {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod push {
|
mod push {
|
||||||
use crate::{commit, push::Force, Commit, GitRef};
|
use crate::{commit, Commit, GitRef};
|
||||||
|
|
||||||
|
use crate::push::Force;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn force_no_should_display() {
|
fn force_no_should_display() {
|
||||||
|
@ -98,34 +100,6 @@ mod push {
|
||||||
"force-if-from:sha"
|
"force-if-from:sha"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// mod reset {
|
|
||||||
// use assert2::let_assert;
|
|
||||||
// use crate::tests::given;
|
|
||||||
// use super::*;
|
|
||||||
// // #[test]
|
|
||||||
// // fn should_perform_a_fetch() {
|
|
||||||
// // let fs = given::a_filesystem();
|
|
||||||
// // let (repository, _mock) = given::an_open_repository(&fs);
|
|
||||||
// // let repo_details = given::repo_details(&fs);
|
|
||||||
// // let branch_name = &repo_details.branch;
|
|
||||||
// // let commit = given::a_commit();
|
|
||||||
// // let gitref = GitRef::from(commit);
|
|
||||||
// // let_assert!(
|
|
||||||
// // Ok(_) = git::push::reset(
|
|
||||||
// // &repository,
|
|
||||||
// // &repo_details,
|
|
||||||
// // branch_name,
|
|
||||||
// // &gitref,
|
|
||||||
// // &git::push::Force::No
|
|
||||||
// // )
|
|
||||||
// // );
|
|
||||||
// // // let operations = mock.operations();
|
|
||||||
// // // assert_eq!(operations, vec![format!("push reset { /}")])
|
|
||||||
// // todo!()
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
mod repo_details {
|
mod repo_details {
|
||||||
|
|
||||||
|
@ -200,6 +174,26 @@ mod repo_details {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// mod branch {
|
||||||
|
// use super::*;
|
||||||
|
// use assert2::let_assert;
|
||||||
|
// #[test]
|
||||||
|
// fn reset_should_fetch_then_push() {
|
||||||
|
// // let repository = given::a_mock_open_repository();
|
||||||
|
// let fs = given::a_filesystem();
|
||||||
|
// let repo_detauls = given::repo_details(&fs);
|
||||||
|
// let repository = given::a_mock_open_repository();
|
||||||
|
// let_assert!(
|
||||||
|
// Ok(result) = git::branch::reset(
|
||||||
|
// repository,
|
||||||
|
// &repo_details,
|
||||||
|
// &repo_details.branch,
|
||||||
|
// git_ref,
|
||||||
|
// force
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
mod given {
|
mod given {
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
//
|
//
|
||||||
|
@ -362,12 +356,4 @@ mod given {
|
||||||
gitdir,
|
gitdir,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn an_open_repository(fs: &kxio::fs::FileSystem) -> (OpenRepository, MockRepository) {
|
|
||||||
// let (repo, mock) = git::repository::mock();
|
|
||||||
//
|
|
||||||
// let gitdir = a_git_dir(fs);
|
|
||||||
// let op = repo.open(&gitdir).unwrap();
|
|
||||||
// (op, mock)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,12 +66,12 @@ pub fn validate_positions(
|
||||||
let next_is_ancestor_of_dev = commit_histories.dev.iter().any(|dev| dev == &next);
|
let next_is_ancestor_of_dev = commit_histories.dev.iter().any(|dev| dev == &next);
|
||||||
if !next_is_ancestor_of_dev {
|
if !next_is_ancestor_of_dev {
|
||||||
info!("Next is not an ancestor of dev - resetting next to main");
|
info!("Next is not an ancestor of dev - resetting next to main");
|
||||||
if let Err(err) = git::push::reset(
|
if let Err(err) = git::branch::reset(
|
||||||
repository,
|
repository,
|
||||||
repo_details,
|
repo_details,
|
||||||
&repo_config.branches().next(),
|
repo_config.branches().next(),
|
||||||
&main.into(),
|
main.into(),
|
||||||
&git::push::Force::From(next.clone().into()),
|
git::push::Force::From(next.clone().into()),
|
||||||
) {
|
) {
|
||||||
warn!(?err, "Failed to reset next to main");
|
warn!(?err, "Failed to reset next to main");
|
||||||
return Err(git::validation::positions::Error::FailedToResetBranch {
|
return Err(git::validation::positions::Error::FailedToResetBranch {
|
||||||
|
@ -96,12 +96,12 @@ pub fn validate_positions(
|
||||||
repo_config.branches().main(),
|
repo_config.branches().main(),
|
||||||
repo_config.branches().next()
|
repo_config.branches().next()
|
||||||
);
|
);
|
||||||
if let Err(err) = git::push::reset(
|
if let Err(err) = git::branch::reset(
|
||||||
repository,
|
repository,
|
||||||
repo_details,
|
repo_details,
|
||||||
&repo_config.branches().next(),
|
repo_config.branches().next(),
|
||||||
&main.into(),
|
main.into(),
|
||||||
&git::push::Force::From(next.clone().into()),
|
git::push::Force::From(next.clone().into()),
|
||||||
) {
|
) {
|
||||||
warn!(?err, "Failed to reset next to main");
|
warn!(?err, "Failed to reset next to main");
|
||||||
return Err(git::validation::positions::Error::FailedToResetBranch {
|
return Err(git::validation::positions::Error::FailedToResetBranch {
|
||||||
|
|
|
@ -30,12 +30,12 @@ pub async fn advance_next(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
info!("Advancing next to commit '{}'", commit);
|
info!("Advancing next to commit '{}'", commit);
|
||||||
if let Err(err) = git::push::reset(
|
if let Err(err) = git::branch::reset(
|
||||||
&repository,
|
&repository,
|
||||||
&repo_details,
|
&repo_details,
|
||||||
&repo_config.branches().next(),
|
repo_config.branches().next(),
|
||||||
&commit.into(),
|
commit.into(),
|
||||||
&git::push::Force::No,
|
git::push::Force::No,
|
||||||
) {
|
) {
|
||||||
warn!(?err, "Failed")
|
warn!(?err, "Failed")
|
||||||
}
|
}
|
||||||
|
@ -84,12 +84,12 @@ pub async fn advance_main(
|
||||||
repository: &git::OpenRepository,
|
repository: &git::OpenRepository,
|
||||||
) {
|
) {
|
||||||
info!("Advancing main to next");
|
info!("Advancing main to next");
|
||||||
if let Err(err) = git::push::reset(
|
if let Err(err) = git::branch::reset(
|
||||||
repository,
|
repository,
|
||||||
repo_details,
|
repo_details,
|
||||||
&repo_config.branches().main(),
|
repo_config.branches().main(),
|
||||||
&next.into(),
|
next.into(),
|
||||||
&git::push::Force::No,
|
git::push::Force::No,
|
||||||
) {
|
) {
|
||||||
warn!(?err, "Failed")
|
warn!(?err, "Failed")
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub enum Error {
|
||||||
File(git::file::Error),
|
File(git::file::Error),
|
||||||
Config(config::server::Error),
|
Config(config::server::Error),
|
||||||
Toml(toml::de::Error),
|
Toml(toml::de::Error),
|
||||||
Branch(git::push::Error),
|
Branch(git::branch::Error),
|
||||||
BranchNotFound(config::BranchName),
|
BranchNotFound(config::BranchName),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue