use anyhow::{Context, Result};
use serde_json::Value;
use std::{fs, path::Path};
use super::super::MigrationContext;
pub fn config_needs_legacy_contract_upgrade(ctx: &MigrationContext) -> bool {
config_file_needs_legacy_contract_upgrade(&ctx.project_config_path).unwrap_or(false)
|| ctx
.global_config_path
.as_ref()
.and_then(|path| config_file_needs_legacy_contract_upgrade(path).ok())
.unwrap_or(false)
}
pub fn apply_legacy_contract_upgrade(ctx: &MigrationContext) -> Result<()> {
upgrade_legacy_contract_in_file(&ctx.project_config_path)?;
if let Some(global_path) = &ctx.global_config_path {
upgrade_legacy_contract_in_file(global_path)?;
}
Ok(())
}
pub(super) fn config_file_needs_legacy_contract_upgrade(path: &Path) -> Result<bool> {
if !path.exists() {
return Ok(false);
}
let raw =
fs::read_to_string(path).with_context(|| format!("read config file {}", path.display()))?;
let value: Value = match jsonc_parser::parse_to_serde_value::<Value>(&raw, &Default::default())
{
Ok(v) => v,
Err(_) => return Ok(false),
};
let has_legacy_version = value.get("version").and_then(Value::as_u64) == Some(1);
let has_legacy_publish_flag = value
.get("agent")
.and_then(Value::as_object)
.is_some_and(|agent| agent.contains_key("git_commit_push_enabled"));
Ok(has_legacy_version || has_legacy_publish_flag)
}
pub(super) fn upgrade_legacy_contract_in_file(path: &Path) -> Result<()> {
if !path.exists() {
return Ok(());
}
let raw =
fs::read_to_string(path).with_context(|| format!("read config file {}", path.display()))?;
let mut value: Value = jsonc_parser::parse_to_serde_value::<Value>(&raw, &Default::default())?;
let Some(root) = value.as_object_mut() else {
return Ok(());
};
let agent_has_legacy_flag = root
.get("agent")
.and_then(Value::as_object)
.is_some_and(|agent| agent.contains_key("git_commit_push_enabled"));
let version_needs_upgrade = root.get("version").and_then(Value::as_u64) == Some(1);
if !agent_has_legacy_flag && !version_needs_upgrade {
return Ok(());
}
if version_needs_upgrade || agent_has_legacy_flag {
root.insert("version".to_string(), Value::from(2));
}
if let Some(agent) = root.get_mut("agent").and_then(Value::as_object_mut) {
let git_publish_mode_exists = agent.contains_key("git_publish_mode");
let legacy_publish_value = agent
.remove("git_commit_push_enabled")
.and_then(|value| value.as_bool());
if let Some(legacy_publish_value) = legacy_publish_value
&& !git_publish_mode_exists
{
let mode = if legacy_publish_value {
"commit_and_push"
} else {
"off"
};
agent.insert(
"git_publish_mode".to_string(),
Value::String(mode.to_string()),
);
}
}
let rendered = serde_json::to_string_pretty(&value).context("serialize migrated config")?;
crate::fsutil::write_atomic(path, rendered.as_bytes())
.with_context(|| format!("write migrated config {}", path.display()))?;
log::info!("Upgraded legacy config contract in {}", path.display());
Ok(())
}