-
Notifications
You must be signed in to change notification settings - Fork 238
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
[RRFC] npm outdated (npm >= 7.24.2) exit with incorrect status code #473
Comments
There are many examples of standard unix tooling (grep for example) that use exit codes to indicate results other than system errors. This is critical to supporting composition in shells. This is why throwing on status codes is incorrect behavior and should be avoided, imo. (This is apparently a contentious opinion, given how many libraries do this, but no, please stop.) I should also note that this is consistent with the behavior npm 6 and all previous versions. |
Yes, grep and cmp for example don't use the conventional exit status codes. But exit status code indicates if a execution was ok (code 0), or if it was any error with the execution (codes 1-255). It wasn't designed to indicate anything more than that. So these programs are faking an error. Unfortunately as npm outdated. The next code example is the empirical proof of what I'm saying.
It throws an error, only because there are outdated packages. That's the fact. It throws an error! Exit status code is a convention because all aplications in a system can work on the same way. If you broke that convention, you must handle exceptions for every application that do this. And as I showed before, there are other ways to retrieve if there are results or not, not really difficult to program, and without breaking any convention. |
And I want to remember that the npm that came by default with node v16.x worked fine (in my opinion) until the last release v16.11. |
So, it seems that instead of using
Now, we can use
To handle the exceptions on the calls to npm outdated. As can be seen, more simple and smart... (ironic) |
Perhaps another option could be a conventional exit status codes, and own exit status codes with a --ownCodes parameter. |
A clear, smart program:
That fails, evidently.
2nd attempt, with a particular exception handled
More clear, as seen (ironic), but hey, it works!!!
Never forget plan B, whatever Schwarzenegger say ;) |
I have to admit that I am very disappointed with the way the npm RFC issue works. I believed that the discussion would be dealt from a technical skill rather than ego. |
You... you know that I'm just a member of the public, right? You say "the npm RFC issue" but you're just disagreeing with another node user. (I was affiliated with the project previously but that was like 3 years ago now.) I have exactly as much weight here as you do. I don't have a strong opinion for outdated in particular, because being notified in a shell scriptable way that some modules are outdated isn't obviously useful to me? But the user base size being the size that it is, you can be pretty sure any change will break someone. (As evidenced by your experience.) So caution is always warrented. That said, I do have the opinion that unintentional breaking changes should be reverted, which is what happened to break you. As a node user I'd want a stronger justification to break from 10 years of behavior than an appeal to standards. |
Well, It was not really with you. You have just an opinion, like me. My reply was for the three guys that said ok to your post. I expected some thoughts, not only an ok. Sorry for the misunderstood. I saw that npm outdated were not working well. So I thinked this should be fixed up. There are simple solutions to follow the exit status code convention and without breaking nothing. For example, following the exit status code convention, and if you want to broke things, just add a --ownExitCodes parameter, and then npm outdated can return whenever you want and do another type of things, to be able to parse it in this way. But broken a default expected behaviour with the rest of the programs in a system (as seen, executing the catch block without really having any error) is not the way to go. I just have used Node 16.x (with default npm), and it was working fine until 16.11. So, for me, npm 7.27.2 it's a breaking behaviour. But anyway, I think (my opinion is) that 10 years of bad behaviour can be fixed up, satisfaying conventions of the whole system. But wait, this was fixed on npm v7, so it was possible to change behaviour with a major release. The weird is that v7 worked in a way (ok for me) and suddenly it changed on 7.27.2. That is very rare, to broke the behavior in the end of 7.x. |
Ah, gotcha, yeah, there was a discussion about this at the RFC meeting (the one that happens every Wednesday and that anyone can join!), and I imagine they thumbs upped in part as a result of that. We did discuss it for quite a while. The change in 7.27.2 was, I'm sure, to their minds, fixing a bug, a regression introduced with the launch of 7.x. But I'm hopeful that if they'd realized it was going to break anyone that they'd have held off till 8. It can be hard to tell sometimes. Honestly, I've only used npm 7 on personal projects because it breaks all my work repos, so I feel ya. (The other major topic at the RFC meeting was reversing a decision to call the behavior that broke my work environment "working as intended".) |
I didn't know that I could attend the meeting. Anyway, I don't think anything would have changed. Things have to be discussed before the meetings. The change in 7.27.2 was to return to a bad behaviour, so it should be avoided. v7 was a new big version, so it was a great moment to do that. As I have show in the code above, I can use my execAsync to escape from that bad behaviour. I think that you could done something similar in your code (I try it and post in this rfc, and it isn't difficult to catch if a command return results or not). |
Let's review: Exit status exit code convention, example that throws an error when there are not error, a v7 (big version, so it could change behaviour) and it was doing it, a revert to working bad at a 7.27.2 version, not a particular interest for me otherwise a npm that fulfill with standards (so it could be integrated with other programs)... The truth is, the more we talk, the more I see that I am right. |
As was discussed in the RFC Meeting on 2021-10-13 (https://github.com/npm/rfcs/blob/main/meetings/2021-10-13.md#issue-473-rrfc-npm-outdated-npm--7242-exit-with-incorrect-status-code---nassau-t) this is working as intended. I plan to document this as part of the doc we discussed in the |
I agree this is really odd behavior... Use-case:
This logic breaks at @nassau-t solution is a good workaround to make it work! EDIT: removed global flags |
It doesn’t make sense to run outdated globally; there’s no package.json to check. |
I have removed the global flags from the example code, the use-case still stands |
@nassau-t thankyou for the suggested workaround - this behaviour was driving us absolutely nuts. After reading through this thread I can see the logic from both sides but I completely agree that sending a failure code when the command has executed successfully is very confusing. It would be great if this could be made configurable somehow. |
I'm trying to save some common commands of my development flow to a Makefile and just ran into the same behavior of "npm outdated" with exit code 1, which breaks my task in the Makefile.
|
My scripts also broke and finally I found out why Back in programming classes, I was taught that return exit code != 0 means execution error (which "proves" nothing, of course). Successfully reporting outdated packages does not seem like an execution error to me. I like the suggested opt-in approach of a parameter (e.g. PS: |
@AndreCunha1 that's never been the case; for example, |
Of course you are entitled to your opinion on what is better, but what you were taught is objectively incorrect because of the existence proof of these other tools. The mental model of exit codes is "what programs DO" and not "what people think programs SHOULD do", and it's important for npm to fit the prevailing mental model. |
I opened this issue, and I think I sufficiently motivated it, citing bibliography. So, it's not only my opinion. Still I think @AndreCunha1 is right. |
So anything can be proven incorrect by writing a tool that does otherwise? Note that I am not implying that what I was taught is correct either, hence my previous "proves nothing" there. Anyway, I am happy to find the cause of my broken scripts and have already adjusted them. Another successful outcome of this discussion could be to simply update the |
I might be missing the obvious here - but is a (what seems to me perfectly reasonable middle-ground) straightforward option not to continue returning 1 if outdated packages are found, but to ensure any error scenario is >1? Certainly, for us, we want (and arguably need) to validate if a problem occurred. I don't mind if the exit code is either 1 or 0 for success, provided non-successes are distinguishable. |
run |
After trying a lot of things, I came to the same conclusion as many peoples in this thread: use a custom I guess there could be an alternative with some arguments to the 😎 |
And I can't fathom switching to the promisified-exec variant, because the code I'm in is sync code, and adding async to it would need me to recolor all the functions I'd be calling it from. My suggestion would be to add an |
Motivation ("The Why")
npm v8.0.0 (included in node v16.11.0) has an exit status code of 1 when there are outdated packages.
By convention, exit status code must be 0 if there is no execution error.
And can be in the range 1-255 if there is an execution error (network, disk, internal error...)
But it has been replaced with a particular behaviour that has no sense with the above convention. Actual behaviour is:
exit status code 0 -> there aren't outdated packages
exit status code 1 -> there are outdated packages.
So this behaviour creates a problem if npm outdated is executed from a any program, because the program throws an error exception.
Example
From a node.js program, I get the error of the catch block, when from cmd npm outdated show no error, only the list of outdated packages.
How
Current Behaviour
So it seems that npm outdated has a status exit code of 0 if there aren't outdated packages.
And a status exit code of 1 if there are outdated packages.
Desired Behaviour
1.1. If stdout return an empty string, there aren't outdated packages.
1.2. If stdout have a non empty string. there are outdated packages.
Examples of 1.1. and 1.2., you know that npm outdated has ended ok, and there is very simple to know if there are outdated packages or not.
Example of 1.1.: Execute ok, there are no outdated packages.
Example of 1.2.: Execute ok, there are outdated packages.
References
Java 7 docs
https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exit(int)
public void exit(int status)
The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.
Python 3 docs
https://docs.python.org/3/library/sys.html#sys.exit
zero is considered “successful termination” and any nonzero value is considered “abnormal termination” by shells and the like. Most systems require it to be in the range 0–127, and produce undefined results otherwise. Some systems have a convention for assigning specific meanings to specific exit codes, but these are generally underdeveloped; Unix programs generally use 2 for command line syntax errors and 1 for all other kind of errors.
The Linux Documentation Project
https://tldp.org/LDP/abs/html/exitcodes.html
Exit Code Number 1
Meaning Catchall for general errors
Unix and linux system administration handbook 5. Evi Nemeth, Garth Snyder, Trent R.Hein, Ben Whaley, Dan Mackin.
init (or systemd) also plays another important role in process management. When a process
completes, it calls a routine named _exit to notify the kernel that it is ready to die. It supplies an
exit code (an integer) that tells why it’s exiting. By convention, zero indicates a normal or
“successful” termination.
Modern Operating Systems 4th Edition. Andrew S. Tanenbaum.
It has one parameter, the exit status (0 to 255), which is returned to the parent in the variable status of the waitpid system call. The low-order byte of status contains the termination status, with 0 being normal termination and the other values being various error conditions.
The text was updated successfully, but these errors were encountered: