summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2017-03-02 23:35:46 -0800
committerJakob Odersky <jakob@odersky.com>2017-03-02 23:35:46 -0800
commitf9cc5e3f8478eb9f19cca093b8019e579f9c87e6 (patch)
tree5834850e91478ceb3dd25d9d390f9f4555e0523e
parentc4ff7eaf274eb4e2cfacdabeb65bfc43a89fdd3a (diff)
downloadcrashbox-ci-f9cc5e3f8478eb9f19cca093b8019e579f9c87e6.tar.gz
crashbox-ci-f9cc5e3f8478eb9f19cca093b8019e579f9c87e6.tar.bz2
crashbox-ci-f9cc5e3f8478eb9f19cca093b8019e579f9c87e6.zip
Implement basic worker functionality
-rw-r--r--build.sbt4
-rw-r--r--crashbox-worker/build.sbt7
-rw-r--r--crashbox-worker/src/main/scala/io/crashbox/ci/build/Builders.scala15
-rw-r--r--crashbox-worker/src/main/scala/io/crashbox/ci/build/ShellBuilders.scala33
-rw-r--r--crashbox-worker/src/main/scala/io/crashbox/ci/source/Fetchers.scala12
-rw-r--r--crashbox-worker/src/main/scala/io/crashbox/ci/source/GitFetchers.scala19
-rw-r--r--crashbox-worker/src/test/scala/io/crashbox/ci/TestUtil.scala13
-rw-r--r--crashbox-worker/src/test/scala/io/crashbox/ci/build/ShellBuildersSpec.scala55
-rw-r--r--crashbox-worker/src/test/scala/io/crashbox/ci/source/GitFetchersSpec.scala36
9 files changed, 192 insertions, 2 deletions
diff --git a/build.sbt b/build.sbt
index 23ac49e..aa14fd3 100644
--- a/build.sbt
+++ b/build.sbt
@@ -5,13 +5,13 @@ scalaVersion in ThisBuild := (crossScalaVersions in ThisBuild).value.head
scalacOptions in ThisBuild ++= Seq(
"-deprecation",
"-feature",
- "-Xfatal-warnings",
+ //"-Xfatal-warnings",
"-Xlint"
)
fork in ThisBuild := true
cancelable in Global := true
-lazy val root = (project in file(".")).aggregate(http)
+lazy val root = (project in file(".")).aggregate(http, worker)
lazy val http = (project in file("crashbox-http"))
diff --git a/crashbox-worker/build.sbt b/crashbox-worker/build.sbt
new file mode 100644
index 0000000..2b9cf08
--- /dev/null
+++ b/crashbox-worker/build.sbt
@@ -0,0 +1,7 @@
+import crashbox.Dependencies
+
+libraryDependencies ++= Seq(
+ Dependencies.jgitArchive,
+ Dependencies.jgitServer,
+ Dependencies.scalatest % Test
+)
diff --git a/crashbox-worker/src/main/scala/io/crashbox/ci/build/Builders.scala b/crashbox-worker/src/main/scala/io/crashbox/ci/build/Builders.scala
new file mode 100644
index 0000000..14b43fe
--- /dev/null
+++ b/crashbox-worker/src/main/scala/io/crashbox/ci/build/Builders.scala
@@ -0,0 +1,15 @@
+package io.crashbox.ci
+package build
+
+import java.io.{ File, OutputStream }
+import scala.concurrent.Future
+
+trait Builders {
+
+ def build(
+ workdir: File,
+ stdout: OutputStream,
+ stderr: OutputStream
+ ): Future[Int]
+
+}
diff --git a/crashbox-worker/src/main/scala/io/crashbox/ci/build/ShellBuilders.scala b/crashbox-worker/src/main/scala/io/crashbox/ci/build/ShellBuilders.scala
new file mode 100644
index 0000000..71bd683
--- /dev/null
+++ b/crashbox-worker/src/main/scala/io/crashbox/ci/build/ShellBuilders.scala
@@ -0,0 +1,33 @@
+package io.crashbox.ci
+package build
+
+import java.io.OutputStream
+import scala.concurrent.Future
+import scala.sys.process.{ Process, _ }
+import java.io.{ File, InputStream }
+import scala.concurrent.Future
+
+trait ShellBuilders extends Builders {
+
+ def pipe(is: InputStream, os: OutputStream) = {
+ var n = 0
+ val buffer = new Array[Byte](1024);
+ while ({n = is.read(buffer); n > -1}) {
+ os.write(buffer, 0, n);
+ }
+ os.close()
+ }
+
+ @deprecated("use git-specific execution context", "todo")
+ implicit private val ec = scala.concurrent.ExecutionContext.global
+
+ override def build(workdir: File, stdout: OutputStream, stderr: OutputStream): Future[Int] = {
+ def ignore(in: OutputStream): Unit = ()
+ val io = new ProcessIO(ignore, pipe(_, stdout), pipe(_, stderr))
+
+ Future{
+ Process("./crashbox", Some(workdir)).run(io).exitValue()
+ }
+ }
+
+}
diff --git a/crashbox-worker/src/main/scala/io/crashbox/ci/source/Fetchers.scala b/crashbox-worker/src/main/scala/io/crashbox/ci/source/Fetchers.scala
new file mode 100644
index 0000000..0fd4f38
--- /dev/null
+++ b/crashbox-worker/src/main/scala/io/crashbox/ci/source/Fetchers.scala
@@ -0,0 +1,12 @@
+package io.crashbox.ci
+package source
+
+import java.io.File
+import java.net.URL
+import scala.concurrent.Future
+
+trait Fetchers {
+
+ def fetch(from: URL, to: File): Future[File]
+
+}
diff --git a/crashbox-worker/src/main/scala/io/crashbox/ci/source/GitFetchers.scala b/crashbox-worker/src/main/scala/io/crashbox/ci/source/GitFetchers.scala
new file mode 100644
index 0000000..9b603e2
--- /dev/null
+++ b/crashbox-worker/src/main/scala/io/crashbox/ci/source/GitFetchers.scala
@@ -0,0 +1,19 @@
+package io.crashbox.ci
+package source
+
+import java.io.File
+import java.net.URL
+import org.eclipse.jgit.api.Git
+import scala.concurrent.Future
+
+trait GitFetchers extends Fetchers {
+
+ @deprecated("use git-specific execution context", "todo")
+ implicit private val ec = scala.concurrent.ExecutionContext.global
+
+ def fetch(from: URL, to: File): Future[File] = Future {
+ Git.cloneRepository.setURI(from.toURI.toString).setDirectory(to).call()
+ to
+ }
+
+}
diff --git a/crashbox-worker/src/test/scala/io/crashbox/ci/TestUtil.scala b/crashbox-worker/src/test/scala/io/crashbox/ci/TestUtil.scala
new file mode 100644
index 0000000..eb177f8
--- /dev/null
+++ b/crashbox-worker/src/test/scala/io/crashbox/ci/TestUtil.scala
@@ -0,0 +1,13 @@
+package io.crashbox.ci
+
+import java.io.{ File, OutputStream }
+import java.nio.file.Files
+
+object TestUtil {
+
+ def withTempDir[A](f: File => A): A = {
+ val dir = Files.createTempDirectory("crashbox-test").toFile
+ try f(dir) finally dir.delete()
+ }
+
+}
diff --git a/crashbox-worker/src/test/scala/io/crashbox/ci/build/ShellBuildersSpec.scala b/crashbox-worker/src/test/scala/io/crashbox/ci/build/ShellBuildersSpec.scala
new file mode 100644
index 0000000..9419804
--- /dev/null
+++ b/crashbox-worker/src/test/scala/io/crashbox/ci/build/ShellBuildersSpec.scala
@@ -0,0 +1,55 @@
+package io.crashbox.ci
+package build
+
+import java.io.{ BufferedOutputStream, ByteArrayOutputStream, File }
+import java.nio.file.Files
+import java.net.URL
+import org.eclipse.jgit.util.Paths
+import scala.concurrent.duration._
+import scala.concurrent.Await
+import org.scalatest._
+
+class ShellBuildersSpec extends FlatSpec with Matchers with ShellBuilders {
+
+ val Timeout = 10.seconds
+
+ def runScript(script: String): (Int, String, String) = {
+ val stdout = new ByteArrayOutputStream(4096)
+ val stderr = new ByteArrayOutputStream(4096)
+
+ val result = TestUtil.withTempDir{ dir =>
+ val exec = new File(dir, "crashbox")
+ exec.createNewFile()
+ Files.write(exec.toPath, script.getBytes)
+ exec.setExecutable(true)
+
+ Await.result(build(dir, stdout, stderr), Timeout)
+ }
+ stdout.close()
+ stderr.close()
+
+ (result, new String(stdout.toByteArray(), "utf-8"), new String(stderr.toByteArray(), "utf-8"))
+ }
+
+ "ShellBuilders" should "run a shell script" in {
+ val script = """|#!/bin/sh
+ |echo "hello world"
+ |echo "foo" >&2
+ |""".stripMargin
+ val (res, stdout, stderr) = runScript(script: String)
+
+ assert(res == 0)
+ assert(stdout == "hello world\n")
+ assert(stderr == "foo\n")
+ }
+
+ it should "report a failed script" in {
+ val script = """|#!/bin/sh
+ |exit 1
+ |""".stripMargin
+ val (res, _, _) = runScript(script: String)
+
+ assert(res == 1)
+ }
+
+}
diff --git a/crashbox-worker/src/test/scala/io/crashbox/ci/source/GitFetchersSpec.scala b/crashbox-worker/src/test/scala/io/crashbox/ci/source/GitFetchersSpec.scala
new file mode 100644
index 0000000..a0886a5
--- /dev/null
+++ b/crashbox-worker/src/test/scala/io/crashbox/ci/source/GitFetchersSpec.scala
@@ -0,0 +1,36 @@
+package io.crashbox.ci
+package source
+
+import java.io.File
+import java.nio.file.Files
+import java.net.URL
+import org.eclipse.jgit.api.Git
+import scala.concurrent.duration._
+import scala.concurrent.Await
+import org.scalatest._
+
+class GitFetchersSpec extends FlatSpec with Matchers with GitFetchers {
+
+ val Timeout = 10.seconds
+
+ def makeRepo(dir: File): Unit = {
+ Git.init().setDirectory(dir).call()
+ val file1 = new File(dir, "file1")
+ file1.createNewFile()
+ val file2 = new File(dir, "file2")
+ file2.createNewFile()
+ Git.open(dir).add().addFilepattern(".").call()
+ Git.open(dir).commit().setMessage("initial commit").call()
+ }
+
+ "GitFetchers" should "be able to clone a local repository" in {
+ TestUtil.withTempDir{ remote =>
+ makeRepo(remote)
+ TestUtil.withTempDir { local =>
+ val cloned = Await.result(fetch(remote.toURI().toURL(), local), Timeout)
+ assert(cloned.listFiles().length == 3)
+ }
+ }
+ }
+
+}