mit_commit_message_lints/relates/cmd/
get_relate_to_configuration.rs1use std::{
2 convert::TryInto,
3 time::{Duration, SystemTime, UNIX_EPOCH},
4};
5
6use miette::{IntoDiagnostic, Result, WrapErr};
7
8use crate::{external::Vcs, relates::RelateTo};
9
10const CONFIG_KEY_EXPIRES: &str = "mit.relate.expires";
11
12pub fn get_relate_to_configuration(config: &dyn Vcs) -> Result<Option<RelateTo<'_>>> {
19 let config_value = config.get_i64(CONFIG_KEY_EXPIRES)?;
20
21 match config_value {
22 Some(config_value) => {
23 let now = now()?;
24
25 if now < Duration::from_secs(config_value.try_into().into_diagnostic()?) {
26 let relate_to_config = get_vcs_relate_to(config)?.map(RelateTo::from);
27
28 Ok(relate_to_config)
29 } else {
30 Ok(None)
31 }
32 }
33 None => Ok(None),
34 }
35}
36
37fn now() -> Result<Duration> {
38 SystemTime::now()
39 .duration_since(UNIX_EPOCH)
40 .into_diagnostic()
41}
42
43fn get_vcs_relate_to(config: &dyn Vcs) -> Result<Option<&str>> {
44 config
45 .get_str("mit.relate.to")
46 .wrap_err("failed to read relate-to issue")
47}
48
49#[cfg(test)]
50mod tests {
51 use std::{
52 collections::BTreeMap,
53 convert::TryFrom,
54 ops::Add,
55 time::{Duration, SystemTime, UNIX_EPOCH},
56 };
57
58 use crate::{
59 external::InMemory,
60 relates::{RelateTo, get_relate_to_configuration},
61 };
62
63 #[test]
64 fn there_is_no_relate_config_if_it_has_expired() {
65 let now_minus_10 = epoch_with_offset(subtract_10_seconds);
66 let mut strings: BTreeMap<String, String> = BTreeMap::new();
67 strings.insert("mit.relate.expires".into(), format!("{now_minus_10}"));
68 let vcs = InMemory::new(&mut strings);
69
70 let actual = get_relate_to_configuration(&vcs).expect("Failed to read VCS config");
71 let expected = None;
72 assert_eq!(
73 expected, actual,
74 "Expected the relate config to be {expected:?}, instead got {actual:?}"
75 );
76 }
77
78 #[test]
79 fn we_get_relate_to_config_back_if_there_is_any() {
80 let mut buffer = BTreeMap::new();
81 buffer.insert(
82 "mit.relate.expires".into(),
83 format!("{}", epoch_with_offset(add_10_seconds)),
84 );
85 buffer.insert("mit.relate.to".into(), "[#12345678]".into());
86 let vcs = InMemory::new(&mut buffer);
87
88 let actual = get_relate_to_configuration(&vcs).expect("Failed to read VCS config");
89 let expected = Some(RelateTo::from("[#12345678]"));
90
91 assert_eq!(
92 expected, actual,
93 "Expected the relate config to be {expected:?}, instead got {actual:?}"
94 );
95 }
96
97 fn add_10_seconds(x: Duration) -> Duration {
98 x.add(Duration::from_secs(10))
99 }
100
101 fn subtract_10_seconds(x: Duration) -> Duration {
102 x.checked_sub(Duration::from_secs(10)).unwrap()
103 }
104
105 const fn into_seconds(x: Duration) -> u64 {
106 x.as_secs()
107 }
108
109 fn epoch_with_offset(x: fn(Duration) -> Duration) -> i64 {
110 SystemTime::now()
111 .duration_since(UNIX_EPOCH)
112 .map(x)
113 .map(into_seconds)
114 .map(i64::try_from)
115 .expect("Failed to get Unix Epoch")
116 .expect("Convert epoch to int")
117 }
118}