mirror of
https://github.com/pnpm/pnpm.git
synced 2026-03-24 10:01:48 -04:00
feat: filtering packages in recursive commands (#1219)
* feat: filtering packages in recursive commands close #1213 * test: recursive --scope ignore excluded packages * test: recursive list --scope PR #1219
This commit is contained in:
@@ -35,6 +35,7 @@ export const types = Object.assign(npmTypes.types, {
|
||||
'production': [null, true],
|
||||
'protocol': ['auto', 'tcp', 'ipc'],
|
||||
'reporter': String,
|
||||
'scope': String,
|
||||
'shamefully-flatten': Boolean,
|
||||
'shrinkwrap-only': Boolean,
|
||||
'side-effects-cache': Boolean,
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"@types/camelcase-keys": "^4.0.0",
|
||||
"@types/get-port": "^3.2.0",
|
||||
"@types/lru-cache": "^4.1.1",
|
||||
"@types/minimatch": "^3.0.3",
|
||||
"@types/mz": "^0.0.32",
|
||||
"@zkochan/libnpx": "^9.6.1",
|
||||
"camelcase": "^4.1.0 || 5",
|
||||
@@ -52,6 +53,7 @@
|
||||
"load-yaml-file": "^0.1.0",
|
||||
"loud-rejection": "^1.6.0",
|
||||
"lru-cache": "^4.1.3",
|
||||
"minimatch": "^3.0.4",
|
||||
"mkdirp-promise": "^5.0.1",
|
||||
"mz": "^2.7.0",
|
||||
"nopt": "^4.0.1",
|
||||
|
||||
@@ -12,6 +12,7 @@ dependencies:
|
||||
'@types/camelcase-keys': 4.0.0
|
||||
'@types/get-port': 3.2.0
|
||||
'@types/lru-cache': 4.1.1
|
||||
'@types/minimatch': 3.0.3
|
||||
'@types/mz': 0.0.32
|
||||
'@zkochan/libnpx': 9.6.1
|
||||
camelcase: 5.0.0
|
||||
@@ -31,6 +32,7 @@ dependencies:
|
||||
load-yaml-file: 0.1.0
|
||||
loud-rejection: 1.6.0
|
||||
lru-cache: 4.1.3
|
||||
minimatch: 3.0.4
|
||||
mkdirp-promise: 5.0.1
|
||||
mz: 2.7.0
|
||||
nopt: 4.0.1
|
||||
@@ -6457,6 +6459,7 @@ specifiers:
|
||||
'@types/get-port': ^3.2.0
|
||||
'@types/load-json-file': ^2.0.6
|
||||
'@types/lru-cache': ^4.1.1
|
||||
'@types/minimatch': ^3.0.3
|
||||
'@types/mkdirp': ^0.5.0
|
||||
'@types/mz': ^0.0.32
|
||||
'@types/node': ^10.0.6
|
||||
@@ -6492,6 +6495,7 @@ specifiers:
|
||||
load-yaml-file: ^0.1.0
|
||||
loud-rejection: ^1.6.0
|
||||
lru-cache: ^4.1.3
|
||||
minimatch: ^3.0.4
|
||||
mkdirp: ^0.5.1
|
||||
mkdirp-promise: ^5.0.1
|
||||
mz: ^2.7.0
|
||||
|
||||
@@ -304,6 +304,10 @@ function getHelpText (command: string) {
|
||||
|
||||
This command runs the "npm build" command on each package.
|
||||
This is useful when you install a new version of node, and must recompile all your C++ addons with the new binary.
|
||||
|
||||
Options:
|
||||
|
||||
--scope restricts the scope to package names matching the given glob.
|
||||
`
|
||||
|
||||
default:
|
||||
|
||||
@@ -3,10 +3,12 @@ import camelcaseKeys = require('camelcase-keys')
|
||||
import findPackages from 'find-packages'
|
||||
import graphSequencer = require('graph-sequencer')
|
||||
import loadYamlFile = require('load-yaml-file')
|
||||
import minimatch = require('minimatch')
|
||||
import pLimit = require('p-limit')
|
||||
import { StoreController } from 'package-store'
|
||||
import path = require('path')
|
||||
import createPkgGraph, {PackageNode} from 'pkgs-graph'
|
||||
import R = require('ramda')
|
||||
import readIniFile = require('read-ini-file')
|
||||
import sortPkgs = require('sort-pkgs')
|
||||
import {
|
||||
@@ -64,7 +66,7 @@ export default async (
|
||||
|
||||
const cwd = process.cwd()
|
||||
const packagesManifest = await requirePackagesManifest(cwd)
|
||||
const pkgs = await findPackages(cwd, {
|
||||
let pkgs = await findPackages(cwd, {
|
||||
ignore: [
|
||||
'**/node_modules/**',
|
||||
'**/bower_components/**',
|
||||
@@ -72,6 +74,12 @@ export default async (
|
||||
patterns: packagesManifest && packagesManifest.packages || undefined,
|
||||
})
|
||||
|
||||
const pkgGraphResult = createPkgGraph(pkgs)
|
||||
if (opts.scope) {
|
||||
pkgGraphResult.graph = filterGraph(pkgGraphResult.graph, opts.scope)
|
||||
pkgs = pkgs.filter((pkg: {path: string}) => pkgGraphResult.graph[pkg.path])
|
||||
}
|
||||
|
||||
switch (cmdFullName) {
|
||||
case 'list':
|
||||
await list(pkgs, input, cmd, opts as any) // tslint:disable-line:no-any
|
||||
@@ -88,7 +96,6 @@ export default async (
|
||||
break
|
||||
}
|
||||
|
||||
const pkgGraphResult = createPkgGraph(pkgs)
|
||||
const store = await createStoreController(opts)
|
||||
|
||||
// It is enough to save the store.json file once,
|
||||
@@ -208,3 +215,33 @@ async function requirePackagesManifest (dir: string): Promise<{packages: string[
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
interface PackageGraph {
|
||||
[id: string]: PackageNode,
|
||||
}
|
||||
|
||||
function filterGraph (
|
||||
graph: PackageGraph,
|
||||
scope: string,
|
||||
): PackageGraph {
|
||||
const root = R.keys(graph).filter((id) => graph[id].manifest.name && minimatch(graph[id].manifest.name, scope))
|
||||
if (!root.length) return {}
|
||||
|
||||
const subgraphNodeIds = new Set()
|
||||
pickSubgraph(graph, root, subgraphNodeIds)
|
||||
|
||||
return R.pick(Array.from(subgraphNodeIds), graph)
|
||||
}
|
||||
|
||||
function pickSubgraph (
|
||||
graph: PackageGraph,
|
||||
nextNodeIds: string[],
|
||||
walked: Set<string>,
|
||||
) {
|
||||
for (const nextNodeId of nextNodeIds) {
|
||||
if (!walked.has(nextNodeId)) {
|
||||
walked.add(nextNodeId)
|
||||
pickSubgraph(graph, graph[nextNodeId].dependencies, walked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface PnpmOptions {
|
||||
saveProd?: boolean,
|
||||
saveDev?: boolean,
|
||||
saveOptional?: boolean,
|
||||
scope: string,
|
||||
production?: boolean,
|
||||
development?: boolean,
|
||||
fetchRetries?: number,
|
||||
|
||||
@@ -440,6 +440,49 @@ test('recursive list', async (t: tape.Test) => {
|
||||
` + '\n\n')
|
||||
})
|
||||
|
||||
test('recursive list --scope', async (t: tape.Test) => {
|
||||
const projects = prepare(t, [
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
'project-2': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-negative': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-3',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-negative': '1.0.0',
|
||||
'is-positive': '1.0.0',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await execPnpm('recursive', 'link')
|
||||
|
||||
const result = execPnpmSync('recursive', 'list', '--scope', 'project-1')
|
||||
|
||||
t.equal(result.status, 0)
|
||||
|
||||
t.equal(result.stdout.toString(), stripIndent`
|
||||
project-1@1.0.0 ${path.resolve('project-1')}
|
||||
├── is-positive@1.0.0
|
||||
└── project-2@link:../project-2
|
||||
|
||||
project-2@1.0.0 ${path.resolve('project-2')}
|
||||
└── is-negative@1.0.0
|
||||
` + '\n\n')
|
||||
})
|
||||
|
||||
test('pnpm recursive outdated', async (t: tape.Test) => {
|
||||
const projects = prepare(t, [
|
||||
{
|
||||
@@ -771,3 +814,76 @@ test('`pnpm recursive rebuild` specific dependencies', async (t: tape.Test) => {
|
||||
t.ok(typeof generatedByPostinstall === 'function', 'generatedByPostinstall() is available')
|
||||
}
|
||||
})
|
||||
|
||||
test('recursive --scope', async (t: tape.Test) => {
|
||||
const projects = prepare(t, [
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
'project-2': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-negative': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-3',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
minimatch: '*',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await execPnpm('recursive', 'link', '--scope', 'project-1')
|
||||
|
||||
projects['project-1'].has('is-positive')
|
||||
projects['project-2'].has('is-negative')
|
||||
projects['project-3'].hasNot('minimatch')
|
||||
})
|
||||
|
||||
test('recursive --scope ignore excluded packages', async (t: tape.Test) => {
|
||||
const projects = prepare(t, [
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
'project-2': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-negative': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-3',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
minimatch: '*',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await writeYamlFile('pnpm-workspace.yaml', {
|
||||
packages: [
|
||||
'**',
|
||||
'!project-1'
|
||||
],
|
||||
})
|
||||
|
||||
await execPnpm('recursive', 'link', '--scope', 'project-1')
|
||||
|
||||
projects['project-1'].hasNot('is-positive')
|
||||
projects['project-2'].hasNot('is-negative')
|
||||
projects['project-3'].hasNot('minimatch')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user