Skip to content

Commit 6b398ff

Browse files
committed
feat(cli): add JSON/YAML output format to gateway list
Add -o/--output flag to `openshell gateway list` matching the existing sandbox list pattern, enabling machine-readable output for scripting. Signed-off-by: Florent Benoit <fbenoit@redhat.com>
1 parent 2d9e532 commit 6b398ff

2 files changed

Lines changed: 88 additions & 5 deletions

File tree

‎crates/openshell-cli/src/main.rs‎

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,11 @@ enum GatewayCommands {
10391039
/// Prints a table of all registered gateways with their endpoint, type,
10401040
/// and authentication mode. The active gateway is marked with `*`.
10411041
#[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")]
1042-
List,
1042+
List {
1043+
/// Output format.
1044+
#[arg(short = 'o', long = "output", value_enum, default_value_t = OutputFormat::Table)]
1045+
output: OutputFormat,
1046+
},
10431047
}
10441048

10451049
// -----------------------------------------------------------------------
@@ -1942,8 +1946,8 @@ async fn main() -> Result<()> {
19421946
.unwrap_or_else(|| "openshell".to_string());
19431947
run::gateway_admin_info(&name)?;
19441948
}
1945-
GatewayCommands::List => {
1946-
run::gateway_list(&cli.gateway)?;
1949+
GatewayCommands::List { output } => {
1950+
run::gateway_list(&cli.gateway, output.as_str())?;
19471951
}
19481952
},
19491953

@@ -3686,6 +3690,51 @@ mod tests {
36863690
assert!(result.is_err(), "--names and -o json should conflict");
36873691
}
36883692

3693+
#[test]
3694+
fn gateway_list_default_output_is_table() {
3695+
let cli = Cli::try_parse_from(["openshell", "gateway", "list"])
3696+
.expect("gateway list should parse");
3697+
3698+
assert!(matches!(
3699+
cli.command,
3700+
Some(Commands::Gateway {
3701+
command: Some(GatewayCommands::List {
3702+
output: OutputFormat::Table,
3703+
})
3704+
})
3705+
));
3706+
}
3707+
3708+
#[test]
3709+
fn gateway_list_accepts_output_json() {
3710+
let cli = Cli::try_parse_from(["openshell", "gateway", "list", "-o", "json"])
3711+
.expect("gateway list -o json should parse");
3712+
3713+
assert!(matches!(
3714+
cli.command,
3715+
Some(Commands::Gateway {
3716+
command: Some(GatewayCommands::List {
3717+
output: OutputFormat::Json,
3718+
})
3719+
})
3720+
));
3721+
}
3722+
3723+
#[test]
3724+
fn gateway_list_accepts_output_yaml() {
3725+
let cli = Cli::try_parse_from(["openshell", "gateway", "list", "-o", "yaml"])
3726+
.expect("gateway list -o yaml should parse");
3727+
3728+
assert!(matches!(
3729+
cli.command,
3730+
Some(Commands::Gateway {
3731+
command: Some(GatewayCommands::List {
3732+
output: OutputFormat::Yaml,
3733+
})
3734+
})
3735+
));
3736+
}
3737+
36893738
#[test]
36903739
fn provider_create_accepts_custom_profile_type_ids() {
36913740
let cli = Cli::try_parse_from([

‎crates/openshell-cli/src/run.rs‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ where
802802

803803
let gateways = list_gateways()?;
804804
if gateways.is_empty() || !interactive {
805-
gateway_list(gateway_flag)?;
805+
gateway_list(gateway_flag, "table")?;
806806
if !gateways.is_empty() {
807807
eprintln!();
808808
eprintln!(
@@ -1256,10 +1256,34 @@ pub fn gateway_logout(name: &str) -> Result<()> {
12561256
}
12571257

12581258
/// List all registered gateways.
1259-
pub fn gateway_list(gateway_flag: &Option<String>) -> Result<()> {
1259+
pub fn gateway_list(gateway_flag: &Option<String>, output: &str) -> Result<()> {
12601260
let gateways = list_gateways()?;
12611261
let active = gateway_flag.clone().or_else(load_active_gateway);
12621262

1263+
match output {
1264+
"json" => {
1265+
let items: Vec<serde_json::Value> = gateways
1266+
.iter()
1267+
.map(|g| gateway_to_json(g, &active))
1268+
.collect();
1269+
println!(
1270+
"{}",
1271+
serde_json::to_string_pretty(&items).into_diagnostic()?
1272+
);
1273+
return Ok(());
1274+
}
1275+
"yaml" => {
1276+
let items: Vec<serde_json::Value> = gateways
1277+
.iter()
1278+
.map(|g| gateway_to_json(g, &active))
1279+
.collect();
1280+
print!("{}", serde_yml::to_string(&items).into_diagnostic()?);
1281+
return Ok(());
1282+
}
1283+
"table" => {}
1284+
_ => return Err(miette!("unsupported output format: {output}")),
1285+
}
1286+
12631287
if gateways.is_empty() {
12641288
println!("No gateways found.");
12651289
println!();
@@ -1319,6 +1343,16 @@ pub fn gateway_list(gateway_flag: &Option<String>) -> Result<()> {
13191343
Ok(())
13201344
}
13211345

1346+
fn gateway_to_json(gateway: &GatewayMetadata, active: &Option<String>) -> serde_json::Value {
1347+
serde_json::json!({
1348+
"name": gateway.name,
1349+
"endpoint": gateway.gateway_endpoint,
1350+
"type": gateway_type_label(gateway),
1351+
"auth": gateway_auth_label(gateway),
1352+
"active": active.as_deref() == Some(&gateway.name),
1353+
})
1354+
}
1355+
13221356
async fn http_health_check(server: &str, tls: &TlsOptions) -> Result<Option<StatusCode>> {
13231357
let base = server.trim_end_matches('/');
13241358
let uri: hyper::Uri = format!("{base}/healthz").parse().into_diagnostic()?;

0 commit comments

Comments
 (0)