TypeScriptプロジェクトのCIでやってること
概要
最近退職に伴いTypeScriptプロジェクトのCI/CDの見直しを行っているので主にプルリクに対するCIを中心に何をやっているのか(やっていた&やろうとしているもの含む)紹介します。
それぞれはさらっとした紹介のみです。
ちなみに書いてから気づいたんですが殆どTS以外でもできます。
tsc, prettier, eslint
基本です。恐らく殆どのプロジェクトでやっているかと思います。
tsc
は--noEmit
オプションを付けて実行、eslint
は--cache
と--quiet
オプションを付けて実行しています。
prettier
は--list-different
オプションを付けると差分があった場合(=prettier
が適用されていないファイルがあった場合)にエラーにしてくれます。
CIでWebpack等でバンドルしてる場合はこの辺を明示的に行わなくてもそこでコケるのでやってないケースもあるかもしれません。
ユニットテスト
これも基本かと思います。
Codecov等を使っていればカバレッジのトラッキングやプルリクのコードがどれくらいカバレッジに影響しているか等を見ることができます。
でも先日のインシデントでCodecov嫌いになってしまった人もいるかもしれません。
ちなみにjest
だとfindRelatedTests
オプションを使って変更されたファイルに関するユニットテストのみ走らせることができます。
precommit hook
ではfindRelatedTests
を使い、CIではカバレッジ計測のために全部走らせるといったケースが多いかと思います。
脆弱なパッケージをチェック
npm/yarn audit
を使って脆弱性が存在するパッケージを使っていないかチェックします。
Dependabotを使っているプロジェクトは多いと思いますが、プルリクの時点でもチェックできた方が良いかと思います。
CIだと以下のようにするとレベルがHIGH以上の脆弱性が含まれていた場合はエラーにしてくれます。
/bin/bash -c 'yarn audit --groups dependencies --level high; [[ $? -ge 8 ]] && exit 1 || exit 0'
なんでこんなHackyな感じになっているのかと言うとこのIssueにあるとおりyarn audit
の戻り値の挙動のためです。
入れといた方が良いかなと思いますが、つい最近React界隈で有名なDan Abramov氏によるこんな記事が投稿されたので見直そうかなとも思ってます。
使われてないファイル等のチェック
以下のようなものを使うと使われていないファイルや変数・関数等を検知することができます。
- https://github.com/pzavolinsky/ts-unused-exports
- https://github.com/tomchentw/unused-files-webpack-plugin/
不要なものはどんどん削除してメンテナンス性を高めていきましょう。
ちなみに残念ながらWebpackのは5系に非対応です。
textlint
textlintはテキストファイルやマークダウンファイル用のlintツールです。eslintのように様々なルールを追加することが出来ます。また、プラグインを追加することでhtml
ファイル等にも対応できるようになります。
テキストファイルでもコード同様ある程度の一貫性を持たせたり表記の揺れを排除したりできるので非常に有用です。
$ textlint --rule terminology README.md
/path/to/README.md
11:21 ✓ error Incorrect usage of the term: “markdown”, use “Markdown” instead terminology
11:50 ✓ error Incorrect usage of the term: “repo”, use “repository” instead terminology
13:40 ✓ error Incorrect usage of the term: “repo”, use “repository” instead terminology
Dead linkをチェック
markdown-link-checkを使ってマークダウンファイルのリンク切れを検知します。
README等にリンク切れがあると新メンバー参画時等に不要なQ&Aが発生したりするのでやっておくと良いのではないでしょうか。
使い方は以下の通りシンプルな感じです。
$ yarn add -D markdown-link-check
$ markdown-link-check ./README.md
FILE: ./README.md
[✓] https://www.example.com
[✖] https://www.exampleeeeeeeeeee.com
Typoチェック
misspell-fixerを使うとコードのTypoをチェックしてくれます。
Typoの修正もできてコマンドラインからの使い方は以下のような感じです。
./misspell-fixer -frunRVD /path/to/src
オプションは公式サイトをご確認ください。
上記の例を簡単に説明するとバックアップ取らずに上書きするファストモードで色々レアなルールを有効にしてる感じです。
何も検知しなかった場合は0、検知した場合は0以外を返してくれるのでCIではそのまま実行するだけでOKです。
一度全部修正したコードをマージしたあとでCIでのTypoチェックをすると良いんじゃないでしょうか。
ちなみに弊社のコードで実行した一例はこんな感じでした。
Camel Caseにもちゃんと対応していることが分かります。
似たようなツールでPython製のcodespellとかもあります。
利用しているパッケージのLicenseをチェック
Copyleftなパッケージを使ってしまっていたりすると問題な場合等はlicense-checkerを使ってインストールされたパッケージのライセンスをチェックすることができます。
普通にシンプルにインストールして走らせるだけで使えます。
yarn add -D license-checker
license-checker
オプションとして--production
を付けるとdependencies
のみを対象としてくれます。またCIでは--onlyAllow
もしくは--failOn
を使って許可したいもしくは禁止したいライセンスのリストを渡すとそれ以外のライセンスのdependencyがあった場合にエラーに出来ます。
ただし残念ながらCopyleftなもの全部みたいな指定はできません。
Accessibilityをチェック
アクセシビリティのチェックはaxe-coreを使っているところが多いと思います。
axe-storybook-testingを使うとStorybookに対するチェックが簡単に出来て便利です。
(ちなみにチャン・ザッカーバーグ・イニシアティブ製です。こんなの作ってるんですね。)
実行すると成功したものと失敗したものを表示してくれます。以下スクリーンショットの一部ですがfailが多すぎますねw
ちなみにがっつりやるなら恐らくaxe-coreを作っているDequeを使うのかと思いますが、残念ながら今の所利用経験はありません。
バンドルサイズのチェック
Webpackでバンドルしたもののサイズチェックにはbundlewatchが使えます。
それぞれのchunkが指定したサイズ以上であればCIでエラーにするといったことができます。
CIで毎回バンドリングするのは時間がかかるので、package.json
に変更があったときと変更されたコードのサイズが大きかったときだけとかにするのも良いかと思います。
より詳細にサイズの内訳を見たい場合はwebpack-bundle-analyzerを使うと良いです。
レポートがhtmlなのでどこかにホストしておけばチームでの共有も楽です。
danger-jsで色々な項目をチェック
danger-jsを使うとプルリクがIssueに紐付いているか、コメントが適切なフォーマットに従っているか、プルリクのサイズが既定値を超えていないか、といった様々なチェックを行うことができます。プロジェクトに合わせたカスタマイズも容易で公式サイトに便利な例が色々載っているので是非ご覧ください。
Static Code Analysis
eslintが静的コード解析的な側面も持っていますが補完する形で別のツールを使うことも多いかと思います。
ライトにやるならコマンドラインから簡単に実行できるsemgrep、がっつりやるならUIもついてくるSonarQubeが良いと思います。
どちらもTypeScript以外の言語にも対応しています。
semgrep
はここからルールセットを探すことができ、React用のルールセット等様々なものがあります。
まだEarly AccessですがJetBrainsのQodanaも良さそうです。
ちなみにOWASPのサイトには静的コード解析ツールのリストがあるのでこちらを参考に探してみると良いかもしれません。
プルリクごとにユニークな環境にデプロイ
フロントエンドのプロジェクトだとNetlify等を使っていれば簡単にプルリクごとにユニークなURLでプレビュー版のデプロイができるので、マージ前の動作確認やテストが楽です。
バックエンドをプルリクごとにデプロイする場合は、実際に本番環境と同じような構成でデプロイしてしまってマネージドサービスは開発環境共通のものに繋ぐパターンか、マネージドサービスはlocalstack的なものでモックして全部コンテナに詰めてデプロイするパターンのいずれかが一般的かと思います。
ドキュメント生成
デプロイプレビューがあるサービスを使っている場合以外はマージされたときのみですが、またCIよりCD寄りかもしれませんが、typedoc等でドキュメント生成してどこかにホストしておくとチーム間で簡単に共有できて便利です。
typedocは公式のデモがここにあります。
あとはテストレポートの生成・デプロイや、フロントエンドのプロジェクトだとStorybookの生成・デプロイも同じタイミングでやるのが良いかと思います。
最後に
ということでTypeScriptのCIでやっていることを色々と紹介してみました。
随時更新する予定です。他にもこれはやったほうが良いみたいのがあれば教えてください。
Happy DevOpsing!
Discussion