WIP RepositoryFactory trait
This commit is contained in:
parent
ea20afee12
commit
c126020656
22 changed files with 861 additions and 816 deletions
|
@ -96,3 +96,4 @@ tokio = { version = "1.37", features = ["rt", "macros"] }
|
|||
assert2 = "0.3"
|
||||
pretty_assertions = "1.4"
|
||||
rand = "0.8"
|
||||
mockall = "0.12"
|
||||
|
|
|
@ -30,7 +30,7 @@ enum Server {
|
|||
async fn main() {
|
||||
let fs = fs::new(PathBuf::default());
|
||||
let net = Network::new_real();
|
||||
let repo = git_next_git::repository::new();
|
||||
let repo = git_next_git::repository::real();
|
||||
let commands = Commands::parse();
|
||||
|
||||
match commands.command {
|
||||
|
|
|
@ -51,12 +51,15 @@ actix = { workspace = true }
|
|||
# actix-rt = { workspace = true }
|
||||
# tokio = { workspace = true }
|
||||
|
||||
mockall = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# Testing
|
||||
assert2 = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
|
||||
|
||||
[lints.clippy]
|
||||
nursery = { level = "warn", priority = -1 }
|
||||
# pedantic = "warn"
|
||||
|
|
|
@ -47,7 +47,7 @@ pub enum Error {
|
|||
}
|
||||
|
||||
pub fn reset(
|
||||
repository: &git::OpenRepository,
|
||||
repository: &dyn git::repository::OpenRepositoryLike,
|
||||
repo_details: &git::RepoDetails,
|
||||
branch_name: &config::BranchName,
|
||||
to_commit: &git::GitRef,
|
||||
|
|
|
@ -10,10 +10,10 @@ use crate as git;
|
|||
use git_next_config as config;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct MockRepository {
|
||||
open_repos: Arc<Mutex<HashMap<config::GitDir, git::repository::MockOpenRepository>>>,
|
||||
pub struct FakeRepository {
|
||||
open_repos: Arc<Mutex<HashMap<config::GitDir, git::repository::FakeOpenRepository>>>,
|
||||
}
|
||||
impl MockRepository {
|
||||
impl FakeRepository {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
open_repos: Default::default(),
|
||||
|
@ -23,8 +23,8 @@ impl MockRepository {
|
|||
pub fn given_can_be_opened(
|
||||
&mut self,
|
||||
gitdir: &config::GitDir,
|
||||
) -> git::repository::MockOpenRepository {
|
||||
let open_repo = git::repository::MockOpenRepository::new();
|
||||
) -> git::repository::FakeOpenRepository {
|
||||
let open_repo = git::repository::FakeOpenRepository::new();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
self.open_repos
|
||||
.lock()
|
||||
|
@ -34,20 +34,20 @@ impl MockRepository {
|
|||
}
|
||||
|
||||
pub fn seal(self) -> (git::Repository, Self) {
|
||||
(git::Repository::Mock(self.clone()), self)
|
||||
(git::Repository::Fake(self.clone()), self)
|
||||
}
|
||||
pub fn unseal(self, _repository: git::Repository) -> Self {
|
||||
// drop repository to allow same mutable access to mock repository
|
||||
self
|
||||
}
|
||||
pub fn get(&self, gitdir: &config::GitDir) -> Option<git::repository::MockOpenRepository> {
|
||||
pub fn get(&self, gitdir: &config::GitDir) -> Option<git::repository::FakeOpenRepository> {
|
||||
self.open_repos
|
||||
.lock()
|
||||
.map(|or| or.get(gitdir).cloned())
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
impl git::repository::RepositoryLike for MockRepository {
|
||||
impl git::repository::RepositoryLike for FakeRepository {
|
||||
fn open(
|
||||
&self,
|
||||
gitdir: &config::GitDir,
|
||||
|
@ -55,7 +55,7 @@ impl git::repository::RepositoryLike for MockRepository {
|
|||
#[allow(clippy::unwrap_used)]
|
||||
self.open_repos
|
||||
.lock()
|
||||
.map_err(|_| crate::repository::Error::MockLock)
|
||||
.map_err(|_| crate::repository::Error::FakeLock)
|
||||
.map(|or| or.get(gitdir).cloned())
|
||||
.transpose()
|
||||
.unwrap_or_else(|| Err(crate::repository::Error::InvalidGitDir(gitdir.clone())))
|
|
@ -1,12 +1,16 @@
|
|||
//
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
pub use mock::MockRepository;
|
||||
#[cfg(test)]
|
||||
pub use open::MockOpenRepository;
|
||||
mod fake;
|
||||
use std::sync::{atomic::AtomicBool, Arc, Mutex};
|
||||
|
||||
mod open;
|
||||
use derive_more::Deref as _;
|
||||
|
||||
#[cfg(test)]
|
||||
pub use fake::FakeRepository;
|
||||
#[cfg(test)]
|
||||
pub use open::FakeOpenRepository;
|
||||
|
||||
pub mod open;
|
||||
mod real;
|
||||
mod test;
|
||||
|
||||
|
@ -26,27 +30,28 @@ pub use real::RealRepository;
|
|||
use tracing::info;
|
||||
|
||||
use crate::repository::test::TestRepository;
|
||||
|
||||
use crate::validation::repo::validate_repo;
|
||||
|
||||
use super::RepoDetails;
|
||||
|
||||
// TODO: #[deprecated]
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum Repository {
|
||||
Real,
|
||||
#[cfg(test)]
|
||||
Mock(MockRepository),
|
||||
Fake(FakeRepository),
|
||||
Test(TestRepository),
|
||||
}
|
||||
|
||||
#[deprecated(note = "use git::repository::real()")]
|
||||
pub const fn new() -> Repository {
|
||||
Repository::Real
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn mock() -> MockRepository {
|
||||
MockRepository::new()
|
||||
pub fn fake() -> FakeRepository {
|
||||
FakeRepository::new()
|
||||
}
|
||||
|
||||
pub const fn test(fs: kxio::fs::FileSystem) -> TestRepository {
|
||||
|
@ -62,11 +67,11 @@ pub const fn test(fs: kxio::fs::FileSystem) -> TestRepository {
|
|||
#[tracing::instrument(skip_all)]
|
||||
#[cfg(not(tarpaulin_include))] // requires network access to either clone new and/or fetch.
|
||||
pub fn open(
|
||||
repository: &Repository,
|
||||
repository: &dyn RepositoryFactory,
|
||||
repo_details: &RepoDetails,
|
||||
gitdir: config::GitDir,
|
||||
) -> Result<OpenRepository> {
|
||||
let repository = if !gitdir.exists() {
|
||||
) -> Result<Box<dyn OpenRepositoryLike>> {
|
||||
let open_repository = if !gitdir.exists() {
|
||||
info!("Local copy not found - cloning...");
|
||||
repository.git_clone(repo_details)?
|
||||
} else {
|
||||
|
@ -74,8 +79,50 @@ pub fn open(
|
|||
repository.open(&gitdir)?
|
||||
};
|
||||
info!("Validating...");
|
||||
validate_repo(&repository, repo_details).map_err(|e| Error::Validation(e.to_string()))?;
|
||||
Ok(repository)
|
||||
validate_repo(&*open_repository, repo_details).map_err(|e| Error::Validation(e.to_string()))?;
|
||||
Ok(open_repository)
|
||||
}
|
||||
|
||||
#[mockall::automock]
|
||||
pub trait RepositoryFactory: std::fmt::Debug + Sync + Send {
|
||||
fn duplicate(&self) -> Box<dyn RepositoryFactory>;
|
||||
fn open(&self, gitdir: &GitDir) -> Result<Box<dyn OpenRepositoryLike>>;
|
||||
fn git_clone(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>>;
|
||||
}
|
||||
|
||||
pub fn real() -> Box<dyn RepositoryFactory> {
|
||||
Box::new(RealRepositoryFactory)
|
||||
}
|
||||
|
||||
pub fn mock() -> Box<MockRepositoryFactory> {
|
||||
Box::new(MockRepositoryFactory::new())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RealRepositoryFactory;
|
||||
impl RepositoryFactory for RealRepositoryFactory {
|
||||
fn open(&self, gitdir: &GitDir) -> Result<Box<dyn OpenRepositoryLike>> {
|
||||
let gix_repo = gix::ThreadSafeRepository::open(gitdir.to_path_buf())?.to_thread_local();
|
||||
let repo = RealOpenRepository::new(Arc::new(Mutex::new(gix_repo)));
|
||||
Ok(Box::new(repo))
|
||||
}
|
||||
|
||||
fn git_clone(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>> {
|
||||
tracing::info!("creating");
|
||||
use secrecy::ExposeSecret;
|
||||
let (gix_repo, _outcome) = gix::prepare_clone_bare(
|
||||
repo_details.origin().expose_secret().as_str(),
|
||||
repo_details.gitdir.deref(),
|
||||
)?
|
||||
.fetch_only(gix::progress::Discard, &AtomicBool::new(false))?;
|
||||
tracing::info!("created");
|
||||
let repo = RealOpenRepository::new(Arc::new(Mutex::new(gix_repo)));
|
||||
Ok(Box::new(repo))
|
||||
}
|
||||
|
||||
fn duplicate(&self) -> Box<dyn RepositoryFactory> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RepositoryLike {
|
||||
|
@ -91,7 +138,7 @@ impl std::ops::Deref for Repository {
|
|||
Self::Test(test_repository) => test_repository,
|
||||
|
||||
#[cfg(test)]
|
||||
Self::Mock(mock_repository) => mock_repository,
|
||||
Self::Fake(mock_repository) => mock_repository,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +187,8 @@ pub enum Error {
|
|||
#[error("git fetch: {0}")]
|
||||
Fetch(String),
|
||||
|
||||
#[error("mock lock")]
|
||||
MockLock,
|
||||
#[error("fake repository lock")]
|
||||
FakeLock,
|
||||
}
|
||||
|
||||
mod gix_errors {
|
||||
|
|
|
@ -8,7 +8,7 @@ pub mod oreal;
|
|||
pub mod otest;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod omock;
|
||||
pub mod ofake;
|
||||
|
||||
use std::{
|
||||
path::Path,
|
||||
|
@ -19,10 +19,11 @@ use crate as git;
|
|||
use git::repository::Direction;
|
||||
use git_next_config as config;
|
||||
#[cfg(test)]
|
||||
pub use omock::MockOpenRepository;
|
||||
pub use ofake::FakeOpenRepository;
|
||||
pub use oreal::RealOpenRepository;
|
||||
pub use otest::TestOpenRepository;
|
||||
|
||||
// TODO: #[deprecated]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum OpenRepository {
|
||||
/// A real git repository.
|
||||
|
@ -45,7 +46,7 @@ pub enum OpenRepository {
|
|||
/// variant is ready for use, tests should be converted to using
|
||||
/// that instead.
|
||||
#[cfg(test)]
|
||||
Mock(git::repository::MockOpenRepository), // TODO: (#38) contain a mock model of a repo
|
||||
Mock(git::repository::FakeOpenRepository), // TODO: (#38) contain a mock model of a repo
|
||||
}
|
||||
|
||||
pub fn real(gix_repo: gix::Repository) -> OpenRepository {
|
||||
|
@ -74,7 +75,9 @@ pub fn test_bare(
|
|||
OpenRepository::Test(TestOpenRepository::new_bare(gitdir, fs, on_fetch, on_push))
|
||||
}
|
||||
|
||||
pub trait OpenRepositoryLike {
|
||||
#[mockall::automock]
|
||||
pub trait OpenRepositoryLike: std::fmt::Debug + Sync {
|
||||
fn duplicate(&self) -> Box<dyn OpenRepositoryLike>;
|
||||
fn remote_branches(&self) -> git::push::Result<Vec<config::BranchName>>;
|
||||
fn find_default_remote(&self, direction: Direction) -> Option<git::GitRemote>;
|
||||
fn fetch(&self) -> Result<(), git::fetch::Error>;
|
||||
|
@ -102,6 +105,11 @@ pub trait OpenRepositoryLike {
|
|||
file_name: &Path,
|
||||
) -> git::file::Result<String>;
|
||||
}
|
||||
|
||||
pub fn mock() -> Box<MockOpenRepositoryLike> {
|
||||
Box::new(MockOpenRepositoryLike::new())
|
||||
}
|
||||
|
||||
impl std::ops::Deref for OpenRepository {
|
||||
type Target = dyn OpenRepositoryLike;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
use crate as git;
|
||||
use crate::{self as git, repository::OpenRepositoryLike};
|
||||
use git_next_config as config;
|
||||
|
||||
use std::{
|
||||
|
@ -8,12 +8,12 @@ use std::{
|
|||
};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MockOpenRepository {
|
||||
pub struct FakeOpenRepository {
|
||||
default_push_remote: Arc<Mutex<Option<git::GitRemote>>>,
|
||||
default_fetch_remote: Arc<Mutex<Option<git::GitRemote>>>,
|
||||
operations: Arc<Mutex<Vec<String>>>,
|
||||
}
|
||||
impl MockOpenRepository {
|
||||
impl FakeOpenRepository {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
@ -50,13 +50,13 @@ impl MockOpenRepository {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
impl From<MockOpenRepository> for git::OpenRepository {
|
||||
fn from(value: MockOpenRepository) -> Self {
|
||||
impl From<FakeOpenRepository> for git::OpenRepository {
|
||||
fn from(value: FakeOpenRepository) -> Self {
|
||||
Self::Mock(value)
|
||||
}
|
||||
}
|
||||
#[allow(clippy::unwrap_used)]
|
||||
impl git::repository::OpenRepositoryLike for MockOpenRepository {
|
||||
impl git::repository::OpenRepositoryLike for FakeOpenRepository {
|
||||
fn remote_branches(&self) -> git::push::Result<Vec<config::BranchName>> {
|
||||
todo!("MockOpenRepository::remote_branched")
|
||||
}
|
||||
|
@ -118,4 +118,8 @@ impl git::repository::OpenRepositoryLike for MockOpenRepository {
|
|||
) -> git::file::Result<String> {
|
||||
todo!("MockOpenRepository::read_file")
|
||||
}
|
||||
|
||||
fn duplicate(&self) -> Box<dyn OpenRepositoryLike> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
use crate as git;
|
||||
use crate::{self as git, repository::OpenRepositoryLike};
|
||||
use config::BranchName;
|
||||
use derive_more::Constructor;
|
||||
use git_next_config as config;
|
||||
|
@ -201,6 +201,10 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
|||
Ok(content)
|
||||
})
|
||||
}
|
||||
|
||||
fn duplicate(&self) -> Box<dyn OpenRepositoryLike> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn as_gix_error(branch: BranchName) -> impl FnOnce(String) -> git::commit::log::Error {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
use crate as git;
|
||||
use crate::{self as git, repository::OpenRepositoryLike};
|
||||
use derive_more::{Constructor, Deref};
|
||||
use git_next_config as config;
|
||||
|
||||
|
@ -132,6 +132,10 @@ impl git::repository::OpenRepositoryLike for TestOpenRepository {
|
|||
) -> git::file::Result<String> {
|
||||
self.real.read_file(branch_name, file_name)
|
||||
}
|
||||
|
||||
fn duplicate(&self) -> Box<dyn OpenRepositoryLike> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
impl TestOpenRepository {
|
||||
pub fn new(
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
use crate as git;
|
||||
use crate::repository::RepositoryLike as _;
|
||||
use git::tests::given;
|
||||
use git::tests::then;
|
||||
use git_next_config as config;
|
||||
|
||||
use assert2::let_assert;
|
||||
|
@ -50,6 +49,7 @@ mod server_repo_config {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_repo() {
|
||||
let repo_path = given::a_name();
|
||||
|
@ -64,6 +64,7 @@ mod server_repo_config {
|
|||
|
||||
assert_eq!(src.repo(), config::RepoPath::new(repo_path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_branch() {
|
||||
let branch = given::a_name();
|
||||
|
@ -78,6 +79,7 @@ mod server_repo_config {
|
|||
|
||||
assert_eq!(src.branch(), config::BranchName::new(branch));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_gitdir() {
|
||||
let gitdir = given::a_name();
|
||||
|
@ -96,6 +98,7 @@ mod server_repo_config {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod repo_config {
|
||||
|
||||
use super::*;
|
||||
|
@ -149,6 +152,7 @@ mod repo_config {
|
|||
assert_eq!(repo_config.source(), config::RepoConfigSource::Repo);
|
||||
}
|
||||
}
|
||||
|
||||
mod forge_config {
|
||||
use super::*;
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -198,6 +202,7 @@ mod forge_config {
|
|||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_forge_type() {
|
||||
let forge_type = config::ForgeType::MockForge;
|
||||
|
@ -209,6 +214,7 @@ mod forge_config {
|
|||
|
||||
assert_eq!(fc.forge_type(), config::ForgeType::MockForge);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_hostname() {
|
||||
let forge_type = config::ForgeType::MockForge;
|
||||
|
@ -220,6 +226,7 @@ mod forge_config {
|
|||
|
||||
assert_eq!(fc.hostname(), config::Hostname::new(hostname));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_user() {
|
||||
let forge_type = config::ForgeType::MockForge;
|
||||
|
@ -231,6 +238,7 @@ mod forge_config {
|
|||
|
||||
assert_eq!(fc.user(), config::User::new(user));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_token() {
|
||||
let forge_type = config::ForgeType::MockForge;
|
||||
|
@ -242,6 +250,7 @@ mod forge_config {
|
|||
|
||||
assert_eq!(fc.token().expose_secret(), token.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_repo() {
|
||||
let forge_type = config::ForgeType::MockForge;
|
||||
|
@ -266,6 +275,7 @@ mod forge_config {
|
|||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let mut repos = BTreeMap::new();
|
||||
repos.insert(red_name.clone(), red.clone());
|
||||
repos.insert(blue_name, blue);
|
||||
|
@ -277,6 +287,27 @@ mod forge_config {
|
|||
}
|
||||
}
|
||||
|
||||
// mod remote_branches {
|
||||
// use super::*;
|
||||
// #[test]
|
||||
// // assumes running in the git-next repo which should have main, next and dev as remote branches
|
||||
// fn should_return_remote_branches() -> TestResult {
|
||||
// let_assert!(Ok(fs) = kxio::fs::temp());
|
||||
// let gitdir: config::GitDir = fs.base().to_path_buf().into();
|
||||
// let test_repository = git::repository::test(fs.clone());
|
||||
// let_assert!(Ok(open_repository) = test_repository.open(&gitdir));
|
||||
// let repo_config = &given::a_repo_config();
|
||||
// let branches = repo_config.branches();
|
||||
// then::create_a_commit_on_branch(&fs, &gitdir, &branches.main())?;
|
||||
// then::create_a_commit_on_branch(&fs, &gitdir, &branches.next())?;
|
||||
// then::create_a_commit_on_branch(&fs, &gitdir, &branches.dev())?;
|
||||
// let_assert!(Ok(remote_branches) = open_repository.remote_branches());
|
||||
// assert!(remote_branches.contains(&branches.main()));
|
||||
// assert!(remote_branches.contains(&branches.next()));
|
||||
// assert!(remote_branches.contains(&branches.dev()));
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
mod find_default_remote {
|
||||
use super::*;
|
||||
|
||||
|
@ -287,7 +318,7 @@ mod find_default_remote {
|
|||
// uses the current repo
|
||||
let_assert!(Ok(cwd) = std::env::current_dir());
|
||||
let gitdir = config::GitDir::from(cwd.join("../..")); // from ./crate/git directory to the project rook
|
||||
let_assert!(Ok(repo) = crate::repository::new().open(&gitdir));
|
||||
let_assert!(Ok(repo) = crate::repository::real().open(&gitdir));
|
||||
let_assert!(Some(remote) = repo.find_default_remote(crate::repository::Direction::Push));
|
||||
assert_eq!(
|
||||
remote,
|
||||
|
@ -304,37 +335,16 @@ mod fetch {
|
|||
use git_next_config::GitDir;
|
||||
|
||||
#[test]
|
||||
#[ignore] // requires authentication to the server
|
||||
#[ignore] // requires authentication to the server - which the CI doesn't have
|
||||
fn should_fetch_from_repo() {
|
||||
// uses the current repo and fetches from the remote server
|
||||
let_assert!(Ok(cwd) = std::env::current_dir());
|
||||
let gitdir = GitDir::from(cwd.join("../.."));
|
||||
let_assert!(Ok(repo) = crate::repository::new().open(&gitdir));
|
||||
let_assert!(Ok(repo) = crate::repository::real().open(&gitdir));
|
||||
let_assert!(Ok(_) = repo.fetch());
|
||||
}
|
||||
}
|
||||
|
||||
mod remote_branches {
|
||||
use super::*;
|
||||
#[test]
|
||||
// assumes running in the git-next repo which should have main, next and dev as remote branches
|
||||
fn should_return_remote_branches() -> TestResult {
|
||||
let_assert!(Ok(fs) = kxio::fs::temp());
|
||||
let gitdir: config::GitDir = fs.base().to_path_buf().into();
|
||||
let test_repository = git::repository::test(fs.clone());
|
||||
let_assert!(Ok(open_repository) = test_repository.open(&gitdir));
|
||||
let repo_config = &given::a_repo_config();
|
||||
let branches = repo_config.branches();
|
||||
then::create_a_commit_on_branch(&fs, &gitdir, &branches.main())?;
|
||||
then::create_a_commit_on_branch(&fs, &gitdir, &branches.next())?;
|
||||
then::create_a_commit_on_branch(&fs, &gitdir, &branches.dev())?;
|
||||
let_assert!(Ok(remote_branches) = open_repository.remote_branches());
|
||||
assert!(remote_branches.contains(&branches.main()));
|
||||
assert!(remote_branches.contains(&branches.next()));
|
||||
assert!(remote_branches.contains(&branches.dev()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
mod commit_log {
|
||||
use git::tests::given;
|
||||
|
||||
|
@ -407,6 +417,7 @@ mod commit_log {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
mod read_file {
|
||||
|
||||
use git::tests::given;
|
||||
|
|
|
@ -1,173 +1,100 @@
|
|||
use crate as git;
|
||||
|
||||
mod validate {
|
||||
use crate::{validation::repo::validate_repo, GitRemote, RepoDetails};
|
||||
use crate::{tests::given, validation::repo::validate_repo};
|
||||
|
||||
use super::*;
|
||||
use assert2::let_assert;
|
||||
use git_next_config::{ForgeDetails, GitDir, Hostname, RepoPath};
|
||||
use git::repository::Direction;
|
||||
|
||||
#[test]
|
||||
fn should_ok_a_valid_repo() {
|
||||
let repo_details = RepoDetails::default()
|
||||
.with_forge(
|
||||
ForgeDetails::default().with_hostname(Hostname::new("localhost".to_string())),
|
||||
)
|
||||
.with_repo_path(RepoPath::new("kemitix/test".to_string()));
|
||||
let gitdir = GitDir::from("foo");
|
||||
let remote = GitRemote::new(
|
||||
Hostname::new("localhost"),
|
||||
RepoPath::new("kemitix/test".to_string()),
|
||||
);
|
||||
let fs = given::a_filesystem();
|
||||
let repo_details = given::repo_details(&fs);
|
||||
let repo_details_mock = repo_details.clone();
|
||||
|
||||
let mut mock_repository = git::repository::mock();
|
||||
{
|
||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
||||
mock_open_repo
|
||||
.given_has_default_remote(git::repository::Direction::Push, Some(remote.clone()));
|
||||
mock_open_repo
|
||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
||||
}
|
||||
let (repository, _mock_repository) = mock_repository.seal();
|
||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||
let_assert!(Ok(_) = validate_repo(&open_repository, &repo_details));
|
||||
let mut open_repository = git::repository::open::mock();
|
||||
open_repository
|
||||
.expect_find_default_remote()
|
||||
.returning(move |_direction| Some(repo_details_mock.git_remote()));
|
||||
|
||||
let result = validate_repo(&*open_repository, &repo_details);
|
||||
println!("{result:?}");
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_fail_where_no_default_push_remote() {
|
||||
let repo_details = RepoDetails::default()
|
||||
.with_forge(
|
||||
ForgeDetails::default().with_hostname(Hostname::new("localhost".to_string())),
|
||||
)
|
||||
.with_repo_path(RepoPath::new("kemitix/test".to_string()));
|
||||
let gitdir = GitDir::from("foo");
|
||||
let remote = GitRemote::new(
|
||||
Hostname::new("localhost"),
|
||||
RepoPath::new("kemitix/test".to_string()),
|
||||
);
|
||||
let fs = given::a_filesystem();
|
||||
let repo_details = given::repo_details(&fs);
|
||||
let repo_details_mock = repo_details.clone();
|
||||
|
||||
let mut mock_repository = git::repository::mock();
|
||||
{
|
||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
||||
mock_open_repo.given_has_default_remote(git::repository::Direction::Push, None);
|
||||
mock_open_repo
|
||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
||||
}
|
||||
let (repository, _mock_repository) = mock_repository.seal();
|
||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||
let mut open_repository = git::repository::open::mock();
|
||||
open_repository
|
||||
.expect_find_default_remote()
|
||||
.returning(move |direction| match direction {
|
||||
Direction::Push => None,
|
||||
Direction::Fetch => Some(repo_details_mock.git_remote()),
|
||||
});
|
||||
|
||||
let result = validate_repo(&*open_repository, &repo_details);
|
||||
println!("{result:?}");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_fail_where_no_default_fetch_remote() {
|
||||
let repo_details = RepoDetails::default()
|
||||
.with_forge(
|
||||
ForgeDetails::default().with_hostname(Hostname::new("localhost".to_string())),
|
||||
)
|
||||
.with_repo_path(RepoPath::new("kemitix/test".to_string()));
|
||||
let gitdir = GitDir::from("foo");
|
||||
let remote = GitRemote::new(
|
||||
Hostname::new("localhost"),
|
||||
RepoPath::new("kemitix/test".to_string()),
|
||||
);
|
||||
let fs = given::a_filesystem();
|
||||
let repo_details = given::repo_details(&fs);
|
||||
let repo_details_mock = repo_details.clone();
|
||||
|
||||
let mut mock_repository = git::repository::mock();
|
||||
{
|
||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
||||
mock_open_repo.given_has_default_remote(git::repository::Direction::Push, None);
|
||||
mock_open_repo
|
||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
||||
}
|
||||
let (repository, _mock_repository) = mock_repository.seal();
|
||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||
let mut open_repository = git::repository::open::mock();
|
||||
open_repository
|
||||
.expect_find_default_remote()
|
||||
.returning(move |direction| match direction {
|
||||
Direction::Push => Some(repo_details_mock.git_remote()),
|
||||
Direction::Fetch => None,
|
||||
});
|
||||
|
||||
let result = validate_repo(&*open_repository, &repo_details);
|
||||
println!("{result:?}");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_fail_where_invalid_default_push_remote() {
|
||||
let repo_details = RepoDetails::default()
|
||||
.with_forge(
|
||||
ForgeDetails::default().with_hostname(Hostname::new("localhost".to_string())),
|
||||
)
|
||||
.with_repo_path(RepoPath::new("kemitix/test".to_string()));
|
||||
let gitdir = GitDir::from("foo");
|
||||
let remote = GitRemote::new(
|
||||
Hostname::new("localhost"),
|
||||
RepoPath::new("kemitix/test".to_string()),
|
||||
);
|
||||
let other_remote = GitRemote::new(
|
||||
Hostname::new("localhost"),
|
||||
RepoPath::new("kemitix/other".to_string()),
|
||||
);
|
||||
let fs = given::a_filesystem();
|
||||
let repo_details = given::repo_details(&fs);
|
||||
let repo_details_mock = repo_details.clone();
|
||||
|
||||
let mut mock_repository = git::repository::mock();
|
||||
{
|
||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
||||
mock_open_repo
|
||||
.given_has_default_remote(git::repository::Direction::Push, Some(other_remote));
|
||||
mock_open_repo
|
||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(remote));
|
||||
}
|
||||
let (repository, _mock_repository) = mock_repository.seal();
|
||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||
let mut open_repository = git::repository::open::mock();
|
||||
open_repository
|
||||
.expect_find_default_remote()
|
||||
.returning(move |direction| match direction {
|
||||
Direction::Push => Some(given::a_git_remote()),
|
||||
Direction::Fetch => Some(repo_details_mock.git_remote()),
|
||||
});
|
||||
|
||||
let result = validate_repo(&*open_repository, &repo_details);
|
||||
println!("{result:?}");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_fail_where_invalid_default_fetch_remote() {
|
||||
let repo_details = RepoDetails::default()
|
||||
.with_forge(
|
||||
ForgeDetails::default().with_hostname(Hostname::new("localhost".to_string())),
|
||||
)
|
||||
.with_repo_path(RepoPath::new("kemitix/test".to_string()));
|
||||
let gitdir = GitDir::from("foo");
|
||||
let remote = GitRemote::new(
|
||||
Hostname::new("localhost"),
|
||||
RepoPath::new("kemitix/test".to_string()),
|
||||
);
|
||||
let other_remote = GitRemote::new(
|
||||
Hostname::new("localhost"),
|
||||
RepoPath::new("kemitix/other".to_string()),
|
||||
);
|
||||
let fs = given::a_filesystem();
|
||||
let repo_details = given::repo_details(&fs);
|
||||
let repo_details_mock = repo_details.clone();
|
||||
|
||||
let mut mock_repository = git::repository::mock();
|
||||
{
|
||||
let mut mock_open_repo = mock_repository.given_can_be_opened(&gitdir);
|
||||
mock_open_repo.given_has_default_remote(git::repository::Direction::Push, Some(remote));
|
||||
mock_open_repo
|
||||
.given_has_default_remote(git::repository::Direction::Fetch, Some(other_remote));
|
||||
}
|
||||
let (repository, _mock_repository) = mock_repository.seal();
|
||||
let_assert!(Ok(open_repository) = repository.open(&gitdir));
|
||||
let_assert!(Err(_) = validate_repo(&open_repository, &repo_details));
|
||||
}
|
||||
}
|
||||
|
||||
mod git_clone {
|
||||
use super::*;
|
||||
use assert2::let_assert;
|
||||
use git_next_config::{ForgeDetails, GitDir, Hostname, RepoPath};
|
||||
|
||||
use crate::{GitRemote, RepoDetails};
|
||||
|
||||
#[test]
|
||||
#[ignore] // slow test ~1.5 seconds
|
||||
fn should_clone_repo() {
|
||||
let_assert!(Ok(fs) = kxio::fs::temp());
|
||||
let r = crate::repository::new();
|
||||
let repo_details = RepoDetails::default()
|
||||
.with_forge(
|
||||
ForgeDetails::default().with_hostname(Hostname::new("git.kemitix.net".to_string())),
|
||||
)
|
||||
.with_gitdir(GitDir::new(fs.base()))
|
||||
.with_repo_path(RepoPath::new("kemitix/git-next".to_string()));
|
||||
let_assert!(Ok(open_repo) = r.git_clone(&repo_details));
|
||||
let_assert!(
|
||||
Some(remote) = open_repo.find_default_remote(git::repository::Direction::Fetch)
|
||||
);
|
||||
assert_eq!(
|
||||
remote,
|
||||
GitRemote::new(
|
||||
Hostname::new("git.kemitix.net"),
|
||||
RepoPath::new("kemitix/git-next".to_string())
|
||||
)
|
||||
);
|
||||
let mut open_repository = git::repository::open::mock();
|
||||
open_repository
|
||||
.expect_find_default_remote()
|
||||
.returning(move |direction| match direction {
|
||||
Direction::Push => Some(repo_details_mock.git_remote()),
|
||||
Direction::Fetch => Some(given::a_git_remote()),
|
||||
});
|
||||
|
||||
let result = validate_repo(&*open_repository, &repo_details);
|
||||
println!("{result:?}");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use crate as git;
|
||||
use git_next_config as config;
|
||||
|
||||
|
@ -102,37 +104,38 @@ mod push {
|
|||
|
||||
mod reset {
|
||||
use super::*;
|
||||
use crate::{tests::given, OpenRepository};
|
||||
use crate::tests::given;
|
||||
use assert2::let_assert;
|
||||
|
||||
#[test]
|
||||
fn should_perform_a_fetch_then_push() {
|
||||
let mut open_repository = git::repository::open::mock();
|
||||
let mut seq = mockall::Sequence::new();
|
||||
open_repository
|
||||
.expect_fetch()
|
||||
.times(1)
|
||||
.in_sequence(&mut seq)
|
||||
.returning(|| Ok(()));
|
||||
open_repository
|
||||
.expect_push()
|
||||
.times(1)
|
||||
.in_sequence(&mut seq)
|
||||
.returning(|_repo_details, _branch_name, _gitref, _force| Ok(()));
|
||||
|
||||
let fs = given::a_filesystem();
|
||||
let (mock_open_repository, gitdir, mock_repository) = given::an_open_repository(&fs);
|
||||
let open_repository: OpenRepository = mock_open_repository.into();
|
||||
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(
|
||||
&open_repository,
|
||||
&*open_repository,
|
||||
&repo_details,
|
||||
branch_name,
|
||||
&gitref,
|
||||
&git::push::Force::No
|
||||
)
|
||||
);
|
||||
let_assert!(Some(mock_open_repository) = mock_repository.get(&gitdir));
|
||||
let operations = mock_open_repository.operations();
|
||||
let forge_alias = repo_details.forge.forge_alias();
|
||||
let repo_alias = &repo_details.repo_alias;
|
||||
let to_commit = gitref;
|
||||
let force = "fast-forward";
|
||||
assert_eq!(
|
||||
operations,
|
||||
vec![format!("fetch"), format!("push fa:{forge_alias} ra:{repo_alias} bn:{branch_name} tc:{to_commit} f:{force}")]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +218,7 @@ pub mod given {
|
|||
//
|
||||
use crate::{
|
||||
self as git,
|
||||
repository::{MockOpenRepository, MockRepository},
|
||||
repository::{FakeOpenRepository, FakeRepository},
|
||||
tests::given,
|
||||
};
|
||||
use config::{
|
||||
|
@ -348,12 +351,19 @@ pub mod given {
|
|||
|
||||
pub fn an_open_repository(
|
||||
fs: &kxio::fs::FileSystem,
|
||||
) -> (MockOpenRepository, GitDir, MockRepository) {
|
||||
let mut mock = git::repository::mock();
|
||||
) -> (FakeOpenRepository, GitDir, FakeRepository) {
|
||||
let mut mock = git::repository::fake();
|
||||
let gitdir = a_git_dir(fs);
|
||||
let or = mock.given_can_be_opened(&gitdir);
|
||||
(or, gitdir, mock)
|
||||
}
|
||||
|
||||
pub fn a_git_remote() -> git::GitRemote {
|
||||
git::GitRemote::new(
|
||||
config::Hostname::new(given::a_name()),
|
||||
config::RepoPath::new(given::a_name()),
|
||||
)
|
||||
}
|
||||
}
|
||||
pub mod then {
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
|
@ -16,7 +16,7 @@ pub struct Positions {
|
|||
|
||||
#[allow(clippy::cognitive_complexity)] // TODO: (#83) reduce complexity
|
||||
pub fn validate_positions(
|
||||
repository: &git::OpenRepository,
|
||||
open_repository: &dyn git::repository::OpenRepositoryLike,
|
||||
repo_details: &git::RepoDetails,
|
||||
repo_config: config::RepoConfig,
|
||||
) -> Result<Positions> {
|
||||
|
@ -24,9 +24,9 @@ pub fn validate_positions(
|
|||
let next_branch = repo_config.branches().next();
|
||||
let dev_branch = repo_config.branches().dev();
|
||||
// Collect Commit Histories for `main`, `next` and `dev` branches
|
||||
repository.fetch()?;
|
||||
open_repository.fetch()?;
|
||||
let commit_histories =
|
||||
get_commit_histories(repository, &repo_config).map_err(Error::CommitLog)?;
|
||||
get_commit_histories(open_repository, &repo_config).map_err(Error::CommitLog)?;
|
||||
// branch tips
|
||||
let main = commit_histories
|
||||
.main
|
||||
|
@ -55,12 +55,12 @@ pub fn validate_positions(
|
|||
// verify that next is on main or at most one commit on top of main, else reset it back to main
|
||||
if is_not_based_on(&commit_histories.next[0..=1], &main) {
|
||||
info!("Main not on same commit as next, or it's parent - resetting next to main",);
|
||||
return reset_next_to_main(repository, repo_details, &main, &next, &next_branch);
|
||||
return reset_next_to_main(open_repository, repo_details, &main, &next, &next_branch);
|
||||
}
|
||||
// verify that next is an ancestor of dev, else reset it back to main
|
||||
if is_not_based_on(&commit_histories.dev, &next) {
|
||||
info!("Next is not an ancestor of dev - resetting next to main");
|
||||
return reset_next_to_main(repository, repo_details, &main, &next, &next_branch);
|
||||
return reset_next_to_main(open_repository, repo_details, &main, &next, &next_branch);
|
||||
}
|
||||
|
||||
Ok(git::validation::positions::Positions {
|
||||
|
@ -72,7 +72,7 @@ pub fn validate_positions(
|
|||
}
|
||||
|
||||
fn reset_next_to_main(
|
||||
repository: &crate::OpenRepository,
|
||||
repository: &dyn crate::repository::OpenRepositoryLike,
|
||||
repo_details: &crate::RepoDetails,
|
||||
main: &crate::Commit,
|
||||
next: &crate::Commit,
|
||||
|
@ -100,7 +100,7 @@ fn is_not_based_on(commits: &[crate::commit::Commit], needle: &crate::Commit) ->
|
|||
}
|
||||
|
||||
fn get_commit_histories(
|
||||
repository: &git::repository::OpenRepository,
|
||||
repository: &dyn git::repository::OpenRepositoryLike,
|
||||
repo_config: &config::RepoConfig,
|
||||
) -> git::commit::log::Result<git::commit::Histories> {
|
||||
let main = (repository.commit_log(&repo_config.branches().main(), &[]))?;
|
||||
|
|
|
@ -4,13 +4,13 @@ use crate as git;
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn validate_repo(
|
||||
repository: &git::OpenRepository,
|
||||
open_repository: &dyn git::repository::OpenRepositoryLike,
|
||||
repo_details: &git::RepoDetails,
|
||||
) -> Result<()> {
|
||||
let push_remote = repository
|
||||
let push_remote = open_repository
|
||||
.find_default_remote(git::repository::Direction::Push)
|
||||
.ok_or_else(|| Error::NoDefaultPushRemote)?;
|
||||
let fetch_remote = repository
|
||||
let fetch_remote = open_repository
|
||||
.find_default_remote(git::repository::Direction::Fetch)
|
||||
.ok_or_else(|| Error::NoDefaultFetchRemote)?;
|
||||
let git_remote = repo_details.git_remote();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,7 +16,7 @@ pub async fn advance_next(
|
|||
dev_commit_history: Vec<git::Commit>,
|
||||
repo_details: git::RepoDetails,
|
||||
repo_config: config::RepoConfig,
|
||||
repository: git::OpenRepository,
|
||||
open_repository: &dyn git::repository::OpenRepositoryLike,
|
||||
addr: Addr<super::RepoActor>,
|
||||
message_token: MessageToken,
|
||||
) {
|
||||
|
@ -31,7 +31,7 @@ pub async fn advance_next(
|
|||
}
|
||||
info!("Advancing next to commit '{}'", commit);
|
||||
if let Err(err) = git::push::reset(
|
||||
&repository,
|
||||
open_repository,
|
||||
&repo_details,
|
||||
&repo_config.branches().next(),
|
||||
&commit.into(),
|
||||
|
@ -81,11 +81,11 @@ pub async fn advance_main(
|
|||
next: git::Commit,
|
||||
repo_details: &git::RepoDetails,
|
||||
repo_config: &config::RepoConfig,
|
||||
repository: &git::OpenRepository,
|
||||
open_repository: &dyn git::repository::OpenRepositoryLike,
|
||||
) {
|
||||
info!("Advancing main to next");
|
||||
if let Err(err) = git::push::reset(
|
||||
repository,
|
||||
open_repository,
|
||||
repo_details,
|
||||
&repo_config.branches().main(),
|
||||
&next.into(),
|
||||
|
|
|
@ -32,8 +32,8 @@ pub struct RepoActor {
|
|||
last_main_commit: Option<git::Commit>,
|
||||
last_next_commit: Option<git::Commit>,
|
||||
last_dev_commit: Option<git::Commit>,
|
||||
repository: git::Repository,
|
||||
open_repository: Option<git::OpenRepository>,
|
||||
repository: Box<dyn git::repository::RepositoryFactory>,
|
||||
open_repository: Option<Box<dyn git::repository::OpenRepositoryLike>>,
|
||||
net: Network,
|
||||
forge: forge::Forge,
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ impl RepoActor {
|
|||
webhook: config::server::Webhook,
|
||||
generation: git::Generation,
|
||||
net: Network,
|
||||
repo: git::Repository,
|
||||
repository: Box<dyn git::repository::RepositoryFactory>,
|
||||
) -> Self {
|
||||
let forge = forge::Forge::new(details.clone(), net.clone());
|
||||
debug!(?forge, "new");
|
||||
|
@ -57,7 +57,7 @@ impl RepoActor {
|
|||
last_main_commit: None,
|
||||
last_next_commit: None,
|
||||
last_dev_commit: None,
|
||||
repository: repo,
|
||||
repository,
|
||||
open_repository: None,
|
||||
net,
|
||||
forge,
|
||||
|
@ -96,7 +96,7 @@ impl Handler<CloneRepo> for RepoActor {
|
|||
#[tracing::instrument(name = "RepoActor::CloneRepo", skip_all, fields(repo = %self.repo_details /*, gitdir = %self.repo_details.gitdir */))]
|
||||
fn handle(&mut self, _msg: CloneRepo, ctx: &mut Self::Context) -> Self::Result {
|
||||
let gitdir = self.repo_details.gitdir.clone();
|
||||
match git::repository::open(&self.repository, &self.repo_details, gitdir) {
|
||||
match git::repository::open(&*self.repository, &self.repo_details, gitdir) {
|
||||
Ok(repository) => {
|
||||
self.open_repository.replace(repository);
|
||||
if self.repo_details.repo_config.is_none() {
|
||||
|
@ -121,14 +121,15 @@ impl Handler<LoadConfigFromRepo> for RepoActor {
|
|||
fn handle(&mut self, _msg: LoadConfigFromRepo, ctx: &mut Self::Context) -> Self::Result {
|
||||
let details = self.repo_details.clone();
|
||||
let addr = ctx.address();
|
||||
let Some(open_repository) = self.open_repository.clone() else {
|
||||
let Some(open_repository) = &self.open_repository else {
|
||||
warn!("missing open repository - can't load configuration");
|
||||
return;
|
||||
};
|
||||
repo_actor::load::load_file(details, addr, open_repository)
|
||||
let open_repository = open_repository.duplicate();
|
||||
async move { repo_actor::load::load_file(details, addr, &*open_repository).await }
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
.wait(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,15 +196,15 @@ impl Handler<ValidateRepo> for RepoActor {
|
|||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
}
|
||||
if let (Some(repository), Some(repo_config)) = (
|
||||
self.open_repository.clone(),
|
||||
self.repo_details.repo_config.clone(),
|
||||
) {
|
||||
if let (Some(open_repository), Some(repo_config)) =
|
||||
(&self.open_repository, self.repo_details.repo_config.clone())
|
||||
{
|
||||
let repo_details = self.repo_details.clone();
|
||||
let addr = ctx.address();
|
||||
let message_token = self.message_token;
|
||||
let open_repository = open_repository.duplicate();
|
||||
async move {
|
||||
match validate_positions(&repository, &repo_details, repo_config) {
|
||||
match validate_positions(&*open_repository, &repo_details, repo_config) {
|
||||
Ok(Positions {
|
||||
main,
|
||||
next,
|
||||
|
@ -258,16 +259,22 @@ impl Handler<StartMonitoring> for RepoActor {
|
|||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
} else if dev_ahead_of_next {
|
||||
if let Some(repository) = self.open_repository.clone() {
|
||||
if let Some(open_repository) = &self.open_repository {
|
||||
let open_repository = open_repository.duplicate();
|
||||
let repo_details = self.repo_details.clone();
|
||||
let message_token = self.message_token;
|
||||
async move {
|
||||
branch::advance_next(
|
||||
msg.next,
|
||||
msg.dev_commit_history,
|
||||
self.repo_details.clone(),
|
||||
repo_details,
|
||||
repo_config,
|
||||
repository,
|
||||
&*open_repository,
|
||||
addr,
|
||||
self.message_token,
|
||||
message_token,
|
||||
)
|
||||
.await
|
||||
}
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
|
@ -304,15 +311,16 @@ impl Handler<AdvanceMainTo> for RepoActor {
|
|||
warn!("No config loaded");
|
||||
return;
|
||||
};
|
||||
let Some(repository) = self.open_repository.clone() else {
|
||||
let Some(open_repository) = &self.open_repository else {
|
||||
warn!("No repository opened");
|
||||
return;
|
||||
};
|
||||
let repo_details = self.repo_details.clone();
|
||||
let addr = ctx.address();
|
||||
let message_token = self.message_token;
|
||||
let open_repository = open_repository.duplicate();
|
||||
async move {
|
||||
branch::advance_main(msg.0, &repo_details, &repo_config, &repository).await;
|
||||
branch::advance_main(msg.0, &repo_details, &repo_config, &*open_repository).await;
|
||||
match repo_config.source() {
|
||||
git_next_config::RepoConfigSource::Repo => addr.do_send(LoadConfigFromRepo),
|
||||
git_next_config::RepoConfigSource::Server => {
|
||||
|
|
|
@ -15,10 +15,10 @@ use super::{LoadedConfig, RepoActor};
|
|||
pub async fn load_file(
|
||||
repo_details: git::RepoDetails,
|
||||
addr: Addr<RepoActor>,
|
||||
open_repository: git::OpenRepository,
|
||||
open_repository: &dyn git::repository::OpenRepositoryLike,
|
||||
) {
|
||||
info!("Loading .git-next.toml from repo");
|
||||
let repo_config = match load(&repo_details, &open_repository).await {
|
||||
let repo_config = match load(&repo_details, open_repository).await {
|
||||
Ok(repo_config) => repo_config,
|
||||
Err(err) => {
|
||||
error!(?err, "Failed to load config");
|
||||
|
@ -31,7 +31,7 @@ pub async fn load_file(
|
|||
|
||||
async fn load(
|
||||
details: &git::RepoDetails,
|
||||
open_repository: &git::OpenRepository,
|
||||
open_repository: &dyn git::repository::OpenRepositoryLike,
|
||||
) -> Result<config::RepoConfig, Error> {
|
||||
let contents = open_repository.read_file(&details.branch, &PathBuf::from(".git-next.toml"))?;
|
||||
let config = config::RepoConfig::parse(&contents)?;
|
||||
|
@ -50,7 +50,7 @@ pub enum Error {
|
|||
|
||||
pub async fn validate(
|
||||
config: config::RepoConfig,
|
||||
open_repository: &git::OpenRepository,
|
||||
open_repository: &dyn git::repository::OpenRepositoryLike,
|
||||
) -> Result<config::RepoConfig, Error> {
|
||||
let branches = open_repository.remote_branches()?;
|
||||
if !branches
|
||||
|
|
|
@ -7,7 +7,7 @@ use config::server::{ServerConfig, ServerStorage, Webhook};
|
|||
use git_next_config::{
|
||||
self as config, ForgeAlias, ForgeConfig, GitDir, RepoAlias, ServerRepoConfig,
|
||||
};
|
||||
use git_next_git::{Generation, RepoDetails, Repository};
|
||||
use git_next_git::{repository::RepositoryFactory, Generation, RepoDetails};
|
||||
use git_next_repo_actor::{CloneRepo, RepoActor};
|
||||
use kxio::{fs::FileSystem, network::Network};
|
||||
use tracing::{error, info, warn};
|
||||
|
@ -38,7 +38,7 @@ pub struct Server {
|
|||
webhook: Option<Addr<WebhookActor>>,
|
||||
fs: FileSystem,
|
||||
net: Network,
|
||||
repo: Repository,
|
||||
repository_factory: Box<dyn RepositoryFactory>,
|
||||
}
|
||||
impl Actor for Server {
|
||||
type Context = Context<Self>;
|
||||
|
@ -114,14 +114,14 @@ impl Handler<ServerConfig> for Server {
|
|||
}
|
||||
}
|
||||
impl Server {
|
||||
pub fn new(fs: FileSystem, net: Network, repo: Repository) -> Self {
|
||||
pub fn new(fs: FileSystem, net: Network, repo: Box<dyn RepositoryFactory>) -> Self {
|
||||
let generation = Generation::new();
|
||||
Self {
|
||||
generation,
|
||||
webhook: None,
|
||||
fs,
|
||||
net,
|
||||
repo,
|
||||
repository_factory: repo,
|
||||
}
|
||||
}
|
||||
fn create_forge_data_directories(
|
||||
|
@ -180,7 +180,7 @@ impl Server {
|
|||
let server_storage = server_storage.clone();
|
||||
let webhook = webhook.clone();
|
||||
let net = self.net.clone();
|
||||
let repo = self.repo.clone();
|
||||
let repository_factory = self.repository_factory.duplicate();
|
||||
let generation = self.generation;
|
||||
move |(repo_alias, server_repo_config)| {
|
||||
let span = tracing::info_span!("create_actor", alias = %repo_alias, config = %server_repo_config);
|
||||
|
@ -213,7 +213,7 @@ impl Server {
|
|||
webhook.clone(),
|
||||
generation,
|
||||
net.clone(),
|
||||
repo.clone(),
|
||||
repository_factory.duplicate(),
|
||||
);
|
||||
(forge_name.clone(), repo_alias, actor)
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ fn repo_details_find_default_push_remote_finds_correct_remote() -> Result<()> {
|
|||
.with_hostname(Hostname::new("git.kemitix.net"));
|
||||
repo_details.repo_path = RepoPath::new("kemitix/git-next".to_string());
|
||||
let gitdir = &repo_details.gitdir;
|
||||
let repository = git::repository::new().open(gitdir)?;
|
||||
let repository = git::repository::mock().open(gitdir)?;
|
||||
let_assert!(
|
||||
Some(found_git_remote) = repository.find_default_remote(Direction::Push),
|
||||
"Default Push Remote not found"
|
||||
|
@ -91,8 +91,8 @@ fn gitdir_validate_should_pass_a_valid_git_repo() -> Result<()> {
|
|||
.with_hostname(Hostname::new("git.kemitix.net"));
|
||||
repo_details.repo_path = RepoPath::new("kemitix/git-next".to_string());
|
||||
let gitdir = &repo_details.gitdir;
|
||||
let repository = git::repository::new().open(gitdir)?;
|
||||
validate_repo(&repository, &repo_details)?;
|
||||
let repository = git::repository::mock().open(gitdir)?;
|
||||
validate_repo(&*repository, &repo_details)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -112,8 +112,8 @@ fn gitdir_validate_should_fail_a_git_repo_with_wrong_remote() -> Result<()> {
|
|||
);
|
||||
repo_details.repo_path = RepoPath::new("hello/world".to_string());
|
||||
let gitdir = &repo_details.gitdir;
|
||||
let repository = git::repository::new().open(gitdir)?;
|
||||
let_assert!(Err(_) = validate_repo(&repository, &repo_details));
|
||||
let repository = git::repository::mock().open(gitdir)?;
|
||||
let_assert!(Err(_) = validate_repo(&*repository, &repo_details));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ mod config;
|
|||
//
|
||||
use actix::prelude::*;
|
||||
|
||||
use git_next_git::Repository;
|
||||
use git_next_git::repository::RepositoryFactory;
|
||||
use kxio::{fs::FileSystem, network::Network};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
@ -37,7 +37,7 @@ pub fn init(fs: FileSystem) {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn start(fs: FileSystem, net: Network, repo: Repository) {
|
||||
pub async fn start(fs: FileSystem, net: Network, repo: Box<dyn RepositoryFactory>) {
|
||||
init_logging();
|
||||
|
||||
info!("Starting Server...");
|
||||
|
|
Loading…
Reference in a new issue