Tracking issue for the plan to publish null-safe core packages.
WIP with @natebosch and @jakemac53
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
See go/dart-null-safety-1st-party-package-publish-plan
@kevmoo can we close this? I believe we have a plan, right?
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.
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).
We need a solution where:
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.
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.
Package version must be with a pre-release version (docs), using nullsafety as the suffix (e.g. 2.0.0-nullsafety.0)
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.
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)
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.
The above package versioning guidance is supplemented by:
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
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)
no planned changes to current pub resolution logic (we believe this isn't needed if the guidance above is followed).
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.
- 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).
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).
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).
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 Can you exemplify this concern? I simply don't see how it could happen without the user opting-in by updating their
pubspec.yamlto 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:
any constraints, which could open them up to this.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.
@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?
@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).
- Some users use
anyconstraints, 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?
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.
@munificent what if instead of using dependency_overrides we say that:
Packages migrated before beta should:
null-safety branch on the original github repository, and,<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.
- 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.
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).
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.
@jonasfj @jakemac53 @natebosch @leafpetersen @munificent I updated the proposed solution after our discussion. Please review, and update thumbs up/down votes.
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 as3.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.
I would add
Also, I'd remove "publish" from that sentence.
Both done!
Closing this issue as resolved.
Most helpful comment
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:
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
Package version must be with a pre-release version (docs), using
nullsafetyas the suffix (e.g.2.0.0-nullsafety.0)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 as3.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 be0.3.0-nullsafety.0.Subsequent updates to the null safety version of the package are handled by incrementing the pre-release suffix
pinx.y.z-nullsafety.p(e.g., if first null safety version is3.0.0-nullsafety.0, use3.0.0-nullsafety.1for the next null safety version)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:
A
pubclient 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 releaseThe existing pub.dev support for pre-releases (e.g.
charactersversion1.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)no planned changes to current
pubresolution logic (we believe this isn't needed if the guidance above is followed).