Skip to content

Commit 96b0ee1

Browse files
committed
feat: refactor build trigger system and fix error
Signed-off-by: allure <1550220889@qq.com>
1 parent 0cd8845 commit 96b0ee1

9 files changed

Lines changed: 202 additions & 123 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use std::{
2+
path::{Path, PathBuf},
3+
sync::Arc,
4+
};
5+
6+
use common::errors::MegaError;
7+
use git_internal::hash::ObjectHash;
8+
use jupiter::storage::Storage;
9+
10+
use crate::{
11+
api_service::{cache::GitObjectCache, mono_api_service::MonoApiService},
12+
build_trigger::{SerializableBuildInfo, SerializableStatus, TriggerContext},
13+
model::change_list::{ClDiffFile, ClFilesRes},
14+
};
15+
16+
pub struct ChangesCalculator {
17+
storage: Storage,
18+
git_object_cache: Arc<GitObjectCache>,
19+
}
20+
21+
impl ChangesCalculator {
22+
pub fn new(storage: Storage, git_object_cache: Arc<GitObjectCache>) -> Self {
23+
Self {
24+
storage,
25+
git_object_cache,
26+
}
27+
}
28+
29+
pub async fn get_builds_for_commit(
30+
&self,
31+
context: &TriggerContext,
32+
) -> Result<Vec<SerializableBuildInfo>, MegaError> {
33+
let old_files = self.get_commit_blobs(&context.from_hash).await?;
34+
let new_files = self.get_commit_blobs(&context.commit_hash).await?;
35+
let diff_files = self.cl_files_list(old_files, new_files).await?;
36+
37+
let changes = self.build_changes(&context.repo_path, diff_files)?;
38+
39+
Ok(vec![SerializableBuildInfo { changes }])
40+
}
41+
42+
fn build_changes(
43+
&self,
44+
cl_path: &str,
45+
cl_diff_files: Vec<ClDiffFile>,
46+
) -> Result<Vec<SerializableStatus>, MegaError> {
47+
let cl_base = PathBuf::from(cl_path);
48+
let path_str = cl_base.to_str().ok_or_else(|| {
49+
MegaError::Other(format!("CL base path is not valid UTF-8: {:?}", cl_base))
50+
})?;
51+
52+
let changes = cl_diff_files
53+
.into_iter()
54+
.map(|m| {
55+
let mut item: ClFilesRes = m.into();
56+
item.path = cl_base.join(item.path).to_string_lossy().to_string();
57+
item
58+
})
59+
.collect::<Vec<_>>();
60+
61+
let counter_changes = changes
62+
.iter()
63+
.filter(|&s| PathBuf::from(&s.path).starts_with(&cl_base))
64+
.map(|s| {
65+
let rel = Path::new(&s.path)
66+
.strip_prefix(path_str)
67+
.map_err(|_| {
68+
MegaError::Other(format!("Invalid project-relative path: {}", s.path))
69+
})?
70+
.to_string_lossy()
71+
.replace('\\', "/")
72+
.trim_start_matches('/')
73+
.to_string();
74+
75+
let status = if s.action == "new" {
76+
SerializableStatus::Added(rel)
77+
} else if s.action == "deleted" {
78+
SerializableStatus::Removed(rel)
79+
} else if s.action == "modified" {
80+
SerializableStatus::Modified(rel)
81+
} else {
82+
return Err(MegaError::Other(format!(
83+
"Unsupported change action: {}",
84+
s.action
85+
)));
86+
};
87+
Ok(status)
88+
})
89+
.collect::<Result<Vec<_>, MegaError>>()?;
90+
91+
Ok(counter_changes)
92+
}
93+
94+
async fn get_commit_blobs(
95+
&self,
96+
commit_hash: &str,
97+
) -> Result<Vec<(PathBuf, ObjectHash)>, MegaError> {
98+
let api_service = MonoApiService {
99+
storage: self.storage.clone(),
100+
git_object_cache: self.git_object_cache.clone(),
101+
};
102+
api_service.get_commit_blobs(commit_hash).await
103+
}
104+
105+
async fn cl_files_list(
106+
&self,
107+
old_files: Vec<(PathBuf, ObjectHash)>,
108+
new_files: Vec<(PathBuf, ObjectHash)>,
109+
) -> Result<Vec<ClDiffFile>, MegaError> {
110+
let api_service = MonoApiService {
111+
storage: self.storage.clone(),
112+
git_object_cache: self.git_object_cache.clone(),
113+
};
114+
api_service.cl_files_list(old_files, new_files).await
115+
}
116+
}

ceres/src/build_trigger/git_push_handler.rs

Lines changed: 12 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,39 @@
1-
use std::{path::PathBuf, sync::Arc};
1+
use std::sync::Arc;
22

33
use async_trait::async_trait;
4-
use bellatrix::orion_client::{BuildInfo, ProjectRelativePath, Status};
54
use chrono::Utc;
65
use common::errors::MegaError;
7-
use git_internal::hash::ObjectHash;
86
use jupiter::storage::Storage;
97

8+
use super::changes_calculator::ChangesCalculator;
109
use crate::{
11-
api_service::{cache::GitObjectCache, mono_api_service::MonoApiService},
10+
api_service::cache::GitObjectCache,
1211
build_trigger::{
13-
BuildTrigger, BuildTriggerPayload, BuildTriggerType, TriggerContext, TriggerHandler,
12+
BuildTrigger, BuildTriggerPayload, BuildTriggerType, GitPushPayload, TriggerContext,
13+
TriggerHandler,
1414
},
15-
model::change_list::ClFilesRes,
1615
};
1716

1817
/// Handler for Git push triggers.
1918
pub struct GitPushHandler {
20-
storage: Storage,
21-
git_object_cache: Arc<GitObjectCache>,
19+
changes_calculator: ChangesCalculator,
2220
}
2321

2422
impl GitPushHandler {
2523
pub fn new(storage: Storage, git_object_cache: Arc<GitObjectCache>) -> Self {
2624
Self {
27-
storage,
28-
git_object_cache,
25+
changes_calculator: ChangesCalculator::new(storage, git_object_cache),
2926
}
3027
}
31-
32-
pub async fn get_builds_for_commit(
33-
&self,
34-
context: &TriggerContext,
35-
) -> Result<Vec<BuildInfo>, MegaError> {
36-
let old_files = self.get_commit_blobs(&context.from_hash).await?;
37-
let new_files = self.get_commit_blobs(&context.commit_hash).await?;
38-
let diff_files = self.cl_files_list(old_files, new_files).await?;
39-
40-
let changes = self.build_changes(&context.repo_path, diff_files)?;
41-
42-
let builds = vec![BuildInfo {
43-
changes: changes.clone(),
44-
}];
45-
46-
Ok(builds)
47-
}
48-
49-
fn build_changes(
50-
&self,
51-
cl_path: &str,
52-
cl_diff_files: Vec<crate::model::change_list::ClDiffFile>,
53-
) -> Result<Vec<Status<ProjectRelativePath>>, MegaError> {
54-
let cl_base = PathBuf::from(cl_path);
55-
let path_str = cl_base.to_str().ok_or_else(|| {
56-
MegaError::Other(format!("CL base path is not valid UTF-8: {:?}", cl_base))
57-
})?;
58-
59-
let changes = cl_diff_files
60-
.into_iter()
61-
.map(|m| {
62-
let mut item: ClFilesRes = m.into();
63-
item.path = cl_base.join(item.path).to_string_lossy().to_string();
64-
item
65-
})
66-
.collect::<Vec<_>>();
67-
68-
let counter_changes = changes
69-
.iter()
70-
.filter(|&s| PathBuf::from(&s.path).starts_with(&cl_base))
71-
.map(|s| {
72-
let path = ProjectRelativePath::from_abs(&s.path, path_str).ok_or_else(|| {
73-
MegaError::Other(format!("Invalid project-relative path: {}", s.path))
74-
})?;
75-
let status = if s.action == "new" {
76-
Status::Added(path)
77-
} else if s.action == "deleted" {
78-
Status::Removed(path)
79-
} else if s.action == "modified" {
80-
Status::Modified(path)
81-
} else {
82-
return Err(MegaError::Other(format!(
83-
"Unsupported change action: {}",
84-
s.action
85-
)));
86-
};
87-
Ok(status)
88-
})
89-
.collect::<Result<Vec<_>, MegaError>>()?;
90-
91-
Ok(counter_changes)
92-
}
93-
94-
async fn get_commit_blobs(
95-
&self,
96-
commit_hash: &str,
97-
) -> Result<Vec<(PathBuf, ObjectHash)>, MegaError> {
98-
let api_service = MonoApiService {
99-
storage: self.storage.clone(),
100-
git_object_cache: self.git_object_cache.clone(),
101-
};
102-
api_service.get_commit_blobs(commit_hash).await
103-
}
104-
105-
async fn cl_files_list(
106-
&self,
107-
old_files: Vec<(PathBuf, ObjectHash)>,
108-
new_files: Vec<(PathBuf, ObjectHash)>,
109-
) -> Result<Vec<crate::model::change_list::ClDiffFile>, MegaError> {
110-
let api_service = MonoApiService {
111-
storage: self.storage.clone(),
112-
git_object_cache: self.git_object_cache.clone(),
113-
};
114-
api_service.cl_files_list(old_files, new_files).await
115-
}
11628
}
11729

11830
#[async_trait]
11931
impl TriggerHandler for GitPushHandler {
12032
async fn handle(&self, context: &TriggerContext) -> Result<BuildTrigger, MegaError> {
121-
let builds = self.get_builds_for_commit(context).await?;
33+
let builds = self
34+
.changes_calculator
35+
.get_builds_for_commit(context)
36+
.await?;
12237

12338
let cl_link = context.cl_link.clone().unwrap_or_else(|| {
12439
format!(
@@ -132,7 +47,7 @@ impl TriggerHandler for GitPushHandler {
13247
trigger_type: context.trigger_type,
13348
trigger_source: context.trigger_source,
13449
trigger_time: Utc::now(),
135-
payload: BuildTriggerPayload::GitPush(crate::build_trigger::GitPushPayload {
50+
payload: BuildTriggerPayload::GitPush(GitPushPayload {
13651
repo: context.repo_path.clone(),
13752
from_hash: context.from_hash.clone(),
13853
commit_hash: context.commit_hash.clone(),

ceres/src/build_trigger/manual_handler.rs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,71 @@ use chrono::Utc;
55
use common::errors::MegaError;
66
use jupiter::storage::Storage;
77

8-
use super::git_push_handler::GitPushHandler;
8+
use super::changes_calculator::ChangesCalculator;
99
use crate::{
1010
api_service::cache::GitObjectCache,
1111
build_trigger::{
12-
BuildTrigger, BuildTriggerPayload, BuildTriggerType, TriggerContext, TriggerHandler,
12+
BuildTrigger, BuildTriggerPayload, BuildTriggerType, ManualPayload, TriggerContext,
13+
TriggerHandler,
1314
},
1415
};
1516

1617
/// Handler for manual build triggers.
1718
pub struct ManualHandler {
18-
git_push_handler: GitPushHandler,
19+
storage: Storage,
20+
changes_calculator: ChangesCalculator,
1921
}
2022

2123
impl ManualHandler {
2224
pub fn new(storage: Storage, git_object_cache: Arc<GitObjectCache>) -> Self {
2325
Self {
24-
git_push_handler: GitPushHandler::new(storage, git_object_cache),
26+
storage: storage.clone(),
27+
changes_calculator: ChangesCalculator::new(storage, git_object_cache),
2528
}
2629
}
30+
31+
/// Get the parent commit hash for a given commit.
32+
/// Returns the first parent if available, otherwise returns the same commit hash.
33+
async fn get_parent_commit(&self, commit_hash: &str) -> Result<String, MegaError> {
34+
let commit = self
35+
.storage
36+
.mono_storage()
37+
.get_commit_by_hash(commit_hash)
38+
.await?
39+
.ok_or_else(|| {
40+
MegaError::Other(format!("[code:404] Commit not found: {}", commit_hash))
41+
})?;
42+
43+
// Parse parents_id JSON array
44+
let parent_ids: Vec<String> =
45+
serde_json::from_value(commit.parents_id.clone()).unwrap_or_default();
46+
47+
// Use first parent if available, otherwise return same hash (initial commit case)
48+
Ok(parent_ids
49+
.first()
50+
.cloned()
51+
.unwrap_or_else(|| commit_hash.to_string()))
52+
}
2753
}
2854

2955
#[async_trait]
3056
impl TriggerHandler for ManualHandler {
3157
async fn handle(&self, context: &TriggerContext) -> Result<BuildTrigger, MegaError> {
32-
// Reuse GitPushHandler logic for getting builds
33-
let builds = self.git_push_handler.get_builds_for_commit(context).await?;
58+
let from_hash = if context.from_hash == context.commit_hash {
59+
self.get_parent_commit(&context.commit_hash).await?
60+
} else {
61+
context.from_hash.clone()
62+
};
63+
64+
let adjusted_context = TriggerContext {
65+
from_hash: from_hash.clone(),
66+
..context.clone()
67+
};
68+
69+
let builds = self
70+
.changes_calculator
71+
.get_builds_for_commit(&adjusted_context)
72+
.await?;
3473

3574
let cl_link = context.cl_link.clone().unwrap_or_else(|| {
3675
format!(
@@ -44,7 +83,7 @@ impl TriggerHandler for ManualHandler {
4483
trigger_type: BuildTriggerType::Manual,
4584
trigger_source: context.trigger_source,
4685
trigger_time: Utc::now(),
47-
payload: BuildTriggerPayload::Manual(crate::build_trigger::ManualPayload {
86+
payload: BuildTriggerPayload::Manual(ManualPayload {
4887
repo: context.repo_path.clone(),
4988
commit_hash: context.commit_hash.clone(),
5089
triggered_by: context

ceres/src/build_trigger/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use jupiter::storage::Storage;
77

88
use crate::api_service::cache::GitObjectCache;
99

10+
mod changes_calculator;
1011
mod dispatcher;
1112
mod git_push_handler;
1213
mod manual_handler;

0 commit comments

Comments
 (0)