Skip to main content

forge_agent/
commit.rs

1//! Commit engine - Transaction finalization.
2//!
3//! This module implements the commit phase, finalizing verified
4//! transactions with version control integration.
5
6use crate::Result;
7
8/// Committer for transaction finalization.
9///
10/// The Committer handles git integration and metadata persistence.
11#[derive(Clone, Default)]
12pub struct Committer {}
13
14impl Committer {
15    /// Creates a new committer.
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    /// Finalizes a verified transaction.
21    ///
22    /// # Arguments
23    ///
24    /// * `working_dir` - Directory for the operation
25    /// * `modified_files` - Files that were modified
26    pub async fn finalize(
27        &self,
28        _working_dir: &std::path::Path,
29        modified_files: &[std::path::PathBuf],
30    ) -> Result<CommitReport> {
31        // Generate transaction ID using timestamp
32        let now = std::time::SystemTime::now()
33            .duration_since(std::time::UNIX_EPOCH)
34            .map(|d| d.as_secs())
35            .unwrap_or(0);
36
37        let transaction_id = format!("txn-{}", now);
38
39        Ok(CommitReport {
40            transaction_id: transaction_id.clone(),
41            files_committed: modified_files.to_vec(),
42        })
43    }
44
45    /// Generates a commit summary.
46    ///
47    /// # Arguments
48    ///
49    /// * `steps` - Steps that were executed
50    pub fn generate_summary(&self, steps: &[crate::planner::PlanStep]) -> String {
51        let mut summary = String::from("Applied ");
52
53        for (i, step) in steps.iter().enumerate() {
54            if i > 0 {
55                summary.push_str(", ");
56            }
57            summary.push_str(&step.description);
58        }
59
60        summary
61    }
62}
63
64/// Commit report.
65#[derive(Clone, Debug)]
66pub struct CommitReport {
67    /// Transaction ID for the commit
68    pub transaction_id: String,
69    /// Files that were committed
70    pub files_committed: Vec<std::path::PathBuf>,
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use tempfile::TempDir;
77    use forge_core::Forge;
78
79    #[tokio::test]
80    async fn test_committer_creation() {
81        let _committer = Committer::new();
82
83        // Should create successfully
84        assert!(true);
85    }
86
87    #[tokio::test]
88    async fn test_generate_summary() {
89        let committer = Committer::new();
90
91        let steps = vec![
92            crate::planner::PlanStep {
93                description: "Step 1".to_string(),
94                operation: crate::planner::PlanOperation::Inspect {
95                    symbol_id: forge_core::types::SymbolId(1),
96                    symbol_name: "test".to_string(),
97                },
98            },
99            crate::planner::PlanStep {
100                description: "Step 2".to_string(),
101                operation: crate::planner::PlanOperation::Inspect {
102                    symbol_id: forge_core::types::SymbolId(2),
103                    symbol_name: "test2".to_string(),
104                },
105            },
106        ];
107
108        let summary = committer.generate_summary(&steps);
109
110        assert!(summary.contains("Step 1"));
111        assert!(summary.contains("Step 2"));
112    }
113
114    #[tokio::test]
115    async fn test_create_checkpoint() {
116        let temp_dir = TempDir::new().unwrap();
117        let _forge = Forge::open(temp_dir.path()).await.unwrap();
118        let committer = Committer::new();
119
120        let result = committer
121            .finalize(&std::path::PathBuf::new(), &[])
122            .await
123            .unwrap();
124
125        assert!(!result.transaction_id.is_empty());
126        assert!(result.files_committed.is_empty());
127    }
128}