From 704853017b1e63c73a96f52cbb4813dccc2e765a Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Fri, 19 Apr 2024 18:15:27 +0100 Subject: [PATCH] feat(config): User can specify git directory to use for a repo Closes kemitix/git-next#53 Does not include using this information. --- Cargo.toml | 1 + server-default.toml | 4 +-- src/server/config/mod.rs | 59 ++++++++++++++++++++++++---------------- src/server/mod.rs | 10 +++---- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 330578e4..0d0baed0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ tokio = { version = "1.37", features = ["full"] } [dev-dependencies] # Testing assert2 = "0.3" +pretty_assertions = "1.4" test-log = "0.2" anyhow = "1.0" diff --git a/server-default.toml b/server-default.toml index 80a6e644..b8fd1b38 100644 --- a/server-default.toml +++ b/server-default.toml @@ -9,5 +9,5 @@ token = "API-Token" # path to private SSH key for user? [forge.default.repos] -hello = { repo = "user/hello", branch = "main" } # maps to https://git.example.net/user/hello on the branch 'main' -world = { repo = "user/world", branch = "master" } # maps to the 'master' branch +hello = { repo = "user/hello", branch = "main", gitdir = "/opt/git/projects/user/hello.git" } # maps to https://git.example.net/user/hello on the branch 'main' +world = { repo = "user/world", branch = "master", main = "master", next = "upcoming", "dev" = "develop" } # maps to the 'master' branch diff --git a/src/server/config/mod.rs b/src/server/config/mod.rs index 87402fa3..548d829e 100644 --- a/src/server/config/mod.rs +++ b/src/server/config/mod.rs @@ -4,6 +4,7 @@ use std::{ collections::HashMap, fmt::{Display, Formatter}, ops::Deref, + path::PathBuf, }; use secrecy::ExposeSecret; @@ -16,7 +17,7 @@ use crate::filesystem::FileSystem; #[derive(Debug, PartialEq, Eq, Deserialize)] pub struct ServerConfig { webhook: Webhook, - forge: HashMap, + forge: HashMap, } impl ServerConfig { pub(crate) fn load(fs: &FileSystem) -> Result> { @@ -24,7 +25,7 @@ impl ServerConfig { toml::from_str(&str).map_err(OneOf::new) } - pub(crate) fn forges(&self) -> impl Iterator { + pub(crate) fn forges(&self) -> impl Iterator { self.forge .iter() .map(|(name, forge)| (ForgeName(name.clone()), forge)) @@ -119,16 +120,16 @@ impl Display for RepoBranches { /// Defines a Forge to connect to /// Maps from `git-next-server.toml` at `forge.{forge}` #[derive(Clone, Debug, PartialEq, Eq, Deserialize)] -pub struct Forge { +pub struct ForgeConfig { forge_type: ForgeType, hostname: String, user: String, token: String, // API Token // Private SSH Key Path - repos: HashMap, + repos: HashMap, } -impl Forge { +impl ForgeConfig { #[allow(dead_code)] pub const fn forge_type(&self) -> &ForgeType { &self.forge_type @@ -146,29 +147,30 @@ impl Forge { ApiToken(self.token.clone().into()) } - pub fn repos(&self) -> impl Iterator { + pub fn repos(&self) -> impl Iterator { self.repos .iter() .map(|(name, repo)| (RepoAlias(name.clone()), repo)) } } -impl Display for Forge { +impl Display for ForgeConfig { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{} - {}@{}", self.forge_type, self.user, self.hostname) } } -/// Defines a Repo within a Forge to be monitored by the server +/// Defines a Repo within a ForgeConfig to be monitored by the server /// Maps from `git-next-server.toml` at `forge.{forge}.repos.{name}` #[derive(Clone, Debug, PartialEq, Eq, Deserialize)] -pub struct Repo { +pub struct ServerRepoConfig { repo: String, branch: String, + gitdir: Option, main: Option, next: Option, dev: Option, } -impl Repo { +impl ServerRepoConfig { #[allow(dead_code)] pub fn repo(&self) -> RepoPath { RepoPath(self.repo.clone()) @@ -193,12 +195,12 @@ impl Repo { } } #[cfg(test)] -impl AsRef for Repo { +impl AsRef for ServerRepoConfig { fn as_ref(&self) -> &Self { self } } -impl Display for Repo { +impl Display for ServerRepoConfig { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{} - {}", self.repo, self.branch) } @@ -259,8 +261,8 @@ pub struct ForgeDetails { // API Token // Private SSH Key Path } -impl From<(&ForgeName, &Forge)> for ForgeDetails { - fn from(forge: (&ForgeName, &Forge)) -> Self { +impl From<(&ForgeName, &ForgeConfig)> for ForgeDetails { + fn from(forge: (&ForgeName, &ForgeConfig)) -> Self { Self { name: forge.0.clone(), forge_type: forge.1.forge_type.clone(), @@ -318,7 +320,12 @@ pub struct RepoDetails { pub config: Option, } impl RepoDetails { - pub fn new(name: &RepoAlias, repo: &Repo, forge_name: &ForgeName, forge: &Forge) -> Self { + pub fn new( + name: &RepoAlias, + repo: &ServerRepoConfig, + forge_name: &ForgeName, + forge: &ForgeConfig, + ) -> Self { Self { name: name.clone(), repo: RepoPath(repo.repo.clone()), @@ -372,13 +379,14 @@ impl Display for ForgeType { #[cfg(test)] mod tests { + use pretty_assertions::assert_eq; + use crate::filesystem::FileSystem; use super::*; #[test] - #[cfg(feature = "forgejo")] - fn test_server_config_load() -> Result<(), OneOf<(std::io::Error, toml::de::Error)>> { + fn load_should_parse_server_config() -> Result<(), OneOf<(std::io::Error, toml::de::Error)>> { let fs = FileSystem::new_temp().map_err(OneOf::new)?; fs.write_file( "git-next-server.toml", @@ -387,13 +395,13 @@ mod tests { url = "http://localhost:9909/webhook" [forge.default] - forge_type = "ForgeJo" + forge_type = "MockForge" hostname = "git.example.net" user = "Bob" token = "API-Token" [forge.default.repos] - hello = { repo = "user/hello", branch = "main" } + hello = { repo = "user/hello", branch = "main", gitdir = "/opt/git/user/hello.git" } world = { repo = "user/world", branch = "master", main = "main", next = "next", dev = "dev" } [forge.default.repos.sam] @@ -412,17 +420,18 @@ mod tests { }, forge: HashMap::from([( "default".to_string(), - Forge { - forge_type: ForgeType::ForgeJo, + ForgeConfig { + forge_type: ForgeType::MockForge, hostname: "git.example.net".to_string(), user: "Bob".to_string(), token: "API-Token".to_string(), repos: HashMap::from([ ( "hello".to_string(), - Repo { + ServerRepoConfig { repo: "user/hello".to_string(), branch: "main".to_string(), + gitdir: Some("/opt/git/user/hello.git".into()), main: None, next: None, dev: None, @@ -430,9 +439,10 @@ mod tests { ), ( "world".to_string(), - Repo { + ServerRepoConfig { repo: "user/world".to_string(), branch: "master".to_string(), + gitdir: None, main: Some("main".to_string()), next: Some("next".to_string()), dev: Some("dev".to_string()), @@ -440,9 +450,10 @@ mod tests { ), ( "sam".to_string(), - Repo { + ServerRepoConfig { repo: "user/sam".to_string(), branch: "main".to_string(), + gitdir: None, main: Some("master".to_string()), next: Some("upcoming".to_string()), dev: Some("sam-dev".to_string()), diff --git a/src/server/mod.rs b/src/server/mod.rs index 242a0eb3..875bf6f7 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -15,11 +15,11 @@ use crate::{ filesystem::FileSystem, server::{ actors::webhook, - config::{Forge, ForgeName, RepoAlias, Webhook}, + config::{ForgeConfig, ForgeName, RepoAlias, Webhook}, }, }; -use self::{actors::repo::RepoActor, config::Repo}; +use self::{actors::repo::RepoActor, config::ServerRepoConfig}; pub fn init(fs: FileSystem) { let file_name = "git-next-server.toml"; @@ -68,7 +68,7 @@ pub async fn start(fs: FileSystem, net: Network) { } fn create_forge_repos( - forge: &Forge, + forge: &ForgeConfig, forge_name: ForgeName, webhook: &Webhook, net: &Network, @@ -85,10 +85,10 @@ fn create_forge_repos( fn create_actor( forge_name: ForgeName, - forge: config::Forge, + forge: config::ForgeConfig, webhook: &Webhook, net: &Network, -) -> impl Fn((RepoAlias, &Repo)) -> (ForgeName, RepoAlias, RepoActor) { +) -> impl Fn((RepoAlias, &ServerRepoConfig)) -> (ForgeName, RepoAlias, RepoActor) { let webhook = webhook.clone(); let net = net.clone(); move |(repo_name, repo)| {