abbaye/version_extractors/
git.rs1use miette::{IntoDiagnostic, Result, miette};
2use serde::Deserialize;
3
4use super::VersionExtractor;
5
6fn default_dirty_suffix() -> String {
7 "-dirty".to_owned()
8}
9
10#[derive(Debug, Clone, Deserialize)]
12pub struct GitVersionConfig {
13 pub tag_prefix: Option<String>,
16
17 #[serde(default = "default_dirty_suffix")]
21 pub dirty_suffix: String,
22}
23
24impl Default for GitVersionConfig {
25 fn default() -> Self {
26 Self {
27 tag_prefix: None,
28 dirty_suffix: default_dirty_suffix(),
29 }
30 }
31}
32
33pub struct GitVersion;
35
36impl VersionExtractor for GitVersion {
37 type ConfigType = GitVersionConfig;
38
39 async fn get_last_version(&self, config: Self::ConfigType) -> Result<String> {
40 let dirty_arg = format!("--dirty={}", config.dirty_suffix);
41
42 let output = tokio::process::Command::new("git")
43 .args(["describe", "--tags", "--always", &dirty_arg])
44 .output()
45 .await
46 .into_diagnostic()?;
47
48 if !output.status.success() {
49 let stderr = String::from_utf8_lossy(&output.stderr);
50 return Err(miette!("git describe failed:\n{stderr}"));
51 }
52
53 let raw = String::from_utf8(output.stdout).into_diagnostic()?;
54 let version = raw.trim();
55
56 let version = match &config.tag_prefix {
57 Some(prefix) => version.strip_prefix(prefix.as_str()).unwrap_or(version),
58 None => version,
59 };
60
61 Ok(version.to_owned())
62 }
63
64 async fn get_all_versions(&self, config: Self::ConfigType) -> Result<Vec<String>> {
65 let output = tokio::process::Command::new("git")
66 .args(["tag", "--list", "--sort=version:refname"])
67 .output()
68 .await
69 .into_diagnostic()?;
70
71 if !output.status.success() {
72 let stderr = String::from_utf8_lossy(&output.stderr);
73 return Err(miette!("git tag failed:\n{stderr}"));
74 }
75
76 let raw = String::from_utf8(output.stdout).into_diagnostic()?;
77
78 let versions = raw
79 .lines()
80 .filter(|s| !s.is_empty())
81 .map(|tag| match &config.tag_prefix {
82 Some(prefix) => tag.strip_prefix(prefix.as_str()).unwrap_or(tag).to_owned(),
83 None => tag.to_owned(),
84 })
85 .collect();
86
87 Ok(versions)
88 }
89}