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
8 changes: 6 additions & 2 deletions crates/turborepo-lib/src/run/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,8 +1135,10 @@ impl Run {
.pkg_dep_graph
.package_task_context(&PackageName::Root)
.ok_or(Error::MissingRootWorkspace)?;
// Compatibility-payload presence is still required for JS root scopes;
// engines for hashing come from task-contract knowledge instead.
let empty_root_workspace = turborepo_repository::package_graph::PackageInfo::default();
let root_workspace = match root_context.package_info() {
let _root_workspace = match root_context.package_info() {
Some(payload) => payload,
None if !root_context.requires_compatibility_payload() => &empty_root_workspace,
None => return Err(Error::MissingPackagePayload(PackageName::Root)),
Expand Down Expand Up @@ -1206,8 +1208,10 @@ impl Run {
.pkg_dep_graph
.external_resolution_global_file_fallback()
.unwrap_or_default();
let root_engines = self.pkg_dep_graph.root_engines();
let root_engines = (!root_engines.is_empty()).then_some(root_engines);
global_file_result = Some(collect_global_file_hash_inputs(
root_workspace,
root_engines,
&self.repo_root,
self.pkg_dep_graph.package_manager(),
&resolution_file_fallback,
Expand Down
33 changes: 30 additions & 3 deletions crates/turborepo-repository/src/package_graph/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -972,8 +972,21 @@ impl<'a, T: PackageDiscovery + Send + Sync> BuildState<'a, ResolvedPackageManage
crate::task_contracts::ScopeTaskContract::javascript(),
));
}
crate::task_contracts::TaskContractKnowledge::build(observations)
.map_err(|error| Error::TaskContracts(error.to_string()))?
let root_engines = root_package_json
.as_ref()
.and_then(|package_json| package_json.engines())
.map(|engines| {
engines
.into_iter()
.map(|(key, value)| (key.to_string(), value.to_string()))
.collect()
})
.unwrap_or_default();
crate::task_contracts::TaskContractKnowledge::build_with_engines(
observations,
root_engines,
)
.map_err(|error| Error::TaskContracts(error.to_string()))?
});

Ok(PackageGraph {
Expand Down Expand Up @@ -1389,7 +1402,21 @@ impl<T: PackageDiscovery + Send + Sync> BuildState<'_, ResolvedLockfile, T> {
crate::task_contracts::ScopeTaskContract::javascript(),
));
}
crate::task_contracts::TaskContractKnowledge::build(observations).map_err(|error| {
let root_engines = root_package_json
.as_ref()
.and_then(|package_json| package_json.engines())
.map(|engines| {
engines
.into_iter()
.map(|(key, value)| (key.to_string(), value.to_string()))
.collect()
})
.unwrap_or_default();
crate::task_contracts::TaskContractKnowledge::build_with_engines(
observations,
root_engines,
)
.map_err(|error| {
discovery::Error::Failed(Box::new(Error::TaskContracts(error.to_string())))
})?
});
Expand Down
5 changes: 5 additions & 0 deletions crates/turborepo-repository/src/package_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,11 @@ impl PackageGraph {
self.package_manager.as_ref()
}

/// Root `engines` captured into task-contract knowledge at construction.
pub fn root_engines(&self) -> &std::collections::BTreeMap<String, String> {
self.task_contract_knowledge.root_engines()
}

/// Toolchains registered during graph construction.
pub fn toolchains(&self) -> &crate::toolchain::ToolchainRegistry {
&self.toolchains
Expand Down
19 changes: 18 additions & 1 deletion crates/turborepo-repository/src/task_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,32 @@ impl ScopeTaskContract {
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct TaskContractKnowledge {
by_scope: BTreeMap<String, ScopeTaskContract>,
/// Root `package.json` `engines` captured at observation time for global
/// hashing. Empty when there is no root JavaScript package.json.
root_engines: BTreeMap<String, String>,
}

impl TaskContractKnowledge {
pub fn build(
observations: impl IntoIterator<Item = (String, ScopeTaskContract)>,
) -> Result<Self, TaskContractError> {
Self::build_with_engines(observations, BTreeMap::new())
}

pub fn build_with_engines(
observations: impl IntoIterator<Item = (String, ScopeTaskContract)>,
root_engines: BTreeMap<String, String>,
) -> Result<Self, TaskContractError> {
let mut by_scope = BTreeMap::new();
for (scope, contract) in observations {
if by_scope.insert(scope.clone(), contract).is_some() {
return Err(TaskContractError::DuplicateScope { scope });
}
}
Ok(Self { by_scope })
Ok(Self {
by_scope,
root_engines,
})
}

pub fn for_scope(&self, scope: &str) -> ScopeTaskContract {
Expand All @@ -91,6 +104,10 @@ impl TaskContractKnowledge {
.unwrap_or_else(ScopeTaskContract::empty)
}

pub fn root_engines(&self) -> &BTreeMap<String, String> {
&self.root_engines
}

pub fn scopes(&self) -> impl Iterator<Item = (&str, &ScopeTaskContract)> {
self.by_scope
.iter()
Expand Down
24 changes: 13 additions & 11 deletions crates/turborepo-task-hash/src/global_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ use tracing::debug;
use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf, RelativeUnixPathBuf};
use turborepo_env::{DetailedMap, EnvironmentVariableMap, get_global_hashable_env_vars};
use turborepo_hash::{GlobalHashable, TurboHash};
use turborepo_repository::{
package_graph::PackageInfo,
package_manager::{self, PackageManager},
};
use turborepo_repository::package_manager::{self, PackageManager};
use turborepo_run_summary::{GlobalEnvVarSummary, GlobalHashSummary};
use turborepo_scm::SCM;
use turborepo_types::{EnvMode, GlobalHashInputs as GlobalHashInputsTrait};
Expand Down Expand Up @@ -64,7 +61,7 @@ pub struct GlobalHashableInputs<'a> {
pub fn get_global_hash_inputs<'a>(
root_external_dependencies_hash: Option<&'a str>,
root_internal_dependencies_hash: Option<&'a str>,
root_package: &'a PackageInfo,
root_engines: Option<&'a std::collections::BTreeMap<String, String>>,
root_path: &AbsoluteSystemPath,
package_manager: Option<&PackageManager>,
resolution_file_fallback: &[AbsoluteSystemPathBuf],
Expand All @@ -82,7 +79,7 @@ pub fn get_global_hash_inputs<'a>(
global_hashable_env_vars,
engines,
} = collect_global_file_hash_inputs(
root_package,
root_engines,
root_path,
package_manager,
resolution_file_fallback,
Expand Down Expand Up @@ -129,7 +126,8 @@ pub struct GlobalFileHashInputs<'a> {
/// hashing since it has no dependencies on those results.
#[allow(clippy::too_many_arguments, clippy::result_large_err)]
pub fn collect_global_file_hash_inputs<'a>(
root_package: &'a PackageInfo,
// Root `engines` from task-contract knowledge (not a live PackageJson read).
root_engines: Option<&'a std::collections::BTreeMap<String, String>>,
root_path: &AbsoluteSystemPath,
// Absent for a pure Cargo workspace: there is no JavaScript package
// manager to enumerate workspace exclusions for `globalDependencies`.
Expand All @@ -143,7 +141,12 @@ pub fn collect_global_file_hash_inputs<'a>(
global_env: &'a [String],
hasher: &SCM,
) -> Result<GlobalFileHashInputs<'a>, Error> {
let engines = root_package.package_json.engines();
let engines = root_engines.map(|engines| {
engines
.iter()
.map(|(key, value)| (key.as_str(), value.as_str()))
.collect()
});

let global_hashable_env_vars =
get_global_hashable_env_vars(env_at_execution_start, global_env)?;
Expand Down Expand Up @@ -386,7 +389,7 @@ impl<'a> GlobalHashInputsTrait for GlobalHashableInputs<'a> {
mod tests {
use turbopath::AbsoluteSystemPathBuf;
use turborepo_env::EnvironmentVariableMap;
use turborepo_repository::{package_graph::PackageInfo, package_manager::PackageManager};
use turborepo_repository::package_manager::PackageManager;
use turborepo_scm::SCM;
use turborepo_types::EnvMode;

Expand All @@ -408,7 +411,6 @@ mod tests {
.unwrap();

let env_var_map = EnvironmentVariableMap::default();
let package_info = PackageInfo::default();
let fallback = [root.join_component("package.json")];
#[cfg(windows)]
let file_deps = ["C:\\some\\path".to_string()];
Expand All @@ -417,7 +419,7 @@ mod tests {
let result = get_global_hash_inputs(
None,
None,
&package_info,
None,
&root,
Some(&PackageManager::Pnpm),
&fallback,
Expand Down
Loading