at bd5ed90
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, Clone, 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, } } /// Returns the full VCS tag name for the given version string. /// /// For Git extractors this re-applies the configured `tag_prefix` (e.g. /// `"v"` → `"v1.2.3"`). For other extractors the version is returned /// unchanged. pub fn tag_name(&self, version: &str) -> String { match self { Self::Git(config) => match &config.tag_prefix { Some(prefix) => format!("{prefix}{version}"), None => version.to_owned(), }, Self::Cargo(_) => version.to_owned(), } } }