mirror of
https://github.com/pnpm/pnpm.git
synced 2026-07-11 16:26:10 -04:00
fix(update): stop downgrading prereleases (#7466)
close #7436 --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
12
.changeset/big-planes-smell.md
Normal file
12
.changeset/big-planes-smell.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": minor
|
||||
"@pnpm/resolve-dependencies": minor
|
||||
"@pnpm/package-requester": patch
|
||||
"@pnpm/store-controller-types": minor
|
||||
"@pnpm/resolver-base": minor
|
||||
"@pnpm/npm-resolver": minor
|
||||
"@pnpm/core": minor
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Running `pnpm update -r --latest` will no longer downgrade prerelease dependencies [#7436](https://github.com/pnpm/pnpm/issues/7436).
|
||||
@@ -44,7 +44,7 @@
|
||||
"@pnpm/constants": "workspace:*",
|
||||
"@pnpm/lockfile-types": "workspace:*",
|
||||
"@pnpm/modules-yaml": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/types": "workspace:*",
|
||||
"is-windows": "^1.0.2",
|
||||
"isexe": "2.0.0",
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"test": "pnpm pretest && pnpm run compile && jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/store.cafs": "workspace:*",
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@pnpm/filter-workspace-packages": "workspace:*",
|
||||
"@pnpm/plugin-commands-rebuild": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@pnpm/test-ipc-server": "workspace:*",
|
||||
"@types/ramda": "0.28.20",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@pnpm/filter-workspace-packages": "workspace:*",
|
||||
"@pnpm/plugin-commands-script-runners": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-ipc-server": "workspace:*",
|
||||
"@types/is-windows": "^1.0.2",
|
||||
"@types/ramda": "0.28.20",
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"@commitlint/prompt-cli": "^17.8.1",
|
||||
"@pnpm/eslint-config": "workspace:*",
|
||||
"@pnpm/meta-updater": "1.0.0",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/tsconfig": "workspace:*",
|
||||
"@pnpm/worker": "workspace:*",
|
||||
"@types/jest": "^29.5.8",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@pnpm/filter-workspace-packages": "workspace:*",
|
||||
"@pnpm/plugin-commands-patching": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@types/normalize-path": "^3.0.2",
|
||||
"@types/ramda": "0.28.20",
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
"@pnpm/lockfile-types": "workspace:*",
|
||||
"@pnpm/package-store": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/store-path": "workspace:*",
|
||||
"@pnpm/store.cafs": "workspace:*",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
|
||||
@@ -91,6 +91,7 @@ export interface StrictInstallOptions {
|
||||
unsafePerm: boolean
|
||||
registries: Registries
|
||||
tag: string
|
||||
updateToLatest?: boolean
|
||||
overrides: Record<string, string>
|
||||
ownLifecycleHooksStdio: 'inherit' | 'pipe'
|
||||
workspacePackages: WorkspacePackages
|
||||
|
||||
@@ -1032,6 +1032,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
saveWorkspaceProtocol: opts.saveWorkspaceProtocol,
|
||||
storeController: opts.storeController,
|
||||
tag: opts.tag,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
virtualStoreDir: ctx.virtualStoreDir,
|
||||
wantedLockfile: ctx.wantedLockfile,
|
||||
workspacePackages: opts.workspacePackages,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"@pnpm/package-store": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/read-projects-context": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/store-path": "workspace:*",
|
||||
"@pnpm/store.cafs": "workspace:*",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
"@pnpm/client": "workspace:*",
|
||||
"@pnpm/create-cafs-store": "workspace:*",
|
||||
"@pnpm/package-requester": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@types/normalize-path": "^3.0.2",
|
||||
"@types/ramda": "0.28.20",
|
||||
|
||||
@@ -184,6 +184,7 @@ async function resolveAndFetch (
|
||||
projectDir: options.projectDir,
|
||||
registry: options.registry,
|
||||
workspacePackages: options.workspacePackages,
|
||||
updateToLatest: options.updateToLatest,
|
||||
}), { priority: options.downloadPriority })
|
||||
|
||||
manifest = resolveResult.manifest
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@pnpm/modules-yaml": "workspace:*",
|
||||
"@pnpm/plugin-commands-installation": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@pnpm/test-ipc-server": "workspace:*",
|
||||
"@types/proxyquire": "^1.3.31",
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { type Config, getOptionsFromRootManifest } from '@pnpm/config'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { filterPkgsBySelectorObjects } from '@pnpm/filter-workspace-packages'
|
||||
import { filterDependenciesByType } from '@pnpm/manifest-utils'
|
||||
import { arrayOfWorkspacePackagesToMap, findWorkspacePackages } from '@pnpm/workspace.find-packages'
|
||||
import { type Lockfile } from '@pnpm/lockfile-types'
|
||||
import { rebuildProjects } from '@pnpm/plugin-commands-rebuild'
|
||||
@@ -25,7 +26,6 @@ import { getPinnedVersion } from './getPinnedVersion'
|
||||
import { getSaveType } from './getSaveType'
|
||||
import { getNodeExecPath } from './nodeExecPath'
|
||||
import { recursive, createMatcher, matchDependencies, makeIgnorePatterns, type UpdateDepsMatcher } from './recursive'
|
||||
import { updateToLatestSpecsFromManifest, createLatestSpecs } from './updateToLatestSpecsFromManifest'
|
||||
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './updateWorkspaceDependencies'
|
||||
|
||||
const OVERWRITE_UPDATE_OPTIONS = {
|
||||
@@ -105,6 +105,7 @@ export type InstallDepsOptions = Pick<Config,
|
||||
*/
|
||||
lockfileCheck?: (prev: Lockfile, next: Lockfile) => void
|
||||
update?: boolean
|
||||
updateToLatest?: boolean
|
||||
updateMatching?: (pkgName: string) => boolean
|
||||
updatePackageManifest?: boolean
|
||||
useBetaCli?: boolean
|
||||
@@ -265,12 +266,8 @@ when running add/update with the --workspace option')
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.update && opts.latest) {
|
||||
if (!params || (params.length === 0)) {
|
||||
params = updateToLatestSpecsFromManifest(manifest, includeDirect)
|
||||
} else {
|
||||
params = createLatestSpecs(params, manifest)
|
||||
}
|
||||
if (opts.update && opts.latest && (!params || (params.length === 0))) {
|
||||
params = Object.keys(filterDependenciesByType(manifest, includeDirect))
|
||||
}
|
||||
if (opts.workspace) {
|
||||
if (!params || (params.length === 0)) {
|
||||
|
||||
@@ -36,7 +36,6 @@ import mem from 'mem'
|
||||
import pFilter from 'p-filter'
|
||||
import pLimit from 'p-limit'
|
||||
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './updateWorkspaceDependencies'
|
||||
import { updateToLatestSpecsFromManifest, createLatestSpecs } from './updateToLatestSpecsFromManifest'
|
||||
import { getSaveType } from './getSaveType'
|
||||
import { getPinnedVersion } from './getPinnedVersion'
|
||||
import { type PreferredVersions } from '@pnpm/resolver-base'
|
||||
@@ -197,16 +196,8 @@ export async function recursive (
|
||||
return
|
||||
}
|
||||
}
|
||||
if (updateToLatest) {
|
||||
if (!params || (params.length === 0)) {
|
||||
currentInput = updateToLatestSpecsFromManifest(manifest, includeDirect)
|
||||
} else {
|
||||
currentInput = createLatestSpecs(currentInput, manifest)
|
||||
if (currentInput.length === 0) {
|
||||
installOpts.pruneLockfileImporters = false
|
||||
return
|
||||
}
|
||||
}
|
||||
if (updateToLatest && (!params || (params.length === 0))) {
|
||||
currentInput = Object.keys(filterDependenciesByType(manifest, includeDirect))
|
||||
}
|
||||
if (opts.workspace) {
|
||||
if (!currentInput || (currentInput.length === 0)) {
|
||||
@@ -319,13 +310,8 @@ export async function recursive (
|
||||
currentInput = matchDependencies(updateMatch, manifest, includeDirect)
|
||||
if (currentInput.length === 0) return
|
||||
}
|
||||
if (updateToLatest) {
|
||||
if (!params || (params.length === 0)) {
|
||||
currentInput = updateToLatestSpecsFromManifest(manifest, includeDirect)
|
||||
} else {
|
||||
currentInput = createLatestSpecs(currentInput, manifest)
|
||||
if (currentInput.length === 0) return
|
||||
}
|
||||
if (updateToLatest && (!params || (params.length === 0))) {
|
||||
currentInput = Object.keys(filterDependenciesByType(manifest, includeDirect))
|
||||
}
|
||||
if (opts.workspace) {
|
||||
if (!currentInput || (currentInput.length === 0)) {
|
||||
|
||||
@@ -290,6 +290,7 @@ async function update (
|
||||
includeDirect,
|
||||
include,
|
||||
update: true,
|
||||
updateToLatest: opts.latest,
|
||||
updateMatching: (dependencies.length > 0) && dependencies.every(dep => !dep.substring(1).includes('@')) && depth > 0 && !opts.latest
|
||||
? createMatcher(dependencies)
|
||||
: undefined,
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { filterDependenciesByType, getAllDependenciesFromManifest } from '@pnpm/manifest-utils'
|
||||
import { type IncludedDependencies, type ProjectManifest } from '@pnpm/types'
|
||||
import getVerSelType from 'version-selector-type'
|
||||
|
||||
export function updateToLatestSpecsFromManifest (manifest: ProjectManifest, include: IncludedDependencies) {
|
||||
const allDeps = filterDependenciesByType(manifest, include)
|
||||
const updateSpecs = []
|
||||
for (const [depName, depVersion] of Object.entries(allDeps)) {
|
||||
if (depVersion.startsWith('npm:')) {
|
||||
updateSpecs.push(`${depName}@${removeVersionFromSpec(depVersion)}@latest`)
|
||||
} else {
|
||||
const selector = getVerSelType(depVersion)
|
||||
if (selector == null) continue
|
||||
updateSpecs.push(`${depName}@latest`)
|
||||
}
|
||||
}
|
||||
return updateSpecs
|
||||
}
|
||||
|
||||
export function createLatestSpecs (specs: string[], manifest: ProjectManifest) {
|
||||
const allDeps = getAllDependenciesFromManifest(manifest)
|
||||
return specs
|
||||
.filter((selector) => selector.includes('@', 1)
|
||||
? allDeps[selector.slice(0, selector.indexOf('@', 1))]
|
||||
: allDeps[selector]
|
||||
)
|
||||
.map((selector) => {
|
||||
if (selector.includes('@', 1)) {
|
||||
return selector
|
||||
}
|
||||
if (allDeps[selector].startsWith('npm:')) {
|
||||
return `${selector}@${removeVersionFromSpec(allDeps[selector])}@latest`
|
||||
}
|
||||
if (getVerSelType(allDeps[selector]) == null) {
|
||||
return selector
|
||||
}
|
||||
return `${selector}@latest`
|
||||
})
|
||||
}
|
||||
|
||||
function removeVersionFromSpec (spec: string) {
|
||||
return spec.substring(0, spec.lastIndexOf('@'))
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { updateToLatestSpecsFromManifest, createLatestSpecs } from '../lib/updateToLatestSpecsFromManifest'
|
||||
|
||||
const MANIFEST = {
|
||||
dependencies: {
|
||||
'@pnpm.e2e/dep-of-pkg-with-1-dep': 'npm:@pnpm.e2e/pkg-with-1-dep@1.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
foo: 'github:pnpm/foo',
|
||||
},
|
||||
optionalDependencies: {
|
||||
'is-positive': '^1.0.0',
|
||||
},
|
||||
}
|
||||
|
||||
test('updateToLatestSpecsFromManifest()', () => {
|
||||
const updateResult1 = expect(updateToLatestSpecsFromManifest(MANIFEST, {
|
||||
optionalDependencies: true,
|
||||
dependencies: true,
|
||||
devDependencies: true,
|
||||
}))
|
||||
updateResult1.toHaveLength(2)
|
||||
updateResult1.toContain('@pnpm.e2e/dep-of-pkg-with-1-dep@npm:@pnpm.e2e/pkg-with-1-dep@latest')
|
||||
updateResult1.toContain('is-positive@latest')
|
||||
|
||||
const updateResult2 = expect(updateToLatestSpecsFromManifest(MANIFEST, {
|
||||
optionalDependencies: false,
|
||||
dependencies: true,
|
||||
devDependencies: false,
|
||||
}))
|
||||
updateResult2.toHaveLength(1)
|
||||
updateResult2.toStrictEqual(['@pnpm.e2e/dep-of-pkg-with-1-dep@npm:@pnpm.e2e/pkg-with-1-dep@latest'])
|
||||
})
|
||||
|
||||
test('createLatestSpecs()', () => {
|
||||
expect(
|
||||
createLatestSpecs(['@pnpm.e2e/dep-of-pkg-with-1-dep', 'is-positive@2.0.0', 'foo'], MANIFEST)
|
||||
).toStrictEqual(['@pnpm.e2e/dep-of-pkg-with-1-dep@npm:@pnpm.e2e/pkg-with-1-dep@latest', 'is-positive@2.0.0', 'foo'])
|
||||
|
||||
expect(
|
||||
createLatestSpecs(['@pnpm.e2e/dep-of-pkg-with-1-dep', 'is-positive', 'foo', 'bar'], MANIFEST)
|
||||
).toStrictEqual(['@pnpm.e2e/dep-of-pkg-with-1-dep@npm:@pnpm.e2e/pkg-with-1-dep@latest', 'is-positive@latest', 'foo'])
|
||||
})
|
||||
@@ -17,6 +17,7 @@ export interface WantedDependency {
|
||||
raw: string
|
||||
pinnedVersion?: PinnedVersion
|
||||
nodeExecPath?: string
|
||||
updateSpec?: boolean
|
||||
}
|
||||
|
||||
export function getWantedDependencies (
|
||||
|
||||
@@ -109,6 +109,8 @@ export async function resolveDependencies (
|
||||
preferredVersions: opts.preferredVersions,
|
||||
virtualStoreDir: opts.virtualStoreDir,
|
||||
workspacePackages: opts.workspacePackages,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
noDependencySelectors: importers.every(({ wantedDependencies }) => wantedDependencies.length === 0),
|
||||
})
|
||||
const projectsToResolve = await Promise.all(importers.map(async (project) => _toResolveImporter(project)))
|
||||
const {
|
||||
|
||||
@@ -255,6 +255,7 @@ interface ResolvedDependenciesOptions {
|
||||
updateDepth: number
|
||||
prefix: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
updateToLatest?: boolean
|
||||
}
|
||||
|
||||
interface PostponedResolutionOpts {
|
||||
@@ -677,6 +678,7 @@ async function resolveDependenciesOfDependency (
|
||||
updateDepth,
|
||||
updateMatching: options.updateMatching,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
updateToLatest: options.updateToLatest,
|
||||
}
|
||||
const resolveDependencyResult = await resolveDependency(extendedWantedDep.wantedDependency, ctx, resolveDependencyOpts)
|
||||
|
||||
@@ -713,6 +715,7 @@ async function resolveDependenciesOfDependency (
|
||||
prefix: options.prefix,
|
||||
updateMatching: options.updateMatching,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
updateToLatest: options.updateToLatest,
|
||||
})
|
||||
return {
|
||||
resolveDependencyResult,
|
||||
@@ -769,6 +772,7 @@ async function resolveChildren (
|
||||
prefix: string
|
||||
updateMatching?: UpdateMatchingFunction
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
updateToLatest?: boolean
|
||||
},
|
||||
{
|
||||
parentPkgAliases,
|
||||
@@ -1019,6 +1023,7 @@ interface ResolveDependencyOptions {
|
||||
updateDepth: number
|
||||
updateMatching?: UpdateMatchingFunction
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
updateToLatest?: boolean
|
||||
}
|
||||
|
||||
type ResolveDependencyResult = PkgAddress | LinkedDependency | null
|
||||
@@ -1098,6 +1103,7 @@ async function resolveDependency (
|
||||
err.pkgsStack = nodeIdToParents(options.parentPkg.nodeId, ctx.resolvedPackagesByDepPath)
|
||||
return err
|
||||
},
|
||||
updateToLatest: options.updateToLatest,
|
||||
})
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (wantedDependency.optional) {
|
||||
|
||||
@@ -99,6 +99,7 @@ export interface ResolveDependenciesOptions {
|
||||
wantedLockfile: Lockfile
|
||||
workspacePackages: WorkspacePackages
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
updateToLatest?: boolean
|
||||
}
|
||||
|
||||
export async function resolveDependencyTree<T> (
|
||||
@@ -166,6 +167,7 @@ export async function resolveDependencyTree<T> (
|
||||
updateMatching: importer.updateMatching,
|
||||
prefix: importer.rootDir,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
}
|
||||
return {
|
||||
updatePackageManifest: importer.updatePackageManifest,
|
||||
|
||||
@@ -17,6 +17,8 @@ export async function toResolveImporter (
|
||||
preferredVersions?: PreferredVersions
|
||||
virtualStoreDir: string
|
||||
workspacePackages: WorkspacePackages
|
||||
updateToLatest?: boolean
|
||||
noDependencySelectors: boolean
|
||||
},
|
||||
project: ImporterToResolve
|
||||
) {
|
||||
@@ -31,6 +33,11 @@ export async function toResolveImporter (
|
||||
const defaultUpdateDepth = (project.update === true || (project.updateMatching != null)) ? opts.defaultUpdateDepth : -1
|
||||
const existingDeps = nonLinkedDependencies
|
||||
.filter(({ alias }) => !project.wantedDependencies.some((wantedDep) => wantedDep.alias === alias))
|
||||
if (opts.updateToLatest && opts.noDependencySelectors) {
|
||||
for (const dep of existingDeps) {
|
||||
dep.updateSpec = true
|
||||
}
|
||||
}
|
||||
let wantedDependencies!: Array<WantedDependency & { isNew?: boolean, updateDepth: number }>
|
||||
if (!project.manifest) {
|
||||
wantedDependencies = [
|
||||
@@ -48,14 +55,18 @@ export async function toResolveImporter (
|
||||
...dep,
|
||||
updateDepth: project.updateMatching != null
|
||||
? defaultUpdateDepth
|
||||
: (prefIsLocalTarball(dep.pref) ? 0 : -1),
|
||||
: (prefIsLocalTarball(dep.pref) ? 0 : defaultUpdateDepth),
|
||||
})
|
||||
wantedDependencies = [
|
||||
...project.wantedDependencies.map(
|
||||
defaultUpdateDepth < 0
|
||||
? updateLocalTarballs
|
||||
: (dep) => ({ ...dep, updateDepth: defaultUpdateDepth })),
|
||||
...existingDeps.map(updateLocalTarballs),
|
||||
...existingDeps.map(
|
||||
opts.noDependencySelectors && project.updateMatching != null
|
||||
? updateLocalTarballs
|
||||
: (dep) => ({ ...dep, updateDepth: -1 })
|
||||
),
|
||||
]
|
||||
}
|
||||
return {
|
||||
|
||||
408
pnpm-lock.yaml
generated
408
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -63,7 +63,7 @@
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/read-package-json": "workspace:*",
|
||||
"@pnpm/read-project-manifest": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/run-npm": "workspace:*",
|
||||
"@pnpm/tabtab": "^0.1.2",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
|
||||
@@ -201,9 +201,9 @@ test('update --latest specific dependency', async function () {
|
||||
addDistTag('@pnpm.e2e/qar', '100.1.0', 'latest'),
|
||||
])
|
||||
|
||||
await execPnpm(['add', '@pnpm.e2e/dep-of-pkg-with-1-dep@100.0.0', '@pnpm.e2e/bar@^100.0.0', '@pnpm.e2e/foo@100.1.0', 'alias@npm:@pnpm.e2e/qar@^100.0.0', 'kevva/is-negative'])
|
||||
await execPnpm(['add', '@pnpm.e2e/dep-of-pkg-with-1-dep@100.0.0', '@pnpm.e2e/bar@^100.0.0', '@pnpm.e2e/foo@100.0.0', 'alias@npm:@pnpm.e2e/qar@^100.0.0', 'kevva/is-negative'])
|
||||
|
||||
await execPnpm(['update', '-L', '@pnpm.e2e/bar', '@pnpm.e2e/foo@100.0.0', 'alias', 'is-negative'])
|
||||
await execPnpm(['update', '-L', '@pnpm.e2e/bar', 'alias', 'is-negative'])
|
||||
|
||||
const lockfile = await project.readLockfile()
|
||||
expect(lockfile.dependencies['@pnpm.e2e/dep-of-pkg-with-1-dep'].version).toBe('100.0.0')
|
||||
@@ -378,7 +378,7 @@ test('recursive update --latest specific dependency on projects that do not shar
|
||||
|
||||
dependencies: {
|
||||
alias: 'npm:@pnpm.e2e/qar@100.0.0',
|
||||
'@pnpm.e2e/dep-of-pkg-with-1-dep': '101.0.0',
|
||||
'@pnpm.e2e/dep-of-pkg-with-1-dep': '100.0.0',
|
||||
'@pnpm.e2e/foo': '^100.0.0',
|
||||
},
|
||||
},
|
||||
@@ -395,7 +395,7 @@ test('recursive update --latest specific dependency on projects that do not shar
|
||||
|
||||
await execPnpm(['-r', 'install'])
|
||||
|
||||
await execPnpm(['-r', 'update', '--latest', '@pnpm.e2e/foo', '@pnpm.e2e/dep-of-pkg-with-1-dep@100.0.0', 'alias'])
|
||||
await execPnpm(['-r', 'update', '--latest', '@pnpm.e2e/foo', 'alias'])
|
||||
|
||||
const manifest1 = await readPackageJsonFromDir(path.resolve('project-1'))
|
||||
expect(manifest1.dependencies).toStrictEqual({
|
||||
@@ -552,7 +552,7 @@ test('recursive update --latest specific dependency on projects with a shared a
|
||||
|
||||
dependencies: {
|
||||
alias: 'npm:@pnpm.e2e/qar@100.0.0',
|
||||
'@pnpm.e2e/dep-of-pkg-with-1-dep': '101.0.0',
|
||||
'@pnpm.e2e/dep-of-pkg-with-1-dep': '100.0.0',
|
||||
'@pnpm.e2e/foo': '100.0.0',
|
||||
},
|
||||
},
|
||||
@@ -570,7 +570,7 @@ test('recursive update --latest specific dependency on projects with a shared a
|
||||
await writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
|
||||
await execPnpm(['recursive', 'install'])
|
||||
|
||||
await execPnpm(['recursive', 'update', '--latest', '@pnpm.e2e/foo', '@pnpm.e2e/dep-of-pkg-with-1-dep@100.0.0', 'alias'])
|
||||
await execPnpm(['recursive', 'update', '--latest', '@pnpm.e2e/foo', 'alias'])
|
||||
|
||||
const manifest1 = await readPackageJsonFromDir(path.resolve('project-1'))
|
||||
expect(manifest1.dependencies).toStrictEqual({
|
||||
@@ -608,3 +608,210 @@ test('deep update', async function () {
|
||||
|
||||
await project.storeHas('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.1.0')
|
||||
})
|
||||
|
||||
test('update to latest without downgrading already defined prerelease (#7436)', async function () {
|
||||
prepare()
|
||||
|
||||
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
|
||||
await execPnpm(['add', '@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
|
||||
const manifest1 = await readPackageJsonFromDir('.')
|
||||
expect(manifest1).toMatchObject({
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
})
|
||||
|
||||
const lockfile1 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile1).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
expect(lockfile1).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
|
||||
await execPnpm(['update', '--latest'])
|
||||
|
||||
const manifest2 = await readPackageJsonFromDir('.')
|
||||
expect(manifest2).toMatchObject({
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
})
|
||||
|
||||
const lockfile2 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile2).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
expect(lockfile2).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
|
||||
await execPnpm(['update', '-r', '--latest'])
|
||||
|
||||
const manifest3 = await readPackageJsonFromDir('.')
|
||||
expect(manifest3).toMatchObject({
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
})
|
||||
|
||||
const lockfile3 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile3).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
expect(lockfile3).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
})
|
||||
|
||||
test('update with tag @latest will downgrade prerelease', async function () {
|
||||
prepare()
|
||||
|
||||
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
|
||||
await execPnpm(['add', '@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
|
||||
const manifest1 = await readPackageJsonFromDir('.')
|
||||
expect(manifest1).toMatchObject({
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
})
|
||||
|
||||
const lockfile1 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile1).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
expect(lockfile1).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
|
||||
await execPnpm(['update', '@pnpm.e2e/has-prerelease@latest'])
|
||||
|
||||
const manifest2 = await readPackageJsonFromDir('.')
|
||||
expect(manifest2).toMatchObject({
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '2.0.0',
|
||||
},
|
||||
})
|
||||
|
||||
const lockfile2 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile2).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
expect(lockfile2).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
})
|
||||
|
||||
test('update to latest recursive workspace (outdated, updated, prerelease, outdated)', async function () {
|
||||
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
|
||||
|
||||
preparePackages([
|
||||
{
|
||||
name: 'project-1',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '2.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-3',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-4',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '1.0.0',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
|
||||
await execPnpm(['install', '-r'])
|
||||
|
||||
const lockfile1 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile1).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@1.0.0'])
|
||||
expect(lockfile1).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
expect(lockfile1).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
|
||||
await execPnpm(['update', '-r', '--latest'])
|
||||
|
||||
const manifests = {
|
||||
'project-1': await readPackageJsonFromDir('project-1'),
|
||||
'project-2': await readPackageJsonFromDir('project-2'),
|
||||
'project-3': await readPackageJsonFromDir('project-3'),
|
||||
'project-4': await readPackageJsonFromDir('project-4'),
|
||||
}
|
||||
expect(manifests).toMatchObject({
|
||||
'project-1': {
|
||||
name: 'project-1',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '2.0.0',
|
||||
},
|
||||
},
|
||||
'project-2': {
|
||||
name: 'project-2',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '2.0.0',
|
||||
},
|
||||
},
|
||||
'project-3': {
|
||||
name: 'project-3',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
},
|
||||
'project-4': {
|
||||
name: 'project-4',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '2.0.0',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const lockfile2 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile2).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@1.0.0'])
|
||||
expect(lockfile2).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
expect(lockfile2).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
})
|
||||
|
||||
test('update to latest recursive workspace (prerelease, outdated)', async function () {
|
||||
await addDistTag('@pnpm.e2e/has-prerelease', '2.0.0', 'latest')
|
||||
|
||||
preparePackages([
|
||||
{
|
||||
name: 'project-1',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '1.0.0',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
|
||||
await execPnpm(['install', '-r'])
|
||||
|
||||
const lockfile1 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile1).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@1.0.0'])
|
||||
expect(lockfile1).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
expect(lockfile1).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
|
||||
await execPnpm(['update', '-r', '--latest'])
|
||||
|
||||
const manifests = {
|
||||
'project-1': await readPackageJsonFromDir('project-1'),
|
||||
'project-2': await readPackageJsonFromDir('project-2'),
|
||||
}
|
||||
expect(manifests).toMatchObject({
|
||||
'project-1': {
|
||||
name: 'project-1',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '3.0.0-rc.0',
|
||||
},
|
||||
},
|
||||
'project-2': {
|
||||
name: 'project-2',
|
||||
dependencies: {
|
||||
'@pnpm.e2e/has-prerelease': '2.0.0',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const lockfile2 = await readYamlFile('pnpm-lock.yaml')
|
||||
expect(lockfile2).not.toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@1.0.0'])
|
||||
expect(lockfile2).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@2.0.0'])
|
||||
expect(lockfile2).toHaveProperty(['packages', '/@pnpm.e2e/has-prerelease@3.0.0-rc.0'])
|
||||
})
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"@pnpm/lockfile-types": "workspace:*",
|
||||
"@pnpm/plugin-commands-deploy": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1"
|
||||
"@pnpm/registry-mock": "3.18.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pnpm/cli-utils": "workspace:*",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@pnpm/filter-workspace-packages": "workspace:*",
|
||||
"@pnpm/plugin-commands-publishing": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-ipc-server": "workspace:*",
|
||||
"@types/cross-spawn": "^6.0.5",
|
||||
"@types/is-windows": "^1.0.2",
|
||||
|
||||
@@ -114,6 +114,7 @@ export type ResolveFromNpmOptions = {
|
||||
registry: string
|
||||
preferredVersions?: PreferredVersions
|
||||
preferWorkspacePackages?: boolean
|
||||
updateToLatest?: boolean
|
||||
} & ({
|
||||
projectDir?: string
|
||||
workspacePackages?: undefined
|
||||
@@ -160,6 +161,7 @@ async function resolveNpm (
|
||||
dryRun: opts.dryRun === true,
|
||||
preferredVersionSelectors: opts.preferredVersions?.[spec.name],
|
||||
registry: opts.registry,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
})
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if ((workspacePackages != null) && opts.projectDir) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import loadJsonFile from 'load-json-file'
|
||||
import pLimit from 'p-limit'
|
||||
import { fastPathTemp as pathTemp } from 'path-temp'
|
||||
import pick from 'ramda/src/pick'
|
||||
import semver from 'semver'
|
||||
import renameOverwrite from 'rename-overwrite'
|
||||
import { toRaw } from './toRaw'
|
||||
import { pickPackageFromMeta, pickVersionByVersionRange, pickLowestVersionByVersionRange } from './pickPackageFromMeta'
|
||||
@@ -85,6 +86,7 @@ export interface PickPackageOptions {
|
||||
pickLowestVersion?: boolean
|
||||
registry: string
|
||||
dryRun: boolean
|
||||
updateToLatest?: boolean
|
||||
}
|
||||
|
||||
function pickPackageFromMetaUsingTime (
|
||||
@@ -112,11 +114,25 @@ export async function pickPackage (
|
||||
opts: PickPackageOptions
|
||||
): Promise<{ meta: PackageMeta, pickedPackage: PackageInRegistry | null }> {
|
||||
opts = opts || {}
|
||||
const _pickPackageFromMeta =
|
||||
let _pickPackageFromMeta =
|
||||
opts.publishedBy
|
||||
? pickPackageFromMetaUsingTime
|
||||
: (pickPackageFromMeta.bind(null, opts.pickLowestVersion ? pickLowestVersionByVersionRange : pickVersionByVersionRange))
|
||||
|
||||
if (opts.updateToLatest) {
|
||||
const _pickPackageBase = _pickPackageFromMeta
|
||||
_pickPackageFromMeta = (spec, ...rest) => {
|
||||
const latestStableSpec: RegistryPackageSpec = { ...spec, type: 'tag', fetchSpec: 'latest' }
|
||||
const latestStable = _pickPackageBase(latestStableSpec, ...rest)
|
||||
const current = _pickPackageBase(spec, ...rest)
|
||||
|
||||
if (!latestStable) return current
|
||||
if (!current) return latestStable
|
||||
if (semver.lt(latestStable.version, current.version)) return current
|
||||
return latestStable
|
||||
}
|
||||
}
|
||||
|
||||
validatePackageName(spec.name)
|
||||
|
||||
const cachedMeta = ctx.metaCache.get(spec.name)
|
||||
@@ -155,7 +171,7 @@ export async function pickPackage (
|
||||
}
|
||||
}
|
||||
|
||||
if (spec.type === 'version') {
|
||||
if (!opts.updateToLatest && spec.type === 'version') {
|
||||
metaCachedInStore = metaCachedInStore ?? await limit(async () => loadMeta(pkgMirror))
|
||||
// use the cached meta only if it has the required package version
|
||||
// otherwise it is probably out of date
|
||||
|
||||
@@ -80,6 +80,7 @@ export interface ResolveOptions {
|
||||
preferWorkspacePackages?: boolean
|
||||
registry: string
|
||||
workspacePackages?: WorkspacePackages
|
||||
updateToLatest?: boolean
|
||||
}
|
||||
|
||||
export type WantedDependency = {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"@pnpm/plugin-commands-licenses": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/read-package-json": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@types/ramda": "0.28.20",
|
||||
"@types/semver": "7.5.3",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@pnpm/plugin-commands-installation": "workspace:*",
|
||||
"@pnpm/plugin-commands-listing": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@types/ramda": "0.28.20",
|
||||
"execa": "npm:safe-execa@0.1.2",
|
||||
"strip-ansi": "^6.0.1",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@pnpm/plugin-commands-installation": "workspace:*",
|
||||
"@pnpm/plugin-commands-outdated": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@types/ramda": "0.28.20",
|
||||
"@types/wrap-ansi": "8.0.2",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@pnpm/lockfile-file": "workspace:*",
|
||||
"@pnpm/plugin-commands-store": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.17.1",
|
||||
"@pnpm/registry-mock": "3.18.0",
|
||||
"@types/archy": "0.0.33",
|
||||
"@types/ramda": "0.28.20",
|
||||
"@types/ssri": "^7.1.4",
|
||||
|
||||
@@ -134,6 +134,7 @@ export interface RequestPackageOptions {
|
||||
forceResolve?: boolean
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
onFetchError?: OnFetchError
|
||||
updateToLatest?: boolean
|
||||
}
|
||||
|
||||
export type BundledManifestFunction = () => Promise<BundledManifest | undefined>
|
||||
|
||||
Reference in New Issue
Block a user