tally-todo 0.7.0

Make TODO management a little more automatic
use crate::models::{
    changes::{Log, Release},
    common::Priority,
};

/// Convert Changelog to markdown format
pub fn to_markdown(changelog: &Log) -> String {
    let mut output = String::new();

    output.push_str(&format!("# Changelog — {}\n\n", changelog.project_name));
    output.push_str(&format!(
        "*Generated on {}*\n\n",
        changelog.generated_at.format("%Y-%m-%d")
    ));

    for release in &changelog.releases {
        output.push_str(&release_to_markdown(release));
        output.push('\n');
    }

    output
}

fn release_to_markdown(release: &Release) -> String {
    let mut output = String::new();

    output.push_str(&format!(
        "## {}{}\n\n",
        release.version,
        release.date.format("%Y-%m-%d")
    ));

    for (priority, section_name) in [
        (Priority::High, "High Priority"),
        (Priority::Medium, "Changes"),
        (Priority::Low, "Minor Changes"),
    ] {
        if let Some(changes) = release.changes_by_priority.get(&priority)
            && !changes.is_empty()
        {
            output.push_str(&format!("### {}\n\n", section_name));

            for change in changes {
                let tags = if change.tags.is_empty() {
                    String::new()
                } else {
                    format!(" `{}`", change.tags.join("`, `"))
                };

                let commit = change
                    .commit
                    .as_ref()
                    .map(|c| format!(" ([`{}`])", &c[..7.min(c.len())]))
                    .unwrap_or_default();

                output.push_str(&format!("- {}{}{}\n", change.description, tags, commit));
            }

            output.push('\n');
        }
    }

    output
}

#[cfg(test)]
#[path = "../../../tests/services/serializers/changelog_serializer_tests.rs"]
mod tests;