panrelease 0.19.0

Utility to release software
Documentation
use std::marker::PhantomData;
use std::path::PathBuf;

use anyhow::anyhow;
use semver::Version;

use crate::package::PanPackage;
use crate::parser::FormatCodec;
use crate::parser::json::JsonString;
use crate::runner::CmdRunner;
use crate::system::FileSystem;

pub struct NpmPackage<F> {
    path: PathBuf,
    doc: JsonString,
    filesystem: PhantomData<F>
}

impl <F: FileSystem> NpmPackage<F> {
    pub fn new(path: PathBuf) -> anyhow::Result<Self> {
        let package_str = F::read_string(&path.join("package.json"))?;
        Ok(Self {
            path,
            doc: JsonString::new(&package_str),
            filesystem: PhantomData
        })
    }
}

impl <F: FileSystem> PanPackage for NpmPackage<F> {
    fn extract_version(&self) -> anyhow::Result<Version> {
        self.doc.extract("version")?
            .ok_or_else(|| anyhow!("Could not find version in package.json"))
            .and_then(|v| Ok(Version::parse(v)?))
    }

    fn set_version(&mut self, version: &Version) -> anyhow::Result<()> {
        self.doc.replace("version", &version.to_string())
    }

    fn persist(&self) -> anyhow::Result<()> {
        F::write_string(&self.path.join("package.json"), &self.doc.to_string())?;
        Ok(())
    }

    fn hook_after_rel(&self) -> anyhow::Result<()> {
        let mut runner = if F::is_a_file(&self.path.join("package-lock.json")) {
            CmdRunner::build("npm", &[
                String::from("i"),
                String::from("--package-lock-only"),
                String::from("--no-audit"),
                String::from("--no-fund")
            ], &self.path)?
        } else if F::is_a_file(&self.path.join("yarn.lock")) {
            CmdRunner::build("yarn", &[
                String::from("install"),
                String::from("--non-interactive"),
                String::from("--silent")
            ], &self.path)?
        } else if F::is_a_file(&self.path.join("pnpm-lock.yaml")) {
            CmdRunner::build("pnpm", &[
                String::from("install"),
                String::from("--lockfile-only")
            ], &self.path)?
        } else {
            anyhow::bail!("Cannot find any lockfile for package.json")
        };
        runner.run()?;
        Ok(())
    }
}