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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
pub use git_version::git_version;
use metrics::gauge;
use semver::Version;

/// Returns latest commit short hash.
pub fn git_rev() -> &'static str {
    env!("VERGEN_SHA_SHORT")
}

/// Returns current date in YYYY-MM-DD format.
pub fn build_date() -> &'static str {
    env!("VERGEN_BUILD_DATE")
}

/// Returns Github Actions build string if available or None.
pub fn build_number_str() -> Option<&'static str> {
    option_env!("GITHUB_RUN_NUMBER")
}

/// Returns Github Actions build number if available or None.
pub fn build_number() -> Option<i64> {
    build_number_str().and_then(|s| s.parse().ok())
}

/// Converts a tag to semantic version
pub fn tag2semver(tag: &str) -> &str {
    let mut version = tag;
    for prefix in ["pre-rel-", "v"].iter() {
        if version.starts_with(prefix) {
            version = &version[prefix.len()..];
        }
    }
    version
}

pub fn report_version_to_metrics() {
    if let Ok(version) = Version::parse(semver_str!()) {
        gauge!("yagna.version.major", version.major as i64);
        gauge!("yagna.version.minor", version.minor as i64);
        gauge!("yagna.version.patch", version.patch as i64);
        gauge!(
            "yagna.version.is_prerelease",
            (!version.pre.is_empty()) as i64
        );
        if let Some(build_number) = build_number() {
            gauge!("yagna.version.build_number", build_number);
        }
    }
}

/// Returns latest version tag
#[macro_export]
macro_rules! git_tag {
    () => {
        $crate::git_version!(
            args = [
                "--tag",
                "--abbrev=0",
                "--match=v[0-9]*",
                "--match=pre-rel-v[0-9]*"
            ],
            cargo_prefix = ""
        )
    };
}

/// Returns a semantic version string of the crate
#[macro_export]
macro_rules! semver_str {
    () => {
        $crate::tag2semver($crate::git_tag!())
    };
}

#[macro_export]
macro_rules! version_describe {
    () => {
        Box::leak(
            [
                $crate::semver_str!(),
                " (",
                $crate::git_rev(),
                " ",
                &$crate::build_date(),
                &$crate::build_number_str()
                    .map(|n| format!(" build #{}", n))
                    .unwrap_or("".to_string()),
                ")",
            ]
            .join("")
            .into_boxed_str(),
        ) as &str
    };
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_git_tag() {
        println!("git tag: {:?}", git_tag!());
    }

    #[test]
    fn test_git_rev() {
        println!("git rev: {:?}", git_rev());
    }

    #[test]
    fn test_semver() {
        println!("semver: {:?}", Version::parse(semver_str!()));
    }

    #[test]
    fn test_build_number() {
        println!("build: {:?}", build_number());
    }
}