Files
appks/service/pr/merge_strategy.rs
T
2026-06-07 11:30:56 +08:00

133 lines
5.4 KiB
Rust

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<String>,
pub auto_merge: Option<bool>,
pub squash_title: Option<String>,
pub squash_message: Option<String>,
pub delete_source_branch: Option<bool>,
pub merge_when_checks_pass: Option<bool>,
}
impl PrService {
pub async fn pr_merge_strategy(
&self,
ctx: &Session,
wk_name: &str,
repo_name: &str,
number: i64,
) -> Result<PrMergeStrategy, AppError> {
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<PrMergeStrategy, AppError> {
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)
}
}
}