mit_commit_message_lints/mit/cmd/
set_config_authors.rs1use miette::Result;
2
3use crate::{external::Vcs, mit::Author};
4pub fn set_config_authors(store: &mut dyn Vcs, initial: &str, author: &Author<'_>) -> Result<()> {
8 store.set_str(
9 &format!("mit.author.config.{initial}.email"),
10 author.email(),
11 )?;
12 store.set_str(&format!("mit.author.config.{initial}.name"), author.name())?;
13
14 if let Some(signingkey) = author.signingkey() {
15 store.set_str(
16 &format!("mit.author.config.{initial}.signingkey"),
17 signingkey,
18 )?;
19 } else {
20 let key = format!("mit.author.config.{initial}.signingkey");
21 if store.get_str(&key)?.is_some() {
22 store.remove(&key)?;
23 }
24 }
25
26 Ok(())
27}
28
29#[cfg(test)]
30mod tests {
31 use std::collections::BTreeMap;
32
33 use miette::{miette, Result};
34
35 use crate::{
36 external::{InMemory, RepoState, Vcs},
37 mit::{cmd::set_config_authors::set_config_authors, Author},
38 };
39
40 struct Git2LikeVcs<'a> {
43 store: &'a mut BTreeMap<String, String>,
44 }
45
46 impl Git2LikeVcs<'_> {
47 const fn new(store: &mut BTreeMap<String, String>) -> Git2LikeVcs<'_> {
48 Git2LikeVcs { store }
49 }
50 }
51
52 impl Vcs for Git2LikeVcs<'_> {
53 fn entries(&self, _glob: Option<&str>) -> Result<Vec<String>> {
54 Ok(vec![])
55 }
56
57 fn get_bool(&self, _name: &str) -> Result<Option<bool>> {
58 Ok(None)
59 }
60
61 fn get_str(&self, name: &str) -> Result<Option<&str>> {
62 Ok(self.store.get(name).map(String::as_str))
63 }
64
65 fn get_i64(&self, _name: &str) -> Result<Option<i64>> {
66 Ok(None)
67 }
68
69 fn set_str(&mut self, name: &str, value: &str) -> Result<()> {
70 self.store.insert(name.into(), value.into());
71 Ok(())
72 }
73
74 fn set_i64(&mut self, _name: &str, _value: i64) -> Result<()> {
75 Ok(())
76 }
77
78 fn remove(&mut self, name: &str) -> Result<()> {
79 if self.store.remove(name).is_none() {
80 return Err(miette!("could not find key '{name}' to delete"));
81 }
82 Ok(())
83 }
84
85 fn state(&self) -> Option<RepoState> {
86 None
87 }
88 }
89
90 #[test]
91 fn can_set_an_author() {
92 let mut store: BTreeMap<String, String> = BTreeMap::new();
93 let mut vcs = InMemory::new(&mut store);
94
95 set_config_authors(
96 &mut vcs,
97 "zy",
98 &Author::new("Z Y".into(), "zy@example.com".into(), None),
99 )
100 .expect("command to have succeeded");
101
102 let mut expected: BTreeMap<String, String> = BTreeMap::new();
103 expected.insert("mit.author.config.zy.email".into(), "zy@example.com".into());
104 expected.insert("mit.author.config.zy.name".into(), "Z Y".into());
105
106 assert_eq!(
107 store, expected,
108 "Expected the VCS store to contain the author's email and name after setting an author"
109 );
110 }
111
112 #[test]
113 fn can_set_an_author_with_signing_key() {
114 let mut store: BTreeMap<String, String> = BTreeMap::new();
115 let mut vcs = InMemory::new(&mut store);
116
117 set_config_authors(
118 &mut vcs,
119 "bt",
120 &Author::new(
121 "Billie Thompson".into(),
122 "billie@example.com".into(),
123 Some("ABC".into()),
124 ),
125 )
126 .expect("Should succeed");
127
128 let mut expected: BTreeMap<String, String> = BTreeMap::new();
129 expected.insert("mit.author.config.bt.name".into(), "Billie Thompson".into());
130 expected.insert(
131 "mit.author.config.bt.email".into(),
132 "billie@example.com".into(),
133 );
134 expected.insert("mit.author.config.bt.signingkey".into(), "ABC".into());
135
136 assert_eq!(
137 store, expected,
138 "Expected the VCS store to contain the author's email, name, and signing key"
139 );
140 }
141
142 #[test]
143 fn updating_author_without_signing_key_removes_old_signing_key() {
144 let mut store: BTreeMap<String, String> = BTreeMap::new();
146 {
147 let mut vcs = InMemory::new(&mut store);
148
149 set_config_authors(
150 &mut vcs,
151 "bt",
152 &Author::new(
153 "Billie Thompson".into(),
154 "billie@example.com".into(),
155 Some("ABC".into()),
156 ),
157 )
158 .expect("Should succeed");
159 }
160
161 assert!(
162 store.contains_key("mit.author.config.bt.signingkey"),
163 "Signing key should be present after first set"
164 );
165
166 {
168 let mut vcs = InMemory::new(&mut store);
169
170 set_config_authors(
171 &mut vcs,
172 "bt",
173 &Author::new(
174 "Billie Thompson".into(),
175 "billie@newdomain.com".into(),
176 None,
177 ),
178 )
179 .expect("Should succeed");
180 }
181
182 let mut expected: BTreeMap<String, String> = BTreeMap::new();
183 expected.insert("mit.author.config.bt.name".into(), "Billie Thompson".into());
184 expected.insert(
185 "mit.author.config.bt.email".into(),
186 "billie@newdomain.com".into(),
187 );
188 assert_eq!(
191 store, expected,
192 "Updating an author without a signing key should remove the old signing key entry"
193 );
194 }
195
196 #[test]
197 fn setting_author_without_signing_key_succeeds_when_no_prior_key_exists() {
198 let mut store: BTreeMap<String, String> = BTreeMap::new();
201 let mut vcs = Git2LikeVcs::new(&mut store);
202
203 set_config_authors(
204 &mut vcs,
205 "jd",
206 &Author::new("Jane Doe".into(), "jd@example.com".into(), None),
207 )
208 .expect("Should succeed even when no prior signingkey exists");
209 }
210}