-
Notifications
You must be signed in to change notification settings - Fork 27
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
feat(yarnv1): read package.json & yarnlock #705
feat(yarnv1): read package.json & yarnlock #705
Conversation
# if installConfig.pnp: | ||
# if self.yarn_cache.path.exists() and self.yarn_cache.path.is_dir(): | ||
# # in this case the cache folder will be populated with downloaded ZIP dependencies | ||
# return any(file.suffix == ".zip" for file in self.yarn_cache.path.iterdir()) |
Check notice
Code scanning / CodeQL
Commented-out code
yarn.cache will be removed; handling yarnrc will be removed to a separate PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few minor suggestions and some questions.
Some fixes and changes mentioned by Alexey are in place; removed YarnRC and yarn.cache |
5d2425d
to
63b7946
Compare
Implemented |
return "package_json" | ||
|
||
@property | ||
def package_manager(self) -> Optional[str]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least for the initial implementation, I don't think we'll need to get/set the packageManager field in package.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
def _check_pnp_installs(project: Project) -> None: | ||
if project.is_pnp_install: | ||
raise PackageRejected( | ||
reason=("Yarn zero install detected, PnP zero installs are unsupported by cachi2"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think "zero-installs" are a term/feature that only really exists in Yarn v2+, so we might want to avoid using it here for Yarn 1.x. Same with the solution text mention of .yarn/cache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gah. Copy-pasta.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
63b7946
to
903bd5b
Compare
We've got 80% coverage of new code. I figure somewhere between 2-5 more unit tests should cover everything, and they'll all be pretty straightforward. |
ea7eeb4
to
9321a9f
Compare
Not ready to merge, as I need to increase coverage, but I'm confident in the implementation. |
b06b279
to
0e585af
Compare
/retest |
def _resolve_yarn_project(project: Project, output_dir: RootedPath) -> list[Component]: # type: ignore | ||
# Temporary type ignore | ||
"""Process a request for a single yarn source directory. | ||
|
||
:param project: the directory to be processed. | ||
:param output_dir: the directory where the prefetched dependencies will be placed. | ||
:raises PackageManagerError: if fetching dependencies fails | ||
""" | ||
log.info(f"Fetching the yarn-classic dependencies at the subpath {project.source_dir}") | ||
|
||
_verify_repository(project) | ||
|
||
# Placeholders for implementations in other PRs | ||
# _set_yarnrc_configuration(project, output_dir) | ||
# packages = resolve_packages(project.source_dir) | ||
# _fetch_dependencies(project.source_dir) | ||
|
||
# return create_components(packages, project, output_dir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is not used anywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
@property | ||
def config_kind(self) -> ConfigKind: | ||
"""Return kind of this ConfigFile.""" | ||
return "yarnlock" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, this property should be dropped and replaced with isinstance(<class-name>)
somewhere else in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use case here is being able to use the pattern what_are_you = foo.config_kind
rather than being forced to use
if isinstance(foo):
what_are_you = i_am_foo
elif isinstance(bar):
what_are_you = i_am_bar
elif isinstance(baz):
what_are_you = i_am_baz
every time.
If we're truly switching a different code block for each and all classes, then yeah, the if-tree is necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the real use case here ? __CommonConfigFile
is the abstract class so you can't instantiate it anyway.
kind = PackageJson.config_kind == "package_json"
this feels awkward to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT: So my point about isinstance
is not valid, ConfigKind
is just Literal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But still don't understand the use case of such property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT 2: I understand, but using the class as type insted of literal is much clearer IMO.
return cls(path, package_json_data) | ||
|
||
|
||
class YarnLock(_CommonConfigFile): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the inheritance here, data
and path
attributes are not used anywhere inside YarnLock
class.
I would say package.json and yarn.lock are quite different from each other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They will be eventually. Also, they are siblings of the yarnrc class which will be implemented later
if not yarn_lockfile: | ||
raise PackageRejected( | ||
reason="The yarn.lock file must not be empty", | ||
solution=("Please verify the content of the file."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(
and )
are not necessary here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactor fallout :rolleyes:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
As I often get these recommendations, you could split the changes into more commits. For example
|
return None | ||
|
||
|
||
def _resolve_yarn_project(project: Project, output_dir: RootedPath) -> list[Component]: # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should just drop this function in this PR and I'll introduce it in mine. That way the unit tests for detecting pnp installs could just test _verify_repository rather than (what will be) the more expansive _resolve_yarn_project
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
), | ||
], | ||
) | ||
def test_pnp_installs_detection( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: It might make this simpler to make the error case a separate test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is applicable to all test cases that have branching in them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
--hash=sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016 \ | ||
--hash=sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504 | ||
# via yarl | ||
pyarn==0.2.0 \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pyarn is pinned to different versions in requirements.txt and requirements-extras.txt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
) | ||
except ValueError as e: | ||
raise PackageRejected( | ||
reason=(f"Can't parse the {path.subpath_from_root} file.\n" f"{e}"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output here could potentially be lengthy, so I think we definitely want the exceptions chained but without repeating the output in the new PackageRejected exception we are raising
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
), | ||
], | ||
) | ||
def test_pnp_installs_detection( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is applicable to all test cases that have branching in them.
0e585af
to
1ffda55
Compare
Fixed |
1ffda55
to
c0892c3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
99% LGTM (with a couple small and trivial fixes).
## What - Ensure that 'package.json' file exists - Read from 'package.json' ## How - introduce ABC `_CommonConfigFile` dataclass to represent config files - implement `PackageJson` CommonConfigFile subclass Signed-off-by: Ben Alkov <[email protected]>
## What - a class representing a yarn project - can create Projects from a source dir - can check for (disallowed) PnP installs ## How - implement `Project` as a frozen dataclass Signed-off-by: Ben Alkov <[email protected]>
## What - Ensure that 'yarn.lock' file exists - Read from 'yarn.lock' ## How - add 'pyarn' to dependencies (to parse 'yarn.lock' file) - implement `YarnLock` CommonConfigFile subclass Signed-off-by: Ben Alkov <[email protected]>
c0892c3
to
8a2e7d3
Compare
58faa67
Closes GH Issue #627
What
Reject packages as unsupported if PnP (Plug n' Play) is being used
i.e. any of
installConfig.pnp: true
in 'package.json'How
_check_pnp_installs()
in 'main.py'N.B. RE: mypy
type: ignore
for the 'pyarn' import, as 'pyarn' is untypedmain.py::_resolve_yarn_project()
has a temporarytype: ignore
for its return type, as it has no return yet (coming later from a different issue)Maintainers will complete the following section
Note: if the contribution is external (not from an organization member), the CI
pipeline will not run automatically. After verifying that the CI is safe to run:
/ok-to-test
(as is the standard for Pipelines as Code)