Target dependency rules #17389
Replies: 7 comments 35 replies
-
I've adjusted the syntax slightly, to accommodate a per target type style of specifying visibility rules, using the same style as for |
Beta Was this translation helpful? Give feedback.
-
Thanks for taking this up! would love to see this happen, it's one of our most requested features. One thing that I'd love to see in this doc, before proceeding to an implementation, is a list of real-world example use-cases, from multiple teams, that support the design. I.e., ask users for 5-8 real-world scenarios and show in each case how this mechanism supports each scenario with minimal boilerplate. The reason I think this is important is the same reason I've been reluctant to just go ahead and implement something here months ago: We need to keep in mind that the problem to be solved is "dependency hygiene enforcement", not "lack of visibility rules". "visibility rules" is a paradigm for solving "dependency hygiene enforcement", and it happens to be Bazel's paradigm, so it's the one people focus on. I'm not yet convinced that the "visibility" paradigm solves the problem of "dependency hygiene" in all cases. So I wonder if we need a lower-level, highly customizable, mechanism, with a very easy way to plug in your own repo's logic, and with "visibility" as the default "logic plugin" we ship. |
Beta Was this translation helpful? Give feedback.
-
I have 2 use cases for visibility in the StackStorm (st2) project.
|
Beta Was this translation helpful? Give feedback.
-
I have an open question for the visibility implementation regarding how to treat relative paths (paths that begin with a period) when inherited in subdirectories. Example: # src/example/BUILD
__dependencies_rules__(
# Python sources must only depend on targets in this directory.
(python_sources, ".", "!*"),
) Now, for targets in the On one hand, I think this makes perfect sense, but what if what I wanted was to just root my rule where it was defined, and any rules that inherit it also inherit the root where it was declared rather than where it gets inherited. Lets look at another example: # src/example/BUILD
__dependencies_rules__(
# Python sources must only depend on targets in this directory subtree.
(python_sources, "./*", "!*"),
) Now this translates to a rule that says that any Python sources may only depend on targets in So this long winded discussion leads to my question: are relative paths treated correctly, wrongly or should it be optional which way to treat them? (I've been so emerged in making all this work, so this nuance didn't really occur to me until now.. 😬 ) |
Beta Was this translation helpful? Give feedback.
-
Note to self to include in upcoming docs: A neat trick to help have rules apply to a subset of 3rd party deps, is to split them out into a separate Before: # 3rdparty/BUILD
python_requirements() After: # 3rdparty/common/BUILD
python_requirements() # 3rdparty/subset/BUILD
python_requirements() With the above, you may have rules like: __dependencies_rules__(
(python_sources, "3rdparty/common", "!3rdparty/subset", ...),
) But keeping the two requirements targets in the same resolve will still produce a single lockfile, awesome! |
Beta Was this translation helpful? Give feedback.
-
Can I make a UI consistency nit? We use the word Unless we want to change the goal and other references to |
Beta Was this translation helpful? Give feedback.
-
Syntax proposal for extended rule spec selection syntax. When looking up which rules that apply for a given dependency link between two targets, we currently only use a set of target type globs followed by a list of rules. Now, if we want to have different rules based on other properties of the target then it's type, we need some syntax for how to declare those properties. With target types it looks like: # A rule spec:
(
# Target type selection globs
("target_a", "target_b", "wild_*"),
rules...
) So the overall structure for the "rule spec" is a n-tuple where the first element is the "selector" and the rest are simply rule globs. Now we may either make the string syntax for the target type a little bit fancier to support selecting based on target filename or tag etc, or switch to a structured format that will be slightly more verbose but crystal clear. I'm a little bit in the camp to go with a structured syntax, but with some sugar to support a more concise string representation of the more common uses. Example: # Rule spec:
(
( # Selectors
{"type": "target_a", "path": "myfile.lib"},
{"type": "resource*", "tag": "libs"},
),
rules...,
) Now I may be off, but I think that path and tag will cover a majority of use cases, so support for them in text form could look like: # Rule spec:
(
( # Selectors
"target_a[/myfile.lib]", # specific target type for a specific file in this directory (i.e. same anchor rules as for rule globs)
"resource*(libs)", # resources tagged `libs`
"file*(all-txt)[files/**/*.txt]", # all file and files targets tagged `all-txt` for all .txt files
"[res/*.png]", # short cut for `*[res/*.png]` i.e. any target type for all png files in res/
),
rules...,
) |
Beta Was this translation helpful? Give feedback.
-
Copied from the design doc:
Background
Monorepos can by definition house very large code bases. In order to maintain good architectural hygiene it is important to adhere to intermodule interfaces and protocols to avoid chaos and escalating maintenance.
Use Case
By implementing clear boundaries for modules to interact only via public interfaces, the inner workings of the modules can be kept private, avoiding intricate and complicated dependency patterns.
The dependency rules instructions offers the ability in a declarative way to specify which modules may depend on a certain target.
Motivation
We want to support large projects promoting good systems design. The dependency rules feature will be a tool that helps with that.
Feature request: #13393
Core API PR: #17550
Visibility implementation PR: #17401
Beta Was this translation helpful? Give feedback.
All reactions