1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Deserialize, Serialize, Default)]
5#[serde(rename_all = "kebab-case")]
6pub struct Config {
7 pub current_version: Option<String>,
8 #[serde(default, skip_serializing_if = "Option::is_none")]
9 pub context_lines: Option<usize>,
10 #[serde(default)]
11 pub default_kind: FileKind,
12 #[serde(default)]
13 pub on_invalid_version: OnInvalidVersion,
14 #[serde(default)]
15 pub git: GitConfig,
16 #[serde(default, rename = "file")]
17 pub files: Vec<FileConfig>,
18}
19
20#[derive(Debug, Deserialize, Serialize)]
21#[serde(rename_all = "kebab-case")]
22pub struct GitConfig {
23 #[serde(default = "default_actions")]
24 pub actions: Vec<Action>,
25 #[serde(default)]
26 pub run_pre_commit: RunPreCommit,
27 #[serde(default = "default_tag_template")]
28 pub tag_template: String,
29 #[serde(default = "default_commit_template")]
30 pub commit_template: String,
31 #[serde(default = "default_branch_template")]
32 pub branch_template: String,
33}
34
35impl Default for GitConfig {
36 fn default() -> Self {
37 Self {
38 actions: default_actions(),
39 run_pre_commit: RunPreCommit::default(),
40 tag_template: default_tag_template(),
41 commit_template: default_commit_template(),
42 branch_template: default_branch_template(),
43 }
44 }
45}
46
47impl GitConfig {
48 pub fn has(&self, action: Action) -> bool {
49 self.actions.contains(&action)
50 }
51
52 pub fn validate(&self) -> Result<(), String> {
53 if self.has(Action::Tag) && !self.has(Action::Commit) {
54 return Err("git action 'tag' requires 'commit'".to_string());
55 }
56 if self.has(Action::Push) && !self.has(Action::Commit) {
57 return Err("git action 'push' requires 'commit'".to_string());
58 }
59 if self.has(Action::Pr) && !self.has(Action::Push) {
60 return Err("git action 'pr' requires 'push'".to_string());
61 }
62 if self.has(Action::Pr) && !self.has(Action::Branch) {
63 return Err("git action 'pr' requires 'branch'".to_string());
64 }
65 if self.has(Action::Tag) && self.has(Action::Branch) {
66 return Err("git actions 'tag' and 'branch' cannot coexist".to_string());
67 }
68 Ok(())
69 }
70}
71
72fn default_actions() -> Vec<Action> {
73 vec![Action::AddAll, Action::Commit, Action::Tag]
74}
75
76fn default_tag_template() -> String {
77 "{new-version}".to_string()
78}
79
80fn default_commit_template() -> String {
81 "Bump version from {current-version} to {new-version}".to_string()
82}
83
84fn default_branch_template() -> String {
85 "release/{new-version}".to_string()
86}
87
88#[derive(Debug, Deserialize, Serialize)]
89pub struct FileConfig {
90 pub src: PathBuf,
91 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub kind: Option<FileKind>,
93}
94
95#[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, PartialEq, Eq)]
96#[serde(rename_all = "lowercase")]
97pub enum FileKind {
98 #[default]
99 Any,
100 Simple,
101 Python,
102 Semver,
103}
104
105#[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, PartialEq, Eq)]
106#[serde(rename_all = "lowercase")]
107pub enum OnInvalidVersion {
108 #[default]
109 Error,
110 Cast,
111}
112
113#[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, PartialEq, Eq)]
114#[serde(rename_all = "kebab-case")]
115pub enum RunPreCommit {
116 Enabled,
117 Disabled,
118 #[default]
119 WhenPresent,
120}
121
122#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
123#[serde(rename_all = "kebab-case")]
124pub enum Action {
125 AddAll,
126 Branch,
127 Commit,
128 Tag,
129 Push,
130 Pr,
131}