git-calver 24.1.1

carlendar versioning utility
Documentation
use chrono::prelude::Datelike;
use chrono::prelude::Local;
use chrono::DateTime;
use git2::Error;
use git2::Oid;
use git2::Repository;

use crate::calver::CalVer;
use crate::calver::ToCalVer;
use crate::repo_release::Release;
use crate::repo_release::RepositoryWithRelease;

pub struct Releaser<'a> {
    repo: &'a Repository,
}

impl<'a> Releaser<'a> {
    pub fn new(repo: &Repository) -> Releaser {
        Releaser { repo }
    }

    pub fn last_release(&self) -> Release {
        self.repo
            .find_latest_release()
            .unwrap_or_else(Release::zero)
    }

    pub fn next_version(&self) -> CalVer {
        self.next_version_of(self.last_release().version)
    }

    pub fn next_version_of(&self, current: CalVer) -> CalVer {
        let t: DateTime<Local> = Local::now();
        let date_ver = format!("{}.{}", t.year() % 100, t.month());
        let mut i = 0;
        loop {
            let v = format!("{}.{}", date_ver, i)
                .calver()
                .unwrap_or_else(|| CalVer::new(i));
            if v > current {
                return v;
            }
            i += 1;
        }
    }
    pub fn is_releasable(&self) -> bool {
        let last_id = self.last_release().commit_id;
        let head_commit = self
            .repo
            .head()
            .ok()
            .and_then(|head| head.peel_to_commit().ok());
        if let Some(commit) = head_commit {
            commit.id() != last_id || last_id == Oid::zero()
        } else {
            false
        }
    }

    pub fn bump(&self, message: &str, lightweught: bool) -> Result<CalVer, Error> {
        let v = self.next_version();
        self.bump_to(v, message, lightweught)
    }

    pub fn bump_to(
        &self,
        version: CalVer,
        message: &str,
        lightweught: bool,
    ) -> Result<CalVer, Error> {
        let result = if lightweught {
            self.repo.tag_lightweight(
                format!("{}", version).as_str(),
                self.repo.head()?.peel_to_commit()?.as_object(),
                false,
            )
        } else {
            self.repo.tag(
                format!("{}", version).as_str(),
                self.repo.head()?.peel_to_commit()?.as_object(),
                &self.repo.signature()?,
                message,
                false,
            )
        };
        match result {
            Ok(_) => Ok(version),
            Err(err) => Err(err),
        }
    }
}