Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(outdated): --compatible #2256

Merged
merged 3 commits into from Jan 7, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions fixtures/has-major-outdated-deps/.gitignore
@@ -0,0 +1 @@
!node_modules
1 change: 1 addition & 0 deletions fixtures/has-major-outdated-deps/.npmrc
@@ -0,0 +1 @@
shared-workspace-lockfile=false
21 changes: 21 additions & 0 deletions fixtures/has-major-outdated-deps/node_modules/.pnpm/lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions fixtures/has-major-outdated-deps/package.json
@@ -0,0 +1,10 @@
{
"name": "wanted-shrinkwrap",
"version": "1.0.0",
"dependencies": {
"is-negative": "^1.0.0"
},
"devDependencies": {
"is-positive": "2.0.0"
}
}
21 changes: 21 additions & 0 deletions fixtures/has-major-outdated-deps/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/outdated/package.json
Expand Up @@ -43,6 +43,7 @@
"@pnpm/lockfile-file": "workspace:3.0.1",
"@pnpm/lockfile-utils": "workspace:2.0.5",
"@pnpm/types": "workspace:4.0.0",
"@pnpm/utils": "workspace:0.12.2",
"dependency-path": "workspace:4.0.2",
"semver": "7.1.1"
},
Expand Down
13 changes: 10 additions & 3 deletions packages/outdated/src/index.ts
Expand Up @@ -11,10 +11,11 @@ import {
PackageManifest,
ProjectManifest,
} from '@pnpm/types'
import { getAllDependenciesFromPackage } from '@pnpm/utils'
import * as dp from 'dependency-path'
import semver = require('semver')

export type GetLatestManifestFunction = (packageName: string) => Promise<PackageManifest | null>
export type GetLatestManifestFunction = (packageName: string, rangeOrTag: string) => Promise<PackageManifest | null>

export interface OutdatedPackage {
alias: string,
Expand All @@ -27,6 +28,7 @@ export interface OutdatedPackage {

export default async function outdated (
opts: {
compatible?: boolean,
currentLockfile: Lockfile | null,
getLatestManifest: GetLatestManifestFunction,
include?: IncludedDependencies,
Expand All @@ -38,6 +40,7 @@ export default async function outdated (
},
): Promise<OutdatedPackage[]> {
if (packageHasNoDeps(opts.manifest)) return []
const allDeps = getAllDependenciesFromPackage(opts.manifest)
const importerId = getLockfileImporterId(opts.lockfileDir, opts.prefix)
const currentLockfile = opts.currentLockfile || { importers: { [importerId]: {} } }

Expand Down Expand Up @@ -82,7 +85,7 @@ export default async function outdated (
const currentRelative = currentRef && dp.refToRelative(currentRef, alias)
const current = currentRelative && dp.parse(currentRelative).version || currentRef
const wanted = dp.parse(relativeDepPath).version || ref
const packageName = nameVerFromPkgSnapshot(relativeDepPath, pkgSnapshot).name
const { name: packageName } = nameVerFromPkgSnapshot(relativeDepPath, pkgSnapshot)

// It might be not the best solution to check for pkgSnapshot.name
// TODO: add some other field to distinct packages not from the registry
Expand All @@ -100,7 +103,11 @@ export default async function outdated (
return
}

const latestManifest = await opts.getLatestManifest(dp.parse(relativeDepPath).name || packageName)
const name = dp.parse(relativeDepPath).name ?? packageName
const latestManifest = await opts.getLatestManifest(
name,
opts.compatible ? (allDeps[name] ?? 'latest') : 'latest',
)

if (!latestManifest) return

Expand Down
Expand Up @@ -26,7 +26,7 @@ export function createLatestManifestGetter (
userAgent?: string,
verifyStoreIntegrity?: boolean,
},
): (packageName: string) => Promise<DependencyManifest | null> {
): (packageName: string, pref: string) => Promise<DependencyManifest | null> {
const resolve = createResolver(Object.assign(opts, {
fullMetadata: true,
metaCache: new LRU({
Expand All @@ -45,8 +45,9 @@ export async function getLatestManifest (
registries: Registries,
},
packageName: string,
pref: string,
) {
const resolution = await resolve({ alias: packageName, pref: 'latest' }, {
const resolution = await resolve({ alias: packageName, pref }, {
lockfileDir: opts.lockfileDir,
preferredVersions: {},
projectDir: opts.dir,
Expand Down
7 changes: 7 additions & 0 deletions packages/plugin-commands-outdated/src/outdated.ts
Expand Up @@ -46,6 +46,7 @@ export function cliOptionsTypes () {
'production',
'recursive',
], allTypes),
'compatible': Boolean,
'table': Boolean,
}
}
Expand All @@ -66,6 +67,10 @@ export function help () {
title: 'Options',

list: [
{
description: 'Print only versions that satisfy the available specs in the manifests',
zkochan marked this conversation as resolved.
Show resolved Hide resolved
name: '--compatible',
},
{
description: oneLine`
By default, details about the outdated packages (such as a link to the repo) are not displayed.
Expand Down Expand Up @@ -111,6 +116,7 @@ export type OutdatedOptions = {
alwaysAuth: boolean
ca?: string
cert?: string
compatible?: boolean,
engineStrict?: boolean
fetchRetries: number
fetchRetryFactor: number
Expand Down Expand Up @@ -338,6 +344,7 @@ export async function outdatedDepsOfProjects (
return {
manifest,
outdatedPackages: await outdated({
compatible: opts.compatible,
currentLockfile,
getLatestManifest,
include: opts.include,
Expand Down
Expand Up @@ -29,7 +29,7 @@ test('getLatestManifest()', async (t) => {
resolvedVia: 'npm-registry',
}
}
t.deepEqual(await getLatestManifest(resolve, opts, 'foo'), {
t.deepEqual(await getLatestManifest(resolve, opts, 'foo', 'latest'), {
name: 'foo',
version: '1.0.0',
})
Expand All @@ -50,7 +50,7 @@ test('getLatestManifest()', async (t) => {
resolvedVia: 'npm-registry',
}
}
t.deepEqual(await getLatestManifest(resolve, opts, '@scope/foo'), {
t.deepEqual(await getLatestManifest(resolve, opts, '@scope/foo', 'latest'), {
name: 'foo',
version: '2.0.0',
})
Expand Down
18 changes: 18 additions & 0 deletions packages/plugin-commands-outdated/test/index.ts
Expand Up @@ -19,6 +19,7 @@ const fixtures = path.join(__dirname, '../../../fixtures')
const hasOutdatedDepsFixture = path.join(fixtures, 'has-outdated-deps')
const hasOutdatedDepsFixtureAndExternalLockfile = path.join(fixtures, 'has-outdated-deps-and-external-shrinkwrap', 'pkg')
const hasNotOutdatedDepsFixture = path.join(fixtures, 'has-not-outdated-deps')
const hasMajorOutdatedDepsFixture = path.join(fixtures, 'has-major-outdated-deps')

const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}`

Expand Down Expand Up @@ -266,3 +267,20 @@ test(`pnpm outdated should fail when there is no ${WANTED_LOCKFILE} file in the
t.equal(err.code, 'ERR_PNPM_OUTDATED_NO_LOCKFILE')
t.end()
})

test('pnpm outdated: print only compatible versions', async (t) => {
const output = await outdated.handler([], {
...OUTDATED_OPTIONS,
compatible: true,
dir: hasMajorOutdatedDepsFixture,
})

t.equal(stripAnsi(output), stripIndent`
┌─────────────┬─────────┬────────┐
│ Package │ Current │ Latest │
├─────────────┼─────────┼────────┤
│ is-negative │ 1.0.0 │ 1.0.1 │
└─────────────┴─────────┴────────┘
` + '\n')
t.end()
})
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.