diff --git a/README.md b/README.md index 127cd11..f42ee45 100644 --- a/README.md +++ b/README.md @@ -9,24 +9,29 @@ -Utility to deal with Uber OSS licences +**Utility to deal with Uber OSS licences** ## Example -`uber-licence` - -Running the `uber-licence` binary adds licencing information +```shell +> uber-licence +``` +Running the `uber-licence` binary adds licencing information to every javascript file in your project. -You can run `uber-licence --dry` where it does not - mutate any files and instead outputs -1. +You can run `uber-licence --dry` where it does not mutate + any files and instead outputs -1. -You can use `--file` and `--dir` to specify your own file - and directory filters to select source files to consider. +You can use `--file` and `--dir` flags to specify your own + file and directory filters to select source files to consider. -## Recommended usage +Use the `-h` or `--help` flags to see all the available options. -```js +## Recommended Config + +We recommend that you add the following two scripts to your `package.json` and run `check-licence` in a git pre-commit. + +```json // package.json { "scripts": { @@ -45,22 +50,61 @@ You can use `--file` and `--dir` to specify your own file } ``` -We recommend you add two scripts to your package and run - `check-licence` in a git pre commit. - ## Installation -`npm install uber-licence` +```shell +> npm install uber-licence --save-dev +``` + +## CLI Usage + +```shell +> uber-licence [options] +``` + +## NodeJS API + +```js +var uberLicence = require('uber-licence'); +uberLicence(options); +``` + +## Options: + +| API | CLI | Type | Default | Description | +| --- | --- | --- | --- | --- | +|`dry` |`-d`, `--dry` |`Boolean`|`false` | does not write to files | +|`file` |`-F`, `--file` |`String` |`*.js` | pattern of files to modify | +| | |`Array`[*](#n0)| | | +|`dir` |`-D`, `--dir` |`String` |`.*`[1](#n1)| list of directory patterns containing files | +| | |`Array`[*](#n0)| | | +|`license`|`-L`, `--license`|`String` |`undefined`| intended license template (file)[2](#n2) | +| | |`Array`[*](#n0)| | | +|`legacy` |`-O`, `--legacy` |`String` |`undefined`| list of licenses to replace | +| | |`Array`[*](#n0)| | | +|`verbose`|`-v`, `--verbose`|`Boolean`|`false` | log skipped and empty files | +|`silent` |`-s`, `--silent `|`Boolean`|`false` | do not log fixed files | + +* *On CLI use comma to separate multiple values* +eg: `--flag=a,b,c` or `--flag a,b,c` + +1 *The following directories are excluded by default:* +`.git, node_modules, coverage, env, .tox, vendor, Godeps` + +2 *by default uses Uber's templates* ## Tests -`npm test` +```shell +> npm test +``` ## Contributors - [Raynos](https://github.com/raynos) - [Kriskowal](https://github.com/kriskowal) - [Dawsonbotsford](https://github.com/dawsonbotsford) + - [CxRes](https://github.com/cxres) ## MIT Licenced diff --git a/bin/licence.js b/bin/licence.js index 3c94ad7..b3db4e9 100755 --- a/bin/licence.js +++ b/bin/licence.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -// Copyright (c) 2017 Uber Technologies, Inc. +// Copyright (c) 2018 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -21,145 +21,60 @@ 'use strict'; -var readdirp = require('readdirp'); var minimist = require('minimist'); -var fs = require('fs'); -var process = require('process'); -var console = require('console'); -// automatically prompt user to update if on older version -var updateNotifier = require('update-notifier'); -var pkg = require('../package.json'); -updateNotifier({pkg: pkg}).notify(); - -var LicenseFixer = require('../license-fixer'); - -var VALID_LICENSES = require('../valid-licences.js'); - -var argv = minimist(process.argv.slice(2)); -var cwd = process.cwd(); +var uberLicense = require('../index.js'); + +var argv = minimist(process.argv.slice(2), { + boolean: [ + 'dry', + 'verbose', + 'silent', + 'help' + ], + string: [ + 'file', + 'dir', + 'license', + 'legacy' + ], + alias: { + license: ['licence', 'L'], + file: 'F', + dir: 'D', + legacy: 'O', + dry: 'd', + verbose: 'v', + silent: 's', + help: 'h' + } +}); -/*eslint no-process-exit: 0, no-console: 0*/ +/*eslint no-console: 0*/ // jscs:disable maximumLineLength -if (argv.help || argv.h) { +if (argv.help) { console.log('uber-licence'); console.log(' '); console.log(' This binary will add a license to the top'); console.log(' of all your files'); console.log(''); console.log(' Options:'); - console.log(' --dry does not write to files'); - console.log(' --file pattern of files to modify'); - console.log(' --dir pattern for directories containing files'); - console.log(' --license intended license (file)'); - console.log(' --legacy licenses to replace'); - console.log(' --verbose log skipped and empty files'); - console.log(' --silent do not log fixed files'); - process.exit(0); -} - -var fileFilter = ['*.js']; -if (typeof argv.file === 'string') { - fileFilter = [argv.file]; -} else if (Array.isArray(argv.file)) { - fileFilter = argv.file; -} - -var directoryFilter = ['!.git', '!node_modules', '!coverage', '!env', '!.tox', '!vendor', '!Godeps']; -if (typeof argv.dir === 'string') { - directoryFilter = [argv.dir]; -} else if (Array.isArray(argv.dir)) { - directoryFilter = argv.dir; -} - -var licenses = null; - -if (typeof argv.license === 'string') { - licenses = licenses || []; - licenses.push(argv.license); -} else if (Array.isArray(argv.license)) { - licenses = licenses || []; - Array.prototype.push.apply(licenses, argv.license); -} - -// licence non-American spelling -if (typeof argv.licence === 'string') { - licenses = licenses || []; - licenses.push(argv.licence); -} else if (Array.isArray(argv.licence)) { - licenses = licenses || []; - Array.prototype.push.apply(licenses, argv.licence); -} - -if (typeof argv.legacy === 'string') { - licenses = licenses || []; - licenses.push(argv.legacy); -} else if (Array.isArray(argv.legacy)) { - licenses = licenses || []; - Array.prototype.push.apply(licenses, argv.legacy); -} - -if (licenses) { - for (var i = 0; i < licenses.length; i++) { - // Replace file names with content of files - licenses[i] = fs.readFileSync(licenses[i], 'utf8'); - } -} else { - // In the absense of any command line arguments, - // use the Uber defaults. - licenses = VALID_LICENSES; + console.log(' -d, --dry does not write to files'); + console.log(' -F, --file pattern of files to modify'); + console.log(' -D, --dir pattern for directories containing files'); + console.log(' -L, --license intended license template (file)'); + console.log(' -O, --legacy licenses to replace'); + console.log(' -v, --verbose log skipped and empty files'); + console.log(' -s, --silent do not log fixed files'); } - -var licenseFixer = new LicenseFixer({ - dry: argv.dry, - silent: argv.silent, - verbose: argv.verbose -}); - -// Set the intended license text -licenseFixer.setLicense(licenses[0]); -// Add a license to match and replace. -// There can be multiple recognized licenses, for migration purposes. -for (var i = 0; i < licenses.length; i++) { - licenseFixer.addLicense(licenses[i]); -} - -readTree({ - root: cwd, - fileFilter: fileFilter, - directoryFilter: directoryFilter -}, processFiles); - -function readTree(options, callback) { - var stream = readdirp(options); - var files = []; - stream.on('data', onData); - stream.on('end', onEnd); - stream.on('error', onEnd); - function onData(event) { - files.push(event.path); - } - function onEnd(err) { - callback(err, files); - } -} - -function processFiles(err, files) { - if (err) { - console.error(err.message); - process.exit(1); - return; - } - - var fixed = 0; - for (var filesIndex = 0; filesIndex < files.length; filesIndex++) { - var file = files[filesIndex]; - fixed = fixed + licenseFixer.fixFile(file); - } - - if (argv.dry) { - process.exit(fixed); - } else { - process.exit(0); - } +else { + uberLicense({ + dry: argv.dry, + silent: argv.silent, + verbose: argv.verbose, + fileFilter: argv.file && argv.file.split(','), + directoryFilter: argv.dir && argv.dir.split(','), + license: argv.license && argv.license.split(','), + legacy: argv.legacy && argv.legacy.split(',') + }); } diff --git a/defaults.js b/defaults.js new file mode 100644 index 0000000..5444b4b --- /dev/null +++ b/defaults.js @@ -0,0 +1,35 @@ +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +module.exports = { + directoryFilter: [ + '!.git', + '!node_modules', + '!coverage', + '!env', + '!.tox', + '!vendor', + '!Godeps' + ], + + fileFilter: [ + '*.js' + ] +}; diff --git a/index.js b/index.js new file mode 100644 index 0000000..a342a8c --- /dev/null +++ b/index.js @@ -0,0 +1,132 @@ +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +var fs = require('fs'); +var readdirp = require('readdirp'); + +var defaults = require('./defaults'); +var LicenseFixer = require('./license-fixer'); +var VALID_LICENSES = require('./valid-licences'); + +// automatically prompt user to update if on older version +var updateNotifier = require('update-notifier'); +var pkg = require('./package.json'); +updateNotifier({pkg: pkg}).notify(); + +function uberLicense(options) { + var dry = options.dry; + var silent = options.silent; + var verbose = options.verbose; + + if (options.licence && !options.license) { + options.license = options.licence; + } + + // If the user enter string when using the API version + var licenses = (typeof options.license === 'string') ? + [options.license] : options.license; + + var legacy = (typeof options.legacy === 'string') ? + [options.legacy] : options.legacy; + + if (licenses) { + for (var i = 0; i < licenses.length; i++) { + // Replace file names with content of files + licenses[i] = fs.readFileSync(licenses[i], 'utf8'); + } + } else { + // In the absense of any command line arguments, + // use the Uber defaults. + licenses = VALID_LICENSES; + } + + // Legacy should not override default license + if (legacy) { + for (var j = 0; j < legacy.length; j++) { + // Replace file names with content of files + licenses[licenses.length + j] = fs.readFileSync(legacy[j], 'utf8'); + } + } + + var licenseFixer = new LicenseFixer({ + dry: dry, + silent: silent, + verbose: verbose + }); + + // Set the intended license text + licenseFixer.setLicense(licenses[0]); + // Add a license to match and replace. + // There can be multiple recognized licenses, for migration purposes. + licenses.forEach(function(license) { + licenseFixer.addLicense(license); + }); + + // If the user enters a string argument when using the API version + var fileFilter = (typeof options.fileFilter === 'string') ? + [options.fileFilter] : options.fileFilter; + + var directoryFilter = (typeof options.directoryFilter === 'string') ? + [options.directoryFilter] : options.directoryFilter; + + readTree({ + root: process.cwd(), + fileFilter: fileFilter || defaults.fileFilter, + directoryFilter: directoryFilter || defaults.directoryFilter, + }, processFiles); + + function readTree(opts, callback) { + var stream = readdirp(opts); + var files = []; + stream.on('data', onData); + stream.on('end', onEnd); + stream.on('error', onEnd); + function onData(event) { + files.push(event.path); + } + function onEnd(err) { + callback(err, files); + } + } + + + function processFiles(err, files) { + if (err) { + console.error(err.message); + process.exit(1); + return; + } + + var fixed = 0; + for (var filesIndex = 0; filesIndex < files.length; filesIndex++) { + var file = files[filesIndex]; + fixed = fixed + licenseFixer.fixFile(file); + } + + if (dry) { + process.exit(fixed); + } else { + process.exit(0); + } + } +} + + +module.exports = uberLicense; \ No newline at end of file diff --git a/license-fixer.js b/license-fixer.js index 15c9ddc..b86483b 100644 --- a/license-fixer.js +++ b/license-fixer.js @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Uber Technologies, Inc. +// Copyright (c) 2018 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json index 479a707..d5f0c43 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uber-licence", - "version": "3.1.1", + "version": "3.2.0", "description": "Utility to deal with Uber OSS licences", "keywords": [], "author": "Raynos ", diff --git a/test/index.js b/test/index.js index c382dc1..86426e8 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Uber Technologies, Inc. +// Copyright (c) 2018 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,11 +24,12 @@ var fs = require('fs-extra'); var temp = require('temp'); var exec = require('child_process').exec; var esc = require('escape-string-regexp'); +var os = require('os'); -// Automatically track and cleanup files at exit -temp.track(); - -var uberLicensePath = path.join(__dirname, '..', 'bin', 'licence.js'); +var uberLicenseCall = path.join(__dirname, '..', 'bin', 'licence.js'); +if (os.platform() === 'win32') { + uberLicenseCall = 'node ' + uberLicenseCall; +} tape('add-header', function (t) { t.plan(2); @@ -38,22 +39,25 @@ tape('add-header', function (t) { var outputFileContent = fs.readFileSync(path.join(fixturePath, 'output.js'), 'utf8'); // remove the dynamic year portion of the header comment - var consistentOutputString = "^".concat(esc(outputFileContent).replace(new RegExp(/\d{4}/), "\\d{4}")); + var consistentOutputString = "^".concat( + esc(outputFileContent).replace(new RegExp(/\d{4}/), "\\d{4}").replace(new RegExp(/\r?\n/g), "\\r?\\n") + ); var outputRegex = new RegExp(consistentOutputString); temp.mkdir('add-header', function(mkTempErr, dirPath) { if (mkTempErr) { return console.error('mkTempErr: ' + mkTempErr); } - process.chdir(dirPath); - fs.copySync(input1FilePath, 'input-1.js'); - fs.copySync(input2FilePath, 'input-2.js'); - exec(uberLicensePath, function(execErr) { + + fs.copySync(input1FilePath, path.join(dirPath, 'input-1.js')); + fs.copySync(input2FilePath, path.join(dirPath, 'input-2.js')); + exec(uberLicenseCall, { cwd: dirPath }, function(execErr) { if (execErr instanceof Error) { throw execErr; } - var input1FileContent = fs.readFileSync('input-1.js', 'utf8'); - var input2FileContent = fs.readFileSync('input-2.js', 'utf8'); + var input1FileContent = fs.readFileSync(path.join(dirPath, 'input-1.js'), 'utf8'); + var input2FileContent = fs.readFileSync(path.join(dirPath, 'input-2.js'), 'utf8'); + temp.cleanupSync(); t.true(outputRegex.test(input1FileContent), 'should prepend header to file without header'); t.true(outputRegex.test(input2FileContent), 'should replace old header (from 2016)'); @@ -73,28 +77,35 @@ tape('add-nonstandard-header', function (t) { var output3FileContent = fs.readFileSync(path.join(fixturePath, 'output-3.js'), 'utf8'); // remove the dynamic year portion of the header comment - var consistentOutputString = "^".concat(esc(output1FileContent).replace(new RegExp(/\d{4}/), "\\d{4}")); + var consistentOutputString = "^".concat( + esc(output1FileContent).replace(new RegExp(/\d{4}/), "\\d{4}").replace(new RegExp(/\r?\n/g), "\\r?\\n") + ); var output1Regex = new RegExp(consistentOutputString); - consistentOutputString = "^".concat(esc(output2FileContent).replace(new RegExp(/\d{4}/), "\\d{4}")); + consistentOutputString = "^".concat( + esc(output2FileContent).replace(new RegExp(/\d{4}/), "\\d{4}").replace(new RegExp(/\r?\n/g), "\\r?\\n") + ); var output2Regex = new RegExp(consistentOutputString); - consistentOutputString = "^".concat(esc(output3FileContent).replace(new RegExp(/\d{4}/), "\\d{4}")); + consistentOutputString = "^".concat( + esc(output3FileContent).replace(new RegExp(/\d{4}/), "\\d{4}").replace(new RegExp(/\r?\n/g), "\\r?\\n") + ); var output3Regex = new RegExp(consistentOutputString); temp.mkdir('add-header', function(mkTempErr, dirPath) { if (mkTempErr) { return console.error('mkTempErr: ' + mkTempErr); } - process.chdir(dirPath); - fs.copySync(input1FilePath, 'input-1.js'); - fs.copySync(input2FilePath, 'input-2.js'); - fs.copySync(input3FilePath, 'input-3.js'); - exec(uberLicensePath, function(execErr) { + + fs.copySync(input1FilePath, path.join(dirPath, 'input-1.js')); + fs.copySync(input2FilePath, path.join(dirPath, 'input-2.js')); + fs.copySync(input3FilePath, path.join(dirPath, 'input-3.js')); + exec(uberLicenseCall, { cwd: dirPath }, function(execErr) { if (execErr instanceof Error) { throw execErr; } - var input1FileContent = fs.readFileSync('input-1.js', 'utf8'); - var input2FileContent = fs.readFileSync('input-2.js', 'utf8'); - var input3FileContent = fs.readFileSync('input-3.js', 'utf8'); + var input1FileContent = fs.readFileSync(path.join(dirPath, 'input-1.js'), 'utf8'); + var input2FileContent = fs.readFileSync(path.join(dirPath, 'input-2.js'), 'utf8'); + var input3FileContent = fs.readFileSync(path.join(dirPath, 'input-3.js'), 'utf8'); + temp.cleanupSync(); t.true(output1Regex.test(input1FileContent), 'should have flow, then blank line, then license'); t.true(output2Regex.test(input2FileContent), 'should have shebang, then blank line, then license'); @@ -111,20 +122,23 @@ tape('dont-add-header', function (t) { var outputFileContent = fs.readFileSync(path.join(fixturePath, 'output.js'), 'utf8'); // remove the dynamic year portion of the header comment - var consistentOutputString = "^".concat(esc(outputFileContent).replace(new RegExp(/\d{4}/), "\\d{4}")); + var consistentOutputString = "^".concat( + esc(outputFileContent).replace(new RegExp(/\d{4}/), "\\d{4}").replace(new RegExp(/\r?\n/g), "\\r?\\n") + ); var outputRegex = new RegExp(consistentOutputString); temp.mkdir('dont-add-header', function(mkTempErr, dirPath) { if (mkTempErr) { return console.error('mkTempErr: ' + mkTempErr); } - process.chdir(dirPath); - fs.copySync(inputFilePath, 'input.js'); - exec(uberLicensePath, function(execErr) { + + fs.copySync(inputFilePath, path.join(dirPath, 'input.js')); + exec(uberLicenseCall, { cwd: dirPath }, function(execErr) { if (execErr instanceof Error) { throw execErr; } - var inputFileContent = fs.readFileSync('input.js', 'utf8'); + var inputFileContent = fs.readFileSync(path.join(dirPath, 'input.js'), 'utf8'); + temp.cleanupSync(); t.true(outputRegex.test(inputFileContent), 'should prepend header'); t.end(); diff --git a/valid-licences.js b/valid-licences.js index cb48efc..5079ccf 100644 --- a/valid-licences.js +++ b/valid-licences.js @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Uber Technologies, Inc. +// Copyright (c) 2018 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal