Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new visibility field to targets to limit target dependees. #15803

Closed
wants to merge 15 commits into from

Conversation

kaos
Copy link
Member

@kaos kaos commented Jun 10, 2022

Closes #13393.

Example

python_sources(
  ...,
  visibility=["<private>"]  # will only be importable from this subtree. Default is `["<public>"]`.
)

resources(
  ...,
  visibility=["src/python/some/lib/", "<private>"]  # will be private, except for `some/lib` which will be granted access.
)

Example error message:

pants.engine.target.VisibilityViolationError: src/python/pants/backend/docker/goals/tailor.py is not visible to src/python/pants/backend/docker/register.py.

Visibility for python_source src/python/pants/backend/docker/goals/tailor.py : <private>.

Also introduces a new `defaults` target which allows to dynamically provide "scoped" default field values.

Closes pantsbuild#13393.

[ci skip-rust]

[ci skip-build-wheels]
@thejcannon
Copy link
Member

Did you just implement #13767? 😐

@kaos
Copy link
Member Author

kaos commented Jun 11, 2022

Did you just implement #13767? 😐

Oh, yeah this would need some more work, but yes pretty much ;)

@kaos
Copy link
Member Author

kaos commented Jun 11, 2022

However I feel the defaults may be a more involved topic better suited in a dedicated PR, so am considering limiting this one to just the visibility field and implementation. That leaves it at a sub optimal use, but could serve as a smoother introduction.

@Eric-Arellano
Copy link
Contributor

Cool!! I agree it would be better to have this only focus on visibility and leave off defaults

@kaos kaos marked this pull request as ready for review June 14, 2022 11:32
Copy link
Member

@stuhood stuhood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines 24 to 25
class ValidateVisibilityRulesRequest(ValidateDependenciesRequest):
field_set_type = ValidateVisibilityRulesFieldSet
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically ValidateDependenciesRequest operates on the consuming target, rather than on the producing target. That means that if someone defined a consuming target which didn't have the visibility field, the producer's visibility wouldn't be validated. I'm not really sure how ValidateDependenciesRequest could be adapted to solve that.

I don't think that that is worth worrying too much about, but maybe worth making a note of here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have a check that enforces all Target types to have a visibility field (and all that include the COMMON_TARGET_FIELDS get it).

I think this would be a potential gotcha for plugin authors, which a note here would be of moot help.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is addressed by #15876 so that we can register the visibility field as a plugin field directly on Target and it will apply to all targets.

return True
if rule == self.PRIVATE_VISIBILITY:
return to_path.startswith(target_path)
if to_path.startswith(rule):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this would need to validate that rule ends in a slash as well?

I'd suggest switching both of these to

def fast_relpath_optional(path: str, start: str) -> str | None:
"""A prefix-based relpath, with no normalization or support for returning `..`.
Returns None if `start` is not a directory-aware prefix of `path`.
"""
, which avoids the need for the trailing slash.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching the entire logic to instead use Specs for determining valid targets.

def rules():
return (
*collect_rules(),
UnionRule(ValidateDependenciesRequest, ValidateVisibilityRulesRequest),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this is already using a pluggable mechanism, is it worth putting it in its own backend, to avoid the overhead of checking visibility if a repo isn't using it at all?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I like that.

@Eric-Arellano
Copy link
Contributor

Awesome! My main open question is what the DSL for users should look like. For example, will there be a need to only allow certain targets to consume another target? Or this should all be filesystem based?

If you're willing, I think it would be helpful to either use something like a Google Doc or GitHub discussion so that we can fully scope out the ideal user experience. What do you think?

@kaos
Copy link
Member Author

kaos commented Jun 15, 2022

Yeah, I considered the possibility to use specs rather than just paths, so you can single out specific targets, or just the targets at one level rather than recursive etc.

Seeing the fruitful use of a design doc for the defaults feature, I can see the benefit to use that here as well.

@kaos
Copy link
Member Author

kaos commented Jun 15, 2022

Start of fleshing out a design doc here: https://docs.google.com/document/d/1DdVZ4DqX7uwiYuCL_ntb17yPxyez1fbiu8K0whZ78Lg/edit#

@cognifloyd
Copy link
Member

Could I use visibility to say "this module should be a leaf" (ie it can be imported by anything but must not import any of the other local modules)?

@cognifloyd
Copy link
Member

Could I use a glob in the path? like visibility = ["contrib/runners/*/tests", "<private>"]

@cognifloyd
Copy link
Member

cognifloyd commented Jun 16, 2022

Could we rename this PR? I think dependees is better than dependencies when describing how this affects targets.

- Add new `visibility` field to targets to limit target dependencies.
+ Add new `visibility` field to targets to limit target dependees.

@kaos kaos changed the title Add new visibility field to targets to limit target dependencies. Add new visibility field to targets to limit target dependees. Jun 16, 2022
Still todo: move into dedicated backend plugin.
@kaos kaos marked this pull request as draft June 19, 2022 19:59
@kaos
Copy link
Member Author

kaos commented Jun 19, 2022

Marking as draft, as there are still quite a few moving pieces before this one is ready.
Notably: #15836 and #15876.

@@ -0,0 +1,85 @@
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2022? 😂

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whopsie 😂

@thejcannon
Copy link
Member

Not necessary for this PR, we can file a feature request ticket later. But another interesting visibility use-case is setting visibility to "test". E.g. "only test utilities or tests can depend on this". It helps me make sure no prod code depends on a test utility or a test

@kaos
Copy link
Member Author

kaos commented Jun 22, 2022

Since the visibility rules now simply are Specs, it would help if we could shoe-horn in this to be a feasible feature for the Specs to support selecting (or excluding) targets by type as well.

Perhaps something along the lines of:

# exclude `python_test` and `python_testutil` targets from the src/python/pants tree..
!src/python/pants|python_test,python_testutil

this would mean that you could run goals on a select subset of target types, like:

# escaping or quoting of the pipe required from the shell..
./pants fmt lint check ::\|python_sources,shell_sources

@kaos kaos marked this pull request as ready for review June 25, 2022 19:13
@kaos
Copy link
Member Author

kaos commented Jul 7, 2022

I swapped out the bespoke visibility check in the explorer backend for this new feature to try it out. Could drop that switch before landing if desired.

…ckend.

# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
@kaos
Copy link
Member Author

kaos commented Jul 7, 2022

Also, I think that we'd maybe want to run some sort of benchmark using this to see if the current approach is feasible from a performance perspective. My time will become rather limited soon to pursue this further for some time (month-ish or more)

@Eric-Arellano
Copy link
Contributor

it would help if we could shoe-horn in this to be a feasible feature for the Specs to support selecting (or excluding) targets by type as well.

That would be --filter-target-type=python_test, which now works from anywhere.

--

Sorry I have not reviewed this! Is this still ready for review?

@kaos
Copy link
Member Author

kaos commented Aug 21, 2022

Sorry I have not reviewed this!

No worries.

Is this still ready for review?

I believe so. Although I'm not setup for dev work on my new machine just yet.

@kaos
Copy link
Member Author

kaos commented Oct 28, 2022

I have a new angle for this feature. I'll also sync some with @benjyw who've expressed an interest in tackling this feature, and update the design doc going forward.

@kaos kaos closed this Oct 28, 2022
@benjyw
Copy link
Contributor

benjyw commented Oct 28, 2022

A GitHub Discussion linking to the design doc would be great!

@kaos
Copy link
Member Author

kaos commented Oct 28, 2022

#17389

@kaos kaos deleted the visibility_13393 branch November 24, 2022 00:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"Visibility" support (akin to Bazel's)
6 participants