Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ceres/src/api_service/import_api_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ impl ImportApiService {
search_item: &TreeItem,
cache: &mut GitObjectCache,
) -> Result<bool, GitError> {
let relative_path = self.strip_relative(path).unwrap();
let relative_path = self.strip_relative(path)?;
let mut search_tree = root_tree;
// first find search tree by path
for component in relative_path.components() {
Expand Down
3 changes: 2 additions & 1 deletion ceres/src/api_service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ pub trait ApiHandler: Send + Sync {

async fn get_commit_by_hash(&self, hash: &str) -> Option<Commit>;

async fn get_tree_relate_commit(&self, t_hash: SHA1, path: PathBuf) -> Result<Commit, GitError>;
async fn get_tree_relate_commit(&self, t_hash: SHA1, path: PathBuf)
-> Result<Commit, GitError>;

async fn get_commits_by_hashes(&self, c_hashes: Vec<String>) -> Result<Vec<Commit>, GitError>;

Expand Down
3 changes: 0 additions & 3 deletions ceres/src/api_service/mono_api_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ use crate::api_service::ApiHandler;
use crate::model::git::CreateFileInfo;
use crate::model::mr::MrDiffFile;


#[derive(Clone)]
pub struct MonoApiService {
pub storage: Storage,
Expand Down Expand Up @@ -500,7 +499,6 @@ impl MonoApiService {
}
}


if !failed_hashes.is_empty() {
tracing::warn!(
"Failed to fetch {} blob(s): {:?}",
Expand Down Expand Up @@ -531,7 +529,6 @@ impl MonoApiService {
.await;

Ok(diff_output)

}

fn collect_page_blobs(
Expand Down
1 change: 1 addition & 0 deletions ceres/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod api_service;
pub mod lfs;
pub mod merge_checker;
pub mod model;
pub mod pack;
pub mod protocol;
116 changes: 116 additions & 0 deletions ceres/src/merge_checker/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use std::{collections::HashMap, sync::Arc};

use async_trait::async_trait;
use serde::Serialize;
use utoipa::ToSchema;

use callisto::{check_result, sea_orm_active_enums::CheckTypeEnum};
use common::errors::MegaError;
use jupiter::{model::mr_dto::MrInfoDto, storage::Storage};

use crate::merge_checker::mr_sync_checker::MrSyncChecker;

pub mod mr_sync_checker;

#[async_trait]
pub trait Checker: Send + Sync {
async fn run(&self, params: &serde_json::Value) -> CheckResult;

async fn build_params(&self, mr_info: &MrInfoDto) -> Result<serde_json::Value, MegaError>;
}

#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, ToSchema)]
pub enum CheckType {
GpgSignature,
BranchProtection,
CommitMessage,
MrSync,
MergeConflict,
CiStatus,
CodeReview,
}

impl From<CheckTypeEnum> for CheckType {
fn from(value: CheckTypeEnum) -> Self {
match value {
CheckTypeEnum::GpgSignature => CheckType::GpgSignature,
CheckTypeEnum::BranchProtection => CheckType::BranchProtection,
CheckTypeEnum::CommitMessage => CheckType::CommitMessage,
CheckTypeEnum::MrSync => CheckType::MrSync,
CheckTypeEnum::MergeConflict => CheckType::MergeConflict,
CheckTypeEnum::CiStatus => CheckType::CiStatus,
CheckTypeEnum::CodeReview => CheckType::CodeReview,
}
}
}

impl From<CheckType> for CheckTypeEnum {
fn from(value: CheckType) -> Self {
match value {
CheckType::GpgSignature => CheckTypeEnum::GpgSignature,
CheckType::BranchProtection => CheckTypeEnum::BranchProtection,
CheckType::CommitMessage => CheckTypeEnum::CommitMessage,
CheckType::MrSync => CheckTypeEnum::MrSync,
CheckType::MergeConflict => CheckTypeEnum::MergeConflict,
CheckType::CiStatus => CheckTypeEnum::CiStatus,
CheckType::CodeReview => CheckTypeEnum::CodeReview,
}
}
}

#[derive(Debug)]
pub struct CheckResult {
pub check_type_code: CheckType,
pub status: String,
pub message: String,
}

pub struct CheckerRegistry {
checkers: HashMap<CheckType, Box<dyn Checker>>,
storage: Arc<Storage>,
}

impl CheckerRegistry {
pub fn new(storage: Arc<Storage>) -> Self {
let mut r = CheckerRegistry {
checkers: HashMap::new(),
storage: storage.clone(),
};
r.register(CheckType::MrSync, Box::new(MrSyncChecker { storage }));
r
}

pub fn register(&mut self, check_type: CheckType, checker: Box<dyn Checker>) {
self.checkers.insert(check_type, checker);
}

pub async fn run_checks(&self, mr_info: MrInfoDto) -> Result<(), MegaError> {
let check_configs = self
.storage
.mr_storage()
.get_checks_config_by_path(&mr_info.path)
.await?;
let mut save_models = vec![];

for c_config in check_configs {
if let Some(checker) = self.checkers.get(&c_config.check_type_code.into()) {
let params = checker.build_params(&mr_info).await?;
let res = checker.run(&params).await;
let model = check_result::Model::new(
&mr_info.path,
&mr_info.link,
&mr_info.to_hash,
res.check_type_code.into(),
&res.status,
&res.message,
);
save_models.push(model);
}
}
self.storage
.mr_storage()
.save_check_results(save_models)
.await?;
Ok(())
}
}
58 changes: 58 additions & 0 deletions ceres/src/merge_checker/mr_sync_checker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use std::sync::Arc;

use async_trait::async_trait;
use serde::Deserialize;

use common::errors::MegaError;
use jupiter::{model::mr_dto::MrInfoDto, storage::Storage};

use crate::merge_checker::{CheckResult, CheckType, Checker};

pub struct MrSyncChecker {
pub storage: Arc<Storage>,
}

#[derive(Debug, Deserialize)]
pub(crate) struct MrSyncParams {
mr_from: String,
current: String,
}

impl MrSyncParams {
fn from_value(v: &serde_json::Value) -> anyhow::Result<Self> {
Ok(serde_json::from_value(v.clone())?)
}
}

#[async_trait]
impl Checker for MrSyncChecker {
async fn run(&self, params: &serde_json::Value) -> CheckResult {
let params = MrSyncParams::from_value(params).expect("parse params err");

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "parse params err" is not descriptive. Consider using a more helpful message like "Failed to parse MR sync parameters" to help with debugging.

Suggested change
let params = MrSyncParams::from_value(params).expect("parse params err");
let params = MrSyncParams::from_value(params).expect("Failed to parse MR sync parameters");

Copilot uses AI. Check for mistakes.
let mut res = CheckResult {
check_type_code: CheckType::MrSync,
status: String::from("PENDING"),
message: String::new(),
};
if params.mr_from == params.current {
res.status = String::from("PASSED");
} else {
res.status = String::from("FAILED");
res.message =
String::from("The pull request must not have any unresolved merge conflicts");
}
res
}

async fn build_params(&self, mr_info: &MrInfoDto) -> Result<serde_json::Value, MegaError> {
let refs = self
.storage
.mono_storage()
.get_ref(&mr_info.path)
.await?
.expect("Err: MR Related Refs Not Found");
Ok(serde_json::json!({
"mr_from": mr_info.from_hash,
"current": refs.ref_commit_hash
}))
}
}
72 changes: 41 additions & 31 deletions ceres/src/pack/monorepo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use mercury::{

use crate::{
api_service::{mono_api_service::MonoApiService, ApiHandler},
merge_checker::CheckerRegistry,
model::mr::BuckFile,
pack::RepoHandler,
protocol::import_refs::{RefCommand, Refs},
Expand Down Expand Up @@ -343,10 +344,10 @@ impl RepoHandler for MonoRepo {
}

async fn post_mr_operation(&self) -> Result<(), MegaError> {
if self.bellatrix.enable_build() {
let link_guard = self.mr_link.read().await;
let mr = link_guard.as_ref().unwrap();
let link_guard = self.mr_link.read().await;
let link = link_guard.as_ref().unwrap();

if self.bellatrix.enable_build() {
let buck_files = self.search_buck_under_mr(&self.path).await?;
if buck_files.is_empty() {
tracing::error!(
Expand All @@ -359,7 +360,7 @@ impl RepoHandler for MonoRepo {
repo: buck_file.path.to_str().unwrap().to_string(),
buck_hash: buck_file.buck.to_string(),
buckconfig_hash: buck_file.buck_config.to_string(),
mr: mr.to_string(),
mr: link.to_string(),
args: Some(vec![]),
};
let bellatrix = self.bellatrix.clone();
Expand All @@ -369,6 +370,15 @@ impl RepoHandler for MonoRepo {
}
}
}
let mr_info = self
.storage
.mr_storage()
.get_mr(link)
.await?
.expect("MR Not Found");

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "MR Not Found" should be more descriptive and follow consistent formatting. Consider using "Failed to find MR" or a similar message that provides more context.

Suggested change
.expect("MR Not Found");
.expect(&format!("Failed to find MR for link: {}", link));

Copilot uses AI. Check for mistakes.

let check_reg = CheckerRegistry::new(self.storage.clone().into());
check_reg.run_checks(mr_info.into()).await?;
Ok(())
}

Expand Down Expand Up @@ -413,37 +423,37 @@ impl MonoRepo {
async fn update_existing_mr(&self, mr: mega_mr::Model) -> Result<(), MegaError> {
let mr_stg = self.storage.mr_storage();
let comment_stg = self.storage.conversation_storage();
if mr.from_hash == self.from_hash {
if mr.to_hash != self.to_hash {
comment_stg
.add_conversation(
&mr.link,
&self.username(),
Some(format!(
"{} updated the mr automatic from {} to {}",
self.username(),
&mr.to_hash[..6],
&self.to_hash[..6]
)),
ConvTypeEnum::ForcePush,
)
.await?;
mr_stg.update_mr_to_hash(mr, &self.to_hash).await?;
} else {
tracing::info!("repeat commit with mr: {}, do nothing", mr.id);
}
} else {
// TODO 直接覆盖?

let from_same = mr.from_hash == self.from_hash;
let to_same = mr.to_hash == self.to_hash;

if from_same && to_same {
tracing::info!("repeat commit with mr: {}, do nothing", mr.id);
return Ok(());
}

if from_same {
let username = self.username();
let old_hash = &mr.to_hash[..6];
let new_hash = &self.to_hash[..6];

comment_stg
.add_conversation(
&mr.link,
&self.username(),
Some(format!("{} closed MR due to conflict", self.username(),)),
ConvTypeEnum::Closed,
&username,
Some(format!(
"{} updated the mr automatic from {} to {}",
username, old_hash, new_hash
)),
ConvTypeEnum::ForcePush,
)
.await
.unwrap();
mr_stg.close_mr(mr).await?;
.await?;

mr_stg.update_mr_to_hash(mr, &self.to_hash).await?;
} else {
mr_stg
.update_mr_hash(mr, &self.from_hash, &self.to_hash)
.await?;
}
Ok(())
}
Expand Down
25 changes: 25 additions & 0 deletions jupiter/callisto/src/check_result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.14

use super::sea_orm_active_enums::CheckTypeEnum;
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "check_result")]
pub struct Model {
pub created_at: DateTime,
pub updated_at: DateTime,
#[sea_orm(primary_key, auto_increment = false)]
pub id: i64,
pub path: String,
pub mr_link: String,
pub commit_id: String,
pub check_type_code: CheckTypeEnum,
pub status: String,
pub message: String,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}
25 changes: 25 additions & 0 deletions jupiter/callisto/src/entity_ext/check_result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::{check_result, entity_ext::generate_id, sea_orm_active_enums::CheckTypeEnum};

impl check_result::Model {
pub fn new(
path: &str,
mr_link: &str,
commit_id: &str,
check_type_code: CheckTypeEnum,
status: &str,
message: &str,
) -> Self {
let now = chrono::Utc::now().naive_utc();
Self {
id: generate_id(),
created_at: now,
updated_at: now,
path: path.to_owned(),
mr_link: mr_link.to_owned(),
commit_id: commit_id.to_owned(),
check_type_code,
status: status.to_owned(),
message: message.to_owned(),
}
}
}
1 change: 1 addition & 0 deletions jupiter/callisto/src/entity_ext/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod check_result;
pub mod item_assignees;
pub mod item_labels;
pub mod label;
Expand Down
Loading
Loading