use std::{path::Path, sync::Arc};
use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder;
use crate::{
diagnostic::Diagnostic,
ir::{AccountId, AttributeMap, Map, Region, Span},
};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct IncludePath {
#[serde(with = "crate::ir::path_serde::arc_path")]
pub path: Arc<Path>,
#[builder(default)]
pub label: Option<Arc<str>>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct GenerateBlock {
pub label: Arc<str>,
#[serde(with = "crate::ir::path_serde::arc_path")]
pub path: Arc<Path>,
pub if_exists: Arc<str>,
pub contents: Arc<str>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct DependencyBlock {
pub name: Arc<str>,
#[serde(with = "crate::ir::path_serde::arc_path")]
pub config_path: Arc<Path>,
#[builder(default)]
pub mock_outputs: AttributeMap,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct StateBackend {
pub kind: Arc<str>,
pub attributes: AttributeMap,
#[builder(default)]
pub state_account_id: Option<AccountId>,
#[builder(default)]
pub state_region: Option<Region>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct TerragruntConfig {
#[serde(with = "crate::ir::path_serde::arc_path")]
pub component_dir: Arc<Path>,
#[builder(default)]
pub effective_locals: Map,
#[builder(default)]
pub inputs: Map,
#[builder(default)]
pub includes: Vec<IncludePath>,
#[builder(default)]
pub generates: Vec<GenerateBlock>,
#[builder(default)]
pub dependencies: Vec<DependencyBlock>,
#[builder(default)]
pub state_backend: Option<StateBackend>,
#[builder(default)]
pub diagnostics: Vec<Diagnostic>,
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use std::path::PathBuf;
use super::*;
use crate::ir::Span;
#[test]
fn test_should_build_minimal_terragrunt_config() {
let cfg = TerragruntConfig::builder()
.component_dir(Arc::<Path>::from(PathBuf::from("/repo/services/x")))
.build();
assert!(cfg.effective_locals.is_empty());
assert!(cfg.includes.is_empty());
}
#[test]
fn test_should_serde_round_trip_generate_block() {
let g = GenerateBlock {
label: Arc::<str>::from("backend"),
path: Arc::<Path>::from(PathBuf::from("generated_backend.tf")),
if_exists: Arc::<str>::from("overwrite_terragrunt"),
contents: Arc::<str>::from("terraform { backend \"s3\" {} }"),
span: Span::synthetic(),
};
let json = serde_json::to_string(&g).unwrap();
let back: GenerateBlock = serde_json::from_str(&json).unwrap();
assert_eq!(g, back);
}
}