1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// This file 'git.rs' is part of the 'hisho' project.
//
// Copyright 2023 Thomas Obernosterer (https://atjon.tv).
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use gix::date::time::format::ISO8601_STRICT;
use std::collections::HashMap;
use std::path::Path;

/// Fetch git repository metadata for a given path
///
/// If the given path is not a git repository, all the keys will be empty strings.
///
/// # Arguments
///
/// * `dir` - The path to the git repository
///
/// # Returns
///
/// A hash map containing the following keys:
/// * `commit_sha` - The long hash of the newest commit
/// * `commit_sha_short` - The short hash of the newest commit
/// * `commit_date` - The date of the newest commit
/// * `commit_author_name` - The name of the author of the newest commit
/// * `commit_author_email` - The email of the author of the newest commit
/// * `commit_committer_name` - The name of the committer of the newest commit
/// * `commit_committer_email` - The email of the committer of the newest commit
/// * `branch` - The current branch of the repository
pub fn fetch_repo_vars(dir: &Path) -> HashMap<String, String> {
    let mut result: HashMap<String, String> = HashMap::new();

    // initialize variables as empty to prevent template errors outside of git repositories
    // TODO: Should we not do this so it errors outside of a git repository?
    result.insert("commit_sha".to_string(), String::new());
    result.insert("commit_sha_short".to_string(), String::new());
    result.insert("commit_date".to_string(), String::new());
    result.insert("commit_author_name".to_string(), String::new());
    result.insert("commit_author_email".to_string(), String::new());
    result.insert("commit_committer_name".to_string(), String::new());
    result.insert("commit_committer_email".to_string(), String::new());
    result.insert("branch".to_string(), String::new());
    if let Ok(repo) = gix::discover(dir) {
        if let Ok(head) = repo.head() {
            if head.is_detached() {
                result.insert("branch".to_string(), "none".to_string());
            }
            if let Some(head_id) = head.id() {
                let long_sha = head_id.to_hex();
                result.insert("commit_sha".to_string(), long_sha.to_string());
                if let Ok(short_sha) = head_id.shorten() {
                    result.insert("commit_sha_short".to_string(), short_sha.to_string());
                    result.insert("branch".to_string(), short_sha.to_string());
                }
                if let Ok(head_obj) = head_id.object() {
                    if let Ok(commit) = head_obj.try_into_commit() {
                        if let Ok(commit_time) = commit.time() {
                            result.insert(
                                "commit_date".to_string(),
                                commit_time.format(ISO8601_STRICT),
                            );
                        }
                        if let Ok(commit_author) = commit.author() {
                            result.insert(
                                "commit_author_name".to_string(),
                                commit_author.name.to_string(),
                            );
                            result.insert(
                                "commit_author_email".to_string(),
                                commit_author.email.to_string(),
                            );
                        }
                        if let Ok(commit_committer) = commit.committer() {
                            result.insert(
                                "commit_committer_name".to_string(),
                                commit_committer.name.to_string(),
                            );
                            result.insert(
                                "commit_committer_email".to_string(),
                                commit_committer.email.to_string(),
                            );
                        }
                    }
                }
            }
        }
        if let Ok(Some(head_ref)) = repo.head_name() {
            result.insert("branch".to_string(), head_ref.shorten().to_string());
        }
    }
    result
}