From 6793c5c4663a45d2f28667f8c61bd41d33a3cf9f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 May 2020 19:56:45 +0100 Subject: [PATCH] CLI: new licences command (#5690) * new licences command * remove old licences command --- lib/cli/bin/doc/licenseList.js | 110 ----------- lib/cli/package.json | 6 +- lib/cli/scripts/licenses.ts | 172 ++++++++++++++++++ lib/cli/templates/auditPage.ejs | 31 ++++ .../{bin/doc => }/templates/licensePage.ejs | 4 +- 5 files changed, 208 insertions(+), 115 deletions(-) delete mode 100755 lib/cli/bin/doc/licenseList.js create mode 100644 lib/cli/scripts/licenses.ts create mode 100644 lib/cli/templates/auditPage.ejs rename lib/cli/{bin/doc => }/templates/licensePage.ejs (81%) diff --git a/lib/cli/bin/doc/licenseList.js b/lib/cli/bin/doc/licenseList.js deleted file mode 100755 index f609e7d8ba..0000000000 --- a/lib/cli/bin/doc/licenseList.js +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env node - -var path = require('path'); -var fs = require('fs'); - -var checker = require('license-checker'); -var spdxCodes = require('spdx-license-list'); -var ejs = require('ejs'); -var program = require('commander'); - -var templatePath = path.resolve(__dirname, 'templates', 'licensePage.ejs'); - -const nonStandardLicenses = { - 'public domain': 'PDDL-1.0', - 'apache': 'Apache-2.0', - 'bsd': 'BSD-2-Clause' -}; - -const missingRepos = { - '@alfresco/adf-testing': 'https://github.com/Alfresco/alfresco-ng2-components', - '@webassemblyjs/helper-api-error': 'https://github.com/xtuc/webassemblyjs', - '@webassemblyjs/helper-fsm': 'https://github.com/xtuc/webassemblyjs', - '@webassemblyjs/ieee754': 'https://github.com/xtuc/webassemblyjs', - '@webassemblyjs/leb128': 'https://github.com/xtuc/webassemblyjs', - 'adf-tslint-rules': 'https://github.com/Alfresco/alfresco-ng2-components', - 'adf-monaco-extension': 'https://github.com/eromano/aca-monaco-extension', - 'indexof': 'https://github.com/component/indexof', - 'rxjs-compat': 'https://github.com/ReactiveX/rxjs/tree/master/compat', -}; - -program - .usage('') - .parse(process.argv); - -var packageJson = JSON.parse(fs.readFileSync(path.resolve('./','package.json'))); - -if (!packageJson) { - console.error('Move in the path where you have the package.json'); - throw ''; -} - -console.log(path.resolve('./','package.json')); - -checker.init({ - start: './', - production: true, - failOn: 'GPL' -}, function (err, packages) { - if (err) { - console.log(err); - } else { - for (var packageName in packages) { - var pack = packages[packageName]; - pack['licenseExp'] = pack['licenses'].toString() - .replace(/\*/, '') - .replace(/[a-zA-Z0-9\-\.]+/g, match => { - var lowerMatch = match.toLowerCase(); - - if ((lowerMatch !== 'and') && (lowerMatch !== 'or') && (lowerMatch !== 'with')) { - return licenseWithMDLinks(match); - } else { - return match; - } - }); - - if (!pack['repository']) { - var lastAtSignPos = packageName.lastIndexOf('@'); - var mainName = packageName.substring(0, lastAtSignPos); - - if (missingRepos[mainName]) { - pack['repository'] = missingRepos[mainName]; - } - } - } - - ejs.renderFile(templatePath, { - packages: packages, - projVersion: packageJson.version, - projName: packageJson.description - }, {}, (err, mdText) => { - if (err) { - console.log(err); - } else { - fs.writeFileSync(`license-info-${packageJson.version}.md`, mdText); - console.log(`Wrote license`); - } - }); - } -}); - - -function licenseWithMDLinks(licenseExp) { - var licenseUrl = ''; - - if (spdxCodes[licenseExp] && spdxCodes[licenseExp]['url']) { - licenseUrl = spdxCodes[licenseExp]['url']; - } else { - var substituteLicString = nonStandardLicenses[licenseExp.toLowerCase()]; - - if (spdxCodes[substituteLicString] && spdxCodes[substituteLicString]['url']) { - licenseUrl = spdxCodes[substituteLicString]['url']; - } - } - - if (licenseUrl) { - return `[${licenseExp}](${licenseUrl})`; - } else { - return licenseExp; - } -} diff --git a/lib/cli/package.json b/lib/cli/package.json index e9eedbee9f..3e49648f8e 100644 --- a/lib/cli/package.json +++ b/lib/cli/package.json @@ -4,9 +4,9 @@ "version": "3.8.0", "author": "Alfresco Software, Ltd.", "bin": { - "adf-license": "./bin/doc/licenseList.js", "adf-audit": "./bin/doc/audit.js", - "adf-cli": "./bin/adf-cli" + "adf-cli": "./bin/adf-cli", + "adf": "./bin/adf-cli" }, "repository": { "type": "git", @@ -18,7 +18,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "develop": "tsc -p tsconfig.json --watch", - "dist": "rm -rf ./dist/ && npm run build && cp -R ./bin ./dist/ && cp ./package.json ./dist/" + "dist": "rm -rf ./dist/ && npm run build && cp -R ./bin ./dist/ && cp -R ./templates ./dist && cp ./package.json ./dist/" }, "dependencies": { "commander": "^4.0.0", diff --git a/lib/cli/scripts/licenses.ts b/lib/cli/scripts/licenses.ts new file mode 100644 index 0000000000..bf91701723 --- /dev/null +++ b/lib/cli/scripts/licenses.ts @@ -0,0 +1,172 @@ +#!/usr/bin/env node +/// types.d.ts + +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import * as fs from 'fs'; +import * as checker from 'license-checker'; +import * as licenseList from 'spdx-license-list'; +import * as ejs from 'ejs'; +import * as program from 'commander'; + +interface PackageInfo { + name: string; + description: string; + version: string; +} + +const nonStandardLicenses = { + 'public domain': 'PDDL-1.0', + 'apache': 'Apache-2.0', + 'bsd': 'BSD-2-Clause' +}; + +const missingRepositories = { + '@alfresco/adf-testing': 'https://github.com/Alfresco/alfresco-ng2-components', + '@webassemblyjs/helper-api-error': 'https://github.com/xtuc/webassemblyjs', + '@webassemblyjs/helper-fsm': 'https://github.com/xtuc/webassemblyjs', + '@webassemblyjs/ieee754': 'https://github.com/xtuc/webassemblyjs', + '@webassemblyjs/leb128': 'https://github.com/xtuc/webassemblyjs', + 'adf-tslint-rules': 'https://github.com/Alfresco/alfresco-ng2-components', + 'adf-monaco-extension': 'https://github.com/eromano/aca-monaco-extension', + 'indexof': 'https://github.com/component/indexof', + 'rxjs-compat': 'https://github.com/ReactiveX/rxjs/tree/master/compat' +}; + +function licenseWithMDLinks(licenseExp: string): string { + let licenseUrl = ''; + + if (licenseList[licenseExp] && licenseList[licenseExp]['url']) { + licenseUrl = licenseList[licenseExp]['url']; + } else { + const substituteLicString = nonStandardLicenses[licenseExp.toLowerCase()]; + + if (licenseList[substituteLicString] && licenseList[substituteLicString]['url']) { + licenseUrl = licenseList[substituteLicString]['url']; + } + } + + if (licenseUrl) { + return `[${licenseExp}](${licenseUrl})`; + } else { + return licenseExp; + } +} + +function getPackageFile(packagePath: string): PackageInfo { + try { + return JSON.parse(fs.readFileSync(packagePath).toString()); + } catch { + console.error('Error parsing package.json file'); + process.exit(1); + } +} + +export default function main(_args: string[], workingDir: string) { + program + .description('Generate a licences report') + .usage('licenses [options]') + .option('-p, --package ', 'Path to package file (default: package.json in working directory)') + .option('-d, --outDir ', 'Ouput directory (default: working directory)') + .parse(process.argv); + + if (process.argv.includes('-h') || process.argv.includes('--help')) { + program.outputHelp(); + return; + } + + let packagePath = path.resolve(workingDir, 'package.json'); + + if (program.package) { + packagePath = path.resolve(program.package); + } + + if (!fs.existsSync(packagePath)) { + console.error('Package.json not found'); + process.exit(1); + } + + const templatePath = path.resolve(__dirname, '../templates/licensePage.ejs'); + if (!fs.existsSync(templatePath)) { + console.error(`Cannot find licence template: ${templatePath}`); + process.exit(1); + } + + return new Promise((resolve, reject) => { + // tslint:disable-next-line: no-console + console.info(`Checking ${packagePath}`); + + checker.init({ + start: workingDir, + production: true, + failOn: 'GPL' + }, function (err: any, packages: any[]) { + if (err) { + console.error(err); + reject(err); + } else { + // tslint:disable-next-line: forin + for (const packageName in packages) { + const pack = packages[packageName]; + pack['licenseExp'] = pack['licenses'].toString() + .replace(/\*/, '') + .replace(/[a-zA-Z0-9\-\.]+/g, (match: string) => { + const lowerMatch = match.toLowerCase(); + + if ((lowerMatch !== 'and') && (lowerMatch !== 'or') && (lowerMatch !== 'with')) { + return licenseWithMDLinks(match); + } else { + return match; + } + }); + + if (!pack['repository']) { + const lastAtSignPos = packageName.lastIndexOf('@'); + const mainName = packageName.substring(0, lastAtSignPos); + + if (missingRepositories[mainName]) { + pack['repository'] = missingRepositories[mainName]; + } + } + } + + const packageJson: PackageInfo = getPackageFile(packagePath); + + ejs.renderFile(templatePath, { + packages: packages, + projVersion: packageJson.version, + projName: packageJson.name + }, {}, (ejsError: any, mdText: string) => { + if (ejsError) { + console.error(ejsError); + reject(ejsError); + } else { + const outputPath = path.resolve(program.outDir || workingDir); + const outputFile = path.join(outputPath, `license-info-${packageJson.version}.md`); + + fs.writeFileSync(outputFile, mdText); + // tslint:disable-next-line: no-console + console.log(`Report saved as ${outputFile}`); + resolve(0); + } + }); + } + }); + }); +} diff --git a/lib/cli/templates/auditPage.ejs b/lib/cli/templates/auditPage.ejs new file mode 100644 index 0000000000..5ef6f2992b --- /dev/null +++ b/lib/cli/templates/auditPage.ejs @@ -0,0 +1,31 @@ +--- +Title: Audit info, <%= projName %> <%= projVersion %> +--- + +# Audit information for <%= projName %> <%= projVersion %> + +This page lists the npm audit of the project in the version <%= projVersion %> + +## Risks + +- Critical risk dependencies <%= jsonAudit.metadata.vulnerabilities.critical %> +- High risk dependencies <%= jsonAudit.metadata.vulnerabilities.high %> +- Moderate risk dependencies <%= jsonAudit.metadata.vulnerabilities.moderate %> +- Low risk dependencies <%= jsonAudit.metadata.vulnerabilities.low %> + +Dependencies analyzed <%= jsonAudit.metadata.totalDependencies %> + +## Libraries + + +| Severity | Vulnerable versions | Module | +| --- | --- | --- | +<% +for(var currentAdvisories in jsonAudit.advisories) { + + severity = jsonAudit.advisories[currentAdvisories].severity; + vulnerable_versions = JSON.stringify(jsonAudit.advisories[currentAdvisories].vulnerable_versions); + module = jsonAudit.advisories[currentAdvisories].module_name; +-%> +|<%= severity %> | <%= vulnerable_versions %> | <%= module %> | +<% } %> diff --git a/lib/cli/bin/doc/templates/licensePage.ejs b/lib/cli/templates/licensePage.ejs similarity index 81% rename from lib/cli/bin/doc/templates/licensePage.ejs rename to lib/cli/templates/licensePage.ejs index 17a4e74a8f..46748bba16 100644 --- a/lib/cli/bin/doc/templates/licensePage.ejs +++ b/lib/cli/templates/licensePage.ejs @@ -2,9 +2,9 @@ Title: License info, <%= projName %> <%= projVersion %> --- -# License information for <%= projName %> <%= projVersion %> +# License information for <%= projName %> <%= projVersion %> -This page lists all third party libraries that ADF <%= projVersion %> depends on. +This page lists all third party libraries the project depends on. ## Libraries