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

Option to bump existing ranges to reflect latest semver version #581

Open
2 tasks done
medikoo opened this issue Sep 11, 2019 · 35 comments
Open
2 tasks done

Option to bump existing ranges to reflect latest semver version #581

medikoo opened this issue Sep 11, 2019 · 35 comments

Comments

@medikoo
Copy link

medikoo commented Sep 11, 2019

  • node version: v12.10.0
  • npm version: 6.10.3
  • npm-check-updates version: 3.1.22

#573 seems related, and #159 seems about same thing

I'm after an option that will bump existing ranges in package.json, so they point to the latest version (within a reflected range).

Currently ncu does that well, only if we use ^ and rely on latest major of given dependency.

However if there's a package where we rely on non-latest major, it automatically updates to latest major (which I find unwanted, as any major version upgrade should rather be done manually ensuring breaking changes are handled).

Explaining on example

There's a package where:

  • Latest version is 3.2.5
  • Latest v2 version is 2.8.5
  • Latest v2.4 version is 2.4.8
Case 1

Range in is package.json is ^2.4.5.

I'd love ncu to upgrade the range to ^2.8.5 (and not ^3.2.5 as it does now).

Case 2

Range in is package.json is ~2.4.5.

I'd love ncu to upgrade the range to ~2.4.8 (and not ^3.2.5 as it does now).


In #159 it was suggested that npm update does that. That's not true

npm update updates package.json only if:

  1. Given package is installed in node_modules
  2. Package is installed at version lower than latest as supported by range.

So in above scenario if in node_modules package is already installed at 2.8.5 (or is not installed at all), there's no way to forcenpm update to update the range in package.json.

@raineorshine
Copy link
Owner

raineorshine commented Sep 12, 2019

Thank you for the detailed explanation! And thank you for looking through existing issues.

I marked this as an enhancement and am open to PR's or +1's to signal interest if others are wanting this option.

As a side note, I'm somewhat unclear what benefit there is to having the number changed in the package.json when the version range gives you the control you are looking for. This likely does not change the status of this ticket, but I thought I would mention that this came up for me.

@medikoo
Copy link
Author

medikoo commented Sep 12, 2019

what benefit there is to having the number changed in the package.json when the version range gives you the control you are looking for.

Bumping the ranges ensures that when user updates our package, its dependencies will be upgraded to latest versions (otherwise if ranges are not updated, npm won't do deep update).

Repeatedly I deal with a situation when some dependency of my project introduces accidentally a bug, and then quickly follows with a fix (note that buggy version cannot be removed from npm), then it's always recommended to bump the range so it gives no chance for buggy version to be installed.

@raineorshine
Copy link
Owner

(otherwise if ranges are not updated npm won't do deep update)

Does this help?

As of [email protected], the npm update will only inspect top-level packages. Prior versions of npm would also recursively inspect all dependencies. To get the old behavior, use npm --depth 9999 update.

https://docs.npmjs.com/cli/update.html

@medikoo
Copy link
Author

medikoo commented Sep 13, 2019

Does this help?

Not really, as it's not about how packages are being installed for maintainer of a package, but for projects that rely on it.

It's impossible to enforce users of my package (and packages that depend on it), to runnpm update --depth 9999 instead of npm install (or npm update)

Also just for maintainers npm update is not very useful.. as it requires two separate runs for prod and dev dependencies (there's no way to update both with one command run)

@raineorshine
Copy link
Owner

Good point! I will keep this open for the feature as requested.

@mesqueeb
Copy link

mesqueeb commented Jul 19, 2020

Big +1 on my part!
It's actually what I was hoping to achieve with ncu --semverLevel major -u but have ncu ignore any hard-coded versions.

This is my goal and I believe it should be a flag called --packageRanges or something very clear.

I have a use case:

  • Some package introduced changed behaviour on a major update (eg. v1.2.0 introduced breaking changes on v1.3.0).
    • So we want to hard code the version to a specific version. Eg. set to "1.2.0" in package.json
    • this should make it so ncu does not touch this ever.
  • All other package we want to keep the latest versions in package.json explicitly (because of the reason above)
    • So that means, have ncu auto-update "^0.8.0" to "^0.9.0" in our package.json

TLDR;

So in conclusion I think a command ncu --packageRanges would be awesome!!

@raineorshine
Copy link
Owner

Sounds reasonable! Just need someone willing to work on this. I'm working on other things at the moment.

@mesqueeb
Copy link

@raineorshine i can cry and make a PR for you!! 🙃 Can I request a little guidance on where you suggest me adding new code ?

@raineorshine
Copy link
Owner

I have a few questions for clarification.

It's actually what I was hoping to achieve with ncu --semverLevel major -u but have ncu ignore any hard-coded versions.

So you're looking for a flag that:

  1. Only affects version ranges, not exact versions
  2. Upgrades to the maxSatisfying version (i.e. respects semver)

@medikoo Is this the same as what you are looking for? Is --semverLevel major also inadequate for your use case?

I have a use case:

  • Some package introduced changed behaviour on a major update (eg. v1.2.0 introduced breaking changes on v1.3.0).

I'm a little confused by this: v1.2.0v1.3.0 is a minor version update, not a major version update. Are you saying the package author accidentally published breaking changes on a minor version?

  • So we want to hard code the version to a specific version. Eg. set to "1.2.0" in package.json
  • this should make it so ncu does not touch this ever.

This can be accomplished with an .ncurc file set to not touch that dependency:

{
  "reject": ["mypackage"]
}
  • All other package we want to keep the latest versions in package.json explicitly (because of the reason above)

    • So that means, have ncu auto-update "^0.8.0" to "^0.9.0" in our package.json

Upgrading "^0.8.0" to "^0.9.0" is the current behavior, right?

@mesqueeb
Copy link

Sorry, I was confused and thought the name of the "middle" number was "major".

The current behaviour of NCU:

  • ncu --semverLevel major -u

This updates everything to latest "minor" (the middle one) version and it's currently my most used command.

This means, with these flags in package.json, the behaviour of this command is:

  • "~1.2.3" is upgraded to "~1.3.0"
  • "^1.2.3" is upgraded to "^1.3.0"
  • "1.2.3" is upgraded to "1.3.0"

This is the reason I was a bit confused on the naming, since we need to write major but it only upgrades minor versions, or is this a bug?

Upgrading "^0.8.0" to "^0.9.0" is the current behavior, right?

I'm not 100% sure what you mean by this. But, I believe ncu -u upgrades everything even to major versions, completely ignoring package ranges.

The behaviour I want with a new command:

ncu --packageRanges -u

I want it to upgrade everything as indicated in package.json. (also see npm ranges docs).

This means, with these flags in package.json, the behaviour of this command is:

  • "~1.2.3" should be upgraded to latest patch version like: "~1.2.4"
  • "^1.2.3" should be upgraded to latest minor version like: "^1.3.3"
  • "1.2.3" should never be touched

I think saving an extra special file just for when hard coding a package version is too confusing when working with teams. If authors can just have a single script like so:

  • "update-all-dependancies": "ncu --packageRanges -u && npm i"

This way the source of all truth is just the package version range, and no extra files are needed that add clutter and can lead to discrepancies more easily.

I feel that ncu --packageRanges -u is so beautiful.
It's the command of commands. The command that will end all other commands.

NCU would basically offer:

  • ncu for checking new major versions and then go in an manually upgrade them on a case-by-case basis after checking breaking changes
  • ncu --packageRanges -u as the main command to upgrade everything in package.json. This can be done routinely every week.
  • once a version needs to be fixed, just do so in package.json and forget about the rest. ;)

NCU is so nice, especially in monorepos.

@medikoo
Copy link
Author

medikoo commented Jul 21, 2020

"~1.2.3" should be upgraded to latest patch version like: "~1.2.4"
"^1.2.3" should be upgraded to latest minor version like: "^1.3.3"
"1.2.3" should never be touched

@raineorshine ☝️ this is exactly the behavior I had in mind with this proposal.

@raineorshine
Copy link
Owner

This is the reason I was a bit confused on the naming, since we need to write major but it only upgrades minor versions, or is this a bug?

It was intended to convey that it locks upgrades to the current "major" version. I can see how it could be interpreted the other way though.

But, I believe ncu -u upgrades everything even to major versions, completely ignoring package ranges.

Yes, aside from semverLevel, that's correct.

I want it to upgrade everything as indicated in package.json. (also see npm ranges docs).

This means, with these flags in package.json, the behaviour of this command is:

  • "~1.2.3" should be upgraded to latest patch version like: "~1.2.4"
  • "^1.2.3" should be upgraded to latest minor version like: "^1.3.3"
  • "1.2.3" should never be touched

I think saving an extra special file just for when hard coding a package version is too confusing when working with teams. If authors can just have a single script like so:

  • "update-all-dependancies": "ncu --packageRanges -u && npm i"

This way the source of all truth is just the package version range, and no extra files are needed that add clutter and can lead to discrepancies more easily.

This makes total sense. It's an interesting use case, as it wasn't the original intent of the library, but it is entirely coherent.

I feel that ncu --packageRanges -u is so beautiful.
It's the command of commands. The command that will end all other commands.

Ha. I am enjoying your hyperbolism.

I think --packageRanges can be combined with --semverLevel since they are mutually exclusive and do the same type of thing: setting the allowable range of upgrades. In fact, this also includes --greatest and --newest. Let's do --semverLevel semver for now and we can combine them all in a separate PR. I hope the name change does not curb your zeal in the slightest.

@raineorshine
Copy link
Owner

Can I request a little guidance on where you suggest me adding new code ?

Sure!

semverLevel gets converted to versionTarget in queryVersions. Start by adding semver as a valid versionTarget.

Then export a semver function from npm.js. This is where the different filtering logic will go. I would recommend copying greatestMajor and adapting it to use semver.maxSatisfying.

Unit tests can be added with the other --semverLevel tests.

@mesqueeb
Copy link

mesqueeb commented Jul 22, 2020

@raineorshine I'll try to see if I can get a PR working.
I'm fine with keeping the --semverLevel flag, but

  • instead of the full param being:
    • --semverLevel semver
  • I would much much much more prefer this:
    • --semverLevel packageRanges

Just for clarity's sake.
Because the message I read in my head when comparing these two:

  • --semverLevel semver
    • "update packages according to the semver level as per the semver." (which really doesn't make much sense)
  • --semverLevel packageRanges
    • "update packages according to the semver level as per the package ranges." (which is clear and makes sense)

I hope it's not just in my head, but I think we'll avoid a loot of confusion with the latter as opposed to the former.

I hope you can agree with my opinion, let me know if I can get the green light on that naming scheme!

@raineorshine
Copy link
Owner

You have a point. --semverLevel semver is redundant and confusing. I still find that packageRanges to be less than clear. The option is there to constrain upgrades to latest, greatest, newest, or semver (the new option). All of them reference the package ranges, but each of them constrains the upgrades in a different way.

I would suggest one of the following two options:

  • --semverLevel maxsatisfying - Explicitly references the node-semver comparison
  • --target semver - Use a more generic option name, similar to versionTarget that is already used internally
  • --to semver - Another generic name that reads well literally.

Open to feedback.

@mesqueeb
Copy link

mesqueeb commented Jul 23, 2020

@raineorshine
Thanks for your insights!
Personally I find --semverLevel maxsatisfying to be clearest in this case. : )

However, I re-read your previous comment and you mention:

In fact, this also includes --greatest and --newest. Let's do --semverLevel semver for now and we can combine them all in a separate PR.

and I think I kind of overlooked this: you want to also come up with alternatives for those --greatest and --newest flags, correct? In this case I will just go ahead with a PR, call it --semverLevel maxsatisfying for now, and you can revisit the naming scheme for everything at a later date.

@medikoo do you have any opinion on naming?

@raineorshine
Copy link
Owner

and I think I kind of overlooked this: you want to also come up with alternatives for those --greatest and --newest flags, correct?

Yes, I believe they should go under the same flag.

In this case I will just go ahead with a PR, call it --semverLevel maxsatisfying for now, and you can revisit the naming scheme for everything at a later date.

Yes! Agree

@raineorshine
Copy link
Owner

@mesqueeb Any update? Thanks!

FYI I am currently planning for the next major release consolidating --semverLevel, --greatest, and --newest into a single flag --target with possible values: latest, greatest, newest, patch, minor, major, semver.

@kachkaev
Copy link

kachkaev commented Sep 3, 2020

Sounds exciting @raineorshine! I just tried v8.0.5 and could not find --target semver. What’s the option to upgrade to the latest available version within the given semver range? (e.g. ^1.2.3^1.99.0, ~1.2.3~1.2.99).

@raineorshine
Copy link
Owner

@kachkaev It hasn't been implemented yet. @mesqueeb had originally volunteered, but it's currently open for submissions.

@mesqueeb
Copy link

mesqueeb commented Sep 6, 2020

I'll try to get to it eventually, but am a bit swamped in a couple of pending releases for some projects. 😰

if it's not yet implemented in a few weeks I'll probably eventually try my hand at it. seems like a fun journey!

@raineorshine
Copy link
Owner

raineorshine commented Feb 13, 2021

Closing with the revive-me tag for interested contributors. See #484.

@medikoo
Copy link
Author

medikoo commented Feb 15, 2021

@raineorshine more common approach is to keep them open with good first issue or help wanted label.

First label has also special handling on GitHub website, as GitHub naturally provides a link to those issues at top of the list.

@raineorshine
Copy link
Owner

raineorshine commented Feb 15, 2021

Thank you for the tip. I think that is a good suggestion, although I have some concerns of using those labels. I'm hesitant to label all suggested enhancements as help wanted when many of them are obscure use cases that are not in high demand. I've had bad experience with good first issue where it invites people that are unqualified and end up wasting my time, despite good intentions. I have yet to have a skilled developer respond to a good first issue label, but that's just my experience.

@medikoo
Copy link
Author

medikoo commented Feb 15, 2021

@raineorshine I agree with all your points. I personally would add good first issue only on issues which are relatively easy to address (and eventually issue provides a clear instructions on how to do that), and help wanted to those that we welcome PR for.

If some enhancement is not welcome I believe either should be closed with something as wontfix, or left open with something as needs feedback, where we welcome additional input that may convince us otherwise (then eventually after some period of time, closing seems justified)

To me closing an issue, means that case is closed and not intended to be revisited.

@raineorshine
Copy link
Owner

If some enhancement is not welcome I believe either should be closed with something as wontfix, or left open with something as needs feedback, where we welcome additional input that may convince us otherwise (then eventually after some period of time, closing seems justified)

That's fair. I think it mostly depends on someone coming along with enough motivation. For ideas that genuinely don't have a place in npm-check-updates, they are marked as out-of-scope (which I find a bit nicer than wontfix 😊).

To me closing an issue, means that case is closed and not intended to be revisited.

I'll make sure to mark such issues with revive-me and clearly document that they may be re-opened if there is sufficient interest. I don't need the issues page cluttered up with random suggestions 95% of which are never acted on. At least that's my personal preference on a small project like this.

@raineorshine raineorshine changed the title Option to bump existing ranges to reflect latest supported version Option to bump existing ranges to reflect latest semver version Feb 25, 2021
@raineorshine raineorshine reopened this Jan 21, 2022
@raineorshine
Copy link
Owner

Re-opening due to ongoing interest. Open to PR's for --target semver.

@raineorshine
Copy link
Owner

As of v12.5.0, you can specify a custom target function in your .ncurc.js file, or when importing npm-check-updates as a module:

/** Custom target.
  @param dependencyName The name of the dependency.
  @param parsedVersion A parsed Semver object from semver-utils.
    (See https://git.coolaj86.com/coolaj86/semver-utils.js#semverutils-parse-semverstring)
  @returns One of the valid target values (specified in the table above).
*/
target: (dependencyName, [{ semver, version, operator, major, minor, patch, release, build }]) => {
  if (major === 0) return 'minor'
  return 'latest'
}

You can hack together your own semver-like target logic, but the intention is to eventually add a --semver option that handles this for you.

@pgrzesik
Copy link

Hello, is that still the problem? I believe ncu --target minor works well and addresses the mentioned issue

@raineorshine
Copy link
Owner

@pgrzesik They're a bit different. --target minor does not handle tilde ranges or caret ranges.

The solution will add a new --target semver that uses semver.maxSatisfying to upgrade to the highest version that satisfies the version range specified in your package.json.

@vsDizzy
Copy link

vsDizzy commented Feb 20, 2023

IMHO this behavior should be the default, without providing extra arguments.

@Maxim-Mazurok
Copy link
Contributor

My use-case:

I want to upgrade most packages to latest major. However there are some packages that I can't upgrade to latest major without big refactoring.

At first I thought I can solve it by using * for most packages and ^x for those I want to pin, and then getting rid of NCU completely, npm update would do what I need.

However a pretty big issue with this is that now I don't have a clear visibility on what packages are updated. And when my build fails I can't do the "doctor" command to figure out which update broke the build.

So yeah, for these reasons +1 from me for this feature, and for now as a workaround I'll be reverting ranges after NCU by hand.

@raineorshine
Copy link
Owner

raineorshine commented Aug 5, 2023

@Maxim-Mazurok To pin a dependency version, you can add it to the reject list in a .ncurc file. npm-check-updates will ignore everything on the reject list, and it's in version control so it's fully auditable.

Obviously this is an aside from the target --semver feature, which would be a great addition.

@Maxim-Mazurok
Copy link
Contributor

Maxim-Mazurok commented Aug 5, 2023

@raineorshine I understand that, however I do want to receive minor and patch updates. What I came up with at the end is to have npm script that first runs ncu --upgrade and then npm install my-dep@5 otherdep@7 etc.

@raineorshine
Copy link
Owner

raineorshine commented Aug 5, 2023

@Maxim-Mazurok Ah, I see. I'm glad you found a workaround.

You can also use a custom target function to specify per-dependency version targets. Run ncu --help target for details.

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

No branches or pull requests

7 participants