use std::path::Path;
use super::emit::Plan;
use super::model::{plan_cargo_deps, validate_resource_name};
use super::naming::{pascal, snake};
use super::{GenerateError, ensure_project_root};
const TASK_DEPS: &[(&str, &str)] = &[("serde", "{ version = \"1\", features = [\"derive\"] }")];
pub fn plan_task(project_root: &Path, name: &str) -> Result<Plan, GenerateError> {
ensure_project_root(project_root)?;
validate_resource_name(name)?;
let snake_name = snake(name);
let pascal_name = pascal(name);
let mut plan = Plan::new(project_root);
plan.create(
project_root.join("tasks").join(format!("{snake_name}.rs")),
render_task_file(&snake_name, &pascal_name),
);
plan_cargo_deps(
&mut plan,
project_root,
TASK_DEPS,
&project_root.join("tasks"),
);
Ok(plan)
}
fn render_task_file(snake_name: &str, pascal_name: &str) -> String {
format!(
r#"//! One-off operational task generated by `autumn generate task`.
use autumn_web::prelude::*;
use serde::Deserialize;
#[derive(Debug, Default, Deserialize)]
pub struct {pascal_name}Args {{
#[serde(default)]
pub dry_run: bool,
}}
/// Describe what `{snake_name}` does.
#[autumn_web::task]
pub async fn {snake_name}(TaskArgs(args): TaskArgs<{pascal_name}Args>) -> AutumnResult<()> {{
if args.dry_run {{
autumn_web::reexports::tracing::info!(task = "{snake_name}", "dry run requested");
return Ok(());
}}
Ok(())
}}
"#
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generate::Flags;
use std::fs;
use tempfile::TempDir;
fn project() -> TempDir {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("Cargo.toml"), "[package]\nname=\"x\"\n").unwrap();
tmp
}
#[test]
fn plan_creates_task_file() {
let tmp = project();
let plan = plan_task(tmp.path(), "cleanup_users").unwrap();
assert!(
plan.actions
.iter()
.any(|action| action.path().ends_with("tasks/cleanup_users.rs")),
"plan should create tasks/cleanup_users.rs"
);
}
#[test]
fn execute_writes_task_skeleton() {
let tmp = project();
let plan = plan_task(tmp.path(), "cleanup_users").unwrap();
plan.execute(Flags::default()).unwrap();
let task = fs::read_to_string(tmp.path().join("tasks/cleanup_users.rs")).unwrap();
assert!(task.contains("#[autumn_web::task]"));
assert!(task.contains("pub async fn cleanup_users"));
assert!(task.contains("TaskArgs<CleanupUsersArgs>"));
}
}