feat(cli): pic pull exports an app's own vars into [vars]

Completes the vars round-trip: pull now fetches the app's OWN env-agnostic
vars (`vars_list` filtered to scope `*`, non-tombstone) and writes them
into the manifest `[vars]` block, alongside scripts/routes/secrets.
Inherited group vars stay out (pull exports own rows only, §4.6); a value
TOML can't represent (e.g. JSON null) is skipped with a warning. So
`pic pull` → edit → `pic apply` is now lossless for app config vars.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-25 08:03:26 +02:00
parent 34dcae98a2
commit 181622a84a

View File

@@ -49,6 +49,24 @@ pub async fn run(app_ident: &str, dir: &Path, force: bool, mode: OutputMode) ->
.secrets_list(VarOwnerArg::App(app_ident), None)
.await?
.secrets;
// App's OWN env-agnostic vars become the manifest `[vars]` block. Inherited
// group vars and tombstones are excluded (pull exports own rows only, §4.6);
// a value TOML can't represent (e.g. JSON null) is skipped with a warning.
let mut manifest_vars = std::collections::BTreeMap::new();
for v in client.vars_list(VarOwnerArg::App(app_ident)).await?.vars {
if v.env != "*" || v.is_tombstone {
continue;
}
match toml::Value::try_from(&v.value) {
Ok(tv) => {
manifest_vars.insert(v.key, tv);
}
Err(_) => eprintln!(
"warning: skipping var `{}` — its value can't be represented in TOML",
v.key
),
}
}
let name_by_id: HashMap<ScriptId, String> =
scripts.iter().map(|s| (s.id, s.name.clone())).collect();
@@ -204,7 +222,7 @@ pub async fn run(app_ident: &str, dir: &Path, force: bool, mode: OutputMode) ->
secrets: ManifestSecrets {
names: secrets.iter().map(|s| s.name.clone()).collect(),
},
vars: std::collections::BTreeMap::new(),
vars: manifest_vars,
};
std::fs::write(&manifest_path, manifest.to_toml()?)