Compare commits

..

No commits in common. "ac3e1be261e668762f879f9011de65a1d6e0cfa1" and "a4694d48f68c0caf4df8ff59912bec0d52b7fd25" have entirely different histories.

17 changed files with 66 additions and 269 deletions

View file

@ -1,28 +1,27 @@
use std::path::PathBuf;
use kxio::fs::FileSystem; use kxio::fs::FileSystem;
pub fn run(fs: FileSystem) { pub fn run(fs: FileSystem) {
let file_name = ".git-next.toml"; let file_name = ".git-next.toml";
let pathbuf = fs.base().join(file_name); let pathbuf = PathBuf::from(file_name);
match fs.path_exists(&pathbuf) { let Ok(exists) = fs.path_exists(&pathbuf) else {
Ok(exists) => { eprintln!("Could not check if file exist: {}", file_name);
if exists { return;
eprintln!( };
"The configuration file already exists at {} - not overwritting it.", if exists {
file_name eprintln!(
); "The configuration file already exists at {} - not overwritting it.",
} else { file_name
match fs.file_write(&pathbuf, include_str!("../../../default.toml")) { );
Ok(_) => { } else {
println!("Created a default configuration file at {}", file_name); match fs.file_write(&pathbuf, include_str!("../../../default.toml")) {
} Ok(_) => {
Err(e) => { println!("Created a default configuration file at {}", file_name);
eprintln!("Failed to write to the configuration file: {}", e) }
} Err(e) => {
} eprintln!("Failed to write to the configuration file: {}", e)
} }
}
Err(err) => {
eprintln!("Could not check if file exist: {} - {err:?}", file_name);
} }
} }
} }

View file

@ -1,8 +1,5 @@
mod init; mod init;
#[cfg(test)]
mod tests;
use std::path::PathBuf; use std::path::PathBuf;
use clap::Parser; use clap::Parser;

View file

@ -1,40 +0,0 @@
type TestResult = Result<(), Box<dyn std::error::Error>>;
mod init {
use super::*;
#[test]
fn should_not_update_file_if_it_exists() -> TestResult {
let fs = kxio::fs::temp()?;
let file = fs.base().join(".git-next.toml");
fs.file_write(&file, "contents")?;
crate::init::run(fs.clone());
assert_eq!(
fs.file_read_to_string(&file)?,
"contents",
"The file has been changed"
);
Ok(())
}
#[test]
fn should_create_default_file_if_not_exists() -> TestResult {
let fs = kxio::fs::temp()?;
crate::init::run(fs.clone());
let file = fs.base().join(".git-next.toml");
assert!(fs.path_exists(&file)?, "The file has not been created");
assert_eq!(
fs.file_read_to_string(&file)?,
include_str!("../../../default.toml"),
"The file does not match the default template"
);
Ok(())
}
}

View file

@ -56,10 +56,10 @@ derive_more = { workspace = true }
# actix-rt = { workspace = true } # actix-rt = { workspace = true }
# tokio = { workspace = true } # tokio = { workspace = true }
# #
[dev-dependencies] # [dev-dependencies]
# # Testing # # Testing
assert2 = { workspace = true } # assert2 = { workspace = true }
pretty_assertions = { workspace = true } # pretty_assertions = { workspace = true }
# test-log = { workspace = true } # test-log = { workspace = true }
# anyhow = { workspace = true } # anyhow = { workspace = true }

View file

@ -1,4 +1,4 @@
use std::collections::BTreeMap; use std::collections::HashMap;
use crate::{ApiToken, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User}; use crate::{ApiToken, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User};
@ -11,7 +11,7 @@ pub struct ForgeConfig {
pub hostname: String, pub hostname: String,
pub user: String, pub user: String,
pub token: String, pub token: String,
pub repos: BTreeMap<String, ServerRepoConfig>, pub repos: HashMap<String, ServerRepoConfig>,
} }
impl ForgeConfig { impl ForgeConfig {
pub const fn forge_type(&self) -> ForgeType { pub const fn forge_type(&self) -> ForgeType {
@ -19,7 +19,7 @@ impl ForgeConfig {
} }
pub fn hostname(&self) -> Hostname { pub fn hostname(&self) -> Hostname {
Hostname::new(&self.hostname) Hostname(self.hostname.clone())
} }
pub fn user(&self) -> User { pub fn user(&self) -> User {
@ -33,6 +33,6 @@ impl ForgeConfig {
pub fn repos(&self) -> impl Iterator<Item = (RepoAlias, &ServerRepoConfig)> { pub fn repos(&self) -> impl Iterator<Item = (RepoAlias, &ServerRepoConfig)> {
self.repos self.repos
.iter() .iter()
.map(|(name, repo)| (RepoAlias::new(name), repo)) .map(|(name, repo)| (RepoAlias(name.clone()), repo))
} }
} }

View file

@ -1,8 +1,3 @@
/// The hostname of a forge /// The hostname of a forge
#[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)] #[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)]
pub struct Hostname(String); pub struct Hostname(pub String);
impl Hostname {
pub fn new(str: impl Into<String>) -> Self {
Self(str.into())
}
}

View file

@ -15,9 +15,6 @@ mod repo_path;
mod server_repo_config; mod server_repo_config;
mod user; mod user;
#[cfg(test)]
mod tests;
pub use api_token::ApiToken; pub use api_token::ApiToken;
pub use branch_name::BranchName; pub use branch_name::BranchName;
pub use forge_config::ForgeConfig; pub use forge_config::ForgeConfig;

View file

@ -1,9 +1,4 @@
/// The alias of a repo /// The alias of a repo
/// This is the alias for the repo within `git-next-server.toml` /// This is the alias for the repo within `git-next-server.toml`
#[derive(Clone, Debug, PartialEq, Eq, Hash, derive_more::Display)] #[derive(Clone, Debug, PartialEq, Eq, Hash, derive_more::Display)]
pub struct RepoAlias(String); pub struct RepoAlias(pub String);
impl RepoAlias {
pub fn new(str: impl Into<String>) -> Self {
Self(str.into())
}
}

View file

@ -1,132 +0,0 @@
type TestResult = Result<(), Box<dyn std::error::Error>>;
mod server_repo_config {
use assert2::let_assert;
use crate::{RepoBranches, RepoConfig, RepoConfigSource};
use super::super::server_repo_config::*;
#[test]
fn should_not_return_repo_config_when_no_branches() {
let src = ServerRepoConfig {
repo: "".to_string(),
branch: "".to_string(),
gitdir: None,
main: None,
next: None,
dev: None,
};
let_assert!(None = src.repo_config());
}
#[test]
fn should_return_repo_config_when_branches() {
let src = ServerRepoConfig {
repo: "".to_string(),
branch: "".to_string(),
gitdir: None,
main: Some("main".to_string()),
next: Some("next".to_string()),
dev: Some("dev".to_string()),
};
let_assert!(Some(rc) = src.repo_config());
assert_eq!(
rc,
RepoConfig {
branches: RepoBranches {
main: "main".to_string(),
next: "next".to_string(),
dev: "dev".to_string()
},
source: RepoConfigSource::Server
}
);
}
}
mod repo_config {
use crate::{RepoBranches, RepoConfigSource};
use super::super::repo_config::*;
use super::*;
#[test]
fn should_parse_toml() -> TestResult {
let toml = r#"
[branches]
main = "main"
next = "next"
dev = "dev"
"#;
let rc = RepoConfig::load(toml)?;
assert_eq!(
rc,
RepoConfig {
branches: RepoBranches {
main: "main".to_string(),
next: "next".to_string(),
dev: "dev".to_string(),
},
source: RepoConfigSource::Repo // reading from repo is the default
}
);
Ok(())
}
}
mod forge_config {
use std::collections::BTreeMap;
use crate::{ForgeConfig, ForgeType, RepoAlias, ServerRepoConfig};
use super::*;
#[test]
fn should_return_repos() -> TestResult {
let forge_type = ForgeType::MockForge;
let hostname = "localhost".to_string();
let user = "bob".to_string();
let token = "alpha".to_string();
let red = ServerRepoConfig {
repo: "red".to_string(),
branch: "main".to_string(),
main: None,
next: None,
dev: None,
gitdir: None,
};
let blue = ServerRepoConfig {
repo: "blue".to_string(),
branch: "main".to_string(),
main: None,
next: None,
dev: None,
gitdir: None,
};
let mut repos = BTreeMap::new();
repos.insert("red".to_string(), red.clone());
repos.insert("blue".to_string(), blue.clone());
let fc = ForgeConfig {
forge_type,
hostname,
user,
token,
repos,
};
let returned_repos = fc.repos().collect::<Vec<_>>();
assert_eq!(
returned_repos,
vec![
// alphabetical order by key
(RepoAlias::new("blue"), &blue),
(RepoAlias::new("red"), &red),
]
);
Ok(())
}
}

View file

@ -47,7 +47,7 @@ pub fn find_default_remote(
let path = path.strip_suffix(".git").map_or(path, |path| path); let path = path.strip_suffix(".git").map_or(path, |path| path);
info!(%host, %path, "found"); info!(%host, %path, "found");
Ok(GitRemote::new( Ok(GitRemote::new(
Hostname::new(host), Hostname(host.to_string()),
RepoPath(path.to_string()), RepoPath(path.to_string()),
)) ))
} }

View file

@ -62,7 +62,7 @@ fn validate_commit_message(message: &git::commit::Message) -> Option<String> {
} }
} }
pub fn find_next_commit_on_dev( fn find_next_commit_on_dev(
next: git::Commit, next: git::Commit,
dev_commit_history: Vec<git::Commit>, dev_commit_history: Vec<git::Commit>,
) -> Option<git::Commit> { ) -> Option<git::Commit> {
@ -100,3 +100,22 @@ pub async fn advance_main(
RepoConfigSource::Server => addr.do_send(ValidateRepo { message_token }), RepoConfigSource::Server => addr.do_send(ValidateRepo { message_token }),
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[actix_rt::test]
async fn test_find_next_commit_on_dev() {
let next = git::Commit::new("current-next", "foo");
let expected = git::Commit::new("dev-next", "next-should-go-here");
let dev_commit_history = vec![
git::Commit::new("dev", "future"),
expected.clone(),
next.clone(),
git::Commit::new("current-main", "history"),
];
let next_commit = find_next_commit_on_dev(next, dev_commit_history);
assert_eq!(next_commit, Some(expected));
}
}

View file

@ -3,9 +3,6 @@ mod config;
pub mod status; pub mod status;
pub mod webhook; pub mod webhook;
#[cfg(test)]
mod tests;
use actix::prelude::*; use actix::prelude::*;
use git_next_config::{ForgeType, RepoConfig}; use git_next_config::{ForgeType, RepoConfig};
use git_next_git::{self as git, Generation, RepoDetails}; use git_next_git::{self as git, Generation, RepoDetails};

View file

@ -1,31 +0,0 @@
//
use super::*;
mod branch {
use super::super::branch::*;
use super::*;
#[actix_rt::test]
async fn test_find_next_commit_on_dev() {
let next = git::Commit::new("current-next", "foo");
let expected = git::Commit::new("dev-next", "next-should-go-here");
let dev_commit_history = vec![
git::Commit::new("dev", "future"),
expected.clone(),
next.clone(),
git::Commit::new("current-main", "history"),
];
let next_commit = find_next_commit_on_dev(next, dev_commit_history);
assert_eq!(next_commit, Some(expected), "Found the wrong commit");
}
}
mod webhook {
use super::super::webhook::*;
#[test]
fn should_split_ref() {
assert_eq!(split_ref("refs/heads/next"), ("refs/heads/", "next"));
}
}

View file

@ -285,7 +285,7 @@ impl Push {
warn!(r#ref = self.reference, "Unexpected ref"); warn!(r#ref = self.reference, "Unexpected ref");
return None; return None;
} }
let (_, branch) = split_ref(&self.reference); let (_, branch) = self.reference.split_at(11);
let branch = BranchName::new(branch); let branch = BranchName::new(branch);
if branch == repo_branches.main() { if branch == repo_branches.main() {
return Some(Branch::Main); return Some(Branch::Main);
@ -299,16 +299,11 @@ impl Push {
warn!(%branch, "Unexpected branch"); warn!(%branch, "Unexpected branch");
None None
} }
pub fn commit(&self) -> git::Commit { pub fn commit(&self) -> git::Commit {
git::Commit::new(&self.after, &self.head_commit.message) git::Commit::new(&self.after, &self.head_commit.message)
} }
} }
pub fn split_ref(reference: &str) -> (&str, &str) {
reference.split_at(11)
}
#[derive(Debug)] #[derive(Debug)]
enum Branch { enum Branch {
Main, Main,
@ -320,3 +315,11 @@ enum Branch {
struct HeadCommit { struct HeadCommit {
message: String, message: String,
} }
#[cfg(test)]
mod tests {
#[test]
fn splt_ref() {
assert_eq!("refs/heads/next".split_at(11), ("refs/heads/", "next"));
}
}

View file

@ -28,7 +28,7 @@ impl Handler<WebhookMessage> for WebhookRouter {
fn handle(&mut self, msg: WebhookMessage, _ctx: &mut Self::Context) -> Self::Result { fn handle(&mut self, msg: WebhookMessage, _ctx: &mut Self::Context) -> Self::Result {
let _gaurd = self.span.enter(); let _gaurd = self.span.enter();
let repo_alias = RepoAlias::new(msg.path()); let repo_alias = RepoAlias(msg.path().clone());
debug!(repo = %repo_alias, "Router..."); debug!(repo = %repo_alias, "Router...");
if let Some(recipient) = self.repos.get(&repo_alias) { if let Some(recipient) = self.repos.get(&repo_alias) {
info!(repo = %repo_alias, "Sending to Recipient"); info!(repo = %repo_alias, "Sending to Recipient");

View file

@ -1,5 +1,3 @@
use std::collections::BTreeMap;
use assert2::let_assert; use assert2::let_assert;
use git_next_config::{ use git_next_config::{
ForgeType, GitDir, Hostname, RepoBranches, RepoConfig, RepoConfigSource, RepoPath, ForgeType, GitDir, Hostname, RepoBranches, RepoConfig, RepoConfigSource, RepoPath,
@ -70,7 +68,7 @@ fn load_should_parse_server_config() -> Result<()> {
hostname: "git.example.net".to_string(), hostname: "git.example.net".to_string(),
user: "Bob".to_string(), user: "Bob".to_string(),
token: "API-Token".to_string(), token: "API-Token".to_string(),
repos: BTreeMap::from([ repos: HashMap::from([
( (
"hello".to_string(), "hello".to_string(),
ServerRepoConfig { ServerRepoConfig {
@ -178,7 +176,7 @@ fn repo_details_find_default_push_remote_finds_correct_remote() -> Result<()> {
None, None,
GitDir::new(root), // Server GitDir - should be ignored GitDir::new(root), // Server GitDir - should be ignored
); );
repo_details.forge.hostname = Hostname::new("git.kemitix.net"); repo_details.forge.hostname = Hostname("git.kemitix.net".to_string());
repo_details.repo_path = RepoPath("kemitix/git-next".to_string()); repo_details.repo_path = RepoPath("kemitix/git-next".to_string());
let gitdir = &repo_details.gitdir; let gitdir = &repo_details.gitdir;
let repository = Repository::open(gitdir)?; let repository = Repository::open(gitdir)?;
@ -204,7 +202,7 @@ fn gitdir_validate_should_pass_a_valid_git_repo() -> Result<()> {
None, None,
GitDir::new(root), // Server GitDir - should be ignored GitDir::new(root), // Server GitDir - should be ignored
); );
repo_details.forge.hostname = Hostname::new("git.kemitix.net"); repo_details.forge.hostname = Hostname("git.kemitix.net".to_string());
repo_details.repo_path = RepoPath("kemitix/git-next".to_string()); repo_details.repo_path = RepoPath("kemitix/git-next".to_string());
let gitdir = &repo_details.gitdir; let gitdir = &repo_details.gitdir;
let repository = Repository::open(gitdir)?; let repository = Repository::open(gitdir)?;
@ -224,7 +222,7 @@ fn gitdir_validate_should_fail_a_git_repo_with_wrong_remote() -> Result<()> {
None, None,
GitDir::new(root), // Server GitDir - should be ignored GitDir::new(root), // Server GitDir - should be ignored
); );
repo_details.forge.hostname = Hostname::new("localhost"); repo_details.forge.hostname = Hostname("localhost".to_string());
repo_details.repo_path = RepoPath("hello/world".to_string()); repo_details.repo_path = RepoPath("hello/world".to_string());
let gitdir = &repo_details.gitdir; let gitdir = &repo_details.gitdir;
let repository = Repository::open(gitdir)?; let repository = Repository::open(gitdir)?;
@ -235,7 +233,7 @@ fn gitdir_validate_should_fail_a_git_repo_with_wrong_remote() -> Result<()> {
#[test] #[test]
fn git_remote_to_string_is_as_expected() { fn git_remote_to_string_is_as_expected() {
let git_remote = GitRemote::new(Hostname::new("foo"), RepoPath("bar".to_string())); let git_remote = GitRemote::new(Hostname("foo".to_string()), RepoPath("bar".to_string()));
let as_string = git_remote.to_string(); let as_string = git_remote.to_string();
assert_eq!(as_string, "foo:bar"); assert_eq!(as_string, "foo:bar");

View file

@ -24,7 +24,7 @@ pub fn user(n: u32) -> User {
} }
pub fn hostname(n: u32) -> Hostname { pub fn hostname(n: u32) -> Hostname {
Hostname::new(format!("hostname-{}", n)) Hostname(format!("hostname-{}", n))
} }
pub fn forge_name(n: u32) -> ForgeName { pub fn forge_name(n: u32) -> ForgeName {
@ -57,7 +57,7 @@ pub fn repo_path(n: u32) -> RepoPath {
} }
pub fn repo_alias(n: u32) -> RepoAlias { pub fn repo_alias(n: u32) -> RepoAlias {
RepoAlias::new(format!("repo-alias-{}", n)) RepoAlias(format!("repo-alias-{}", n))
} }
pub fn repo_config(n: u32, source: RepoConfigSource) -> RepoConfig { pub fn repo_config(n: u32, source: RepoConfigSource) -> RepoConfig {