pull requestした差分にrubocopの結果を自動でコメントしてCircleCIをfailedにするよ


Viibar社員でもないのにまた登場しました @nifuramu です。おっすおっす〜〜〜

[変更したファイルにrubocopやjscsを実行して pull requestに自動でコメントする](http://packsaddle.org/articles/saddler-overview/)

に少しだけ手を加えてCircleCIをfailedにして直すまでマージ阻止だ！！！って感じの内容です。


# 必要とするGem

```
  gem 'rubocop'
  gem 'rubocop-select'
  gem 'rubocop-checkstyle_formatter'
  gem 'saddler'
  gem 'saddler-reporter-github'
  gem 'checkstyle_filter-git'
```

# ベースとなるスクリプト

```
#!/bin/bash
if [ "${CIRCLE_BRANCH}" != "master" ]; then
    git diff -z --name-only origin/master \
    | xargs -0 bundle exec rubocop-select \
    | xargs bundle exec rubocop \
        --require rubocop/formatter/checkstyle_formatter \
        --format RuboCop::Formatter::CheckstyleFormatter \
    | bundle exec checkstyle_filter-git diff origin/master \
    | bundle exec saddler report \
        --require saddler/reporter/github \
        --reporter Saddler::Reporter::Github::PullRequestReviewComment
fi

exit 0
```

こちらに手を加えて行くます。

# 方針

rubocopを実行した結果、何かしらエラーが発生したら `exit 1` してCircleCIの結果をfailedにする。

## Step1

まずはrubocopが何かしらの警告があるかどうかを調べ、その後にpull request送信、そしてfailという処理を愚直に書いてみる。

```bash
#!/bin/bash
if [ "${CIRCLE_BRANCH}" != "master" ]; then
    warn=$(git diff -z --name-only origin/master \
           | xargs -0 bundle exec rubocop-select \
           | xargs bundle exec rubocop)
           
    if [ -n "$warn" ]; then
        echo "$warn" \
        | bundle exec rubocop \
            --require rubocop/formatter/checkstyle_formatter \
            --format RuboCop::Formatter::CheckstyleFormatter \
        | bundle exec checkstyle_filter-git diff origin/master \
        | bundle exec saddler report \
            --require saddler/reporter/github \
            --reporter Saddler::Reporter::Github::PullRequestReviewComment
        exit 1
    fi
fi

exit 0
```

このままではhtmlやcssなどrubyに関係のない変更があった場合やそもそも何も警告がなかった場合でも `$warn` は

```
1 file inspected, no offenses detected
```

という値となりifの中のスクリプトが実行されてしまうので、何かしらの警告があった場合のみに対応する。

## Step2

`Offenses:` が存在すればrubocopが何かしらの警告を出しているはずなので、`$warn` をgrepして存在した時のみ実行するようにした。

```bash
#!/bin/bash
if [ "${CIRCLE_BRANCH}" != "master" ]; then
    warn=$(git diff -z --name-only origin/master \
           | xargs -0 bundle exec rubocop-select \
           | xargs bundle exec rubocop)
           
    detected=$(echo "$warn" | grep "Offenses:")
    if [ -n "$detected" ]; then
        # fail処理
    fi
fi

exit 0
```

## Step3

rubocop-selectで対象となるファイルが存在しない場合は `bundle exec rubocop` しなくてよいのでxargsコマンドに`--no-run-if-empty`オプションをつけてrubocopを実行しないようにする


```bash
#!/bin/bash
if [ "${CIRCLE_BRANCH}" != "master" ]; then
    warn=$(git diff -z --name-only origin/master \
           | xargs -0 bundle exec rubocop-select \
           | xargs --no-run-if-empty bundle exec rubocop)
           
    detected=$(echo "$warn" | grep "Offenses:")
    if [ -n "$detected" ]; then
        # fail処理
    fi
fi

exit 0
```

# 完成形

```bash
#!/bin/bash
if [ "${CIRCLE_BRANCH}" != "master" ]; then
    warn=$(git diff -z --name-only origin/master \
           | xargs -0 bundle exec rubocop-select \
           | xargs --no-run-if-empty bundle exec rubocop)
           
    detected=$(echo "$warn" | grep "Offenses:")
    if [ -n "$detected" ]; then
        echo "$warn" \
        | bundle exec rubocop \
            --require rubocop/formatter/checkstyle_formatter \
            --format RuboCop::Formatter::CheckstyleFormatter \
        | bundle exec checkstyle_filter-git diff origin/master \
        | bundle exec saddler report \
            --require saddler/reporter/github \
            --reporter Saddler::Reporter::Github::PullRequestReviewComment
        exit 1
    fi
fi

exit 0
```

# CircleCIで実行できるようにする

## スクリプトに実行権限をつける

上記スクリプトを適当な名前で保存し、実行権限をつける。今回はrun-rubocop.shとして保存しました。

```
$ chmod a+x run-rubocop.sh
```

## cicle.ymlの設定

circle.ymlに設定を追加

```circle.yml
test:
  post:
    - run-rubocop.sh
```

## GitHubアクセストークンを取得してCicleCIへ保存

`Saddler::Reporter::Github:: PullRequestReviewComment` はGitHubのアクセストークンがないと動かないので[Personal access tokens](https://github.com/settings/tokens)からトークンを取得します。

取得したトークンをCircleCIのProject SettingsページのEnvironment variablesにて `GITHUB_ACCESS_TOKEN` という名前で保存します。

以上でpull requestした差分にrubocopの結果を自動でコメントしてCircleCIをfailedが完成です！

![84ca3f43ea0ec4d7ccb315cad10cb9e1.png](https://qiita-image-store.s3.amazonaws.com/0/978/d94c0010-a201-e3fd-4dd6-0a9756496324.png "84ca3f43ea0ec4d7ccb315cad10cb9e1.png")




なお、こちらの元ネタは @shrkw がViibar社で対応したものをちょろっといじったものとなります。手柄を横取りしたった！

あとこんな事しないでも[SideCI](https://www.sideci.com/)使えばいいんじゃないかなーと思いました。