mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[dev/license_checker][dev/npm] reactor, ts-ify, de-grunt (#37807)
This commit is contained in:
parent
a1ecfffd4f
commit
5973c2a08c
24 changed files with 318 additions and 354 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -5,7 +5,7 @@
|
|||
.DS_Store
|
||||
.node_binaries
|
||||
node_modules
|
||||
!/src/dev/npm/__tests__/fixtures/fixture1/node_modules
|
||||
!/src/dev/npm/integration_tests/__fixtures__/fixture1/node_modules
|
||||
!/src/dev/notice/__fixtures__/node_modules
|
||||
trash
|
||||
/optimize
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
"test:server": "grunt test:server",
|
||||
"test:coverage": "grunt test:coverage",
|
||||
"typespec": "typings-tester --config x-pack/plugins/canvas/public/lib/aeroelastic/tsconfig.json x-pack/plugins/canvas/public/lib/aeroelastic/__fixtures__/typescript/typespec_tests.ts",
|
||||
"checkLicenses": "grunt licenses --dev",
|
||||
"checkLicenses": "node scripts/check_licenses --dev",
|
||||
"build": "node scripts/build --all-platforms",
|
||||
"start": "node --trace-warnings --trace-deprecation scripts/kibana --dev ",
|
||||
"debug": "node --nolazy --inspect scripts/kibana --dev",
|
||||
|
@ -304,6 +304,7 @@
|
|||
"@types/jquery": "^3.3.6",
|
||||
"@types/js-yaml": "^3.11.1",
|
||||
"@types/json5": "^0.0.30",
|
||||
"@types/license-checker": "15.0.0",
|
||||
"@types/listr": "^0.14.0",
|
||||
"@types/lodash": "^3.10.1",
|
||||
"@types/lru-cache": "^5.1.0",
|
||||
|
|
21
scripts/check_licenses.js
Normal file
21
scripts/check_licenses.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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.
|
||||
*/
|
||||
|
||||
require('../src/setup_node_env');
|
||||
require('../src/dev/license_checker/run_check_licenses_cli');
|
|
@ -56,6 +56,7 @@ export const LICENSE_WHITELIST = [
|
|||
'ISC',
|
||||
'ISC*',
|
||||
'MIT OR GPL-2.0',
|
||||
'(MIT OR CC0-1.0)',
|
||||
'MIT',
|
||||
'MIT*',
|
||||
'MIT/X11',
|
||||
|
@ -69,15 +70,13 @@ export const LICENSE_WHITELIST = [
|
|||
|
||||
// The following list only applies to licenses that
|
||||
// we wanna allow in packages only used as dev dependencies
|
||||
export const DEV_ONLY_LICENSE_WHITELIST = [
|
||||
'MPL-2.0'
|
||||
];
|
||||
export const DEV_ONLY_LICENSE_WHITELIST = ['MPL-2.0'];
|
||||
|
||||
// Globally overrides a license for a given package@version
|
||||
export const LICENSE_OVERRIDES = {
|
||||
'cycle@1.0.3': ['CC0-1.0'], // conversion to a public-domain like license
|
||||
'jsts@1.1.2': ['Eclipse Distribution License - v 1.0'], //cf. https://github.com/bjornharrtell/jsts
|
||||
'@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], //license in readme https://github.com/tmcw/jsonlint
|
||||
'jsts@1.1.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts
|
||||
'@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint
|
||||
|
||||
// TODO can be removed once we upgrade past elasticsearch-browser@14.0.0
|
||||
'elasticsearch-browser@13.0.1': ['Apache-2.0'],
|
||||
|
@ -105,5 +104,5 @@ export const LICENSE_OVERRIDES = {
|
|||
'walk@2.3.9': ['MIT'],
|
||||
|
||||
// TODO remove this once we upgrade past or equal to v1.0.2
|
||||
'babel-plugin-mock-imports@1.0.1': ['MIT']
|
||||
'babel-plugin-mock-imports@1.0.1': ['MIT'],
|
||||
};
|
61
src/dev/license_checker/run_check_licenses_cli.ts
Normal file
61
src/dev/license_checker/run_check_licenses_cli.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { getInstalledPackages } from '../npm';
|
||||
import { run } from '../run';
|
||||
|
||||
import { LICENSE_WHITELIST, DEV_ONLY_LICENSE_WHITELIST, LICENSE_OVERRIDES } from './config';
|
||||
import { assertLicensesValid } from './valid';
|
||||
import { REPO_ROOT } from '../constants';
|
||||
|
||||
run(
|
||||
async ({ log, flags }) => {
|
||||
const packages = await getInstalledPackages({
|
||||
directory: REPO_ROOT,
|
||||
licenseOverrides: LICENSE_OVERRIDES,
|
||||
includeDev: !!flags.dev,
|
||||
});
|
||||
|
||||
// Assert if the found licenses in the production
|
||||
// packages are valid
|
||||
assertLicensesValid({
|
||||
packages: packages.filter(pkg => !pkg.isDevOnly),
|
||||
validLicenses: LICENSE_WHITELIST,
|
||||
});
|
||||
log.success('All production dependency licenses are allowed');
|
||||
|
||||
// Do the same as above for the packages only used in development
|
||||
// if the dev flag is found
|
||||
if (flags.dev) {
|
||||
assertLicensesValid({
|
||||
packages: packages.filter(pkg => pkg.isDevOnly),
|
||||
validLicenses: LICENSE_WHITELIST.concat(DEV_ONLY_LICENSE_WHITELIST),
|
||||
});
|
||||
log.success('All development dependency licenses are allowed');
|
||||
}
|
||||
},
|
||||
{
|
||||
flags: {
|
||||
boolean: ['dev'],
|
||||
help: `
|
||||
--dev Also check dev dependencies
|
||||
`,
|
||||
},
|
||||
}
|
||||
);
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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.
|
||||
*/
|
||||
|
||||
const describeInvalidLicenses = getInvalid => pkg => (
|
||||
`
|
||||
${pkg.name}
|
||||
version: ${pkg.version}
|
||||
all licenses: ${pkg.licenses}
|
||||
invalid licenses: ${getInvalid(pkg.licenses).join(', ')}
|
||||
path: ${pkg.relative}
|
||||
`
|
||||
);
|
||||
|
||||
/**
|
||||
* When given a list of packages and the valid license
|
||||
* options, either throws an error with details about
|
||||
* violations or returns undefined.
|
||||
*
|
||||
* @param {Object} [options={}]
|
||||
* @property {Array<Package>} options.packages List of packages to check, see
|
||||
* getInstalledPackages() in ../packages
|
||||
* @property {Array<string>} options.validLicenses
|
||||
* @return {undefined}
|
||||
*/
|
||||
export function assertLicensesValid(options = {}) {
|
||||
const {
|
||||
packages,
|
||||
validLicenses
|
||||
} = options;
|
||||
|
||||
if (!packages || !validLicenses) {
|
||||
throw new Error('packages and validLicenses options are required');
|
||||
}
|
||||
|
||||
const getInvalid = licenses => (
|
||||
licenses.filter(license => !validLicenses.includes(license))
|
||||
);
|
||||
|
||||
const isPackageInvalid = pkg => (
|
||||
!pkg.licenses.length || getInvalid(pkg.licenses).length > 0
|
||||
);
|
||||
|
||||
const invalidMsgs = packages
|
||||
.filter(isPackageInvalid)
|
||||
.map(describeInvalidLicenses(getInvalid));
|
||||
|
||||
if (invalidMsgs.length) {
|
||||
throw new Error(`Non-conforming licenses: ${invalidMsgs.join('')}`);
|
||||
}
|
||||
}
|
67
src/dev/license_checker/valid.ts
Normal file
67
src/dev/license_checker/valid.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 dedent from 'dedent';
|
||||
import { createFailError } from '../run';
|
||||
|
||||
interface Options {
|
||||
packages: Array<{
|
||||
name: string;
|
||||
version: string;
|
||||
relative: string;
|
||||
licenses: string[];
|
||||
}>;
|
||||
validLicenses: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* When given a list of packages and the valid license
|
||||
* options, either throws an error with details about
|
||||
* violations or returns undefined.
|
||||
*/
|
||||
export function assertLicensesValid({ packages, validLicenses }: Options) {
|
||||
const invalidMsgs = packages.reduce(
|
||||
(acc, pkg) => {
|
||||
const invalidLicenses = pkg.licenses.filter(license => !validLicenses.includes(license));
|
||||
|
||||
if (pkg.licenses.length && !invalidLicenses.length) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return acc.concat(dedent`
|
||||
${pkg.name}
|
||||
version: ${pkg.version}
|
||||
all licenses: ${pkg.licenses}
|
||||
invalid licenses: ${invalidLicenses.join(', ')}
|
||||
path: ${pkg.relative}
|
||||
`);
|
||||
},
|
||||
[] as string[]
|
||||
);
|
||||
|
||||
if (invalidMsgs.length) {
|
||||
throw createFailError(
|
||||
`Non-conforming licenses:\n${invalidMsgs
|
||||
.join('\n')
|
||||
.split('\n')
|
||||
.map(l => ` ${l}`)
|
||||
.join('\n')}`
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { relative, resolve } from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
import { callLicenseChecker } from './license_checker';
|
||||
|
||||
function resolveLicense(licenseInfo, key, licenseOverrides) {
|
||||
const {
|
||||
private: isPrivate,
|
||||
licenses: detectedLicenses,
|
||||
realPath,
|
||||
} = licenseInfo[key];
|
||||
|
||||
// `license-checker` marks all packages that have `private: true`
|
||||
// in their `package.json` as "UNLICENSED", so we try to lookup the
|
||||
// actual license by reading the license field from their package.json
|
||||
if (isPrivate && detectedLicenses === 'UNLICENSED') {
|
||||
try {
|
||||
const pkg = JSON.parse(readFileSync(resolve(realPath, 'package.json')));
|
||||
if (!pkg.license) {
|
||||
throw new Error('no license field');
|
||||
}
|
||||
return [pkg.license];
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to detect license for \`"private": true\` package at ${realPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return [].concat(
|
||||
licenseOverrides[key]
|
||||
? licenseOverrides[key]
|
||||
: detectedLicenses
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of objects with details about each installed
|
||||
* NPM package.
|
||||
*
|
||||
* @param {Object} [options={}]
|
||||
* @property {String} options.directory root of the project to read
|
||||
* @property {Boolean} [options.dev=false] should development dependencies be included?
|
||||
* @property {Object} [options.licenseOverrides] map of `${name}@${version}` to a list of
|
||||
* license ids to override the automatically
|
||||
* detected ones
|
||||
* @return {Array<Object>}
|
||||
*/
|
||||
export async function getInstalledPackages(options = {}) {
|
||||
const {
|
||||
directory,
|
||||
dev = false,
|
||||
licenseOverrides = {}
|
||||
} = options;
|
||||
|
||||
if (!directory) {
|
||||
throw new Error('You must specify a directory to read installed packages from');
|
||||
}
|
||||
|
||||
const licenseInfo = await callLicenseChecker({ directory, dev });
|
||||
return Object
|
||||
.keys(licenseInfo)
|
||||
.map(key => {
|
||||
const { realPath, repository, isDevOnly } = licenseInfo[key];
|
||||
if (realPath === directory) return;
|
||||
|
||||
const keyParts = key.split('@');
|
||||
const name = keyParts.slice(0, -1).join('@');
|
||||
const version = keyParts[keyParts.length - 1];
|
||||
|
||||
const licenses = resolveLicense(licenseInfo, key, licenseOverrides);
|
||||
|
||||
return {
|
||||
name,
|
||||
version,
|
||||
repository,
|
||||
licenses,
|
||||
directory: realPath,
|
||||
relative: relative(directory, realPath),
|
||||
isDevOnly
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
124
src/dev/npm/installed_packages.ts
Normal file
124
src/dev/npm/installed_packages.ts
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { relative, resolve } from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import licenseChecker from 'license-checker';
|
||||
|
||||
export type InstalledPackage = NonNullable<ReturnType<typeof readModuleInfo>>;
|
||||
interface Options {
|
||||
directory: string;
|
||||
includeDev?: boolean;
|
||||
licenseOverrides?: { [pgkNameAndVersion: string]: string[] };
|
||||
}
|
||||
|
||||
const toArray = <T>(input: T | T[]) => ([] as T[]).concat(input);
|
||||
|
||||
function resolveLicenses(
|
||||
isPrivate: boolean,
|
||||
realPath: string,
|
||||
licenses: string[] | string | undefined
|
||||
) {
|
||||
// `license-checker` marks all packages that have `private: true`
|
||||
// in their `package.json` as "UNLICENSED", so we try to lookup the
|
||||
// actual license by reading the license field from their package.json
|
||||
if (isPrivate && licenses === 'UNLICENSED') {
|
||||
try {
|
||||
const pkg = JSON.parse(readFileSync(resolve(realPath, 'package.json'), 'utf8'));
|
||||
if (!pkg.license) {
|
||||
throw new Error('no license field');
|
||||
}
|
||||
return [pkg.license as string];
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Unable to detect license for \`"private": true\` package at ${realPath}: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return toArray(licenses || []);
|
||||
}
|
||||
|
||||
function readModuleInfo(
|
||||
pkgAndVersion: string,
|
||||
moduleInfo: licenseChecker.ModuleInfo,
|
||||
dev: boolean,
|
||||
options: Options
|
||||
) {
|
||||
const directory = (moduleInfo as any).realPath as string;
|
||||
if (directory === options.directory) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isPrivate = !!(moduleInfo as any).private as boolean;
|
||||
const keyParts = pkgAndVersion.split('@');
|
||||
const name = keyParts.slice(0, -1).join('@');
|
||||
const version = keyParts[keyParts.length - 1];
|
||||
const override = options.licenseOverrides && options.licenseOverrides[pkgAndVersion];
|
||||
|
||||
return {
|
||||
name,
|
||||
version,
|
||||
isDevOnly: dev,
|
||||
repository: moduleInfo.repository,
|
||||
directory,
|
||||
relative: relative(options.directory, directory),
|
||||
licenses: toArray(
|
||||
override ? override : resolveLicenses(isPrivate, directory, moduleInfo.licenses)
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
async function _getInstalledPackages(dev: boolean, options: Options) {
|
||||
const lcResult = await promisify(licenseChecker.init)({
|
||||
start: options.directory,
|
||||
development: dev,
|
||||
production: !dev,
|
||||
json: true,
|
||||
customFormat: {
|
||||
realPath: true,
|
||||
licenseText: false,
|
||||
licenseFile: false,
|
||||
},
|
||||
} as any);
|
||||
|
||||
const result = [];
|
||||
|
||||
for (const [pkgAndVersion, moduleInfo] of Object.entries(lcResult)) {
|
||||
const installedPackage = readModuleInfo(pkgAndVersion, moduleInfo, dev, options);
|
||||
if (installedPackage) {
|
||||
result.push(installedPackage);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of objects with details about each installed
|
||||
* NPM package.
|
||||
*/
|
||||
export async function getInstalledPackages(options: Options) {
|
||||
return [
|
||||
...(await _getInstalledPackages(false, options)),
|
||||
...(options.includeDev ? await _getInstalledPackages(true, options) : []),
|
||||
];
|
||||
}
|
|
@ -20,46 +20,35 @@
|
|||
import { resolve, sep } from 'path';
|
||||
|
||||
import { uniq } from 'lodash';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import { getInstalledPackages } from '../installed_packages';
|
||||
import { getInstalledPackages, InstalledPackage } from '../installed_packages';
|
||||
import { REPO_ROOT } from '../../constants';
|
||||
|
||||
const KIBANA_ROOT = resolve(__dirname, '../../../../');
|
||||
const FIXTURE1_ROOT = resolve(__dirname, 'fixtures/fixture1');
|
||||
const FIXTURE1_ROOT = resolve(__dirname, '__fixtures__/fixture1');
|
||||
|
||||
describe('src/dev/npm/installed_packages', () => {
|
||||
describe('getInstalledPackages()', function () {
|
||||
describe('getInstalledPackages()', function() {
|
||||
let kibanaPackages: InstalledPackage[];
|
||||
let fixture1Packages: InstalledPackage[];
|
||||
|
||||
let kibanaPackages;
|
||||
let fixture1Packages;
|
||||
before(async function () {
|
||||
this.timeout(30 * 1000);
|
||||
beforeAll(async function() {
|
||||
[kibanaPackages, fixture1Packages] = await Promise.all([
|
||||
getInstalledPackages({
|
||||
directory: KIBANA_ROOT
|
||||
directory: REPO_ROOT,
|
||||
}),
|
||||
getInstalledPackages({
|
||||
directory: FIXTURE1_ROOT,
|
||||
dev: true
|
||||
includeDev: true,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('requires a directory', async () => {
|
||||
try {
|
||||
await getInstalledPackages({});
|
||||
throw new Error('expected getInstalledPackages() to reject');
|
||||
} catch (err) {
|
||||
expect(err.message).to.contain('directory');
|
||||
}
|
||||
});
|
||||
}, 30 * 1000);
|
||||
|
||||
it('reads all installed packages of a module', () => {
|
||||
expect(fixture1Packages).to.eql([
|
||||
expect(fixture1Packages).toEqual([
|
||||
{
|
||||
name: 'dep1',
|
||||
version: '0.0.2',
|
||||
licenses: [ 'Apache-2.0' ],
|
||||
licenses: ['Apache-2.0'],
|
||||
repository: 'https://github.com/mycorp/dep1',
|
||||
directory: resolve(FIXTURE1_ROOT, 'node_modules/dep1'),
|
||||
relative: ['node_modules', 'dep1'].join(sep),
|
||||
|
@ -69,7 +58,7 @@ describe('src/dev/npm/installed_packages', () => {
|
|||
name: 'privatedep',
|
||||
version: '0.0.2',
|
||||
repository: 'https://github.com/mycorp/privatedep',
|
||||
licenses: [ 'Apache-2.0' ],
|
||||
licenses: ['Apache-2.0'],
|
||||
directory: resolve(FIXTURE1_ROOT, 'node_modules/privatedep'),
|
||||
relative: ['node_modules', 'privatedep'].join(sep),
|
||||
isDevOnly: false,
|
||||
|
@ -77,23 +66,28 @@ describe('src/dev/npm/installed_packages', () => {
|
|||
{
|
||||
name: 'dep2',
|
||||
version: '0.0.2',
|
||||
licenses: [ 'Apache-2.0' ],
|
||||
licenses: ['Apache-2.0'],
|
||||
repository: 'https://github.com/mycorp/dep2',
|
||||
directory: resolve(FIXTURE1_ROOT, 'node_modules/dep2'),
|
||||
relative: ['node_modules', 'dep2'].join(sep),
|
||||
isDevOnly: true,
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns a single entry for every package/version combo', () => {
|
||||
const tags = kibanaPackages.map(pkg => `${pkg.name}@${pkg.version}`);
|
||||
expect(tags).to.eql(uniq(tags));
|
||||
expect(tags).toEqual(uniq(tags));
|
||||
});
|
||||
|
||||
it('does not include root package in the list', async () => {
|
||||
expect(kibanaPackages.find(pkg => pkg.name === 'kibana')).to.be(undefined);
|
||||
expect(fixture1Packages.find(pkg => pkg.name === 'fixture1')).to.be(undefined);
|
||||
if (kibanaPackages.find(pkg => pkg.name === 'kibana')) {
|
||||
throw new Error('Expected getInstalledPackages(kibana) to not include kibana pkg');
|
||||
}
|
||||
|
||||
if (fixture1Packages.find(pkg => pkg.name === 'fixture1')) {
|
||||
throw new Error('Expected getInstalledPackages(fixture1) to not include fixture1 pkg');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 licenseChecker from 'license-checker';
|
||||
|
||||
async function runLicenseChecker(directory, dev) {
|
||||
return new Promise((resolve, reject) => {
|
||||
licenseChecker.init({
|
||||
start: directory,
|
||||
development: dev,
|
||||
production: !dev,
|
||||
json: true,
|
||||
customFormat: {
|
||||
realPath: true,
|
||||
licenseText: false,
|
||||
licenseFile: false
|
||||
}
|
||||
}, (err, licenseInfo) => {
|
||||
if (err) reject(err);
|
||||
else {
|
||||
resolve(
|
||||
// Extend original licenseInfo object with a new attribute
|
||||
// stating whether a license was found in a package used
|
||||
// only as a dev dependency or not
|
||||
Object.keys(licenseInfo).reduce(function (result, key) {
|
||||
result[key] = Object.assign(licenseInfo[key], { isDevOnly: dev });
|
||||
return result;
|
||||
}, {})
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function callLicenseChecker(options = {}) {
|
||||
const {
|
||||
directory,
|
||||
dev = false
|
||||
} = options;
|
||||
|
||||
if (!directory) {
|
||||
throw new Error('You must specify the directory where license checker should start');
|
||||
}
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
// Run license checker for prod only packages
|
||||
const prodOnlyLicenses = await runLicenseChecker(directory, false);
|
||||
|
||||
if (!dev) {
|
||||
resolve(prodOnlyLicenses);
|
||||
return;
|
||||
}
|
||||
|
||||
// In case we have the dev option
|
||||
// also run the license checker for the
|
||||
// dev only packages and build a final object
|
||||
// merging the previous results too
|
||||
const devOnlyLicenses = await runLicenseChecker(directory, true);
|
||||
resolve(Object.assign(prodOnlyLicenses, devOnlyLicenses));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -269,7 +269,15 @@ module.exports = function (grunt) {
|
|||
],
|
||||
}),
|
||||
|
||||
licenses: gruntTaskWithGithubChecks('Licenses', 'licenses'),
|
||||
licenses: scriptWithGithubChecks({
|
||||
title: 'Check licenses',
|
||||
cmd: NODE,
|
||||
args: [
|
||||
'scripts/check_licenses',
|
||||
'--dev',
|
||||
],
|
||||
}),
|
||||
|
||||
verifyDependencyVersions:
|
||||
gruntTaskWithGithubChecks('Verify dependency versions', 'verifyDependencyVersions'),
|
||||
test_server:
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { getInstalledPackages } from '../src/dev/npm';
|
||||
import {
|
||||
assertLicensesValid,
|
||||
LICENSE_WHITELIST,
|
||||
DEV_ONLY_LICENSE_WHITELIST,
|
||||
LICENSE_OVERRIDES,
|
||||
} from '../src/dev/license_checker';
|
||||
|
||||
export default function licenses(grunt) {
|
||||
grunt.registerTask('licenses', 'Checks dependency licenses', async function () {
|
||||
const done = this.async();
|
||||
|
||||
try {
|
||||
const dev = Boolean(grunt.option('dev'));
|
||||
|
||||
// Get full packages list according dev flag
|
||||
const packages = await getInstalledPackages({
|
||||
directory: grunt.config.get('root'),
|
||||
licenseOverrides: LICENSE_OVERRIDES,
|
||||
dev
|
||||
});
|
||||
// Filter the packages only used in production
|
||||
const prodPackages = packages.filter(pkg => !pkg.isDevOnly);
|
||||
|
||||
// Assert if the found licenses in the production
|
||||
// packages are valid
|
||||
assertLicensesValid({
|
||||
packages: prodPackages,
|
||||
validLicenses: LICENSE_WHITELIST
|
||||
});
|
||||
|
||||
// Do the same as above for the packages only used in development
|
||||
// if the dev flag is found
|
||||
if (dev) {
|
||||
const devPackages = packages.filter(pkg => pkg.isDevOnly);
|
||||
|
||||
assertLicensesValid({
|
||||
packages: devPackages,
|
||||
validLicenses: LICENSE_WHITELIST.concat(DEV_ONLY_LICENSE_WHITELIST)
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
} catch (err) {
|
||||
grunt.fail.fatal(err);
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -3625,6 +3625,11 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/license-checker@15.0.0":
|
||||
version "15.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/license-checker/-/license-checker-15.0.0.tgz#685d69e2cf61ffd862320434601f51c85e28bba1"
|
||||
integrity sha512-dHZdn+VxvPGwKyKUlqi6Dj/t3Q4KFmbmPpsCOwagytr8P98jmz/nXzyxzz9wbfgpw72mVMx7PMlR/PT0xNsF7A==
|
||||
|
||||
"@types/listr@^0.14.0":
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/listr/-/listr-0.14.0.tgz#55161177ed5043987871bca5f66d87ca0a63a0b7"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue