refactor: config: use newtype
Some checks failed
ci/woodpecker/cron/cron-docker-builder Pipeline was successful
ci/woodpecker/cron/push-next Pipeline was successful
ci/woodpecker/cron/tag-created Pipeline was successful
ci/woodpecker/push/cron-docker-builder Pipeline was successful
ci/woodpecker/push/push-next Pipeline was successful
ci/woodpecker/push/tag-created Pipeline was successful
Rust / build (push) Has been cancelled

This commit is contained in:
Paul Campbell 2024-06-19 07:02:18 +01:00
parent 5e9f9eb80f
commit ea20afee12
18 changed files with 105 additions and 123 deletions

View file

@ -1,2 +1,2 @@
// The name of a Branch
crate::newtype!(BranchName is a String);
crate::newtype!(BranchName is a String, derive_more::Display, Default);

View file

@ -1,5 +1,5 @@
// The name of a Forge to connect to
crate::newtype!(ForgeAlias is a String);
crate::newtype!(ForgeAlias is a String, derive_more::Display, Default);
impl From<&ForgeAlias> for std::path::PathBuf {
fn from(value: &ForgeAlias) -> Self {
Self::from(&value.0)

View file

@ -1,7 +1,7 @@
//
use std::path::PathBuf;
crate::newtype!(GitDir is a PathBuf, without Display);
crate::newtype!(GitDir is a PathBuf, Default);
impl GitDir {
pub const fn pathbuf(&self) -> &PathBuf {
&self.0
@ -22,8 +22,3 @@ impl From<&GitDir> for PathBuf {
value.to_path_buf()
}
}
impl From<GitDir> for PathBuf {
fn from(value: GitDir) -> Self {
value.0
}
}

View file

@ -1,2 +1,2 @@
// The hostname of a forge
crate::newtype!(Hostname is a String);
crate::newtype!(Hostname is a String, derive_more::Display, Default);

View file

@ -3,9 +3,9 @@
mod api_token;
mod branch_name;
pub mod common;
mod forge_alias;
mod forge_config;
mod forge_details;
mod forge_name;
mod forge_type;
pub mod git_dir;
mod host_name;
@ -26,9 +26,9 @@ mod tests;
pub use api_token::ApiToken;
pub use branch_name::BranchName;
pub use forge_alias::ForgeAlias;
pub use forge_config::ForgeConfig;
pub use forge_details::ForgeDetails;
pub use forge_name::ForgeAlias;
pub use forge_type::ForgeType;
pub use git_dir::GitDir;
pub use host_name::Hostname;

View file

@ -1,35 +1,10 @@
//
#[macro_export]
macro_rules! newtype {
($name:ident is a $type:ty, without Display) => {
#[derive(
Clone,
Default,
Debug,
derive_more::From,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
derive_more::AsRef,
derive_more::Deref,
serde::Deserialize,
serde::Serialize,
)]
pub struct $name($type);
impl $name {
pub fn new(value: impl Into<$type>) -> Self {
Self(value.into())
}
pub fn unwrap(self) -> $type {
self.0
}
}
};
($name:ident is a $type:ty) => {
($name:ident) => {
#[derive(
Clone,
Copy,
Default,
Debug,
derive_more::Display,
@ -40,18 +15,42 @@ macro_rules! newtype {
Ord,
Hash,
derive_more::AsRef,
)]
pub struct $name;
impl $name {
pub fn new() -> Self {
Self
}
}
};
($name:ident is a $type:ty $(, $derive:ty)*) => {
#[derive(
Clone,
Debug,
derive_more::From,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
derive_more::AsRef,
derive_more::Deref,
serde::Deserialize,
serde::Serialize,
$($derive),*
)]
pub struct $name($type);
impl $name {
pub fn new(value: impl Into<$type>) -> Self {
Self(value.into())
}
#[allow(clippy::missing_const_for_fn)]
pub fn unwrap(self) -> $type {
self.0
}
}
impl From<$name> for $type {
fn from(value: $name) -> $type {
value.unwrap()
}
}
};
}

View file

@ -2,7 +2,17 @@ use crate::BranchName;
/// Mapped from `.git-next.toml` file at `branches`
#[derive(
Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Constructor, derive_more::Display,
Clone,
Hash,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
serde::Deserialize,
serde::Serialize,
derive_more::Constructor,
derive_more::Display,
)]
#[display("{},{},{}", main, next, dev)]
pub struct RepoBranches {

View file

@ -5,7 +5,17 @@ use crate::RepoConfigSource;
/// Is also derived from the optional parameters in `git-next-server.toml` at
/// `forge.{forge}.repos.{repo}.(main|next|dev)`
#[derive(
Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Constructor, derive_more::Display,
Clone,
Hash,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
serde::Deserialize,
serde::Serialize,
derive_more::Constructor,
derive_more::Display,
)]
#[display("{}", branches)]
pub struct RepoConfig {
@ -13,7 +23,7 @@ pub struct RepoConfig {
source: RepoConfigSource,
}
impl RepoConfig {
pub fn load(toml: &str) -> Result<Self, toml::de::Error> {
pub fn parse(toml: &str) -> Result<Self, toml::de::Error> {
toml::from_str(format!("source = \"Repo\"\n{}", toml).as_str())
}

View file

@ -1,4 +1,6 @@
#[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Deserialize)]
#[derive(
Copy, Hash, Clone, Debug, PartialEq, Eq, serde::Deserialize, PartialOrd, Ord, serde::Serialize,
)]
pub enum RepoConfigSource {
Repo,
Server,

View file

@ -1,6 +1,5 @@
//
use actix::prelude::*;
use derive_more::Constructor;
use std::{
collections::HashMap,
@ -12,7 +11,7 @@ use std::{
use kxio::fs::FileSystem;
use tracing::info;
use crate::{ForgeAlias, ForgeConfig, RepoAlias};
use crate::{newtype, ForgeAlias, ForgeConfig, RepoAlias};
#[derive(Debug, thiserror::Error)]
pub enum Error {
@ -96,18 +95,8 @@ impl Webhook {
}
}
/// The URL for the webhook where forges should send their updates
#[derive(
Clone,
Debug,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
derive_more::AsRef,
Constructor,
)]
pub struct WebhookUrl(String);
// The RL for the webhook where forges should send their updates
newtype!(WebhookUrl is a String, serde::Serialize);
/// The directory to store server data, such as cloned repos
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, derive_more::Constructor)]

View file

@ -1,18 +1,22 @@
//
use super::*;
use assert2::let_assert;
use secrecy::ExposeSecret;
use std::collections::BTreeMap;
use std::path::PathBuf;
use crate::server::Http;
use crate::server::ServerConfig;
use crate::server::ServerStorage;
use crate::server::Webhook;
use crate::webhook::push::Branch;
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
type TestResult = Result<()>;
mod server_repo_config {
use std::path::PathBuf;
use assert2::let_assert;
use crate::{
tests::given, BranchName, GitDir, RepoBranches, RepoConfig, RepoConfigSource, RepoPath,
};
use super::super::server_repo_config::*;
use super::*;
#[test]
fn should_not_return_repo_config_when_no_branches() {
@ -91,9 +95,6 @@ mod server_repo_config {
}
}
mod repo_config {
use crate::{RepoBranches, RepoConfigSource};
use super::super::repo_config::*;
use super::*;
#[test]
@ -110,7 +111,7 @@ mod repo_config {
"#
);
let rc = RepoConfig::load(toml.as_str())?;
let rc = RepoConfig::parse(toml.as_str())?;
assert_eq!(
rc,
@ -144,13 +145,7 @@ mod repo_config {
}
}
mod forge_config {
use std::collections::BTreeMap;
use secrecy::ExposeSecret;
use crate::{
tests::given, ForgeConfig, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User,
};
use super::*;
#[test]
fn should_return_repos() {
@ -246,14 +241,9 @@ mod forge_config {
}
}
mod forge_details {
use std::collections::BTreeMap;
use super::*;
use secrecy::ExposeSecret;
use crate::{
tests::given, ApiToken, ForgeAlias, ForgeConfig, ForgeDetails, ForgeType, Hostname, User,
};
#[test]
fn should_return_forge_alias() {
let forge_type = ForgeType::MockForge;
@ -364,10 +354,9 @@ mod forge_details {
}
}
mod forge_name {
use super::*;
use std::path::PathBuf;
use crate::{tests::given, ForgeAlias};
#[test]
fn should_convert_to_pathbuf() {
let name = given::a_name();
@ -379,7 +368,7 @@ mod forge_name {
}
}
mod forge_type {
use crate::ForgeType;
use super::*;
#[test]
fn should_display_as_string() {
@ -387,10 +376,9 @@ mod forge_type {
}
}
mod gitdir {
use super::*;
use std::path::PathBuf;
use crate::{tests::given, GitDir};
#[test]
fn should_return_pathbuf() {
let pathbuf = PathBuf::default().join(given::a_name());
@ -439,7 +427,7 @@ mod gitdir {
}
}
mod repo_branches {
use crate::{tests::given, BranchName, RepoBranches};
use super::*;
#[test]
fn should_return_main() {
@ -470,15 +458,10 @@ mod repo_branches {
}
}
mod server {
use super::*;
mod load {
use assert2::let_assert;
use pretty_assertions::assert_eq;
use crate::{
server::ServerConfig,
tests::{given, TestResult},
};
use super::*;
#[test]
fn load_should_parse_server_config() -> TestResult {
@ -559,7 +542,7 @@ token = "{forge_token}"
{repos}
"#
);
eprintln!("{file_contents}");
println!("{file_contents}");
fs.file_write(
&fs.base().join("git-next-server.toml"),
file_contents.as_str(),
@ -569,8 +552,7 @@ token = "{forge_token}"
}
}
mod registered_webhook {
use crate::{tests::given, RegisteredWebhook, WebhookAuth};
use super::*;
#[test]
fn should_return_id() {
@ -590,11 +572,11 @@ mod registered_webhook {
}
}
mod webhook {
use super::*;
mod message {
use super::*;
use std::collections::HashMap;
use crate::{tests::given, WebhookMessage};
#[test]
fn should_return_forge_alias() {
let forge_alias = given::a_forge_alias();
@ -645,7 +627,8 @@ mod webhook {
}
}
mod push {
use crate::{tests::given, webhook::push::Branch, BranchName};
use super::*;
#[test]
fn should_return_main_branch() {
@ -717,18 +700,14 @@ mod push {
}
}
mod given {
use super::*;
use rand::Rng as _;
use std::{
collections::{BTreeMap, HashMap},
path::{Path, PathBuf},
};
use rand::Rng as _;
use crate::{
server::{Http, ServerConfig, ServerStorage, Webhook},
ForgeAlias, ForgeConfig, ForgeType, RepoAlias, RepoBranches, ServerRepoConfig, WebhookId,
};
pub fn a_name() -> String {
use rand::Rng;
use std::iter;

View file

@ -1,7 +1,7 @@
#[derive(Clone, Debug, PartialEq, Eq, derive_more::Deref, derive_more::Display)]
pub struct WebhookAuth(ulid::Ulid);
//
crate::newtype!(WebhookAuth is a ulid::Ulid, derive_more::Display);
impl WebhookAuth {
pub fn new(authorisation: &str) -> Result<Self, ulid::DecodeError> {
pub fn try_new(authorisation: &str) -> Result<Self, ulid::DecodeError> {
use std::str::FromStr as _;
let id = ulid::Ulid::from_str(authorisation)?;
tracing::info!("Parse auth token: {}", id);

View file

@ -1,4 +1,2 @@
use derive_more::{Constructor, Deref, Display};
#[derive(Clone, Debug, PartialEq, Eq, Constructor, Deref, Display)]
pub struct WebhookId(String);
//
crate::newtype!(WebhookId is a String, derive_more::Display);

View file

@ -5,7 +5,7 @@ mod auth {
fn bytes() -> Result<(), Box<dyn std::error::Error>> {
let ulid = ulid::Ulid::new();
let wa = WebhookAuth::new(ulid.to_string().as_str())?;
let wa = WebhookAuth::try_new(ulid.to_string().as_str())?;
assert_eq!(ulid.to_bytes(), wa.to_bytes());
@ -16,7 +16,7 @@ mod auth {
fn string() -> Result<(), Box<dyn std::error::Error>> {
let ulid = ulid::Ulid::new();
let wa = WebhookAuth::new(ulid.to_string().as_str())?;
let wa = WebhookAuth::try_new(ulid.to_string().as_str())?;
assert_eq!(ulid.to_string(), wa.to_string());

View file

@ -36,7 +36,7 @@ impl git::ForgeLike for ForgeJo {
tracing::info!(?authorization, %expected, "is message authorised?");
authorization
.and_then(|header| header.strip_prefix("Basic ").map(|v| v.to_owned()))
.and_then(|value| config::WebhookAuth::new(value.as_str()).ok())
.and_then(|value| config::WebhookAuth::try_new(value.as_str()).ok())
.map(|auth| &auth == expected)
.unwrap_or(false)
}

View file

@ -114,7 +114,7 @@ mod repo_config {
"#
);
let rc = config::RepoConfig::load(toml.as_str())?;
let rc = config::RepoConfig::parse(toml.as_str())?;
assert_eq!(
rc,

View file

@ -34,7 +34,7 @@ async fn load(
open_repository: &git::OpenRepository,
) -> Result<config::RepoConfig, Error> {
let contents = open_repository.read_file(&details.branch, &PathBuf::from(".git-next.toml"))?;
let config = config::RepoConfig::load(&contents)?;
let config = config::RepoConfig::parse(&contents)?;
let config = validate(config, open_repository).await?;
Ok(config)
}

View file

@ -18,7 +18,7 @@ fn test_repo_config_load() -> Result<()> {
[options]
"#;
let config = RepoConfig::load(toml)?;
let config = RepoConfig::parse(toml)?;
assert_eq!(
config,