Skip to content

[META] Plan for publishing null-safe core packages #41398

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

Closed
kevmoo opened this issue Apr 8, 2020 · 35 comments
Closed

[META] Plan for publishing null-safe core packages #41398

kevmoo opened this issue Apr 8, 2020 · 35 comments
Assignees
Labels
area-meta Cross-cutting, high-level issues (for tracking many other implementation issues, ...). NNBD Issues related to NNBD Release

Comments

@kevmoo
Copy link
Member

kevmoo commented Apr 8, 2020

Tracking issue for the plan to publish null-safe core packages.

WIP with @natebosch and @jakemac53

@kevmoo kevmoo added area-meta Cross-cutting, high-level issues (for tracking many other implementation issues, ...). NNBD Issues related to NNBD Release labels Apr 8, 2020
@jcollins-g
Copy link
Contributor

FYI: Dartdoc needs to know about the planned allow-list of null-safe core packages for the tech preview to make sure they are documented correctly. See dart-lang/dartdoc#2211

@kevmoo
Copy link
Member Author

kevmoo commented May 20, 2020

See go/dart-null-safety-1st-party-package-publish-plan

@mit-mit
Copy link
Member

mit-mit commented Jun 26, 2020

@kevmoo can we close this? I believe we have a plan, right?

@natebosch
Copy link
Member

I don't think we have a settled plan for all packages. We have a plan for packages pinned by flutter. For the rest there is still open questions around whether we'll do breaking version bumps by default. Last we spoke I think @leafpetersen still wanted to push for non-breaking releases and I'm strongly in favor of breaking releases.

@mit-mit
Copy link
Member

mit-mit commented Aug 26, 2020

This comment details how to handle packages migrated to null safety prior to launch. The term 'trial-migrated' is used to refer to a package that has been migrated during this stage. These migrations are 'trial' by definition, as the null safety isn't guaranteed to be API stable until we reach stable (although the actual API churn is expected to slow down as we approach launch).

Problem statement

We need a solution where:

  1. Packages that have been trial-migrated can be published on pub.dev (as the alternative of relying on git-dependencies + overrides is too cumbersome).
  2. Developers who are using the null safety experiment (i.e. dev release with a flag), or a null safety beta release (i.e. without a flag), can opt-in to resolve to a package that has been trial-migrated.
  3. Developers who are not using null safety don't get resolved to trial-migrated packages without their consent, even if they use those same dev or beta channel releases (which contain null safety support).

Proposed solution for package versioning

Publishing prior to null safety beta

Prior to beta, publishing to pub.dev is strongly discouraged. Doing so, even as a pre-release version, can in some cases lead to pub resolving to the null safety version for a consumer that is not yet using null safety. If that happens, they will be broken.

Thus, prior to beta, we recommend that any trial migrated packages are consumed via git dependencies to the package source code, and that this code is in a branch called null_safety.

The only exception to this role is for a small selection of core packages owned by the core Dart team. Backwards compatible versions of these can be published with extreme care, and only after being added to an allow-list that ensures they work when consumed even without the experiment flag.

Publishing after null safety beta

Once null safety is no longer behind an experimental flag, but prior to the stable launch of the feature, publishing to pub.dev can happen. The below listed steps for versioning must be followed to ensure the null safety version only reaches developers who are ready for it.

Versioning

  1. Package version must be with a pre-release version (docs), using nullsafety as the suffix (e.g. 2.0.0-nullsafety.0)

  2. Package version must be a major version increment of the most recent stable version on pub.dev (e.g., if most recent stable version is 2.4.0, publish first null safety version as 3.0.0-nullsafety.0). If your package has not already reached 1.0.0, then the package version should be a minor version increment. So if the most recent stable published version is 0.2.4, your first null safety version would be 0.3.0-nullsafety.0.

  3. Subsequent updates to the null safety version of the package are handled by incrementing the pre-release suffix p in x.y.z-nullsafety.p (e.g., if first null safety version is 3.0.0-nullsafety.0, use 3.0.0-nullsafety.1 for the next null safety version)

  4. Must use a tight SDK constraint that only allows non-stable SDK releases. For example, if the trial migration was done with Dart SDK version 2.11.0-18.0.dev, use:

    • A lower constraint matching the SDK version that was used for the migration, e.g.
      sdk: '>=2.11.0-18.0.dev <2.11.0'

    • An upper constraint that allows subsequent non-stable SDKs, but not the following stable SDK, e.g.
      sdk: '>=2.11.0-18.0.dev <2.11.0'
      This ensures that the pre-release version never get's resolved by a stable SDK release.

Proposed Dart platform support

The above package versioning guidance is supplemented by:

  1. A pub client warning which identifies when a package potentially depends on an experimental feature (i.e. that it has a lower SDK constraint which is a non-stable SDK) yet has an upper SDK constraint that allows a stable release

  2. The existing pub.dev support for pre-releases (e.g. characters version 1.1.0-nullsafety.2), potentially augmented with support for analyzing packages correctly when they don't use stable SDKs (no earlier than null safety beta)

  3. no planned changes to current pub resolution logic (we believe this isn't needed if the guidance above is followed).

@jakemac53
Copy link
Contributor

The more I think about this the less comfortable I am with it. There could be any number of unforeseen circumstances which end up with users picking up a null safety release without intending to.

If we don't want or aren't able to put the time into some solution that actually prevents users from getting these packages at all, then I would prefer to just use git overrides.

@natebosch
Copy link
Member

  1. as the alternative of relying on git-dependencies + overrides is too cumbersome

How are we determining this? We know that it is cumbersome, but I don't know the criteria we are using to determine how cumbersome it can or should be. If it's because we think it will dissuade users from trying it and we'll have too little feedback my gut instinct goes against that and I wonder if we can find out whether that is true (or delay an implementation of something different until we find it is true).

@jonasfj
Copy link
Member

jonasfj commented Aug 26, 2020

How are we determining this?

I suppose that if we suggest people use git-dependencies on a null-safety branch, then there wouldn't necessarily be a need for dependency_overrides? (as all dependencies also have to migrate and use git dependencies).

@mit-mit
Copy link
Member

mit-mit commented Aug 26, 2020

There could be any number of unforeseen circumstances which end up with users picking up a null safety release without intending to

@jakemac53 Can you exemplify this concern? I simply don't see how it could happen without the user opting-in by updating their pubspec.yaml to allow the new major release. And even in that case it will fail fast (they should get analysis errors quickly), and it's easy to revert (just change the pubspec back).

@mit-mit
Copy link
Member

mit-mit commented Aug 26, 2020

How are we determining this? We know that it is cumbersome, but I don't know the criteria we are using to determine how cumbersome it can or should be.

It's a qualified guess. If trial migration is hard, we'll get fewer doing it, and thus less feature validation. This is a significant risk (to both feature quality and timelines), so we need to weigh that risk against the risk of the proposal I summarized.

@jakemac53
Copy link
Contributor

@jakemac53 Can you exemplify this concern? I simply don't see how it could happen without the user opting-in by updating their pubspec.yaml to allow the new major release. And even in that case it will fail fast (they should get analysis errors quickly), and it's easy to revert (just change the pubspec back).

A big part of the concern is the unforseen part. I cannot say with any confidence that no significant number of users will be affected by this. Because these are considered valid packages by pub my assumption is the opposite - that people almost certainly will end up with them one way or the other. Some theoretical examples could include:

  • Some users use any constraints, which could open them up to this.
  • A single package could do something bad like publishing a stable version that requires one of these versions, breaking all their (transitive) users without realizing it.
  • A package expands their constraint to allow a null safe version but doesn't actually get it, and they publish. Then later on that becomes the only valid version of said package for some downstream user and they do get it.

Another part of the concern is, if this becomes a problem, what course of action to we have to remedy it? We are really left with very few options once these packages are published.

Ultimately, the potential for headache here is a lot larger than the win we are getting from it, because it could potentially negatively affect all users, instead of just being a pain to use for those who do choose to.

@mit-mit
Copy link
Member

mit-mit commented Aug 27, 2020

@jakemac53 is your main concern with the kinds of potential failures you describe during the phase of null safety development where the feature is behind an experimental flag? In other words, would you feel comfortable with the guidance I described above once we get to beta and the feature is no longer behind a flag?

@jakemac53
Copy link
Contributor

@mit-mit Yes I would feel perfectly comfortable at that point - the packages at least at the time of their publishing should be perfectly valid, and even if the feature did have a breaking change you do have some recourse which is to publish a new version of your null safe package that fixes any breakage (and it would be one that anybody should be able to get on pub upgrade).

@munificent
Copy link
Member

  • Some users use any constraints, which could open them up to this.

Unlikely. Since the package has a pre-release version, pub will try to prefer any stable release of that package before it considers the null safety one.

I think I'm with @natebosch, though. Using Git dependencies and dependency overrides is completely safe with respect to the package ecosystem. The only concerns are that it may be annoying for the relatively small number of people that are trying out null safety. But I would rather inconvenience them than potentially harm random Dart users who don't care about null safety yet.

How about we put a Gist somewhere like:

dependency_overrides:
  args:
    git:
      url: [email protected]/args.git
      ref: null_safety
  path:
    git:
      url: [email protected]/path.git
      ref: null_safety
  # Every other package we've trial-migrated...

And just tell users, "If you want to try out null safety, copy/paste that into your pubspec and you're good."

Is that enough to make this usable?

@jakemac53
Copy link
Contributor

I think we would want a shared repo somewhere so people could submit their own git branches to it - that is essentially what @leafpetersen suggested in the meeting this week. The downside is that could accumulate a lot of overrides and pull down more packages than people need.

Note that for the really core packages (those required for test, flutter, and flutter_test), you can instead update your normal dependencies to require the published versions, such as test: ^1.16.0-nullsafety.1.

@jonasfj
Copy link
Member

jonasfj commented Sep 1, 2020

@munificent what if instead of using dependency_overrides we say that:

Packages migrated before beta should:

  • Be pushed to a null-safety branch on the original github repository, and,
  • Use <pkg>: {git: {url: <original_repo_for_pkg>, ref: null-safety}} for dependency on <pkg>.

Then use of dependency_overrides shouldn't be necessary, since all of these packages will have to be migrated bottom-up.


If someone starts using another repository than the original repository, or a branch name different than null-safety that will cause conflicts unless everybody does so. But those conflicts could be solved with dependency_overrides.

@natebosch
Copy link
Member

  • Use <pkg>: {git: {url: <original_repo_for_pkg>, ref: null-safety}} for dependency on <pkg>.

I think this can fall down if you also want to mix in some transitive published deps, which we'll want to do for the packages the Dart team has published.

@jonasfj
Copy link
Member

jonasfj commented Sep 1, 2020

I think this can fall down if you also want to mix in some transitive published deps, which we'll want to do for the packages the Dart team has published.

Yes, everybody has to agree to use it from git or from pub.dev, I'm guessing that these packages will be on the enabled_experiments.json list (so maybe those shouldn't have a null-safety branch, or the readme should direct how to depend on them).

@jakemac53
Copy link
Contributor

The regular dependency strategy requires all of your transitive deps to have migrated effectively - at least any that share any deps with a migrated package (even non-runtime deps).

It is possible it might be sufficient, but ultimately I think a lot of people would end up using overrides to work around this anyways.

@mit-mit
Copy link
Member

mit-mit commented Sep 3, 2020

@jonasfj @jakemac53 @natebosch @leafpetersen @munificent I updated the proposed solution after our discussion. Please review, and update thumbs up/down votes.

@munificent
Copy link
Member

Your proposed solution looks good to me.

Here:

2. Package version must be a major version increment of the most recent published stable version on pub.dev (e.g., if most recent stable version is 2.4.0, publish first null safety version as 3.0.0-nullsafety.0)

I would add:

If your package has not already reached 1.0.0, then the package version should be a minor version increment. So if the most recent stable published version is 0.2.4, your first null safety version would be 0.3.0-nullsafety.0.

Also, I'd remove "publish" from that sentence.

@mit-mit
Copy link
Member

mit-mit commented Sep 7, 2020

I would add

Also, I'd remove "publish" from that sentence.

Both done!

@mit-mit
Copy link
Member

mit-mit commented Sep 7, 2020

Closing this issue as resolved.

@lukepighetti
Copy link

lukepighetti commented Jan 31, 2021

I have a unique situation and I was hoping someone could help me unwind my options.

  • Package is fluro
  • Current version is 1.7.8
  • We have been reserving the major version 2.0.0 for a major rewrite to migrate to Navigator 2.0
  • We have ported 1.7.8 to null safety and would like to make this available before we start work on fluro 2.0

As I understand it, we are being asked to burn the 2.0 major release number to release our null safe version of the package. This is a high cost option for us because we have built up an expectation that fluro 2.0 will be using navigator 2.0.

  1. Can we distribute this as a git dependency?
  2. What happens if we distribute this as 1.8.0-nullsafety.0?
  3. Is there any other option? I don't want to force people to migrate to the fluro 2.0 rewrite just to obtain null safety, as that will require them to rewrite their entire routing logic.

@kevmoo
Copy link
Member Author

kevmoo commented Feb 1, 2021 via email

@lukepighetti
Copy link

lukepighetti commented Feb 1, 2021

If that's the only option we will be waiting for our rewrite of fluro to nav 2.0 for nnbd, that may be a few months. I have made the null-safe version of 1.x available as a git dependency until then. Thanks for the quick reply!

@kevmoo
Copy link
Member Author

kevmoo commented Feb 1, 2021 via email

@lukepighetti
Copy link

lukepighetti commented Feb 1, 2021

Fluro 1.0 uses Navigator 1.0
Fluro 2.0 uses Navigator 2.0

If I burn a 2.0 release on Fluro 1.0 NNBD I am anticipating that it will confuse people. We've been tying the future Fluro 2.0 release to a Navigator 2.0 migration for many months now publicly.

The good news is we have precious few dependent packages and none of them appear to be in common use, so a git dependency shouldn't be outlandish.

@lukepighetti
Copy link

Is there a target date for major packages to be null-safe on pub?

@mit-mit
Copy link
Member

mit-mit commented Feb 3, 2021

Hi @lukepighetti we hope to share more information about this next week, stay tuned!

@lukepighetti
Copy link

lukepighetti commented Feb 25, 2021

Trying to get more context on this and this

I was under the impression that we had to do a major release and use the null safety preview tag.

It sounds like now we can do a minor release and use SDK constraints.

Some clarification would be appreciated.

@mit-mit
Copy link
Member

mit-mit commented Feb 25, 2021

As of our post from February 17th (https://medium.com/dartlang/preparing-the-dart-and-flutter-ecosystem-for-null-safety-e550ce72c010), we've declared null safety API stable, and will not be changing semantics. With that the previously guidance that you have to publish pre-release versions (e.g. 1.15.0-nullsafety.1) has been removed, and you can publish a stable version.

Wrt. minor or major version bump, @natebosch @jakemac53 can you comment if minor is an option now (assuming there are no other API breaks, and all deps have been migrated to stable, null safe versions)?

@lukepighetti
Copy link

lukepighetti commented Feb 25, 2021

Looking forward to clarification on minor version bumps.

One more thing, is there any way to tell on pub.dev if a package is null safe? I thought all the tooling was using the preview tag to determine. Of interest was redux which is now null safe on 5.0.0 but I see no indication that it is null safe on pub. https://pub.dev/packages/redux

Edit: I see this now, but it's not visible until you click on the 5.0.0

Screen Shot 2021-02-25 at 3 42 53 PM

@natebosch
Copy link
Member

Major version bumps are the recommendation. There is no mechanical enforcement of this best practice, and AFAIK it won't impact the way your package shows up as "Null Safety" on the pub site.

There are two main reasons we recommend a major version bump.

  1. Sometimes it isn't obvious when you are making a breaking change. For instance after null safety the analyzer might tell you that you don't need some == null branch in a conditional so you might remove it - but that could be breaking for code that opts out of null safety. If you want to go the route of a minor version bump I would recommend double checking that all of your tests pass without code changes and a // @dart=2.9 language version marker. Writing code that is both sensible for null safety and also 100% backwards compatible is not always easy to do.
  2. If a downstream package ignore our other best practice of not migrating until your dependencies are all migrated, and they guessed wrong about any one API migration - they thought you'd make an argument nullable when it isn't, or though you'd make a return non-nullable when it isn't - then they may be statically broken with the migrated version of the package, but their constraints would not express that. A user downstream of even then could get stuck with no recourse other than carefully overriding transitive override versions to find a combination that works.

For a few packages owned by the Dart team we were careful with 1 and validated the code carefully against a large corpus of unmigrated downstream code, and for flutter users specifically number 2 is not a concern for the packages that are pinned by flutter. For our packages that aren't pinned by flutter we are using major version bumps.

@jakemac53
Copy link
Contributor

jakemac53 commented Feb 25, 2021

+1 for major version bumps still, while mostly safe there are enough edge cases that I would avoid doing a minor release. You can potentially break the whole world that depends on you without realizing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-meta Cross-cutting, high-level issues (for tracking many other implementation issues, ...). NNBD Issues related to NNBD Release
Projects
None yet
Development

No branches or pull requests

8 participants