holochain_release_util 0.1.3

Utility crate for Holochain release management
Documentation
use crate::utils::get_version_from_cliff_output;
use anyhow::Context;
use std::path::Path;

pub(crate) fn generate_changelog(
    dir: impl AsRef<Path>,
    cliff_config: &str,
    force_tag: &Option<String>,
) -> anyhow::Result<()> {
    println!("Generating changelog");

    let mut command = common_git_cliff_command(&dir, cliff_config, force_tag);

    command.arg("--unreleased");

    if !dir.as_ref().join("CHANGELOG.md").exists() {
        println!("Changelog does not exist, creating a new one.");
        command.arg("--output");
    } else {
        println!("Changelog already exists, prepending new changes.");
        command.arg("--prepend").arg("CHANGELOG.md");
    }

    if let Some(tag) = force_tag {
        println!("Forcing tag: {}", tag);
        command.arg("--tag").arg(tag);
    } else {
        command.arg("--bump");
    }

    let status = command.status().context("git-cliff failed to run")?;

    if !status.success() {
        anyhow::bail!("git-cliff command failed with status: {}", status);
    }

    Ok(())
}

pub(crate) fn get_next_version(
    dir: impl AsRef<Path>,
    cliff_config: &str,
    force_tag: &Option<String>,
) -> anyhow::Result<String> {
    println!("Retrieving next version");

    let mut command = common_git_cliff_command(&dir, cliff_config, force_tag);

    command
        .arg("--unreleased")
        .arg("--bump")
        .arg("--context")
        .stdout(std::process::Stdio::piped());

    if let Some(tag) = force_tag {
        command.arg("--tag").arg(tag);
    }

    let output = command.output().context("git-cliff failed to run")?;

    get_version_from_cliff_output(&output.stdout)
}

pub(crate) fn set_version(dir: impl AsRef<Path>, version: &str) -> anyhow::Result<()> {
    let version = version.trim_start_matches('v');
    println!("Setting version to {}", version);

    let mut command = std::process::Command::new("cargo");

    command
        .current_dir(dir)
        .stdout(std::process::Stdio::inherit())
        .stderr(std::process::Stdio::inherit())
        .arg("workspaces")
        .arg("version")
        .arg("--no-git-commit")
        .arg("--yes")
        .arg("custom")
        .arg(version)
        .arg("--force")
        .arg("*");

    let status = command
        .status()
        .context("Failed to run cargo workspaces version")?;

    if !status.success() {
        anyhow::bail!(
            "cargo workspaces version command failed with status: {}",
            status
        );
    }

    Ok(())
}

pub(crate) fn get_released_version_tag(
    dir: impl AsRef<Path>,
    cliff_config: &str,
    force_tag: &Option<String>,
) -> anyhow::Result<String> {
    println!("Retrieving released version tag");

    let mut command = common_git_cliff_command(&dir, cliff_config, force_tag);

    command
        .arg("--latest")
        .arg("--context")
        .stdout(std::process::Stdio::piped());

    let output = command.output().context("git-cliff failed to run")?;

    get_version_from_cliff_output(&output.stdout)
}

pub(crate) fn run_semver_checks(
    dir: impl AsRef<Path>,
    against_revision: &str,
    i_am_so_sorry_but_my_features_clash: bool,
) -> anyhow::Result<()> {
    let mut command = std::process::Command::new("cargo");
    command
        .current_dir(&dir)
        .arg("semver-checks")
        .arg("--workspace")
        .arg("--baseline-rev")
        .arg(against_revision)
        .stdout(std::process::Stdio::inherit())
        .stderr(std::process::Stdio::inherit());

    if i_am_so_sorry_but_my_features_clash {
        command.arg("--default-features");
    }

    let status = command
        .status()
        .context("Failed to run cargo semver-checks")?;

    if !status.success() {
        anyhow::bail!("cargo semver-checks command failed with status: {}", status);
    }

    Ok(())
}

fn common_git_cliff_command(
    dir: impl AsRef<Path>,
    cliff_config: &str,
    force_tag: &Option<String>,
) -> std::process::Command {
    let mut command = std::process::Command::new("git-cliff");

    command
        .current_dir(dir)
        .stderr(std::process::Stdio::inherit())
        .stdout(std::process::Stdio::inherit())
        .arg("--use-branch-tags");

    if url::Url::parse(cliff_config).is_ok() {
        command.arg("--config-url").arg(cliff_config);
    } else {
        command.arg("--config").arg(cliff_config);
    }

    if force_tag.as_ref().is_some_and(|tag| !(tag.contains("-dev") || tag.contains("-rc"))) {
        command.arg("--tag-pattern").arg("^v\\d+.\\d+.\\d+$");
    } else {
        command.arg("--tag-pattern").arg("^v\\d+.\\d+.\\d+");
    }

    command
}