feat: refactor frontend configuration

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2023-08-01 02:31:44 +02:00
parent e235483783
commit 8cd68d569b
22 changed files with 557 additions and 268 deletions

View File

@@ -0,0 +1,71 @@
use std::path::PathBuf;
use clap::Args;
use crate::stage0_config::{
PleaseConfigBuilder, PleaseProjectConfigBuilder, PleaseSettingsConfigBuilder,
};
#[derive(Args, Debug, Clone)]
pub struct ConfigArgs {
/// Which repository to publish against. If not supplied remote url will be inferred from environment or fail if not present.
#[arg(
env = "CUDDLE_PLEASE_API_URL",
long,
global = true,
help_heading = "Config"
)]
pub api_url: Option<String>,
/// repo is the name of repository you want to release for
#[arg(
env = "CUDDLE_PLEASE_REPO",
long,
global = true,
help_heading = "Config"
)]
pub repo: Option<String>,
/// owner is the name of user from which the repository belongs <user>/<repo>
#[arg(
env = "CUDDLE_PLEASE_OWNER",
long,
global = true,
help_heading = "Config"
)]
pub owner: Option<String>,
/// which source directory to use, if not set `std::env::current_dir` is used instead.
#[arg(
env = "CUDDLE_PLEASE_SOURCE",
long,
global = true,
help_heading = "Config"
)]
pub source: Option<PathBuf>,
/// which branch is being run from
#[arg(
env = "CUDDLE_PLEASE_BRANCH",
long,
global = true,
help_heading = "Config"
)]
pub branch: Option<String>,
}
impl From<ConfigArgs> for PleaseConfigBuilder {
fn from(value: ConfigArgs) -> Self {
Self {
project: Some(PleaseProjectConfigBuilder {
owner: value.owner,
repository: value.repo,
source: value.source,
branch: value.branch,
}),
settings: Some(PleaseSettingsConfigBuilder {
api_url: value.api_url,
}),
}
}
}

View File

@@ -0,0 +1,80 @@
use std::path::{Path, PathBuf};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::stage0_config::PleaseConfigBuilder;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct CuddleEmbeddedPleaseConfig {
please: PleaseConfigBuilder,
}
impl From<CuddleEmbeddedPleaseConfig> for PleaseConfigBuilder {
fn from(value: CuddleEmbeddedPleaseConfig) -> Self {
value.please
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct CuddlePleaseConfig {
#[serde(flatten)]
please: PleaseConfigBuilder,
}
impl From<CuddlePleaseConfig> for PleaseConfigBuilder {
fn from(value: CuddlePleaseConfig) -> Self {
value.please
}
}
const CUDDLE_FILE_NAME: &str = "cuddle";
const CUDDLE_CONFIG_FILE_NAME: &str = "cuddle.please";
const YAML_EXTENSION: &str = "yaml";
pub fn get_config_from_config_file(current_dir: &Path) -> PleaseConfigBuilder {
let current_cuddle_path = current_dir
.clone()
.join(format!("{CUDDLE_FILE_NAME}.{YAML_EXTENSION}"));
let current_cuddle_config_path = current_dir
.clone()
.join(format!("{CUDDLE_CONFIG_FILE_NAME}.{YAML_EXTENSION}"));
let mut please_config = PleaseConfigBuilder::default();
if let Some(config) = get_config_from_file::<CuddleEmbeddedPleaseConfig>(current_cuddle_path) {
please_config = please_config.merge(&config).clone();
}
if let Some(config) = get_config_from_file::<CuddlePleaseConfig>(current_cuddle_config_path) {
please_config = please_config.merge(&config).clone();
}
please_config
}
pub fn get_config_from_file<T>(current_cuddle_path: PathBuf) -> Option<PleaseConfigBuilder>
where
T: DeserializeOwned,
T: Into<PleaseConfigBuilder>,
{
match std::fs::File::open(&current_cuddle_path) {
Ok(file) => match serde_yaml::from_reader::<_, T>(file) {
Ok(config) => {
return Some(config.into());
}
Err(e) => {
tracing::debug!(
"{} doesn't contain a valid please config: {}",
&current_cuddle_path.display(),
e
);
}
},
Err(e) => {
tracing::debug!(
"did not find or was not allowed to read {}, error: {}",
&current_cuddle_path.display(),
e,
);
}
}
None
}

View File

@@ -0,0 +1,53 @@
use std::{collections::HashMap, path::PathBuf};
use crate::stage0_config::{PleaseConfigBuilder, PleaseProjectConfigBuilder};
pub fn get_from_environment(vars: std::env::Vars) -> PleaseConfigBuilder {
let vars: HashMap<String, String> = vars.collect();
let env = detect_environment(&vars);
match env {
ExecutionEnvironment::Local => PleaseConfigBuilder {
project: Some(PleaseProjectConfigBuilder {
source: Some(PathBuf::from(".")),
..Default::default()
}),
settings: None,
},
ExecutionEnvironment::Drone => PleaseConfigBuilder {
project: Some(PleaseProjectConfigBuilder {
owner: Some(
vars.get("DRONE_REPO_OWNER")
.expect("DRONE_REPO_OWNER to be present")
.clone(),
),
repository: Some(
vars.get("DRONE_REPO_NAME")
.expect("DRONE_REPO_NAME to be present")
.clone(),
),
source: Some(PathBuf::from(".")),
branch: Some(
vars.get("DRONE_REPO_BRANCH")
.expect("DRONE_REPO_BRANCH to be present")
.clone(),
),
}),
settings: None,
},
}
}
pub fn detect_environment(vars: &HashMap<String, String>) -> ExecutionEnvironment {
if let Some(_) = vars.get("DRONE".into()) {
return ExecutionEnvironment::Drone;
}
ExecutionEnvironment::Local
}
pub enum ExecutionEnvironment {
Local,
Drone,
}

View File

@@ -0,0 +1,9 @@
mod cli;
mod config_file;
mod execution_env;
mod stdin;
pub use cli::ConfigArgs;
pub(crate) use config_file::get_config_from_config_file;
pub(crate) use execution_env::get_from_environment;
pub(crate) use stdin::get_config_from_stdin;

View File

@@ -0,0 +1,19 @@
use serde::Deserialize;
use crate::stage0_config::PleaseConfigBuilder;
pub fn get_config_from_stdin<'d, T>(stdin: &'d str) -> PleaseConfigBuilder
where
T: Deserialize<'d>,
T: Into<PleaseConfigBuilder>,
{
match serde_yaml::from_str::<'d, T>(stdin) {
Ok(config) => {
return config.into();
}
Err(e) => {
tracing::debug!("stdin doesn't contain a valid please config: {}", e);
}
}
PleaseConfigBuilder::default()
}