diff --git a/ceres/src/api_service/import_api_service.rs b/ceres/src/api_service/import_api_service.rs index 9d554eaf9..805c3949c 100644 --- a/ceres/src/api_service/import_api_service.rs +++ b/ceres/src/api_service/import_api_service.rs @@ -277,7 +277,7 @@ impl ImportApiService { search_item: &TreeItem, cache: &mut GitObjectCache, ) -> Result { - 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() { diff --git a/ceres/src/api_service/mod.rs b/ceres/src/api_service/mod.rs index 75db9c9f6..e86320cc5 100644 --- a/ceres/src/api_service/mod.rs +++ b/ceres/src/api_service/mod.rs @@ -76,7 +76,8 @@ pub trait ApiHandler: Send + Sync { async fn get_commit_by_hash(&self, hash: &str) -> Option; - async fn get_tree_relate_commit(&self, t_hash: SHA1, path: PathBuf) -> Result; + async fn get_tree_relate_commit(&self, t_hash: SHA1, path: PathBuf) + -> Result; async fn get_commits_by_hashes(&self, c_hashes: Vec) -> Result, GitError>; diff --git a/ceres/src/api_service/mono_api_service.rs b/ceres/src/api_service/mono_api_service.rs index ff3f1899b..c14ce2955 100644 --- a/ceres/src/api_service/mono_api_service.rs +++ b/ceres/src/api_service/mono_api_service.rs @@ -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, @@ -500,7 +499,6 @@ impl MonoApiService { } } - if !failed_hashes.is_empty() { tracing::warn!( "Failed to fetch {} blob(s): {:?}", @@ -531,7 +529,6 @@ impl MonoApiService { .await; Ok(diff_output) - } fn collect_page_blobs( diff --git a/ceres/src/lib.rs b/ceres/src/lib.rs index 858c974a1..cc7116ccb 100644 --- a/ceres/src/lib.rs +++ b/ceres/src/lib.rs @@ -1,5 +1,6 @@ pub mod api_service; pub mod lfs; +pub mod merge_checker; pub mod model; pub mod pack; pub mod protocol; diff --git a/ceres/src/merge_checker/mod.rs b/ceres/src/merge_checker/mod.rs new file mode 100644 index 000000000..40e629e4f --- /dev/null +++ b/ceres/src/merge_checker/mod.rs @@ -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; +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, ToSchema)] +pub enum CheckType { + GpgSignature, + BranchProtection, + CommitMessage, + MrSync, + MergeConflict, + CiStatus, + CodeReview, +} + +impl From 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 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>, + storage: Arc, +} + +impl CheckerRegistry { + pub fn new(storage: Arc) -> 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) { + 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(¶ms).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(()) + } +} diff --git a/ceres/src/merge_checker/mr_sync_checker.rs b/ceres/src/merge_checker/mr_sync_checker.rs new file mode 100644 index 000000000..671a339d1 --- /dev/null +++ b/ceres/src/merge_checker/mr_sync_checker.rs @@ -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, +} + +#[derive(Debug, Deserialize)] +pub(crate) struct MrSyncParams { + mr_from: String, + current: String, +} + +impl MrSyncParams { + fn from_value(v: &serde_json::Value) -> anyhow::Result { + 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"); + 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 { + 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 + })) + } +} diff --git a/ceres/src/pack/monorepo.rs b/ceres/src/pack/monorepo.rs index 3189ee039..5648acdcd 100644 --- a/ceres/src/pack/monorepo.rs +++ b/ceres/src/pack/monorepo.rs @@ -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}, @@ -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!( @@ -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(); @@ -369,6 +370,15 @@ impl RepoHandler for MonoRepo { } } } + let mr_info = self + .storage + .mr_storage() + .get_mr(link) + .await? + .expect("MR Not Found"); + + let check_reg = CheckerRegistry::new(self.storage.clone().into()); + check_reg.run_checks(mr_info.into()).await?; Ok(()) } @@ -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(()) } diff --git a/jupiter/callisto/src/check_result.rs b/jupiter/callisto/src/check_result.rs new file mode 100644 index 000000000..b0d09c967 --- /dev/null +++ b/jupiter/callisto/src/check_result.rs @@ -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 {} diff --git a/jupiter/callisto/src/entity_ext/check_result.rs b/jupiter/callisto/src/entity_ext/check_result.rs new file mode 100644 index 000000000..da835c4c6 --- /dev/null +++ b/jupiter/callisto/src/entity_ext/check_result.rs @@ -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(), + } + } +} diff --git a/jupiter/callisto/src/entity_ext/mod.rs b/jupiter/callisto/src/entity_ext/mod.rs index e22234b13..72faa8b1b 100644 --- a/jupiter/callisto/src/entity_ext/mod.rs +++ b/jupiter/callisto/src/entity_ext/mod.rs @@ -1,3 +1,4 @@ +pub mod check_result; pub mod item_assignees; pub mod item_labels; pub mod label; diff --git a/jupiter/callisto/src/mod.rs b/jupiter/callisto/src/mod.rs index 8fd7b8cb2..6dbe3afa5 100644 --- a/jupiter/callisto/src/mod.rs +++ b/jupiter/callisto/src/mod.rs @@ -5,6 +5,7 @@ pub mod prelude; pub mod access_token; pub mod builds; +pub mod check_result; pub mod git_blob; pub mod git_commit; pub mod git_issue; @@ -29,6 +30,7 @@ pub mod mega_tag; pub mod mega_tree; pub mod mq_storage; pub mod notes; +pub mod path_check_configs; pub mod raw_blob; pub mod reactions; pub mod relay_lfs_info; diff --git a/jupiter/callisto/src/path_check_configs.rs b/jupiter/callisto/src/path_check_configs.rs new file mode 100644 index 000000000..82bade468 --- /dev/null +++ b/jupiter/callisto/src/path_check_configs.rs @@ -0,0 +1,23 @@ +//! `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 = "path_check_configs")] +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 check_type_code: CheckTypeEnum, + pub enabled: bool, + pub required: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/jupiter/callisto/src/prelude.rs b/jupiter/callisto/src/prelude.rs index b72f56f96..d1b7c368a 100644 --- a/jupiter/callisto/src/prelude.rs +++ b/jupiter/callisto/src/prelude.rs @@ -2,6 +2,7 @@ pub use super::access_token::Entity as AccessToken; pub use super::builds::Entity as Builds; +pub use super::check_result::Entity as CheckResult; pub use super::git_blob::Entity as GitBlob; pub use super::git_commit::Entity as GitCommit; pub use super::git_issue::Entity as GitIssue; @@ -26,6 +27,7 @@ pub use super::mega_tag::Entity as MegaTag; pub use super::mega_tree::Entity as MegaTree; pub use super::mq_storage::Entity as MqStorage; pub use super::notes::Entity as Notes; +pub use super::path_check_configs::Entity as PathCheckConfigs; pub use super::raw_blob::Entity as RawBlob; pub use super::reactions::Entity as Reactions; pub use super::relay_lfs_info::Entity as RelayLfsInfo; diff --git a/jupiter/callisto/src/sea_orm_active_enums.rs b/jupiter/callisto/src/sea_orm_active_enums.rs index cc8b9505f..aae4c4142 100644 --- a/jupiter/callisto/src/sea_orm_active_enums.rs +++ b/jupiter/callisto/src/sea_orm_active_enums.rs @@ -3,6 +3,24 @@ use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "check_type_enum")] +pub enum CheckTypeEnum { + #[sea_orm(string_value = "gpg_signature")] + GpgSignature, + #[sea_orm(string_value = "branch_protection")] + BranchProtection, + #[sea_orm(string_value = "commit_message")] + CommitMessage, + #[sea_orm(string_value = "mr_sync")] + MrSync, + #[sea_orm(string_value = "merge_conflict")] + MergeConflict, + #[sea_orm(string_value = "ci_status")] + CiStatus, + #[sea_orm(string_value = "code_review")] + CodeReview, +} #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "conv_type_enum")] pub enum ConvTypeEnum { diff --git a/jupiter/src/migration/m20250821_083749_add_checks.rs b/jupiter/src/migration/m20250821_083749_add_checks.rs new file mode 100644 index 000000000..0716ea1c6 --- /dev/null +++ b/jupiter/src/migration/m20250821_083749_add_checks.rs @@ -0,0 +1,131 @@ +use extension::postgres::Type; +use sea_orm_migration::{ + prelude::*, + schema::*, + sea_orm::{DatabaseBackend, EnumIter, Iterable}, +}; + +use crate::migration::pk_bigint; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let backend = manager.get_database_backend(); + + match backend { + DatabaseBackend::Postgres => { + manager + .create_type( + Type::create() + .as_enum(CheckTypeEnum) + .values(CheckType::iter()) + .to_owned(), + ) + .await?; + } + DatabaseBackend::MySql | DatabaseBackend::Sqlite => {} + } + + manager + .create_table( + table_auto(PathCheckConfigs::Table) + .col(pk_bigint(PathCheckConfigs::Id)) + .col(string(PathCheckConfigs::Path)) + .col(enumeration( + PathCheckConfigs::CheckTypeCode, + Alias::new("check_type_enum"), + CheckType::iter(), + )) + .col(boolean(PathCheckConfigs::Enabled)) + .col(boolean(PathCheckConfigs::Required)) + .to_owned(), + ) + .await?; + + manager + .create_table( + table_auto(CheckResult::Table) + .col(pk_bigint(CheckResult::Id)) + .col(string(CheckResult::Path)) + .col(string(CheckResult::MrLink)) + .col(string(CheckResult::CommitId)) + .col(enumeration( + CheckResult::CheckTypeCode, + Alias::new("check_type_enum"), + CheckType::iter(), + )) + .col(string(CheckResult::Status)) + .col(string(CheckResult::Message)) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("check_res_unique") + .table(CheckResult::Table) + .col(CheckResult::MrLink) + .col(CheckResult::CheckTypeCode) + .unique() + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("path_check_type_unique") + .table(PathCheckConfigs::Table) + .col(PathCheckConfigs::Path) + .col(PathCheckConfigs::CheckTypeCode) + .unique() + .to_owned(), + ) + .await?; + Ok(()) + } + + async fn down(&self, _: &SchemaManager) -> Result<(), DbErr> { + Ok(()) + } +} + +#[derive(DeriveIden)] +enum PathCheckConfigs { + Table, + Id, + Path, + CheckTypeCode, + Enabled, + Required, +} + +#[derive(DeriveIden)] +struct CheckTypeEnum; + +#[derive(Iden, EnumIter)] +pub enum CheckType { + GpgSignature, + BranchProtection, + CommitMessage, + MrSync, + MergeConflict, + CiStatus, + CodeReview, +} + +#[derive(DeriveIden)] +enum CheckResult { + Table, + Id, + Path, + MrLink, + CommitId, + CheckTypeCode, + Status, + Message, +} diff --git a/jupiter/src/migration/mod.rs b/jupiter/src/migration/mod.rs index f150a8a64..db8332c4f 100644 --- a/jupiter/src/migration/mod.rs +++ b/jupiter/src/migration/mod.rs @@ -49,6 +49,7 @@ mod m20250804_151214_alter_builds_end_at; mod m20250812_022434_alter_mega_mr; mod m20250815_075653_remove_commit_id; mod m20250819_025231_alter_builds; +mod m20250821_083749_add_checks; /// Creates a primary key column definition with big integer type. /// /// # Arguments @@ -85,6 +86,7 @@ impl MigratorTrait for Migrator { Box::new(m20250812_022434_alter_mega_mr::Migration), Box::new(m20250815_075653_remove_commit_id::Migration), Box::new(m20250819_025231_alter_builds::Migration), + Box::new(m20250821_083749_add_checks::Migration), ] } } diff --git a/jupiter/src/model/mr_dto.rs b/jupiter/src/model/mr_dto.rs index 14d41c0ce..ce985213a 100644 --- a/jupiter/src/model/mr_dto.rs +++ b/jupiter/src/model/mr_dto.rs @@ -1,4 +1,5 @@ -use callisto::{item_assignees, label, mega_mr}; +use callisto::{item_assignees, label, mega_mr, sea_orm_active_enums::MergeStatusEnum}; +use sea_orm::entity::prelude::*; use crate::model::conv_dto::ConvWithReactions; @@ -9,3 +10,33 @@ pub struct MRDetails { pub labels: Vec, pub assignees: Vec, } + +pub struct MrInfoDto { + pub link: String, + pub title: String, + pub merge_date: Option, + pub status: MergeStatusEnum, + pub path: String, + pub from_hash: String, + pub to_hash: String, + pub created_at: DateTime, + pub updated_at: DateTime, + pub username: String, +} + +impl From for MrInfoDto { + fn from(value: mega_mr::Model) -> Self { + Self { + link: value.link, + title: value.title, + merge_date: value.merge_date, + status: value.status, + path: value.path, + from_hash: value.from_hash, + to_hash: value.to_hash, + created_at: value.created_at, + updated_at: value.updated_at, + username: value.username, + } + } +} diff --git a/jupiter/src/storage/mr_storage.rs b/jupiter/src/storage/mr_storage.rs index 820510f91..f1138c587 100644 --- a/jupiter/src/storage/mr_storage.rs +++ b/jupiter/src/storage/mr_storage.rs @@ -3,13 +3,16 @@ use std::ops::Deref; use common::model::Pagination; use sea_orm::prelude::Expr; +use sea_orm::sea_query::OnConflict; use sea_orm::{ ActiveModelTrait, ColumnTrait, Condition, EntityTrait, IntoActiveModel, JoinType, PaginatorTrait, QueryFilter, QuerySelect, RelationTrait, Set, }; use callisto::sea_orm_active_enums::MergeStatusEnum; -use callisto::{item_assignees, label, mega_conversation, mega_mr}; +use callisto::{ + check_result, item_assignees, label, mega_conversation, mega_mr, path_check_configs, +}; use common::errors::MegaError; use crate::model::common::{ItemDetails, ListParams}; @@ -245,4 +248,54 @@ impl MrStorage { a_model.update(self.get_connection()).await.unwrap(); Ok(()) } + + pub async fn update_mr_hash( + &self, + model: mega_mr::Model, + from_hash: &str, + to_hash: &str, + ) -> Result<(), MegaError> { + let mut a_model = model.into_active_model(); + a_model.from_hash = Set(from_hash.to_owned()); + a_model.to_hash = Set(to_hash.to_owned()); + a_model.updated_at = Set(chrono::Utc::now().naive_utc()); + a_model.update(self.get_connection()).await.unwrap(); + Ok(()) + } + + pub async fn get_checks_config_by_path( + &self, + path: &str, + ) -> Result, MegaError> { + let models = path_check_configs::Entity::find() + .filter(path_check_configs::Column::Path.eq(path)) + .all(self.get_connection()) + .await?; + Ok(models) + } + + pub async fn save_check_results( + &self, + models: Vec, + ) -> Result<(), MegaError> { + let models: Vec = + models.into_iter().map(|m| m.into_active_model()).collect(); + check_result::Entity::insert_many(models) + .on_conflict( + OnConflict::columns(vec![ + check_result::Column::MrLink, + check_result::Column::CheckTypeCode, + ]) + .update_columns([ + check_result::Column::CommitId, + check_result::Column::Status, + check_result::Column::Message, + ]) + .to_owned(), + ) + .do_nothing() + .exec(self.get_connection()) + .await?; + Ok(()) + } } diff --git a/mono/src/api/api_router.rs b/mono/src/api/api_router.rs index 04131b3b7..03b90d4e3 100644 --- a/mono/src/api/api_router.rs +++ b/mono/src/api/api_router.rs @@ -121,10 +121,22 @@ async fn get_latest_commit( Query(query): Query, state: State, ) -> Result, ApiError> { + let query_path: std::path::PathBuf = query.path.into(); + let import_dir = state.storage.config().monorepo.import_dir.clone(); + if let Ok(rest) = query_path.strip_prefix(import_dir) { + if rest.components().count() == 1 { + let res = state + .monorepo() + .get_latest_commit(query_path.clone()) + .await?; + return Ok(Json(res)); + } + } + let res = state - .api_handler(query.path.as_ref()) + .api_handler(&query_path) .await? - .get_latest_commit(query.path.into()) + .get_latest_commit(query_path) .await?; Ok(Json(res)) }