mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-10 18:18:56 -04:00
feat: filter packages based on glob pattern when filtering by directories (#3521)
Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
5
.changeset/mean-jeans-pretend.md
Normal file
5
.changeset/mean-jeans-pretend.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
When `use-beta-cli` is `true`, filtering by directories supports globs.
|
||||
5
.changeset/smooth-horses-draw.md
Normal file
5
.changeset/smooth-horses-draw.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/filter-workspace-packages": minor
|
||||
---
|
||||
|
||||
New option added: `useGlobDirFiltering`. When `true`, directory filtering is done using globs.
|
||||
@@ -5,6 +5,7 @@ import isSubdir from 'is-subdir'
|
||||
import difference from 'ramda/src/difference'
|
||||
import partition from 'ramda/src/partition'
|
||||
import pick from 'ramda/src/pick'
|
||||
import * as micromatch from 'micromatch'
|
||||
import getChangedPkgs from './getChangedPackages'
|
||||
import parsePackageSelector, { PackageSelector } from './parsePackageSelector'
|
||||
|
||||
@@ -55,6 +56,7 @@ export async function filterPackages<T> (
|
||||
prefix: string
|
||||
workspaceDir: string
|
||||
testPattern?: string[]
|
||||
useGlobDirFiltering?: boolean
|
||||
}
|
||||
): Promise<{
|
||||
selectedProjectsGraph: PackageGraph<T>
|
||||
@@ -72,6 +74,7 @@ export async function filterPkgsBySelectorObjects<T> (
|
||||
linkWorkspacePackages?: boolean
|
||||
workspaceDir: string
|
||||
testPattern?: string[]
|
||||
useGlobDirFiltering?: boolean
|
||||
}
|
||||
): Promise<{
|
||||
selectedProjectsGraph: PackageGraph<T>
|
||||
@@ -87,6 +90,7 @@ export async function filterPkgsBySelectorObjects<T> (
|
||||
filteredGraph = await filterGraph(graph, allPackageSelectors, {
|
||||
workspaceDir: opts.workspaceDir,
|
||||
testPattern: opts.testPattern,
|
||||
useGlobDirFiltering: opts.useGlobDirFiltering,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -97,6 +101,7 @@ export async function filterPkgsBySelectorObjects<T> (
|
||||
prodFilteredGraph = await filterGraph(graph, prodPackageSelectors, {
|
||||
workspaceDir: opts.workspaceDir,
|
||||
testPattern: opts.testPattern,
|
||||
useGlobDirFiltering: opts.useGlobDirFiltering,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -122,6 +127,7 @@ export default async function filterGraph<T> (
|
||||
opts: {
|
||||
workspaceDir: string
|
||||
testPattern?: string[]
|
||||
useGlobDirFiltering?: boolean
|
||||
}
|
||||
): Promise<{
|
||||
selectedProjectsGraph: PackageGraph<T>
|
||||
@@ -150,6 +156,7 @@ async function _filterGraph<T> (
|
||||
opts: {
|
||||
workspaceDir: string
|
||||
testPattern?: string[]
|
||||
useGlobDirFiltering?: boolean
|
||||
},
|
||||
packageSelectors: PackageSelector[]
|
||||
): Promise<{
|
||||
@@ -163,6 +170,9 @@ async function _filterGraph<T> (
|
||||
const graph = pkgGraphToGraph(pkgGraph)
|
||||
const unmatchedFilters = [] as string[]
|
||||
let reversedGraph: Graph | undefined
|
||||
const matchPackagesByPath = opts.useGlobDirFiltering === true
|
||||
? matchPackagesByGlob
|
||||
: matchPackagesByExactPath
|
||||
for (const selector of packageSelectors) {
|
||||
let entryPackages: string[] | null = null
|
||||
if (selector.diff) {
|
||||
@@ -257,13 +267,22 @@ function matchPackages<T> (
|
||||
return Object.keys(graph).filter((id) => graph[id].package.manifest.name && match(graph[id].package.manifest.name!))
|
||||
}
|
||||
|
||||
function matchPackagesByPath<T> (
|
||||
function matchPackagesByExactPath<T> (
|
||||
graph: PackageGraph<T>,
|
||||
pathStartsWith: string
|
||||
) {
|
||||
return Object.keys(graph).filter((parentDir) => isSubdir(pathStartsWith, parentDir))
|
||||
}
|
||||
|
||||
function matchPackagesByGlob<T> (
|
||||
graph: PackageGraph<T>,
|
||||
pathStartsWith: string
|
||||
) {
|
||||
const format = (str: string) => str.replace(/\/$/, '')
|
||||
const formattedFilter = pathStartsWith.replace(/\\/g, '/').replace(/\/$/, '')
|
||||
return Object.keys(graph).filter((parentDir) => micromatch.isMatch(parentDir, formattedFilter, { format }))
|
||||
}
|
||||
|
||||
function pickSubgraph (
|
||||
graph: Graph,
|
||||
nextNodeIds: string[],
|
||||
|
||||
@@ -96,6 +96,20 @@ const PKGS_GRAPH: PackageGraph<{}> = {
|
||||
name: 'project-5',
|
||||
version: '1.0.0',
|
||||
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'/project-5/packages/project-6': {
|
||||
dependencies: [],
|
||||
package: {
|
||||
dir: '/project-5/packages/project-6',
|
||||
manifest: {
|
||||
name: 'project-6',
|
||||
version: '1.0.0',
|
||||
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
},
|
||||
@@ -204,6 +218,39 @@ test('select by parentDir', async () => {
|
||||
expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/packages/project-0', '/packages/project-1'])
|
||||
})
|
||||
|
||||
test('select by parentDir using glob', async () => {
|
||||
const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [
|
||||
{
|
||||
excludeSelf: false,
|
||||
parentDir: '/packages/*',
|
||||
},
|
||||
], { workspaceDir: process.cwd(), useGlobDirFiltering: true })
|
||||
|
||||
expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/packages/project-0', '/packages/project-1'])
|
||||
})
|
||||
|
||||
test('select by parentDir using globstar', async () => {
|
||||
const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [
|
||||
{
|
||||
excludeSelf: false,
|
||||
parentDir: '/project-5/**',
|
||||
},
|
||||
], { workspaceDir: process.cwd(), useGlobDirFiltering: true })
|
||||
|
||||
expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/project-5', '/project-5/packages/project-6'])
|
||||
})
|
||||
|
||||
test('select by parentDir with no glob', async () => {
|
||||
const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [
|
||||
{
|
||||
excludeSelf: false,
|
||||
parentDir: '/project-5',
|
||||
},
|
||||
], { workspaceDir: process.cwd(), useGlobDirFiltering: true })
|
||||
|
||||
expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/project-5'])
|
||||
})
|
||||
|
||||
test('select changed packages', async () => {
|
||||
// This test fails on Appveyor due to environmental issues
|
||||
if (isCI && isWindows()) {
|
||||
@@ -338,11 +385,11 @@ test('should return unmatched filters', async () => {
|
||||
{
|
||||
excludeSelf: true,
|
||||
includeDependencies: true,
|
||||
namePattern: 'project-6',
|
||||
namePattern: 'project-7',
|
||||
},
|
||||
], { workspaceDir: process.cwd() })
|
||||
|
||||
expect(unmatchedFilters).toStrictEqual(['project-6'])
|
||||
expect(unmatchedFilters).toStrictEqual(['project-7'])
|
||||
})
|
||||
|
||||
test('select all packages except one', async () => {
|
||||
@@ -375,3 +422,20 @@ test('select by parentDir and exclude one package by pattern', async () => {
|
||||
|
||||
expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/packages/project-0'])
|
||||
})
|
||||
|
||||
test('select by parentDir with glob and exclude one package by pattern', async () => {
|
||||
const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [
|
||||
{
|
||||
excludeSelf: false,
|
||||
parentDir: '/packages/*',
|
||||
},
|
||||
{
|
||||
exclude: true,
|
||||
excludeSelf: false,
|
||||
includeDependents: false,
|
||||
namePattern: '*-1',
|
||||
},
|
||||
], { workspaceDir: process.cwd(), useGlobDirFiltering: true })
|
||||
|
||||
expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/packages/project-0'])
|
||||
})
|
||||
|
||||
@@ -184,6 +184,7 @@ export default async function run (inputArgv: string[]) {
|
||||
prefix: process.cwd(),
|
||||
workspaceDir: wsDir,
|
||||
testPattern: config.testPattern,
|
||||
useGlobDirFiltering: config.useBetaCli,
|
||||
})
|
||||
config.selectedProjectsGraph = filterResults.selectedProjectsGraph
|
||||
if (isEmpty(config.selectedProjectsGraph)) {
|
||||
|
||||
Reference in New Issue
Block a user