use crate::db::pool; use crate::models::GitRepo; use rusqlite::params; use serde::Deserialize; // ── 输入结构体 ───────────────────────────────────────────────────────────────── #[derive(Debug, Deserialize)] pub struct ImportGitRepoInput { pub id: String, pub repo_url: String, pub name: String, pub description: Option, pub default_branch: Option, pub upstream_url: Option, pub tech_stack: Option, } #[derive(Debug, Deserialize)] pub struct UpdateGitRepoDeployInput { pub staging_url: Option, pub prod_url: Option, pub server_note: Option, pub upstream_url: Option, pub tech_stack: Option, pub status: Option, pub priority: Option, } #[derive(Debug, Deserialize)] pub struct MountRepoInput { /// 新 workspace 的 id(前端传 UUID) pub workspace_id: String, pub repo_id: String, pub space_id: Option, pub win_path: Option, pub wsl_path: Option, pub platform: Option, } // ── 命令实现 ─────────────────────────────────────────────────────────────────── /// 获取所有已注册仓库 #[tauri::command] pub fn get_git_repos() -> Result, String> { let conn = pool().get().map_err(|e| e.to_string())?; let mut stmt = conn .prepare("SELECT * FROM git_repos ORDER BY created_at DESC") .map_err(|e| e.to_string())?; let rows = stmt .query_map([], GitRepo::from_row) .map_err(|e| e.to_string())? .collect::>>() .map_err(|e| e.to_string())?; Ok(rows) } /// 批量导入 GitHub 仓库(INSERT OR IGNORE,幂等) #[tauri::command] pub fn import_git_repos(repos: Vec) -> Result, String> { let conn = pool().get().map_err(|e| e.to_string())?; let mut imported = Vec::new(); for r in repos { let affected = conn .execute( "INSERT OR IGNORE INTO git_repos (id, repo_url, name, description, default_branch, upstream_url, tech_stack, last_synced_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, datetime('now'))", params![ r.id, r.repo_url, r.name, r.description, r.default_branch, r.upstream_url, r.tech_stack, ], ) .map_err(|e| e.to_string())?; if affected > 0 { imported.push(r.id); } } Ok(imported) } /// 更新仓库部署信息(staging_url, prod_url, server_note, upstream_url 等) #[tauri::command] pub fn update_git_repo_deploy(id: String, input: UpdateGitRepoDeployInput) -> Result<(), String> { let conn = pool().get().map_err(|e| e.to_string())?; conn.execute( "UPDATE git_repos SET staging_url = COALESCE(?2, staging_url), prod_url = COALESCE(?3, prod_url), server_note = COALESCE(?4, server_note), upstream_url = COALESCE(?5, upstream_url), tech_stack = COALESCE(?6, tech_stack), status = COALESCE(?7, status), priority = COALESCE(?8, priority) WHERE id = ?1", params![ id, input.staging_url, input.prod_url, input.server_note, input.upstream_url, input.tech_stack, input.status, input.priority, ], ) .map_err(|e| e.to_string())?; Ok(()) } /// 将仓库挂载到某个空间(创建 workspace + profile) #[tauri::command] pub fn mount_repo(input: MountRepoInput) -> Result<(), String> { let conn = pool().get().map_err(|e| e.to_string())?; // 读取 git_repo 基础信息 let repo: GitRepo = conn .query_row( "SELECT * FROM git_repos WHERE id = ?1", params![input.repo_id], GitRepo::from_row, ) .map_err(|e| format!("仓库不存在: {e}"))?; let profile_id = format!("prof-{}", input.workspace_id); // 创建 project_profile(若已存在则忽略) conn.execute( "INSERT OR IGNORE INTO project_profiles (id, name, description, repo_url, upstream_url, default_branch, staging_url, prod_url, server_note, status, priority, tech_stack) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)", params![ profile_id, repo.name, repo.description, repo.repo_url, repo.upstream_url, repo.default_branch, repo.staging_url, repo.prod_url, repo.server_note, repo.status.as_deref().unwrap_or("active"), repo.priority.as_deref().unwrap_or("mid"), repo.tech_stack, ], ) .map_err(|e| e.to_string())?; let platform = input.platform.as_deref().unwrap_or("windows"); // 创建 project_workspace(若同一 space 已挂载则报错) conn.execute( "INSERT INTO project_workspaces (id, profile_id, repo_id, space_id, win_path, wsl_path, platform) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", params![ input.workspace_id, profile_id, input.repo_id, input.space_id, input.win_path, input.wsl_path, platform, ], ) .map_err(|e| { if e.to_string().contains("UNIQUE") { "该仓库已在此空间中挂载".to_string() } else { e.to_string() } })?; Ok(()) } /// 删除仓库注册记录(同时删除关联的 workspace/profile) #[tauri::command] pub fn delete_git_repo(id: String) -> Result<(), String> { let conn = pool().get().map_err(|e| e.to_string())?; conn.execute("DELETE FROM git_repos WHERE id = ?1", params![id]) .map_err(|e| e.to_string())?; Ok(()) }