mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-26 00:28:10 -05:00
feat(interactive-update): group dependancies by type, add package url column (#6978)
* feat(interactive-update): group dependancies by type, add package url column Partially resolves https://github.com/pnpm/pnpm/issues/6314 * refactor: update * docs: update changeset --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
6
.changeset/young-dryers-smash.md
Normal file
6
.changeset/young-dryers-smash.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": minor
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Improve the `pnpm update --interactive` output. Dependencies are grouped by dependency types and a new column is added with links to the outdated package's docs [#6978](https://github.com/pnpm/pnpm/pull/6978).
|
||||
@@ -2,80 +2,120 @@ import colorizeSemverDiff from '@pnpm/colorize-semver-diff'
|
||||
import { type OutdatedPackage } from '@pnpm/outdated'
|
||||
import semverDiff from '@pnpm/semver-diff'
|
||||
import { getBorderCharacters, table } from '@zkochan/table'
|
||||
import { pipe, groupBy, pluck, uniqBy, pickBy, and } from 'ramda'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
import unnest from 'ramda/src/unnest'
|
||||
|
||||
export function getUpdateChoices (outdatedPkgsOfProjects: OutdatedPackage[]) {
|
||||
const allOutdatedPkgs = mergeOutdatedPkgs(outdatedPkgsOfProjects)
|
||||
if (isEmpty(allOutdatedPkgs)) {
|
||||
export interface ChoiceRow {
|
||||
name: string
|
||||
value: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
type ChoiceGroup = Array<{
|
||||
name: string
|
||||
choices: ChoiceRow[]
|
||||
}>
|
||||
|
||||
export function getUpdateChoices (outdatedPkgsOfProjects: OutdatedPackage[], workspacesEnabled: boolean) {
|
||||
if (isEmpty(outdatedPkgsOfProjects)) {
|
||||
return []
|
||||
}
|
||||
const rowsGroupedByPkgs = Object.entries(allOutdatedPkgs)
|
||||
.sort(([pkgName1], [pkgName2]) => pkgName1.localeCompare(pkgName2))
|
||||
.map(([pkgName, outdatedPkgs]) => ({
|
||||
pkgName,
|
||||
rows: outdatedPkgsRows(Object.values(outdatedPkgs)),
|
||||
}))
|
||||
const renderedTable = alignColumns(
|
||||
unnest(rowsGroupedByPkgs.map(({ rows }) => rows))
|
||||
|
||||
const pkgUniqueKey = (outdatedPkg: OutdatedPackage) => {
|
||||
return JSON.stringify([outdatedPkg.packageName, outdatedPkg.latestManifest?.version, outdatedPkg.current])
|
||||
}
|
||||
|
||||
const dedupeAndGroupPkgs = pipe(
|
||||
uniqBy((outdatedPkg: OutdatedPackage) => pkgUniqueKey(outdatedPkg)),
|
||||
groupBy((outdatedPkg: OutdatedPackage) => outdatedPkg.belongsTo)
|
||||
)
|
||||
|
||||
const choices = []
|
||||
let i = 0
|
||||
for (const { pkgName, rows } of rowsGroupedByPkgs) {
|
||||
choices.push({
|
||||
message: renderedTable
|
||||
.slice(i, i + rows.length)
|
||||
.join('\n '),
|
||||
name: pkgName,
|
||||
})
|
||||
i += rows.length
|
||||
const groupPkgsByType = dedupeAndGroupPkgs(outdatedPkgsOfProjects)
|
||||
|
||||
const headerRow = {
|
||||
Package: true,
|
||||
Current: true,
|
||||
' ': true,
|
||||
Target: true,
|
||||
Workspace: workspacesEnabled,
|
||||
URL: true,
|
||||
}
|
||||
return choices
|
||||
// returns only the keys that are true
|
||||
const header: string[] = Object.keys(pickBy(and, headerRow))
|
||||
|
||||
return Object.entries(groupPkgsByType).reduce((finalChoices: ChoiceGroup, [depGroup, choiceRows]) => {
|
||||
if (choiceRows.length === 0) {
|
||||
return finalChoices
|
||||
}
|
||||
|
||||
const rawChoices = choiceRows.map(choice => buildPkgChoice(choice, workspacesEnabled))
|
||||
// add in a header row for each group
|
||||
rawChoices.unshift({
|
||||
raw: header,
|
||||
name: '',
|
||||
disabled: true,
|
||||
})
|
||||
const renderedTable = alignColumns(pluck('raw', rawChoices)).filter(Boolean)
|
||||
|
||||
const choices = rawChoices.map((outdatedPkg, i) => {
|
||||
if (i === 0) {
|
||||
return {
|
||||
name: renderedTable[i],
|
||||
value: '',
|
||||
disabled: true,
|
||||
hint: '',
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: renderedTable[i],
|
||||
value: outdatedPkg.name,
|
||||
}
|
||||
})
|
||||
|
||||
finalChoices.push({ name: depGroup, choices })
|
||||
|
||||
return finalChoices
|
||||
}, [])
|
||||
}
|
||||
|
||||
function mergeOutdatedPkgs (outdatedPkgs: OutdatedPackage[]) {
|
||||
const allOutdatedPkgs: Record<string, Record<string, OutdatedPackage>> = {}
|
||||
for (const outdatedPkg of outdatedPkgs) {
|
||||
if (!allOutdatedPkgs[outdatedPkg.packageName]) {
|
||||
allOutdatedPkgs[outdatedPkg.packageName] = {}
|
||||
}
|
||||
const key = JSON.stringify([
|
||||
outdatedPkg.latestManifest?.version,
|
||||
outdatedPkg.current,
|
||||
])
|
||||
if (!allOutdatedPkgs[outdatedPkg.packageName][key]) {
|
||||
allOutdatedPkgs[outdatedPkg.packageName][key] = outdatedPkg
|
||||
continue
|
||||
}
|
||||
if (allOutdatedPkgs[outdatedPkg.packageName][key].belongsTo === 'dependencies') continue
|
||||
if (outdatedPkg.belongsTo !== 'devDependencies') {
|
||||
allOutdatedPkgs[outdatedPkg.packageName][key].belongsTo = outdatedPkg.belongsTo
|
||||
}
|
||||
function buildPkgChoice (outdatedPkg: OutdatedPackage, workspacesEnabled: boolean): { raw: string[], name: string, disabled?: boolean } {
|
||||
const sdiff = semverDiff(outdatedPkg.wanted, outdatedPkg.latestManifest!.version)
|
||||
const nextVersion = sdiff.change === null
|
||||
? outdatedPkg.latestManifest!.version
|
||||
: colorizeSemverDiff(sdiff as any) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
const label = outdatedPkg.packageName
|
||||
|
||||
const lineParts = {
|
||||
label,
|
||||
current: outdatedPkg.current,
|
||||
arrow: '❯',
|
||||
nextVersion,
|
||||
workspace: outdatedPkg.workspace,
|
||||
url: getPkgUrl(outdatedPkg),
|
||||
}
|
||||
|
||||
if (!workspacesEnabled) {
|
||||
delete lineParts.workspace
|
||||
}
|
||||
|
||||
return {
|
||||
raw: Object.values(lineParts),
|
||||
name: outdatedPkg.packageName,
|
||||
}
|
||||
return allOutdatedPkgs
|
||||
}
|
||||
|
||||
function outdatedPkgsRows (outdatedPkgs: OutdatedPackage[]) {
|
||||
return outdatedPkgs
|
||||
.map((outdatedPkg) => {
|
||||
const sdiff = semverDiff(outdatedPkg.wanted, outdatedPkg.latestManifest!.version)
|
||||
const nextVersion = sdiff.change === null
|
||||
? outdatedPkg.latestManifest!.version
|
||||
: colorizeSemverDiff(sdiff as any) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
let label = outdatedPkg.packageName
|
||||
switch (outdatedPkg.belongsTo) {
|
||||
case 'devDependencies': {
|
||||
label += ' (dev)'
|
||||
break
|
||||
}
|
||||
case 'optionalDependencies': {
|
||||
label += ' (optional)'
|
||||
break
|
||||
}
|
||||
}
|
||||
return [label, outdatedPkg.current, '❯', nextVersion]
|
||||
})
|
||||
function getPkgUrl (pkg: OutdatedPackage) {
|
||||
if (pkg.latestManifest?.homepage) {
|
||||
return pkg.latestManifest?.homepage
|
||||
}
|
||||
|
||||
if (typeof pkg.latestManifest?.repository !== 'string') {
|
||||
if (pkg.latestManifest?.repository?.url) {
|
||||
return pkg.latestManifest?.repository?.url
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
function alignColumns (rows: string[][]) {
|
||||
@@ -86,10 +126,16 @@ function alignColumns (rows: string[][]) {
|
||||
columnDefault: {
|
||||
paddingLeft: 0,
|
||||
paddingRight: 1,
|
||||
wrapWord: true,
|
||||
},
|
||||
columns: {
|
||||
1: { alignment: 'right' },
|
||||
},
|
||||
columns:
|
||||
{
|
||||
0: { width: 50, truncate: 100 },
|
||||
1: { width: 15, alignment: 'right' },
|
||||
3: { width: 15 },
|
||||
4: { paddingLeft: 2 },
|
||||
5: { paddingLeft: 2 },
|
||||
},
|
||||
drawHorizontalLine: () => false,
|
||||
}
|
||||
).split('\n')
|
||||
|
||||
@@ -12,12 +12,12 @@ import { outdatedDepsOfProjects } from '@pnpm/outdated'
|
||||
import { prompt } from 'enquirer'
|
||||
import chalk from 'chalk'
|
||||
import pick from 'ramda/src/pick'
|
||||
import pluck from 'ramda/src/pluck'
|
||||
import unnest from 'ramda/src/unnest'
|
||||
import renderHelp from 'render-help'
|
||||
import { type InstallCommandOptions } from '../install'
|
||||
import { installDeps } from '../installDeps'
|
||||
import { getUpdateChoices } from './getUpdateChoices'
|
||||
|
||||
import { type ChoiceRow, getUpdateChoices } from './getUpdateChoices'
|
||||
export function rcOptionsTypes () {
|
||||
return pick([
|
||||
'cache-dir',
|
||||
@@ -202,7 +202,8 @@ async function interactiveUpdate (
|
||||
},
|
||||
timeout: opts.fetchTimeout,
|
||||
})
|
||||
const choices = getUpdateChoices(unnest(outdatedPkgsOfProjects))
|
||||
const workspacesEnabled = !!opts.workspaceDir
|
||||
const choices = getUpdateChoices(unnest(outdatedPkgsOfProjects), workspacesEnabled)
|
||||
if (choices.length === 0) {
|
||||
if (opts.latest) {
|
||||
return 'All of your dependencies are already up to date'
|
||||
@@ -221,6 +222,9 @@ async function interactiveUpdate (
|
||||
`${chalk.cyan('<i>')} to invert selection)`,
|
||||
name: 'updateDependencies',
|
||||
pointer: '❯',
|
||||
result () {
|
||||
return this.selected
|
||||
},
|
||||
styles: {
|
||||
dark: chalk.white,
|
||||
em: chalk.bgBlack.whiteBright,
|
||||
@@ -247,9 +251,12 @@ async function interactiveUpdate (
|
||||
// Otherwise, pnpm CLI would print an error and confuse users.
|
||||
// See related issue: https://github.com/enquirer/enquirer/issues/225
|
||||
globalInfo('Update canceled')
|
||||
process.exit(0)
|
||||
},
|
||||
} as any) as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
return update(updateDependencies, opts)
|
||||
|
||||
const updatePkgNames = pluck('value', updateDependencies as ChoiceRow[])
|
||||
return update(updatePkgNames, opts)
|
||||
}
|
||||
|
||||
async function update (
|
||||
|
||||
@@ -11,6 +11,7 @@ test('getUpdateChoices()', () => {
|
||||
latestManifest: {
|
||||
name: 'foo',
|
||||
version: '2.0.0',
|
||||
homepage: 'https://pnpm.io/',
|
||||
},
|
||||
packageName: 'foo',
|
||||
wanted: '1.0.0',
|
||||
@@ -22,6 +23,9 @@ test('getUpdateChoices()', () => {
|
||||
latestManifest: {
|
||||
name: 'foo',
|
||||
version: '2.0.0',
|
||||
repository: {
|
||||
url: 'git://github.com/pnpm/pnpm.git',
|
||||
},
|
||||
},
|
||||
packageName: 'foo',
|
||||
wanted: '1.0.0',
|
||||
@@ -70,23 +74,60 @@ test('getUpdateChoices()', () => {
|
||||
packageName: 'foo',
|
||||
wanted: '1.0.1',
|
||||
},
|
||||
]))
|
||||
], false))
|
||||
.toStrictEqual([
|
||||
{
|
||||
message: chalk`foo 1.0.0 ❯ {redBright.bold 2.0.0} \n foo (dev) 1.0.1 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
name: 'foo',
|
||||
name: 'dependencies',
|
||||
choices: [
|
||||
{
|
||||
name: 'Package Current Target URL ',
|
||||
disabled: true,
|
||||
hint: '',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: chalk`foo 1.0.0 ❯ {redBright.bold 2.0.0} https://pnpm.io/ `,
|
||||
value: 'foo',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
message: chalk`qar (dev) 1.0.0 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
name: 'qar',
|
||||
name: 'devDependencies',
|
||||
choices: [
|
||||
{
|
||||
name: 'Package Current Target URL ',
|
||||
disabled: true,
|
||||
hint: '',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: chalk`qar 1.0.0 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
value: 'qar',
|
||||
},
|
||||
{
|
||||
name: chalk`zoo 1.1.0 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
value: 'zoo',
|
||||
},
|
||||
{
|
||||
name: chalk`foo 1.0.1 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
value: 'foo',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
message: chalk`qaz (optional) 1.0.1 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
name: 'qaz',
|
||||
},
|
||||
{
|
||||
message: chalk`zoo (dev) 1.1.0 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
name: 'zoo',
|
||||
name: 'optionalDependencies',
|
||||
choices: [
|
||||
{
|
||||
name: 'Package Current Target URL ',
|
||||
disabled: true,
|
||||
hint: '',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: chalk`qaz 1.0.1 ❯ 1.{yellowBright.bold 2.0} `,
|
||||
value: 'qaz',
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import path from 'path'
|
||||
import { readProjects } from '@pnpm/filter-workspace-packages'
|
||||
import { type Lockfile } from '@pnpm/lockfile-types'
|
||||
import { add, install, update } from '@pnpm/plugin-commands-installation'
|
||||
import { prepare, preparePackages } from '@pnpm/prepare'
|
||||
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
import readYamlFile from 'read-yaml-file'
|
||||
import chalk from 'chalk'
|
||||
import * as enquirer from 'enquirer'
|
||||
|
||||
jest.mock('enquirer', () => ({ prompt: jest.fn() }))
|
||||
|
||||
// eslint-disable-next-line
|
||||
import * as enquirer from 'enquirer'
|
||||
|
||||
// eslint-disable-next-line
|
||||
const prompt = enquirer.prompt as any
|
||||
|
||||
// eslint-disable-next-line
|
||||
import { add, install, update } from '@pnpm/plugin-commands-installation'
|
||||
|
||||
const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}`
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
@@ -59,21 +55,33 @@ test('interactively update', async () => {
|
||||
})
|
||||
|
||||
const storeDir = path.resolve('pnpm-store')
|
||||
await add.handler({
|
||||
...DEFAULT_OPTIONS,
|
||||
cacheDir: path.resolve('cache'),
|
||||
dir: process.cwd(),
|
||||
linkWorkspacePackages: true,
|
||||
save: false,
|
||||
storeDir,
|
||||
}, [
|
||||
'is-negative@1.0.0',
|
||||
'is-positive@2.0.0',
|
||||
'micromatch@3.0.0',
|
||||
])
|
||||
|
||||
const headerChoice = {
|
||||
name: 'Package Current Target URL ',
|
||||
disabled: true,
|
||||
hint: '',
|
||||
value: '',
|
||||
}
|
||||
|
||||
await add.handler(
|
||||
{
|
||||
...DEFAULT_OPTIONS,
|
||||
cacheDir: path.resolve('cache'),
|
||||
dir: process.cwd(),
|
||||
linkWorkspacePackages: true,
|
||||
save: false,
|
||||
storeDir,
|
||||
},
|
||||
['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0']
|
||||
)
|
||||
|
||||
prompt.mockResolvedValue({
|
||||
updateDependencies: ['is-negative'],
|
||||
updateDependencies: [
|
||||
{
|
||||
value: 'is-negative',
|
||||
name: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} https://pnpm.io/ `,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
prompt.mockClear()
|
||||
@@ -89,23 +97,32 @@ test('interactively update', async () => {
|
||||
|
||||
expect(prompt.mock.calls[0][0].choices).toStrictEqual([
|
||||
{
|
||||
message: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} `,
|
||||
name: 'is-negative',
|
||||
},
|
||||
{
|
||||
message: chalk`micromatch 3.0.0 ❯ 3.{yellowBright.bold 1.10} `,
|
||||
name: 'micromatch',
|
||||
choices: [
|
||||
headerChoice,
|
||||
{
|
||||
name: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} `,
|
||||
value: 'is-negative',
|
||||
},
|
||||
{
|
||||
name: chalk`micromatch 3.0.0 ❯ 3.{yellowBright.bold 1.10} `,
|
||||
value: 'micromatch',
|
||||
},
|
||||
],
|
||||
name: 'dependencies',
|
||||
},
|
||||
])
|
||||
expect(prompt).toBeCalledWith(expect.objectContaining({
|
||||
footer: '\nEnter to start updating. Ctrl-c to cancel.',
|
||||
message: 'Choose which packages to update ' +
|
||||
expect(prompt).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
footer: '\nEnter to start updating. Ctrl-c to cancel.',
|
||||
message:
|
||||
'Choose which packages to update ' +
|
||||
`(Press ${chalk.cyan('<space>')} to select, ` +
|
||||
`${chalk.cyan('<a>')} to toggle all, ` +
|
||||
`${chalk.cyan('<i>')} to invert selection)`,
|
||||
name: 'updateDependencies',
|
||||
type: 'multiselect',
|
||||
}))
|
||||
name: 'updateDependencies',
|
||||
type: 'multiselect',
|
||||
})
|
||||
)
|
||||
|
||||
{
|
||||
const lockfile = await project.readLockfile()
|
||||
@@ -129,27 +146,36 @@ test('interactively update', async () => {
|
||||
|
||||
expect(prompt.mock.calls[0][0].choices).toStrictEqual([
|
||||
{
|
||||
message: chalk`is-negative 1.0.1 ❯ {redBright.bold 2.1.0} `,
|
||||
name: 'is-negative',
|
||||
},
|
||||
{
|
||||
message: chalk`is-positive 2.0.0 ❯ {redBright.bold 3.1.0} `,
|
||||
name: 'is-positive',
|
||||
},
|
||||
{
|
||||
message: chalk`micromatch 3.0.0 ❯ {redBright.bold 4.0.5} `,
|
||||
name: 'micromatch',
|
||||
choices: [
|
||||
headerChoice,
|
||||
{
|
||||
name: chalk`is-negative 1.0.1 ❯ {redBright.bold 2.1.0} `,
|
||||
value: 'is-negative',
|
||||
},
|
||||
{
|
||||
name: chalk`is-positive 2.0.0 ❯ {redBright.bold 3.1.0} `,
|
||||
value: 'is-positive',
|
||||
},
|
||||
{
|
||||
name: chalk`micromatch 3.0.0 ❯ {redBright.bold 4.0.5} `,
|
||||
value: 'micromatch',
|
||||
},
|
||||
],
|
||||
name: 'dependencies',
|
||||
},
|
||||
])
|
||||
expect(prompt).toBeCalledWith(expect.objectContaining({
|
||||
footer: '\nEnter to start updating. Ctrl-c to cancel.',
|
||||
message: 'Choose which packages to update ' +
|
||||
expect(prompt).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
footer: '\nEnter to start updating. Ctrl-c to cancel.',
|
||||
message:
|
||||
'Choose which packages to update ' +
|
||||
`(Press ${chalk.cyan('<space>')} to select, ` +
|
||||
`${chalk.cyan('<a>')} to toggle all, ` +
|
||||
`${chalk.cyan('<i>')} to invert selection)`,
|
||||
name: 'updateDependencies',
|
||||
type: 'multiselect',
|
||||
}))
|
||||
name: 'updateDependencies',
|
||||
type: 'multiselect',
|
||||
})
|
||||
)
|
||||
|
||||
{
|
||||
const lockfile = await project.readLockfile()
|
||||
@@ -180,10 +206,18 @@ test('interactive update of dev dependencies only', async () => {
|
||||
const storeDir = path.resolve('store')
|
||||
|
||||
prompt.mockResolvedValue({
|
||||
updateDependencies: ['is-negative'],
|
||||
updateDependencies: [
|
||||
{
|
||||
value: 'is-negative',
|
||||
name: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} https://pnpm.io/ `,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const { allProjects, selectedProjectsGraph } = await readProjects(process.cwd(), [])
|
||||
const { allProjects, selectedProjectsGraph } = await readProjects(
|
||||
process.cwd(),
|
||||
[]
|
||||
)
|
||||
await install.handler({
|
||||
...DEFAULT_OPTIONS,
|
||||
cacheDir: path.resolve('cache'),
|
||||
@@ -218,11 +252,10 @@ test('interactive update of dev dependencies only', async () => {
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>('pnpm-lock.yaml')
|
||||
|
||||
expect(
|
||||
Object.keys(lockfile.packages ?? {})
|
||||
).toStrictEqual(
|
||||
['/is-negative@1.0.1', '/is-negative@2.1.0']
|
||||
)
|
||||
expect(Object.keys(lockfile.packages ?? {})).toStrictEqual([
|
||||
'/is-negative@1.0.1',
|
||||
'/is-negative@2.1.0',
|
||||
])
|
||||
})
|
||||
|
||||
test('interactively update should ignore dependencies from the ignoreDependencies field', async () => {
|
||||
@@ -243,21 +276,21 @@ test('interactively update should ignore dependencies from the ignoreDependencie
|
||||
})
|
||||
|
||||
const storeDir = path.resolve('pnpm-store')
|
||||
await add.handler({
|
||||
...DEFAULT_OPTIONS,
|
||||
cacheDir: path.resolve('cache'),
|
||||
dir: process.cwd(),
|
||||
linkWorkspacePackages: true,
|
||||
save: false,
|
||||
storeDir,
|
||||
}, [
|
||||
'is-negative@1.0.0',
|
||||
'is-positive@2.0.0',
|
||||
'micromatch@3.0.0',
|
||||
])
|
||||
|
||||
await add.handler(
|
||||
{
|
||||
...DEFAULT_OPTIONS,
|
||||
cacheDir: path.resolve('cache'),
|
||||
dir: process.cwd(),
|
||||
linkWorkspacePackages: true,
|
||||
save: false,
|
||||
storeDir,
|
||||
},
|
||||
['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0']
|
||||
)
|
||||
|
||||
prompt.mockResolvedValue({
|
||||
updateDependencies: ['micromatch'],
|
||||
updateDependencies: [{ value: 'micromatch', name: 'anything' }],
|
||||
})
|
||||
|
||||
prompt.mockClear()
|
||||
@@ -270,21 +303,38 @@ test('interactively update should ignore dependencies from the ignoreDependencie
|
||||
storeDir,
|
||||
})
|
||||
|
||||
expect(prompt.mock.calls[0][0].choices).toStrictEqual([
|
||||
{
|
||||
message: chalk`micromatch 3.0.0 ❯ 3.{yellowBright.bold 1.10} `,
|
||||
name: 'micromatch',
|
||||
},
|
||||
])
|
||||
expect(prompt).toBeCalledWith(expect.objectContaining({
|
||||
footer: '\nEnter to start updating. Ctrl-c to cancel.',
|
||||
message: 'Choose which packages to update ' +
|
||||
expect(prompt.mock.calls[0][0].choices).toStrictEqual(
|
||||
[
|
||||
{
|
||||
choices: [
|
||||
{
|
||||
disabled: true,
|
||||
hint: '',
|
||||
name: 'Package Current Target URL ',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: chalk`micromatch 3.0.0 ❯ 3.{yellowBright.bold 1.10} `,
|
||||
value: 'micromatch',
|
||||
},
|
||||
],
|
||||
name: 'dependencies',
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
expect(prompt).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
footer: '\nEnter to start updating. Ctrl-c to cancel.',
|
||||
message:
|
||||
'Choose which packages to update ' +
|
||||
`(Press ${chalk.cyan('<space>')} to select, ` +
|
||||
`${chalk.cyan('<a>')} to toggle all, ` +
|
||||
`${chalk.cyan('<i>')} to invert selection)`,
|
||||
name: 'updateDependencies',
|
||||
type: 'multiselect',
|
||||
}))
|
||||
name: 'updateDependencies',
|
||||
type: 'multiselect',
|
||||
})
|
||||
)
|
||||
|
||||
{
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
@@ -32,6 +32,7 @@ export interface OutdatedPackage {
|
||||
latestManifest?: PackageManifest
|
||||
packageName: string
|
||||
wanted: string
|
||||
workspace?: string
|
||||
}
|
||||
|
||||
export async function outdated (
|
||||
@@ -118,6 +119,7 @@ export async function outdated (
|
||||
latestManifest: undefined,
|
||||
packageName,
|
||||
wanted,
|
||||
workspace: opts.manifest.name,
|
||||
})
|
||||
}
|
||||
return
|
||||
@@ -137,6 +139,8 @@ export async function outdated (
|
||||
latestManifest,
|
||||
packageName,
|
||||
wanted,
|
||||
workspace: opts.manifest.name,
|
||||
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -149,6 +153,8 @@ export async function outdated (
|
||||
latestManifest,
|
||||
packageName,
|
||||
wanted,
|
||||
workspace: opts.manifest.name,
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -150,6 +150,7 @@ test('outdated()', async () => {
|
||||
latestManifest: undefined,
|
||||
packageName: 'from-github',
|
||||
wanted: 'github.com/blabla/from-github/d5f8d5500f7faf593d32e134c1b0043ff69151b3',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
{
|
||||
alias: 'from-github-2',
|
||||
@@ -158,6 +159,7 @@ test('outdated()', async () => {
|
||||
latestManifest: undefined,
|
||||
packageName: 'from-github-2',
|
||||
wanted: 'github.com/blabla/from-github-2/d5f8d5500f7faf593d32e134c1b0043ff69151b3',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
{
|
||||
alias: 'is-negative',
|
||||
@@ -169,6 +171,7 @@ test('outdated()', async () => {
|
||||
},
|
||||
packageName: 'is-negative',
|
||||
wanted: '1.1.0',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
{
|
||||
alias: 'is-positive',
|
||||
@@ -180,6 +183,7 @@ test('outdated()', async () => {
|
||||
},
|
||||
packageName: 'is-positive',
|
||||
wanted: '3.1.0',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
])
|
||||
})
|
||||
@@ -236,6 +240,7 @@ test('outdated() should return deprecated package even if its current version is
|
||||
},
|
||||
packageName: 'deprecated-pkg',
|
||||
wanted: '1.0.0',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
])
|
||||
})
|
||||
@@ -355,6 +360,7 @@ test('using a matcher', async () => {
|
||||
},
|
||||
packageName: 'is-negative',
|
||||
wanted: '1.1.0',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
])
|
||||
})
|
||||
@@ -427,6 +433,7 @@ test('outdated() aliased dependency', async () => {
|
||||
},
|
||||
packageName: 'is-positive',
|
||||
wanted: '3.1.0',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
])
|
||||
})
|
||||
@@ -666,6 +673,7 @@ test('should ignore dependencies as expected', async () => {
|
||||
},
|
||||
packageName: 'is-positive',
|
||||
wanted: '3.1.0',
|
||||
workspace: 'wanted-shrinkwrap',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user