fundaia 0.52.2

Command line for the Fundaia deployment platform: projects, services, variables, deployments, logs and metrics
use anyhow::{bail, Result};
use owo_colors::OwoColorize;

use crate::changelog::{self, history, Release};
use crate::output::Format;
use crate::render::markdown;
use crate::render::theme;
use crate::render::time::relative_since;

pub struct Query {
    pub all: bool,
    pub version: Option<String>,
    pub since: Option<String>,
    pub count: Option<usize>,
}

pub fn show(query: &Query, format: Format) -> Result<()> {
    let releases = changelog::releases();
    let current = env!("CARGO_PKG_VERSION");

    let chosen = match (&query.version, &query.since, query.all) {
        (Some(version), _, _) => match changelog::only(releases, version) {
            Some(release) => vec![release],
            None => bail!("no hay notas de la versión {version} en este binario"),
        },
        (_, Some(floor), _) => changelog::since(releases, floor),
        (_, _, true) => releases,
        _ => changelog::running(releases, current).into_iter().collect(),
    };

    let chosen = match query.count {
        Some(count) => chosen.into_iter().take(count).collect(),
        None => chosen,
    };

    if format.answered_in_json(&chosen) {
        return Ok(());
    }

    if chosen.is_empty() {
        println!();
        println!("  {}", "No hay nada nuevo escrito.".style(theme::muted()));
        println!();
        return Ok(());
    }

    print(&chosen, current);
    Ok(())
}

pub fn show_history(format: Format) -> Result<()> {
    let seen = history::seen();

    if format.answered_in_json(&seen) {
        return Ok(());
    }

    println!();

    if seen.is_empty() {
        println!(
            "  {}",
            "Todavía no hay historial: se escribe la primera vez que cambia la versión."
                .style(theme::muted())
        );
        println!();
        return Ok(());
    }

    let current = env!("CARGO_PKG_VERSION");

    for entry in &seen {
        let when = if entry.at == 0 {
            "sin fecha".to_string()
        } else {
            relative_since(entry.at as i64 * 1_000)
        };

        let mark = if entry.version == current {
            format!(" {}", "· ahora".style(theme::success()))
        } else {
            String::new()
        };

        println!(
            "  {}  {}{}",
            entry.version.style(theme::strong()),
            when.style(theme::muted()),
            mark
        );
    }

    println!();
    Ok(())
}

fn print(releases: &[Release], current: &str) {
    for release in releases {
        println!();

        let date = match &release.date {
            Some(date) => format!("  {date}"),
            None => String::new(),
        };

        let mark = if release.version == current {
            format!("  {}", "· la que estás usando".style(theme::success()))
        } else {
            String::new()
        };

        println!(
            "  {}{}{}",
            format!("v{}", release.version).style(theme::accent()),
            date.style(theme::muted()),
            mark
        );
        println!();
        println!("{}", markdown::body(&release.body));
    }

    println!();
}