今日は下記の記事で紹介していた、CIでOSSライセンスを自動チェック、のnpm辺について、別のツールを使った方法を紹介します。
というのも、こちらの記事で紹介した grunt-license-report
を職場で他のチームに導入しようとしたところ、同僚に「え、今更gruntとか将来性がなくね?このモジュール4年も更新されてないし」的なコメントを頂き、「あー、ツールの活性度とかあまり考えてなかったわ!」と反省したところなのでした。
そこで今回は、数あるnpmで管理されているライブラリのライセンスを収集するツールの中から、 license-checker
を使ってCIに組み込むところまでをやってみます。
2019年2月現在、Star数781, Fork 111, last published が a month ago、つまり先月ってことで十分活発なOSSではないでしょうか!
OSS情報一覧を生成する
対象のリポジトリ構成は前回と同じにします。
. ├── app │ ├── front │ │ ├── main.js │ │ ├── package.json │ └── test │ ├── package.json │ └── sample_test.js ├── infra └── tool └── license_check ├── license_config.yml └── npm ├── judge_npm_license.js └── package.json
ライセンスを確認したいモジュールは、 app/front/package.json の dependencies とします。※package.jsonの devDependencies は対象外とします。
tool 配下は今回のライセンスチェックのためのツールです。
まずは license-checker
をglobalにinstallします。
$ npm install -g license-checker
app/front ディレクトリで、package.json に記載されたpackage(とそれが依存しているpackage)をinstallします。
$ npm install
あとは license-checker --production
コマンドを走らせるだけです。
ここで --production
を指定しなければ、devDependencies
も対象になります。
$ license-checker --production ├─ accepts@1.3.5 │ ├─ licenses: MIT │ ├─ repository: https://github.com/jshttp/accepts │ ├─ path: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/accepts │ └─ licenseFile: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/accepts/LICENSE ├─ array-flatten@1.1.1 │ ├─ licenses: MIT │ ├─ repository: https://github.com/blakeembrey/array-flatten │ ├─ publisher: Blake Embrey │ ├─ email: hello@blakeembrey.com │ ├─ url: http://blakeembrey.me │ ├─ path: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/array-flatten │ └─ licenseFile: /Users/natsumi/workspace/git/npm_license_ci/app/front/ ~~(中略)~~ node_modules/xml2js/LICENSE └─ xmlbuilder@9.0.7 ├─ licenses: MIT ├─ repository: https://github.com/oozcitak/xmlbuilder-js ├─ publisher: Ozgur Ozcitak ├─ email: oozcitak@gmail.com ├─ path: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/xmlbuilder └─ licenseFile: /Users/natsumi/workspace/git/npm_license_ci/app/front/node_modules/xmlbuilder/LICENSE
こんな感じでだーーーーっと出力されます。
実行時のOptionで、開発用のpackageのみを対象にしたり、推測によるライセンス出力をすべてunknownと出力させたり、出力形式をjsonやcsvにしたりできます。Optionの詳細はこちらを参照
--unknown
optionは、個人的には安全側に倒すために入れておいたほうが良さそうかなーと思います。
csv形式で出力するとこんな感じ。非常に見やすいですね。
今回、このファイルは下記のようにして作成、出力しています。
$ license-checker --production --csv --out report/licernses.csv --unknown
許可していないライセンスのOSSがないかをチェック
ここからはCIに組み込んだりして、許可していないライセンスのOSSがないかをチェックします。
上記で tool 配下に配置されているライセンスチェックのためのスクリプト群の中身はこんな感じ。
license_config.yml
# 許可するライセンスのリスト。以下のリストは例。 allowed: - MIT - Apache-2.0 - BSD-3-Clause - ISC - Apache 2.0 # 許可するライセンス一覧にはないが、ライセンスに問題が無いことが確認できたライブラリ reviewed: npm: - hogehoge pip: - hogehoge # チェック対象外のライブラリ ignored: npm: - my-app # my-app pip: - my-app # my-app
tool/license_check/npm/package.json
{ "name": "grunt-license-tools", "version": "0.0.0", "license": "UNLICENSED", "dependencies": {}, "devDependencies": { "fs": "latest", "js-yaml": "latest" }, "private": true }
tool/license_check/npm/judge_npm_license.js
/******************************************************************** * 説明 * ========== * * license-checker で作成したライセンス一覧ファイル(csv)をパースし、 * 指定されたconfigファイルで許可されていないライセンスのライブラリがないかをチェックします。 * ※csv形式のファイル出力オプション付き license-checker コマンド * license-checker --csv --out {report_file_name}.csv * * パラメータ * ========== * * 1. パース対象のlicense一覧 csv ファイルパス * license-checker で作成したライセンス一覧ファイルのパス * e.g.) report/licenses.csv * * 2. configファイルパス * 使用を許可するライセンスや、確認済みのライブラリの設定が書かれたconfig fileのパス * e.g.) license_check_config.yml * * 返却値 * ========== * * exit 0: warningなしの場合 * exit 1: warningありの場合 * ********************************************************************/ const fs = require('fs'); const yaml = require('js-yaml') if (process.argv.length < 4) { throw new Error('Insufficient number of arguments.'); } const target_path = process.argv[2]; const config_path = process.argv[3]; var lines = fs.readFileSync(target_path, 'utf-8'); let libraries = {}; let warnings = {}; for (line of lines.split('\n')) { let project_name = '' name_with_version = line.split(',')[0].replace(/\"/g,''); library_name = name_with_version.split('/').pop().split('@')[0]; if (library_name != 'module name') { license = line.split(',')[1].replace(/\"/g,''); libraries[library_name] = license; } }; const config = yaml.safeLoad(fs.readFileSync(config_path), 'utf-8') Object.keys(libraries) .filter(key => !config.allowed.includes(libraries[key])) .filter(key => !config.reviewed.npm.includes(key)) .filter(key => !config.ignored.npm.includes(key)) .forEach(key => { warnings[key] = libraries[key] }); // result console.log('warnings: ') console.log(warnings) const result = 'RESULT: ' + Object.keys(libraries).length + ' dependencies checked, ' + Object.keys(warnings).length + ' warnings found.' console.log(result) // judge if (Object.keys(warnings).length > 0) { console.log('license check failed.') process.exit(1) }
必要なモジュールをinstallして、スクリプトを実行します。
$ cd tool/license_check/npm $ npm install $ node judge_npm_license.js ../../../app/front/report/licenses.csv ../license_config.yml
実行結果(例)
warnings: { argv: 'MIT*', atob: '(MIT OR Apache-2.0)', 'css-select': 'BSD-like', domutils: 'BSD*', 'my-app': 'UNKNOWN' } RESULT: 290 dependencies checked, 5 warnings found. license check failed.
warningが1つでもあれば異常終了、0件で正常終了します。
今回は特殊な書き方のライセンスが見つかっているので、一つ一つチェックし、問題なければ設定ファイル (license_check_config.yml) の allowed, reviewed, ignored の適切な箇所に追記します。
すべてのライセンスが問題なし、もしくはレビュー済・対象外になっている場合、下記のような出力になります。
warnings: {} RESULT: 290 dependencies checked, 0 warnings found.
まとめ
今回は、license-checkerを使って、npmで管理されているOSSライブラリのライセンスに問題ないかを確認する方法を紹介しました。また、これをCIに組み込むなどして、自動でチェックする際に利用できるスクリプト群を紹介しました。
前回紹介した grunt-license-report
と比較して、今回のpackage.jsonでは特に精度・パフォーマンス的な違いは見られませんでしたが、同僚からのアドバイスの通り、license-checkerのほうがよく使われている・メンテナンスがされている、という点でおすすめです。
関連記事
kusuwada.hatenablog.com kusuwada.hatenablog.com kusuwada.hatenablog.com kusuwada.hatenablog.com