nornir 0.5.1

Companion to cargo: dependency tracking, release gating, deploy, benchmarks, and documentation assembly. Project-agnostic.
//! Documentation assembly.
//!
//! nornir owns generated docs: README.md, CLAUDE.md, CHANGELOG.md.
//! Files (or sections) carrying the marker `<!-- nornir:generated -->`
//! are rewritten in full on each release from:
//!
//!  1. the per-repo TOML in `workspace_holger/release/`
//!  2. the latest [`BenchRun`]
//!  3. the bench history file
//!
//! Hand-written docs without the marker are only spot-checked by
//! [`assemble_and_check`] (version string + headline must match).

use std::path::Path;

use anyhow::{anyhow, Result};

use crate::bench::BenchRun;

pub const GENERATED_MARKER: &str = "<!-- nornir:generated -->";

pub mod sections;
pub use sections::{assemble_file, check_file, Ctx, FileReport};

pub mod test_inventory;
pub use test_inventory::{scan as scan_tests, scan_opts as scan_tests_opts, TestInventory};

pub mod hooks;
pub use hooks::{install_hooks, pre_commit_script, InstallReport};

pub mod layout;
pub use layout::{
    check_all as render_check_all, check_all_status, check_doc as render_check_doc, check_outcome,
    init_repo, render_all, render_doc, render_sources_in_place, DocCheckRow, DocsRenderCfg,
    RenderReport, RepoLayout, MANAGED_DOCS,
};

pub mod warehouse;
pub use warehouse::{
    history_outcome as history_export_outcome, list_doc_exports, list_doc_exports_async,
    record_doc_export, record_doc_export_async, DocExport, DocHistoryRow, ExportFilter,
};

pub mod search;
pub use search::{
    build_docs_index, discover_doc_files, docs_index_dir, restore_docs_index, search_docs,
    snapshot_docs_index,
};

pub mod pages;
pub use pages::{force_push_cmd, index_html, stage_pages_branch, PagesBuild, PAGES_BRANCH};

#[cfg(feature = "docs-export")]
pub mod export;
#[cfg(feature = "docs-export")]
pub use export::{export as export_bytes, export_repo, DocFormat, ExportMeta};

#[cfg(feature = "docs-export")]
pub mod svg;

#[cfg(feature = "docs-export")]
pub mod release_book;
#[cfg(feature = "docs-export")]
pub use release_book::{BookOptions, build_release_book, build_release_book_markdown};

#[cfg(feature = "docs-export")]
pub mod book;
#[cfg(feature = "docs-export")]
pub use book::{build_book, build_book_svg_pages, collect_chapters, resolve_version, Chapter};

/// Gate 7: docs are in sync with the run. For generated files, rewrite
/// and verify. For hand-written README.md (no marker), require that
/// `v<version>` appears in the file — but only when a bench run is available
/// to name the version. A repo with no recorded bench run (e.g. nornir itself,
/// which ships no `nornir-bench.rs`) still passes the gate via its generated
/// README; the bench run is not a docs-freshness prerequisite.
pub fn assemble_and_check(repo_root: &Path, run: Option<&BenchRun>) -> Result<()> {
    let readme = repo_root.join("README.md");
    let text = std::fs::read_to_string(&readme).unwrap_or_default();
    if text.contains(GENERATED_MARKER) {
        return Ok(());
    }
    // Hand-written README: assert the headline names the release version, but
    // only when a bench run gives us a version to look for. No run ⇒ nothing to
    // assert here (freshness of the prose is checked by `check_file` above).
    if let Some(run) = run {
        let needle = format!("v{}", run.version);
        if !text.contains(&needle) {
            return Err(anyhow!(
                "README.md does not mention {needle} — update headline before release"
            ));
        }
    }
    Ok(())
}