怠惰のすゝめ。今更聞けない!? Jenkins・Gradle・Githubで簡単自動化①
こんにちは、2014年新卒エンジニアの玉川です。
エンジニアブログでは前々回、Dockerによる完全自動化について記事を投稿しましたが、今回は私が現在取り組んでいるJenkins、Gradle、Githubの連携によるCI環境の構築について説明していきます。記事が長くなってしまったため2回に分けて投稿します。
CI環境とは
CI (Continuous Integration)とはアプリケーション作成時の品質を保ちつつ、作業効率を高める習慣のことです。プログラムを構築した後、様々な種類のテストや静的解析を一つ一つ行い、ビルドしてというアクションを非常に面倒くさいと感じる方は少なくないのではないでしょうか。「怠惰のすゝめ。Dockerで環境構築・テスト・デプロイを完全自動化」の最初に述べていたフローにおいて①~③を完全自動化することで、品質の向上とテスト面でのエンジニアの負担を軽減する事を目指します。
こちらもまだ検証段階ですが、以下の開発フロー構築を想定しています。
①自身のGitリポジトリにプッシュを行い、プルリクエストを送る
②Jenkinsはプルリクエストが送られた事を検知する
③静的解析&ビルド&単体テストを行う
④テストが成功した事をGithubコメント上に表示する
今回の解説にあたり、サーバーはCentOS、開発環境はMacOS Xを想定しています。
Jenkinsとは
Jenkinsとは、Apache TomcatなどのServletコンテナ上で動作する継続的インテグレーションツールです。CIツールとして有名だったHudsonが商標上などの問題によりJenkinsと改名しました。Subversion、Gitなど様々なバージョン管理システムツールに対応し、Ant、Mavenといったビルドツールからビルド、シェルスクリプト、プロジェクトの実行を行えます。また、プラグインをインストールする事でビルド後に静的解析をし、その結果を出力することなども可能です。
以下のプラグインを追加することで、①~④の流れが全て可能になります。
Checkstyle Plugin
Checkstyle結果のレポートを表示します。コーディングスタイルの統一などを図る事ができます。
FindBugs Plugin
Findbugs結果のレポートを表示します。プログラム上でバグを生む可能性がある部分を検出します。
Cobertura Plugin
Cobertura結果のレポートを表示します。テストコードのカバレッジを計測します。
Git Plugin
GitリポジトリをSCMとして利用できるようにします。
GitHub Plugin
GitHubプロジェクトをJenkinsで利用可能にします。
GitHub pull request builder plugin
プルリクエストがあったかどうかを判断します。
以下のプラグインは今回使用しませんが、あると便利なプラグインです。
Gradle Plugin
JenkinsでGradleによるビルドを可能にします。ラッパー&シェルスクリプトで実行する場合は不要です。
Violations
Jenkins上で様々な解析プラグインを導入した際に、増えてしまうレポートを統一し、レポートをよりわかりやすく表示してくれます。
Jenkinsのインストールと環境設定
それでは早速Jenkinsをインストールしていきます。Jenkinsのインストールは非常に簡単です。
$ sudo yum install jenkins
$ sudo service jenkins start
デフォルトでは http://localhost:8080 がJenkinsのアドレスです。ポート、アドレス等を変更したい場合は /etc/sysconfig/jenkins の設定を変更してください。
Tomcatと連携し動作させたい場合は、JENKINS_PORT、JENKINS_AJP_PORTの項目を変更する必要があります。
Jenkinsにプラグインの追加
各種プラグインを追加していきます。JenkinsトップページからJenkinsの管理→プラグインの管理に進んでください。利用可能タブを選択し、プラグインを追加していきます。
インストールを開始するボタンをクリックすると自動でダウンロード&インストールが開始します。プラグインによっては他のプラグインと依存関係にあるものもありますが、その場合は自動で依存関係にあるプラグインも自動でダウンロード&インストールされます。念のため、インストール後にJenkinsを再起動しておきます。
Jenkinsの設定
トップページ→Jenkinsの管理→システムの設定からJenkinsの設定を行います。今回やっておく必要があるものは以下の通りです。
JDK・・・インストール済みのJAVA_HOMEのパスを設定します。
Git・・・インストール済みのGitのパスを設定します。
Gradle・・・Jenkinsサーバー側にGradleをインストールした場合はGradleへのパスを設定します。
Gradleとは
GradleとはGroovyで記述されるビルドツールです。Mavenとの互換性があり、POMやAntタスクをそのまま利用する事ができます。Groovyで記述されるため、プログラミングの一般的な設計原則を適用でき、XMLの記述が面倒くさいと感じる人にも馴染みやすいと思います。また、Gradleにはラッパーがあり、Gradleラッパーを用いるとGradleをインストールをしていないマシンでもビルドを実行する事が可能です。
今回はこのラッパーを使用します。そのため、Gradleをサーバー側ではなく開発環境側にインストールしておき、プロジェクト作成後にラッピングを行います。
$ gradle -v
Gradleのテストとビルドを実行する
プロジェクトルートで以下のコマンドを実行し、プロジェクトをラッピングします。
:wrapper
BUILD SUCCESSFUL
Total time: 9.023 secs
プロジェクトルートに「build.gradle」ファイルを作ります。このファイルがMavenでいうところのpom.xmlのような役割をし、このファイルに依存関係や各タスクの設定を記述します。
Gradleラッパーでのラッピングタスクの記載
Gradleではtask ○○と記述することで新たなタスクを定義します。
description = "Generates gradlew[.bat] scripts"
gradleVersion = "1.12"
}
今回はプロジェクト内の依存関係を考慮していないため、全てのタスクをallprojects{}内に記載しています。ここに記載する事で、ルートプロジェクトを含む全プロジェクトに適用され、サブプロジェクトにも継承されます。
プラグインを導入する場合は上記のように記述します。また、.gradleファイルを別ファイルに分けて記述した場合は
上記のように記述する事で読み込む事ができます。
mavenCentral()
}
依存関係のあるライブラリの入手先としてMavenレポジトリを追加します。
compile fileTree(dir: "WEB-INF/lib", include: '*.jar')
testCompile 'junit:junit:4.11'
compile 'org.hamcrest:hamcrest-core:1.3'
}
依存関係のあるライブラリを記述します。libフォルダの指定や外部ライブラリを追加します。http://mvnrepository.com/が便利です。
it.options.encoding = 'UTF-8'
it.options.compilerArgs += ['-source', '1.7', '-target', '1.7']
}
targetCompatibility = 1.7
sourceCompatibility = 1.7
main {
java {
srcDir 'WEB-INF/src'
}
}
test {
java {
srcDir 'WEB-INF/test'
}
}
}
ソースの場所を記述します。
以上で簡単な設定は終了です。
ターミナル上から以下を実行するとJUnitによるテスト&ビルドが行われます。
$ ./gradlew build
静的分析テストを追加する
JUnitによるテストだけでなく、checkstyle、findbugs、coberturaによる静的分析を行います。
プラグインを導入します。以下の3行を追加してください。
apply plugin: 'findbugs'
apply plugin: 'cobertura'
dependanciesに以下の3行を追加します。実は追加しなくても自動で追加してくれるのですが、明示的なバージョンを示すために追加しています。
compile 'net.sourceforge.findbugs:findbugs:1.3.7'
compile 'net.sourceforge.cobertura:cobertura:2.0.3'
checkstyleの設定
以下のように設定を追加します。レポートとして出力するフォルダと設定のxmlファイルがある場所を設定しています。ignoreFailuresは失敗した際にビルドを止めるかどうかの設定です。Test用コードのチェックを除外するためにexcludesにより設定を行っています。
reportsDir = file('./build/reports/checkstyle')
configFile = file('./checkstyle.xml')
ignoreFailures = true
}
checkstyleTest {
excludes = ['**/*']
}
findbugsの設定
同様にfind bugsも設定します。reportLevelはhigh、medium、lowを選べます。highは優先度が高になってるもののみを出力します。lowは全て出力します。
reportsDir = file('./build/reports/findbugs')
reportLevel = "low"
ignoreFailures = true
}
findbugsTest {
excludes = ['**/*']
}
coberturaの設定
出力フォーマットの形式を記述します。後ほどjenkinsで結果を出力する際にxmlファイルが必要です。htmlは不要ですが、念のため設定しています。
coverageFormats = ['xml','html']
coverageDirs = [sourceSets.main]
coverageReportDir = file('build/reports/cobertura')
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "net.saliman:gradle-cobertura-plugin:2.2.2"
}
}
以上で設定は終了です。
ターミナルから以下を実行するとそれぞれの結果を取得します。結果は設定したreportフォルダに格納されます。
$ ./gradlew findbugsMain
$ ./gradlew cobertura
JenkinsとGradleの連携
実際にJenkinsとGradleの連携により、Jenkins上から各種のテストとビルドを実行します。
Jenkinsのトップページから「新規ジョブ作成」を選択してください。
ジョブ名は任意、フリースタイル・プロジェクトのビルドを選択します。
詳細な設定画面に移行します。
GitHub project・・・GitHubプロジェクトのURLを入力
ソースコード管理・・・Gitを選択
Repository URL・・・git@github.com:~~~を入力
Branch Specifier (blank for 'any’)・・・branchを作っている場合はbranchを入力
ビルド・・・シェルの実行を選択し、以下のスクリプトを入力
./gradlew checkstyleMain
./gradlew findbugsMain
./gradlew cobertura
./gradlew build
ビルド後の処理・・・Checkstyle警告の集計、FindBugs警告の集計、Coberturaカバレッジレポートの集計、JUnitテスト結果の集計、Report Violationsを追加
Checkstyle警告の集計・・・集計するファイルにreportsDirのフォルダ+正規表現を記述(build/reports/checkstyle/*.xml)
FindBugs警告の集計・・・集計するファイルにreportsDirのフォルダ+正規表現を記述(build/reports/findbugs/*.xml)
Coberturaカバレッジレポートの集計・・・XMLレポートパターンにcoverageReportDir+正規表現を記述(build/reports/cobertura/*.xml)
JUnitテスト結果の集計・・・テスト結果XMLに結果XMLフォルダのパス+正規表現を記述(build/test-results/*.xml)
実行してみる
実際に実行は左上のビルド実行から行います。gitリポジトリからコードをダウンロードし、テスト&ビルドを行います。左下のビルド履歴にビルドが表示されます。
コンソール出力では詳細にビルドの進み具合が確認できます。
ビルドが全て終了するとテスト結果が確認できます。
テストが失敗した場合はビルドせず、失敗した箇所を確認できます。
各種テストの結果を閲覧できます。
ハマりポイント
→Eclipse Gradleプラグインで確認を取った際はエラーでビルドが失敗するが、ターミナルからは大丈夫ということが稀にありました。Eclipseでうまくいかない場合はターミナルでも確認してみましょう。
②ディレクトリのPATH設定はちゃんとやる
→GradleもJenkinsもcheckstyle等のデフォルトディレクトリPATHが設定されていますが、過信しないように。レポート表示など、しっかり設定しないと表示されません。エラーが出てビルドが通らない場合もあります。
③Java8の対応状況
→FindBugs、CoberturaについてはJava8で動作しませんでした。Java8で利用したい場合は対応を待つかJaCoCoやPMDに変更する必要があります。
おわりに
今回はGradleとJenkinsの連携を説明しました。実際の開発環境ではどのような静的テストを行うべきか、Jenkinsに入れるべきプラグインをどうするかなどを検討する必要があります。
次回、Githubとさらに連携をとり、pull requestが行われた段階で、今回のテスト&ビルドを自動的に行い、結果をGitHubのコメントとして出力するところまでを説明予定です。
様々な種類のテストを一つ一つ調べて、ビルドしてというアクションは非常に面倒くさいものです。皆さんもこれを機に、CI環境を構築し、どんどん怠惰していきましょう!