feat(cli): kebab config migrate 서브커맨드 + wire config_migration.v1
- Cmd::Config { Migrate { --dry-run } }, --json 시 config_migration.v1.
- wire_config_migration (ConfigMigrationReport 가 schema_version 자체 보유).
- schema.rs WIRE_SCHEMAS 에 config_migration.v1 등록 + JSON schema 파일.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -108,6 +108,7 @@ const WIRE_SCHEMAS: &[&str] = &[
|
||||
"doc_summary.v1",
|
||||
"chunk_inspection.v1",
|
||||
"doctor.v1",
|
||||
"config_migration.v1",
|
||||
"ingest_report.v1",
|
||||
"ingest_progress.v1",
|
||||
"reset_report.v1",
|
||||
|
||||
@@ -60,6 +60,12 @@ enum Cmd {
|
||||
force: bool,
|
||||
},
|
||||
|
||||
/// config.toml 관리 (스키마 마이그레이션 등).
|
||||
Config {
|
||||
#[command(subcommand)]
|
||||
what: ConfigWhat,
|
||||
},
|
||||
|
||||
/// Scan the workspace and ingest new/updated documents.
|
||||
Ingest {
|
||||
/// Workspace root override.
|
||||
@@ -346,6 +352,16 @@ enum Cmd {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum ConfigWhat {
|
||||
/// 기존 config.toml 을 새 스키마로 마이그레이션(빠진 섹션 추가 + 멱등 + .bak 백업).
|
||||
Migrate {
|
||||
/// 변경만 출력하고 파일은 수정하지 않는다.
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum ListWhat {
|
||||
/// List documents currently indexed.
|
||||
@@ -1310,6 +1326,42 @@ fn run(cli: &Cli) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Cmd::Config { what } => match what {
|
||||
ConfigWhat::Migrate { dry_run } => {
|
||||
let report =
|
||||
kebab_app::config_migrate_with_config_path(cli.config.as_deref(), *dry_run)?;
|
||||
if cli.json {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string(&wire::wire_config_migration(&report))?
|
||||
);
|
||||
} else if !report.changed {
|
||||
println!(
|
||||
"config 이미 최신입니다 (schema v{}).",
|
||||
report.to_schema_version
|
||||
);
|
||||
} else {
|
||||
let verb = if report.dry_run { "변경 예정" } else { "적용됨" };
|
||||
println!(
|
||||
"config 마이그레이션 {verb}: v{} → v{} ({} changes)",
|
||||
report.from_schema_version,
|
||||
report.to_schema_version,
|
||||
report.changes.len()
|
||||
);
|
||||
for c in &report.changes {
|
||||
println!(" - [{:?}] {} — {}", c.kind, c.path, c.detail);
|
||||
}
|
||||
if let Some(bak) = &report.backup_path {
|
||||
println!("백업: {bak}");
|
||||
}
|
||||
if report.dry_run {
|
||||
println!("(--dry-run: 파일 미수정. 적용하려면 --dry-run 없이 재실행)");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
|
||||
Cmd::Doctor => {
|
||||
let report = kebab_app::doctor_with_config_path(cli.config.as_deref())?;
|
||||
if cli.json {
|
||||
|
||||
@@ -225,6 +225,12 @@ pub fn wire_bulk_search_item(item: &kebab_core::BulkSearchItem) -> Value {
|
||||
v
|
||||
}
|
||||
|
||||
/// `config_migration.v1` 직렬화. `ConfigMigrationReport` 가 `schema_version`
|
||||
/// 필드를 자체 보유하므로(doctor 와 동일) 그대로 직렬화한다.
|
||||
pub fn wire_config_migration(r: &kebab_app::ConfigMigrationReport) -> Value {
|
||||
serde_json::to_value(r).expect("ConfigMigrationReport serializes")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
38
docs/wire-schema/v1/config_migration.v1.schema.json
Normal file
38
docs/wire-schema/v1/config_migration.v1.schema.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "config_migration.v1",
|
||||
"description": "Result of `kebab config migrate` — schema reconciliation of a user's config.toml.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"config_path",
|
||||
"dry_run",
|
||||
"from_schema_version",
|
||||
"to_schema_version",
|
||||
"changed",
|
||||
"changes"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": { "const": "config_migration.v1" },
|
||||
"config_path": { "type": "string" },
|
||||
"dry_run": { "type": "boolean" },
|
||||
"from_schema_version": { "type": "integer" },
|
||||
"to_schema_version": { "type": "integer" },
|
||||
"changed": { "type": "boolean" },
|
||||
"backup_path": { "type": ["string", "null"] },
|
||||
"changes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["kind", "path", "detail"],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": ["added_section", "added_key", "removed_deprecated"]
|
||||
},
|
||||
"path": { "type": "string" },
|
||||
"detail": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user