use crate::error::AppError; use crate::models::common::MergeStrategyKind; use crate::models::prs::PrMergeStrategy; use crate::service::PrService; use crate::session::Session; use super::util::parse_enum; #[derive(serde::Deserialize, serde::Serialize, Clone, Debug, utoipa::ToSchema)] pub struct UpdateMergeStrategyParams { pub strategy: Option, pub auto_merge: Option, pub squash_title: Option, pub squash_message: Option, pub delete_source_branch: Option, pub merge_when_checks_pass: Option, } impl PrService { pub async fn pr_merge_strategy( &self, ctx: &Session, wk_name: &str, repo_name: &str, number: i64, ) -> Result { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let pr = self.resolve_pr(wk_name, repo_name, number).await?; self.ensure_pr_readable(user_uid, &pr).await?; sqlx::query_as::<_, PrMergeStrategy>( "SELECT pull_request_id, strategy, auto_merge, squash_title, squash_message, \ delete_source_branch, merge_when_checks_pass, selected_by, created_at, updated_at \ FROM pr_merge_strategy WHERE pull_request_id = $1", ) .bind(pr.id) .fetch_optional(self.ctx.db.reader()) .await .map_err(AppError::Database)? .ok_or(AppError::NotFound("PR merge strategy not found".into())) } pub async fn pr_update_merge_strategy( &self, ctx: &Session, wk_name: &str, repo_name: &str, number: i64, params: UpdateMergeStrategyParams, ) -> Result { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let pr = self.resolve_pr(wk_name, repo_name, number).await?; self.ensure_pr_editable(user_uid, &pr).await?; let current = sqlx::query_as::<_, PrMergeStrategy>( "SELECT pull_request_id, strategy, auto_merge, squash_title, squash_message, \ delete_source_branch, merge_when_checks_pass, selected_by, created_at, updated_at \ FROM pr_merge_strategy WHERE pull_request_id = $1", ) .bind(pr.id) .fetch_optional(self.ctx.db.reader()) .await .map_err(AppError::Database)?; let strategy = match params.strategy { Some(ref v) => parse_enum( Some(v.clone()), current .as_ref() .map(|c| c.strategy) .unwrap_or(MergeStrategyKind::Merge), MergeStrategyKind::Unknown, "strategy", )?, None => current .as_ref() .map(|c| c.strategy) .unwrap_or(MergeStrategyKind::Merge), }; let auto_merge = params .auto_merge .or(current.as_ref().map(|c| c.auto_merge)) .unwrap_or(false); let squash_title = params .squash_title .or_else(|| current.as_ref().and_then(|c| c.squash_title.clone())); let squash_message = params .squash_message .or_else(|| current.as_ref().and_then(|c| c.squash_message.clone())); let delete_source_branch = params .delete_source_branch .or(current.as_ref().map(|c| c.delete_source_branch)) .unwrap_or(false); let merge_when_checks_pass = params .merge_when_checks_pass .or(current.as_ref().map(|c| c.merge_when_checks_pass)) .unwrap_or(false); let now = chrono::Utc::now(); if current.is_some() { sqlx::query_as::<_, PrMergeStrategy>( "UPDATE pr_merge_strategy SET strategy = $1, auto_merge = $2, squash_title = $3, \ squash_message = $4, delete_source_branch = $5, merge_when_checks_pass = $6, \ selected_by = $7, updated_at = $8 WHERE pull_request_id = $9 \ RETURNING pull_request_id, strategy, auto_merge, squash_title, squash_message, \ delete_source_branch, merge_when_checks_pass, selected_by, created_at, updated_at", ) .bind(strategy) .bind(auto_merge) .bind(squash_title.as_deref()) .bind(squash_message.as_deref()) .bind(delete_source_branch) .bind(merge_when_checks_pass) .bind(user_uid) .bind(now) .bind(pr.id) .fetch_one(self.ctx.db.writer()) .await .map_err(AppError::Database) } else { sqlx::query_as::<_, PrMergeStrategy>( "INSERT INTO pr_merge_strategy (pull_request_id, strategy, auto_merge, squash_title, \ squash_message, delete_source_branch, merge_when_checks_pass, selected_by, created_at, updated_at) \ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $9) \ RETURNING pull_request_id, strategy, auto_merge, squash_title, squash_message, \ delete_source_branch, merge_when_checks_pass, selected_by, created_at, updated_at", ) .bind(pr.id).bind(strategy).bind(auto_merge).bind(squash_title.as_deref()).bind(squash_message.as_deref()) .bind(delete_source_branch).bind(merge_when_checks_pass).bind(user_uid).bind(now) .fetch_one(self.ctx.db.writer()).await.map_err(AppError::Database) } } }