コミット時にMarkdownファイルの構文が正しいかnpm testでチェックさせる

By raimon, 2015-05-01(金), in category Node

CI, Git, Markdown, Node

静的ページジェネレータHexoで作成したブログをGitHub Pagesで公開するの記事で作成したブログのGitリポジトリに対して、コミット時にMarkdownファイルの構文チェックさせる方法は無いか調べた。

依存ツール

次のツールを利用することで可能だった。

これらを --save-dev オプションを指定してインストールする。

$ npm install markdownlint husky glob --save-dev

テストを書く

test/markdown.js として、Hexoのブログ記事生成元となるMarkdownファイル全体を構文チェックするテストを記述する。

options.config には relaxed.jsonのようなJSONファイルで定義したルールを渡しても良いようだ。

var result = markdownlint.sync(options) で同期的に実行したチェック結果が返るので、その文字列表現としてエラー情報が取得できたか否かを見ている。

var markdownlint = require("markdownlint"),
    glob = require("glob"),
    options = {
        "files": glob.sync("blog/source/_posts/*.md"),
        "config": {
            "default": true,
            "MD007": {"indent": 4}
        }
    };

var result = markdownlint.sync(options),
    resultString = result.toString();

if (resultString.length > 0) {
    console.log(resultString);
    process.exit(1);
} else {
    console.log("Markdown Syntax OK");
    process.exit(0);
}

標準付属しているassertモジュールを使うべきかと考えたが、上手くアサーションで表現する方法が思いつかなかった。よって、原始的なやり方だが終了コードで失敗させることにした。

run-scriptとして実行可能にする

テストコードが完成したのでリポジトリルートに package.json を置いて、コミット時に自動実行されるようにする。

{
  "scripts": {
      "lint": "node test/markdown.js",
      "precommit": "npm run lint",
      "test": "npm run lint"
  },
  "devDependencies": {
    "glob": "^5.0.5",
    "husky": "^0.7.0",
    "markdownlint": "0.0.4"
  }
}

コミット時に失敗するか確認する

仕込んだテストがコミット時にきちんと機能するか確認してみる。

blog/source/_posts/hello-my-post.md ファイルを、わざと構文エラーが出るように編集する。

 Hexo最初のpost
-==============
+--------------

 リストのテスト
---------------
+==============

 - A
+  - AAA

この状態で git commit を実行すると、コミットログの入力へは進めず、 husky によって中止できた。

$ git commit -a
blog/source/_posts/hello-my-post.md: 7: MD002 First header should be a h1 header
blog/source/_posts/hello-my-post.md: 14: MD007 Unordered list indentation
blog/source/_posts/hello-my-post.md: 16: MD007 Unordered list indentation

husky - pre-commit hook failed (add --no-verify to bypass)

Nodeのプロセスで構文チェックを実行しているだけだが、意外と時間のかかる印象を持った。

huskyのフックでテストさせるのは "precommit" ではなく "prepush" が良かったかも知れない。

CIサービスを使って自動テストさせる

ここまで来るとTravis CICircleCIといったCI as a Serviceを利用して、リポジトリへのプッシュやPull Requestの時に自動でテストを走らせることが可能になる。

上記のサービスは2つとも、Nodeプロジェクトであれば暗黙的に npm test が実行させるので、走らせるテストコマンドを特別に明示させる必要は無く、実行環境だけを設定ファイルに書いておけば上手くテストしてくれた。

Travis CI

.travis.yml という名前のファイルを置く。

language: node_js
node_js:
  - "0.12"
  - "0.10"
  - "iojs"

CircleCI

circle.yml という名前のファイルを置く。というか、このファイルを置かなくても、サービス連携した時点で自動的にNodeのプロジェクトだと認識して、良い感じに動いてくれた。

machine:
  node:
    version: 0.10.22

まとめ