Skip to main content

abbaye/version_extractors/
mod.rs

1use chrono::{DateTime, Utc};
2use miette::{Result, bail};
3use serde::Deserialize;
4
5pub mod cargo;
6pub mod git;
7
8use cargo::{CargoVersion, CargoVersionConfig};
9use git::{GitVersion, GitVersionConfig};
10
11/// A version string paired with an optional release date.
12///
13/// Returned by [`VersionExtractor::get_last_version`] and
14/// [`VersionExtractor::get_all_versions`] so that callers can propagate
15/// date information (e.g. to Atom feed entries) without a second round-trip.
16#[derive(Debug, Clone)]
17pub struct VersionInfo {
18    /// The human-readable version string (e.g. `"1.2.3"`).
19    pub version: String,
20    /// The UTC date/time at which this version was released, if known.
21    pub date: Option<DateTime<Utc>>,
22}
23
24#[allow(async_fn_in_trait)]
25pub trait VersionExtractor {
26    type ConfigType: Default + for<'de> Deserialize<'de> + Clone;
27
28    async fn get_last_version(&self, config: Self::ConfigType) -> Result<VersionInfo>;
29
30    async fn get_all_versions(&self, _config: Self::ConfigType) -> Result<Vec<VersionInfo>> {
31        bail!("get_all_versions is not supported by this version extractor")
32    }
33}
34
35#[derive(Debug, Deserialize)]
36#[serde(tag = "type", rename_all = "snake_case")]
37pub enum AnyVersionExtractor {
38    /// Reads the version from the `version` field in the `[package]` section
39    /// of a `Cargo.toml` file.
40    ///
41    /// ```toml
42    /// [version_extractor]
43    /// type = "cargo"
44    /// manifest_path = "Cargo.toml" # optional, defaults to ./Cargo.toml
45    /// ```
46    Cargo(CargoVersionConfig),
47
48    /// Derives the version from the most recent Git tag using
49    /// `git describe --tags --always`.
50    /// Supports stripping a tag prefix (e.g. `"v"`) and customising the
51    /// suffix appended when the working tree has uncommitted changes.
52    ///
53    /// ```toml
54    /// [version_extractor]
55    /// type = "git"
56    /// tag_prefix = "v"      # optional, strips leading "v"
57    /// dirty_suffix = "-dev" # optional, defaults to "-dirty"
58    /// ```
59    Git(GitVersionConfig),
60}
61
62impl AnyVersionExtractor {
63    pub async fn extract(&self) -> Result<VersionInfo> {
64        match self {
65            Self::Cargo(config) => CargoVersion.get_last_version(config.clone()).await,
66            Self::Git(config) => GitVersion.get_last_version(config.clone()).await,
67        }
68    }
69
70    pub async fn extract_all(&self) -> Result<Vec<VersionInfo>> {
71        match self {
72            Self::Cargo(config) => CargoVersion.get_all_versions(config.clone()).await,
73            Self::Git(config) => GitVersion.get_all_versions(config.clone()).await,
74        }
75    }
76}