refactor(config): more derive_more replacing boilerplate
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

This commit is contained in:
Paul Campbell 2024-05-15 07:55:05 +01:00
parent c374076323
commit d70baa4350
23 changed files with 217 additions and 220 deletions

View file

@ -62,9 +62,10 @@ warp = "0.3"
# error handling # error handling
derive_more = { version = "1.0.0-beta.6", features = [ derive_more = { version = "1.0.0-beta.6", features = [
"from", "constructor",
"display", "display",
"deref", "deref",
"from",
] } ] }
terrors = "0.3" terrors = "0.3"

View file

@ -1,13 +1,8 @@
/// The API Token for the [user] /// The API Token for the [user]
/// ForgeJo: https://{hostname}/user/settings/applications /// ForgeJo: https://{hostname}/user/settings/applications
/// Github: https://github.com/settings/tokens /// Github: https://github.com/settings/tokens
#[derive(Clone, Debug)] #[derive(Clone, Debug, derive_more::Constructor)]
pub struct ApiToken(pub secrecy::Secret<String>); pub struct ApiToken(secrecy::Secret<String>);
impl From<String> for ApiToken {
fn from(value: String) -> Self {
Self(value.into())
}
}
/// The API Token is in effect a password, so it must be explicitly exposed to access its value /// The API Token is in effect a password, so it must be explicitly exposed to access its value
impl secrecy::ExposeSecret<String> for ApiToken { impl secrecy::ExposeSecret<String> for ApiToken {
fn expose_secret(&self) -> &String { fn expose_secret(&self) -> &String {

View file

@ -4,14 +4,16 @@ use crate::{ApiToken, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User};
/// Defines a Forge to connect to /// Defines a Forge to connect to
/// Maps from `git-next-server.toml` at `forge.{forge}` /// Maps from `git-next-server.toml` at `forge.{forge}`
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Display)] #[derive(
Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Constructor, derive_more::Display,
)]
#[display("{}:{}@{}", forge_type.to_string().to_lowercase(), user, hostname)] #[display("{}:{}@{}", forge_type.to_string().to_lowercase(), user, hostname)]
pub struct ForgeConfig { pub struct ForgeConfig {
pub forge_type: ForgeType, forge_type: ForgeType,
pub hostname: String, hostname: String,
pub user: String, user: String,
pub token: String, token: String,
pub repos: BTreeMap<String, ServerRepoConfig>, repos: BTreeMap<String, ServerRepoConfig>,
} }
impl ForgeConfig { impl ForgeConfig {
pub const fn forge_type(&self) -> ForgeType { pub const fn forge_type(&self) -> ForgeType {
@ -23,11 +25,11 @@ impl ForgeConfig {
} }
pub fn user(&self) -> User { pub fn user(&self) -> User {
User(self.user.clone()) User::new(self.user.clone())
} }
pub fn token(&self) -> ApiToken { pub fn token(&self) -> ApiToken {
ApiToken(self.token.clone().into()) ApiToken::new(self.token.clone().into())
} }
pub fn repos(&self) -> impl Iterator<Item = (RepoAlias, &ServerRepoConfig)> { pub fn repos(&self) -> impl Iterator<Item = (RepoAlias, &ServerRepoConfig)> {
@ -35,4 +37,8 @@ impl ForgeConfig {
.iter() .iter()
.map(|(name, repo)| (RepoAlias::new(name), repo)) .map(|(name, repo)| (RepoAlias::new(name), repo))
} }
pub fn get_repo(&self, arg: &str) -> Option<&ServerRepoConfig> {
self.repos.get(arg)
}
} }

View file

@ -1,16 +1,38 @@
use crate::{ApiToken, ForgeConfig, ForgeName, ForgeType, Hostname, User}; use crate::{ApiToken, ForgeConfig, ForgeName, ForgeType, Hostname, User};
/// The derived information about a Forge, used to create interactions with it /// The derived information about a Forge, used to create interactions with it
#[derive(Clone, Debug)] #[derive(Clone, Debug, derive_more::Constructor)]
pub struct ForgeDetails { pub struct ForgeDetails {
pub forge_name: ForgeName, forge_name: ForgeName,
pub forge_type: ForgeType, forge_type: ForgeType,
pub hostname: Hostname, hostname: Hostname,
pub user: User, user: User,
pub token: ApiToken, token: ApiToken,
// API Token // API Token
// Private SSH Key Path // Private SSH Key Path
} }
impl ForgeDetails {
pub const fn forge_name(&self) -> &ForgeName {
&self.forge_name
}
pub const fn forge_type(&self) -> ForgeType {
self.forge_type
}
pub const fn hostname(&self) -> &Hostname {
&self.hostname
}
pub const fn user(&self) -> &User {
&self.user
}
pub const fn token(&self) -> &ApiToken {
&self.token
}
pub fn with_hostname(self, hostname: Hostname) -> Self {
let mut me = self;
me.hostname = hostname;
me
}
}
impl From<(&ForgeName, &ForgeConfig)> for ForgeDetails { impl From<(&ForgeName, &ForgeConfig)> for ForgeDetails {
fn from(forge: (&ForgeName, &ForgeConfig)) -> Self { fn from(forge: (&ForgeName, &ForgeConfig)) -> Self {
Self { Self {

View file

@ -1,8 +1,8 @@
use std::path::PathBuf; use std::path::PathBuf;
/// The name of a Forge to connect to /// The name of a Forge to connect to
#[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)] #[derive(Clone, Debug, PartialEq, Eq, derive_more::Constructor, derive_more::Display)]
pub struct ForgeName(pub String); pub struct ForgeName(String);
impl From<&ForgeName> for PathBuf { impl From<&ForgeName> for PathBuf {
fn from(value: &ForgeName) -> Self { fn from(value: &ForgeName) -> Self {
Self::from(&value.0) Self::from(&value.0)

View file

@ -1,6 +1,8 @@
use std::{ops::Deref, path::PathBuf}; use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, derive_more::From)] #[derive(
Debug, Clone, PartialEq, Eq, serde::Deserialize, derive_more::Deref, derive_more::From,
)]
pub struct GitDir(PathBuf); pub struct GitDir(PathBuf);
impl GitDir { impl GitDir {
pub fn new(pathbuf: &std::path::Path) -> Self { pub fn new(pathbuf: &std::path::Path) -> Self {
@ -11,13 +13,6 @@ impl GitDir {
&self.0 &self.0
} }
} }
impl Deref for GitDir {
type Target = PathBuf;
fn deref(&self) -> &Self::Target {
&self.0
}
}
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 {
write!(f, "{}", &self.0.display()) write!(f, "{}", &self.0.display())

View file

@ -1,12 +1,14 @@
use crate::BranchName; use crate::BranchName;
/// Mapped from `.git-next.toml` file at `branches` /// Mapped from `.git-next.toml` file at `branches`
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Display)] #[derive(
Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Constructor, derive_more::Display,
)]
#[display("{},{},{}", main, next, dev)] #[display("{},{},{}", main, next, dev)]
pub struct RepoBranches { pub struct RepoBranches {
pub main: String, main: String,
pub next: String, next: String,
pub dev: String, dev: String,
} }
impl RepoBranches { impl RepoBranches {
pub fn main(&self) -> BranchName { pub fn main(&self) -> BranchName {

View file

@ -4,11 +4,13 @@ use crate::RepoConfigSource;
/// Mapped from `.git-next.toml` file in target repo /// Mapped from `.git-next.toml` file in target repo
/// Is also derived from the optional parameters in `git-next-server.toml` at /// Is also derived from the optional parameters in `git-next-server.toml` at
/// `forge.{forge}.repos.{repo}.(main|next|dev)` /// `forge.{forge}.repos.{repo}.(main|next|dev)`
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Display)] #[derive(
Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Constructor, derive_more::Display,
)]
#[display("{}", branches)] #[display("{}", branches)]
pub struct RepoConfig { pub struct RepoConfig {
pub branches: RepoBranches, branches: RepoBranches,
pub source: RepoConfigSource, source: RepoConfigSource,
} }
impl RepoConfig { impl RepoConfig {
pub fn load(toml: &str) -> Result<Self, toml::de::Error> { pub fn load(toml: &str) -> Result<Self, toml::de::Error> {

View file

@ -1,5 +1,5 @@
/// The path for the repo within the forge. /// The path for the repo within the forge.
/// Typically this is composed of the user or organisation and the name of the repo /// Typically this is composed of the user or organisation and the name of the repo
/// e.g. `{user}/{repo}` /// e.g. `{user}/{repo}`
#[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)] #[derive(Clone, Debug, PartialEq, Eq, derive_more::Constructor, derive_more::Display)]
pub struct RepoPath(pub String); pub struct RepoPath(String);

View file

@ -4,19 +4,21 @@ use crate::{BranchName, GitDir, RepoBranches, RepoConfig, RepoConfigSource, Repo
/// Defines a Repo within a ForgeConfig 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}` /// Maps from `git-next-server.toml` at `forge.{forge}.repos.{name}`
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Display)] #[derive(
Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Constructor, derive_more::Display,
)]
#[display("{}@{}", repo, branch)] #[display("{}@{}", repo, branch)]
pub struct ServerRepoConfig { pub struct ServerRepoConfig {
pub repo: String, repo: String,
pub branch: String, branch: String,
pub gitdir: Option<PathBuf>, gitdir: Option<PathBuf>,
pub main: Option<String>, main: Option<String>,
pub next: Option<String>, next: Option<String>,
pub dev: Option<String>, dev: Option<String>,
} }
impl ServerRepoConfig { impl ServerRepoConfig {
pub fn repo(&self) -> RepoPath { pub fn repo(&self) -> RepoPath {
RepoPath(self.repo.clone()) RepoPath::new(self.repo.clone())
} }
pub fn branch(&self) -> BranchName { pub fn branch(&self) -> BranchName {
@ -30,14 +32,10 @@ impl ServerRepoConfig {
/// Returns a RepoConfig from the server configuration if ALL THREE branches were provided /// Returns a RepoConfig from the server configuration if ALL THREE branches were provided
pub fn repo_config(&self) -> Option<RepoConfig> { pub fn repo_config(&self) -> Option<RepoConfig> {
match (&self.main, &self.next, &self.dev) { match (&self.main, &self.next, &self.dev) {
(Some(main), Some(next), Some(dev)) => Some(RepoConfig { (Some(main), Some(next), Some(dev)) => Some(RepoConfig::new(
branches: RepoBranches { RepoBranches::new(main.to_string(), next.to_string(), dev.to_string()),
main: main.to_string(), RepoConfigSource::Server,
next: next.to_string(), )),
dev: dev.to_string(),
},
source: RepoConfigSource::Server,
}),
_ => None, _ => None,
} }
} }

View file

@ -9,40 +9,29 @@ mod server_repo_config {
#[test] #[test]
fn should_not_return_repo_config_when_no_branches() { fn should_not_return_repo_config_when_no_branches() {
let src = ServerRepoConfig { let src = ServerRepoConfig::new("".to_string(), "".to_string(), None, None, None, None);
repo: "".to_string(),
branch: "".to_string(),
gitdir: None,
main: None,
next: None,
dev: None,
};
let_assert!(None = src.repo_config()); let_assert!(None = src.repo_config());
} }
#[test] #[test]
fn should_return_repo_config_when_branches() { fn should_return_repo_config_when_branches() {
let src = ServerRepoConfig { let src = ServerRepoConfig::new(
repo: "".to_string(), "".to_string(),
branch: "".to_string(), "".to_string(),
gitdir: None, None,
main: Some("main".to_string()), Some("main".to_string()),
next: Some("next".to_string()), Some("next".to_string()),
dev: Some("dev".to_string()), Some("dev".to_string()),
}; );
let_assert!(Some(rc) = src.repo_config()); let_assert!(Some(rc) = src.repo_config());
assert_eq!( assert_eq!(
rc, rc,
RepoConfig { RepoConfig::new(
branches: RepoBranches { RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string()),
main: "main".to_string(), RepoConfigSource::Server
next: "next".to_string(), )
dev: "dev".to_string()
},
source: RepoConfigSource::Server
}
); );
} }
} }
@ -65,14 +54,10 @@ mod repo_config {
assert_eq!( assert_eq!(
rc, rc,
RepoConfig { RepoConfig::new(
branches: RepoBranches { RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string(),),
main: "main".to_string(), RepoConfigSource::Repo // reading from repo is the default
next: "next".to_string(), )
dev: "dev".to_string(),
},
source: RepoConfigSource::Repo // reading from repo is the default
}
); );
Ok(()) Ok(())
@ -90,32 +75,26 @@ mod forge_config {
let hostname = "localhost".to_string(); let hostname = "localhost".to_string();
let user = "bob".to_string(); let user = "bob".to_string();
let token = "alpha".to_string(); let token = "alpha".to_string();
let red = ServerRepoConfig { let red = ServerRepoConfig::new(
repo: "red".to_string(), "red".to_string(),
branch: "main".to_string(), "main".to_string(),
main: None, None,
next: None, None,
dev: None, None,
gitdir: None, None,
}; );
let blue = ServerRepoConfig { let blue = ServerRepoConfig::new(
repo: "blue".to_string(), "blue".to_string(),
branch: "main".to_string(), "main".to_string(),
main: None, None,
next: None, None,
dev: None, None,
gitdir: None, None,
}; );
let mut repos = BTreeMap::new(); let mut repos = BTreeMap::new();
repos.insert("red".to_string(), red.clone()); repos.insert("red".to_string(), red.clone());
repos.insert("blue".to_string(), blue.clone()); repos.insert("blue".to_string(), blue.clone());
let fc = ForgeConfig { let fc = ForgeConfig::new(forge_type, hostname, user, token, repos);
forge_type,
hostname,
user,
token,
repos,
};
let returned_repos = fc.repos().collect::<Vec<_>>(); let returned_repos = fc.repos().collect::<Vec<_>>();

View file

@ -1,3 +1,3 @@
/// The user within the forge to connect as /// The user within the forge to connect as
#[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)] #[derive(Clone, Debug, PartialEq, Eq, derive_more::Constructor, derive_more::Display)]
pub struct User(pub String); pub struct User(String);

View file

@ -7,8 +7,8 @@ use super::{Generation, GitRemote};
/// The derived information about a repo, used to interact with it /// The derived information about a repo, used to interact with it
#[derive(Clone, Debug, derive_more::Display)] #[derive(Clone, Debug, derive_more::Display)]
#[display("gen-{}:{}:{}/{}:{}@{}/{}@{}", generation, forge.forge_type, #[display("gen-{}:{}:{}/{}:{}@{}/{}@{}", generation, forge.forge_type(),
forge.forge_name, repo_alias, forge.user, forge.hostname, repo_path, forge.forge_name(), repo_alias, forge.user(), forge.hostname(), repo_path,
branch)] branch)]
pub struct RepoDetails { pub struct RepoDetails {
pub generation: Generation, pub generation: Generation,
@ -31,32 +31,32 @@ impl RepoDetails {
Self { Self {
generation, generation,
repo_alias: repo_alias.clone(), repo_alias: repo_alias.clone(),
repo_path: RepoPath(server_repo_config.repo.clone()), repo_path: server_repo_config.repo(),
repo_config: server_repo_config.repo_config(), repo_config: server_repo_config.repo_config(),
branch: BranchName::new(&server_repo_config.branch), branch: server_repo_config.branch(),
gitdir, gitdir,
forge: ForgeDetails { forge: ForgeDetails::new(
forge_name: forge_name.clone(), forge_name.clone(),
forge_type: forge_config.forge_type(), forge_config.forge_type(),
hostname: forge_config.hostname(), forge_config.hostname(),
user: forge_config.user(), forge_config.user(),
token: forge_config.token(), forge_config.token(),
}, ),
} }
} }
pub fn origin(&self) -> secrecy::Secret<String> { pub fn origin(&self) -> secrecy::Secret<String> {
let repo_details = self; let repo_details = self;
let user = &repo_details.forge.user; let user = &repo_details.forge.user();
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let expose_secret = repo_details.forge.token();
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let expose_secret = &repo_details.forge.token;
let token = expose_secret.expose_secret(); let token = expose_secret.expose_secret();
let origin = format!("https://{user}:{token}@{hostname}/{repo_path}.git"); let origin = format!("https://{user}:{token}@{hostname}/{repo_path}.git");
origin.into() origin.into()
} }
pub fn git_remote(&self) -> GitRemote { pub fn git_remote(&self) -> GitRemote {
GitRemote::new(self.forge.hostname.clone(), self.repo_path.clone()) GitRemote::new(self.forge.hostname().clone(), self.repo_path.clone())
} }
} }

View file

@ -48,7 +48,7 @@ pub fn find_default_remote(
info!(%host, %path, "found"); info!(%host, %path, "found");
Ok(GitRemote::new( Ok(GitRemote::new(
Hostname::new(host), Hostname::new(host),
RepoPath(path.to_string()), RepoPath::new(path.to_string()),
)) ))
} }

View file

@ -37,7 +37,7 @@ impl RepoActor {
generation: Generation, generation: Generation,
net: Network, net: Network,
) -> Self { ) -> Self {
let forge = match details.forge.forge_type { let forge = match details.forge.forge_type() {
#[cfg(feature = "forgejo")] #[cfg(feature = "forgejo")]
ForgeType::ForgeJo => gitforge::Forge::new_forgejo(details.clone(), net.clone()), ForgeType::ForgeJo => gitforge::Forge::new_forgejo(details.clone(), net.clone()),
ForgeType::MockForge => gitforge::Forge::new_mock(), ForgeType::MockForge => gitforge::Forge::new_mock(),
@ -84,7 +84,9 @@ impl std::fmt::Display for RepoActor {
write!( write!(
f, f,
"{}:{}:{}", "{}:{}:{}",
self.generation, self.details.forge.forge_name, self.details.repo_alias self.generation,
self.details.forge.forge_name(),
self.details.repo_alias
) )
} }
} }

View file

@ -60,10 +60,10 @@ impl Deref for WebhookAuth {
#[tracing::instrument(skip_all, fields(%webhook_id))] #[tracing::instrument(skip_all, fields(%webhook_id))]
pub async fn unregister(webhook_id: WebhookId, repo_details: RepoDetails, net: network::Network) { pub async fn unregister(webhook_id: WebhookId, repo_details: RepoDetails, net: network::Network) {
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = repo_details.repo_path; let repo_path = repo_details.repo_path;
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let token = repo_details.forge.token.expose_secret(); let token = repo_details.forge.token().expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}"
)); ));
@ -101,10 +101,10 @@ pub async fn register(
unregister(webhook_id, repo_details.clone(), net.clone()).await; unregister(webhook_id, repo_details.clone(), net.clone()).await;
} }
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = repo_details.repo_path; let repo_path = repo_details.repo_path;
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let token = repo_details.forge.token.expose_secret(); let token = repo_details.forge.token().expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}"
)); ));
@ -149,12 +149,12 @@ async fn find_existing_webhooks(
net: &network::Network, net: &network::Network,
) -> Vec<WebhookId> { ) -> Vec<WebhookId> {
let mut ids: Vec<WebhookId> = vec![]; let mut ids: Vec<WebhookId> = vec![];
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let mut page = 1; let mut page = 1;
loop { loop {
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let token = &repo_details.forge.token.expose_secret(); let token = &repo_details.forge.token().expose_secret();
let url = let url =
format!("https://{hostname}/api/v1/repos/{repo_path}/hooks?page={page}&token={token}"); format!("https://{hostname}/api/v1/repos/{repo_path}/hooks?page={page}&token={token}");
let net_url = network::NetUrl::new(url); let net_url = network::NetUrl::new(url);

View file

@ -45,7 +45,7 @@ impl ServerConfig {
pub(crate) fn forges(&self) -> impl Iterator<Item = (ForgeName, &ForgeConfig)> { pub(crate) fn forges(&self) -> impl Iterator<Item = (ForgeName, &ForgeConfig)> {
self.forge self.forge
.iter() .iter()
.map(|(name, forge)| (ForgeName(name.clone()), forge)) .map(|(name, forge)| (ForgeName::new(name.clone()), forge))
} }
pub const fn storage(&self) -> &ServerStorage { pub const fn storage(&self) -> &ServerStorage {

View file

@ -65,62 +65,62 @@ fn load_should_parse_server_config() -> Result<()> {
}, },
forge: HashMap::from([( forge: HashMap::from([(
"default".to_string(), "default".to_string(),
ForgeConfig { ForgeConfig::new(
forge_type: ForgeType::MockForge, ForgeType::MockForge,
hostname: "git.example.net".to_string(), "git.example.net".to_string(),
user: "Bob".to_string(), "Bob".to_string(),
token: "API-Token".to_string(), "API-Token".to_string(),
repos: BTreeMap::from([ BTreeMap::from([
( (
"hello".to_string(), "hello".to_string(),
ServerRepoConfig { ServerRepoConfig::new(
repo: "user/hello".to_string(), "user/hello".to_string(),
branch: "main".to_string(), "main".to_string(),
gitdir: Some("/opt/git/user/hello.git".into()), Some("/opt/git/user/hello.git".into()),
main: None, None,
next: None, None,
dev: None, None,
}, ),
), ),
( (
"world".to_string(), "world".to_string(),
ServerRepoConfig { ServerRepoConfig::new(
repo: "user/world".to_string(), "user/world".to_string(),
branch: "master".to_string(), "master".to_string(),
gitdir: None, None,
main: Some("main".to_string()), Some("main".to_string()),
next: Some("next".to_string()), Some("next".to_string()),
dev: Some("dev".to_string()), Some("dev".to_string()),
}, ),
), ),
( (
"sam".to_string(), "sam".to_string(),
ServerRepoConfig { ServerRepoConfig::new(
repo: "user/sam".to_string(), "user/sam".to_string(),
branch: "main".to_string(), "main".to_string(),
gitdir: None, None,
main: Some("master".to_string()), Some("master".to_string()),
next: Some("upcoming".to_string()), Some("upcoming".to_string()),
dev: Some("sam-dev".to_string()), Some("sam-dev".to_string()),
}, ),
), ),
]), ]),
}, ),
)]), )]),
}; };
assert_eq!(config, expected, "ServerConfig"); assert_eq!(config, expected, "ServerConfig");
if let Some(forge) = config.forge.get("world") { if let Some(forge) = config.forge.get("world") {
if let Some(repo) = forge.repos.get("sam") { if let Some(repo) = forge.get_repo("sam") {
let repo_config = repo.repo_config(); let repo_config = repo.repo_config();
let expected = Some(RepoConfig { let expected = Some(RepoConfig::new(
branches: RepoBranches { RepoBranches::new(
main: "master".to_string(), "master".to_string(),
next: "upcoming".to_string(), "upcoming".to_string(),
dev: "sam-dev".to_string(), "sam-dev".to_string(),
}, ),
source: RepoConfigSource::Server, RepoConfigSource::Server,
}); ));
assert_eq!(repo_config, expected, "RepoConfig"); assert_eq!(repo_config, expected, "RepoConfig");
} }
} }
@ -141,14 +141,10 @@ fn test_repo_config_load() -> Result<()> {
assert_eq!( assert_eq!(
config, config,
RepoConfig { RepoConfig::new(
branches: RepoBranches { RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string(),),
main: "main".to_string(), RepoConfigSource::Repo
next: "next".to_string(), )
dev: "dev".to_string(),
},
source: RepoConfigSource::Repo
}
); );
Ok(()) Ok(())
@ -178,8 +174,10 @@ 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 = repo_details
repo_details.repo_path = RepoPath("kemitix/git-next".to_string()); .forge
.with_hostname(Hostname::new("git.kemitix.net"));
repo_details.repo_path = RepoPath::new("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)?;
let found_git_remote = git::validate::find_default_remote(&repository, Direction::Push)?; let found_git_remote = git::validate::find_default_remote(&repository, Direction::Push)?;
@ -204,8 +202,10 @@ 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 = repo_details
repo_details.repo_path = RepoPath("kemitix/git-next".to_string()); .forge
.with_hostname(Hostname::new("git.kemitix.net"));
repo_details.repo_path = RepoPath::new("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)?;
git::validate(&repository, &repo_details)?; git::validate(&repository, &repo_details)?;
@ -224,8 +224,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.repo_path = RepoPath::new("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)?;
let_assert!(Err(_) = git::validate(&repository, &repo_details)); let_assert!(Err(_) = git::validate(&repository, &repo_details));
@ -235,7 +234,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::new("foo"), RepoPath::new("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

@ -9,10 +9,10 @@ pub async fn get_all(
repo_details: &RepoDetails, repo_details: &RepoDetails,
net: &Network, net: &Network,
) -> Result<Vec<BranchName>, ForgeBranchError> { ) -> Result<Vec<BranchName>, ForgeBranchError> {
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let token = repo_details.forge.token.expose_secret(); let token = repo_details.forge.token().expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(
"https://{hostname}/api/v1/repos/{repo_path}/branches?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/branches?token={token}"
)); ));

View file

@ -190,7 +190,7 @@ async fn get_commit_history(
find_commits: Vec<git::Commit>, find_commits: Vec<git::Commit>,
net: &kxio::network::Network, net: &kxio::network::Network,
) -> Result<Vec<git::Commit>, network::NetworkError> { ) -> Result<Vec<git::Commit>, network::NetworkError> {
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let mut page = 1; let mut page = 1;
@ -201,7 +201,7 @@ async fn get_commit_history(
let options = "stat=false&verification=false&files=false"; let options = "stat=false&verification=false&files=false";
let mut all_commits = Vec::new(); let mut all_commits = Vec::new();
loop { loop {
let api_token = &repo_details.forge.token; let api_token = &repo_details.forge.token();
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let token = api_token.expose_secret(); let token = api_token.expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(

View file

@ -11,9 +11,9 @@ pub(super) async fn contents_get(
branch: &BranchName, branch: &BranchName,
file_path: &str, file_path: &str,
) -> Result<String, ForgeFileError> { ) -> Result<String, ForgeFileError> {
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let api_token = &repo_details.forge.token; let api_token = &repo_details.forge.token();
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let token = api_token.expose_secret(); let token = api_token.expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(

View file

@ -93,9 +93,9 @@ impl super::ForgeLike for ForgeJoEnv {
async fn commit_status(&self, commit: &git::Commit) -> gitforge::CommitStatus { async fn commit_status(&self, commit: &git::Commit) -> gitforge::CommitStatus {
let repo_details = &self.repo_details; let repo_details = &self.repo_details;
let hostname = &repo_details.forge.hostname; let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let api_token = &repo_details.forge.token; let api_token = &repo_details.forge.token();
use secrecy::ExposeSecret; use secrecy::ExposeSecret;
let token = api_token.expose_secret(); let token = api_token.expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(

View file

@ -6,21 +6,21 @@ use git_next_config::{
use git_next_git::{Generation, RepoDetails}; use git_next_git::{Generation, RepoDetails};
pub fn forge_details(n: u32, forge_type: ForgeType) -> ForgeDetails { pub fn forge_details(n: u32, forge_type: ForgeType) -> ForgeDetails {
ForgeDetails { ForgeDetails::new(
forge_name: forge_name(n), forge_name(n),
forge_type, forge_type,
hostname: hostname(n), hostname(n),
user: user(n), user(n),
token: api_token(n), api_token(n),
} )
} }
pub fn api_token(n: u32) -> ApiToken { pub fn api_token(n: u32) -> ApiToken {
ApiToken::from(format!("api-{}", n)) ApiToken::new(format!("api-{}", n).into())
} }
pub fn user(n: u32) -> User { pub fn user(n: u32) -> User {
User(format!("user-{}", n)) User::new(format!("user-{}", n))
} }
pub fn hostname(n: u32) -> Hostname { pub fn hostname(n: u32) -> Hostname {
@ -28,7 +28,7 @@ pub fn hostname(n: u32) -> Hostname {
} }
pub fn forge_name(n: u32) -> ForgeName { pub fn forge_name(n: u32) -> ForgeName {
ForgeName(format!("forge-name-{}", n)) ForgeName::new(format!("forge-name-{}", n))
} }
pub fn repo_details( pub fn repo_details(
n: u32, n: u32,
@ -53,7 +53,7 @@ pub fn branch_name(n: u32) -> BranchName {
} }
pub fn repo_path(n: u32) -> RepoPath { pub fn repo_path(n: u32) -> RepoPath {
RepoPath(format!("repo-path-{}", n)) RepoPath::new(format!("repo-path-{}", n))
} }
pub fn repo_alias(n: u32) -> RepoAlias { pub fn repo_alias(n: u32) -> RepoAlias {
@ -61,12 +61,8 @@ pub fn repo_alias(n: u32) -> RepoAlias {
} }
pub fn repo_config(n: u32, source: RepoConfigSource) -> RepoConfig { pub fn repo_config(n: u32, source: RepoConfigSource) -> RepoConfig {
RepoConfig { RepoConfig::new(
branches: RepoBranches { RepoBranches::new(format!("main-{n}"), format!("next-{n}"), format!("dev-{n}")),
main: format!("main-{n}"),
next: format!("next-{n}"),
dev: format!("dev-{n}"),
},
source, source,
} )
} }