{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# 十徳ナイフとしてのGradle\n", "\n", "[JJUG CCC 2016 Spring](http://www.java-users.jp/?page_id=2377) / [M-6_1 十徳ナイフとしてのGradle](http://www.java-users.jp/?page_id=2396#M-6_1)\n", "\n", "*[#ccc_m61](https://twitter.com/search?f=tweets&q=%23ccc_m61&src=typd)*" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 自己紹介\n", "\n", "よしだ\n", "\n", "* twitter: [@grimrose](https://twitter.com/grimrose) /とーます \n", "* github: [grimrose](https://github.com/grimrose)\n", "* Community: [Yokohama.groovy](http://connpass.com/series/253/)\n", "![icon](https://avatars3.githubusercontent.com/u/623724?v=3&s=280)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "好きな言語: ![Groovy Logo](https://upload.wikimedia.org/wikipedia/commons/3/36/Groovy-logo.svg)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "好きなIDE: ![IntelliJ IDEA](img/icon_IntelliJIDEA.png)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## お仕事\n", "\n", "* 所属: とある人材紹介会社のマーケティング部門\n", "* 役割: データ分析チームのデータエンジニア\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## お仕事\n", "\n", "社内BIツールの開発、設計、運用\n", "\n", "* [Skinny](http://skinny-framework.org), [ScalikeJDBC](http://scalikejdbc.org), [Scalaz](https://github.com/scalaz/scalaz), [Hazelcast](http://hazelcast.org), [scalaxb](http://scalaxb.org/ja), [Akka](http://akka.io), [Embulk](http://www.embulk.org/)\n", "\n", "* [Laravel](https://laravel.com), [FuelPHP](http://fuelphp.com), [Angular](https://angularjs.org), [TypeScript](https://www.typescriptlang.org), [Wijmo5](http://wijmo.c1.grapecity.com/products/wijmo-5/)\n", "* [Electron](http://electron.atom.io), [Mithril.js](http://mithril-ja.js.org)\n", "* etc." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Agenda\n", "\n", "* Gradleとは?\n", "* 今日話す内容と「Gradle 徹底入門」\n", "* タスクランナーとしてのGradle\n", "* Gradleを使った自動化例\n", "* Pluginの紹介\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## [Gradle](http://gradle.org/)とは?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "* 全く知らない?\n", "* 聞いたことがある?\n", "* 触ったことがある?\n", "* 使っている?\n", "* Plugin書いてる?\n", "* 俺がGradleだ!\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "* 次世代ビルドツール\n", "* version: 2.13\n", "* 主にJava、Groovyで実装\n", "* Java8対応, Java9も対応開始\n", "* Groovy: 2.4\n", "* [sdkman](http://sdkman.io/index.html)を使うとインストールが簡単" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Gradle Wrapperのアップデート\n", "\n", "```shell\n", "./gradlew wrapper --gradle-version=2.13\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## NEW!!\n", "\n", "build.gradleが[Kotlin](http://kotlinlang.org/)で書けるように\n", "\n", "* [Gradle Meets Kotlin](http://blog.jetbrains.com/kotlin/2016/05/gradle-meets-kotlin/)\n", "\n", "* [Kotlin Meets Gradle](https://gradle.org/blog/kotlin-meets-gradle/)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "```groovy\n", "apply plugin: 'application'\n", "\n", "mainClassName = 'samples.HelloWorld'\n", "\n", "repositories {\n", " jcenter()\n", "}\n", "\n", "dependencies {\n", " testCompile \"junit:junit:4.12\"\n", "}\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "[gradle/gradle-script-kotlin](https://github.com/gradle/gradle-script-kotlin)\n", "\n", "```kotlin\n", "import org.gradle.api.plugins.*\n", "import org.gradle.script.lang.kotlin.*\n", "\n", "apply()\n", "\n", "configure {\n", " mainClassName = \"samples.HelloWorld\"\n", "}\n", "\n", "repositories {\n", " jcenter()\n", "}\n", "\n", "dependencies {\n", " \"testCompile\"(\"junit:junit:4.12\")\n", "}\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "その他、Gradleについては\n", "[Gradleで始めるGroovy expand](https://speakerdeck.com/grimrose/gradledeshi-merugroovy-expand-number-jjug-ccc-number-ccc-r14)\n", "でも紹介しているので、参考にしてください。\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "### Gradle徹底入門\n", "\n", "![Gradle徹底入門](http://www.seshop.com/static/images/product/17414/L.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "* 第2部 基礎編 6章 スクリプトファイルの記述\n", "* 第4部 発展編 13章 エキスパートへの道" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## build.gradle\n", "\n", "ざっくりと言うと以下の内容\n", "\n", "* 利用しているプラグイン\n", "* ライブラリの依存関係\n", "* プラグインの設定\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "その他に\n", "\n", "* タスクの定義\n", "* ソースファイルの位置\n", "* メソッド、クラス\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "つまり、\n", "\n", "すっきりしている**build.gradle**ほど\n", "\n", "よりGradle Pluginに依存している" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "[Groovyを知らない人のためのbuild.gradle読み書き入門](http://qiita.com/opengl-8080/items/a0bb31fb20cb6505188b)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## タスクランナーとしてのGradle" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Gradleはタスクを組み合わせて、DAG(有向非循環グラフ)を作る " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "1. **実行したいことをタスクに落とし込む**\n", "1. **タスクを繋げる**\n", "1. **ワンクリックで実行できるようにする**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### タスクの依存関係\n", "\n", "後に実行したいタスク名**.dependsOn** 先に実行するタスク名\n", "\n", "* 先に実行するタスクは、配列またはクロージャで渡すことが出来る。\n", "* タスクが循環参照する場合は、例外が発生する。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### タスクの順位付け\n", "\n", "後に実行したいタスク名**.mustRunAfter** 先に実行するタスク名\n", "\n", "後に実行したいタスク名**.shouldRunAfter** 先に実行するタスク名\n", "\n", "* 依存関係よりも緩やかな制約を付ける場合に利用する。\n", "* mustを通常使うとよい。\n", "* shouldは例外ケースに該当したら無視されるので、それでも問題ない時のみがよい。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### タスクの後始末\n", "\n", "後始末が必要なタスク名**.finalizedBy** 後始末を行うタスク名\n", "\n", "* 一連のタスクで生成した中間ファイルや、起動したプロセスの停止をしたい場合に利用する。\n", "* 前のタスクで例外やエラーになっても実行される。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### タスクの条件実行\n", "\n", "条件によって実行したいタスク名**.onlyIf** { 条件式 }\n", "\n", "* 条件式の戻り値をbool値にする。\n", "* コマンドの引数や環境変数によって変えたりしたい場合等。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### UP-TO-DATEでタスクをスキップ\n", "\n", "タスクの**inputs, outputs**プロパティのfileやdirへ、ファイルパスやディレクトリパスを指定すると、更新に応じてタスクをスキップする事が出来る。\n", "\n", "**outputs.upToDateWhen{ true }**とすると常に最新として扱われるので、**inputs**に更新があった場合のみ、タスクが実行されるようになる。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "参考:\n", "\n", "* Gradle徹底入門 \n", " * 6.2.2 Taskオブジェクト\n", " * 6.3.2 依存関係の定義方法\n", " * 6.3.4 タスクの制御\n", " * 6.3.7 タスクの順位付け\n", " * 6.3.8 ファイナライザータスク\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "* [17.4. Adding dependencies to a task](https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:adding_dependencies_to_tasks)\n", "* [17.5. Ordering tasks](https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:ordering_tasks)\n", "* [17.8. Skipping tasks](https://docs.gradle.org/current/userguide/more_about_tasks.html#N112CB)\n", "* [17.9. Skipping tasks that are up-to-date](https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:up_to_date_checks)\n", "* [17.11. Finalizer tasks](https://docs.gradle.org/current/userguide/more_about_tasks.html#N113D6)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### build.gradleの分割\n", "\n", "タスクが多くなってbuild.gradleが見づらくなってきた。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "-> build.gradleを分割してみましょう。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "\n", "build.gradleを以下のように記載。\n", "\n", "```groovy\n", "apply from: 'gradle/front.gradle'\n", "// URLも利用可能\n", "apply from: 'http://example.com/extra.gradle'\n", "\n", "// releaseのみ含めたい場合\n", "if (ext.env == 'release') {\n", " apply from: 'gradle/release.gradle'\n", "}\n", "```\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 注意!!\n", "\n", "Gradle Pluginを使ったタスクや\n", "\n", "Pluginのクラスを利用する場合は、\n", "\n", "classpathが読み込まれるか確認しておく" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Gradleを使った自動化のタスク例\n", "\n", "* [Apache POI](https://poi.apache.org)を使ってxlsxからcsvへ\n", "* [H2](http://www.h2database.com/html/main.html)を使ってcsvからSQLへ\n", "* windowsからLinuxのサーバへファイルを条件に応じて転送する\n", "* リモートに置いてあるファイルとの差分をチェックする\n", "* ブラウザから指定のリンクが活きてるかをチェックする\n", "* ローカルから[Jenkins](https://jenkins.io)のjobをRESTで実行する\n", "* etc.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 自動化するタスク例\n", "\n", "低頻度で発生する作業だけど、毎回手でやるには面倒くさい。\n", "\n", "でも、システム化するには工数がかかる。\n", "\n", "既にExcelで運用管理しているが、改善の優先順位が低い。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "そういったタスクをいかに楽して自動化するか?\n", "\n", "* PowerShell?\n", "* ShellScript(cygwin)?\n", "* JScript ?\n", "* .bat or .cmd ?\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "もしかしてVBですかーッ?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "**またまた、ご冗談を(AA略**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## なぜGradleを使うのか\n", "\n", "* Pluginがあれば、タスクの組み合わせで出来る。\n", "* Pluginが無ければ、一旦タスクにしてみる。\n", "* buildscriptブロックにライブラリを書けば、タスクで利用できる。\n", "* Gradle TestKitでを使うことで、テストが[Spock](https://github.com/spockframework/spock)で書ける。\n", "* Gradleに依存する部分としない部分を切り分けておけば、再利用しやすい。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### なぜGradleを使うのか\n", "\n", "* ファイルの移動、コピー、削除程度なら[CopySpec](https://docs.gradle.org/current/javadoc/org/gradle/api/file/CopySpec.html)の基本をおさえておけば十分活用できる。\n", "* ライブラリを呼ばなくてもJSON, JDBCラッパー等、Gradleが用意しているGroovyの標準機能で十分まかなえる。\n", "* 大きくなったら、クラスにして別のプロジェクトとして切り出すことも可能。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "オレオレTaskクラスは、Groovyだけでなく、もちろんJavaや他のJVM言語でも書けます!\n", "\n", "* 参考: [Chapter 38. Writing Custom Task Classes](https://docs.gradle.org/current/userguide/custom_tasks.html)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "タスクをクラスにして別のプロジェクトとして切り出す\n", "\n", "-> **Gradle Plugin** " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Gradle Pluginの紹介" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### [Gradle - Plugins](https://plugins.gradle.org/)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Gradle Pluginを知るポイント\n", "\n", "* READMEを読む\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Gradle Pluginを知るポイント\n", "\n", "* `src/main/resources/META-INF/gradle-plugins/`のpropertiesファイルにあるPluginのクラスを見つける\n", "* Pluginクラスの`apply`メソッドを探す\n", " * タスクの定義やExtensionの設定をしている為\n", "* Extensionクラスを探す\n", " * Pluginが利用する設定の名前や型を知る為" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Groovyに関するPlugin\n", "\n", "REPL(groovysh)を使いたい\n", "\n", "* [com.github.tkruse.groovysh](https://plugins.gradle.org/plugin/com.github.tkruse.groovysh)\n", "\n", "groovy scriptをgradleから実行したい\n", "\n", "* [com.mrhaki.groovyrun](https://plugins.gradle.org/plugin/com.mrhaki.groovyrun)\n", " * **SimpleHttpServer**が付いているので、簡易HTTPサーバが必要なときもこれで。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Download Task Plugin\n", "\n", "外部リソースをダウンロードしたい\n", "\n", "* [de.undercouch.download](https://plugins.gradle.org/plugin/de.undercouch.download)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### SSH Plugin\n", "\n", "[org.hidetake.ssh](https://plugins.gradle.org/plugin/org.hidetake.ssh)\n", "\n", "* ファイルを転送する\n", "* リモートのTomcat, Apacheの再起動等\n", "* SSHクライアントの代替\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### フロントエンドとの連携に関するPlugin\n", "\n", "CoffeeScriptやLESSなどのビルドをまとめて実行したい\n", "\n", "* [com.bertramlabs.asset-pipeline](https://plugins.gradle.org/plugin/com.bertramlabs.asset-pipeline)\n", "\n", "フロントエンドのNode.jsのタスクを実行したい\n", "\n", "* [com.moowork.node](https://plugins.gradle.org/plugin/com.moowork.node)\n", "* [com.moowork.grunt](https://plugins.gradle.org/plugin/com.moowork.grunt)\n", "* [com.moowork.gulp](https://plugins.gradle.org/plugin/com.moowork.gulp)\n", " * 利用例: [borysn/spring-boot-angular2](https://github.com/borysn/spring-boot-angular2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Git Plugin\n", "\n", "build時にGitのハッシュを取得する\n", "\n", "* Spring Boot Actuator向け\n", " * [com.gorylenko.gradle-git-properties](https://plugins.gradle.org/plugin/com.gorylenko.gradle-git-properties)\n", " * 参考: [SpringBootでリリースモジュールのGit情報を表示する](http://qiita.com/AkihiroTakamura/items/9f6a04de2a09e807efd8)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Git Plugin\n", "\n", "build時にGitのハッシュを取得する\n", "\n", "* その他\n", " * [org.ajoberstar.grgit](https://plugins.gradle.org/plugin/org.ajoberstar.grgit)\n", " * GitのHEADを取得して、applicationの成果物にファイルとして含める。\n", " * 参考: [Gradle Goodness: Use Git Commit Id in Build Script](http://mrhaki.blogspot.jp/2015/04/gradle-goodness-use-git-commit-id-in.html)\n", " * 参考: [50.1.1. The distribution](https://docs.gradle.org/current/userguide/application_plugin.html#N15EBE)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Dockerに関するPlugin\n", "\n", "Dockerfileやdocker-compose.ymlを生成したり、dockerのコマンドを[docker-java](https://github.com/docker-java/docker-java)で実行する\n", "\n", "* [com.bmuschko.docker-java-application](https://plugins.gradle.org/plugin/com.bmuschko.docker-java-application)\n", "* [com.chrisgahlert.gradle-dcompose-plugin](https://plugins.gradle.org/plugin/com.chrisgahlert.gradle-dcompose-plugin)\n", "* [com.palantir.docker](https://plugins.gradle.org/plugin/com.palantir.docker)\n", "* [de.gesellix.docker](https://plugins.gradle.org/plugin/de.gesellix.docker)\n", " * 参考: [gesellix/gradle-docker-plugin-example](https://github.com/gesellix/gradle-docker-plugin-example)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### JRuby Gradle Plugin\n", "\n", "GradleからJRubyを実行したい\n", "\n", "* [com.github.jruby-gradle.base](https://plugins.gradle.org/plugin/com.github.jruby-gradle.base)\n", "\n", "[Asciidoctor](http://asciidoctor.org/)を使いたい場合も\n", "\n", "* [org.asciidoctor.gradle.asciidoctor](https://plugins.gradle.org/plugin/org.asciidoctor.gradle.asciidoctor)\n", " * 参考: [asciidoctor/asciidoctor-gradle-examples](https://github.com/asciidoctor/asciidoctor-gradle-examples)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### その他のPlugin\n", "\n", "DBのマイグレーション\n", "\n", "* [org.flywaydb.flyway](https://plugins.gradle.org/plugin/org.flywaydb.flyway)\n", "\n", "AWSに関する操作\n", "\n", "* [jp.classmethod.aws](https://plugins.gradle.org/plugin/jp.classmethod.aws)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### その他のPlugin\n", "\n", "Nebula Plugin\n", "\n", "* [Nebula: A collection of Gradle plugins, built by Netflix](http://nebula-plugins.github.io/)\n", "* Netflixで利用されている、ビルドに関係するGradle Pluginのセット。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## まとめ\n", "\n", "* Gradleは怖くない。\n", "* 小さいタスクを作る。\n", "* タスクを繋げる。\n", "* 大きくなったら分割する。\n", "* 困ったらPluginを探してみる。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Let's enjoy Gradle!" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Bash", "language": "bash", "name": "bash" }, "language_info": { "codemirror_mode": "shell", "file_extension": ".sh", "mimetype": "text/x-sh", "name": "bash" } }, "nbformat": 4, "nbformat_minor": 0 }