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

Support filtering in licenses list in a monorepo #5806

Closed
1 task
segevfiner opened this issue Dec 17, 2022 · 6 comments · Fixed by #7204
Closed
1 task

Support filtering in licenses list in a monorepo #5806

segevfiner opened this issue Dec 17, 2022 · 6 comments · Fixed by #7204

Comments

@segevfiner
Copy link

Describe the user story

When using pnpm licenses list in a monorepo, it currently lists all dependencies of all projects. But this command could be useful in generating a NOTICE file for distribution with proper attribution for user FOSS packages, for such a case, we need to filter the dependencies to only the dependencies used by a particular package in a monorepo (Recursively, so you also get dependencies of dependencies as so on)

Describe the solution you'd like

Support filtering in pnpm licenses list

Describe the drawbacks of your solution

The complexity of implementing this. I'm not sure how easy it would be. I'm not sure if the currently implementation just dumps everything from the lockfile without any knowledge of what comes from which package in a monorepo.

Describe alternatives you've considered

Use an external tool. But I couldn't find any good one for this purpose, especially one that works in a monorepo, and they will have to know about pnpm's monorepo layout.

@weyert
Copy link
Contributor

weyert commented Dec 25, 2022

I am trying to work on this over the holidays. I think this is a useful feature. I only need to find a way how to convert the --filter-argument in the correct internal importerId inside the lock file so I can filter out the unnecessary bits and pass it to the license scanner. I have asked @zkochan about this

@TheLarkInn
Copy link

At first it appeared that @pnpm/license-scanner package would actually solve this because findDependencyLicense() takes a manifest: ProjectManifest argument.

However looking at the implementation:

export async function findDependencyLicenses (opts: {
ignoreDependencies?: Set<string>
include?: IncludedDependencies
lockfileDir: string
manifest: ProjectManifest
storeDir: string
virtualStoreDir: string
modulesDir?: string
registries: Registries
wantedLockfile: Lockfile | null
}): Promise<LicensePackage[]> {
if (opts.wantedLockfile == null) {
throw new PnpmError(
'LICENSES_NO_LOCKFILE',
`No lockfile in directory "${opts.lockfileDir}". Run \`pnpm install\` to generate one.`
)
}
const licenseNodeTree = await lockfileToLicenseNodeTree(opts.wantedLockfile, {
dir: opts.lockfileDir,
modulesDir: opts.modulesDir,
storeDir: opts.storeDir,
virtualStoreDir: opts.virtualStoreDir,
include: opts.include,
registries: opts.registries,
})
const licensePackages = new Map<string, LicensePackage>()
for (const dependencyName in licenseNodeTree.dependencies) {
const licenseNode = licenseNodeTree.dependencies[dependencyName]
const dependenciesOfNode = getDependenciesFromLicenseNode(licenseNode)
dependenciesOfNode.forEach((dependencyNode) => {
licensePackages.set(dependencyNode.name, dependencyNode)
})
}
// Get all non-duplicate dependencies of the project
const projectDependencies = Array.from(licensePackages.values())
return Array.from(projectDependencies).sort((pkg1, pkg2) =>
pkg1.name.localeCompare(pkg2.name)
)
}

it appears that manifest is not currently used in the function 😁

However this would be the overall implementation point in the API if it was going to be attempted to be patched, etc.

@TheLarkInn
Copy link

@weyert @zkochan if this does get implemented as a feature, probably best to incorporate its capabilities into the node API also.

@zkochan
Copy link
Member

zkochan commented Mar 2, 2023

What do you mean by incorporating this feature to the Node API? Like to node.js CLI? But this only works with the pnpm lockfile. It doesn't work with npm or Yarn.

@TheLarkInn
Copy link

TheLarkInn commented Mar 2, 2023

What do you mean by incorporating this feature to the Node API? Like to node.js CLI? But this only works with the pnpm lockfile. It doesn't work with npm or Yarn.

I was looking to implement something very similar, but I was not planning to use the cli to accomplish it, rather, using the packages and their API's.

In fact, it appears that this is possible today by just passing a filtered Lockfile instance into findDependencyLicenses():

import { ProjectManifest, Registries, IncludedDependencies } from '@pnpm/types';
import { filterLockfileByImporters } from "@pnpm/filter-lockfile";
import { Lockfile, readWantedLockfile } from '@pnpm/lockfile-file';
import { findDependencyLicenses, LicensePackage } from '@pnpm/license-scanner';

/*...*/

const include: IncludedDependencies = {
  dependencies: true,
  devDependencies: false,
  optionalDependencies: false
};

const lockfile: Lockfile | null = await readWantedLockfile(pnpmLockfilePath, { ignoreIncompatible: false });

const projectDependencies: LicensePackage[] = await findDependencyLicenses({
  include,
  manifest,
  lockfileDir,
  registries: {} as Registries,
  wantedLockfile: filterLockfileByImporters(lockfile, ['../../some/importer/name'], {include, skipped: new Set(), failOnMissingDependencies: false}),
  virtualStoreDir,
  storeDir
});

Nevertheless it would be very cool to incorporate both api's together into one cli feature in some way.

@robotkutya
Copy link

👍 this feature would be useful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants