継続的にSwiftLintを実行する


## 目的

Swiftも2.0になり、使う機会が増えてきました。

複数人で書くことも増えてくると、コードフォーマットの統一を図りたくなってきます。

[realm/SwiftLint](https://github.com/realm/SwiftLint)を利用したら、[github/swift-style-guide](https://github.com/github/swift-style-guide)ベースのチェックが出来そうです。

ローカルでやる場合は、[Xcodeに設定しておけば](https://github.com/realm/SwiftLint#xcode)保存などのタイミングでチェックしてくれるのですが、担当者によっては無視してしまう可能性があります。

また、SwiftLintも日々チェック項目が追加されているので、開発者のローカルのSwiftLintが古く、チェックしきれてない可能性もあります。

[Androidのコードを自動で解析し、GitHubのpull requestにコメントする](http://qiita.com/noboru_i/items/2f30296db1c8a6dfbd9b)みたいにしておけば、CircleCI→GitHubのコメントをしてくれ、Slackと連携しておけば違反が可視化しやすそうです。

## 実現すること

CircleCI上で、SwiftLintを実行し、違反があればGitHubのコミットコメントorプルリクコメントに追加します。

実現にあたっては、

- [CircleCI](https://circleci.com/)
- [SwiftLint](https://github.com/realm/SwiftLint)
- [fastlane](https://fastlane.tools/)

などを利用します。

## 手順

### 前提

**CircleCIの場合、iOS planの課金を行っている必要があります。**

TravisCIの方も、流れは共通だと思うので、circle.ymlなどを読み替えて頂ければと思います。

[受託開発でもfastlaneとCircleCIでiOSアプリを継続的デリバリー](http://qiita.com/noboru_i/items/2e50ddd396a6970033d9)と重複している部分もあり、端折ってる部分もあります。合わせて参照ください。

### circle.ymlの設定

```yaml:circle.yml
machine:
  timezone: Asia/Tokyo
  xcode:
    version: "7.2"
dependencies:
  pre:
    - brew update
    - brew install swiftlint
test:
  override:
    # workaround https://github.com/realm/SwiftLint/issues/13
    - ln -s /Applications/Xcode-7.2.app /Applications/Xcode.app
    - bundle exec fastlane analyze
```

dependenciesのフェーズで、swiftlintのインストールを行っています。
常に最新版を利用して欲しいので、先に`brew update`を行っています。（2016/01現在、どんどんアップデートされています）

testフェーズでは、fastlaneのアクション実行前に、symlinkの作成を行っています。
コメントに記載した通り、ライブラリのロードエラー（？）が発生することへの回避策です。
`Xcode-7.2`の部分は、machine.xcode.versionの部分と一致させておく必要があるのかな、と思っています。

'7.2'になっている部分は、CircleCI上のXcodeの最新バージョンに逐次アップデートした方が良さそうです。

### Gemfileの設定

```ruby:Gemfile
source "https://rubygems.org"

gem 'cocoapods'
gem 'fastlane'
gem 'checkstyle_filter-git'
gem 'saddler'
gem 'saddler-reporter-github'
gem 'swiftlint_translate_checkstyle_format'
```

ここでは、cocoapodsと同時に、fastlaneやチェック結果をGitHubに送るためのsaddlerなどを指定しています。

ローカルで実行する場合は、`bundle install --path vendor/bundle`などを実行し、`bundle exec cocoapods`や`bundle exec fastlane analyze`と実行する必要があります。

### fastlane/Appfileの設定

プロジェクトの設定ファイルをそのまま利用するので、特に指定しません。
ファイルだけ作っておきました。

### fastlane/Fastfileの設定

```ruby:Fastfile
fastlane_version '1.51.0'

default_platform :ios

# And you need to set environment variables.
# GITHUB_ACCESS_TOKEN : GitHub access token, using when comment to Pull Request and create release.

platform :ios do
  desc 'Analyze codes'
  desc 'This may comment to pull request'
  lane :analyze do
    create_lint_config

    swiftlint(
      output_file: 'swiftlint.result.json',
      config_file: '.swiftlint-ci.yml'
    )

    sh 'cp ../swiftlint.result.json $CIRCLE_ARTIFACTS/'

    sh <<-EOS
cd ../;
cat swiftlint.result.json \
    | swiftlint_translate_checkstyle_format translate \
    | checkstyle_filter-git diff origin/master \
    | saddler report --require saddler/reporter/github --reporter #{reporter}
    EOS

    delete_lint_config
  end

  def create_lint_config
    File.delete('../.swiftlint-ci.yml') if File.exist?('../.swiftlint-ci.yml')
    require 'yaml'
    config = YAML.load_file('../.swiftlint.yml')
    config['reporter'] = 'json'
    open('../.swiftlint-ci.yml', 'w') do |file|
      YAML.dump(config, file)
    end
  end

  def delete_lint_config
    File.delete('../.swiftlint-ci.yml')
  end

  def reporter
    if ENV['CI_PULL_REQUEST'].nil? || ENV['CI_PULL_REQUEST'].empty?
      'Saddler::Reporter::Github::CommitReviewComment'
    else
      'Saddler::Reporter::Github::PullRequestReviewComment'
    end
  end
end
```

`analyze`というlaneを定義しています。

`swiftlint`にconfig_fileというオプションを[付けてもらった](https://github.com/fastlane/fastlane/pull/989)ので、それを利用し、CI用の設定ファイル（.swiftlint-ci.yml）を使います。

リポジトリ上には`.swiftlint.yml`を置いておき、`create_lint_config`でそこから`reporter`のみを変更したものを`.swiftlint-ci.yml`として利用します。
`delete_lint_config`で削除しておきます。

GitHubのコメントに追加する部分が、Rubyのコード上でコマンドを実行しているのが微妙なので、なんとかしたいところ。

### CircleCIの環境変数設定

Fastfileに記載したとおり、`GITHUB_ACCESS_TOKEN`を設定する必要があります。

BOTアカウントを作成し、そのユーザのaccess tokenを取得したほうが、見栄えが良いかと。（コメントが並んだ時とか）

### 完成

あとは、違反を含んだコードをコミット、GitHubにpushすると、CircleCIが動き、コミットコメントが作成されると思います。

人間のレビューの前に、それらの自動レビューの結果をクリーンにしておくことで、人間のレビューが楽になるはずです。