From 213df03ae949ffb4af1e99391c44bcff8ebd72f9 Mon Sep 17 00:00:00 2001 From: rroskam Date: Fri, 20 Feb 2026 09:49:56 -0500 Subject: [PATCH] refactor: replace SourceInfo struct with TemplateOrigin enum SourceInfo encoded local-vs-Git origin through three nullable Option fields, relying on url.is_some() as a proxy for 'Git template'. Replace with an explicit enum: TemplateOrigin::Local TemplateOrigin::Git { url, git_ref, commit_sha } - Hook-warning check becomes matches!(origin, TemplateOrigin::Git { .. }) - write_answers now takes &TemplateOrigin directly - Construction sites in plan_generation updated (2 locations) - Integration test updated to use TemplateOrigin::Local --- src/answers/mod.rs | 60 +++++++++++++++++++++++--------------------- src/lib.rs | 38 +++++++++++++--------------- tests/integration.rs | 7 +----- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/src/answers/mod.rs b/src/answers/mod.rs index d753bd5..02d1bc0 100644 --- a/src/answers/mod.rs +++ b/src/answers/mod.rs @@ -7,10 +7,13 @@ use tera::Value; use crate::config::schema::TemplateConfig; use crate::error::{DicecutError, Result}; -pub struct SourceInfo { - pub url: Option, - pub git_ref: Option, - pub commit_sha: Option, +pub enum TemplateOrigin { + Local, + Git { + url: String, + git_ref: Option, + commit_sha: Option, + }, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -80,7 +83,7 @@ pub fn write_answers( output_dir: &Path, config: &TemplateConfig, variables: &BTreeMap, - source_info: &SourceInfo, + origin: &TemplateOrigin, ) -> Result<()> { let answers_path = output_dir.join(&config.answers.file); @@ -94,23 +97,22 @@ pub fn write_answers( if let Some(version) = &config.template.version { meta.insert("version".to_string(), toml::Value::String(version.clone())); } - if let Some(source) = source_info.url.as_deref() { + if let TemplateOrigin::Git { + url, + git_ref, + commit_sha, + } = origin + { meta.insert( "template_source".to_string(), - toml::Value::String(source.to_string()), - ); - } - if let Some(git_ref) = source_info.git_ref.as_deref() { - meta.insert( - "template_ref".to_string(), - toml::Value::String(git_ref.to_string()), - ); - } - if let Some(sha) = source_info.commit_sha.as_deref() { - meta.insert( - "commit_sha".to_string(), - toml::Value::String(sha.to_string()), + toml::Value::String(url.clone()), ); + if let Some(r) = git_ref { + meta.insert("template_ref".to_string(), toml::Value::String(r.clone())); + } + if let Some(sha) = commit_sha { + meta.insert("commit_sha".to_string(), toml::Value::String(sha.clone())); + } } meta.insert( "diecut_version".to_string(), @@ -197,13 +199,13 @@ mod tests { ); variables.insert("enabled".to_string(), Value::Bool(true)); - let source_info = SourceInfo { - url: Some("https://example.com/repo.git".to_string()), + let origin = TemplateOrigin::Git { + url: "https://example.com/repo.git".to_string(), git_ref: Some("v1.0".to_string()), commit_sha: Some("deadbeef".to_string()), }; - write_answers(output_dir.path(), &config, &variables, &source_info).unwrap(); + write_answers(output_dir.path(), &config, &variables, &origin).unwrap(); // Read back and verify let answers_file = output_dir.path().join(".diecut-answers.toml"); @@ -278,13 +280,13 @@ mod tests { Value::String("visible".to_string()), ); - let source_info = SourceInfo { - url: None, - git_ref: None, - commit_sha: None, - }; - - write_answers(output_dir.path(), &config, &variables, &source_info).unwrap(); + write_answers( + output_dir.path(), + &config, + &variables, + &TemplateOrigin::Local, + ) + .unwrap(); let answers_file = output_dir.path().join(".diecut-answers.toml"); let content = fs::read_to_string(&answers_file).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index d57ac83..eb54374 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ use console::style; use tera::Value; use crate::adapter::resolve_template; -use crate::answers::SourceInfo; +use crate::answers::TemplateOrigin; use crate::error::{DicecutError, Result}; use crate::prompt::{collect_variables, PromptOptions}; use crate::render::{build_context, execute_plan, plan_render, GeneratedProject, GenerationPlan}; @@ -35,7 +35,7 @@ pub struct FullGenerationPlan { pub output_dir: PathBuf, pub config: crate::config::schema::TemplateConfig, pub variables: BTreeMap, - pub source_info: SourceInfo, + pub origin: TemplateOrigin, pub template_dir: PathBuf, pub no_hooks: bool, } @@ -46,15 +46,8 @@ pub struct FullGenerationPlan { /// hooks, and rendering) but does **not** write any files to disk. pub fn plan_generation(options: GenerateOptions) -> Result { let source = resolve_source(&options.template)?; - let (template_dir, source_info) = match &source { - TemplateSource::Local(path) => ( - path.clone(), - SourceInfo { - url: None, - git_ref: None, - commit_sha: None, - }, - ), + let (template_dir, origin) = match &source { + TemplateSource::Local(path) => (path.clone(), TemplateOrigin::Local), TemplateSource::Git { url, git_ref, @@ -73,8 +66,8 @@ pub fn plan_generation(options: GenerateOptions) -> Result { }; ( path, - SourceInfo { - url: Some(url.clone()), + TemplateOrigin::Git { + url: url.clone(), git_ref: git_ref.clone(), commit_sha, }, @@ -92,15 +85,20 @@ pub fn plan_generation(options: GenerateOptions) -> Result { ); } - if !options.no_hooks && source_info.url.is_some() && resolved.config.hooks.has_hooks() { + if !options.no_hooks + && matches!(origin, TemplateOrigin::Git { .. }) + && resolved.config.hooks.has_hooks() + { + let url = if let TemplateOrigin::Git { url, .. } = &origin { + url.as_str() + } else { + "unknown" + }; eprintln!( "{} This template contains hooks that will execute code on your machine", style("warning:").yellow().bold() ); - eprintln!( - " source: {}", - source_info.url.as_deref().unwrap_or("unknown") - ); + eprintln!(" source: {url}"); eprintln!(" use --no-hooks to skip hook execution"); } @@ -144,7 +142,7 @@ pub fn plan_generation(options: GenerateOptions) -> Result { output_dir, config: resolved.config, variables, - source_info, + origin, template_dir, no_hooks: options.no_hooks, }) @@ -163,7 +161,7 @@ pub fn execute_generation(plan: FullGenerationPlan) -> Result &plan.output_dir, &plan.config, &plan.variables, - &plan.source_info, + &plan.origin, )?; if !plan.no_hooks { diff --git a/tests/integration.rs b/tests/integration.rs index a283b93..6c9376c 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -219,16 +219,11 @@ fn test_answers_file_written() { let output_dir = tempfile::tempdir().unwrap(); walk_and_render(&resolved, output_dir.path(), &variables, &context).unwrap(); - let source_info = diecut::answers::SourceInfo { - url: None, - git_ref: None, - commit_sha: None, - }; diecut::answers::write_answers( output_dir.path(), &resolved.config, &variables, - &source_info, + &diecut::answers::TemplateOrigin::Local, ) .unwrap();