commit_wizard/engine/models/policy/
changelog.rs1use crate::engine::models::{policy::enforcement::ChangelogFormat, runtime::ResolvedConfig};
2use std::collections::BTreeMap;
3
4#[derive(Debug, Clone)]
5pub struct ChangelogHeaderModel {
6 pub use_header: bool,
7 pub title: String,
8 pub description: Option<String>,
9}
10
11#[derive(Debug, Clone)]
12pub struct ChangelogSectionModel {
13 pub title: Option<String>,
14 pub order: Option<i32>,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum ChangelogOutputFormat {
19 Markdown,
20 Json,
21}
22
23impl From<ChangelogFormat> for ChangelogOutputFormat {
24 fn from(value: ChangelogFormat) -> Self {
25 match value {
26 ChangelogFormat::Markdown => Self::Markdown,
27 ChangelogFormat::Json => Self::Json,
28 }
29 }
30}
31
32#[derive(Debug, Clone)]
33pub struct ChangelogModel {
34 pub output: String,
35 pub format: ChangelogOutputFormat,
36 pub header: ChangelogHeaderModel,
37 pub group_by: Vec<String>,
38 pub section_order: Vec<String>,
39 pub scope_order: Vec<String>,
40 pub show_scope: bool,
41 pub show_empty_sections: Option<bool>,
42 pub show_empty_scopes: Option<bool>,
43 pub misc_section: Option<String>,
44 pub unreleased_label: String,
45 pub date_format: Option<String>,
46 pub sections: BTreeMap<String, ChangelogSectionModel>,
47}
48
49impl Default for ChangelogModel {
50 fn default() -> Self {
51 Self {
52 output: "CHANGELOG.md".to_string(),
53 format: ChangelogOutputFormat::Markdown,
54 header: ChangelogHeaderModel {
55 use_header: true,
56 title: "Changelog".to_string(),
57 description: None,
58 },
59 group_by: vec!["type".to_string()],
60 section_order: vec![
61 "feat".to_string(),
62 "fix".to_string(),
63 "docs".to_string(),
64 "style".to_string(),
65 "refactor".to_string(),
66 "perf".to_string(),
67 "test".to_string(),
68 "chore".to_string(),
69 ],
70 scope_order: Vec::new(),
71 show_scope: true,
72 show_empty_sections: Some(false),
73 show_empty_scopes: Some(false),
74 misc_section: Some("Miscellaneous".to_string()),
75 unreleased_label: "Unreleased".to_string(),
76 date_format: None,
77 sections: BTreeMap::new(),
78 }
79 }
80}
81
82impl ChangelogModel {
83 pub fn from_config(config: &ResolvedConfig) -> Self {
84 let base = &config.base;
85
86 let sections_from_config = base.changelog_sections();
88 let sections = sections_from_config
89 .into_iter()
90 .map(|(key, cfg)| {
91 (
92 key,
93 ChangelogSectionModel {
94 title: cfg.title,
95 order: cfg.order,
96 },
97 )
98 })
99 .collect();
100
101 Self {
102 output: base.changelog_output(),
103 format: base.changelog_format().into(),
104 header: ChangelogHeaderModel {
105 use_header: base.changelog_header_use(),
106 title: base.changelog_header_title(),
107 description: base.changelog_header_description(),
108 },
109 group_by: base.changelog_group_by(),
110 section_order: base.changelog_section_order(),
111 scope_order: base.changelog_scope_order(),
112 show_scope: base.changelog_show_scope(),
113 show_empty_sections: base.changelog_show_empty_sections(),
114 show_empty_scopes: base.changelog_show_empty_scopes(),
115 misc_section: base.changelog_misc_section(),
116 unreleased_label: base.changelog_unreleased_label(),
117 date_format: base.changelog_date_format(),
118 sections,
119 }
120 }
121}
122
123pub fn section_for_type<'a>(sections: &'a BTreeMap<String, Vec<String>>, typ: &'a str) -> &'a str {
124 for (section, types) in sections {
125 if types.iter().any(|t| t == typ) {
126 return section;
127 }
128 }
129 "Uncategorized"
130}