1use std::collections::{HashMap, HashSet};
6
7#[derive(Debug, Clone)]
9pub struct MigrationBranch {
10 pub name: String,
12 pub base_version: String,
14 pub versions: Vec<String>,
16 pub merged: bool,
18}
19
20impl MigrationBranch {
21 pub fn new(name: String, base_version: String) -> Self {
23 Self {
24 name,
25 base_version,
26 versions: Vec::new(),
27 merged: false,
28 }
29 }
30
31 pub fn add_version(&mut self, version: String) {
33 self.versions.push(version);
34 }
35
36 pub fn mark_merged(&mut self) {
38 self.merged = true;
39 }
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct MergeConflict {
45 pub conflict_type: ConflictType,
47 pub version: String,
49 pub source_branch: String,
51 pub description: String,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
57pub enum ConflictType {
58 VersionConflict,
60 DependencyConflict,
62 SchemaConflict,
64}
65
66pub struct MigrationBranchManager {
68 main_versions: Vec<String>,
70 branches: HashMap<String, MigrationBranch>,
72}
73
74impl MigrationBranchManager {
75 pub fn new() -> Self {
77 Self {
78 main_versions: Vec::new(),
79 branches: HashMap::new(),
80 }
81 }
82
83 pub fn add_main_version(&mut self, version: String) {
85 self.main_versions.push(version);
86 }
87
88 pub fn create_branch(&mut self, name: &str, base_version: &str) -> Result<(), String> {
90 if self.branches.contains_key(name) {
91 return Err(format!("分支 {} 已存在", name));
92 }
93 if !self.main_versions.contains(&base_version.to_string()) {
94 return Err(format!("基线版本 {} 不存在于主干", base_version));
95 }
96 self.branches.insert(
97 name.to_string(),
98 MigrationBranch::new(name.to_string(), base_version.to_string()),
99 );
100 Ok(())
101 }
102
103 pub fn add_branch_version(&mut self, branch: &str, version: String) -> Result<(), String> {
105 let b = self
106 .branches
107 .get_mut(branch)
108 .ok_or_else(|| format!("分支 {} 不存在", branch))?;
109 if b.merged {
110 return Err(format!("分支 {} 已合并,不能添加版本", branch));
111 }
112 b.add_version(version);
113 Ok(())
114 }
115
116 pub fn detect_conflicts(&self, branch: &str) -> Result<Vec<MergeConflict>, String> {
118 let b = self
119 .branches
120 .get(branch)
121 .ok_or_else(|| format!("分支 {} 不存在", branch))?;
122
123 let mut conflicts = Vec::new();
124 let main_set: HashSet<&String> = self.main_versions.iter().collect();
125
126 for version in &b.versions {
127 if main_set.contains(version) {
128 conflicts.push(MergeConflict {
129 conflict_type: ConflictType::VersionConflict,
130 version: version.clone(),
131 source_branch: branch.to_string(),
132 description: format!("版本 {} 与主干版本冲突", version),
133 });
134 }
135 }
136
137 for (other_name, other_branch) in &self.branches {
138 if other_name == branch {
139 continue;
140 }
141 let other_set: HashSet<&String> = other_branch.versions.iter().collect();
142 for version in &b.versions {
143 if other_set.contains(version) {
144 conflicts.push(MergeConflict {
145 conflict_type: ConflictType::VersionConflict,
146 version: version.clone(),
147 source_branch: branch.to_string(),
148 description: format!("版本 {} 与分支 {} 冲突", version, other_name),
149 });
150 }
151 }
152 }
153
154 Ok(conflicts)
155 }
156
157 pub fn merge_branch(&mut self, branch: &str) -> Result<Vec<String>, String> {
159 let conflicts = self.detect_conflicts(branch)?;
160 if !conflicts.is_empty() {
161 return Err(format!("合并失败:检测到 {} 个冲突", conflicts.len()));
162 }
163
164 let b = self
165 .branches
166 .get_mut(branch)
167 .ok_or_else(|| format!("分支 {} 不存在", branch))?;
168 if b.merged {
169 return Err(format!("分支 {} 已合并", branch));
170 }
171
172 let merged_versions = b.versions.clone();
173 for version in &merged_versions {
174 self.main_versions.push(version.clone());
175 }
176 b.mark_merged();
177 Ok(merged_versions)
178 }
179
180 pub fn branches(&self) -> Vec<&MigrationBranch> {
182 self.branches.values().collect()
183 }
184
185 pub fn main_version_count(&self) -> usize {
187 self.main_versions.len()
188 }
189}
190
191impl Default for MigrationBranchManager {
192 fn default() -> Self {
193 Self::new()
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 #[test]
202 fn test_create_branch() {
203 let mut manager = MigrationBranchManager::new();
204 manager.add_main_version("v1".to_string());
205 manager.add_main_version("v2".to_string());
206
207 assert!(manager.create_branch("feature-a", "v1").is_ok());
208 assert!(manager.create_branch("feature-a", "v2").is_err());
209 assert!(manager.create_branch("feature-b", "v3").is_err());
210 }
211
212 #[test]
213 fn test_add_branch_version() {
214 let mut manager = MigrationBranchManager::new();
215 manager.add_main_version("v1".to_string());
216 manager.create_branch("feature-a", "v1").unwrap();
217
218 assert!(manager
219 .add_branch_version("feature-a", "v1.1".to_string())
220 .is_ok());
221 assert!(manager
222 .add_branch_version("nonexistent", "v1.2".to_string())
223 .is_err());
224 }
225
226 #[test]
227 fn test_detect_no_conflicts() {
228 let mut manager = MigrationBranchManager::new();
229 manager.add_main_version("v1".to_string());
230 manager.add_main_version("v2".to_string());
231 manager.create_branch("feature-a", "v1").unwrap();
232 manager
233 .add_branch_version("feature-a", "v1.1".to_string())
234 .unwrap();
235
236 let conflicts = manager.detect_conflicts("feature-a").unwrap();
237 assert!(conflicts.is_empty());
238 }
239
240 #[test]
241 fn test_detect_version_conflict_with_main() {
242 let mut manager = MigrationBranchManager::new();
243 manager.add_main_version("v1".to_string());
244 manager.add_main_version("v2".to_string());
245 manager.create_branch("feature-a", "v1").unwrap();
246 manager
247 .add_branch_version("feature-a", "v2".to_string())
248 .unwrap();
249
250 let conflicts = manager.detect_conflicts("feature-a").unwrap();
251 assert_eq!(conflicts.len(), 1);
252 assert_eq!(conflicts[0].conflict_type, ConflictType::VersionConflict);
253 }
254
255 #[test]
256 fn test_detect_conflict_between_branches() {
257 let mut manager = MigrationBranchManager::new();
258 manager.add_main_version("v1".to_string());
259 manager.create_branch("feature-a", "v1").unwrap();
260 manager.create_branch("feature-b", "v1").unwrap();
261 manager
262 .add_branch_version("feature-a", "v1.1".to_string())
263 .unwrap();
264 manager
265 .add_branch_version("feature-b", "v1.1".to_string())
266 .unwrap();
267
268 let conflicts = manager.detect_conflicts("feature-a").unwrap();
269 assert_eq!(conflicts.len(), 1);
270 assert!(conflicts[0].description.contains("feature-b"));
271 }
272
273 #[test]
274 fn test_merge_branch_success() {
275 let mut manager = MigrationBranchManager::new();
276 manager.add_main_version("v1".to_string());
277 manager.create_branch("feature-a", "v1").unwrap();
278 manager
279 .add_branch_version("feature-a", "v1.1".to_string())
280 .unwrap();
281 manager
282 .add_branch_version("feature-a", "v1.2".to_string())
283 .unwrap();
284
285 let merged = manager.merge_branch("feature-a").unwrap();
286 assert_eq!(merged.len(), 2);
287 assert_eq!(manager.main_version_count(), 3);
288 }
289
290 #[test]
291 fn test_merge_branch_with_conflicts() {
292 let mut manager = MigrationBranchManager::new();
293 manager.add_main_version("v1".to_string());
294 manager.add_main_version("v2".to_string());
295 manager.create_branch("feature-a", "v1").unwrap();
296 manager
297 .add_branch_version("feature-a", "v2".to_string())
298 .unwrap();
299
300 let result = manager.merge_branch("feature-a");
301 assert!(result.is_err());
302 }
303
304 #[test]
305 fn test_merge_already_merged() {
306 let mut manager = MigrationBranchManager::new();
307 manager.add_main_version("v1".to_string());
308 manager.create_branch("feature-a", "v1").unwrap();
309 manager
310 .add_branch_version("feature-a", "v1.1".to_string())
311 .unwrap();
312
313 manager.merge_branch("feature-a").unwrap();
314 let result = manager.merge_branch("feature-a");
315 assert!(result.is_err());
316 }
317
318 #[test]
319 fn test_add_version_after_merge() {
320 let mut manager = MigrationBranchManager::new();
321 manager.add_main_version("v1".to_string());
322 manager.create_branch("feature-a", "v1").unwrap();
323 manager
324 .add_branch_version("feature-a", "v1.1".to_string())
325 .unwrap();
326 manager.merge_branch("feature-a").unwrap();
327
328 let result = manager.add_branch_version("feature-a", "v1.2".to_string());
329 assert!(result.is_err());
330 }
331}