You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This RFC proposes a new standalone publishing sequence intended to minimize downstream disruption when migrating to new versions of standalone packages.
Current Status
At the time of this RFC, whenever we want to release new versions of standalone packages, we perform the following two-pass publishing sequence:
Perform a topological sort according to the stdlib dependency tree. Note that this sort prioritizes the JavaScript dependency tree. The corresponding sort may not match the C dependency tree, as a package's JavaScript implementation may not have the same dependencies as a package's C implementation. This can mean that the JavaScript topological sort is incorrect/out-of-order relative to the C topological sort. Previously, we attempted to factor both JavaScript and C dependencies into a single topological sort, but that resulted in false positive circular dependencies, so we focused on prioritizing the JavaScript sort, as this is likely the most important from a downstream user perspective (i.e., the JavaScript user base is and will likely always be larger than our C user base).
Next, starting from the root of the sort, sequentially publish to npm the next standalone package version according to conventional changelog, where the semantic version is derived from a package's Git history. This Git history is derived from the history on the main repository, as we do not currently replay commits on standalone repositories.
During the first pass publishing sequence, published packages will have broken builds as certain stdlib dependencies (e.g., C dependencies and dev dependencies) within the package's dependency tree will not have been published yet. This can be exacerbated if refactorings have occurred such that a new dependency has been introduced to a package, which has not yet been published. All of this can lead to temporary broken production builds. Because of this, we do another publishing pass in which we publish a new patch release of each standalone package, updating a package's dependency versions to point to the version released in (2). This subsequent release is intended to address the broken builds introduced in (2).
This current release protocol introduces significant problems, especially as downstream projects continue to build on stdlib. We need a better way.
Proposed Sequence
This RFC proposes a new three-pass standalone publishing sequence which is intended to address the shortcomings of the current approach.
Perform a topological sort, as done above. No change here. It is fine to continue prioritizing the JavaScript topological sort, as this approach already assumes the inevitability of broken builds.
Starting from the root of the sort, sequentially publish to npm a new standalone package version according to conventional changelog, with the key difference from above being that this package version must be a prerelease x.x.x-beta.1 version. This step is key because, by default, npm install only matches stable release versions (see https://docs.npmjs.com/cli/v11/commands/npm-install). During this sequence, we are fully acknowledging that the publish sequence will result in broken packages, but this is not an issue for downstream packages, as they are highly unlikely to install the prerelease versions, thus mitigating the problems encountered in stdlib-js/math-base-napi-unary is breaking build pipelines #9993.
After completion of (2), we kick off a new publishing sequence, this time publishing from the last package in the topological sort to the root (i.e., in reverse order). This release should be an x.x.x version, where a package's package.json stdlib dependency versions are updated to explicitly point to the prerelease x.x.x-beta.1 versions published in (2). Assuming that all packages in (2) were published, the newly released packages should all successfully build, and downstream failures should be mitigated even when downstream packages upgrade to the new x.x.x releases.
At this point, we have released x.x.x standalone packages which depend on x.x.x-beta.1 prereleases. Now, we need to publish new x.x.y (y = x+1) releases which point to the newly released x.x.x packages and do so according to normal semver rules (^x.x.x), such that npm install only matches the published stable versions. So, again, we kick off a new publishing sequence, iterating from the last package in the topological sort to the root (i.e., in reverse order).
Once (4) is completed, all packages will be published with individual x.x.y releases, which all point to x.x.x stdlib dependencies. Because of semver, on npm install, the newly released patch releases x.x.y will match, thus ensuring that all downstream dependencies have the most recent releases.
Other Notes
Can we not just enable automatic standalone publishing? Won't that fix everything?
No, it doesn't. The primary reason being that downstream breakages are likely to occur due to out-of-order distributed publishing and publishing failure modes. E.g., suppose package A has only patch updates and depends on package B. Package B was recently refactored to provide a new method and to now depend on newly created package C. Unfortunately, a random build failure resulted in the standalone repo publish sequence to fail and C was never published. If B gets published, it is now broken due to a missing dependency. If does not get published, but we publish A, A will fail because the latest published B does not contain the new method.
In short, distributed publishing has all the failure modes of distributed databases. Too many things can go wrong, randomly, resulting in a similar whack-a-whole mitigation scramble.
Automatic publishing is not entirely bad, but it should only be done on *-alpha release lines, where we signal that this release truly is bleeding edge. And rather than relying on strict conventional changelog semver, we may want automatic publishing to be triggered based on whether a package or any of its dependencies within the entire dependency chain has been updated. Having these continual *-alpha release lines could be useful in order to snuff out any early warning signs before initiating a formal standalone publish release sequences.
If no automatic publishing, do we not still have a bottleneck on individual maintainers initiating the release sequence?
Yes, although we could automate the proposed release sequence and have it run, say, only a monthly basis. This would require, however, a dedicated local dev machine kicking off this process, as the entire publishing sequence is likely too much to perform on GitHub CI, especially as the project continues to scale.
Assuming that we can work out the kinks and create a clean publishing sequence, this is something I would be willing to host.
Description
This RFC proposes a new standalone publishing sequence intended to minimize downstream disruption when migrating to new versions of standalone packages.
Current Status
At the time of this RFC, whenever we want to release new versions of standalone packages, we perform the following two-pass publishing sequence:
This current release protocol introduces significant problems, especially as downstream projects continue to build on stdlib. We need a better way.
Proposed Sequence
This RFC proposes a new three-pass standalone publishing sequence which is intended to address the shortcomings of the current approach.
x.x.x-beta.1version. This step is key because, by default,npm installonly matches stable release versions (see https://docs.npmjs.com/cli/v11/commands/npm-install). During this sequence, we are fully acknowledging that the publish sequence will result in broken packages, but this is not an issue for downstream packages, as they are highly unlikely to install the prerelease versions, thus mitigating the problems encountered in stdlib-js/math-base-napi-unary is breaking build pipelines #9993.x.x.xversion, where a package'spackage.jsonstdlib dependency versions are updated to explicitly point to the prereleasex.x.x-beta.1versions published in (2). Assuming that all packages in (2) were published, the newly released packages should all successfully build, and downstream failures should be mitigated even when downstream packages upgrade to the newx.x.xreleases.x.x.xstandalone packages which depend onx.x.x-beta.1prereleases. Now, we need to publish newx.x.y(y = x+1) releases which point to the newly releasedx.x.xpackages and do so according to normal semver rules (^x.x.x), such thatnpm installonly matches the published stable versions. So, again, we kick off a new publishing sequence, iterating from the last package in the topological sort to the root (i.e., in reverse order).Once (4) is completed, all packages will be published with individual
x.x.yreleases, which all point tox.x.xstdlib dependencies. Because of semver, onnpm install, the newly released patch releasesx.x.ywill match, thus ensuring that all downstream dependencies have the most recent releases.Other Notes
No, it doesn't. The primary reason being that downstream breakages are likely to occur due to out-of-order distributed publishing and publishing failure modes. E.g., suppose package A has only patch updates and depends on package B. Package B was recently refactored to provide a new method and to now depend on newly created package C. Unfortunately, a random build failure resulted in the standalone repo publish sequence to fail and C was never published. If B gets published, it is now broken due to a missing dependency. If does not get published, but we publish
A,Awill fail because the latest publishedBdoes not contain the new method.In short, distributed publishing has all the failure modes of distributed databases. Too many things can go wrong, randomly, resulting in a similar whack-a-whole mitigation scramble.
Automatic publishing is not entirely bad, but it should only be done on
*-alpharelease lines, where we signal that this release truly is bleeding edge. And rather than relying on strict conventional changelog semver, we may want automatic publishing to be triggered based on whether a package or any of its dependencies within the entire dependency chain has been updated. Having these continual*-alpharelease lines could be useful in order to snuff out any early warning signs before initiating a formal standalone publish release sequences.Yes, although we could automate the proposed release sequence and have it run, say, only a monthly basis. This would require, however, a dedicated local dev machine kicking off this process, as the entire publishing sequence is likely too much to perform on GitHub CI, especially as the project continues to scale.
Assuming that we can work out the kinks and create a clean publishing sequence, this is something I would be willing to host.
Related Issues
Related issues:
Questions
Other
cc @Planeshifter
Checklist
RFC:.