ふつうのWebアプリにGradleをしこむ

個人的にテストコードを書いたり、Gradle で自動化するのを実践しているのですが、
仕事に活かせているのは小規模で自分の裁量が大きいプロジェクトに限られています。

大規模なプロジェクトになると色々と抵抗勢力が多くて、色々と説得するのが億劫なので
こっそり Gradle を仕込んで Jenkins 動かそうと今試みています。

個人的にはコソコソ動いてておもしろいので、成果をメモしていきます。

"ふつう" な前提条件

Gradle を仕込むのは「ふつうの Eclipse プロジェクト」です。
ここで言う「ふつう」とは…

Maven ディレクトリ構成ではない

src/main/java, src/main/resource, src/main/webapp といったディレクトリ構成ではなく、
src の下に java ファイルがあったり、WebContent ディレクトリの下に WEB-INF や JSP があったりです。
Eclipse がプロジェクト新規作成時に勝手に作ってくれるディレクトリ構成ですね。

◯みんなのPCには Maven も Gradle も入ってない

そんなビルドツールなんて知りません。Eclipse の付属で付いている Ant のちょっとしたビルドが
動いているかもしれません。でも、そんなの意識したことがありません。

jar ファイルは WebContent/WEB-INF/lib にちゃんとコミットして置く必要があります。
ビルドするたびにリポジトリから最新のライブラリを取得するなんてよくわからないです。
それに、プロキシが邪魔して Gradle のプロキシ設定しないと、社外にはアクセスできないです。

◯自動化するからといってやり方が変わるのは嫌だ

Maven でビルド動かさないと jar ファイルが見つからないとか、そういうのはいけません。
Subversion からソースコードを取得したらそのまま使えるのが大事です。
build.gradle というよくわからないファイルがコミットされてるぞ?くらいで留めないとダメです。

こっそり仕込むこと

主に Gradle と Jenkins を使って、色々と自動化を仕込んでいきます。

1.War ファイルを作る  ←今ココ
2.ちょっとずつ作っていく JUnit テストコードでテストする
3.テスト環境に War ファイルをデプロイする
4.テスト環境でスモークテストを実行する

とりあえず build.gradle ファイル

apply plugin: 'war'

repositories {
    mavenCentral()
}

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

    compile 'org.apache.tomcat:tomcat-servlet-api:7.0.42'
    compile 'org.apache.tomcat:tomcat-jsp-api:7.0.42'
}

project.webAppDirName = 'WebContent'

sourceSets {
    main {
        java {
            srcDir 'src'
        }
        resources {
            srcDir 'src'
        }
    }
}

war {
    exclude 'WEB-INF/lib/**'
    exclude 'WEB-INF/classes/**'
}

def defaultEncoding = 'UTF-8'
compileJava {
    options.encoding = defaultEncoding
}

以下、順を追って設定内容を説明していきます。

お決まりの冒頭

apply plugin: 'war'

repositories {
    mavenCentral()
}

Java の Web アプリケーションなので、War プラグインを設定します。
あと、リポジトリMaven セントラルレポジトリを設定します。
ここまではお決まりです。

jar ファイルはすでにコミットされているものを使う

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

    compile 'org.apache.tomcat:tomcat-servlet-api:7.0.42'
    compile 'org.apache.tomcat:tomcat-jsp-api:7.0.42'
} 

普通は依存関係にある jar ファイルは次のような形式で書いてリポジトリから取得するのですが、

compile 'org.springframework:spring-web:3.2.1.RELEASE'

jar ファイルは WEB-INF/lib にコミットされているものを使わないといけないので、
そのディレクトリにある jar ファイルをコンパイル時に参照するように設定します。

例外的に Tomcat のランタイムの jar ファイルをコンパイル時に参照するように設定しています。
Eclipse プロジェクトではサーバランタイムを参照するように設定します。それに対応するものです。
これを設定しておかないと、Gradle でビルドするときに HttpServletRequest などの Java EE クラスが
存在しないということでコンパイルエラーになります。
Gradle で動かす時だけ Tomcat のランタイムをレポジトリから引っ張ってくることになります。

Maven ディレクトリ構成ではないので調整する

project.webAppDirName = 'WebContent'

sourceSets {
    main {
        java {
            srcDir 'src'
        }
        resources {
            srcDir 'src'
        }
    }
} 

Gradle や Maven のデフォルトのままだと、

 JSP や WEB-INF は… src/main/webapp ディレクトリ
 Java ファイルは… src/main/java ディレクトリ
 Java 以外のファイルは… src/main/resources ディレクトリ

に配置しないと動かないので、次のようにディレクトリ構成を変更しています。

 JSP や WEB-INF は… WebContent ディレクトリ
 Java ファイルは… src ディレクトリ
 Java 以外のファイルは… src ディレクトリ

本当はテストコードのディレクトリ構成も調整しないといけないのですが、
今はテストコードがないので調整していません。

War ファイルを作るときの不都合を回避する

war {
    exclude 'WEB-INF/lib/**'
    exclude 'WEB-INF/classes/**'
}

「gradle war」をたたくことで、Gradle が War ファイルを作ってくれるのですが、
ディレクトリ構成をいじったりしていることもあり、作成された War ファイルの中を見ると
同じファイルが重複して梱包されてしまいます。ファイルがサイズ膨大化します。
重複を回避するおまじないです。

エンコーディングを指定する

def defaultEncoding = 'UTF-8'
compileJava {
    options.encoding = defaultEncoding
}

ほとんどお決まりのような設定です。
こちらも本当はテストコードに対する指定も必要です。

こっそり War ファイルを作成できるようになる

色々と書きましたが、build.gradle を少し調整するだけで
Gradle をインストールした環境で「gradle war」とするだけで War ファイルが作れます。

自分のPCやテスト環境に Gradle を入れることとで、こっそりと簡単に実行できます。

問題点はテストコードがなく自動テストをしていないので、作った War が正しく動くかはわからないということです。それをやるためにはテストコードを書かないといけないのですが、それはハードル高いですね。

まずは War ファイルを作れるようになったということで。
Eclipse プロジェクトの右クリック→「エクスポート」→「War ファイル」からの脱却です。