diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e34f40f..3aa142b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,13 +133,12 @@ jobs: - name: Checkout code uses: actions/checkout@v6 - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: "3.14" + - name: Install Rust + uses: dtolnay/rust-toolchain@stable - - name: Install planoai - run: pip install -e ./cli + - name: Build planoai CLI + working-directory: ./crates + run: cargo build --release -p plano-cli - name: Validate plano config run: bash config/validate_plano_config.sh diff --git a/config/validate_plano_config.sh b/config/validate_plano_config.sh index 572ac2ec..e65bf5c2 100644 --- a/config/validate_plano_config.sh +++ b/config/validate_plano_config.sh @@ -8,13 +8,7 @@ for file in $(find . -name config.yaml -o -name plano_config_full_reference.yaml rendered_file="$(pwd)/${file}_rendered" touch "$rendered_file" - PLANO_CONFIG_FILE="$(pwd)/${file}" \ - PLANO_CONFIG_SCHEMA_FILE="${SCRIPT_DIR}/plano_config_schema.yaml" \ - TEMPLATE_ROOT="${SCRIPT_DIR}" \ - ENVOY_CONFIG_TEMPLATE_FILE="envoy.template.yaml" \ - PLANO_CONFIG_FILE_RENDERED="$rendered_file" \ - ENVOY_CONFIG_FILE_RENDERED="/dev/null" \ - python -m planoai.config_generator 2>&1 > /dev/null + planoai validate "$(pwd)/${file}" 2>&1 > /dev/null if [ $? -ne 0 ]; then echo "Validation failed for $file" diff --git a/crates/plano-cli/src/commands/mod.rs b/crates/plano-cli/src/commands/mod.rs index 380f2a64..129a8906 100644 --- a/crates/plano-cli/src/commands/mod.rs +++ b/crates/plano-cli/src/commands/mod.rs @@ -5,6 +5,7 @@ pub mod init; pub mod logs; pub mod self_update; pub mod up; +pub mod validate; use clap::{Parser, Subcommand}; @@ -134,6 +135,16 @@ pub enum Command { list_templates: bool, }, + /// Validate a Plano configuration file + Validate { + /// Config file path + file: Option, + + /// Path to the directory containing config.yaml + #[arg(long, default_value = ".")] + path: String, + }, + /// Update planoai to the latest version #[command(name = "self-update")] SelfUpdate { @@ -261,6 +272,7 @@ pub async fn run(cli: Cli) -> anyhow::Result<()> { force, list_templates, }) => init::run(template, clean, output, force, list_templates).await, + Some(Command::Validate { file, path }) => validate::run(file, &path).await, Some(Command::SelfUpdate { version }) => self_update::run(version.as_deref()).await, } } diff --git a/crates/plano-cli/src/commands/validate.rs b/crates/plano-cli/src/commands/validate.rs new file mode 100644 index 00000000..d1bdc9a6 --- /dev/null +++ b/crates/plano-cli/src/commands/validate.rs @@ -0,0 +1,31 @@ +use anyhow::Result; + +use crate::native::runner::validate_config; +use crate::utils::find_config_file; + +pub async fn run(file: Option, path: &str) -> Result<()> { + let green = console::Style::new().green(); + let red = console::Style::new().red(); + + let config_path = find_config_file(path, file.as_deref()); + if !config_path.exists() { + eprintln!( + "{} Config file not found: {}", + red.apply_to("✗"), + config_path.display() + ); + std::process::exit(1); + } + + match validate_config(&config_path) { + Ok(()) => { + eprintln!("{} Configuration valid", green.apply_to("✓")); + Ok(()) + } + Err(e) => { + eprintln!("{} Validation failed", red.apply_to("✗")); + eprintln!(" {e:#}"); + std::process::exit(1); + } + } +}