😺

TypeScriptプロジェクトのCIでやってること

2021/07/09に公開

概要

最近退職に伴い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氏によるこんな記事が投稿されたので見直そうかなとも思ってます。

使われてないファイル等のチェック

以下のようなものを使うと使われていないファイルや変数・関数等を検知することができます。

不要なものはどんどん削除してメンテナンス性を高めていきましょう。

ちなみに残念ながら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