継続的にSwiftLintを実行する

  • 59
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

目的

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

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

realm/SwiftLintを利用したら、github/swift-style-guideベースのチェックが出来そうです。

ローカルでやる場合は、Xcodeに設定しておけば保存などのタイミングでチェックしてくれるのですが、担当者によっては無視してしまう可能性があります。

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

Androidのコードを自動で解析し、GitHubのpull requestにコメントするみたいにしておけば、CircleCI→GitHubのコメントをしてくれ、Slackと連携しておけば違反が可視化しやすそうです。

実現すること

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

実現にあたっては、

などを利用します。

手順

前提

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

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

受託開発でもfastlaneとCircleCIでiOSアプリを継続的デリバリーと重複している部分もあり、端折ってる部分もあります。合わせて参照ください。

circle.ymlの設定

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の設定

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 cocoapodsbundle exec fastlane analyzeと実行する必要があります。

fastlane/Appfileの設定

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

fastlane/Fastfileの設定

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というオプションを付けてもらったので、それを利用し、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が動き、コミットコメントが作成されると思います。

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