Sebastian Thielfix depreaction warning47264d44 years agoHistory
182 lines · 5.9 KB · Rust
RawDownload
use cargo_metadata::Package;use semver::{Prerelease, Version}; use crate::Context; #[derive(Copy, Clone)]pub enum BumpSpec {    Auto,    Keep,    Patch,    Minor,    Major,} impl std::fmt::Display for BumpSpec {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        f.write_str(match self {            BumpSpec::Auto => "auto",            BumpSpec::Keep => "no",            BumpSpec::Patch => "patch",            BumpSpec::Minor => "minor",            BumpSpec::Major => "major",        })    }} #[allow(clippy::ptr_arg)]pub(crate) fn select_publishee_bump_spec(name: &String, ctx: &Context) -> BumpSpec {    if ctx.crate_names.contains(name) {        ctx.bump    } else {        ctx.bump_dependencies    }} /// Returns true if this would be a breaking change for `v`.fn bump_major_minor_patch(v: &mut semver::Version, bump_spec: BumpSpec) -> bool {    use BumpSpec::*;    match bump_spec {        Major => {            v.major += 1;            v.minor = 0;            v.patch = 0;            v.pre = Prerelease::EMPTY;            true        }        Minor => {            v.minor += 1;            v.patch = 0;            v.pre = Prerelease::EMPTY;            is_pre_release(v)        }        Patch => {            v.patch += 1;            v.pre = Prerelease::EMPTY;            false        }        Keep | Auto => unreachable!("BUG: auto mode or keep are unsupported"),    }} #[derive(Clone, Debug)]pub struct Bump {    pub next_release: semver::Version,    pub package_version: semver::Version,    pub latest_release: Option<semver::Version>,    pub desired_release: semver::Version,} impl Bump {    pub(crate) fn next_release_changes_manifest(&self) -> bool {        self.next_release > self.package_version    }    pub(crate) fn is_breaking(&self) -> bool {        rhs_is_breaking_bump_for_lhs(&self.package_version, &self.next_release)    }} pub(crate) fn bump_package_with_spec(    package: &Package,    bump_spec: BumpSpec,    ctx: &Context,    bump_when_needed: bool,) -> anyhow::Result<Bump> {    let mut v = package.version.clone();    use BumpSpec::*;    let package_version_must_be_breaking = match bump_spec {        Major | Minor | Patch => bump_major_minor_patch(&mut v, bump_spec),        Keep => false,        Auto => {            let segments = crate::git::history::crate_ref_segments(                package,                ctx,                ctx.history.as_ref().expect("BUG: assure history is set here"),                crate::git::history::SegmentScope::Unreleased,            )?;            assert_eq!(                segments.len(),                1,                "there should be exactly one section, the 'unreleased' one"            );            let unreleased = &segments[0];            if unreleased.history.is_empty() {                false            } else if unreleased.history.iter().any(|item| item.message.breaking) {                let is_breaking = if is_pre_release(&v) {                    bump_major_minor_patch(&mut v, Minor)                } else {                    bump_major_minor_patch(&mut v, Major)                };                assert!(is_breaking, "BUG: breaking changes are…breaking :D");                is_breaking            } else if unreleased                .history                .iter()                .any(|item| item.message.kind.map(|kind| kind == "feat").unwrap_or(false))            {                let is_breaking = if is_pre_release(&v) {                    bump_major_minor_patch(&mut v, Patch)                } else {                    bump_major_minor_patch(&mut v, Minor)                };                assert!(!is_breaking, "BUG: new features are never breaking");                is_breaking            } else {                let is_breaking = bump_major_minor_patch(&mut v, Patch);                assert!(!is_breaking, "BUG: patch releases are never breaking");                false            }        }    };    let desired_release = v;    let (latest_release, next_release) = match ctx.crates_index.crate_(&package.name) {        Some(published_crate) => {            let latest_release = semver::Version::parse(published_crate.most_recent_version().version())                .expect("valid version in crate index");            let next_release = if latest_release >= desired_release {                desired_release.clone()            } else {                let mut next_release = desired_release.clone();                if bump_when_needed && package.version > latest_release && desired_release != package.version {                    if package_version_must_be_breaking {                        if rhs_is_breaking_bump_for_lhs(&latest_release, &package.version) {                            next_release = package.version.clone();                        }                    } else {                        next_release = package.version.clone();                    };                }                next_release            };            (Some(latest_release), next_release)        }        None => (            None,            if bump_when_needed {                package.version.clone()            } else {                desired_release.clone()            },        ),    };    Ok(Bump {        next_release,        package_version: package.version.clone(),        desired_release,        latest_release,    })} pub(crate) fn bump_package(package: &Package, ctx: &Context, bump_when_needed: bool) -> anyhow::Result<Bump> {    let bump_spec = select_publishee_bump_spec(&package.name, ctx);    bump_package_with_spec(package, bump_spec, ctx, bump_when_needed)} pub(crate) fn is_pre_release(semver: &Version) -> bool {    crate::utils::is_pre_release_version(semver)} pub(crate) fn rhs_is_breaking_bump_for_lhs(lhs: &Version, rhs: &Version) -> bool {    rhs.major > lhs.major || rhs.minor > lhs.minor}