Skip to content

Commit f0070cd

Browse files
committed
Use package boundaries rules to restrict package's dependencies and dependents
1 parent 3f35410 commit f0070cd

File tree

3 files changed

+97
-35
lines changed

3 files changed

+97
-35
lines changed

crates/turborepo-lib/src/boundaries/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ pub enum SecondaryDiagnostic {
6767

6868
#[derive(Clone, Debug, Error, Diagnostic)]
6969
pub enum BoundariesDiagnostic {
70+
#[error("Package boundaries rules cannot have `tags` key")]
71+
PackageBoundariesHasTags {
72+
#[label("tags defined here")]
73+
span: Option<SourceSpan>,
74+
#[source_code]
75+
text: NamedSource<String>,
76+
},
7077
#[error("Tag `{tag}` cannot share the same name as package `{package}`")]
7178
TagSharesPackageName {
7279
tag: String,

crates/turborepo-lib/src/boundaries/tags.rs

+82-35
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,53 @@ impl Run {
177177
Ok(None)
178178
}
179179

180+
pub(crate) fn check_tag(
181+
&self,
182+
diagnostics: &mut Vec<BoundariesDiagnostic>,
183+
dependencies: Option<&ProcessedPermissions>,
184+
dependents: Option<&ProcessedPermissions>,
185+
pkg: &PackageNode,
186+
package_json: &PackageJson,
187+
) -> Result<(), Error> {
188+
if let Some(dependency_permissions) = dependencies {
189+
for dependency in self.pkg_dep_graph().dependencies(&pkg) {
190+
if matches!(dependency, PackageNode::Root) {
191+
continue;
192+
}
193+
194+
let dependency_tags = self.load_package_tags(dependency.as_package_name());
195+
196+
diagnostics.extend(self.validate_relation(
197+
pkg.as_package_name(),
198+
package_json,
199+
dependency.as_package_name(),
200+
dependency_tags,
201+
dependency_permissions.allow.as_ref(),
202+
dependency_permissions.deny.as_ref(),
203+
)?);
204+
}
205+
}
206+
207+
if let Some(dependent_permissions) = dependents {
208+
for dependent in self.pkg_dep_graph().ancestors(&pkg) {
209+
if matches!(dependent, PackageNode::Root) {
210+
continue;
211+
}
212+
let dependent_tags = self.load_package_tags(dependent.as_package_name());
213+
diagnostics.extend(self.validate_relation(
214+
pkg.as_package_name(),
215+
package_json,
216+
dependent.as_package_name(),
217+
dependent_tags,
218+
dependent_permissions.allow.as_ref(),
219+
dependent_permissions.deny.as_ref(),
220+
)?)
221+
}
222+
}
223+
224+
Ok(())
225+
}
226+
180227
pub(crate) fn check_package_tags(
181228
&self,
182229
pkg: PackageNode,
@@ -185,6 +232,34 @@ impl Run {
185232
tags_rules: &ProcessedRulesMap,
186233
) -> Result<Vec<BoundariesDiagnostic>, Error> {
187234
let mut diagnostics = Vec::new();
235+
let package_boundaries = self
236+
.turbo_json_loader()
237+
.load(pkg.as_package_name())
238+
.ok()
239+
.and_then(|turbo_json| turbo_json.boundaries.as_ref());
240+
241+
if let Some(boundaries) = package_boundaries {
242+
if let Some(tags) = &boundaries.tags {
243+
let (span, text) = tags.span_and_text("turbo.json");
244+
diagnostics.push(BoundariesDiagnostic::PackageBoundariesHasTags { span, text });
245+
}
246+
let dependencies = boundaries
247+
.dependencies
248+
.clone()
249+
.map(|deps| deps.into_inner().into());
250+
let dependents = boundaries
251+
.dependents
252+
.clone()
253+
.map(|deps| deps.into_inner().into());
254+
255+
self.check_tag(
256+
&mut diagnostics,
257+
dependencies.as_ref(),
258+
dependents.as_ref(),
259+
&pkg,
260+
package_json,
261+
)?;
262+
}
188263

189264
// We don't allow tags to share the same name as the package because
190265
// we allow package names to be used as a tag
@@ -210,41 +285,13 @@ impl Run {
210285

211286
for tag in current_package_tags.iter() {
212287
if let Some(rule) = tags_rules.get(tag.as_inner()) {
213-
if let Some(dependency_permissions) = &rule.dependencies {
214-
for dependency in self.pkg_dep_graph().dependencies(&pkg) {
215-
if matches!(dependency, PackageNode::Root) {
216-
continue;
217-
}
218-
219-
let dependency_tags = self.load_package_tags(dependency.as_package_name());
220-
221-
diagnostics.extend(self.validate_relation(
222-
pkg.as_package_name(),
223-
package_json,
224-
dependency.as_package_name(),
225-
dependency_tags,
226-
dependency_permissions.allow.as_ref(),
227-
dependency_permissions.deny.as_ref(),
228-
)?);
229-
}
230-
}
231-
232-
if let Some(dependent_permissions) = &rule.dependents {
233-
for dependent in self.pkg_dep_graph().ancestors(&pkg) {
234-
if matches!(dependent, PackageNode::Root) {
235-
continue;
236-
}
237-
let dependent_tags = self.load_package_tags(dependent.as_package_name());
238-
diagnostics.extend(self.validate_relation(
239-
pkg.as_package_name(),
240-
package_json,
241-
dependent.as_package_name(),
242-
dependent_tags,
243-
dependent_permissions.allow.as_ref(),
244-
dependent_permissions.deny.as_ref(),
245-
)?)
246-
}
247-
}
288+
self.check_tag(
289+
&mut diagnostics,
290+
rule.dependencies.as_ref(),
291+
rule.dependents.as_ref(),
292+
&pkg,
293+
package_json,
294+
)?;
248295
}
249296
}
250297

crates/turborepo-lib/src/query/boundaries.rs

+8
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ impl From<BoundariesDiagnostic> for Diagnostic {
100100
import: None,
101101
reason: Some(tag),
102102
},
103+
BoundariesDiagnostic::PackageBoundariesHasTags { span, text: _ } => Diagnostic {
104+
message,
105+
path: None,
106+
start: span.map(|span| span.offset()),
107+
end: span.map(|span| span.offset() + span.len()),
108+
import: None,
109+
reason: None,
110+
},
103111
}
104112
}
105113
}

0 commit comments

Comments
 (0)