diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 29bf8453fd..5e9c8ac614 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -81,6 +81,13 @@ npm-e2e: - yarn - yarn test:e2e:npm +check-licenses: + stage: test + tags: ['runner:main', 'size:large'] + image: $CI_IMAGE + script: + - node --no-warnings scripts/check-licenses.js + unit-cbt: except: refs: diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index 179567e4cd..b20c77b3ec 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -5,6 +5,7 @@ require,tslib,Apache-2.0,Copyright Microsoft Corporation require,url-polyfill,MIT,Copyright 2017 Valentin Richard file,tracekit,MIT,Copyright 2013 Onur Can Cakmak and all TraceKit contributors dev,@types/jasmine,MIT,Copyright Microsoft Corporation +dev,@types/lodash.assign,MIT,Copyright Microsoft Corporation dev,@types/lodash.merge,MIT,Copyright Microsoft Corporation dev,@types/request,MIT,Copyright Microsoft Corporation dev,@types/sinon,MIT,Copyright Microsoft Corporation @@ -16,6 +17,7 @@ dev,@wdio/selenium-standalone-service,MIT,Copyright JS Foundation and other cont dev,@wdio/spec-reporter,MIT,Copyright JS Foundation and other contributors dev,@wdio/sync,MIT,Copyright JS Foundation and other contributors dev,body-parser,MIT,Copyright 2014 Jonathan Ong 2014-2015 Douglas Christopher Wilson +dev,codecov,MIT,Copyright 2014 Gregg Caines dev,cors,MIT,Copyright 2013 Troy Goode dev,express,MIT,Copyright 2009-2014 TJ Holowaychuk 2013-2014 Roman Shtylman 2014-2015 Douglas Christopher Wilson dev,istanbul-instrumenter-loader,MIT,Copyright JS Foundation and other contributors @@ -30,6 +32,7 @@ dev,karma-spec-reporter,MIT,Copyright 2015 Michael Lex dev,karma-typescript-preprocessor2,MIT,Copyright 2015 Cleiton Gomes Loiola dev,karma-webpack,MIT,Copyright JS Foundation and other contributors dev,lerna,MIT,Copyright 2015-present Lerna Contributors +dev,morgan,MIT,Copyright 2014 Jonathan Ong 2014-2017 Douglas Christopher Wilson dev,npm-run-all,MIT,Copyright 2015 Toru Nagashima dev,prettier,MIT,Copyright James Long and contributors dev,replace-in-file,MIT,Copyright 2015-2019 Adam Reis diff --git a/scripts/check-licenses.js b/scripts/check-licenses.js new file mode 100644 index 0000000000..3974ae2aa6 --- /dev/null +++ b/scripts/check-licenses.js @@ -0,0 +1,69 @@ +'use strict' + +const fs = require('fs') +const path = require('path') +const readline = require('readline') +const util = require('util') +const exec = util.promisify(require('child_process').exec) + +const LICENSE_FILE = 'LICENSE-3rdparty.csv' + +async function main() { + const packageJsonPaths = await findPackageJsonPaths() + + console.log(`Look for dependencies in:\n`, packageJsonPaths) + const declaredDependencies = withoutDuplicates(packageJsonPaths.flatMap(retrievePackageJsonDependencies)).sort() + + const declaredLicenses = (await retrieveLicenses()).sort() + + if (JSON.stringify(declaredDependencies) !== JSON.stringify(declaredLicenses)) { + console.error(`\n❌ package.json dependencies and ${LICENSE_FILE} mismatch`) + console.error( + `\nIn package.json but not in ${LICENSE_FILE}:\n`, + declaredDependencies.filter((d) => !declaredLicenses.includes(d)) + ) + console.error( + `\nIn ${LICENSE_FILE} but not in package.json:\n`, + declaredLicenses.filter((d) => !declaredDependencies.includes(d)) + ) + throw new Error('dependencies mismatch') + } + console.log(`\n✅ All dependencies listed in ${LICENSE_FILE}`) +} + +async function findPackageJsonPaths() { + const { stdout } = await exec('find . -path "*/node_modules/*" -prune -o -name "package.json" -print') + return stdout.trim().split('\n') +} + +function retrievePackageJsonDependencies(packageJsonPath) { + const packageJson = require(path.join(__dirname, '..', packageJsonPath)) + + return Object.keys(packageJson.dependencies || {}) + .concat(Object.keys(packageJson.devDependencies || {})) + .filter((dependency) => !dependency.includes('@datadog')) +} + +function withoutDuplicates(a) { + return [...new Set(a)] +} + +async function retrieveLicenses() { + const fileStream = fs.createReadStream(path.join(__dirname, '..', LICENSE_FILE)) + const rl = readline.createInterface({ input: fileStream }) + const licenses = [] + let header = true + for await (const line of rl) { + const csvColumns = line.split(',') + if (!header && csvColumns[0] !== 'file') { + licenses.push(csvColumns[1]) + } + header = false + } + return licenses +} + +main().catch((e) => { + console.error('\nStacktrace:\n', e) + process.exit(1) +})