Skip to content

Commit

Permalink
Rework peer dep.
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Oct 6, 2023
1 parent b7cde16 commit 2b57577
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 46 deletions.
4 changes: 2 additions & 2 deletions nextgen/action-graph/tests/action_graph_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ mod action_graph {
let project = container.project_graph.get("cases").unwrap();
let task = project.get_task("parallel").unwrap();

builder.run_task(&project, &task, None).unwrap();
builder.run_task(&project, task, None).unwrap();

let graph = builder.build().unwrap();

Expand All @@ -462,7 +462,7 @@ mod action_graph {
let project = container.project_graph.get("cases").unwrap();
let task = project.get_task("serial").unwrap();

builder.run_task(&project, &task, None).unwrap();
builder.run_task(&project, task, None).unwrap();

let graph = builder.build().unwrap();

Expand Down
52 changes: 46 additions & 6 deletions nextgen/project-builder/src/project_builder.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use moon_common::path::WorkspaceRelativePath;
use moon_common::{color, consts, Id};
use moon_config::{
DependencyConfig, DependencySource, InheritedTasksManager, InheritedTasksResult, LanguageType,
PlatformType, ProjectConfig, ProjectDependsOn, TaskConfig, ToolchainConfig,
DependencyConfig, DependencyScope, DependencySource, InheritedTasksManager,
InheritedTasksResult, LanguageType, PlatformType, ProjectConfig, ProjectDependsOn, TaskConfig,
ToolchainConfig,
};
use moon_file_group::FileGroup;
use moon_project::Project;
use moon_task::Task;
use moon_task::{TargetScope, Task};
use moon_task_builder::{DetectPlatformEvent, TasksBuilder, TasksBuilderContext};
use rustc_hash::FxHashMap;
use starbase_events::{Emitter, Event};
Expand Down Expand Up @@ -197,11 +198,13 @@ impl<'app> ProjectBuilder<'app> {

#[tracing::instrument(name = "project", skip_all)]
pub async fn build(mut self) -> miette::Result<Project> {
let tasks = self.build_tasks().await?;

let mut project = Project {
alias: self.alias.map(|a| a.to_owned()),
dependencies: self.build_dependencies()?,
dependencies: self.build_dependencies(&tasks)?,
file_groups: self.build_file_groups()?,
tasks: self.build_tasks().await?,
tasks,
id: self.id.to_owned(),
language: self.language,
platform: self.platform,
Expand All @@ -220,7 +223,10 @@ impl<'app> ProjectBuilder<'app> {
Ok(project)
}

fn build_dependencies(&self) -> miette::Result<FxHashMap<Id, DependencyConfig>> {
fn build_dependencies(
&self,
tasks: &BTreeMap<Id, Task>,
) -> miette::Result<FxHashMap<Id, DependencyConfig>> {
let mut deps = FxHashMap::default();

trace!(id = self.id.as_str(), "Building project dependencies");
Expand All @@ -237,7 +243,41 @@ impl<'app> ProjectBuilder<'app> {

deps.insert(dep_config.id.clone(), dep_config);
}
}

// Tasks can depend on arbitray projects, so include them also
for task_config in tasks.values() {
for task_dep in &task_config.deps {
if let TargetScope::Project(dep_id) = &task_dep.scope {
// Already a dependency, or references self
if deps.contains_key(dep_id)
|| self.id == dep_id
|| self.alias.as_ref().is_some_and(|a| *a == dep_id.as_str())
{
continue;
}

trace!(
id = self.id.as_str(),
dep = dep_id.as_str(),
task = task_config.target.as_str(),
"Marking arbitrary project as a peer dependency because of a task dependency"
);

deps.insert(
dep_id.to_owned(),
DependencyConfig {
id: dep_id.to_owned(),
scope: DependencyScope::Peer,
source: DependencySource::Implicit,
via: Some(task_config.target.to_string()),
},
);
}
}
}

if !deps.is_empty() {
trace!(
id = self.id.as_str(),
deps = ?deps.keys().map(|k| k.as_str()).collect::<Vec<_>>(),
Expand Down
41 changes: 3 additions & 38 deletions nextgen/project-graph/src/project_graph_builder.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
use crate::project_events::ExtendProjectEvent;
use crate::project_events::ExtendProjectGraphEvent;
use crate::project_events::{ExtendProjectEvent, ExtendProjectGraphEvent};
use crate::project_graph::{GraphType, ProjectGraph, ProjectNode};
use crate::project_graph_cache::ProjectsState;
use crate::project_graph_error::ProjectGraphError;
use crate::project_graph_hash::ProjectGraphHash;
use crate::projects_locator::locate_projects_with_globs;
use async_recursion::async_recursion;
use moon_cache::CacheEngine;
use moon_common::is_test_env;
use moon_common::path::{to_virtual_string, WorkspaceRelativePath, WorkspaceRelativePathBuf};
use moon_common::{color, consts, Id};
use moon_config::{
DependencyScope, InheritedTasksManager, ToolchainConfig, WorkspaceConfig, WorkspaceProjects,
};
use moon_common::{color, consts, is_test_env, Id};
use moon_config::{InheritedTasksManager, ToolchainConfig, WorkspaceConfig, WorkspaceProjects};
use moon_hash::HashEngine;
use moon_project::Project;
use moon_project_builder::{DetectLanguageEvent, ProjectBuilder, ProjectBuilderContext};
use moon_project_constraints::{enforce_project_type_relationships, enforce_tag_relationships};
use moon_task::TargetScope;
use moon_task_builder::DetectPlatformEvent;
use moon_vcs::BoxedVcs;
use petgraph::graph::DiGraph;
Expand Down Expand Up @@ -256,36 +251,6 @@ impl<'app> ProjectGraphBuilder<'app> {
}
}

// Tasks can depend on arbitray projects, so include them also
for (task_id, task_config) in &project.tasks {
for task_dep in &task_config.deps {
if let TargetScope::Project(dep_id) = &task_dep.scope {
if
// Already a dependency
project.dependencies.contains_key(dep_id) ||
// Don't reference itself
project.matches_locator(dep_id.as_str())
{
continue;
}

if cycle.contains(dep_id) {
warn!(
id = id.as_str(),
dependency_id = dep_id.as_str(),
task_id = task_id.as_str(),
"Encountered a dependency cycle (from task); will disconnect nodes to avoid recursion",
);
} else {
edges.push((
self.internal_load(dep_id, cycle).await?,
DependencyScope::Peer,
));
}
}
}
}

// Insert into the graph and connect edges
let index = self.graph.add_node(project);

Expand Down
26 changes: 26 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,32 @@
- More accurately monitors signals (ctrl+c) and shutdowns.
- Tasks can now be configured with a timeout.

## Unreleased

#### 💥 Breaking

- Tasks that depend (via `deps`) on other tasks from arbitrary projects (the parent project doesn't
implicitly or explicitly depend on the other project) will now automatically mark that other
project as a "peer" dependency. For example, "b" becomes a peer dependency for "a".

```yaml
tasks:
build:
deps: ['b:build']

# Now internally becomes:
dependsOn:
- id: 'b'
scope: 'peer'

tasks:
build:
deps: ['b:build']
```
We're marking this as a breaking change as this could subtly introduce cycles in the project graph
that weren't present before, and for Node.js projects, this may inject `peerDependencies`.

## 1.14.5

#### 🐞 Fixes
Expand Down

0 comments on commit 2b57577

Please sign in to comment.