更新が必要なnpmパッケージを可視化する

こんにちは。ウェブアプリケーションエンジニアのid:masawadaです。普段は、はてなブログチームで開発を行なっています。

今回は、日々の開発で生まれた困りごとを解消するために作ったyarn-outdated-formatterというツールを紹介します。

経緯

以前id:amagitakayosiが「フロントエンドPodcastはじめました - Hatena Developer Blog」にて書いたとおり、はてなには現在「フロントエンドエンジニア」という肩書きのメンバーはいません。はてなブログチームでも全員がバックエンド(Perl)とフロントエンド(JavaScript)両方のコードを書いており、どちらかというとバックエンドがメインのためクライアントサイドは片手間になりがちという問題がありました。

そこで、チーム内でFWG(フロントエンド・ワーキング・グループ)という会を組織しました。FWGはワーキング・グループと言いつつも、基本的にはチームのエンジニア全員が参加してJavaScriptを用いたフロントエンド開発に関する現状の問題点や知見を共有する会です。

FWGで課題の一つとして挙がったのが「パッケージのアップデートタイミングを調整したい」ということでした。

npmパッケージの管理に関する課題意識

はてなブログではnpmパッケージをyarnで管理しており、これまで1ヶ月おきにアップデートデーを設けて必要に応じてパッケージを更新してきました。作業の流れは以下の通りです。

  • yarn outdatedで更新が必要なパッケージをリストする
  • 各パッケージのCHANGELOGを探して眺め、破壊的変更がないか確認する
  • パッケージを最新版に更新する
    • 破壊的な変更があり影響を受ける場合は、当該パッケージを利用しているコードを修正する
  • すべての変更をPull Requestにしてレビュー依頼する
  • レビュアーがCHANGELOGを眺め、更新に問題がないか確認する

最初の数回はこれに則って更新を行いましたが「CHANGELOGを探す工数がかかりすぎる」「定期的にやるには更新の数がまちまちすぎる」などの課題意識を抱えていました。特にCHANGELOGに関してはnpmパッケージのリポジトリ直下にあるとは限らず、GitHubのreleasesに書いてあったりそもそもない場合もあります。これを探してPull Requestにまとめるのにエンジニアの工数が半日近く割かれることもありました。

この課題を解決するために作成したツールがyarn-outdated-formatterです。

yarn-outdated-formatterとは

yarn outdatedには--jsonオプションをつけることで出力をJSON形式にする機能があります。このJSONを整形して任意の形式に変換するのがyarn-outdated-formatterです。このツールを用いることでnpmパッケージのアップデートにかかる労力を軽減することができます。

github.com

yarn-outdated-formatterの使い方

yarn-outdated-formatterは以下のコマンドでインストール、利用することができます。

$ yarn add -D yarn-outdated-formatter
$ yarn outdated --json | $(yarn bin)/format-yarn-outdated

更新が必要なパッケージが存在していた場合、SemVerでメジャーレベル、マイナーレベル、パッチレベルに分類して表示します。出力はMarkdown、JSON、Mackerelに対応しており、デフォルトでMarkdown形式で出力します。

先程のコマンドを実行すると以下のようなMarkdownの出力が得られます。

gist.github.com

出力形式を変更するには--formatオプションでmarkdownjsonmackerelのいずれかを指定します。

jQuery等を使っていてサポートするブラウザなどの関係からバージョンを固定したい場合は、それらのパッケージを出力から省略することができます。省略するには--excludesオプションで対象のパッケージ名を記述したYAMLファイルのパスを指定します。YAMLは以下のように記述してください。

- jquery
- tinymce
- ...

yarn-outdated-formatterでは、各パッケージのCHANGELOGへの参照をYAMLファイルにまとめておき、出力する際に添付することもできます。CHANGELOG情報を添付するには、事前に以下のようなYAMLファイルを作成しておき、--changelogsオプションでそのファイルパスを指定します。

react: https://github.com/facebook/react/blob/master/CHANGELOG.md
eslint: https://github.com/eslint/eslint/blob/master/CHANGELOG.md
babel-eslint: https://github.com/babel/babel-eslint/releases
...

はてなブログでは、これらのオプションを組み合わせて出力したMarkdownをPull Requestに貼り付けてレビュー依頼を行なっています。パッケージのバージョンやCHANGELOGの情報がまとまった状態で出力されるため、作業者がこれらの情報をまとめるコストとレビューにかかるコストの両方を軽減することができました。

以下のGistは、はてなブログで実際に使用しているchangelogs.ymlです。アップデートをする度に対象のCHANGELOGがなければ継ぎ足しています。

さらに便利につかう

他のコマンドと組み合わせることでさらに便利に使うこともできます。

更新が必要なパッケージ数をMackerelに投稿する

mkrコマンドを使うことで、更新が必要なパッケージ数をMackerelのサービスメトリックとして投稿することができます。mkrについては以下を参照ください。

mackerel.io

APIキーを設定した上で以下のコマンドを実行するとメトリックを投稿できます。

$ yarn outdated --json | $(yarn bin)/format-yarn-outdated --format mackerel | mkr throw --service ServiceMetricName

はてなブログでは、このコマンドをCIで毎朝8時に定期実行しています。以下の画像は4月上旬からの更新が必要なパッケージ数の推移です。パッケージの更新を行った4月17日の翌日に数が減っていることが確認できるかと思います。

f:id:masawada:20170606112848p:plain

(一時的に爆発的に増えている瞬間は、もともとPerlで書いていたyarn-outdated-formatterをJavaScript製のものに変更した際に発生したものです)

マイナーレベルとパッチレベルの更新のみを適用する

jqxargsを組み合わせることで、任意のレベルの更新だけを適用することができます。例えば、マイナーレベルとパッチレベルの更新を適用したい場合は、以下のようなコマンドを実行します。

$ yarn outdated --json | $(yarn bin)/format-yarn-outdated --format json | jq '.minor[],.patch[] | .[0]' | xargs -I{} yarn upgrade {}

このコマンドを実行することで、マイナーレベルとパッチレベルの更新についてpackage.jsonに書かれているバージョンの範囲指定を無視して適用することができます。

さいごに

このツールを作成したことでnpmパッケージのCHANGELOG情報を集約することができ、これまで毎月更新にかかっていたエンジニアの工数を減らすことができました。是非みなさんもご利用ください。

はてなでは、便利ツールを作成して開発の効率を爆上げしたいエンジニアを募集しています。

hatenacorp.jp