Skip to content
This repository was archived by the owner on Oct 19, 2026. It is now read-only.

Commit ac46041

Browse files
authored
Refactor/buck2 task changes root relative (#2039)
* buck2: standardize task changes as repo-root-relative Signed-off-by: jackieismpc <jackieismpc@gmail.com> (cherry picked from commit 1a75c884b70513125ca9a6798896d8ff23323982) Signed-off-by: jackieismpc <jackieismpc@gmail.com> * test: cover repo-root change normalization Signed-off-by: jackieismpc <jackieismpc@gmail.com> * orion-server: avoid preallocating change normalization Signed-off-by: jackieismpc <jackieismpc@gmail.com> --------- Signed-off-by: jackieismpc <jackieismpc@gmail.com>
1 parent b3bac43 commit ac46041

6 files changed

Lines changed: 105 additions & 276 deletions

File tree

‎api-model/src/buck2/api.rs‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ use crate::buck2::{status::Status, types::ProjectRelativePath};
1616
/// Parameters required to build a task.
1717
#[derive(Debug, Deserialize, Serialize, ToSchema)]
1818
pub struct TaskBuildRequest {
19-
/// The repository base path
19+
/// The Buck2 project path within the monorepo (for example `/jupiter/callisto`).
2020
pub repo: String,
2121
/// The change list link (URL)
2222
pub cl_link: String,
2323
//TODO: for old database only, delete after updated
2424
pub cl_id: i64,
25-
/// The list of file diff changes
25+
/// The list of changed files, expressed relative to the monorepo root.
26+
///
27+
/// Example values:
28+
/// - `jupiter/callisto/src/access_token.rs`
29+
/// - `common/lib.rs`
2630
pub changes: Vec<Status<ProjectRelativePath>>,
2731
/// Buck2 target path (e.g. //app:server). Optional for backward compatibility.
2832
#[serde(default, alias = "targets_path")]
@@ -41,6 +45,7 @@ pub struct RetryBuildRequest {
4145
pub build_id: String,
4246
pub cl_link: String,
4347
pub cl_id: i64,
48+
/// The list of changed files, expressed relative to the monorepo root.
4449
pub changes: Vec<Status<ProjectRelativePath>>,
4550
pub targets: Option<Vec<String>>,
4651
}

‎api-model/src/buck2/types.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ pub enum TaskPhase {
1111
RunningBuild,
1212
}
1313

14+
/// Slash-separated relative path used in Buck2 payloads.
15+
///
16+
/// The exact base directory is defined by the surrounding API. For task/build
17+
/// requests, see the field-level docs to determine whether the path is relative
18+
/// to the monorepo root or some other project root.
1419
#[derive(Clone, Debug, Hash, PartialEq, Eq, Display, Deserialize, Serialize, ToSchema)]
1520
pub struct ProjectRelativePath(String);
1621

‎api-model/src/buck2/ws.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ pub enum WSMessage {
1414
// Server -> Worker messages
1515
TaskBuild {
1616
build_id: String,
17+
/// The Buck2 project path within the monorepo (for example `/jupiter/callisto`).
1718
repo: String,
1819
cl_link: String,
20+
/// The list of changed files, expressed relative to the monorepo root.
1921
changes: Vec<Status<ProjectRelativePath>>,
2022
},
2123

‎ceres/src/build_trigger/changes_calculator.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ impl ChangesCalculator {
4141
&self,
4242
cl_diff_files: Vec<ClDiffFile>,
4343
) -> Result<Vec<Status<ProjectRelativePath>>, MegaError> {
44+
// Orion task requests carry change paths relative to the monorepo root,
45+
// so we preserve repository-relative diff paths here.
4446
let to_project_relative = |path: &PathBuf| -> Result<ProjectRelativePath, MegaError> {
4547
let rel = path
4648
.to_string_lossy()

‎orion-server/src/service/api_v2_service.rs‎

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{convert::Infallible, pin::Pin, time::Duration};
1+
use std::{collections::HashSet, convert::Infallible, pin::Pin, time::Duration};
22

33
use api_model::{
44
buck2::{
@@ -47,6 +47,29 @@ type MessageErrorResponse = (StatusCode, Json<MessageResponse>);
4747
type JsonValueErrorResponse = (StatusCode, Json<Value>);
4848
type LogSseStream = Pin<Box<dyn Stream<Item = Result<Event, Infallible>> + Send>>;
4949

50+
/// Normalize incoming task changes to the repo-root-relative contract.
51+
///
52+
/// The protocol no longer asks workers to guess whether a path was expressed
53+
/// relative to the selected sub-project. We only perform lossless cleanup here:
54+
/// trim accidental leading slashes and drop exact duplicates.
55+
fn normalize_repo_root_changes(
56+
changes: Vec<Status<ProjectRelativePath>>,
57+
) -> Vec<Status<ProjectRelativePath>> {
58+
// Avoid reserving memory directly from request-controlled input length.
59+
let mut normalized = Vec::new();
60+
let mut seen = HashSet::new();
61+
62+
for change in changes {
63+
let normalized_change =
64+
change.into_map(|path| ProjectRelativePath::new(path.as_str().trim_start_matches('/')));
65+
if seen.insert(normalized_change.clone()) {
66+
normalized.push(normalized_change);
67+
}
68+
}
69+
70+
normalized
71+
}
72+
5073
pub async fn task_output(state: &AppState, id: &str) -> Result<Sse<LogSseStream>, StatusCode> {
5174
if !state.scheduler.active_builds.contains_key(id) {
5275
return Err(StatusCode::NOT_FOUND);
@@ -584,6 +607,10 @@ pub async fn build_retry(
584607
state: &AppState,
585608
req: api_model::buck2::api::RetryBuildRequest,
586609
) -> Response {
610+
let req = api_model::buck2::api::RetryBuildRequest {
611+
changes: normalize_repo_root_changes(req.changes),
612+
..req
613+
};
587614
let old_build_id = match req.build_id.parse::<uuid::Uuid>() {
588615
Ok(uuid) => uuid,
589616
Err(_) => {
@@ -881,6 +908,10 @@ async fn handle_immediate_task_dispatch_v2(
881908
}
882909

883910
pub async fn task_handler_v2(state: &AppState, req: TaskBuildRequest) -> Response {
911+
let req = TaskBuildRequest {
912+
changes: normalize_repo_root_changes(req.changes),
913+
..req
914+
};
884915
let task_id = Uuid::now_v7();
885916
if let Err(err) =
886917
OrionTasksRepo::insert_task(task_id, &req.cl_link, &req.repo, &req.changes, &state.conn)
@@ -1020,3 +1051,44 @@ pub async fn get_orion_client_status_by_id(
10201051
})?;
10211052
Ok(Json(OrionClientStatus::from_worker_status(&worker)))
10221053
}
1054+
1055+
#[cfg(test)]
1056+
mod tests {
1057+
use api_model::buck2::{status::Status, types::ProjectRelativePath};
1058+
1059+
use super::normalize_repo_root_changes;
1060+
1061+
#[test]
1062+
fn test_normalize_repo_root_changes_trims_leading_slashes_and_deduplicates() {
1063+
let normalized = normalize_repo_root_changes(vec![
1064+
Status::Modified(ProjectRelativePath::new("/jupiter/callisto/src/main.rs")),
1065+
Status::Modified(ProjectRelativePath::new("jupiter/callisto/src/main.rs")),
1066+
Status::Removed(ProjectRelativePath::new("//common/lib.rs")),
1067+
Status::Removed(ProjectRelativePath::new("common/lib.rs")),
1068+
]);
1069+
1070+
assert_eq!(
1071+
normalized,
1072+
vec![
1073+
Status::Modified(ProjectRelativePath::new("jupiter/callisto/src/main.rs")),
1074+
Status::Removed(ProjectRelativePath::new("common/lib.rs")),
1075+
]
1076+
);
1077+
}
1078+
1079+
#[test]
1080+
fn test_normalize_repo_root_changes_keeps_distinct_status_entries() {
1081+
let normalized = normalize_repo_root_changes(vec![
1082+
Status::Added(ProjectRelativePath::new("/common/lib.rs")),
1083+
Status::Removed(ProjectRelativePath::new("common/lib.rs")),
1084+
]);
1085+
1086+
assert_eq!(
1087+
normalized,
1088+
vec![
1089+
Status::Added(ProjectRelativePath::new("common/lib.rs")),
1090+
Status::Removed(ProjectRelativePath::new("common/lib.rs")),
1091+
]
1092+
);
1093+
}
1094+
}

0 commit comments

Comments
 (0)