diary/ops/
commit.rs

1use chrono::prelude::*;
2use git2::Repository;
3use pathdiff;
4
5use crate::{errors::DiaryError, utils::git, Diary};
6pub struct CommitOptions {
7    /// The date of the entry to open.
8    pub entry_date: DateTime<Local>,
9    pub message: String,
10    pub push: bool,
11}
12
13pub fn commit(opts: &CommitOptions, diary: &Diary) -> Result<(), DiaryError> {
14    let entry_path = diary.get_entry_path(&opts.entry_date);
15    let relative_path = pathdiff::diff_paths(entry_path, diary.diary_path()).unwrap();
16
17    let repo = Repository::open(diary.diary_path())?;
18
19    git::add_and_commit(&repo, &relative_path, &opts.message)?;
20
21    if opts.push {
22        git::push_to_origin(&repo)?;
23    }
24    Ok(())
25}
26
27#[cfg(test)]
28mod test {
29    use chrono::prelude::*;
30    use git2::Repository;
31
32    use super::{commit, CommitOptions};
33    use crate::{
34        ops::{init, testing, InitOptions},
35        utils::git,
36        Diary,
37    };
38
39    #[test]
40    fn commit_today() {
41        let config = testing::temp_config();
42
43        let init_opts = InitOptions {
44            path: testing::temp_path(),
45            prefix: None,
46            git_repo: true,
47        };
48        init(&init_opts, config.diary_path()).unwrap();
49
50        let entry_date = Local.with_ymd_and_hms(2022, 1, 13, 0, 0, 0).unwrap();
51        testing::new_entry(&config, &entry_date);
52
53        let opts = CommitOptions {
54            entry_date,
55            message: "Test message".to_string(),
56            push: false,
57        };
58        let repo = Repository::open(config.diary_path()).unwrap();
59
60        let diary = Diary::from_config(&config).unwrap();
61        commit(&opts, &diary).unwrap();
62
63        let last_commit = git::find_last_commit(&repo).unwrap();
64        commit(&opts, &diary).unwrap();
65        assert!(last_commit.is_some());
66
67        let index = repo.index().unwrap();
68        assert_eq!(index.len(), 1)
69    }
70
71    #[test]
72    fn commit_multiple() {
73        let config = testing::temp_config();
74
75        let init_opts = InitOptions {
76            path: testing::temp_path(),
77            prefix: None,
78            git_repo: true,
79        };
80        init(&init_opts, config.diary_path()).unwrap();
81
82        let entry_date = Local.with_ymd_and_hms(2022, 1, 13, 0, 0, 0).unwrap();
83        testing::new_entry(&config, &entry_date);
84
85        let opts = CommitOptions {
86            entry_date,
87            message: "Test message".to_string(),
88            push: false,
89        };
90        let repo = Repository::open(config.diary_path()).unwrap();
91
92        let diary = Diary::from_config(&config).unwrap();
93        commit(&opts, &diary).unwrap();
94
95        let last_commit = git::find_last_commit(&repo).unwrap();
96        assert!(last_commit.is_some());
97
98        let entry_date = Local.with_ymd_and_hms(2022, 1, 14, 0, 0, 0).unwrap();
99        testing::new_entry(&config, &entry_date);
100
101        let opts = CommitOptions {
102            entry_date,
103            message: "Test message".to_string(),
104            push: false,
105        };
106        let repo = Repository::open(config.diary_path()).unwrap();
107
108        commit(&opts, &diary).unwrap();
109
110        let last_commit = git::find_last_commit(&repo).unwrap();
111        assert!(last_commit.is_some());
112
113        let index = repo.index().unwrap();
114        assert_eq!(index.len(), 2)
115    }
116
117    #[test]
118    #[should_panic(expected = "No such file or directory")]
119    fn commit_no_entry() {
120        let config = testing::temp_config();
121
122        let init_opts = InitOptions {
123            path: testing::temp_path(),
124            prefix: None,
125            git_repo: true,
126        };
127        init(&init_opts, config.diary_path()).unwrap();
128
129        let entry_date = Local.with_ymd_and_hms(2022, 1, 13, 0, 0, 0).unwrap();
130
131        let opts = CommitOptions {
132            entry_date,
133            message: "Test message".to_string(),
134            push: false,
135        };
136
137        let diary = Diary::from_config(&config).unwrap();
138        commit(&opts, &diary).unwrap();
139    }
140
141    #[test]
142    #[should_panic(expected = "remote 'origin' does not exist")]
143    fn commit_and_fail_to_push() {
144        let config = testing::temp_config();
145
146        let init_opts = InitOptions {
147            path: testing::temp_path(),
148            prefix: None,
149            git_repo: true,
150        };
151        init(&init_opts, config.diary_path()).unwrap();
152
153        let entry_date = Local.with_ymd_and_hms(2022, 1, 13, 0, 0, 0).unwrap();
154
155        testing::new_entry(&config, &entry_date);
156
157        let opts = CommitOptions {
158            entry_date,
159            message: "Test message".to_string(),
160            push: true,
161        };
162
163        let diary = Diary::from_config(&config).unwrap();
164        commit(&opts, &diary).unwrap();
165    }
166}