読者です 読者をやめる 読者になる 読者になる

怠惰のすゝめ。今更聞けない!? Jenkins・Gradle・Githubで簡単自動化①

こんにちは、2014年新卒エンジニアの玉川です。

エンジニアブログでは前々回、Dockerによる完全自動化について記事を投稿しましたが、今回は私が現在取り組んでいるJenkins、Gradle、Githubの連携によるCI環境の構築について説明していきます。記事が長くなってしまったため2回に分けて投稿します。

 

CI環境とは

CI (Continuous Integration)とはアプリケーション作成時の品質を保ちつつ、作業効率を高める習慣のことです。プログラムを構築した後、様々な種類のテストや静的解析を一つ一つ行い、ビルドしてというアクションを非常に面倒くさいと感じる方は少なくないのではないでしょうか。「怠惰のすゝめ。Dockerで環境構築・テスト・デプロイを完全自動化」の最初に述べていたフローにおいて①~③を完全自動化することで、品質の向上とテスト面でのエンジニアの負担を軽減する事を目指します。

こちらもまだ検証段階ですが、以下の開発フロー構築を想定しています。

 

①自身のGitリポジトリにプッシュを行い、プルリクエストを送る

②Jenkinsはプルリクエストが送られた事を検知する

③静的解析&ビルド&単体テストを行う

④テストが成功した事をGithubコメント上に表示する

 

JenkinsによるCI環境構築

 

今回の解説にあたり、サーバーは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 rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key 

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

トップページ→Jenkinsの管理→システムの設定からJenkinsの設定を行います。今回やっておく必要があるものは以下の通りです。

JDK・・・インストール済みのJAVA_HOMEのパスを設定します。

Git・・・インストール済みのGitのパスを設定します。

Gradle・・・Jenkinsサーバー側にGradleをインストールした場合はGradleへのパスを設定します。

 

Gradleとは

GradleとはGroovyで記述されるビルドツールです。Mavenとの互換性があり、POMやAntタスクをそのまま利用する事ができます。Groovyで記述されるため、プログラミングの一般的な設計原則を適用でき、XMLの記述が面倒くさいと感じる人にも馴染みやすいと思います。また、Gradleにはラッパーがあり、Gradleラッパーを用いるとGradleをインストールをしていないマシンでもビルドを実行する事が可能です。

今回はこのラッパーを使用します。そのため、Gradleをサーバー側ではなく開発環境側にインストールしておき、プロジェクト作成後にラッピングを行います。

 

$ brew install gradle

$ gradle -v

 

Gradleのテストとビルドを実行する

プロジェクトルートで以下のコマンドを実行し、プロジェクトをラッピングします。

 

$ gradle wrapper

:wrapper

 

BUILD SUCCESSFUL

 

Total time: 9.023 secs

 

プロジェクトルートに「build.gradle」ファイルを作ります。このファイルがMavenでいうところのpom.xmlのような役割をし、このファイルに依存関係や各タスクの設定を記述します。

 

Gradleラッパーでのラッピングタスクの記載

Gradleではtask ○○と記述することで新たなタスクを定義します。

 

task wrapper(type: Wrapper) {

description = "Generates gradlew[.bat] scripts"

gradleVersion = "1.12"

}

 

今回はプロジェクト内の依存関係を考慮していないため、全てのタスクをallprojects{}内に記載しています。ここに記載する事で、ルートプロジェクトを含む全プロジェクトに適用され、サブプロジェクトにも継承されます。

 

apply plugin: 'java'

 

プラグインを導入する場合は上記のように記述します。また、.gradleファイルを別ファイルに分けて記述した場合は

 

apply from: ‘build2.gradle'

 

上記のように記述する事で読み込む事ができます。

 

repositories {

mavenCentral()

}

 

依存関係のあるライブラリの入手先としてMavenレポジトリを追加します。

 

dependencies {

compile fileTree(dir: "WEB-INF/lib", include: '*.jar')

testCompile 'junit:junit:4.11'

compile 'org.hamcrest:hamcrest-core:1.3'

}

 

依存関係のあるライブラリを記述します。libフォルダの指定や外部ライブラリを追加します。http://mvnrepository.com/が便利です。

 

[compileJava, compileTestJava].each{

it.options.encoding = 'UTF-8'

it.options.compilerArgs += ['-source', '1.7', '-target', '1.7']

}

targetCompatibility = 1.7

sourceCompatibility = 1.7

 

コンパイル時のJavaのバージョンを記述します。

 

sourceSets {

main {

java {

srcDir 'WEB-INF/src'

}

}

test {

java {

srcDir 'WEB-INF/test'

}

}

}

 

ソースの場所を記述します。

 

以上で簡単な設定は終了です。

ターミナル上から以下を実行するとJUnitによるテスト&ビルドが行われます。

$ ./gradlew test

$ ./gradlew build

 

静的分析テストを追加する

JUnitによるテストだけでなく、checkstylefindbugs、coberturaによる静的分析を行います。

プラグインを導入します。以下の3行を追加してください。

 

apply plugin: 'checkstyle'

apply plugin: 'findbugs'

apply plugin: 'cobertura'

 

dependanciesに以下の3行を追加します。実は追加しなくても自動で追加してくれるのですが、明示的なバージョンを示すために追加しています。

 

compile 'com.puppycrawl.tools:checkstyle:5.7'

compile 'net.sourceforge.findbugs:findbugs:1.3.7'

compile 'net.sourceforge.cobertura:cobertura:2.0.3'

 

checkstyleの設定

以下のように設定を追加します。レポートとして出力するフォルダと設定のxmlファイルがある場所を設定しています。ignoreFailuresは失敗した際にビルドを止めるかどうかの設定です。Test用コードのチェックを除外するためにexcludesにより設定を行っています。

 

checkstyle {

reportsDir = file('./build/reports/checkstyle')

configFile = file('./checkstyle.xml')

ignoreFailures = true

}

checkstyleTest {

excludes = ['**/*']

}

 

findbugsの設定

同様にfind bugsも設定します。reportLevelはhigh、medium、lowを選べます。highは優先度が高になってるもののみを出力します。lowは全て出力します。

 

findbugs {

reportsDir = file('./build/reports/findbugs')

reportLevel = "low"

ignoreFailures = true

}

findbugsTest {

excludes = ['**/*']

}

 

coberturaの設定

出力フォーマットの形式を記述します。後ほどjenkinsで結果を出力する際にxmlファイルが必要です。htmlは不要ですが、念のため設定しています。

 

cobertura{

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 checkstyleMain

$ ./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 test

./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リポジトリからコードをダウンロードし、テスト&ビルドを行います。左下のビルド履歴にビルドが表示されます。

 

コンソール出力では詳細にビルドの進み具合が確認できます。

 

ビルド履歴

 

ビルド結果

 

ビルドが全て終了するとテスト結果が確認できます。

 

テスト結果

 

テストが失敗した場合はビルドせず、失敗した箇所を確認できます。

 

ビルド失敗

 

JUnit失敗結果

 

各種テストの結果を閲覧できます。

 

CheckStyle結果

 

FindBugs結果

 

カバレッジ結果

 

ハマりポイント

Eclipse Gradleプラグインの挙動がおかしい

Eclipse Gradleプラグインで確認を取った際はエラーでビルドが失敗するが、ターミナルからは大丈夫ということが稀にありました。Eclipseでうまくいかない場合はターミナルでも確認してみましょう。

ディレクトリのPATH設定はちゃんとやる

→GradleもJenkinsもcheckstyle等のデフォルトディレクトリPATHが設定されていますが、過信しないように。レポート表示など、しっかり設定しないと表示されません。エラーが出てビルドが通らない場合もあります。

③Java8の対応状況

FindBugs、CoberturaについてはJava8で動作しませんでした。Java8で利用したい場合は対応を待つかJaCoCoやPMDに変更する必要があります。

 

おわりに

 

今回はGradleとJenkinsの連携を説明しました。実際の開発環境ではどのような静的テストを行うべきか、Jenkinsに入れるべきプラグインをどうするかなどを検討する必要があります。

次回、Githubとさらに連携をとり、pull requestが行われた段階で、今回のテスト&ビルドを自動的に行い、結果をGitHubのコメントとして出力するところまでを説明予定です。

様々な種類のテストを一つ一つ調べて、ビルドしてというアクションは非常に面倒くさいものです。皆さんもこれを機に、CI環境を構築し、どんどん怠惰していきましょう!