目的
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の設定
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の設定
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の設定
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が動き、コミットコメントが作成されると思います。
人間のレビューの前に、それらの自動レビューの結果をクリーンにしておくことで、人間のレビューが楽になるはずです。