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",
|
"doc_summary.v1",
|
||||||
"chunk_inspection.v1",
|
"chunk_inspection.v1",
|
||||||
"doctor.v1",
|
"doctor.v1",
|
||||||
|
"config_migration.v1",
|
||||||
"ingest_report.v1",
|
"ingest_report.v1",
|
||||||
"ingest_progress.v1",
|
"ingest_progress.v1",
|
||||||
"reset_report.v1",
|
"reset_report.v1",
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ enum Cmd {
|
|||||||
force: bool,
|
force: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// config.toml 관리 (스키마 마이그레이션 등).
|
||||||
|
Config {
|
||||||
|
#[command(subcommand)]
|
||||||
|
what: ConfigWhat,
|
||||||
|
},
|
||||||
|
|
||||||
/// Scan the workspace and ingest new/updated documents.
|
/// Scan the workspace and ingest new/updated documents.
|
||||||
Ingest {
|
Ingest {
|
||||||
/// Workspace root override.
|
/// 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)]
|
#[derive(Subcommand, Debug)]
|
||||||
enum ListWhat {
|
enum ListWhat {
|
||||||
/// List documents currently indexed.
|
/// List documents currently indexed.
|
||||||
@@ -1310,6 +1326,42 @@ fn run(cli: &Cli) -> anyhow::Result<()> {
|
|||||||
Ok(())
|
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 => {
|
Cmd::Doctor => {
|
||||||
let report = kebab_app::doctor_with_config_path(cli.config.as_deref())?;
|
let report = kebab_app::doctor_with_config_path(cli.config.as_deref())?;
|
||||||
if cli.json {
|
if cli.json {
|
||||||
|
|||||||
@@ -225,6 +225,12 @@ pub fn wire_bulk_search_item(item: &kebab_core::BulkSearchItem) -> Value {
|
|||||||
v
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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