use crate::config::project_root;
use crate::ui;
use anyhow::{Context, Result};
use clap::Subcommand;
use std::process::{Command, Stdio};
#[derive(Subcommand)]
pub enum RunCommand {
Dev,
Test,
#[command(name = "test:unit")]
TestUnit,
#[command(name = "test:integration")]
TestIntegration,
Lint,
Typecheck,
Script {
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
}
pub fn run(cmd: RunCommand) -> Result<()> {
check_bun()?;
match cmd {
RunCommand::Dev => bun_run(&["dev"])?,
RunCommand::Test => bun_run(&["test"])?,
RunCommand::TestUnit => bun_run(&["test:unit"])?,
RunCommand::TestIntegration => bun_run(&["test:integration"])?,
RunCommand::Lint => bun_run(&["lint"])?,
RunCommand::Typecheck => bun_run(&["typecheck"])?,
RunCommand::Script { args } => {
if args.is_empty() {
anyhow::bail!("Please specify a script to run");
}
let args_str: Vec<&str> = args.iter().map(String::as_str).collect();
bun_run(&args_str)?;
}
}
Ok(())
}
fn check_bun() -> Result<()> {
which::which("bun").context("Bun is not installed or not in PATH")?;
Ok(())
}
fn bun_run(args: &[&str]) -> Result<()> {
let root = project_root()?;
ui::show_command(&format!("bun run {}", args.join(" ")));
let status = Command::new("bun")
.arg("run")
.args(args)
.current_dir(&root)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.context("Failed to execute bun")?;
if !status.success() {
std::process::exit(status.code().unwrap_or(1));
}
Ok(())
}