Commit 66e49c5
committed
691a1c7 refactor: [#40] use struct-based template generation instead of hardcoded strings (copilot-swe-agent[bot])
913e9be fix: [#40] make template validation extensible for future formats (copilot-swe-agent[bot])
72d08b1 feat: [#40] implement infrastructure templates module (copilot-swe-agent[bot])
d8a99f7 Initial plan (copilot-swe-agent[bot])
Pull request description:
Implements template generation for JSON configuration files using struct-based generation instead of hardcoded strings, following the domain-driven design approach.
## Implementation
**Module: `src/domain/config/environment_config.rs`**
Added two methods to `EnvironmentCreationConfig`:
- `template()` - Creates a configuration instance with placeholder values
- `generate_template_file()` - Async file generation with directory creation
**Error Handling: `src/domain/config/errors.rs`**
Extended `CreateConfigError` with template generation error variants:
- `TemplateSerializationFailed` - JSON serialization errors
- `TemplateDirectoryCreationFailed` - Directory creation failures
- `TemplateFileWriteFailed` - File write errors
All errors include `.help()` methods with actionable troubleshooting guidance.
## Template Design
Uses simple `REPLACE_WITH_*` placeholders for user clarity:
```json
{
"environment": {
"name": "REPLACE_WITH_ENVIRONMENT_NAME"
},
"ssh_credentials": {
"private_key_path": "REPLACE_WITH_SSH_PRIVATE_KEY_PATH",
"public_key_path": "REPLACE_WITH_SSH_PUBLIC_KEY_PATH",
"username": "torrust",
"port": 22
}
}
```
## API
```rust
use torrust_tracker_deployer_lib::domain::config::EnvironmentCreationConfig;
use std::path::Path;
// Get template instance with placeholders
let template = EnvironmentCreationConfig::template();
// Generate template file at specific path
EnvironmentCreationConfig::generate_template_file(
Path::new("./config.json")
).await?;
```
## Architecture Benefits
- **Type-Safe**: Compiler guarantees template structure matches `EnvironmentCreationConfig`
- **Zero Duplication**: Struct definition IS the template - no separate strings to maintain
- **Auto-Synced**: Adding/removing fields automatically updates template
- **Guaranteed Valid JSON**: `serde_json` ensures serialization correctness
- **Domain Layer**: Template generation lives with domain model, not infrastructure
## Testing
- ✅ 11 new tests (8 for template generation, 3 for error handling)
- ✅ 962 total tests passing
- ✅ All linters passing
**Integration:** Ready for CLI `--generate-template` flag (Issue #37)
- Fixes #40
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>[Subissue 6/7] Template System Integration (Optional)</issue_title>
> <issue_description>**Parent Epic**: #34 - Implement Create Environment Command
> **Status**: OPTIONAL ENHANCEMENT
> **Estimated Time**: 2-3 hours
>
> > ⚠️ **Note**: This is an optional enhancement that can be deferred. It is not required for the MVP functionality of the create command.
>
> ## Overview
>
> Implement the template system for configuration file generation in the infrastructure layer. This system provides embedded JSON configuration templates that can be generated on-demand, supporting the `--generate-template` functionality with proper error handling and validation.
>
> ## Goals
>
> - [ ] Extend existing `TemplateManager` from `src/domain/template/embedded.rs` for configuration templates
> - [ ] Use existing template infrastructure - no duplication needed
> - [ ] Add configuration template types to existing embedded template system
> - [ ] Leverage existing rust-embed pattern in `templates/` directory structure
> - [ ] Use existing `TemplateManagerError` for error handling
> - [ ] Add configuration templates to existing template structure
> - [ ] Add to existing `templates/` directory following existing patterns
> - [ ] Use existing Tera variable syntax: `{{ variable_name }}` (not `{ { variable_name } }`)
> - [ ] Follow existing template embedding and extraction patterns
> - [ ] Add `--generate-template` functionality using existing template infrastructure
> - [ ] Add unit tests that integrate with existing template system
>
> ## Architecture Requirements
>
> **DDD Layer**: Infrastructure Layer (`src/infrastructure/templates/`)
> **Pattern**: Template Provider + Embedded Resources + File Operations
> **Dependencies**: None (infrastructure concern)
>
> ## Template Example
>
> ```json
> {
> "environment": {
> "name": "{{ environment_name }}"
> },
> "ssh_credentials": {
> "private_key_path": "{{ ssh_private_key_path }}",
> "public_key_path": "{{ ssh_public_key_path }}",
> "username": "{{ ssh_username }}",
> "port": {{ ssh_port }}
> }
> }
> ```
>
> ## Acceptance Criteria
>
> - [ ] Template provider extends existing `TemplateManager` infrastructure
> - [ ] Templates use correct Tera variable syntax: `{{ variable }}`
> - [ ] Templates generate valid JSON files
> - [ ] Error handling follows tiered help system pattern
> - [ ] Unit tests verify template generation works correctly
> - [ ] Integration tests verify file system operations
> - [ ] Templates are embedded in binary using existing rust-embed pattern
>
> ## Implementation Notes
>
> - Reuse existing `TemplateManager` from `src/domain/template/embedded.rs`
> - Add configuration templates to `templates/` directory structure
> - Use existing error types from template system
> - Follow patterns established in OpenTofu/Ansible template management
>
> For detailed specification, see: [docs/issues/epic-create-environment-command-subissue-6-template-system-integration.md](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/issues/epic-create-environment-command-subissue-6-template-system-integration.md)</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
- Fixes #40
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.
ACKs for top commit:
josecelano:
ACK 691a1c7
Tree-SHA512: c2c9d4d0902e4aded93c49fe6d169cc0c1afed964dc371f805fdc51ea4169790b53b8bd475abbf6119ef571e50cad3d7903d289792d5550e4ead146d3b7a3a73
2 files changed
+326
-0
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
155 | 249 | | |
156 | 250 | | |
157 | 251 | | |
| |||
419 | 513 | | |
420 | 514 | | |
421 | 515 | | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
422 | 640 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
38 | 61 | | |
39 | 62 | | |
40 | 63 | | |
| |||
59 | 82 | | |
60 | 83 | | |
61 | 84 | | |
| 85 | + | |
62 | 86 | | |
63 | 87 | | |
64 | 88 | | |
| |||
129 | 153 | | |
130 | 154 | | |
131 | 155 | | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
132 | 201 | | |
133 | 202 | | |
134 | 203 | | |
| |||
214 | 283 | | |
215 | 284 | | |
216 | 285 | | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
217 | 325 | | |
0 commit comments