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

fix: don't emit package-lock.json when package.json does not exist #7097

Open
wants to merge 4 commits into
base: latest
Choose a base branch
from

Conversation

xiongmao86
Copy link

npm install in a folder that doesn't have package.json doesn't write package-lock.json file.

References

Fixes #6986

@xiongmao86 xiongmao86 requested a review from a team as a code owner December 23, 2023 07:27
@xiongmao86
Copy link
Author

xiongmao86 commented Dec 23, 2023

Hi, there. It's my first time to contribute to the repo. Thank you very much.

@wraithgar
Copy link
Member

Won't this still omit the package-lock if the package.json is an empty object?

@wraithgar
Copy link
Member

It seems to me the root problem here is that the check for the existence of a package.json is happening too late. Arborist should never be given the task of reifying if npm is ultimately going to throw an exception.

@xiongmao86
Copy link
Author

Thanks very much for the response, @wraithgar, I'll try to figure that out.

@xiongmao86 xiongmao86 force-pushed the fix/no-package-lock branch from 1481863 to 56b9023 Compare January 5, 2024 10:16
@xiongmao86
Copy link
Author

Hi, @wraithgar, would you take another look?

lib/commands/install.js Outdated Show resolved Hide resolved
@wraithgar
Copy link
Member

This would need a test.

@xiongmao86 xiongmao86 force-pushed the fix/no-package-lock branch from 56b9023 to 0acd2a2 Compare January 8, 2024 01:39
@xiongmao86
Copy link
Author

Hi, @wraithgar, I have added tests, would you take a look when you have time?

@wraithgar wraithgar self-assigned this Jan 8, 2024
@xiongmao86
Copy link
Author

I have fixed the smoke-test proxy test.

@wraithgar
Copy link
Member

I took a look and I think the fact that you had to add name to all those fixtures is a signal that this isn't quite right. Unless I'm mistaken @npmcli/package-json will throw an exception by default if you give it a directory with either no package-json file, or one that does not parse correctly. The fact that it is empty shouldn't matter. I suspect that code was left over from when you were using the previous module, which returned an empty object by default.

Another wrinkle here is that I think this check is going to have to happen in Arborist. Consider this situation

npm install abbrev --no-save
mkdir sub
cd sub
npm install

This will generate the same error state, i.e. a package-lock written to the main folder, but this code wouldn't catch it. This is because Arborist does some tree walking to see if any parent directories are in fact the root of the module. The presence of a node_modules folder is one such signal.

What's frustrating is that it appears that wherever is throwing this error is not being properly caught by npm in a way where the error stack is preserved. It appears to be generated without one. After some digging it looks like this is a failure of @npmcli/run-script in the situation where a package-json file is missing.

So. We likely have two bugs here:

First, we have a situation where there is no package.json file, but npm install is called. In that case, Arborist handles things just fine, but when npm goes to try to run the lifecycle scripts it throws an exception. Either run-script needs to more gracefully handle the situation, or npm needs to not call it in this situation.

Second, we have a situation where sometimes Arborist is told to reify a truly empty directory. That is, one with no package lock, package.json, OR node_modules. In that very limited situation it should not be writing the package lock file. We need a much more fine tuned test inside arborist itself to prevent this bug.

Unfortunately when I made this statement

Arborist should never be given the task of reifying if npm is ultimately going to throw an exception.

It was before we knew that there were two bugs. What we should be saying is "Arborist should not write the package-lock on a truly empty set of folders (no package.json, lock, or node_modules)" and "npm should not error when trying to run lifecycle scripts when there is no package.json"

@wraithgar
Copy link
Member

Also as a side task I have made npm/run-script#190 and assigned it to myself. We are obviously not done in the process of moving onto that consolidated module for all package json parsing.

const isJsonEmptyObject = Object.keys(jsonContent).length === 0
&& jsonContent.constructor === Object

const emptyJson = new Error('EEMPTYPKGJSON: package.json is empty object')
Copy link
Contributor

Choose a reason for hiding this comment

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

why not remove this check, let it generate empty lock file if package.json is empty. Only make sure not to generate lock file if package.json file doesn't exists

Copy link
Member

@wraithgar wraithgar Jan 9, 2024

Choose a reason for hiding this comment

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

If you'll read my (admittedly long) comment you'll see that this check in this place is not the right solution to begin with.

@xiongmao86
Copy link
Author

Hi, @wraithgar, I have confusion on your comment, would you mind elaborate for me?

I suspect that code was left over from when you were using the previous module, which returned an empty object by default.

I suspect when you mention previous module you mean the rpj call using read-package-json-fast. What is that code which is left over referring to?

What's frustrating is that it appears that wherever is throwing this error is not being properly caught by npm in a way where the error stack is preserved. It appears to be generated without one. After some digging it looks like this is a failure of @npmcli/run-script in the situation where a package-json file is missing.

I have search error stack on google, but I don't understand what it has to do with the current situation? The rpj throw a 'ENOENT` error, why do we need to generate an error stack here?

@wraithgar
Copy link
Member

"that code" refers to all the code checking if what was returned was an empty object or not. That's immaterial when using @npmcli/package-json, either it returns a parsed package.json file or it throws an exception.

The generating an error stack comment was about how hard it was to debug. Without one we have no way of knowing where that error is being thrown from. I did discover it however, and it is in fact the run-script call.

Comment on lines +147 to +156
const jsonContent = pkgJson.content
const isJsonEmptyObject = Object.keys(jsonContent).length === 0
&& jsonContent.constructor === Object

const emptyJson = new Error('EEMPTYPKGJSON: package.json is empty object')
emptyJson.code = 'EEMPTYPKGJSON'
emptyJson.path = pkgJson.filename
if (isJsonEmptyObject) {
throw emptyJson
}
Copy link
Author

Choose a reason for hiding this comment

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

Hi, @wraithgar, that code do you mean this snippet? But it's written by me, not left over before I wrote the commit? I still don't understand, Can you point to one place of the code for example?

Copy link
Member

@wraithgar wraithgar Jan 16, 2024

Choose a reason for hiding this comment

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

I was trying to infer why the test for an empty object was there and assumed it was due to rpj. The long and the short of it is we don't need that check, either package-json returns or it doesn't, if it returns at all we read a package.json file from somewhere in the tree.

@xiongmao86
Copy link
Author

The generating an error stack comment was about how hard it was to debug. Without one we have no way of knowing where that error is being thrown from. I did discover it however, and it is in fact the run-script call.

Doesn't rpj throw an ENOENT error, isn't that enough, @npmcli/package-json would throw an 'ENOENTifpackage.json` is not presented in project dir. Wouldn't they just be the same?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] npm install writes package-lock.json even after failing to find package.json
3 participants