provenance-cli 0.2.1

Command-line interface for Provenance requirements traceability
use crate::cli::knowledge::{FogCommand, RequirementsCommand, SourceRefCommand};
use crate::output;
use provenance_core::{RequirementStatus, ScopeId, StableId};
use provenance_store::{
    layout::ProvenanceLayout,
    state_store::{AddSourceReferenceInput, CreateRequirementInput, StateStore},
};

#[derive(serde::Serialize)]
struct FogView {
    requirement_id: String,
    fog: Option<String>,
}

pub(super) fn handle(command: RequirementsCommand) -> anyhow::Result<()> {
    match command {
        RequirementsCommand::Create {
            repo,
            scope,
            id,
            statement,
            description,
            status,
            domain_id,
            origin_thread,
            origin_message,
            format,
        } => {
            let requirement = StateStore::new(ProvenanceLayout::new(repo)).create_requirement(
                CreateRequirementInput {
                    scope_id: ScopeId::new(scope)?,
                    id: StableId::new(id)?,
                    statement,
                    description,
                    status: RequirementStatus::parse(&status)?,
                    domain_id: domain_id.map(StableId::new).transpose()?,
                    origin_thread: origin_thread.map(StableId::new).transpose()?,
                    origin_message: origin_message.map(StableId::new).transpose()?,
                },
            )?;
            output::print(format, &requirement)?;
        }
        RequirementsCommand::SourceRef { command } => match command {
            SourceRefCommand::Add {
                repo,
                scope,
                requirement_id,
                source_id,
                clause,
                format,
            } => {
                let edge = StateStore::new(ProvenanceLayout::new(repo)).add_source_reference(
                    AddSourceReferenceInput {
                        scope_id: ScopeId::new(scope)?,
                        source_id: StableId::new(source_id)?,
                        requirement_id: StableId::new(requirement_id)?,
                        clause,
                    },
                )?;
                output::print(format, &edge)?;
            }
        },
        RequirementsCommand::Fog { command } => match command {
            FogCommand::Set {
                repo,
                scope,
                requirement_id,
                text,
                format,
            } => {
                let requirement = StateStore::new(ProvenanceLayout::new(repo))
                    .set_requirement_fog(
                        &ScopeId::new(scope)?,
                        &StableId::new(requirement_id)?,
                        Some(text),
                    )?;
                output::print(format, &requirement)?;
            }
            FogCommand::Show {
                repo,
                scope,
                requirement_id,
                format,
            } => {
                let requirement_id = StableId::new(requirement_id)?;
                let requirement = StateStore::new(ProvenanceLayout::new(repo))
                    .list_requirements(&ScopeId::new(scope)?)?
                    .into_iter()
                    .find(|requirement| requirement.id == requirement_id)
                    .ok_or_else(|| anyhow::anyhow!("requirement does not exist"))?;
                output::print(
                    format,
                    &FogView {
                        requirement_id: requirement.id.as_str().to_string(),
                        fog: requirement.fog,
                    },
                )?;
            }
            FogCommand::Clear {
                repo,
                scope,
                requirement_id,
                format,
            } => {
                let requirement = StateStore::new(ProvenanceLayout::new(repo))
                    .set_requirement_fog(
                        &ScopeId::new(scope)?,
                        &StableId::new(requirement_id)?,
                        None,
                    )?;
                output::print(format, &requirement)?;
            }
        },
    }
    Ok(())
}