greentic-bundle 0.5.6

Greentic bundle authoring CLI scaffold with embedded i18n and answer-document contracts.
Documentation
use std::path::Path;
use std::time::{Duration, Instant};

use anyhow::Result;
use greentic_bundle::catalog::client::{CatalogArtifactClient, FetchedCatalog};
use greentic_bundle::catalog::resolve::{CatalogResolveOptions, resolve_catalogs_with_client};
use tempfile::TempDir;

#[derive(Debug)]
struct StaticClient {
    bytes: Vec<u8>,
}

impl CatalogArtifactClient for StaticClient {
    fn fetch_catalog(&self, _root: &Path, reference: &str) -> Result<FetchedCatalog> {
        Ok(FetchedCatalog {
            resolved_ref: reference.to_string(),
            digest: "sha256:timeout".to_string(),
            bytes: self.bytes.clone(),
        })
    }
}

#[test]
fn catalog_resolution_finishes_within_expected_bound() {
    let temp = TempDir::new().expect("tempdir");
    let root = temp.path().join("bundle");
    std::fs::create_dir_all(&root).expect("mkdir");
    let client = StaticClient {
        bytes: build_catalog(400).into_bytes(),
    };

    let start = Instant::now();
    let resolved = resolve_catalogs_with_client(
        &root,
        &["oci://example/catalogs/demo:1".to_string()],
        &CatalogResolveOptions {
            offline: false,
            write_cache: false,
        },
        &client,
    )
    .expect("resolve");
    let elapsed = start.elapsed();

    assert_eq!(resolved.discovered_items.len(), 400);
    assert!(
        elapsed < Duration::from_secs(2),
        "catalog resolution took too long: {elapsed:?}"
    );
}

fn build_catalog(items: usize) -> String {
    let mut raw = String::from("{\"registry_version\":\"providers@1\",\"categories\":[");
    for idx in 0..8 {
        if idx > 0 {
            raw.push(',');
        }
        raw.push_str(&format!(
            "{{\"id\":\"cat-{idx}\",\"label\":{{\"fallback\":\"Category {idx}\"}},\"description\":{{\"fallback\":\"Category description {idx}\"}}}}"
        ));
    }
    raw.push_str("],\"items\":[");
    for idx in 0..items {
        if idx > 0 {
            raw.push(',');
        }
        raw.push_str(&format!(
            "{{\"id\":\"provider-{idx}\",\"category\":\"cat-{}\",\"label\":{{\"fallback\":\"Provider {idx}\"}},\"ref\":\"oci://ghcr.io/greenticai/packs/provider-{idx}:stable\"}}",
            idx % 8
        ));
    }
    raw.push_str("]}");
    raw
}