Abbaye

at 44bfea6

use chrono::{DateTime, Utc};
use miette::{Result, bail};
use serde::{Deserialize, Serialize};

pub mod cargo;
pub mod git;

use cargo::{CargoVersion, CargoVersionConfig};
use git::{GitVersion, GitVersionConfig};

/// A version string paired with an optional release date.
///
/// Returned by [`VersionExtractor::get_last_version`] and
/// [`VersionExtractor::get_all_versions`] so that callers can propagate
/// date information (e.g. to Atom feed entries) without a second round-trip.
#[derive(Debug, Clone)]
pub struct VersionInfo {
    /// The human-readable version string (e.g. `"1.2.3"`).
    pub version: String,
    /// The UTC date/time at which this version was released, if known.
    pub date: Option<DateTime<Utc>>,
}

#[allow(async_fn_in_trait)]
pub trait VersionExtractor {
    type ConfigType: Default + for<'de> Deserialize<'de> + Clone;

    async fn get_last_version(&self, config: Self::ConfigType) -> Result<VersionInfo>;

    async fn get_all_versions(&self, _config: Self::ConfigType) -> Result<Vec<VersionInfo>> {
        bail!("get_all_versions is not supported by this version extractor")
    }
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AnyVersionExtractor {
    /// Reads the version from the `version` field in the `[package]` section
    /// of a `Cargo.toml` file.
    ///
    /// ```toml
    /// [version_extractor]
    /// type = "cargo"
    /// manifest_path = "Cargo.toml" # optional, defaults to ./Cargo.toml
    /// ```
    Cargo(CargoVersionConfig),

    /// Derives the version from the most recent Git tag using
    /// `git describe --tags --always`.
    /// Supports stripping a tag prefix (e.g. `"v"`) and customising the
    /// suffix appended when the working tree has uncommitted changes.
    ///
    /// ```toml
    /// [version_extractor]
    /// type = "git"
    /// tag_prefix = "v"      # optional, strips leading "v"
    /// dirty_suffix = "-dev" # optional, defaults to "-dirty"
    /// ```
    Git(GitVersionConfig),
}

impl AnyVersionExtractor {
    pub async fn extract(&self) -> Result<VersionInfo> {
        match self {
            Self::Cargo(config) => CargoVersion.get_last_version(config.clone()).await,
            Self::Git(config) => GitVersion.get_last_version(config.clone()).await,
        }
    }

    pub async fn extract_all(&self) -> Result<Vec<VersionInfo>> {
        match self {
            Self::Cargo(config) => CargoVersion.get_all_versions(config.clone()).await,
            Self::Git(config) => GitVersion.get_all_versions(config.clone()).await,
        }
    }
}