use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Config {
#[serde(default = "default_base_branch")]
pub base_branch: String,
#[serde(default)]
pub parties: HashMap<String, Party>,
#[serde(default)]
pub auto_update: AutoUpdateConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AutoUpdateConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub parties: AutoUpdateParties,
#[serde(default)]
pub push: bool,
#[serde(default)]
pub quiet: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum AutoUpdateParties {
All(String), Specific(Vec<String>),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Party {
#[serde(default)]
pub members: Vec<String>,
#[serde(default)]
pub merge_order: MergeOrderStrategy,
#[serde(default)]
pub conflict_policy: ConflictPolicy,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum MergeOrderStrategy {
Listed,
NewestFirst,
OldestFirst,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConflictPolicy {
#[serde(default = "default_conflict_mode")]
pub default: ConflictMode,
#[serde(default)]
pub overrides: Vec<ConflictOverride>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConflictOverride {
pub path: String,
pub mode: ConflictMode,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ConflictMode {
Ours,
Theirs,
Union,
Manual,
}
impl Default for Config {
fn default() -> Self {
Self {
base_branch: default_base_branch(),
parties: HashMap::new(),
auto_update: AutoUpdateConfig::default(),
}
}
}
impl Default for Party {
fn default() -> Self {
Self {
members: Vec::new(),
merge_order: MergeOrderStrategy::default(),
conflict_policy: ConflictPolicy::default(),
}
}
}
impl Default for MergeOrderStrategy {
fn default() -> Self {
MergeOrderStrategy::Listed
}
}
impl Default for ConflictPolicy {
fn default() -> Self {
Self {
default: default_conflict_mode(),
overrides: Vec::new(),
}
}
}
impl Default for ConflictMode {
fn default() -> Self {
ConflictMode::Manual
}
}
impl Default for AutoUpdateConfig {
fn default() -> Self {
Self {
enabled: true,
parties: AutoUpdateParties::default(),
push: false,
quiet: false,
}
}
}
impl Default for AutoUpdateParties {
fn default() -> Self {
AutoUpdateParties::All("all".to_string())
}
}
fn default_base_branch() -> String {
"main".to_string()
}
fn default_conflict_mode() -> ConflictMode {
ConflictMode::Manual
}
impl Config {
pub fn sample() -> Self {
let mut parties = HashMap::new();
parties.insert("qa".to_string(), Party {
members: vec![
"feature/a".to_string(),
"feature/b".to_string(),
"@payments".to_string(),
],
merge_order: MergeOrderStrategy::Listed,
conflict_policy: ConflictPolicy {
default: ConflictMode::Ours,
overrides: vec![
ConflictOverride {
path: "Gemfile.lock".to_string(),
mode: ConflictMode::Ours,
},
ConflictOverride {
path: "yarn.lock".to_string(),
mode: ConflictMode::Theirs,
},
],
},
});
parties.insert("payments".to_string(), Party {
members: vec![
"feature/pay-ux".to_string(),
"feature/pay-api".to_string(),
],
merge_order: MergeOrderStrategy::Listed,
conflict_policy: ConflictPolicy::default(),
});
Self {
base_branch: "main".to_string(),
parties,
auto_update: AutoUpdateConfig {
enabled: true,
parties: AutoUpdateParties::All("all".to_string()),
push: false,
quiet: true,
},
}
}
}
impl std::fmt::Display for MergeOrderStrategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MergeOrderStrategy::Listed => write!(f, "listed"),
MergeOrderStrategy::NewestFirst => write!(f, "newest_first"),
MergeOrderStrategy::OldestFirst => write!(f, "oldest_first"),
}
}
}
impl std::str::FromStr for MergeOrderStrategy {
type Err = crate::error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"listed" => Ok(MergeOrderStrategy::Listed),
"newest_first" => Ok(MergeOrderStrategy::NewestFirst),
"oldest_first" => Ok(MergeOrderStrategy::OldestFirst),
_ => Err(crate::error::Error::config(format!("Invalid merge order strategy: {}", s))),
}
}
}
impl std::fmt::Display for ConflictMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConflictMode::Ours => write!(f, "ours"),
ConflictMode::Theirs => write!(f, "theirs"),
ConflictMode::Union => write!(f, "union"),
ConflictMode::Manual => write!(f, "manual"),
}
}
}
impl std::str::FromStr for ConflictMode {
type Err = crate::error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ours" => Ok(ConflictMode::Ours),
"theirs" => Ok(ConflictMode::Theirs),
"union" => Ok(ConflictMode::Union),
"manual" => Ok(ConflictMode::Manual),
_ => Err(crate::error::Error::invalid_conflict_strategy(s)),
}
}
}