みんな大好き Airbnb JS スタイルを Jenkins + SonarQube で CI 運用に組み込む

## 概要

React 含む Javascript の開発現場では、Airbnb スタイルは人気が高いですね。
そこで、SonarQube で Airbnb スタイルを適用し、CI に組み込むことを考えます。

難しいポイントは、SonarQube では Javascript はデフォルト(無料) で使えるのですが、以下の理由で　Sonar 社が考えるオリジナルスタイル(Sonar way)が適用されてしまうことにあります。
http://stackoverflow.com/questions/32519522/sonarqube-integrate-eslint-for-javascript-in-sonarqube

悩んでいたところ、偶然、二日前(2017/02/02) に [sleroy](https://github.com/sleroy/SonarEsLintPlugin) という方が SonarQube の ESLint プラグインをリリースしてくれていました！ Thank you sleroy！！


## Airbnb スタイル
Airbnb スタイル とは
https://github.com/airbnb/javascript

GitHub上のスター数を比較してみました。
Google スタイルと比較しても、Airbnb スタイルは圧倒的に人気が高いですね。
![style比較.png](https://qiita-image-store.s3.amazonaws.com/0/69410/2a6ee930-dee7-f4da-90a7-693e69eeba51.png)

特徴は翻訳者であるmitsuruogさんの[ブログ](http://blog.mitsuruog.info/2013/02/airbnb-javascript.html)によると以下だそうです。

 - オープンな議論を通じてスタイルが決定していること。
 - スタイルについてパフォーマンスに関するエビデンスがあること。



## ESLint
スタイルが決められているだけでは運用がまわりません。
実際には自動的にチェックしてくれる仕組みが必要です。

ESLint の Airbnb 用のプラグインが以下になります。
https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb

３パターン選択できるようですので、プロジェクトに合わせて、package.json に記載します。

 - eslint-config-airbnb  
   ES6 + React
 - eslint-config-airbnb/base  
   ES6
 - eslint-config-airbnb/legacy  
   ES5 以前


## SonarQube
https://www.sonarqube.org/

### インストール
ここでは省略します

### SonarQube ESLint プラグイン
https://github.com/sleroy/SonarEsLintPlugin

 1. [sonar-eslint-plugin-0.1.1.jar](https://github.com/sleroy/SonarEsLintPlugin/releases) を取得
 2. extensions/plugins ディレクトリに配置

```
# pwd
/opt/sonar/extensions/plugins

# ls -l
-rw-r--r-- 1 sonar sonar      128 Dec 14 08:34 README.txt
-rw-r--r-- 1 sonar sonar 10882400 Jan  5 17:25 sonar-csharp-plugin-5.5.2.537.jar
-rw-r--r-- 1 sonar sonar  2412031 Feb  2 23:45 sonar-eslint-plugin-0.1.1.jar
-rw-r--r-- 1 sonar sonar  5993128 Jan  5 17:25 sonar-java-plugin-4.4.0.8066.jar
-rw-r--r-- 1 sonar sonar  2981258 Dec 14 08:34 sonar-javascript-plugin-2.18.0.3454.jar
-rw-r--r-- 1 sonar sonar  3233128 Dec 14 08:34 sonar-scm-git-plugin-1.2.jar
```
 3. SonarQube 再起動

### 設定

ESLint プラグインが正常に配置できていれば、以下のようになります。
![スクリーンショット 2017-02-04 12.41.42.png](https://qiita-image-store.s3.amazonaws.com/0/69410/dcae9879-ea79-26bd-1791-0fd7bed81431.png)

Javascript の Quality Profile を、Sonar way から ESLint に変更します。
![sonar_eslint_設定.png](https://qiita-image-store.s3.amazonaws.com/0/69410/e03a71dd-4488-93b1-953c-704cbbc0d956.png)

[追加 2017/02/08]
Javascript の ファイル拡張子に、.jsx を追加します。
![スクリーンショット_2017-02-08_9_17_22.png](https://qiita-image-store.s3.amazonaws.com/0/69410/489c40db-cbb2-42fe-48fc-ef939e759409.png)


## Jenkins
GitHub にコードがコミットされたら、Jenkins で自動的に ESLint されるように設定します。

### 設定
Jenkins で sonar-schanner が動作するように環境変数を設定します。

```sh:/etc/profile.d/sonar-scaner.sh 
export SONAR_SCANNER_HOME=/opt/sonar-scanner
export PATH=$SONAR_SCANNER_HOME/bin:$PATH
```

ビルド - シェルの実行 - シェルスクリプト の内容は以下になります。
(詳しくは [Jenkins で GitHub のイベントを受けてゴニョゴニョする準備](http://qiita.com/exabugs/items/cc2c6f59da98cd81a06f) を参照して下さい。)

```sh
#!/bin/bash

export PATH=/usr/bin:/usr/local/bin:$PATH
. /etc/profile.d/sonar-scaner.sh

param() {
  echo $payload | jq -r $1
}

OWNER=`param '.repository.owner.name'`
BRANCH=`param '.ref' | sed "s:^refs/heads:remotes/origin:"`
NAME=`param '.repository.name'`
URL=`param '.repository.ssh_url'`
ID=`param '.after'`

echo $URL
echo $BRANCH

if [ ! -d $NAME ]; then
  git clone $URL
fi

cd $NAME

git fetch origin
git reset --hard ${BRANCH}

# npm
if [ -f 'package.json' ]; then
  npm install
fi

# SonarQube
if [ -f 'sonar-project.properties' ]; then
  ${SONAR_SCANNER_HOME}/bin/sonar-scanner
fi
```

## プロジェクト(リポジトリ)毎の設定

package.json は、以下のような感じになります。

```package.json
...
  "devDependencies": {
    "eslint": "^3.14.1",
    "eslint-config-airbnb": "^14.0.0",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-jsx-a11y": "^3.0.2",
    "eslint-plugin-react": "^6.9.0"
    ...
  },
...
```
sonar-project.properties は以下。
ESLint 設定は、指定しなくても .eslintrc.json が読まれるようです。

```sonar-project.properties
sonar.projectKey=HogeHoge
sonar.projectName=HogeHoge
sonar.projectVersion=0.0.0

sonar.sources=src
sonar.exclusions=build/**, **/bundle.js

sonar.eslint.eslintpath=node_modules/eslint/bin/eslint.js
#sonar.eslint.eslintconfigpath=.eslintrc.json

```

ESLint 設定は以下。airbnb を指定しています。

```json:.eslintrc.json
{
  "extends": "airbnb"
}
```

## 結果
![sonar_result.png](https://qiita-image-store.s3.amazonaws.com/0/69410/7d9f6937-803b-af55-412f-6c4eb2326b18.png)

以下のような(よく見かけるwww)Airbnbスタイルのワーニングが、上手く出力されていることがわかります。

 - Component should be written as a pure function
 - JSX not allowed in files with extension '.js' 

これで、スタイルの統一が捗りそうです。

## おわりに
 - SonarQube で Airbnb スタイルを上手く適用することができました。
 - Airbnb スタイルは条件一つづつにキチッとした理由があります。  
   後は、ワーニングの詳細でそのページに飛ぶようになればいいですね。