Версионирование

Анализ и инкремент строки с версией

semver-badge cat-config-badge

Пример строит semver::Version из строкового значения используя Version::parse, затем осуществляет инкремент номера патча, минорного и мажорного номера версии один за одним.

Заметим, что в соответствии со спецификацией Semantic Versioning Specification увеличение минорного номера версии сбрасывает счётчик патча на 0. Аналогично увеличение мажорного номера версии сбрасывает и минорный номер и номер патча на 0.

extern crate semver;

use semver::{Version, SemVerError};

fn main() -> Result<(), SemVerError> {
    let mut parsed_version = Version::parse("0.2.6")?;

    assert_eq!(
        parsed_version,
        Version {
            major: 0,
            minor: 2,
            patch: 6,
            pre: vec![],
            build: vec![],
        }
    );

    parsed_version.increment_patch();
    assert_eq!(parsed_version.to_string(), "0.2.7");
    println!("New patch release: v{}", parsed_version);

    parsed_version.increment_minor();
    assert_eq!(parsed_version.to_string(), "0.3.0");
    println!("New minor release: v{}", parsed_version);

    parsed_version.increment_major();
    assert_eq!(parsed_version.to_string(), "1.0.0");
    println!("New major release: v{}", parsed_version);

    Ok(())
}

Разбор строки содержащей сложную версию

semver-badge cat-config-badge

Строит semver::Version из строки используя Version::parse. Строка содержит номер предварительного релиза и метаданные сборки как определяется в спецификации Semantic Versioning Specification.

Заметим, что в соответствии со спецификации метаданные сборки анализируются, но не принимаются во внимание в процессе сравнения версий. Другими словами, две версии могут быть равны даже если их данные сборки различаются.

extern crate semver;

use semver::{Identifier, Version, SemVerError};

fn main() -> Result<(), SemVerError> {
    let version_str = "1.0.49-125+g72ee7853";
    let parsed_version = Version::parse(version_str)?;

    assert_eq!(
        parsed_version,
        Version {
            major: 1,
            minor: 0,
            patch: 49,
            pre: vec![Identifier::Numeric(125)],
            build: vec![],
        }
    );
    assert_eq!(
        parsed_version.build,
        vec![Identifier::AlphaNumeric(String::from("g72ee7853"))]
    );

    let serialized_version = parsed_version.to_string();
    assert_eq!(&serialized_version, version_str);

    Ok(())
}

Проверка того, является ли версия предварительным релизом

semver-badge cat-config-badge

Даны две версии, is_prerelease проверяет, что одна является предварительным релизом, а вторая - нет.

extern crate semver;

use semver::{Version, SemVerError};

fn main() -> Result<(), SemVerError> {
    let version_1 = Version::parse("1.0.0-alpha")?;
    let version_2 = Version::parse("1.0.0")?;

    assert!(version_1.is_prerelease());
    assert!(!version_2.is_prerelease());

    Ok(())
}

Нахождение самой последней версии из заданного диапазона

semver-badge cat-config-badge

Дан список версий в виде &str, найти самую последнюю версию semver::Version. Тип semver::VersionReq фильтрует список с помощью метода VersionReq::matches. Также демонстрируется semver настройки для предварительного релиза.

#[macro_use]
extern crate error_chain;
extern crate semver;

use semver::{Version, VersionReq};

error_chain! {
    foreign_links {
        SemVer(semver::SemVerError);
        SemVerReq(semver::ReqParseError);
    }
}

fn find_max_matching_version<'a, I>(version_req_str: &str, iterable: I) -> Result<Option<Version>>
where
    I: IntoIterator<Item = &'a str>,
{
    let vreq = VersionReq::parse(version_req_str)?;

    Ok(
        iterable
            .into_iter()
            .filter_map(|s| Version::parse(s).ok())
            .filter(|s| vreq.matches(s))
            .max(),
    )
}

fn main() -> Result<()> {
    assert_eq!(
        find_max_matching_version("<= 1.0.0", vec!["0.9.0", "1.0.0", "1.0.1"])?,
        Some(Version::parse("1.0.0")?)
    );

    assert_eq!(
        find_max_matching_version(
            ">1.2.3-alpha.3",
            vec![
                "1.2.3-alpha.3",
                "1.2.3-alpha.4",
                "1.2.3-alpha.10",
                "1.2.3-beta.4",
                "3.4.5-alpha.9",
            ]
        )?,
        Some(Version::parse("1.2.3-beta.4")?)
    );

    Ok(())
}

Проверка версии внешней команды на совместимость

semver-badge cat-text-processing-badge cat-os-badge

Код в рецепте выполняет git --version используя Command а затем анализирует номер версии и преобразует в semver::Version используя Version::parse. Метод VersionReq::matches сравнивает требуемую версию semver::VersionReq с только что полученной версией. Вывод программы напоминает результат "git version x.y.z".

#[macro_use]
extern crate error_chain;
extern crate semver;

use std::process::Command;
use semver::{Version, VersionReq};

error_chain! {
    foreign_links {
        Io(std::io::Error);
        Utf8(std::string::FromUtf8Error);
        SemVer(semver::SemVerError);
        SemVerReq(semver::ReqParseError);
    }
}

fn main() -> Result<()> {
    let version_constraint = "> 1.12.0";
    let version_test = VersionReq::parse(version_constraint)?;
    let output = Command::new("git").arg("--version").output()?;

    if !output.status.success() {
        bail!("Command executed with failing error code");
    }

    let stdout = String::from_utf8(output.stdout)?;
    let version = stdout.split(" ").last().ok_or_else(|| {
        "Invalid command output"
    })?;
    let parsed_version = Version::parse(version)?;

    if !version_test.matches(&parsed_version) {
        bail!("Command version lower than minimum supported version (found {}, need {})",
            parsed_version, version_constraint);
    }

    Ok(())
}