use anyhow::Result;
use serde::Deserialize;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct Config {
pub path: PathBuf,
pub changelog_enabled: bool,
pub changelog_path: Option<String>,
pub default_bump: String,
pub bump_commit_message: String,
pub bump_tag_message: Option<String>,
pub changelog_header: Option<String>,
pub pkg_tag_template: String,
pub include_v_prefix: bool,
pub releases_per_package: bool,
pub umbrella_release: bool,
pub monorepo_bump_commit_message: Option<String>,
pub allow_dirty: bool,
pub packages: Vec<String>,
pub migration: BTreeMap<String, MigrationHints>,
pub post_bump_command: Option<String>,
}
#[derive(Deserialize, Default)]
struct RcChangelog {
pub enable: Option<bool>,
pub path: Option<String>,
}
#[derive(Deserialize, Default)]
struct RawConfig {
pub default_bump: Option<String>,
pub bump_commit_message: Option<String>,
pub bump_tag_message: Option<String>,
pub changelog_header: Option<String>,
pub changelog: Option<RcChangelog>,
pub pkg_tag_template: Option<String>,
pub include_v_prefix: Option<bool>,
pub releases_per_package: Option<bool>,
pub umbrella_release: Option<bool>,
pub monorepo_bump_commit_message: Option<String>,
pub allow_dirty: Option<bool>,
pub packages: Option<Vec<String>>,
pub migration: Option<BTreeMap<String, MigrationHints>>,
pub post_bump_command: Option<String>,
}
#[derive(Deserialize, Default, Debug, Clone)]
pub struct MigrationHints {
pub legacy_tag_patterns: Option<Vec<String>>,
}
fn env_bool(key: &str) -> Option<bool> {
std::env::var(key).ok().and_then(|v| {
let s = v.trim().to_ascii_lowercase();
match s.as_str() {
"1" | "true" | "yes" | "on" => Some(true),
"0" | "false" | "no" | "off" => Some(false),
_ => None,
}
})
}
fn env_str(key: &str) -> Option<String> {
std::env::var(key)
.ok()
.map(|v| v.trim().to_string())
.filter(|s| !s.is_empty())
}
pub fn load<P: AsRef<Path>>(path: P) -> Result<Config> {
let mut path = path.as_ref().to_path_buf();
if !path.exists() {
let alt = Path::new("rlyx.toml");
if alt.exists() {
path = alt.to_path_buf();
}
}
let mut raw: RawConfig = if path.exists() {
let s = fs_err::read_to_string(&path)?;
toml::from_str(&s).unwrap_or_default()
} else {
RawConfig::default()
};
if let Some(v) = env_str("RLYX_DEFAULT_BUMP") {
raw.default_bump = Some(v);
}
if let Some(v) = env_str("RLYX_BUMP_COMMIT_MESSAGE") {
raw.bump_commit_message = Some(v);
}
if let Some(v) = env_str("RLYX_BUMP_TAG_MESSAGE") {
raw.bump_tag_message = Some(v);
}
if let Some(v) = env_str("RLYX_CHANGELOG_HEADER") {
raw.changelog_header = Some(v);
}
if let Some(b) = env_bool("RLYX_CHANGELOG_ENABLE") {
raw.changelog.get_or_insert(Default::default()).enable =
Some(b);
}
if let Some(v) = env_str("RLYX_CHANGELOG_PATH") {
raw.changelog.get_or_insert(Default::default()).path =
Some(v);
}
if let Some(v) = env_str("RLYX_PKG_TAG_TEMPLATE") {
raw.pkg_tag_template = Some(v);
}
if let Some(b) = env_bool("RLYX_INCLUDE_V_PREFIX") {
raw.include_v_prefix = Some(b);
}
if let Some(b) = env_bool("RLYX_RELEASES_PER_PACKAGE") {
raw.releases_per_package = Some(b);
}
if let Some(b) = env_bool("RLYX_UMBRELLA_RELEASE") {
raw.umbrella_release = Some(b);
}
if let Some(v) = env_str("RLYX_MONOREPO_BUMP_COMMIT_MESSAGE") {
raw.monorepo_bump_commit_message = Some(v);
}
if let Some(v) = env_str("RLYX_POST_BUMP_CMD") {
raw.post_bump_command = Some(v);
}
let default_bump =
raw.default_bump.unwrap_or_else(|| "patch".into());
let bump_commit_message = raw
.bump_commit_message
.unwrap_or_else(|| "release v{{version}}".into());
let monorepo_bump_commit_message =
raw.monorepo_bump_commit_message.unwrap_or_else(|| {
"release {{count}} packages\n\n{{list}}".into()
});
let (changelog_enabled, changelog_path) = {
let en = raw
.changelog
.as_ref()
.and_then(|c| c.enable)
.unwrap_or(true);
let p = raw.changelog.as_ref().and_then(|c| c.path.clone());
(en, p)
};
let pkg_tag_template = raw
.pkg_tag_template
.unwrap_or_else(|| "{{name}}@v{{version}}".into());
let include_v_prefix = raw.include_v_prefix.unwrap_or(true);
let releases_per_package =
raw.releases_per_package.unwrap_or(true);
let umbrella_release = raw.umbrella_release.unwrap_or(false);
let allow_dirty = raw.allow_dirty.unwrap_or(false);
let packages = raw.packages.unwrap_or_default();
let migration = raw.migration.unwrap_or_default();
let post_bump_command = raw.post_bump_command;
Ok(Config {
path,
changelog_enabled,
changelog_path,
default_bump,
bump_commit_message,
bump_tag_message: raw.bump_tag_message,
changelog_header: raw.changelog_header,
pkg_tag_template,
include_v_prefix,
releases_per_package,
umbrella_release,
monorepo_bump_commit_message: Some(
monorepo_bump_commit_message,
),
allow_dirty,
packages,
migration,
post_bump_command,
})
}