license-report
Advanced tools
Comparing version 6.1.0 to 6.2.0
@@ -5,2 +5,14 @@ # Changelog | ||
## [6.2.0](https://github.com/ironSource/license-report/compare/v6.1.0...v6.2.0) (2022-10-06) | ||
### Features | ||
* add support for monorepos ([bb1f364](https://github.com/ironSource/license-report/commit/bb1f364925502e9890bab3a143c2523935543114)) | ||
### Bug Fixes | ||
* add new fields from v6.1.0 to output of cli help ([6dde8dd](https://github.com/ironSource/license-report/commit/6dde8dd5f362fcd32d43c9e2761a216eb1257c31)) | ||
## [6.1.0](https://github.com/ironSource/license-report/compare/v6.0.0...v6.1.0) (2022-07-31) | ||
@@ -7,0 +19,0 @@ |
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
import createDebugMessages from 'debug'; | ||
import semver from 'semver'; | ||
import util from './util.js'; | ||
@@ -13,3 +14,4 @@ import extractAuthor from './extractAuthor.js'; | ||
* and adds it to the given 'element' object. | ||
* If package.json file is found, 'n/a' is added as installedVersion | ||
* If package.json file is found, 'n/a' is added as installedVersion. | ||
* The logic to resolve mimics nodes logic (if not found, step up 1 level up to root) | ||
* @param {object} element - entry for a package in depsIndex | ||
@@ -20,3 +22,11 @@ * @param {string} projectRootPath - path of the package.json the report is generated for | ||
async function addLocalPackageData(element, projectRootPath) { | ||
const notAvailableText = 'n/a' | ||
const notAvailableText = 'n/a' | ||
let projectPackageJsonPath = projectRootPath | ||
let oldProjectPackageJsonPath = '' | ||
element['installedVersion'] = notAvailableText | ||
element['author'] = notAvailableText | ||
element['licenseType'] = notAvailableText | ||
let packageFolderName | ||
@@ -28,18 +38,21 @@ if (element.alias.length === 0) { | ||
} | ||
const elementPackageJsonPath = path.join(projectRootPath, 'node_modules', packageFolderName, 'package.json') | ||
if (fs.existsSync(elementPackageJsonPath)) { | ||
const packageJSONContent = await util.readJson(elementPackageJsonPath) | ||
if ((packageJSONContent !== undefined) && (packageJSONContent.version !== undefined)) { | ||
element['installedVersion'] = packageJSONContent.version | ||
} else { | ||
element['installedVersion'] = notAvailableText | ||
do { | ||
const elementPackageJsonPath = path.join(projectPackageJsonPath, 'node_modules', packageFolderName, 'package.json') | ||
if (fs.existsSync(elementPackageJsonPath)) { | ||
const packageJSONContent = await util.readJson(elementPackageJsonPath) | ||
if ((packageJSONContent?.version !== undefined)) { | ||
if(!semver.validRange(element.version) || semver.satisfies(packageJSONContent.version, element.version)) { | ||
element['installedVersion'] = packageJSONContent.version | ||
element['author'] = extractAuthor(packageJSONContent) | ||
element['licenseType'] = extractLicense(packageJSONContent) | ||
break | ||
} | ||
} | ||
} | ||
oldProjectPackageJsonPath = projectPackageJsonPath | ||
projectPackageJsonPath = path.dirname(projectPackageJsonPath) | ||
} while (projectPackageJsonPath !== oldProjectPackageJsonPath) | ||
element['author'] = extractAuthor(packageJSONContent) | ||
element['licenseType'] = extractLicense(packageJSONContent) | ||
} else { | ||
element['installedVersion'] = notAvailableText | ||
element['author'] = notAvailableText | ||
element['licenseType'] = notAvailableText | ||
if (element['installedVersion'] === notAvailableText) { | ||
debug('found no package.json file for %s', element.fullName) | ||
@@ -51,2 +64,2 @@ } | ||
export default addLocalPackageData; | ||
export default addLocalPackageData; |
@@ -40,3 +40,4 @@ import fs from 'node:fs'; | ||
department, relatedTo, name, licensePeriod, material, licenseType, | ||
link, remoteVersion, installedVersion, definedVersion, author, installedFrom. | ||
link, remoteVersion, installedVersion, definedVersion, author, installedFrom, | ||
latestRemoteVersion, latestRemoteModified. | ||
@@ -43,0 +44,0 @@ --<field>.value=<new-value> Set value for static output field. Allowed field names are: |
{ | ||
"name": "license-report", | ||
"version": "6.1.0", | ||
"version": "6.2.0", | ||
"description": "creates a short report about project's dependencies (license, url etc)", | ||
@@ -30,5 +30,5 @@ "main": "index.js", | ||
"eol": "^0.9.1", | ||
"got": "^12.3.0", | ||
"got": "^12.5.1", | ||
"rc": "^1.2.8", | ||
"semver": "^7.3.7", | ||
"semver": "^7.3.8", | ||
"text-table": "^0.2.0", | ||
@@ -38,4 +38,4 @@ "visit-values": "^2.0.0" | ||
"devDependencies": { | ||
"@commitlint/cli": "^17.0.3", | ||
"@commitlint/config-conventional": "^17.0.3", | ||
"@commitlint/cli": "^17.1.2", | ||
"@commitlint/config-conventional": "^17.1.0", | ||
"husky": "^8.0.1", | ||
@@ -42,0 +42,0 @@ "mocha": "^10.0.0", |
# license report tool | ||
![Version](https://img.shields.io/badge/version-6.1.0-blue.svg?cacheSeconds=2592000) | ||
![Version](https://img.shields.io/badge/version-6.2.0-blue.svg?cacheSeconds=2592000) | ||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE) | ||
@@ -12,5 +12,8 @@ | ||
## Functionality | ||
`license-report` gets the dependencies of a program or package from its `package.json` file and for each dependency adds the installed version, the license type and the author from the corresponding `package.json` file in the `node_modules` directory and the latest available version and other data from the (npm) registry where this package was installed from. | ||
As a prerequisite, the dependencies must be installed so that the node_modules directory exists in the path of the `package.json` file. | ||
`license-report` gets the dependencies of a program or package from its `package.json` file and for each dependency adds the installed version, the license type and the author from the corresponding `package.json` file in the `node_modules` directory and the latest available version and other data from the (npm) registry where this package was installed from. | ||
## Prerequisites | ||
1. The dependencies of the project under inspection must be installed so that the node_modules directory exists in the path of the `package.json` file. | ||
2. The registry defined in the `registry` configuration setting must be accessible (default: 'https://registry.npmjs.org/'). | ||
## Usage | ||
@@ -17,0 +20,0 @@ |
@@ -30,2 +30,15 @@ import assert from 'node:assert'; | ||
it('adds package data for package with fixed version', async () => { | ||
const depsIndexElement = { | ||
fullName: 'myfixedpackage', | ||
alias: '', | ||
name: 'myfixedpackage', | ||
version: '5.6.7' | ||
} | ||
await addLocalPackageData(depsIndexElement, projectRootPath) | ||
assert.ok(depsIndexElement.installedVersion) | ||
assert.strictEqual(depsIndexElement.installedVersion, '5.6.7') | ||
}) | ||
it('adds package data for scoped package', async () => { | ||
@@ -96,2 +109,39 @@ const depsIndexElement = { | ||
}) | ||
}) | ||
describe('addLocalPackageData with monorepo', function() { | ||
it('adds package data for package in root level', async () => { | ||
const projectRootPath = path | ||
.resolve(__dirname, 'fixture', 'monorepo', 'sub-project', 'sub-sub-project') | ||
.replace(/(\s+)/g, '\\$1') | ||
const depsIndexElement = { | ||
fullName: 'lodash', | ||
alias: '', | ||
name: 'lodash', | ||
version: '^4.17.20' | ||
} | ||
await addLocalPackageData(depsIndexElement, projectRootPath) | ||
assert.ok(depsIndexElement.installedVersion) | ||
assert.strictEqual(depsIndexElement.installedVersion, '4.17.21') | ||
}) | ||
it('adds package data for package with multiple versions', async () => { | ||
const projectRootPath = path | ||
.resolve(__dirname, 'fixture', 'monorepo', 'sub-project', 'sub-sub-project') | ||
.replace(/(\s+)/g, '\\$1') | ||
const depsIndexElement = { | ||
fullName: 'semver', | ||
alias: '', | ||
name: 'semver', | ||
version: '^7.3.5' | ||
} | ||
await addLocalPackageData(depsIndexElement, projectRootPath) | ||
assert.ok(depsIndexElement.installedVersion) | ||
assert.strictEqual(depsIndexElement.installedVersion, '7.3.7') | ||
}) | ||
}) |
@@ -21,2 +21,7 @@ import assert from 'node:assert'; | ||
// test data for e2e test using the default fields in monorepo | ||
const defaultFieldsMonorepoPackageJsonPath = path | ||
.resolve(__dirname, 'fixture', 'monorepo', 'sub-project', 'sub-sub-project', 'package.json') | ||
.replace(/(\s+)/g, '\\$1') | ||
// test data for e2e test using all fields | ||
@@ -86,2 +91,46 @@ const allFieldsPackageJsonPath = path | ||
describe('end to end test for default fields in monorepo', function() { | ||
this.timeout(50000) | ||
beforeEach(async () => { | ||
expectedData = EXPECTED_DEFAULT_FIELDS_RAW_DATA.slice(0) | ||
await expectedOutput.addRemoteVersionsToExpectedData(expectedData) | ||
}) | ||
it('produce a json report', async () => { | ||
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${defaultFieldsMonorepoPackageJsonPath}`) | ||
const result = JSON.parse(stdout) | ||
const expectedJsonResult = expectedOutput.rawDataToJson(expectedData) | ||
assert.deepStrictEqual(result, expectedJsonResult) | ||
assert.strictEqual(stderr, '', 'expected no warnings') | ||
}) | ||
it('produce a table report', async () => { | ||
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${defaultFieldsMonorepoPackageJsonPath} --output=table`) | ||
const expectedTableResult = expectedOutput.rawDataToTable(expectedData, EXPECTED_TABLE_TEMPLATE) | ||
assert.strictEqual(stdout, expectedTableResult) | ||
assert.strictEqual(stderr, '', 'expected no warnings') | ||
}) | ||
it('produce a csv report', async () => { | ||
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${defaultFieldsMonorepoPackageJsonPath} --output=csv --csvHeaders`) | ||
const expectedCsvResult = expectedOutput.rawDataToCsv(expectedData, EXPECTED_CSV_TEMPLATE) | ||
assert.strictEqual(stdout, expectedCsvResult) | ||
assert.strictEqual(stderr, 'Warning: field contains delimiter; value: \"Dan VerWeire, Yaniv Kessler\"\n') | ||
}) | ||
it('produce an html report', async () => { | ||
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${defaultFieldsMonorepoPackageJsonPath} --output=html`) | ||
const actualResult = eol.auto(stdout) | ||
const expectedHtmlTemplate = eol.auto(fs.readFileSync(path.join(__dirname, 'fixture', 'expectedOutput.e2e.html'), 'utf8')) | ||
const expectedHtmlResult = expectedOutput.rawDataToHtml(expectedData, expectedHtmlTemplate) | ||
assert.strictEqual(actualResult, expectedHtmlResult) | ||
assert.strictEqual(stderr, '', 'expected no warnings') | ||
}) | ||
}) | ||
describe('end to end test for local packages', function() { | ||
@@ -88,0 +137,0 @@ this.timeout(50000) |
@@ -12,10 +12,10 @@ import path from 'node:path'; | ||
/* | ||
get latest version from registry and add it to the entry in the expectedData; | ||
Add all required data from the remote repository and add it to the entry | ||
in the expectedData; | ||
the field 'definedVersion' in the packagesData entries must contain the | ||
package name with the range character from the package.json to find the | ||
latest version satisfying the defined range (the range character will be | ||
removed later) | ||
removed later). | ||
*/ | ||
async function addRemoteVersion(dependency) { | ||
dependency.remoteVersion = 'n/a' | ||
async function addRemoteData(dependency) { | ||
let uri = path.join(config.registry, dependency.name) | ||
@@ -50,10 +50,29 @@ | ||
// find the right version for this package | ||
if(packagesJson.versions) { | ||
const versions = Object.keys(packagesJson.versions) | ||
const version = semver.maxSatisfying(versions, dependency.definedVersion) | ||
if (version) { | ||
dependency.remoteVersion = version.toString() | ||
// 'remoteVersion': find the right version for this package | ||
if(dependency.remoteVersion !== undefined) { | ||
dependency.remoteVersion = 'n/a' | ||
if(packagesJson.versions) { | ||
const versions = Object.keys(packagesJson.versions) | ||
const version = semver.maxSatisfying(versions, dependency.definedVersion) | ||
if (version) { | ||
dependency.remoteVersion = version.toString() | ||
} | ||
} | ||
} | ||
// latestRemoteVersion | ||
if(dependency.latestRemoteVersion !== undefined) { | ||
dependency.latestRemoteVersion = 'n/a' | ||
if ((packagesJson['dist-tags'] !== undefined) && (packagesJson['dist-tags'].latest !== undefined)) { | ||
dependency.latestRemoteVersion = packagesJson['dist-tags'].latest | ||
} | ||
} | ||
// latestRemoteModified | ||
if(dependency.latestRemoteModified !== undefined) { | ||
dependency.latestRemoteModified = 'n/a' | ||
if ((packagesJson.time !== undefined) && (packagesJson.time.modified !== undefined)) { | ||
dependency.latestRemoteModified = packagesJson.time.modified | ||
} | ||
} | ||
} | ||
@@ -67,3 +86,3 @@ | ||
await Promise.all(expectedData.map(async (packageData) => { | ||
await addRemoteVersion(packageData) | ||
await addRemoteData(packageData) | ||
})) | ||
@@ -70,0 +89,0 @@ } |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
494274
55
2755
225
8
Updatedgot@^12.5.1
Updatedsemver@^7.3.8