diff --git a/Cargo.toml b/Cargo.toml index 77f909bfd..687c78cce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,8 @@ taurus = { path = "taurus" } mega = { path = "mega" } mono = { path = "mono" } -anyhow = "1.0.86" -serde = "1.0.205" +anyhow = "1.0.87" +serde = "1.0.210" serde_json = "1.0.128" tracing = "0.1.40" tracing-subscriber = "0.3.18" @@ -44,7 +44,7 @@ thiserror = "1.0.63" rand = "0.8.5" smallvec = "1.13.2" tokio = "1.40.0" -tokio-stream = "0.1.15" +tokio-stream = "0.1.16" tokio-test = "0.4.4" clap = "4.5.17" async-trait = "0.1.82" @@ -63,7 +63,7 @@ axum = "0.7.5" axum-extra = "0.9.3" axum-server = "0.7" tower-http = "0.5.2" -tower = "0.5.0" +tower = "0.5.1" hex = "0.4.3" sea-orm = "1.0.1" flate2 = "1.0.30" @@ -73,7 +73,7 @@ idgenerator = "2.0.0" num_cpus = "1.16.0" config = "0.14.0" shadow-rs = "0.34.0" -reqwest = "0.12.5" +reqwest = "0.12.7" lazy_static = "1.5.0" uuid = "1.10.0" regex = "1.10.4" diff --git a/ceres/src/api_service/mono_api_service.rs b/ceres/src/api_service/mono_api_service.rs index cda4d35c3..237b953d1 100644 --- a/ceres/src/api_service/mono_api_service.rs +++ b/ceres/src/api_service/mono_api_service.rs @@ -214,21 +214,21 @@ impl MonoApiService { Ok(mr_list.into_iter().map(|m| m.into()).collect()) } - pub async fn mr_detail(&self, mr_id: i64) -> Result, MegaError> { + pub async fn mr_detail(&self, mr_link: &str) -> Result, MegaError> { let storage = self.context.services.mono_storage.clone(); - let model = storage.get_mr(mr_id).await.unwrap(); + let model = storage.get_mr(mr_link).await.unwrap(); if let Some(model) = model { let mut detail: MRDetail = model.into(); - let conversions = storage.get_mr_conversations(mr_id).await.unwrap(); + let conversions = storage.get_mr_conversations(mr_link).await.unwrap(); detail.conversions = conversions.into_iter().map(|x| x.into()).collect(); return Ok(Some(detail)); } Ok(None) } - pub async fn mr_tree_files(&self, mr_id: i64) -> Result, MegaError> { + pub async fn mr_tree_files(&self, mr_link: &str) -> Result, MegaError> { let storage = self.context.services.mono_storage.clone(); - let model = storage.get_mr(mr_id).await.unwrap(); + let model = storage.get_mr(mr_link).await.unwrap(); if let Some(model) = model { let to_tree_id = storage .get_commit_by_hash(&model.to_hash) @@ -281,9 +281,9 @@ impl MonoApiService { Err(MegaError::with_message("Can not find related MR by id")) } - pub async fn merge_mr(&self, mr_id: i64) -> Result<(), MegaError> { + pub async fn merge_mr(&self, mr_link: &str) -> Result<(), MegaError> { let storage = self.context.services.mono_storage.clone(); - if let Some(model) = storage.get_open_mr_by_id(mr_id).await.unwrap() { + if let Some(model) = storage.get_open_mr_by_link(mr_link).await.unwrap() { let mut mr: MergeRequest = model.into(); let refs = storage.get_ref(&mr.path).await.unwrap().unwrap(); @@ -301,7 +301,7 @@ impl MonoApiService { // add conversation storage - .add_mr_conversation(mr.id, 0, ConvType::Merged) + .add_mr_conversation(&mr.mr_link, 0, ConvType::Merged) .await .unwrap(); if mr.path != "/" { diff --git a/ceres/src/model/mr.rs b/ceres/src/model/mr.rs index dbdf01ad1..3fa4e597b 100644 --- a/ceres/src/model/mr.rs +++ b/ceres/src/model/mr.rs @@ -4,7 +4,7 @@ use callisto::{mega_mr, mega_mr_conv}; #[derive(Serialize, Deserialize)] pub struct MrInfoItem { - pub id: i64, + pub mr_link: String, pub title: String, pub status: String, pub open_timestamp: i64, @@ -14,7 +14,7 @@ pub struct MrInfoItem { impl From for MrInfoItem { fn from(value: mega_mr::Model) -> Self { Self { - id: value.id, + mr_link: value.mr_link, title: String::new(), status: value.status.to_string(), open_timestamp: value.created_at.and_utc().timestamp(), @@ -26,6 +26,7 @@ impl From for MrInfoItem { #[derive(Serialize, Deserialize)] pub struct MRDetail { pub id: i64, + pub mr_link: String, pub title: String, pub status: String, pub open_timestamp: i64, @@ -45,6 +46,7 @@ impl From for MRDetail { fn from(value: mega_mr::Model) -> Self { Self { id: value.id, + mr_link: value.mr_link, title: String::new(), status: value.status.to_string(), open_timestamp: value.created_at.and_utc().timestamp(), diff --git a/ceres/src/pack/handler.rs b/ceres/src/pack/handler.rs deleted file mode 100644 index 55b08a156..000000000 --- a/ceres/src/pack/handler.rs +++ /dev/null @@ -1,176 +0,0 @@ -use std::{ - collections::HashSet, - pin::Pin, - sync::{ - atomic::{AtomicUsize, Ordering}, - mpsc::Receiver, - }, -}; - -use async_trait::async_trait; -use bytes::Bytes; -use futures::Stream; -use tokio_stream::wrappers::ReceiverStream; - -use callisto::raw_blob; -use common::{config::PackConfig, errors::MegaError, utils::ZERO_ID}; -use mercury::internal::pack::Pack; -use mercury::{ - errors::GitError, - internal::{ - object::{ - blob::Blob, - tree::{Tree, TreeItemMode}, - }, - pack::entry::Entry, - }, -}; -use crate::protocol::import_refs::{RefCommand, Refs}; - -#[async_trait] -pub trait PackHandler: Send + Sync { - async fn head_hash(&self) -> (String, Vec); - - async fn handle_receiver(&self, rx: Receiver) -> Result<(), GitError>; - - /// Asynchronously retrieves the full pack data for the specified repository path. - /// This function collects commits and nodes from the storage and packs them into - /// a single binary vector. There is no need to build the entire tree; the function - /// only sends all the data related to this repository. - /// - /// # Returns - /// * `Result, GitError>` - The packed binary data as a vector of bytes. - /// - async fn full_pack(&self) -> Result>, GitError>; - - async fn incremental_pack( - &self, - want: Vec, - have: Vec, - ) -> Result>, GitError>; - - async fn get_trees_by_hashes(&self, hashes: Vec) -> Result, MegaError>; - - async fn get_blobs_by_hashes( - &self, - hashes: Vec, - ) -> Result, MegaError>; - - async fn update_refs(&self, refs: &RefCommand) -> Result<(), GitError>; - - async fn check_commit_exist(&self, hash: &str) -> bool; - - async fn check_default_branch(&self) -> bool; - - fn find_head_hash(&self, refs: Vec) -> (String, Vec) { - let mut head_hash = ZERO_ID.to_string(); - for git_ref in refs.iter() { - if git_ref.default_branch { - head_hash.clone_from(&git_ref.ref_hash); - } - } - (head_hash, refs) - } - - async fn unpack_stream( - &self, - pack_config: &PackConfig, - stream: Pin> + Send>>, - ) -> Result, GitError> { - let (sender, receiver) = std::sync::mpsc::channel(); - let p = Pack::new( - None, - Some(1024 * 1024 * 1024 * pack_config.pack_decode_mem_size), - Some(pack_config.pack_decode_cache_path.clone()), - pack_config.clean_cache_after_decode, - ); - tokio::spawn(async move { - p.decode_stream(stream, sender).await; - }); - Ok(receiver) - } - - async fn traverse_for_count( - &self, - tree: Tree, - exist_objs: &HashSet, - counted_obj: &mut HashSet, - obj_num: &AtomicUsize, - ) { - let mut search_tree_ids = vec![]; - let mut search_blob_ids = vec![]; - for item in &tree.tree_items { - let hash = item.id.to_plain_str(); - if !exist_objs.contains(&hash) && counted_obj.insert(hash.clone()) { - if item.mode == TreeItemMode::Tree { - search_tree_ids.push(hash.clone()) - } else { - search_blob_ids.push(hash.clone()); - } - } - } - obj_num.fetch_add(search_blob_ids.len(), Ordering::SeqCst); - let trees = self.get_trees_by_hashes(search_tree_ids).await.unwrap(); - for t in trees { - self.traverse_for_count(t, exist_objs, counted_obj, obj_num) - .await; - } - obj_num.fetch_add(1, Ordering::SeqCst); - } - - /// Traverse a tree structure asynchronously. - /// - /// This function traverses a given tree, keeps track of processed objects, and optionally sends - /// traversal data to a provided sender. The function will: - /// 1. Traverse the tree and calculate the quantities of tree and blob items. - /// 2. If a sender is provided, send blob and tree data via the sender. - /// - /// # Parameters - /// - `tree`: The tree structure to traverse. - /// - `exist_objs`: A mutable reference to a set containing already processed object IDs. - /// - `sender`: An optional sender for sending traversal data. - /// - /// # Details - /// - The function processes tree items, distinguishing between tree and blob items. - /// - It collects IDs of items that have not been processed yet. - /// - It retrieves and sends blob data if a sender is provided. - /// - It recursively traverses sub-trees. - /// - It sends the entire tree data if a sender is provided. - async fn traverse( - &self, - tree: Tree, - exist_objs: &mut HashSet, - sender: Option<&tokio::sync::mpsc::Sender>, - ) { - let mut search_tree_ids = vec![]; - let mut search_blob_ids = vec![]; - - for item in &tree.tree_items { - let hash = item.id.to_plain_str(); - if exist_objs.insert(hash.clone()) { - if item.mode == TreeItemMode::Tree { - search_tree_ids.push(hash); - } else { - search_blob_ids.push(hash); - } - } - } - - if let Some(sender) = sender { - let blobs = self.get_blobs_by_hashes(search_blob_ids).await.unwrap(); - for b in blobs { - let blob: Blob = b.into(); - sender.send(blob.into()).await.unwrap(); - } - } - - let trees = self.get_trees_by_hashes(search_tree_ids).await.unwrap(); - for t in trees { - self.traverse(t, exist_objs, sender).await; - } - - if let Some(sender) = sender { - sender.send(tree.into()).await.unwrap(); - } - } -} diff --git a/ceres/src/pack/import_repo.rs b/ceres/src/pack/import_repo.rs index 3b3e67074..eba8f3bac 100644 --- a/ceres/src/pack/import_repo.rs +++ b/ceres/src/pack/import_repo.rs @@ -17,7 +17,7 @@ use callisto::{mega_tree, raw_blob}; use common::errors::MegaError; use jupiter::{ context::Context, - storage::{batch_save_model}, + storage::batch_save_model, }; use mercury::{ errors::GitError, @@ -30,7 +30,7 @@ use mercury::{hash::SHA1, internal::pack::encode::PackEncoder}; use crate::{ api_service::{mono_api_service::MonoApiService, ApiHandler}, - pack::handler::PackHandler, protocol::{import_refs::{CommandType, RefCommand, Refs}, repo::Repo}, + pack::PackHandler, protocol::{import_refs::{CommandType, RefCommand, Refs}, repo::Repo}, }; pub struct ImportRepo { diff --git a/ceres/src/pack/mod.rs b/ceres/src/pack/mod.rs index 34293017c..b94afc688 100644 --- a/ceres/src/pack/mod.rs +++ b/ceres/src/pack/mod.rs @@ -1,3 +1,179 @@ -pub mod handler; +use std::{ + collections::HashSet, + pin::Pin, + sync::{ + atomic::{AtomicUsize, Ordering}, + mpsc::Receiver, + }, +}; + +use async_trait::async_trait; +use bytes::Bytes; +use futures::Stream; +use tokio_stream::wrappers::ReceiverStream; + +use crate::protocol::import_refs::{RefCommand, Refs}; +use callisto::raw_blob; +use common::{config::PackConfig, errors::MegaError, utils::ZERO_ID}; +use mercury::internal::pack::Pack; +use mercury::{ + errors::GitError, + internal::{ + object::{ + blob::Blob, + tree::{Tree, TreeItemMode}, + }, + pack::entry::Entry, + }, +}; + pub mod import_repo; pub mod monorepo; + +#[async_trait] +pub trait PackHandler: Send + Sync { + async fn head_hash(&self) -> (String, Vec); + + async fn handle_receiver(&self, rx: Receiver) -> Result<(), GitError>; + + /// Asynchronously retrieves the full pack data for the specified repository path. + /// This function collects commits and nodes from the storage and packs them into + /// a single binary vector. There is no need to build the entire tree; the function + /// only sends all the data related to this repository. + /// + /// # Returns + /// * `Result, GitError>` - The packed binary data as a vector of bytes. + /// + async fn full_pack(&self) -> Result>, GitError>; + + async fn incremental_pack( + &self, + want: Vec, + have: Vec, + ) -> Result>, GitError>; + + async fn get_trees_by_hashes(&self, hashes: Vec) -> Result, MegaError>; + + async fn get_blobs_by_hashes( + &self, + hashes: Vec, + ) -> Result, MegaError>; + + async fn update_refs(&self, refs: &RefCommand) -> Result<(), GitError>; + + async fn check_commit_exist(&self, hash: &str) -> bool; + + async fn check_default_branch(&self) -> bool; + + fn find_head_hash(&self, refs: Vec) -> (String, Vec) { + let mut head_hash = ZERO_ID.to_string(); + for git_ref in refs.iter() { + if git_ref.default_branch { + head_hash.clone_from(&git_ref.ref_hash); + } + } + (head_hash, refs) + } + + async fn unpack_stream( + &self, + pack_config: &PackConfig, + stream: Pin> + Send>>, + ) -> Result, GitError> { + let (sender, receiver) = std::sync::mpsc::channel(); + let p = Pack::new( + None, + Some(1024 * 1024 * 1024 * pack_config.pack_decode_mem_size), + Some(pack_config.pack_decode_cache_path.clone()), + pack_config.clean_cache_after_decode, + ); + tokio::spawn(async move { + p.decode_stream(stream, sender).await; + }); + Ok(receiver) + } + + async fn traverse_for_count( + &self, + tree: Tree, + exist_objs: &HashSet, + counted_obj: &mut HashSet, + obj_num: &AtomicUsize, + ) { + let mut search_tree_ids = vec![]; + let mut search_blob_ids = vec![]; + for item in &tree.tree_items { + let hash = item.id.to_plain_str(); + if !exist_objs.contains(&hash) && counted_obj.insert(hash.clone()) { + if item.mode == TreeItemMode::Tree { + search_tree_ids.push(hash.clone()) + } else { + search_blob_ids.push(hash.clone()); + } + } + } + obj_num.fetch_add(search_blob_ids.len(), Ordering::SeqCst); + let trees = self.get_trees_by_hashes(search_tree_ids).await.unwrap(); + for t in trees { + self.traverse_for_count(t, exist_objs, counted_obj, obj_num) + .await; + } + obj_num.fetch_add(1, Ordering::SeqCst); + } + + /// Traverse a tree structure asynchronously. + /// + /// This function traverses a given tree, keeps track of processed objects, and optionally sends + /// traversal data to a provided sender. The function will: + /// 1. Traverse the tree and calculate the quantities of tree and blob items. + /// 2. If a sender is provided, send blob and tree data via the sender. + /// + /// # Parameters + /// - `tree`: The tree structure to traverse. + /// - `exist_objs`: A mutable reference to a set containing already processed object IDs. + /// - `sender`: An optional sender for sending traversal data. + /// + /// # Details + /// - The function processes tree items, distinguishing between tree and blob items. + /// - It collects IDs of items that have not been processed yet. + /// - It retrieves and sends blob data if a sender is provided. + /// - It recursively traverses sub-trees. + /// - It sends the entire tree data if a sender is provided. + async fn traverse( + &self, + tree: Tree, + exist_objs: &mut HashSet, + sender: Option<&tokio::sync::mpsc::Sender>, + ) { + let mut search_tree_ids = vec![]; + let mut search_blob_ids = vec![]; + + for item in &tree.tree_items { + let hash = item.id.to_plain_str(); + if exist_objs.insert(hash.clone()) { + if item.mode == TreeItemMode::Tree { + search_tree_ids.push(hash); + } else { + search_blob_ids.push(hash); + } + } + } + + if let Some(sender) = sender { + let blobs = self.get_blobs_by_hashes(search_blob_ids).await.unwrap(); + for b in blobs { + let blob: Blob = b.into(); + sender.send(blob.into()).await.unwrap(); + } + } + + let trees = self.get_trees_by_hashes(search_tree_ids).await.unwrap(); + for t in trees { + self.traverse(t, exist_objs, sender).await; + } + + if let Some(sender) = sender { + sender.send(tree.into()).await.unwrap(); + } + } +} diff --git a/ceres/src/pack/monorepo.rs b/ceres/src/pack/monorepo.rs index 026483748..61946046c 100644 --- a/ceres/src/pack/monorepo.rs +++ b/ceres/src/pack/monorepo.rs @@ -11,12 +11,13 @@ use std::{ use async_trait::async_trait; use futures::future::join_all; +use rand::{distributions::Alphanumeric, thread_rng, Rng}; use tokio::sync::mpsc; use tokio_stream::wrappers::ReceiverStream; use callisto::raw_blob; use common::{errors::MegaError, utils::MEGA_BRANCH_NAME}; -use jupiter::context::Context; +use jupiter::{context::Context, storage::mono_storage::MonoStorage}; use mercury::internal::pack::encode::PackEncoder; use mercury::{ errors::GitError, @@ -28,7 +29,7 @@ use mercury::{ }; use crate::{ - pack::handler::PackHandler, + pack::PackHandler, protocol::{ import_refs::{RefCommand, Refs}, mega_refs::MegaRefs, @@ -39,8 +40,8 @@ use crate::{ pub struct MonoRepo { pub context: Context, pub path: PathBuf, - pub from_hash: Option, - pub to_hash: Option, + pub from_hash: String, + pub to_hash: String, } #[async_trait] @@ -121,50 +122,32 @@ impl PackHandler for MonoRepo { async fn handle_receiver(&self, receiver: Receiver) -> Result<(), GitError> { let storage = self.context.services.mono_storage.clone(); - - let (mut mr, mr_exist) = self.get_mr().await; - - let mut unpack_res = Ok(()); - if mr_exist { - if mr.from_hash == self.from_hash.clone().unwrap() { - let to_hash = self.to_hash.clone().unwrap(); - if mr.to_hash != to_hash { - let comment = self.comment_for_force_update(&mr.to_hash, &to_hash); - mr.to_hash = to_hash; - storage - .add_mr_comment(mr.id, 0, Some(comment)) - .await - .unwrap(); - unpack_res = self.save_entry(receiver).await; - if unpack_res.is_err() { - mr.close(); - storage - .add_mr_comment( - mr.id, - 0, - Some("Mega closed MR due to multi commit detected".to_string()), - ) - .await - .unwrap(); - } - } else { - tracing::info!("repeat commit with mr: {}, do nothing", mr.id); - } - } else { - mr.close(); - storage - .add_mr_comment(mr.id, 0, Some("Mega closed MR due to conflict".to_string())) - .await - .unwrap(); + let path_str = self.path.to_str().unwrap(); + match storage.get_open_mr_by_path(path_str).await.unwrap() { + Some(mr) => { + let mut mr = mr.into(); + self.handle_existing_mr(&mut mr, &storage, receiver).await } - storage.update_mr(mr.clone().into()).await.unwrap(); - } else { - unpack_res = self.save_entry(receiver).await; - if unpack_res.is_ok() { - storage.save_mr(mr.clone().into()).await.unwrap(); + None => { + let mr_link: String = thread_rng() + .sample_iter(&Alphanumeric) + .take(8) + .map(char::from) + .collect(); + let mr = MergeRequest { + path: path_str.to_owned(), + from_hash: self.from_hash.clone(), + to_hash: self.to_hash.clone(), + mr_link: mr_link.to_uppercase(), + ..Default::default() + }; + let unpack_res = self.save_entry(receiver).await; + if unpack_res.is_ok() { + storage.save_mr(mr.clone().into()).await.unwrap(); + } + unpack_res } - }; - unpack_res + } } // monorepo full pack should follow the shallow clone command 'git clone --depth=1' @@ -345,24 +328,50 @@ impl PackHandler for MonoRepo { } impl MonoRepo { - async fn get_mr(&self) -> (MergeRequest, bool) { - let storage = self.context.services.mono_storage.clone(); + async fn handle_existing_mr( + &self, + mr: &mut MergeRequest, + storage: &MonoStorage, + receiver: Receiver, + ) -> Result<(), GitError> { + if mr.from_hash == self.from_hash { + if mr.to_hash != self.to_hash { + let comment = self.comment_for_force_update(&mr.to_hash, &self.to_hash); + mr.to_hash = self.to_hash.clone(); + storage + .add_mr_comment(&mr.mr_link, 0, Some(comment)) + .await + .unwrap(); - let mr = storage - .get_open_mr(self.path.to_str().unwrap()) - .await - .unwrap(); - if let Some(mr) = mr { - (mr.into(), true) + let unpack_res = self.save_entry(receiver).await; + if unpack_res.is_err() { + mr.close(); + storage + .add_mr_comment( + &mr.mr_link, + 0, + Some("Mega closed MR due to multi commit detected".to_string()), + ) + .await + .unwrap(); + } + } else { + tracing::info!("repeat commit with mr: {}, do nothing", mr.id); + } } else { - let mr = MergeRequest { - path: self.path.to_str().unwrap().to_owned(), - from_hash: self.from_hash.clone().unwrap(), - to_hash: self.to_hash.clone().unwrap(), - ..Default::default() - }; - (mr, false) + mr.close(); + storage + .add_mr_comment( + &mr.mr_link, + 0, + Some("Mega closed MR due to conflict".to_string()), + ) + .await + .unwrap(); } + + storage.update_mr(mr.clone().into()).await.unwrap(); + Ok(()) } fn comment_for_force_update(&self, from: &str, to: &str) -> String { diff --git a/ceres/src/protocol/mod.rs b/ceres/src/protocol/mod.rs index 9441cfc59..4200b6d23 100644 --- a/ceres/src/protocol/mod.rs +++ b/ceres/src/protocol/mod.rs @@ -10,7 +10,7 @@ use import_refs::RefCommand; use jupiter::context::Context; use repo::Repo; -use crate::pack::{handler::PackHandler, import_repo::ImportRepo, monorepo::MonoRepo}; +use crate::pack::{PackHandler, import_repo::ImportRepo, monorepo::MonoRepo}; pub mod smart; pub mod repo; @@ -177,16 +177,16 @@ impl SmartProtocol { let mut res = MonoRepo { context: self.context.clone(), path: self.path.clone(), - from_hash: None, - to_hash: None, + from_hash: String::new(), + to_hash: String::new(), }; if let Some(command) = self .command_list .iter() .find(|x| x.ref_type == RefType::Branch) { - res.from_hash = Some(command.old_id.clone()); - res.to_hash = Some(command.new_id.clone()); + res.from_hash = command.old_id.clone(); + res.to_hash = command.new_id.clone(); } Ok(Arc::new(res)) } diff --git a/docker/README.md b/docker/README.md index 5b3ebbadd..d4da943f9 100644 --- a/docker/README.md +++ b/docker/README.md @@ -50,9 +50,9 @@ docker run --rm -it -d --name mono-ui --network mono-network -e MEGA_INTERNAL_HO docker network create mono-network # run postgres -docker run --rm -it -d --name mono-pg --network mono-network -v /mnt/data/mono/pg-data:/var/lib/postgresql/data -p 5432:5432 mono-pg:0.1-pre-release -docker run --rm -it -d --name mono-engine --network mono-network -v /mnt/data/mono/mono-data:/opt/mega -p 8000:8000 -p 22:9000 mono-engine:0.1-pre-release -docker run --rm -it -d --name mono-ui --network mono-network -e MEGA_INTERNAL_HOST=http://mono-engine:8000 -e MEGA_HOST=https://git.gitmono.com -p 3000:3000 mono-ui:0.1-pre-release +docker run --rm -it -d --name mono-pg --network mono-network --memory=4g -v /mnt/data/mono/pg-data:/var/lib/postgresql/data -p 5432:5432 mono-pg:0.1-pre-release +docker run --rm -it -d --name mono-engine --network mono-network --memory=8g -v /mnt/data/mono/mono-data:/opt/mega -p 8000:8000 -p 22:9000 mono-engine:0.1-pre-release +docker run --rm -it -d --name mono-ui --network mono-network --memory=1g -e MEGA_INTERNAL_HOST=http://mono-engine:8000 -e MEGA_HOST=https://git.gitmono.com -p 3000:3000 mono-ui:0.1-pre-release ``` [4] Nginx configuration for Mono diff --git a/docker/mono-pg-dockerfile b/docker/mono-pg-dockerfile index 9c04bb95f..a28d02bd2 100644 --- a/docker/mono-pg-dockerfile +++ b/docker/mono-pg-dockerfile @@ -17,6 +17,6 @@ EXPOSE 5432 # Add the database initialization script to the container # When the container starts, PostgreSQL will automatically execute all .sql files in the docker-entrypoint-initdb.d/ directory -COPY ./sql/postgres/pg_20240905__init.sql /docker-entrypoint-initdb.d/ +COPY ./sql/postgres/pg_20240910__init.sql /docker-entrypoint-initdb.d/ CMD ["postgres"] diff --git a/jupiter/callisto/src/mega_mr_conv.rs b/jupiter/callisto/src/mega_mr_conv.rs index ac1633cd7..63b0b4064 100644 --- a/jupiter/callisto/src/mega_mr_conv.rs +++ b/jupiter/callisto/src/mega_mr_conv.rs @@ -9,7 +9,7 @@ use crate::db_enums::ConvType; pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: i64, - pub mr_id: i64, + pub mr_link: String, pub user_id: i64, pub conv_type: ConvType, pub created_at: DateTime, diff --git a/jupiter/src/storage/init.rs b/jupiter/src/storage/init.rs index 7d1a65643..c9dc052fb 100644 --- a/jupiter/src/storage/init.rs +++ b/jupiter/src/storage/init.rs @@ -51,7 +51,7 @@ async fn setup_sql(conn: &DatabaseConnection) -> Result<(), TransactionError Result, MegaError> { + pub async fn get_open_mr_by_path(&self, path: &str) -> Result, MegaError> { let model = mega_mr::Entity::find() .filter(mega_mr::Column::Path.eq(path)) .filter(mega_mr::Column::Status.eq(MergeStatus::Open)) @@ -126,37 +126,35 @@ impl MonoStorage { Ok(model) } - pub async fn get_mr(&self, mr_id: i64) -> Result, MegaError> { - let model = mega_mr::Entity::find_by_id(mr_id) + pub async fn get_mr(&self, mr_link: &str) -> Result, MegaError> { + let model = mega_mr::Entity::find() + .filter(mega_mr::Column::MrLink.eq(mr_link)) .one(self.get_connection()) .await .unwrap(); Ok(model) } - pub async fn get_open_mr_by_id(&self, mr_id: i64) -> Result, MegaError> { - let model = mega_mr::Entity::find_by_id(mr_id) + pub async fn get_open_mr_by_link( + &self, + mr_link: &str, + ) -> Result, MegaError> { + let model = mega_mr::Entity::find() + .filter(mega_mr::Column::MrLink.eq(mr_link)) .filter(mega_mr::Column::Status.eq(MergeStatus::Open)) .one(self.get_connection()) .await .unwrap(); - // if let Some(model) = model { - // let mr: MergeRequest = model.into(); - // return Ok(Some(mr)); - // } - // Ok(None) Ok(model) } pub async fn save_mr(&self, mr: mega_mr::Model) -> Result<(), MegaError> { - // let model: mega_mr::Model = mr.into(); let a_model = mr.into_active_model(); a_model.insert(self.get_connection()).await.unwrap(); Ok(()) } pub async fn update_mr(&self, mr: mega_mr::Model) -> Result<(), MegaError> { - // let model: mega_mr::Model = mr.into(); let mut a_model = mr.into_active_model(); a_model = a_model.reset_all(); a_model.created_at = NotSet; @@ -166,10 +164,10 @@ impl MonoStorage { pub async fn get_mr_conversations( &self, - mr_id: i64, + mr_link: &str, ) -> Result, MegaError> { let model = mega_mr_conv::Entity::find() - .filter(mega_mr_conv::Column::MrId.eq(mr_id)) + .filter(mega_mr_conv::Column::MrLink.eq(mr_link)) .all(self.get_connection()) .await; Ok(model?) @@ -177,13 +175,13 @@ impl MonoStorage { pub async fn add_mr_conversation( &self, - mr_id: i64, + mr_link: &str, user_id: i64, conv_type: ConvType, ) -> Result { let conversation = mega_mr_conv::Model { id: generate_id(), - mr_id, + mr_link: mr_link.to_owned(), user_id, conv_type, created_at: chrono::Utc::now().naive_utc(), @@ -196,12 +194,12 @@ impl MonoStorage { pub async fn add_mr_comment( &self, - mr_id: i64, + mr_link: &str, user_id: i64, comment: Option, ) -> Result<(), MegaError> { let conv_id = self - .add_mr_conversation(mr_id, user_id, ConvType::Comment) + .add_mr_conversation(mr_link, user_id, ConvType::Comment) .await .unwrap(); let comment = mega_mr_comment::Model { diff --git a/mono/src/api/mr_router.rs b/mono/src/api/mr_router.rs index 9da10f019..93d645855 100644 --- a/mono/src/api/mr_router.rs +++ b/mono/src/api/mr_router.rs @@ -16,18 +16,18 @@ use crate::api::MonoApiServiceState; pub fn routers() -> Router { Router::new() .route("/mr/list", get(get_mr_list)) - .route("/mr/:mr_id/detail", get(mr_detail)) - .route("/mr/:mr_id/merge", post(merge)) - .route("/mr/:mr_id/files", get(get_mr_files)) + .route("/mr/:mr_link/detail", get(mr_detail)) + .route("/mr/:mr_link/merge", post(merge)) + .route("/mr/:mr_link/files", get(get_mr_files)) } async fn merge( - Path(mr_id): Path, + Path(mr_link): Path, state: State, ) -> Result>, ApiError> { ApiRequestEvent::notify(ApiType::MergeRequest, &state.0.context.config); - let res = state.monorepo().merge_mr(mr_id).await; + let res = state.monorepo().merge_mr(&mr_link).await; let res = match res { Ok(_) => CommonResult::success(None), Err(err) => CommonResult::failed(&err.to_string()), @@ -51,11 +51,11 @@ async fn get_mr_list( } async fn mr_detail( - Path(mr_id): Path, + Path(mr_link): Path, state: State, ) -> Result>>, ApiError> { ApiRequestEvent::notify(ApiType::MergeDetail, &state.0.context.config); - let res = state.monorepo().mr_detail(mr_id).await; + let res = state.monorepo().mr_detail(&mr_link).await; let res = match res { Ok(data) => CommonResult::success(Some(data)), Err(err) => CommonResult::failed(&err.to_string()), @@ -64,11 +64,11 @@ async fn mr_detail( } async fn get_mr_files( - Path(mr_id): Path, + Path(mr_link): Path, state: State, ) -> Result>>, ApiError> { ApiRequestEvent::notify(ApiType::MergeFiles, &state.0.context.config); - let res = state.monorepo().mr_tree_files(mr_id).await; + let res = state.monorepo().mr_tree_files(&mr_link).await; let res = match res { Ok(data) => CommonResult::success(Some(data)), Err(err) => CommonResult::failed(&err.to_string()), diff --git a/moon/src/app/(dashboard)/application-layout.tsx b/moon/src/app/(dashboard)/application-layout.tsx index daaf90c7e..826c8a5ed 100644 --- a/moon/src/app/(dashboard)/application-layout.tsx +++ b/moon/src/app/(dashboard)/application-layout.tsx @@ -108,7 +108,7 @@ export function ApplicationLayout({ - + diff --git a/moon/src/components/MergeDetail.tsx b/moon/src/components/MergeDetail.tsx index 03e7e8718..f2bf2ae56 100644 --- a/moon/src/components/MergeDetail.tsx +++ b/moon/src/components/MergeDetail.tsx @@ -13,7 +13,7 @@ const MRDetailPage = ({ mrDetail }) => { const fetchFileList = async () => { set_to_loading(2) try { - const res = await fetch(`/api/mr/${mrDetail.id}/files`); + const res = await fetch(`/api/mr/${mrDetail.mr_link}/files`); const result = await res.json(); setFileData(result.data.data); } catch (err) { @@ -22,7 +22,7 @@ const MRDetailPage = ({ mrDetail }) => { cancel_loading(2) } }; - if (!mrDetail || !mrDetail.id) { + if (!mrDetail || !mrDetail.mr_link) { return; } fetchFileList(); @@ -45,9 +45,9 @@ const MRDetailPage = ({ mrDetail }) => { }); } - const approve_mr = async (index: number, id: number) => { + const approve_mr = async (index: number, mr_link: string) => { set_to_loading(index); - const res = await fetch(`/api/mr/${id}/merge`,{ + const res = await fetch(`/api/mr/${mr_link}/merge`,{ method: 'POST', }); if (res) { @@ -66,7 +66,7 @@ const MRDetailPage = ({ mrDetail }) => { @@ -75,7 +75,7 @@ const MRDetailPage = ({ mrDetail }) => { More} > = ({ mrList }) => { avatar={ } - title={{`MR ${item.id} open by Mega automacticlly${item.title}`}{getStatusTag(item.status)}} + title={{`MR ${item.mr_link} open by Mega automacticlly${item.title}`}{getStatusTag(item.status)}} description={getDescription(item)} /> diff --git a/sql/postgres/pg_20240905__init.sql b/sql/postgres/pg_20240910__init.sql similarity index 98% rename from sql/postgres/pg_20240905__init.sql rename to sql/postgres/pg_20240910__init.sql index a2200e81c..ce97b2ec4 100644 --- a/sql/postgres/pg_20240905__init.sql +++ b/sql/postgres/pg_20240910__init.sql @@ -54,13 +54,13 @@ CREATE INDEX "idx_mr_path" ON "mega_mr" ("path"); CREATE TABLE IF NOT EXISTS "mega_mr_conv" ( "id" BIGINT PRIMARY KEY, - "mr_id" BIGINT NOT NULL, + "mr_link" VARCHAR(20) NOT NULL, "user_id" BIGINT NOT NULL, "conv_type" VARCHAR(20) NOT NULL, "created_at" TIMESTAMP NOT NULL, "updated_at" TIMESTAMP NOT NULL ); -CREATE INDEX "idx_conversation" ON "mega_mr_conv" ("mr_id"); +CREATE INDEX "idx_conversation" ON "mega_mr_conv" ("mr_link"); CREATE TABLE IF NOT EXISTS "mega_mr_comment" ( diff --git a/sql/sqlite/sqlite_20240905_init.sql b/sql/sqlite/sqlite_20240910_init.sql similarity index 98% rename from sql/sqlite/sqlite_20240905_init.sql rename to sql/sqlite/sqlite_20240910_init.sql index def9ed1f4..32a2b2670 100644 --- a/sql/sqlite/sqlite_20240905_init.sql +++ b/sql/sqlite/sqlite_20240910_init.sql @@ -54,13 +54,13 @@ CREATE INDEX "idx_mr_path" ON "mega_mr" ("path"); CREATE TABLE IF NOT EXISTS "mega_mr_conv" ( "id" INTEGER PRIMARY KEY, - "mr_id" INTEGER NOT NULL, + "mr_link" INTEGER NOT NULL, "user_id" INTEGER NOT NULL, "conv_type" TEXT NOT NULL, "created_at" TEXT NOT NULL, "updated_at" TEXT NOT NULL ); -CREATE INDEX "idx_conversation" ON "mega_mr_conv" ("mr_id"); +CREATE INDEX "idx_conversation" ON "mega_mr_conv" ("mr_link"); CREATE TABLE IF NOT EXISTS "mega_mr_comment" (