Skip to content

Commit bb47158

Browse files
committed
fix: Scope repo index prefixes to Git root
1 parent 72cc81c commit bb47158

2 files changed

Lines changed: 82 additions & 12 deletions

File tree

crates/turborepo-lib/src/run/builder.rs

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use std::{
77

88
use chrono::Local;
99
use tracing::Instrument;
10-
use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf, RelativeUnixPathBuf};
10+
use turbopath::{
11+
AbsoluteSystemPath, AbsoluteSystemPathBuf, AnchoredSystemPath, RelativeUnixPathBuf,
12+
};
1113
use turborepo_analytics::{start_analytics, AnalyticsHandle};
1214
use turborepo_api_client::{APIAuth, APIClient, CacheClient, SharedHttpClient};
1315
use turborepo_cache::{AsyncCache, CacheScmState, LazyScmState};
@@ -284,21 +286,39 @@ impl RunBuilder {
284286
}
285287
}
286288

287-
fn all_package_prefixes(pkg_dep_graph: &PackageGraph) -> Vec<RelativeUnixPathBuf> {
289+
fn package_prefix_for_repo_index(
290+
repo_root: &AbsoluteSystemPath,
291+
index_root: &AbsoluteSystemPath,
292+
package_dir: &AnchoredSystemPath,
293+
) -> Result<RelativeUnixPathBuf, Error> {
294+
let full_package_dir = repo_root.resolve(package_dir);
295+
Ok(index_root.anchor(&full_package_dir)?.to_unix())
296+
}
297+
298+
fn all_package_prefixes(
299+
pkg_dep_graph: &PackageGraph,
300+
scm: &SCM,
301+
) -> Result<Vec<RelativeUnixPathBuf>, Error> {
302+
let repo_root = pkg_dep_graph.repo_root();
303+
let index_root = scm.git_root().unwrap_or(repo_root);
288304
let mut prefixes = pkg_dep_graph
289305
.packages()
290306
.filter_map(|(name, _)| pkg_dep_graph.package_dir(name))
291-
.map(|package_dir| package_dir.to_unix())
292-
.collect::<Vec<_>>();
307+
.map(|package_dir| {
308+
Self::package_prefix_for_repo_index(repo_root, index_root, package_dir)
309+
})
310+
.collect::<Result<Vec<_>, _>>()?;
293311

294-
prefixes.extend(
295-
pkg_dep_graph
296-
.root_internal_package_dependencies_paths()
297-
.into_iter()
298-
.map(|package_dir| package_dir.to_unix()),
299-
);
312+
let root_dependency_prefixes = pkg_dep_graph
313+
.root_internal_package_dependencies_paths()
314+
.into_iter()
315+
.map(|package_dir| {
316+
Self::package_prefix_for_repo_index(repo_root, index_root, package_dir)
317+
})
318+
.collect::<Result<Vec<_>, _>>()?;
319+
prefixes.extend(root_dependency_prefixes);
300320

301-
prefixes
321+
Ok(prefixes)
302322
}
303323

304324
/// Resolve the set of packages that should participate in this run.
@@ -493,11 +513,11 @@ impl RunBuilder {
493513
// parallel walk for untracked file discovery. This replaces the
494514
// subprocess approach (ls-tree + diff-index + ls-files race) which
495515
// burned ~500ms of CPU on background threads.
496-
let all_prefixes = Self::all_package_prefixes(&pkg_dep_graph);
497516
let scm = scm_task
498517
.instrument(tracing::info_span!("scm_task_await"))
499518
.await
500519
.expect("detecting scm panicked");
520+
let all_prefixes = Self::all_package_prefixes(&pkg_dep_graph, &scm)?;
501521
let repo_index_task = if all_prefixes.is_empty() {
502522
None
503523
} else {
@@ -1052,6 +1072,51 @@ fn hosts_match(url1: &str, url2: &str) -> bool {
10521072
}
10531073
}
10541074

1075+
#[cfg(test)]
1076+
mod package_prefix_tests {
1077+
use super::*;
1078+
1079+
#[test]
1080+
fn repo_index_prefixes_are_git_root_relative_for_nested_turbo_root() {
1081+
let tmp = tempfile::tempdir().unwrap();
1082+
let git_root = AbsoluteSystemPathBuf::try_from(tmp.path()).unwrap();
1083+
let repo_root = git_root.join_component("downloaded-app");
1084+
1085+
let root_package = AnchoredSystemPath::new("").unwrap();
1086+
let workspace_package = AnchoredSystemPath::new("packages/web").unwrap();
1087+
1088+
assert_eq!(
1089+
RunBuilder::package_prefix_for_repo_index(&repo_root, &git_root, root_package).unwrap(),
1090+
RelativeUnixPathBuf::new("downloaded-app").unwrap()
1091+
);
1092+
assert_eq!(
1093+
RunBuilder::package_prefix_for_repo_index(&repo_root, &git_root, workspace_package)
1094+
.unwrap(),
1095+
RelativeUnixPathBuf::new("downloaded-app/packages/web").unwrap()
1096+
);
1097+
}
1098+
1099+
#[test]
1100+
fn repo_index_prefixes_stay_repo_relative_when_git_root_matches_turbo_root() {
1101+
let tmp = tempfile::tempdir().unwrap();
1102+
let repo_root = AbsoluteSystemPathBuf::try_from(tmp.path()).unwrap();
1103+
1104+
let root_package = AnchoredSystemPath::new("").unwrap();
1105+
let workspace_package = AnchoredSystemPath::new("packages/web").unwrap();
1106+
1107+
assert_eq!(
1108+
RunBuilder::package_prefix_for_repo_index(&repo_root, &repo_root, root_package)
1109+
.unwrap(),
1110+
RelativeUnixPathBuf::new("").unwrap()
1111+
);
1112+
assert_eq!(
1113+
RunBuilder::package_prefix_for_repo_index(&repo_root, &repo_root, workspace_package)
1114+
.unwrap(),
1115+
RelativeUnixPathBuf::new("packages/web").unwrap()
1116+
);
1117+
}
1118+
}
1119+
10551120
#[cfg(test)]
10561121
mod hosts_match_tests {
10571122
use super::*;

crates/turborepo/ARCHITECTURE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ still warming the client before the first network request in the common case.
261261
actually needs for hashing and augments that tracked index with untracked
262262
files only for those prefixes
263263

264+
Those prefixes are relative to the repo index root, which is usually the Git
265+
root. This matters when the Turbo root is nested inside a larger Git repository:
266+
the root package should scope to the nested Turbo directory, not request an
267+
untracked walk of the entire parent repository.
268+
264269
This keeps the cheap tracked-index work overlapped with other startup work while
265270
avoiding a repo-wide untracked walk when only a subset of packages will be
266271
hashed.

0 commit comments

Comments
 (0)