tix-tracker 0.12.0

A terminal issue tracker: markdown + YAML frontmatter issues with a kanban TUI and CLI
Documentation
#[allow(clippy::wildcard_imports)]
use super::*;

/// A refusal with one reason.
pub(super) fn refused(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: Option<GeneratedCycleId>,
    kind: LifecycleDiagnosticKind,
    field: impl Into<String>,
    message: impl Into<String>,
) -> LifecycleOutcome {
    LifecycleOutcome::Rejected {
        action,
        schedule_id,
        cycle_id,
        diagnostics: vec![LifecycleDiagnostic::new(kind, field, message)],
    }
}

/// A `no-op` with its reason.
pub(super) fn no_op(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: Option<GeneratedCycleId>,
    message: impl Into<String>,
) -> LifecycleOutcome {
    LifecycleOutcome::NoOp {
        action,
        schedule_id,
        cycle_id,
        message: message.into(),
    }
}

/// A refusal for an action that must name an instance but named none.
pub(super) fn missing_cycle(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    verb: &str,
) -> LifecycleOutcome {
    refused(
        action,
        schedule_id.clone(),
        None,
        LifecycleDiagnosticKind::MissingCycle,
        format!("cycle_schedules.{schedule_id}.cycle_id"),
        format!("{verb} names the instance to act on; none was given"),
    )
}

/// A refusal for an instance the request did not name.
pub(super) fn not_owned(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: GeneratedCycleId,
) -> LifecycleOutcome {
    let field = format!("cycles.{cycle_id}");
    let message = format!(
        "cycle id `{cycle_id}` belongs to schedule `{}`, not `{schedule_id}`",
        cycle_id.schedule_id()
    );
    refused(
        action,
        schedule_id,
        Some(cycle_id),
        LifecycleDiagnosticKind::CycleNotOwned,
        field,
        message,
    )
}

/// A refusal for an instance that does not exist.
pub(super) fn unknown_cycle(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: GeneratedCycleId,
) -> LifecycleOutcome {
    refused(
        action,
        schedule_id,
        Some(cycle_id.clone()),
        LifecycleDiagnosticKind::UnknownCycle,
        format!("cycles.{cycle_id}"),
        format!("generated cycle `{cycle_id}` does not exist"),
    )
}

/// A refusal for a schedule with no cadence family.
pub(super) fn missing_cadence(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: Option<GeneratedCycleId>,
) -> LifecycleOutcome {
    refused(
        action,
        schedule_id.clone(),
        cycle_id,
        LifecycleDiagnosticKind::MissingCadence,
        format!("cycle_schedules.{schedule_id}.cadence.kind"),
        format!("schedule `{schedule_id}` names no cadence family"),
    )
}

/// A refusal for a cadence the shared validator rejects.
pub(super) fn invalid_cadence(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: Option<GeneratedCycleId>,
    error: &crate::recurrence::rule::RuleError,
    request: &LifecycleRequest,
) -> LifecycleOutcome {
    refused(
        action,
        schedule_id,
        cycle_id,
        LifecycleDiagnosticKind::InvalidCadence,
        format!("cycle_schedules.{}.cadence", request.schedule_id),
        error.first().message.clone(),
    )
}

/// A refusal for a date the shared rule could not resolve.
pub(super) fn unresolvable(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: Option<GeneratedCycleId>,
) -> LifecycleOutcome {
    refused(
        action,
        schedule_id.clone(),
        cycle_id,
        LifecycleDiagnosticKind::UnresolvableDate,
        format!("cycle_schedules.{schedule_id}.cadence"),
        format!(
            "schedule `{schedule_id}` could not resolve a candidate date for the sequence through \
             its cadence"
        ),
    )
}

/// A refusal when the configuration could not be persisted, naming any rollback that
/// itself failed.
pub(super) fn refused_rollback(
    action: LifecycleAction,
    schedule_id: CycleScheduleId,
    cycle_id: Option<GeneratedCycleId>,
    config_path: &str,
    error: &TixError,
    rollback_failure: Option<String>,
) -> LifecycleOutcome {
    let message = match rollback_failure {
        None => format!(
            "the configuration could not be persisted through `{config_path}`: {error}; the record \
             writes were rolled back, so the project is exactly as it was"
        ),
        Some(failure) => format!(
            "the configuration could not be persisted through `{config_path}`: {error}; rolling \
             back a record also failed ({failure}), so a re-run may be needed"
        ),
    };
    refused(
        action,
        schedule_id,
        cycle_id,
        LifecycleDiagnosticKind::ConfigNotPersisted,
        config_path,
        message,
    )
}