mirror of
https://github.com/pnpm/pnpm.git
synced 2026-02-15 17:42:31 -05:00
fix: don't downgrade dist-tags to prerelease versions when minimumReleaseAge is set (#9988)
close #9979
This commit is contained in:
6
.changeset/weak-aliens-brake.md
Normal file
6
.changeset/weak-aliens-brake.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/npm-resolver": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
When `minimumReleaseAge` is set and the active version under a dist-tag is not mature enough, do not downgrade to a prerelease version in case the original version wasn't a prerelease one [#9979](https://github.com/pnpm/pnpm/issues/9979).
|
||||
@@ -240,6 +240,19 @@ function filterMetaByPublishedDate (meta: PackageMetaWithTime, publishedBy: Date
|
||||
|
||||
const distTagsWithinDate: PackageMeta['dist-tags'] = {}
|
||||
const allDistTags = meta['dist-tags'] ?? {}
|
||||
const parsedSemverCache = new Map<string, semver.SemVer>()
|
||||
function tryParseSemver (semverStr: string): semver.SemVer | null {
|
||||
let parsedSemver = parsedSemverCache.get(semverStr)
|
||||
if (!parsedSemver) {
|
||||
try {
|
||||
parsedSemver = new semver.SemVer(semverStr, true)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
parsedSemverCache.set(semverStr, parsedSemver)
|
||||
}
|
||||
return parsedSemver
|
||||
}
|
||||
for (const tag in allDistTags) {
|
||||
if (!Object.hasOwn(allDistTags, tag)) continue
|
||||
const distTagVersion = allDistTags[tag]
|
||||
@@ -248,17 +261,18 @@ function filterMetaByPublishedDate (meta: PackageMetaWithTime, publishedBy: Date
|
||||
continue
|
||||
}
|
||||
// Repopulate the tag to the highest version available within date that has the same major as the original tag's version
|
||||
let originalSemVer: semver.SemVer | null = null
|
||||
try {
|
||||
originalSemVer = new semver.SemVer(distTagVersion, true)
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
const originalMajor = originalSemVer.major
|
||||
const originalSemVer = tryParseSemver(distTagVersion)
|
||||
if (!originalSemVer) continue
|
||||
const originalIsPrerelease = (originalSemVer.prerelease.length > 0)
|
||||
let bestVersion: string | undefined
|
||||
const originalMajorPrefix = `${originalMajor}.`
|
||||
for (const candidate in versionsWithinDate) {
|
||||
if (!Object.hasOwn(versionsWithinDate, candidate) || !candidate.startsWith(originalMajorPrefix)) continue
|
||||
if (!Object.hasOwn(versionsWithinDate, candidate)) continue
|
||||
const candidateParsed = tryParseSemver(candidate)
|
||||
if (
|
||||
!candidateParsed ||
|
||||
candidateParsed.major !== originalSemVer.major ||
|
||||
(candidateParsed.prerelease.length > 0) !== originalIsPrerelease
|
||||
) continue
|
||||
if (!bestVersion) {
|
||||
bestVersion = candidate
|
||||
} else {
|
||||
|
||||
@@ -79,6 +79,128 @@ test('repopulate dist-tag to highest same-major version within the date cutoff',
|
||||
expect(res!.id).toBe(`${name}@3.1.0`)
|
||||
})
|
||||
|
||||
test('repopulate dist-tag to highest non-prerelease same-major version within the date cutoff', async () => {
|
||||
const name = 'dist-tag-date'
|
||||
const meta = {
|
||||
name,
|
||||
versions: {
|
||||
'3.0.0': {
|
||||
name,
|
||||
version: '3.0.0',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.0.0.tgz` },
|
||||
},
|
||||
'3.1.0-alpha.0': {
|
||||
name,
|
||||
version: '3.1.0-alpha.0',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.1.0-alpha.0.tgz` },
|
||||
},
|
||||
'3.2.0': {
|
||||
name,
|
||||
version: '3.2.0',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.2.0.tgz` },
|
||||
},
|
||||
'2.9.9': {
|
||||
name,
|
||||
version: '2.9.9',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-2.9.9.tgz` },
|
||||
},
|
||||
},
|
||||
'dist-tags': {
|
||||
latest: '3.2.0',
|
||||
},
|
||||
time: {
|
||||
'2.9.9': '2020-01-01T00:00:00.000Z',
|
||||
'3.0.0': '2020-02-01T00:00:00.000Z',
|
||||
'3.1.0-alpha.0': '2020-03-01T00:00:00.000Z',
|
||||
'3.2.0': '2020-05-01T00:00:00.000Z',
|
||||
},
|
||||
}
|
||||
|
||||
// Cutoff before 3.2.0, so latest must be remapped to 3.1.0 (same major 3)
|
||||
const cutoff = new Date('2020-04-01T00:00:00.000Z')
|
||||
|
||||
nock(registries.default)
|
||||
.get(`/${name}`)
|
||||
.reply(200, meta)
|
||||
|
||||
const cacheDir = tempy.directory()
|
||||
const { resolveFromNpm } = createResolveFromNpm({
|
||||
cacheDir,
|
||||
fullMetadata: true,
|
||||
registries,
|
||||
})
|
||||
|
||||
const res = await resolveFromNpm({ alias: name, bareSpecifier: 'latest' }, {
|
||||
publishedBy: cutoff,
|
||||
})
|
||||
|
||||
expect(res!.id).toBe(`${name}@3.0.0`)
|
||||
})
|
||||
|
||||
test('repopulate dist-tag to highest prerelease same-major version within the date cutoff', async () => {
|
||||
const name = 'dist-tag-date'
|
||||
const meta = {
|
||||
name,
|
||||
versions: {
|
||||
'3.0.0-alpha.0': {
|
||||
name,
|
||||
version: '3.0.0-alpha.0',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.0.0-alpha.0.tgz` },
|
||||
},
|
||||
'3.0.0-alpha.1': {
|
||||
name,
|
||||
version: '3.0.0-alpha.1',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.0.0-alpha.1.tgz` },
|
||||
},
|
||||
'3.0.0-alpha.2': {
|
||||
name,
|
||||
version: '3.0.0-alpha.2',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.0.0-alpha.2.tgz` },
|
||||
},
|
||||
'3.2.0': {
|
||||
name,
|
||||
version: '3.2.0',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.2.0.tgz` },
|
||||
},
|
||||
'2.9.9': {
|
||||
name,
|
||||
version: '2.9.9',
|
||||
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-2.9.9.tgz` },
|
||||
},
|
||||
},
|
||||
'dist-tags': {
|
||||
latest: '3.0.0-alpha.2',
|
||||
},
|
||||
time: {
|
||||
'2.9.9': '2020-01-01T00:00:00.000Z',
|
||||
'3.0.0-alpha.0': '2020-02-01T00:00:00.000Z',
|
||||
'3.0.0-alpha.1': '2020-03-01T00:00:00.000Z',
|
||||
'3.0.0-alpha.2': '2020-05-01T00:00:00.000Z',
|
||||
'3.2.0': '2020-05-01T00:00:00.000Z',
|
||||
},
|
||||
}
|
||||
|
||||
// Cutoff before 3.2.0 and 3.0.0-alpha.2, so latest must be remapped to 3.0.0-alpha.1 (the highest prerelease version within the cutoff)
|
||||
const cutoff = new Date('2020-04-01T00:00:00.000Z')
|
||||
|
||||
nock(registries.default)
|
||||
.get(`/${name}`)
|
||||
.reply(200, meta)
|
||||
|
||||
const cacheDir = tempy.directory()
|
||||
const { resolveFromNpm } = createResolveFromNpm({
|
||||
cacheDir,
|
||||
fullMetadata: true,
|
||||
registries,
|
||||
})
|
||||
|
||||
const res = await resolveFromNpm({ alias: name, bareSpecifier: 'latest' }, {
|
||||
publishedBy: cutoff,
|
||||
})
|
||||
|
||||
expect(res!.id).toBe(`${name}@3.0.0-alpha.1`)
|
||||
})
|
||||
|
||||
test('keep dist-tag if original version is within the date cutoff', async () => {
|
||||
const name = 'dist-tag-date-keep'
|
||||
const meta = {
|
||||
|
||||
Reference in New Issue
Block a user