metis_docs_cli/commands/
archive.rs1use crate::workspace;
2use anyhow::Result;
3use clap::Args;
4use metis_core::application::services::workspace::ArchiveService;
5
6#[derive(Args)]
7pub struct ArchiveCommand {
8 pub short_code: String,
10
11 #[arg(short = 't', long)]
13 pub document_type: Option<String>,
14}
15
16impl ArchiveCommand {
17 pub async fn execute(&self) -> Result<()> {
18 let (workspace_exists, metis_dir) = workspace::has_metis_vault();
20 if !workspace_exists {
21 anyhow::bail!("Not in a Metis workspace. Run 'metis init' to create one.");
22 }
23 let metis_dir = metis_dir.unwrap();
24
25 let db = metis_core::dal::Database::new(&metis_dir.join("metis.db").to_string_lossy())
27 .map_err(|e| anyhow::anyhow!("Database initialization failed: {}", e))?;
28 let mut db_service =
29 metis_core::application::services::DatabaseService::new(db.into_repository());
30 let archive_service = ArchiveService::new(&metis_dir);
31
32 let mut sync_service = metis_core::application::services::SyncService::new(&mut db_service)
34 .with_workspace_dir(&metis_dir);
35 sync_service
36 .sync_directory(&metis_dir)
37 .await
38 .map_err(|e| anyhow::anyhow!("Failed to sync workspace: {}", e))?;
39
40 let archive_result = archive_service
42 .archive_document_by_short_code(&self.short_code, &mut db_service)
43 .await?;
44
45 println!("✓ Archived {} documents:", archive_result.total_archived);
47 for doc in archive_result.archived_documents {
48 println!(" - {} ({})", doc.document_id, doc.document_type);
49 }
50
51 println!("Archive completed.");
53
54 Ok(())
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use crate::commands::InitCommand;
62 use tempfile::tempdir;
63
64 #[tokio::test]
65 async fn test_archive_command_no_workspace() {
66 let temp_dir = tempdir().unwrap();
67 let original_dir = std::env::current_dir().ok();
68
69 if std::env::set_current_dir(temp_dir.path()).is_err() {
71 return; }
73
74 let cmd = ArchiveCommand {
75 short_code: "TEST-T-0001".to_string(),
76 document_type: None,
77 };
78
79 let result = cmd.execute().await;
80
81 if let Some(original) = original_dir {
83 let _ = std::env::set_current_dir(&original);
84 }
85
86 assert!(result.is_err());
87 assert!(result
88 .unwrap_err()
89 .to_string()
90 .contains("Not in a Metis workspace"));
91 }
92
93 #[tokio::test]
94 async fn test_archive_document_not_found() {
95 let temp_dir = tempdir().unwrap();
96 let original_dir = std::env::current_dir().ok();
97
98 std::env::set_current_dir(temp_dir.path()).unwrap();
100
101 let init_cmd = InitCommand {
103 name: Some("Test Project".to_string()),
104 prefix: None,
105 preset: None,
106 strategies: None,
107 initiatives: None,
108 };
109 init_cmd.execute().await.unwrap();
110
111 let cmd = ArchiveCommand {
112 short_code: "TEST-T-9999".to_string(),
113 document_type: None,
114 };
115
116 let result = cmd.execute().await;
117
118 if let Some(original) = original_dir {
120 let _ = std::env::set_current_dir(&original);
121 }
122
123 assert!(result.is_err());
124 assert!(result.unwrap_err().to_string().contains("not found"));
125 }
126
127 #[tokio::test]
128 async fn test_archive_vision_document() {
129 let temp_dir = tempdir().unwrap();
130 let original_dir = std::env::current_dir().ok();
131
132 std::env::set_current_dir(temp_dir.path()).unwrap();
134
135 let init_cmd = InitCommand {
137 name: Some("Test Project".to_string()),
138 prefix: None,
139 preset: None,
140 strategies: None,
141 initiatives: None,
142 };
143 init_cmd.execute().await.unwrap();
144
145 let metis_dir = temp_dir.path().join(".metis");
146 let vision_path = metis_dir.join("vision.md");
147 let archived_vision_path = metis_dir.join("archived").join("vision.md");
148
149 assert!(vision_path.exists());
151 assert!(!archived_vision_path.exists());
152
153 let cmd = ArchiveCommand {
154 short_code: "TEST-V-0001".to_string(),
155 document_type: Some("vision".to_string()),
156 };
157
158 let result = cmd.execute().await;
159
160 if let Some(original) = original_dir {
162 let _ = std::env::set_current_dir(&original);
163 }
164
165 assert!(result.is_ok(), "Archive failed: {:?}", result.err());
166
167 assert!(!vision_path.exists());
169 assert!(archived_vision_path.exists());
170
171 let archived_content = std::fs::read_to_string(&archived_vision_path).unwrap();
173 assert!(archived_content.contains("archived: true"));
174 }
175}