SlideShare a Scribd company logo
1 of 41
Download to read offline
sbt(すぶた)職人のススメ
かとじゅん@j5ik2o
誰?
• 加藤潤一(かとうじゅんいち)
• j5ik2o = junichikato = j unich i k at o = j5ik2o
• 年齢 0x2B
• ChatWork社 テックリード
• スキル
• DDD x Scala 伝道師
• ケトジェニック・ダイエット・アドバイザー
• 他にもスキル習得中。8月公開予定
今日のテーマは…
酢豚じゃなくsbtの話です
アジェンダ
• 基礎
• 実践
• セッティング
• タスク
• プラグイン
基礎
インストール
$ brew install sbt

==> Downloading https://homebrew.bintray.com/bottles/
sbt-0.13.8.yosemite.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/
sbt-0.13.8.yosemite.bottle.tar.gz
==> Pouring sbt-0.13.8.yosemite.bottle.tar.gz
==> Caveats
You can use $SBT_OPTS to pass additional JVM options to SBT:
SBT_OPTS="-XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M"
This formula is now using the standard typesafe sbt launcher script.
Project specific options should be placed in .sbtopts in the root of your
project.
Global settings should be placed in /usr/local/etc/sbtopts
==> Summary
🍺 /usr/local/Cellar/sbt/0.13.8: 5 files, 1.2M
プロジェクトの最小構成
$ brew install typesafe-activator
==> Downloading https://downloads.typesafe.com/typesafe-activator/1.3.2/typesafe-
activator-1.3.2.zip
Already downloaded: /Library/Caches/Homebrew/typesafe-activator-1.3.2.zip
🍺 /usr/local/Cellar/typesafe-activator/1.3.2: 4413 files, 470M, built in 9 seconds
$ activator new sbt-simple
Fetching the latest list of templates...
Browse the list of templates: http://typesafe.com/activator/templates
Choose from these featured templates or enter a template name:
1) minimal-akka-java-seed
2) minimal-akka-scala-seed
3) minimal-java
4) minimal-scala
5) play-java
6) play-scala
(hit tab to see a list of all templates)
> 4

OK, application "sbt-simple" is being created using the "minimal-scala" template.
To run "sbt-simple" from the command line, "cd sbt-simple" then:
/Users/cw-junichi/temp/sbt-simple/activator run
To run the test for "sbt-simple" from the command line, "cd sbt-simple" then:
/Users/cw-junichi/temp/sbt-simple/activator test
To run the Activator UI for "sbt-simple" from the command line, "cd sbt-simple" then:
/Users/cw-junichi/temp/sbt-simple/activator ui
生成されたファイル群
.
"## LICENSE
"## activator
"## activator-launch-1.3.2.jar
"## build.sbt
"## project
$   &## build.properties
&## src
"## main
$   &## scala
$   &## com
$   &## example
$   &## Hello.scala
&## test
&## scala
&## HelloSpec.scala
build.sbt
name := """sbt-simple"""
version := "1.0"
scalaVersion := "2.11.7"
// Change this to another test framework if you prefer
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test"
// Uncomment to use Akka
//libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.11"
project/build.properties
Activator-generated Properties
#Thu Jul 30 14:55:12 JST 2015
template.uuid=e17acfbb-1ff5-41f5-b8cf-2c40be6a8340
sbt.version=0.13.8 # sbtのバージョンを固定できる
build.sbt vs project/Build.scala
• sbt 0.12の時代は、マルチプロジェクトのために
Build.scalaを利用していた。
• sbt 0.13からは、build.sbtだけでマルチプロジェク
トに対応できるようになった。加えてval, def も定
義できるようになった。
• Build.scalaは積極的に使わなくなった?
sbt compile
$ sbt
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/project/}sbt-simple-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-
simple/)

> compile
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/
scala-2.11/classes...
[success] Total time: 3 s, completed 2015/07/30 15:37:49
$ sbt compile
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/
sbt-simple/)
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/
scala-2.11/classes...
[success] Total time: 3 s, completed 2015/07/30 15:38:19
sbt run
package com.example
object Hello {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
$ sbt run
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
[info] Running com.example.Hello
Hello, world!
[success] Total time: 0 s, completed 2015/07/30 15:40:02
sbt test
import org.scalatest._
class HelloSpec extends FlatSpec with Matchers {
"Hello" should "have tests" in {
true should === (true)
}
}
$ sbt test
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/)
[info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/scala-2.11/
test-classes...
[info] HelloSpec:
[info] Hello
[info] - should have tests
[info] Run completed in 294 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 4 s, completed 2015/07/30 15:42:53
IDEAでそのまま読み込めます
マルチプロジェクト
lazy val commonSettings = Seq(
organization := "com.example",
version := "0.1.0",
scalaVersion := "2.11.4"
)
lazy val core = (project in file("core")).
settings(commonSettings: _*).
settings(
// other settings
)
lazy val util = (project in file("util")).
settings(commonSettings: _*).
settings(
// other settings
)
lazy val root = (project in file(".")).
aggregate(util, core)
プラグイン
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0")
Add following to project/plugins.sbt
scalariformSettings
Add following to build.sbt
$ sbt scalariformFormat
$ sbt compile
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/)
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple...
[info] Formatting 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile) ...
[info] Resolving org.scala-lang#scala-library;2.11.7 ...
[info] Reformatted 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile).
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[success] Total time: 1 s, completed 2015/07/30 16:24:30
Execute plugin’s function.
実践
コマンド
def hello = Command.command("hello") { state =>
println("Hello")
state
}
commands ++= Seq(hello)
コマンドの定義
$ sbt hello

[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
Hello
コマンド名で呼び出す
sbtで使えるキー
• キーには3種類ある
• SettingKey[T]
• 一度だけ値が計算されるキー(値はプロジェクトの読み込
み時に計算され、保存される)
• TaskKey[T]
• 毎回再計算されるタスクを呼び出す、副作用を伴う可能性
のある値のキー。
• InputKey[T]
• コマンドラインの引数を入力として受け取るタスクのキー。
• 組み込みキー
• import sbt.Keys._
セッティング
lazy val message = settingKey[String]("message")

message := “hello”
セッティングキーを定義して、セッティングに対して値を割り当てる
$ sbt message

[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
[info] hello
セッティングキー名で呼び出す
タスク
lazy val hello = taskKey[Unit]("An example task")

hello := { println(“Hello!") }
タスクキーを定義して、タスクに対して関数を割り当てる
$ sbt hello

[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
Hello!
[success] Total time: 0 s, completed 2015/07/31 10:51:11
タスクキー名で呼び出す
タスクからセッティングを参照する
lazy val message = settingKey[String]("message")
lazy val say = taskKey[Unit]("say task")
message := "hello"
say := { println(message.value) }
セッティングキー名.valueで割当られている値を参照する
$ sbt say
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
hello
[success] Total time: 0 s, completed 2015/07/31 12:04:46
タスクの結果を得る
lazy val message = settingKey[String]("message")
lazy val modifier = taskKey[String]("modifier task")
lazy val display = taskKey[Unit]("display task")
message := "hello"
modifier := { "{{{" + message.value + "}}}" }
display := { println(modifier.value) }
タスクキー.valueでタスクの結果を得ることができる
$ sbt display
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
{{{hello}}}
[success] Total time: 0 s, completed 2015/08/01 7:43:23
タスクの実行意味論
val startServer = taskKey[Unit]("start server")
val stopServer = taskKey[Unit]("stop server")
val sampleIntTask = taskKey[Int]("A sample int task.")
val sampleStringTask = taskKey[String]("A sample string task.")
startServer := {
println("starting...")
Thread.sleep(500)
}
stopServer := {
println("stopping...")
Thread.sleep(500)
}
sampleIntTask := {
startServer.value
val sum = 1 + 2
println("sum: " + sum)
stopServer.value // THIS WON'T WORK
sum
}
sampleStringTask := {
startServer.value
val s = sampleIntTask
.value.toString
println("s: " + s)
s
}
$ sbt sampleStringTask
[info] Loading project definition from /
Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in
build file:/Users/cw-junichi/temp/sbt-
simple/)
stopping...
starting...
sum: 3
s: 3
[success] Total time: 1 s, completed
2015/07/31 12:40:28
sampleIntTask := {
ServerUtil.startServer
try {
val sum = 1 + 2
println("sum: " + sum)
sum
} finally {
ServerUtil.stopServer
}
}
スコープ
• マルチプロジェクトで、各プロジェクトにおいて
同じキーが別の値を取ることができる
• メインとテストのソースで異なるようにコンパイ
ルしたければ、compileキーは別の値と取ること
ができる
• つまり、キーとスコープによって値が決定され
る
• スコープには、プロジェクト、コンフィグレーショ
ン、タスクがある。
タスクのスコープ
lazy val say = taskKey[Unit](“say task”)



lazy val message = settingKey[String]("message")
lazy val modifier = taskKey[String]("modifier task")
lazy val display = taskKey[Unit]("display task")
message in say := "hello"
modifier in say := { "{{{" + (message in say).value + "}}}" }
display in say := { println((modifier in say).value) }
$ sbt say::display
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
{{{hello}}}
[success] Total time: 0 s, completed 2015/08/01 7:45:33
sbt plugin
sbtPlugin := true



name := """sbt-simple-plugin"""
version := "1.0"
scalaVersion := “2.10.5"
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test"
sbtPlugin := trueとするだけ、他は通常のsbtプロジェクトと同じ
chatwork/sbt-docker
chatwork/sbt-docker
$ sbt docker::build
[info] Loading project definition from /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/project
[info] Set current project to simple (in build file:/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/)
[info] generated docker file from template file. dockerTemplate = /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/
docker/Dockerfile.ftl, templateContext = Map(name -> simple, version -> 0.1-SNAPSHOT), dockerfile = /Users/cw-junichi/sbt-
docker/src/sbt-test/sbt-docker/simple/docker/Dockerfile
[info] Set(/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/target/docker/Dockerfile, /Users/cw-junichi/sbt-docker/
src/sbt-test/sbt-docker/simple/target/docker/bin/echo.sh)
[info] userName = , emailAddress =
[info] Step 0 : FROM busybox
[info] ---> 8c2e06607696
[info] Step 1 : ADD bin/echo.sh /
[info] ---> f7bffdfc573c
[info] Removing intermediate container f6a8e236bf34
[info] Step 2 : CMD sh /echo.sh simple-0.1-SNAPSHOT
[info] ---> Running in d761354df21a
[info] ---> 7ae24d96c42c
[info] Removing intermediate container d761354df21a
[info] Successfully built 7ae24d96c42c
[info] docker build, imageId = 7ae24d96c42c
[success] Total time: 3 s, completed 2015/07/31 13:58:46
docker build
docker buildの前にアプリケーションをbuildできる。
ディレクトリ構成
"## build.sbt
"## project
$   "## build.properties
$   "## plugins.sbt
$   "## scripted.sbt
"## release.sbt
"## scripted.sbt
"## src
$   "## main
$   $   "## resources
$   $   $   &## logback.xml
$   $   &## scala
$   $   &## com
$   $   &## chatwork
$   $   &## sbt
$   $   &## docker
$   $   "## BuildOptions.scala
$   $   "## DockerfileBuilder.scala
$   $   "## SbtDocker.scala
$   $   "## SbtDockerKeys.scala
$   $   &## SbtDockerPlugin.scala
$   &## sbt-test
$   &## sbt-docker
$   &## simple
$   "## build.sbt
$   "## docker
$   $   "## Dockerfile.ftl
$   $   &## bin
$   $   &## echo.sh
$   &## project
$      &## plugins.sbt
&## version.sbt
build.sbt
import scalariform.formatter.preferences._
scalaVersion := "2.10.5"
sonatypeProfileName := "com.chatwork"
organization := "com.chatwork"
publishMavenStyle := true
publishArtifact in Test := false
pomIncludeRepository := {
_ => false
}
pomExtra := {
<url>https://github.com/chatwork/sbt-docker</url>
<licenses>
<license>
<name>The MIT License</name>
<url>http://opensource.org/licenses/MIT</url>
</license>
</licenses>
<scm>
<url>git@github.com:chatwork/sbt-docker.git</url>
<connection>scm:git:github.com/chatwork/sbt-docker</
connection>
<developerConnection>scm:git:git@github.com:chatwork/
sbt-docker.git</developerConnection>
</scm>
<developers>
<developer>
<id>cw-junichikato</id>
<name>Junichi Kato</name>
</developer>
</developers>
}
name := "sbt-docker"
sbtPlugin := true



resolvers ++= Seq(
"Sonatype OSS Snapshot Repository" at "https://
oss.sonatype.org/content/repositories/snapshots/",
"Sonatype OSS Release Repository" at "https://
oss.sonatype.org/content/repositories/releases/",
"Typesafe Releases" at "http://repo.typesafe.com/
typesafe/releases/"
)



libraryDependencies ++= Seq(
"com.spotify" % "docker-client" % "2.7.7",
"ch.qos.logback" % "logback-classic" % "1.1.3",
"org.slf4j" % "slf4j-api" % "1.7.12",
"org.freemarker" % "freemarker" % "2.3.14"
)
scalariformSettings
ScalariformKeys.preferences :=
ScalariformKeys.preferences.value
.setPreference(AlignParameters, true)
.setPreference(AlignSingleLineCaseStatements, true)
.setPreference(DoubleIndentClassDeclaration, true)
.setPreference(PreserveDanglingCloseParenthesis, true)
.setPreference(MultilineScaladocCommentsStartOnFirstLin
e, false)
credentials <<= Def.task {
val ivyCredentials = (baseDirectory in
LocalRootProject).value / ".credentials"
val result = Credentials(ivyCredentials) :: Nil
result
}
project/plugins.sbt
logLevel := Level.Warn
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.0")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.0")
プラグイン本体
package
com.chatwork.sbt.docker
import sbt.Keys._
import sbt._
import sbt.plugins.IvyPlugin
object SbtDockerPlugin
extends AutoPlugin {
override def trigger =
allRequirements
override def requires:
Plugins = IvyPlugin
object autoImport extends
SbtDockerKeys
import SbtDocker._
import SbtDockerKeys._
override def projectSettings: Seq[Def.Setting[_]] = Seq(
name in docker := (name in thisProjectRef).value,
sourceDirectory in docker := baseDirectory.value / "docker",
buildDirectory in docker :=
baseDirectory.value / "target" / "docker",
sourceFiles in docker := Seq(),
login in docker := false,
emailAddress in docker := "",
userName in docker := "",
password in docker := "",
buildOptions in docker := Set.empty[BuildOptions.Value],
build in docker <<=
dockerBuildTask dependsOn (copySourceFiles in docker),
copySourceFiles in docker <<= copySourceFilesTask,
dockerfileTemplate in docker :=
(sourceDirectory in docker).value / "Dockerfile.ftl",
dockerfile in docker :=
(sourceDirectory in docker).value / "Dockerfile",
templateContext in docker := Map(
"name" -> (name in thisProjectRef).value,
"version" -> (version in thisProjectRef).value
),
generateDockerfile in docker <<= generateDockerfileTask,
push in docker <<= dockerPushTask,
pull in docker <<= dockerPullTask,
list in docker <<= dockerListImagesTask,
start in docker <<= dockerStartTask dependsOn (copySourceFiles in docker),
startAndWait in docker <<=
dockerStartAndWaitTask dependsOn (copySourceFiles in docker)
)
}
Key関係
val build = taskKey[Option[String]]("build")
val buildOptions = settingKey[Set[BuildOptions.Value]]
("build-options")
val buildDirectory = settingKey[File]("build-
directory")
// ---
val dockerfileTemplate = settingKey[File]("dockerfile-
template")
val dockerfile = settingKey[File]("dockerfile")
val templateContext = settingKey[Map[String, String]]
("template-context")
val generateDockerfile = taskKey[File]("generate-
dockerfile")
// ---
val push = taskKey[Unit]("push")
val pull = taskKey[Unit]("pull")
val list = taskKey[Unit]("list")
val start = taskKey[Option[Future[String]]]("start")
val startAndWait = taskKey[Unit]("start-and-wait")
}
package com.chatwork.sbt.docker
import sbt._
import scala.concurrent.Future
object SbtDockerKeys extends SbtDockerKeys
trait SbtDockerKeys {
val docker = taskKey[Unit]("docker")
val login = settingKey[Boolean]("login")
val emailAddress = settingKey[String]("email-
address")
val userName = settingKey[String]("user-name")
val password = settingKey[String]("password")
// ---
val sourceFiles = taskKey[Seq[(File, String)]]
("source-files")
val copySourceFiles = taskKey[Set[File]]
("copy-source-files")
// ---
タスクの定義
trait SbtDocker {
def dockerBuildTask: Def.Initialize[Task[Option[String]]] = Def.task {
val logger = streams.value.log
val sut = dockerClient.value
val workDir = (buildDirectory in docker).value.toPath
val repositoryName = (name in docker).value
val bo = (buildOptions in docker).value.map(toBuildParameter)
Try {
val result = sut.build(workDir, repositoryName, progressHandler(logger)
{ pm => Some(pm.stream()) }, bo.toArray: _*)
logger.info(s"docker build, imageId = $result")
Some(result)
}.recover {
case ex: DockerException =>
logger.error(ex.toString)
None
}.get
}
}
AutoPlugin
• これまでは
• project/plugins.sbtにプラグインを追加
• build.sbtにプラグイン固有のセッティングを追加
• AutoPluginでは、タスク、セッティングなどのビルド定義を自動的に追加できる
• 明示的に利用するプラグインを指定できる。
• (project in file(“.”)).enablePlugins(a, b).disablePlugins(c)
• requires
• 依存しているプラグイン(AutoPlugin)を指定できる
• trigger
• プラグインが動作する条件。allRequirementsは、すべての依存プラグインが
使えるようになってから動作できるようにする。
• autoImport
• importの自動化。autoImportメンバー内に存在するものはimport宣言なしで
利用できるようになる
お知らせ
ありがとうございました

More Related Content

What's hot

Java, Ruby & Rails
Java, Ruby & RailsJava, Ruby & Rails
Java, Ruby & RailsPeter Lind
 
Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)DECK36
 
Java Unit Testing with Unitils
Java Unit Testing with UnitilsJava Unit Testing with Unitils
Java Unit Testing with UnitilsMikalai Alimenkou
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentAll Things Open
 
Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrationstakezoe
 
“Purikura” culture in Japan and our web application architecture
“Purikura” culturein Japan andour web application architecture“Purikura” culturein Japan andour web application architecture
“Purikura” culture in Japan and our web application architectureKoichi Sakata
 
Ruby - a tester's best friend
Ruby - a tester's best friendRuby - a tester's best friend
Ruby - a tester's best friendPeter Lind
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkAarti Parikh
 
Play Framework 2.5
Play Framework 2.5Play Framework 2.5
Play Framework 2.5m-kurz
 
Dmp hadoop getting_start
Dmp hadoop getting_startDmp hadoop getting_start
Dmp hadoop getting_startGim GyungJin
 
JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発Naoto Takai
 
A Taste of Clojure
A Taste of ClojureA Taste of Clojure
A Taste of ClojureDavid Leung
 
Node.js Explained
Node.js ExplainedNode.js Explained
Node.js ExplainedJeff Kunkle
 
Gradle in a Polyglot World
Gradle in a Polyglot WorldGradle in a Polyglot World
Gradle in a Polyglot WorldSchalk Cronjé
 
Single Page Applications in Drupal
Single Page Applications in DrupalSingle Page Applications in Drupal
Single Page Applications in DrupalChris Tankersley
 
Pse2010 rel storage
Pse2010 rel storagePse2010 rel storage
Pse2010 rel storageLars Noldan
 

What's hot (20)

Java, Ruby & Rails
Java, Ruby & RailsJava, Ruby & Rails
Java, Ruby & Rails
 
NodeJS for Beginner
NodeJS for BeginnerNodeJS for Beginner
NodeJS for Beginner
 
Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)
 
Java Unit Testing with Unitils
Java Unit Testing with UnitilsJava Unit Testing with Unitils
Java Unit Testing with Unitils
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrations
 
Zen of Akka
Zen of AkkaZen of Akka
Zen of Akka
 
“Purikura” culture in Japan and our web application architecture
“Purikura” culturein Japan andour web application architecture“Purikura” culturein Japan andour web application architecture
“Purikura” culture in Japan and our web application architecture
 
Ruby - a tester's best friend
Ruby - a tester's best friendRuby - a tester's best friend
Ruby - a tester's best friend
 
Nodejs vatsal shah
Nodejs vatsal shahNodejs vatsal shah
Nodejs vatsal shah
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talk
 
Play Framework 2.5
Play Framework 2.5Play Framework 2.5
Play Framework 2.5
 
Nashorn
NashornNashorn
Nashorn
 
Dmp hadoop getting_start
Dmp hadoop getting_startDmp hadoop getting_start
Dmp hadoop getting_start
 
JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発
 
A Taste of Clojure
A Taste of ClojureA Taste of Clojure
A Taste of Clojure
 
Node.js Explained
Node.js ExplainedNode.js Explained
Node.js Explained
 
Gradle in a Polyglot World
Gradle in a Polyglot WorldGradle in a Polyglot World
Gradle in a Polyglot World
 
Single Page Applications in Drupal
Single Page Applications in DrupalSingle Page Applications in Drupal
Single Page Applications in Drupal
 
Pse2010 rel storage
Pse2010 rel storagePse2010 rel storage
Pse2010 rel storage
 

Viewers also liked

コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門潤一 加藤
 
第一回Scala会議
第一回Scala会議第一回Scala会議
第一回Scala会議潤一 加藤
 
Servlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksServlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksKazuhiro Sera
 
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)潤一 加藤
 
3週連続DDDその1 ドメイン駆動設計の基本を理解する
3週連続DDDその1  ドメイン駆動設計の基本を理解する3週連続DDDその1  ドメイン駆動設計の基本を理解する
3週連続DDDその1 ドメイン駆動設計の基本を理解する増田 亨
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発Kota Mizushima
 
RICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフトRICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフトTakehiko YOSHIDA
 
某S社のddd(メイリオ)
某S社のddd(メイリオ)某S社のddd(メイリオ)
某S社のddd(メイリオ)kumake
 
Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例侑亮 原田
 
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekJava エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekKazuhiro Sera
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24Kazuhiro Sera
 
めんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaめんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaKazuhiro Sera
 
Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今Koichi Sakata
 
GANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経ったGANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経ったYasuyuki Sugitani
 
Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)Yuki Katada
 
JPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミングJPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミングYohsuke Furuta
 
はじめての CircleCI
はじめての CircleCIはじめての CircleCI
はじめての CircleCIYosuke Mizutani
 
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016Yota Ishida
 

Viewers also liked (20)

Scala with DDD
Scala with DDDScala with DDD
Scala with DDD
 
コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門
 
Actor&stm
Actor&stmActor&stm
Actor&stm
 
第一回Scala会議
第一回Scala会議第一回Scala会議
第一回Scala会議
 
Servlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksServlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ks
 
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
 
3週連続DDDその1 ドメイン駆動設計の基本を理解する
3週連続DDDその1  ドメイン駆動設計の基本を理解する3週連続DDDその1  ドメイン駆動設計の基本を理解する
3週連続DDDその1 ドメイン駆動設計の基本を理解する
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発
 
RICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフトRICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフト
 
某S社のddd(メイリオ)
某S社のddd(メイリオ)某S社のddd(メイリオ)
某S社のddd(メイリオ)
 
Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例
 
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekJava エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
 
めんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaめんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scala
 
Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今
 
GANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経ったGANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経った
 
Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)
 
JPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミングJPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミング
 
はじめての CircleCI
はじめての CircleCIはじめての CircleCI
はじめての CircleCI
 
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
 

Similar to Sbt職人のススメ

An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbtFabio Fumarola
 
Continuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and JenkinsContinuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and JenkinsFrancesco Bruni
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new buildIgor Khotin
 
sbt 0.10 for beginners?
sbt 0.10 for beginners?sbt 0.10 for beginners?
sbt 0.10 for beginners?k4200
 
Acquia BLT for the Win, or How to speed up the project setup, development an...
Acquia BLT for the Win, or  How to speed up the project setup, development an...Acquia BLT for the Win, or  How to speed up the project setup, development an...
Acquia BLT for the Win, or How to speed up the project setup, development an...DrupalCamp Kyiv
 
sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)Eugene Yokota
 
Developing Liferay Plugins with Maven
Developing Liferay Plugins with MavenDeveloping Liferay Plugins with Maven
Developing Liferay Plugins with MavenMika Koivisto
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Tomek Kaczanowski
 
SBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaSBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaVasil Remeniuk
 
How to start using Scala
How to start using ScalaHow to start using Scala
How to start using ScalaNgoc Dao
 
Sbt, idea and eclipse
Sbt, idea and eclipseSbt, idea and eclipse
Sbt, idea and eclipseMike Slinn
 

Similar to Sbt職人のススメ (20)

SBT Concepts, part 2
SBT Concepts, part 2SBT Concepts, part 2
SBT Concepts, part 2
 
An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbt
 
Pragmatic sbt
Pragmatic sbtPragmatic sbt
Pragmatic sbt
 
Apache DeltaSpike: The CDI Toolbox
Apache DeltaSpike: The CDI ToolboxApache DeltaSpike: The CDI Toolbox
Apache DeltaSpike: The CDI Toolbox
 
Apache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolboxApache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolbox
 
Gradle como alternativa a maven
Gradle como alternativa a mavenGradle como alternativa a maven
Gradle como alternativa a maven
 
Intro to sbt-web
Intro to sbt-webIntro to sbt-web
Intro to sbt-web
 
Continuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and JenkinsContinuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and Jenkins
 
Simple build tool
Simple build toolSimple build tool
Simple build tool
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new build
 
Dev ops meetup
Dev ops meetupDev ops meetup
Dev ops meetup
 
sbt 0.10 for beginners?
sbt 0.10 for beginners?sbt 0.10 for beginners?
sbt 0.10 for beginners?
 
Acquia BLT for the Win, or How to speed up the project setup, development an...
Acquia BLT for the Win, or  How to speed up the project setup, development an...Acquia BLT for the Win, or  How to speed up the project setup, development an...
Acquia BLT for the Win, or How to speed up the project setup, development an...
 
SBT Crash Course
SBT Crash CourseSBT Crash Course
SBT Crash Course
 
sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)
 
Developing Liferay Plugins with Maven
Developing Liferay Plugins with MavenDeveloping Liferay Plugins with Maven
Developing Liferay Plugins with Maven
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010
 
SBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaSBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius Valatka
 
How to start using Scala
How to start using ScalaHow to start using Scala
How to start using Scala
 
Sbt, idea and eclipse
Sbt, idea and eclipseSbt, idea and eclipse
Sbt, idea and eclipse
 

Recently uploaded

Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...OnePlan Solutions
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxRTS corp
 
Advantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxAdvantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxRTS corp
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxAS Design & AST.
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...OnePlan Solutions
 
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...kalichargn70th171
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogueitservices996
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfkalichargn70th171
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolsosttopstonverter
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...Bert Jan Schrijver
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesVictoriaMetrics
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxSasikiranMarri
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITmanoharjgpsolutions
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfRTS corp
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonApplitools
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecturerahul_net
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfmaor17
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shardsChristopher Curtin
 

Recently uploaded (20)

Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
 
Advantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxAdvantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptx
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptx
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
 
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogue
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration tools
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 Updates
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh IT
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecture
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdf
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards
 

Sbt職人のススメ

  • 2. 誰? • 加藤潤一(かとうじゅんいち) • j5ik2o = junichikato = j unich i k at o = j5ik2o • 年齢 0x2B • ChatWork社 テックリード • スキル • DDD x Scala 伝道師 • ケトジェニック・ダイエット・アドバイザー • 他にもスキル習得中。8月公開予定
  • 5.
  • 6. アジェンダ • 基礎 • 実践 • セッティング • タスク • プラグイン
  • 8. インストール $ brew install sbt
 ==> Downloading https://homebrew.bintray.com/bottles/ sbt-0.13.8.yosemite.bottle.tar.gz Already downloaded: /Library/Caches/Homebrew/ sbt-0.13.8.yosemite.bottle.tar.gz ==> Pouring sbt-0.13.8.yosemite.bottle.tar.gz ==> Caveats You can use $SBT_OPTS to pass additional JVM options to SBT: SBT_OPTS="-XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M" This formula is now using the standard typesafe sbt launcher script. Project specific options should be placed in .sbtopts in the root of your project. Global settings should be placed in /usr/local/etc/sbtopts ==> Summary 🍺 /usr/local/Cellar/sbt/0.13.8: 5 files, 1.2M
  • 9. プロジェクトの最小構成 $ brew install typesafe-activator ==> Downloading https://downloads.typesafe.com/typesafe-activator/1.3.2/typesafe- activator-1.3.2.zip Already downloaded: /Library/Caches/Homebrew/typesafe-activator-1.3.2.zip 🍺 /usr/local/Cellar/typesafe-activator/1.3.2: 4413 files, 470M, built in 9 seconds $ activator new sbt-simple Fetching the latest list of templates... Browse the list of templates: http://typesafe.com/activator/templates Choose from these featured templates or enter a template name: 1) minimal-akka-java-seed 2) minimal-akka-scala-seed 3) minimal-java 4) minimal-scala 5) play-java 6) play-scala (hit tab to see a list of all templates) > 4
 OK, application "sbt-simple" is being created using the "minimal-scala" template. To run "sbt-simple" from the command line, "cd sbt-simple" then: /Users/cw-junichi/temp/sbt-simple/activator run To run the test for "sbt-simple" from the command line, "cd sbt-simple" then: /Users/cw-junichi/temp/sbt-simple/activator test To run the Activator UI for "sbt-simple" from the command line, "cd sbt-simple" then: /Users/cw-junichi/temp/sbt-simple/activator ui
  • 10. 生成されたファイル群 . "## LICENSE "## activator "## activator-launch-1.3.2.jar "## build.sbt "## project $   &## build.properties &## src "## main $   &## scala $   &## com $   &## example $   &## Hello.scala &## test &## scala &## HelloSpec.scala
  • 11. build.sbt name := """sbt-simple""" version := "1.0" scalaVersion := "2.11.7" // Change this to another test framework if you prefer libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test" // Uncomment to use Akka //libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.11" project/build.properties Activator-generated Properties #Thu Jul 30 14:55:12 JST 2015 template.uuid=e17acfbb-1ff5-41f5-b8cf-2c40be6a8340 sbt.version=0.13.8 # sbtのバージョンを固定できる
  • 12. build.sbt vs project/Build.scala • sbt 0.12の時代は、マルチプロジェクトのために Build.scalaを利用していた。 • sbt 0.13からは、build.sbtだけでマルチプロジェク トに対応できるようになった。加えてval, def も定 義できるようになった。 • Build.scalaは積極的に使わなくなった?
  • 13. sbt compile $ sbt [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/project/}sbt-simple-build... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt- simple/)
 > compile [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple... [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/ scala-2.11/classes... [success] Total time: 3 s, completed 2015/07/30 15:37:49 $ sbt compile [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/ sbt-simple/) [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple... [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/ scala-2.11/classes... [success] Total time: 3 s, completed 2015/07/30 15:38:19
  • 14. sbt run package com.example object Hello { def main(args: Array[String]): Unit = { println("Hello, world!") } } $ sbt run [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) [info] Running com.example.Hello Hello, world! [success] Total time: 0 s, completed 2015/07/30 15:40:02
  • 15. sbt test import org.scalatest._ class HelloSpec extends FlatSpec with Matchers { "Hello" should "have tests" in { true should === (true) } } $ sbt test [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/) [info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/scala-2.11/ test-classes... [info] HelloSpec: [info] Hello [info] - should have tests [info] Run completed in 294 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 [info] All tests passed. [success] Total time: 4 s, completed 2015/07/30 15:42:53
  • 17. マルチプロジェクト lazy val commonSettings = Seq( organization := "com.example", version := "0.1.0", scalaVersion := "2.11.4" ) lazy val core = (project in file("core")). settings(commonSettings: _*). settings( // other settings ) lazy val util = (project in file("util")). settings(commonSettings: _*). settings( // other settings ) lazy val root = (project in file(".")). aggregate(util, core)
  • 18. プラグイン addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") Add following to project/plugins.sbt scalariformSettings Add following to build.sbt $ sbt scalariformFormat $ sbt compile [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/) [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple... [info] Formatting 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile) ... [info] Resolving org.scala-lang#scala-library;2.11.7 ... [info] Reformatted 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile). [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [success] Total time: 1 s, completed 2015/07/30 16:24:30 Execute plugin’s function.
  • 20. コマンド def hello = Command.command("hello") { state => println("Hello") state } commands ++= Seq(hello) コマンドの定義 $ sbt hello
 [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) Hello コマンド名で呼び出す
  • 21. sbtで使えるキー • キーには3種類ある • SettingKey[T] • 一度だけ値が計算されるキー(値はプロジェクトの読み込 み時に計算され、保存される) • TaskKey[T] • 毎回再計算されるタスクを呼び出す、副作用を伴う可能性 のある値のキー。 • InputKey[T] • コマンドラインの引数を入力として受け取るタスクのキー。 • 組み込みキー • import sbt.Keys._
  • 22. セッティング lazy val message = settingKey[String]("message")
 message := “hello” セッティングキーを定義して、セッティングに対して値を割り当てる $ sbt message
 [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) [info] hello セッティングキー名で呼び出す
  • 23. タスク lazy val hello = taskKey[Unit]("An example task")
 hello := { println(“Hello!") } タスクキーを定義して、タスクに対して関数を割り当てる $ sbt hello
 [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) Hello! [success] Total time: 0 s, completed 2015/07/31 10:51:11 タスクキー名で呼び出す
  • 24. タスクからセッティングを参照する lazy val message = settingKey[String]("message") lazy val say = taskKey[Unit]("say task") message := "hello" say := { println(message.value) } セッティングキー名.valueで割当られている値を参照する $ sbt say [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) hello [success] Total time: 0 s, completed 2015/07/31 12:04:46
  • 25. タスクの結果を得る lazy val message = settingKey[String]("message") lazy val modifier = taskKey[String]("modifier task") lazy val display = taskKey[Unit]("display task") message := "hello" modifier := { "{{{" + message.value + "}}}" } display := { println(modifier.value) } タスクキー.valueでタスクの結果を得ることができる $ sbt display [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) {{{hello}}} [success] Total time: 0 s, completed 2015/08/01 7:43:23
  • 26. タスクの実行意味論 val startServer = taskKey[Unit]("start server") val stopServer = taskKey[Unit]("stop server") val sampleIntTask = taskKey[Int]("A sample int task.") val sampleStringTask = taskKey[String]("A sample string task.") startServer := { println("starting...") Thread.sleep(500) } stopServer := { println("stopping...") Thread.sleep(500) } sampleIntTask := { startServer.value val sum = 1 + 2 println("sum: " + sum) stopServer.value // THIS WON'T WORK sum } sampleStringTask := { startServer.value val s = sampleIntTask .value.toString println("s: " + s) s } $ sbt sampleStringTask [info] Loading project definition from / Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt- simple/) stopping... starting... sum: 3 s: 3 [success] Total time: 1 s, completed 2015/07/31 12:40:28 sampleIntTask := { ServerUtil.startServer try { val sum = 1 + 2 println("sum: " + sum) sum } finally { ServerUtil.stopServer } }
  • 28. タスクのスコープ lazy val say = taskKey[Unit](“say task”)
 
 lazy val message = settingKey[String]("message") lazy val modifier = taskKey[String]("modifier task") lazy val display = taskKey[Unit]("display task") message in say := "hello" modifier in say := { "{{{" + (message in say).value + "}}}" } display in say := { println((modifier in say).value) } $ sbt say::display [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) {{{hello}}} [success] Total time: 0 s, completed 2015/08/01 7:45:33
  • 29. sbt plugin sbtPlugin := true
 
 name := """sbt-simple-plugin""" version := "1.0" scalaVersion := “2.10.5" libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test" sbtPlugin := trueとするだけ、他は通常のsbtプロジェクトと同じ
  • 31. chatwork/sbt-docker $ sbt docker::build [info] Loading project definition from /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/project [info] Set current project to simple (in build file:/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/) [info] generated docker file from template file. dockerTemplate = /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/ docker/Dockerfile.ftl, templateContext = Map(name -> simple, version -> 0.1-SNAPSHOT), dockerfile = /Users/cw-junichi/sbt- docker/src/sbt-test/sbt-docker/simple/docker/Dockerfile [info] Set(/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/target/docker/Dockerfile, /Users/cw-junichi/sbt-docker/ src/sbt-test/sbt-docker/simple/target/docker/bin/echo.sh) [info] userName = , emailAddress = [info] Step 0 : FROM busybox [info] ---> 8c2e06607696 [info] Step 1 : ADD bin/echo.sh / [info] ---> f7bffdfc573c [info] Removing intermediate container f6a8e236bf34 [info] Step 2 : CMD sh /echo.sh simple-0.1-SNAPSHOT [info] ---> Running in d761354df21a [info] ---> 7ae24d96c42c [info] Removing intermediate container d761354df21a [info] Successfully built 7ae24d96c42c [info] docker build, imageId = 7ae24d96c42c [success] Total time: 3 s, completed 2015/07/31 13:58:46 docker build docker buildの前にアプリケーションをbuildできる。
  • 32. ディレクトリ構成 "## build.sbt "## project $   "## build.properties $   "## plugins.sbt $   "## scripted.sbt "## release.sbt "## scripted.sbt "## src $   "## main $   $   "## resources $   $   $   &## logback.xml $   $   &## scala $   $   &## com $   $   &## chatwork $   $   &## sbt $   $   &## docker $   $   "## BuildOptions.scala $   $   "## DockerfileBuilder.scala $   $   "## SbtDocker.scala $   $   "## SbtDockerKeys.scala $   $   &## SbtDockerPlugin.scala $   &## sbt-test $   &## sbt-docker $   &## simple $   "## build.sbt $   "## docker $   $   "## Dockerfile.ftl $   $   &## bin $   $   &## echo.sh $   &## project $      &## plugins.sbt &## version.sbt
  • 33. build.sbt import scalariform.formatter.preferences._ scalaVersion := "2.10.5" sonatypeProfileName := "com.chatwork" organization := "com.chatwork" publishMavenStyle := true publishArtifact in Test := false pomIncludeRepository := { _ => false } pomExtra := { <url>https://github.com/chatwork/sbt-docker</url> <licenses> <license> <name>The MIT License</name> <url>http://opensource.org/licenses/MIT</url> </license> </licenses> <scm> <url>git@github.com:chatwork/sbt-docker.git</url> <connection>scm:git:github.com/chatwork/sbt-docker</ connection> <developerConnection>scm:git:git@github.com:chatwork/ sbt-docker.git</developerConnection> </scm> <developers> <developer> <id>cw-junichikato</id> <name>Junichi Kato</name> </developer> </developers> } name := "sbt-docker" sbtPlugin := true
 
 resolvers ++= Seq( "Sonatype OSS Snapshot Repository" at "https:// oss.sonatype.org/content/repositories/snapshots/", "Sonatype OSS Release Repository" at "https:// oss.sonatype.org/content/repositories/releases/", "Typesafe Releases" at "http://repo.typesafe.com/ typesafe/releases/" )
 
 libraryDependencies ++= Seq( "com.spotify" % "docker-client" % "2.7.7", "ch.qos.logback" % "logback-classic" % "1.1.3", "org.slf4j" % "slf4j-api" % "1.7.12", "org.freemarker" % "freemarker" % "2.3.14" ) scalariformSettings ScalariformKeys.preferences := ScalariformKeys.preferences.value .setPreference(AlignParameters, true) .setPreference(AlignSingleLineCaseStatements, true) .setPreference(DoubleIndentClassDeclaration, true) .setPreference(PreserveDanglingCloseParenthesis, true) .setPreference(MultilineScaladocCommentsStartOnFirstLin e, false) credentials <<= Def.task { val ivyCredentials = (baseDirectory in LocalRootProject).value / ".credentials" val result = Credentials(ivyCredentials) :: Nil result }
  • 34. project/plugins.sbt logLevel := Level.Warn addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.0") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.0")
  • 35. プラグイン本体 package com.chatwork.sbt.docker import sbt.Keys._ import sbt._ import sbt.plugins.IvyPlugin object SbtDockerPlugin extends AutoPlugin { override def trigger = allRequirements override def requires: Plugins = IvyPlugin object autoImport extends SbtDockerKeys import SbtDocker._ import SbtDockerKeys._ override def projectSettings: Seq[Def.Setting[_]] = Seq( name in docker := (name in thisProjectRef).value, sourceDirectory in docker := baseDirectory.value / "docker", buildDirectory in docker := baseDirectory.value / "target" / "docker", sourceFiles in docker := Seq(), login in docker := false, emailAddress in docker := "", userName in docker := "", password in docker := "", buildOptions in docker := Set.empty[BuildOptions.Value], build in docker <<= dockerBuildTask dependsOn (copySourceFiles in docker), copySourceFiles in docker <<= copySourceFilesTask, dockerfileTemplate in docker := (sourceDirectory in docker).value / "Dockerfile.ftl", dockerfile in docker := (sourceDirectory in docker).value / "Dockerfile", templateContext in docker := Map( "name" -> (name in thisProjectRef).value, "version" -> (version in thisProjectRef).value ), generateDockerfile in docker <<= generateDockerfileTask, push in docker <<= dockerPushTask, pull in docker <<= dockerPullTask, list in docker <<= dockerListImagesTask, start in docker <<= dockerStartTask dependsOn (copySourceFiles in docker), startAndWait in docker <<= dockerStartAndWaitTask dependsOn (copySourceFiles in docker) ) }
  • 36. Key関係 val build = taskKey[Option[String]]("build") val buildOptions = settingKey[Set[BuildOptions.Value]] ("build-options") val buildDirectory = settingKey[File]("build- directory") // --- val dockerfileTemplate = settingKey[File]("dockerfile- template") val dockerfile = settingKey[File]("dockerfile") val templateContext = settingKey[Map[String, String]] ("template-context") val generateDockerfile = taskKey[File]("generate- dockerfile") // --- val push = taskKey[Unit]("push") val pull = taskKey[Unit]("pull") val list = taskKey[Unit]("list") val start = taskKey[Option[Future[String]]]("start") val startAndWait = taskKey[Unit]("start-and-wait") } package com.chatwork.sbt.docker import sbt._ import scala.concurrent.Future object SbtDockerKeys extends SbtDockerKeys trait SbtDockerKeys { val docker = taskKey[Unit]("docker") val login = settingKey[Boolean]("login") val emailAddress = settingKey[String]("email- address") val userName = settingKey[String]("user-name") val password = settingKey[String]("password") // --- val sourceFiles = taskKey[Seq[(File, String)]] ("source-files") val copySourceFiles = taskKey[Set[File]] ("copy-source-files") // ---
  • 37. タスクの定義 trait SbtDocker { def dockerBuildTask: Def.Initialize[Task[Option[String]]] = Def.task { val logger = streams.value.log val sut = dockerClient.value val workDir = (buildDirectory in docker).value.toPath val repositoryName = (name in docker).value val bo = (buildOptions in docker).value.map(toBuildParameter) Try { val result = sut.build(workDir, repositoryName, progressHandler(logger) { pm => Some(pm.stream()) }, bo.toArray: _*) logger.info(s"docker build, imageId = $result") Some(result) }.recover { case ex: DockerException => logger.error(ex.toString) None }.get } }
  • 38. AutoPlugin • これまでは • project/plugins.sbtにプラグインを追加 • build.sbtにプラグイン固有のセッティングを追加 • AutoPluginでは、タスク、セッティングなどのビルド定義を自動的に追加できる • 明示的に利用するプラグインを指定できる。 • (project in file(“.”)).enablePlugins(a, b).disablePlugins(c) • requires • 依存しているプラグイン(AutoPlugin)を指定できる • trigger • プラグインが動作する条件。allRequirementsは、すべての依存プラグインが 使えるようになってから動作できるようにする。 • autoImport • importの自動化。autoImportメンバー内に存在するものはimport宣言なしで 利用できるようになる
  • 40.