-
fix(core): degrade cooldown-blocked dist-tags within their own channel (#35967)
发布于
2026-06-11 20:48:14 +00:00 Current Behavior
When a package manager's minimum-release-age (cooldown) policy is
active,nx migrateresolves dist-tags through per-package-manager
emulation, and degrading a too-new tag produced inconsistent, often
nonsensical results.nx migrate nextcould resolve to an internal
pr.*preview build or a years-old release candidate; the npm path
diverged from what npm itself installs; and yarn errored outright. Each
of npm, pnpm, yarn, and bun carried its own tag-degrade implementation.Expected Behavior
Dist-tag degrade is unified into a single rule across all four package
managers. When the resolved tag target is within the cooldown window,
the candidate pool is every version at or below it that is stable, in
the target's own prerelease channel, or on a lower rung of an explicit
channel ladder (alpha < beta < rc). That pool is ordered, and the
first compliant version wins:- Prereleases of the target's exact
major.minor.patchcome first — own
channel, then lower ladder rungs. - Then everything else, ordered by most recently published.
So
latest(or any stable tag) lands on the newest compliant stable. A
prerelease tag keeps a compliant prerelease of the release it points at:
every same-line release candidate is exhausted first, and a blocked
rc.0with no older rc sibling falls to a same-linebeta.xrather
than skipping back to the previous stable. A newer-published cross-line
backport can't outrank the same-line beta, and the degrade never climbs
the ladder upward. Channels with no place on the ladder (such as the
internalprbuilds, orcanary) stay walled off entirely.nextis
deliberately left off the ladder: it is pre-rc in some ecosystems
(Angular) but a rolling dev snapshot in others — exactly the class of
build a degrade must never land on. The channel is derived generically
from a version's prerelease identifier, so it works for any package's
naming convention.Implementation Details
A shared
degradeTagToComplianthelper replaces npm's<=tagTarget
recursion, pnpm's same-major degrade (and its deprecation tie-break
machinery), yarn's latest-only walk-down, and bun's channel walk. It
builds the pool, orders it (same-line own-channel, then same-line
lower-rung, then by publish date), and returns the first version that
passes the caller's maturity test; each package manager supplies only
that test and its own violation shape. The helper guards against
non-semver dist-tag targets and registry version entries
(semver.comparepreviously threw, and the migrate consumer swallows
unknown errors into a real-install fallback).The cleanup also drops the now-dead
latestTagDegradebehavior axis and
the redundant pnpm 10.20 behavior row, along with the tests that pinned
the old version-specific behavior. The npm policy-reader specs are
isolated from the host's real~/.npmrcand reuse the real.npmrc
parser (parseNpmrcContent) instead of a hand-copied mirror, and npm's
tag-path ENOVERSIONS branch is now covered.
Co-authored-by: FrozenPandaz jasonjean1993@gmail.com
下载附件
- Prereleases of the target's exact