//! `pic vars ls | set | rm` — manage Phase-3 group/app config vars. //! //! Wraps `/api/v1/admin/{apps,groups}/{id}/vars*`. Exactly one of //! `--group` / `--app` selects the owner. `ls` shows the owner's OWN rows //! (not the resolved/inherited view). Set values are JSON strings by //! default; `--json` parses the value as raw JSON. use anyhow::{anyhow, Result}; use crate::client::{Client, VarOwnerArg}; use crate::config; use crate::output::{OutputMode, Table}; /// Resolve the `--group`/`--app` pair into exactly one owner. fn owner<'a>(group: Option<&'a str>, app: Option<&'a str>) -> Result> { match (group, app) { (Some(g), None) => Ok(VarOwnerArg::Group(g)), (None, Some(a)) => Ok(VarOwnerArg::App(a)), (Some(_), Some(_)) => Err(anyhow!("pass exactly one of --group / --app, not both")), (None, None) => Err(anyhow!("pass one of --group / --app")), } } pub async fn ls(group: Option<&str>, app: Option<&str>, mode: OutputMode) -> Result<()> { let owner = owner(group, app)?; let creds = config::resolve()?; let client = Client::from_creds(&creds)?; let resp = client.vars_list(owner).await?; let mut table = Table::new(["key", "env", "value", "tombstone", "updated_at"]); for v in resp.vars { table.row([ v.key, v.env, v.value.to_string(), v.is_tombstone.to_string(), v.updated_at.to_rfc3339(), ]); } table.print(mode); Ok(()) } pub async fn set( group: Option<&str>, app: Option<&str>, key: &str, value: &str, env: Option<&str>, as_json: bool, tombstone: bool, ) -> Result<()> { let owner = owner(group, app)?; let creds = config::resolve()?; let client = Client::from_creds(&creds)?; // A tombstone carries no value (the server stores JSON null + the // deletion marker); otherwise parse per `--json`. let parsed = if tombstone { serde_json::Value::Null } else if as_json { serde_json::from_str(value).map_err(|e| anyhow!("parse value as JSON: {e}"))? } else { serde_json::Value::String(value.to_string()) }; client.vars_set(owner, key, parsed, env, tombstone).await?; if tombstone { println!("Set tombstone for {key}"); } else { println!("Set var {key}"); } Ok(()) } pub async fn rm( group: Option<&str>, app: Option<&str>, key: &str, env: Option<&str>, ) -> Result<()> { let owner = owner(group, app)?; let creds = config::resolve()?; let client = Client::from_creds(&creds)?; client.vars_delete(owner, key, env).await?; println!("Deleted var {key}"); Ok(()) }