pub icon indicating copy to clipboard operation
pub copied to clipboard

Introduce a `pub upgrade --(no)-allow-prereleases` flag.

Open sigurdm opened this issue 5 years ago • 7 comments

It is somewhat surprising that the solver will use pre-releases for dependencies. See eg. https://github.com/dart-lang/pub/issues/2446

Ideally this would be off by default - but that might be a breaking change.

If solving without prereleases fails we should probably report that a solution exists with prereleases and mention the flag.

sigurdm avatar Apr 30 '20 08:04 sigurdm

One question we have not answered: Probably want to allow explicitly chosen pre-releases from the root pubspec.

dependencies:
  foo: 1.0.0-dev # just get me that prerelease!

But it is not clear how to generalize this. (Should we allow that also transitively - what does ^1.0.0-dev mean...)

sigurdm avatar Apr 30 '20 13:04 sigurdm

The use case I feel the most strongly about is the one where a pubspec.yaml lists a package and a stable version (single or range), and the solver ends up resolving that to a pre-release. Consider this example:

  • package foo is published in one version:
    • foo 1.0.0 which depends on bar: ^1.0.0
  • package bar is published in one version:
    • bar 1.0.0 with no dependencies

The developer starts with this pubspec.yaml:

   foo: ^1.0.0
   bar: ^1.0.0

Running pub get, the developers gets locked on foo 1.0.0 and bar 1.0.0 as expected.

Updates are now published on pub.dev:

  • package foo is published in two versions:
    • foo 1.0.0 which depends on bar: ^1.0.0
    • foo 2.0.0 which depends on bar: ^1.1.0-dev
  • package bar is published in two versions:
    • bar 1.0.0 with no dependencies
    • bar 1.1.0-dev-1.0 with no dependencies

The developer now hears about foo 2.0.0 and it has something they need, so they update their pubspec.yaml to:

   foo: ^2.0.0
   bar: ^1.0.0

The developer runs pub get with an intention of picking up foo 2.0.0. They are not aware that foo itself depends on a pre-release bar, and they generally have a policy to only use stable versions. So when they later debug a bug in their app, and realize it's coming from bar and that they had been locked on foo 2.0.0 and bar 1.1.0-dev-1.0 they get angry.

I suggest that a pub get/upgrade without an --allow-pre-release flag should have failed and reported something like:

Could not resolve, foo 2.0.0 requires bar >=1.1.0-dev and your pubspec allows only stable versions of bar >=1.0.0 <2.0.0. Update your dependency on bar to allow a pre-release, or opt-in to selecting pre-release by passing the flag --allow-pre-releases.

They can then either use the flag, or change pubspec.yaml to:

   foo: ^2.0.0
   bar: ^1.1.0-dev-1.0

mit-mit avatar Apr 30 '20 13:04 mit-mit

Probably want to allow explicitly chosen pre-releases from the root pubspec.

I agree that this is probably the most desirable behavior, with a small tweak which is that we allow explicit pre-release dependencies in pre-release packages always. This way an explicit pre-release dependency in the root package is allowed to itself have pre-release deps without any warnings.

Reasoning

  • Transitive prerelease dependencies are surprising and should always be flagged whether they are explicit or not.
    • Unless they are the result of an explicit root package pre-release dep, then it isn't surprising.
  • Ultimately we don't want people to release stable versions of a package if they have any immediate prerelease dependencies anyways, so this just encourages that.
  • Assuming everybody follows this policy there can be no explicit prerelease dep (even transitively) without a prerelease dep in the root pubspec.

jakemac53 avatar Apr 30 '20 14:04 jakemac53

Ultimately we don't want people to release stable versions of a package if they have any immediate prerelease dependencies anyways, so this just encourages that.

@sigurdm recently did a warning to discourage this too.

Assuming everybody follows this policy there can be no explicit prerelease dep (even transitively) without a prerelease dep in the root pubspec.

We could enforce this, but I'm not sure we need to be this strict.


If solving without prereleases fails we should probably report that a solution exists with prereleases and mention the flag.

That, or we could print a warning if we use pre-releases in the solution.

So 1st try to solve without pre-releases (except those allowed by root pubspec.yaml, or transitively from there), then try to solve with pre-releases if that doesn't work. And print a warning if we had to do a second resolution.

jonasfj avatar May 01 '20 08:05 jonasfj

If we go with the solution suggested by @jakemac53 two more questions came up while @jonasfj and i discussed this a bit:

  • If

    • the root package depends on foo: 1.0.0 and bar: 1.0.0-dev and
    • foo 1.0.0 depends on baz: ^1.0.0
    • bar 1.0.0-dev depends on baz: ^1.1.0-dev
    • baz exists in 1.0.0 and 1.1.0-dev Should this resolve?
  • Another interesting case:

    • A stable package foo: 1.0.0 depends on bar: 1.0.0-dev.
    • The root package depends on foo. Should this resolve?

sigurdm avatar May 07 '20 14:05 sigurdm

My suggestion: Without the -allow-pre-release flag, we simple disallow / filter away all pre-release versions. We could allow-list any packages in the pubspec.yaml listed with pre-release versions. That seems like a simple to understand solution?

mit-mit avatar Aug 20 '20 11:08 mit-mit

Are we still interested in this?

sigurdm avatar Jan 16 '25 09:01 sigurdm