cuddle-please-frontend 0.1.0

A release-please inspired release manager tool, built on top of cuddle, but also useful standalone, cuddle-please supports, your ci of choice, as well as gitea, github
Documentation
use std::path::PathBuf;

use serde::{Deserialize, Serialize};

use crate::{PleaseConfig, PleaseProjectConfig, PleaseSettingsConfig};

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PleaseProjectConfigBuilder {
    pub owner: Option<String>,
    pub repository: Option<String>,
    pub source: Option<PathBuf>,
    pub branch: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PleaseSettingsConfigBuilder {
    pub api_url: Option<String>,
    pub git_username: Option<String>,
    pub git_email: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PleaseConfigBuilder {
    pub project: Option<PleaseProjectConfigBuilder>,
    pub settings: Option<PleaseSettingsConfigBuilder>,
}

impl PleaseConfigBuilder {
    pub fn merge(&mut self, config: &PleaseConfigBuilder) -> &Self {
        let config = config.clone();
        let mut fproject = match self.project.clone() {
            None => PleaseProjectConfigBuilder::default(),
            Some(project) => project,
        };
        let mut fsettings = match self.settings.clone() {
            None => PleaseSettingsConfigBuilder::default(),
            Some(settings) => settings,
        };

        if let Some(project) = config.project {
            if let Some(owner) = project.owner {
                fproject.owner = Some(owner);
            }
            if let Some(repository) = project.repository {
                fproject.repository = Some(repository);
            }
            if let Some(source) = project.source {
                fproject.source = Some(source);
            }
            if let Some(branch) = project.branch {
                fproject.branch = Some(branch);
            }
            self.project = Some(fproject);
        }

        if let Some(settings) = config.settings {
            if let Some(api_url) = settings.api_url {
                fsettings.api_url = Some(api_url);
            }

            if let Some(git_username) = settings.git_username {
                fsettings.git_username = Some(git_username);
            }
            if let Some(git_email) = settings.git_email {
                fsettings.git_email = Some(git_email);
            }

            self.settings = Some(fsettings);
        }

        self
    }
}

impl TryFrom<PleaseConfigBuilder> for PleaseConfig {
    type Error = anyhow::Error;

    fn try_from(value: PleaseConfigBuilder) -> Result<Self, Self::Error> {
        Ok(Self {
            project: value
                .project
                .ok_or(value_is_missing("project"))?
                .try_into()?,
            settings: value
                .settings
                .ok_or(value_is_missing("settings"))?
                .try_into()?,
        })
    }
}

impl TryFrom<PleaseProjectConfigBuilder> for PleaseProjectConfig {
    type Error = anyhow::Error;

    fn try_from(value: PleaseProjectConfigBuilder) -> Result<Self, Self::Error> {
        Ok(Self {
            owner: value.owner.ok_or(value_is_missing("owner"))?,
            repository: value.repository.ok_or(value_is_missing("repository"))?,
            source: value.source.ok_or(value_is_missing("source"))?,
            branch: value.branch.ok_or(value_is_missing("branch"))?,
        })
    }
}

impl TryFrom<PleaseSettingsConfigBuilder> for PleaseSettingsConfig {
    type Error = anyhow::Error;

    fn try_from(value: PleaseSettingsConfigBuilder) -> Result<Self, Self::Error> {
        Ok(Self {
            api_url: value.api_url.ok_or(value_is_missing("api_url"))?,
            git_username: value.git_username.clone(),
            git_email: value.git_username.clone(),
        })
    }
}

fn value_is_missing(message: &str) -> anyhow::Error {
    anyhow::anyhow!(
        "{} is required, pass via. cli, env or config file, see --help",
        message.to_string()
    )
}