feat(config): User can specify git directory to use for a repo
All checks were successful
ci/woodpecker/push/push-next Pipeline was successful
ci/woodpecker/push/cron-docker-builder Pipeline was successful
ci/woodpecker/push/tag-created Pipeline was successful

Closes kemitix/git-next#53

Does not include using this information.
This commit is contained in:
Paul Campbell 2024-04-19 18:15:27 +01:00
parent 50a969ede6
commit 704853017b
4 changed files with 43 additions and 31 deletions

View file

@ -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"

View file

@ -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

View file

@ -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<String, Forge>,
forge: HashMap<String, ForgeConfig>,
}
impl ServerConfig {
pub(crate) fn load(fs: &FileSystem) -> Result<Self, OneOf<(std::io::Error, toml::de::Error)>> {
@ -24,7 +25,7 @@ impl ServerConfig {
toml::from_str(&str).map_err(OneOf::new)
}
pub(crate) fn forges(&self) -> impl Iterator<Item = (ForgeName, &Forge)> {
pub(crate) fn forges(&self) -> impl Iterator<Item = (ForgeName, &ForgeConfig)> {
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<String, Repo>,
repos: HashMap<String, ServerRepoConfig>,
}
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<Item = (RepoAlias, &Repo)> {
pub fn repos(&self) -> impl Iterator<Item = (RepoAlias, &ServerRepoConfig)> {
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<PathBuf>,
main: Option<String>,
next: Option<String>,
dev: Option<String>,
}
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<Self> for Repo {
impl AsRef<Self> 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<RepoConfig>,
}
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()),

View file

@ -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)| {