diff --git a/crates/omnigraph-cli/src/main.rs b/crates/omnigraph-cli/src/main.rs index 2dfc902..dfe4c94 100644 --- a/crates/omnigraph-cli/src/main.rs +++ b/crates/omnigraph-cli/src/main.rs @@ -898,68 +898,19 @@ fn print_config_origins(provenance: &Provenance, json: bool) -> Result<()> { } } -/// Print a resolved [`GraphLocator`] (embedded vs remote) in human or JSON form. +/// Print a resolved [`GraphLocator`] (embedded vs remote). Serializes the typed +/// locator (internally tagged `kind:`) and prunes null/empty values, so every +/// field — including an Embedded graph's `region`/`endpoint`/`policy_file` — is +/// reported and no field can be forgotten by hand. fn print_resolved_locator(locator: &GraphLocator, json: bool) -> Result<()> { - match locator { - GraphLocator::Embedded { - uri, - branch, - snapshot, - graph_id, - .. - } => { - if json { - print_json(&serde_json::json!({ - "kind": "embedded", - "uri": uri, - "graph_id": graph_id, - "branch": branch, - "snapshot": snapshot, - })) - } else { - println!("embedded"); - println!(" uri: {uri}"); - println!(" graph_id: {graph_id}"); - if let Some(branch) = branch { - println!(" branch: {branch}"); - } - if let Some(snapshot) = snapshot { - println!(" snapshot: {snapshot}"); - } - Ok(()) - } - } - GraphLocator::Remote { - endpoint, - server, - graph_id, - branch, - snapshot, - } => { - if json { - print_json(&serde_json::json!({ - "kind": "remote", - "endpoint": endpoint, - "server": server, - "graph_id": graph_id, - "branch": branch, - "snapshot": snapshot, - })) - } else { - println!("remote"); - println!(" endpoint: {endpoint}"); - println!(" server: {server}"); - println!(" graph_id: {graph_id}"); - if let Some(branch) = branch { - println!(" branch: {branch}"); - } - if let Some(snapshot) = snapshot { - println!(" snapshot: {snapshot}"); - } - Ok(()) - } - } + let mut value = serde_yaml::to_value(locator)?; + prune_empty(&mut value); + if json { + println!("{}", serde_json::to_string_pretty(&value)?); + } else { + print!("{}", serde_yaml::to_string(&value)?); } + Ok(()) } #[derive(Debug, Clone)] diff --git a/crates/omnigraph-cli/tests/cli.rs b/crates/omnigraph-cli/tests/cli.rs index 0a7c2de..e6caea9 100644 --- a/crates/omnigraph-cli/tests/cli.rs +++ b/crates/omnigraph-cli/tests/cli.rs @@ -336,7 +336,7 @@ fn config_view_resolved_prints_embedded_and_remote_locators() { write_config( &config, "version: 1\nservers:\n prod:\n endpoint: https://prod.example\n\ - graphs:\n local:\n storage: ./l.omni\n staging:\n server: prod\n graph_id: prod\n", + graphs:\n local:\n storage:\n uri: ./l.omni\n region: eu-west-1\n endpoint: https://minio.local\n staging:\n server: prod\n graph_id: prod\n", ); let embedded = parse_stdout_json(&output_success( @@ -351,6 +351,10 @@ fn config_view_resolved_prints_embedded_and_remote_locators() { )); assert_eq!(embedded["kind"], "embedded"); assert!(embedded["uri"].as_str().unwrap().ends_with("l.omni")); + // The serialized locator exposes every field — incl. the storage block's + // region/endpoint, which the old hand-listed printer dropped. + assert_eq!(embedded["region"], "eu-west-1"); + assert_eq!(embedded["endpoint"], "https://minio.local"); let remote = parse_stdout_json(&output_success( cli() diff --git a/crates/omnigraph-config/src/lib.rs b/crates/omnigraph-config/src/lib.rs index c87e89c..2b78978 100644 --- a/crates/omnigraph-config/src/lib.rs +++ b/crates/omnigraph-config/src/lib.rs @@ -169,8 +169,11 @@ pub struct ServerEntry { } /// A resolved graph address (RFC-002 §1.1/§2) — replaces scheme-sniffing on a -/// `uri` string with a typed embedded-XOR-remote locator. -#[derive(Debug, Clone)] +/// `uri` string with a typed embedded-XOR-remote locator. `Serialize` is +/// internally tagged (`kind: embedded|remote`) so `config view --resolved` dumps +/// every field without hand-listing — a new field can't be silently omitted. +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "kind", rename_all = "snake_case")] pub enum GraphLocator { Embedded { /// Object-store URI, resolved against the config `base_dir`.