mockforge_core/pr_generation/
templates.rs

1//! PR template generation
2//!
3//! This module provides templates for generating PR titles and descriptions.
4
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8/// Context for PR template generation
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct PRTemplateContext {
11    /// Endpoint affected
12    pub endpoint: String,
13    /// HTTP method
14    pub method: String,
15    /// Number of breaking changes
16    pub breaking_changes: u32,
17    /// Number of non-breaking changes
18    pub non_breaking_changes: u32,
19    /// List of affected files
20    pub affected_files: Vec<String>,
21    /// Change summary
22    pub change_summary: String,
23    /// Whether this is a breaking change
24    pub is_breaking: bool,
25    /// Additional context
26    pub metadata: HashMap<String, serde_json::Value>,
27}
28
29/// PR template generator
30#[derive(Debug, Clone)]
31pub struct PRTemplate;
32
33impl PRTemplate {
34    /// Generate PR title
35    pub fn generate_title(context: &PRTemplateContext) -> String {
36        if context.is_breaking {
37            format!("🚨 [BREAKING] Update contract for {} {}", context.method, context.endpoint)
38        } else {
39            format!("📝 Update contract for {} {}", context.method, context.endpoint)
40        }
41    }
42
43    /// Generate PR body
44    pub fn generate_body(context: &PRTemplateContext) -> String {
45        let mut body = String::new();
46
47        // Header
48        body.push_str("## Contract Update\n\n");
49        body.push_str(&format!(
50            "This PR updates the contract for `{} {}`\n\n",
51            context.method, context.endpoint
52        ));
53
54        // Breaking changes warning
55        if context.is_breaking {
56            body.push_str("### ⚠️ Breaking Changes Detected\n\n");
57            body.push_str(&format!(
58                "This update includes **{} breaking change(s)**. Please review carefully.\n\n",
59                context.breaking_changes
60            ));
61        }
62
63        // Change summary
64        body.push_str("### Change Summary\n\n");
65        body.push_str(&context.change_summary);
66        body.push_str("\n\n");
67
68        // Statistics
69        body.push_str("### Statistics\n\n");
70        body.push_str(&format!("- Breaking changes: {}\n", context.breaking_changes));
71        body.push_str(&format!("- Non-breaking changes: {}\n", context.non_breaking_changes));
72        body.push_str(&format!(
73            "- Total changes: {}\n\n",
74            context.breaking_changes + context.non_breaking_changes
75        ));
76
77        // Affected files
78        if !context.affected_files.is_empty() {
79            body.push_str("### Affected Files\n\n");
80            for file in &context.affected_files {
81                body.push_str(&format!("- `{}`\n", file));
82            }
83            body.push_str("\n");
84        }
85
86        // Testing instructions
87        body.push_str("### Testing Instructions\n\n");
88        body.push_str("Please verify that:\n");
89        body.push_str("- [ ] All affected endpoints still work correctly\n");
90        if context.is_breaking {
91            body.push_str("- [ ] Breaking changes are documented\n");
92            body.push_str("- [ ] Consumers have been notified\n");
93        }
94        body.push_str("- [ ] Mock fixtures are updated\n");
95        body.push_str("- [ ] Generated clients are updated\n");
96        body.push_str("- [ ] Example tests pass\n\n");
97
98        // Footer
99        body.push_str("---\n");
100        body.push_str("*This PR was automatically generated by MockForge*\n");
101
102        body
103    }
104}