forked from kemitix/git-next
refactor(config): more derive_more replacing boilerplate
This commit is contained in:
parent
c374076323
commit
d70baa4350
23 changed files with 217 additions and 220 deletions
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<_>>();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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}"
|
||||||
));
|
));
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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,
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue