gobby-wiki 0.7.0

Gobby wiki CLI shell
mod common;

fn assert_vault_shape(root: &std::path::Path) {
    for dir in [
        "raw",
        "raw/assets",
        "knowledge/sources",
        "knowledge/concepts",
        "knowledge/topics",
        "inbox",
        "outputs",
        "meta/health",
        "_gwiki",
    ] {
        assert!(root.join(dir).is_dir(), "missing directory {dir}");
    }

    for file in ["raw/INDEX.md", "_index.md", "log.md"] {
        assert!(root.join(file).is_file(), "missing file {file}");
    }
}

#[test]
fn init_creates_vault_shape() {
    let tmp = tempfile::tempdir().expect("tempdir");
    let hub = tmp.path().join("hub");
    let topic_output = common::gwiki_command()
        .args(["init", "--topic", "rust"])
        .env("GOBBY_WIKI_HUB", &hub)
        .current_dir(tmp.path())
        .output()
        .expect("run topic init");

    assert!(
        topic_output.status.success(),
        "topic init failed\nstdout:\n{}\nstderr:\n{}",
        String::from_utf8_lossy(&topic_output.stdout),
        String::from_utf8_lossy(&topic_output.stderr)
    );
    assert_vault_shape(&hub.join("topics").join("rust"));
    assert!(hub.join("wikis.json").is_file());

    let project = tmp.path().join("project");
    let gcode_json = common::write_gcode_json(&project);

    let project_output = common::gwiki_command()
        .args(["init", "--project"])
        .env_remove("GOBBY_WIKI_HUB")
        .current_dir(&project)
        .output()
        .expect("run project init");

    assert!(
        project_output.status.success(),
        "project init failed\nstdout:\n{}\nstderr:\n{}",
        String::from_utf8_lossy(&project_output.stdout),
        String::from_utf8_lossy(&project_output.stderr)
    );
    assert_vault_shape(&project.join("gobby-wiki"));
    assert!(project.join("gobby-wiki").join("wikis.json").is_file());
    common::assert_gcode_json_unchanged(&gcode_json);
}

#[test]
fn init_seeds_obsidian_and_gitignores_inside_git_repo() {
    let tmp = tempfile::tempdir().expect("tempdir");
    let project = tmp.path().join("project");
    std::fs::create_dir_all(project.join(".git")).expect("fake git work tree");
    let gcode_json = common::write_gcode_json(&project);

    let output = common::gwiki_command()
        .args(["init", "--project"])
        .env_remove("GOBBY_WIKI_HUB")
        .current_dir(&project)
        .output()
        .expect("run project init");
    assert!(
        output.status.success(),
        "project init failed\nstdout:\n{}\nstderr:\n{}",
        String::from_utf8_lossy(&output.stdout),
        String::from_utf8_lossy(&output.stderr)
    );

    let vault = project.join("gobby-wiki");
    let app_json = std::fs::read_to_string(vault.join(".obsidian").join("app.json"))
        .expect("read obsidian app.json");
    assert!(app_json.contains("userIgnoreFilters"));
    assert!(app_json.contains("_gwiki/"));

    let gitignore = std::fs::read_to_string(project.join(".gitignore")).expect("read .gitignore");
    assert_eq!(
        gitignore
            .lines()
            .filter(|l| l.trim() == "gobby-wiki/.obsidian/workspace.json")
            .count(),
        1,
        "exactly one workspace.json rule"
    );
    assert!(
        !gitignore.lines().any(|l| l.trim() == ".obsidian/"),
        "stable Obsidian config should not be ignored wholesale"
    );

    common::assert_gcode_json_unchanged(&gcode_json);
}

#[test]
fn init_outside_git_repo_seeds_obsidian_without_gitignore() {
    let tmp = tempfile::tempdir().expect("tempdir");
    let project = tmp.path().join("project");
    common::write_gcode_json(&project);

    let output = common::gwiki_command()
        .args(["init", "--project"])
        .env_remove("GOBBY_WIKI_HUB")
        .current_dir(&project)
        .output()
        .expect("run project init");
    assert!(output.status.success(), "project init failed");

    let vault = project.join("gobby-wiki");
    assert!(
        vault.join(".obsidian").join("app.json").is_file(),
        "app.json seeded even without git"
    );
    assert!(
        !project.join(".gitignore").exists(),
        "no .gitignore created outside a git work tree"
    );
}