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
5 changes: 4 additions & 1 deletion ceres/src/merge_checker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,16 @@ pub struct CheckResult {
pub struct CheckerRegistry {
checkers: HashMap<CheckType, Box<dyn Checker>>,
storage: Arc<Storage>,
#[allow(dead_code)]
username: String,
}

impl CheckerRegistry {
pub fn new(storage: Arc<Storage>) -> Self {
pub fn new(storage: Arc<Storage>, username: String) -> Self {
let mut r = CheckerRegistry {
checkers: HashMap::new(),
storage: storage.clone(),
username,
};
r.register(CheckType::MrSync, Box::new(MrSyncChecker { storage }));
r
Expand Down
2 changes: 1 addition & 1 deletion ceres/src/pack/monorepo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ impl MonoRepo {
.await?
.expect("MR Not Found");

let check_reg = CheckerRegistry::new(self.storage.clone().into());
let check_reg = CheckerRegistry::new(self.storage.clone().into(), self.username());
check_reg.run_checks(mr_info.into()).await?;
Ok(())
}
Expand Down
22 changes: 22 additions & 0 deletions jupiter/callisto/src/issue_mr_references.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.15

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

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "issue_mr_references")]
pub struct Model {
pub created_at: DateTime,
pub updated_at: DateTime,
#[sea_orm(primary_key, auto_increment = false)]
pub source_id: String,
#[sea_orm(primary_key, auto_increment = false)]
pub target_id: String,
pub reference_type: ReferenceTypeEnum,
}

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

impl ActiveModelBehavior for ActiveModel {}
1 change: 1 addition & 0 deletions jupiter/callisto/src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod git_tag;
pub mod git_tree;
pub mod gpg_key;
pub mod import_refs;
pub mod issue_mr_references;
pub mod item_assignees;
pub mod item_labels;
pub mod label;
Expand Down
1 change: 1 addition & 0 deletions jupiter/callisto/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub use super::git_tag::Entity as GitTag;
pub use super::git_tree::Entity as GitTree;
pub use super::gpg_key::Entity as GpgKey;
pub use super::import_refs::Entity as ImportRefs;
pub use super::issue_mr_references::Entity as IssueMrReferences;
pub use super::item_assignees::Entity as ItemAssignees;
pub use super::item_labels::Entity as ItemLabels;
pub use super::label::Entity as Label;
Expand Down
16 changes: 16 additions & 0 deletions jupiter/callisto/src/sea_orm_active_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub enum ConvTypeEnum {
Label,
#[sea_orm(string_value = "assignee")]
Assignee,
#[sea_orm(string_value = "mention")]
Mention,
}
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "merge_status_enum")]
Expand All @@ -70,6 +72,20 @@ pub enum RefTypeEnum {
Tag,
}
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
enum_name = "reference_type_enum"
)]
pub enum ReferenceTypeEnum {
#[sea_orm(string_value = "mention")]
Mention,
#[sea_orm(string_value = "build_relates")]
BuildRelates,
#[sea_orm(string_value = "blocks")]
Blocks,
}
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "storage_type_enum")]
pub enum StorageTypeEnum {
#[sea_orm(string_value = "database")]
Expand Down
76 changes: 76 additions & 0 deletions jupiter/src/migration/m20250903_071928_add_issue_refs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use sea_orm::{sea_query::extension::postgres::Type, DatabaseBackend, EnumIter, Iterable};
use sea_orm_migration::{prelude::*, schema::*};

#[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(ReferenceTypeEnum)
.values(ReferenceType::iter())
.to_owned(),
)
.await?;

manager
.get_connection()
.execute_unprepared(
r#"ALTER TYPE conv_type_enum ADD VALUE IF NOT EXISTS 'mention';"#,
)
.await?;
}
DatabaseBackend::MySql | DatabaseBackend::Sqlite => {}
}

manager
.create_table(
table_auto(IssueMrReferences::Table)
.if_not_exists()
.col(string(IssueMrReferences::SourceId))
.col(string(IssueMrReferences::TargetId))
.col(enumeration(
IssueMrReferences::ReferenceType,
Alias::new("reference_type_enum"),
ReferenceType::iter(),
))
.primary_key(
Index::create()
.col(IssueMrReferences::SourceId)
.col(IssueMrReferences::TargetId),
)
.to_owned(),
)
.await?;
Ok(())
}

async fn down(&self, _: &SchemaManager) -> Result<(), DbErr> {
Ok(())
}
}

#[derive(DeriveIden)]
enum IssueMrReferences {
Table,
SourceId,
TargetId,
ReferenceType,
}

#[derive(DeriveIden)]
struct ReferenceTypeEnum;

#[derive(Iden, EnumIter)]
pub enum ReferenceType {
Mention,
BuildRelates,
Blocks,
}
2 changes: 2 additions & 0 deletions jupiter/src/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ mod m20250821_083749_add_checks;
mod m20250828_092459_remove_gpg_table;
mod m20250828_092729_create_standalone_table;
mod m20250903_013904_create_task_table;
mod m20250903_071928_add_issue_refs;
/// Creates a primary key column definition with big integer type.
///
/// # Arguments
Expand Down Expand Up @@ -95,6 +96,7 @@ impl MigratorTrait for Migrator {
Box::new(m20250828_092459_remove_gpg_table::Migration),
Box::new(m20250828_092729_create_standalone_table::Migration),
Box::new(m20250903_013904_create_task_table::Migration),
Box::new(m20250903_071928_add_issue_refs::Migration),
]
}
}
Expand Down
25 changes: 24 additions & 1 deletion jupiter/src/storage/issue_storage.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::collections::HashMap;
use std::ops::Deref;

use callisto::sea_orm_active_enums::ReferenceTypeEnum;
use sea_orm::prelude::Expr;
use sea_orm::{
ActiveModelTrait, ColumnTrait, Condition, EntityTrait, IntoActiveModel, JoinType,
PaginatorTrait, QueryFilter, QuerySelect, RelationTrait, Set, TransactionTrait,
};

use callisto::{item_assignees, item_labels, label, mega_conversation, mega_issue};
use callisto::{issue_mr_references, item_assignees, item_labels, label, mega_conversation, mega_issue};
use common::errors::MegaError;
use common::model::Pagination;

Expand Down Expand Up @@ -350,6 +351,28 @@ impl IssueStorage {

Ok(())
}

pub async fn add_reference(
&self,
source_id: &str,
target_id: &str,
reference_type: ReferenceTypeEnum,
) -> Result<issue_mr_references::Model, MegaError> {
let issue_ref = issue_mr_references::Model {
source_id: source_id.to_owned(),
target_id: target_id.to_owned(),
reference_type,
created_at: chrono::Utc::now().naive_utc(),
updated_at: chrono::Utc::now().naive_utc(),
};

let res = issue_ref
.into_active_model()
.insert(self.get_connection())
.await?;

Ok(res)
}
}

fn filter_by_author(cond: Condition, author: Option<String>) -> Condition {
Expand Down
75 changes: 75 additions & 0 deletions mono/src/api/api_common/comment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::collections::HashSet;

use axum::{extract::State, Json};
use regex::Regex;

use callisto::sea_orm_active_enums::{ConvTypeEnum, ReferenceTypeEnum};
use common::model::CommonResult;

use crate::api::error::ApiError;
use crate::api::oauth::model::LoginUser;
use crate::api::MonoApiServiceState;

pub fn parse_data_id(comment: &str) -> HashSet<String> {
let data_id = Regex::new(r#"data-id="([A-Za-z0-9]+)""#).unwrap();
let links: HashSet<String> = data_id
.captures_iter(comment)
.map(|cap| cap[1].to_string())
.collect();
links
}

pub async fn check_comment_ref(
user: LoginUser,
state: State<MonoApiServiceState>,
comment: &str,
source_link: &str,
) -> Result<Json<CommonResult<()>>, ApiError> {
let links = parse_data_id(comment);
let username = user.username;
for ref_link in links {
state
.issue_stg()
.add_reference(source_link, &ref_link, ReferenceTypeEnum::Mention)
.await?;
state
.conv_stg()
.add_conversation(
&ref_link,
&username,
Some(format!("{username} mentioned this on")),
ConvTypeEnum::Mention,
)
.await?;
}

Ok(Json(CommonResult::success(None)))
}

#[cfg(test)]
mod test {
use std::collections::HashSet;

use crate::api::api_common::comment::parse_data_id;

#[test]
pub fn test_parse_data_id_from_comment() {
let single_ref = r#"<p><span class="link-issue" data-type="linkIssue" data-id="HDQL6ATY" data-label="HDQL6ATY" data-suggestiontype="merge_request">$HDQL6ATY</span> </p>"#;
let data_id = parse_data_id(single_ref);
assert_eq!(
data_id.iter().next(),
Some(String::from("HDQL6ATY")).as_ref()
);

let normal_comment = r#"<p>This is a normal comment without reference</p>"#;
let data_id = parse_data_id(normal_comment);
assert_eq!(data_id.iter().next(), None);

let multi_referene = r#"<p>multireference?? <span class="link-issue" data-type="linkIssue" data-id="PIXLXMS9" data-label="PIXLXMS9" data-suggestiontype="issue">$PIXLXMS9</span> <span class="link-issue" data-type="linkIssue" data-id="PIXLXMS9" data-label="PIXLXMS9" data-suggestiontype="issue">$PIXLXMS9</span> <span class="link-issue" data-type="linkIssue" data-id="ZE710J7U" data-label="ZE710J7U" data-suggestiontype="merge_request">$ZE710J7U</span> </p>"#;
let data_id = parse_data_id(multi_referene);
assert_eq!(
data_id,
HashSet::from([String::from("PIXLXMS9"), String::from("ZE710J7U")])
);
}
}
1 change: 1 addition & 0 deletions mono/src/api/api_common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod comment;
pub mod label_assignee;
pub mod model;
2 changes: 2 additions & 0 deletions mono/src/api/conversation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ pub enum ConvType {
Reopen,
Label,
Assignee,
Mention,
}

impl From<ConvTypeEnum> for ConvType {
Expand All @@ -116,6 +117,7 @@ impl From<ConvTypeEnum> for ConvType {
ConvTypeEnum::Reopen => ConvType::Reopen,
ConvTypeEnum::Label => ConvType::Label,
ConvTypeEnum::Assignee => ConvType::Assignee,
ConvTypeEnum::Mention => ConvType::Mention
}
}
}
6 changes: 3 additions & 3 deletions mono/src/api/issue/issue_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,17 +200,17 @@ async fn save_comment(
Path(link): Path<String>,
state: State<MonoApiServiceState>,
Json(payload): Json<ContentPayload>,
) -> Result<Json<CommonResult<String>>, ApiError> {
) -> Result<Json<CommonResult<()>>, ApiError> {
state
.conv_stg()
.add_conversation(
&link,
&user.username,
Some(payload.content),
Some(payload.content.clone()),
ConvTypeEnum::Comment,
)
.await?;
Ok(Json(CommonResult::success(None)))
api_common::comment::check_comment_ref(user, state, &payload.content, &link).await
}

/// Update issue related labels
Expand Down
6 changes: 3 additions & 3 deletions mono/src/api/mr/mr_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,19 +418,19 @@ async fn save_comment(
Path(link): Path<String>,
state: State<MonoApiServiceState>,
Json(payload): Json<ContentPayload>,
) -> Result<Json<CommonResult<String>>, ApiError> {
) -> Result<Json<CommonResult<()>>, ApiError> {
let res = state.mr_stg().get_mr(&link).await?;
let model = res.ok_or(MegaError::with_message("Not Found"))?;
state
.conv_stg()
.add_conversation(
&model.link,
&user.username,
Some(payload.content),
Some(payload.content.clone()),
ConvTypeEnum::Comment,
)
.await?;
Ok(Json(CommonResult::success(None)))
api_common::comment::check_comment_ref(user, state, &payload.content, &link).await
}

/// Edit MR title
Expand Down
Loading