Automatically setup an analytics dashboard

This plugin allows to add a step in the github gerrit workflow configuration
to automatically setup an analytics dashboard.

At the moment it is creating a customised docker-compose file that can
be used to spin up the resuorces needed for the dashboard.

Change-Id: If77502e0ff3b28355b87eed2e7fb0b65dbaf1eda
diff --git a/.gitignore b/.gitignore
index 9c07d4a..b4790c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,9 @@
 *.class
 *.log
+/bin/
+.project
+.classpath
+.settings/
+.idea
+target
+.DS_Store
diff --git a/build.sbt b/build.sbt
new file mode 100644
index 0000000..7b9e7ea
--- /dev/null
+++ b/build.sbt
@@ -0,0 +1,31 @@
+enablePlugins(GitVersioning)
+
+val gerritApiVersion = "2.15.1"
+val pluginName = "analytics-wizard"
+
+git.useGitDescribe := true
+
+lazy val root = (project in file("."))
+  .settings(
+    name := pluginName,
+
+    scalaVersion := "2.12.5",
+
+    libraryDependencies ++= Seq(
+      "com.google.inject" % "guice" % "3.0" % Provided,
+      "com.google.gerrit" % "gerrit-plugin-api" % gerritApiVersion % Provided withSources(),
+      "com.google.code.gson" % "gson" % "2.7" % Provided,
+
+      "org.scalatest" %% "scalatest" % "3.0.4" % Test,
+      "net.codingwell" %% "scala-guice" % "4.1.0" % Test),
+
+    assemblyJarName in assembly := s"$pluginName.jar",
+
+    packageOptions in(Compile, packageBin) += Package.ManifestAttributes(
+      ("Gerrit-ApiType", "plugin"),
+      ("Gerrit-PluginName", pluginName),
+      ("Gerrit-Module", "com.googlesource.gerrit.plugins.analytics.wizard.Module"),
+      ("Implementation-Title", "Analytics plugin wizard")
+    )
+  )
+
diff --git a/project/build.properties b/project/build.properties
new file mode 100644
index 0000000..9abea12
--- /dev/null
+++ b/project/build.properties
@@ -0,0 +1 @@
+sbt.version=1.0.3
diff --git a/project/plugins.sbt b/project/plugins.sbt
new file mode 100644
index 0000000..45f9d0f
--- /dev/null
+++ b/project/plugins.sbt
@@ -0,0 +1,4 @@
+logLevel := Level.Warn
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
+addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.9.3")
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4")
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetup.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetup.scala
new file mode 100644
index 0000000..ada25a1
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetup.scala
@@ -0,0 +1,64 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.plugins.analytics.wizard
+
+import java.io.PrintWriter
+
+trait ConfigWriter {
+  def write(filename: String, out: String)
+}
+
+class ConfigWriterImpl extends ConfigWriter {
+  def write(filename: String, out: String) = {
+    val p = new PrintWriter(filename)
+    p.write(out)
+    p.close()
+  }
+}
+
+case class AnalyticDashboardSetup(name: String, config: Option[String] = None)(
+    implicit val writer: ConfigWriter) {
+
+  private val dockerComposeTemplate = { (name: String) =>
+    s"""
+       |version: '3'
+       |services:
+       |  kibana:
+       |    build: kibana
+       |    container_name: "kibana-for-${name}-project"
+       |    environment:
+       |      SERVER_BASEPATH: "/kibana"
+       |    depends_on:
+       |      - elasticsearch
+       |  elasticsearch:
+       |    build: elasticsearch
+       |    container_name: "es-for-${name}-project"
+       |    environment:
+       |      - ES_JAVA_OPTS=-Xmx4g -Xms4g
+       |      - http.host=0.0.0.0
+       |    volumes:
+       |      - es-indexes:/usr/share/elasticsearch/data
+     """.stripMargin
+  }
+
+  val configFileName = s"/tmp/docker-compose.${name}.yaml"
+  def createDashboardSetupFile(): Unit = {
+    writer.write(configFileName, dockerComposeTemplate(name))
+  }
+
+}
+
+object AnalyticDashboardSetup {
+  implicit val writer = new ConfigWriterImpl()
+}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticsWizardActions.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticsWizardActions.scala
new file mode 100644
index 0000000..f0f6632
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticsWizardActions.scala
@@ -0,0 +1,55 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.plugins.analytics.wizard
+
+import com.google.gerrit.extensions.restapi.{
+  Response,
+  RestModifyView,
+  RestReadView
+}
+import com.google.gerrit.server.project.ProjectResource
+import com.google.inject.Inject
+
+import scala.io.Source
+
+import AnalyticDashboardSetup.writer
+
+class GetAnalyticsStack @Inject()() extends RestReadView[ProjectResource] {
+  override def apply(
+      resource: ProjectResource): Response[AnalyticDashboardSetup] = {
+
+    val projectName = resource.getControl.getProject.getName
+    Response.ok(
+      AnalyticDashboardSetup(
+        projectName,
+        Some(
+          Source
+            .fromFile(s"/tmp/docker-compose.${projectName}.yaml")
+            .getLines
+            .mkString)))
+  }
+}
+
+class Input(var dashboardName: String)
+
+class PutAnalyticsStack @Inject()()
+    extends RestModifyView[ProjectResource, Input] {
+  override def apply(resource: ProjectResource,
+                     input: Input): Response[String] = {
+
+    val projectName = resource.getControl.getProject.getName
+    AnalyticDashboardSetup(projectName).createDashboardSetupFile()
+    Response.created(s"Dashboard configuration created for $projectName!")
+  }
+}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/Module.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/Module.scala
new file mode 100644
index 0000000..36d21dd
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/wizard/Module.scala
@@ -0,0 +1,31 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.plugins.analytics.wizard
+
+import com.google.gerrit.extensions.restapi.RestApiModule
+import com.google.gerrit.server.project.ProjectResource.PROJECT_KIND
+import com.google.inject.AbstractModule
+
+class Module extends AbstractModule {
+
+  override protected def configure() {
+    install(new RestApiModule() {
+      override protected def configure() = {
+        get(PROJECT_KIND, "stack").to(classOf[GetAnalyticsStack])
+
+        put(PROJECT_KIND, "stack").to(classOf[PutAnalyticsStack])
+      }
+    })
+  }
+}
diff --git a/src/test/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetupSpec.scala b/src/test/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetupSpec.scala
new file mode 100644
index 0000000..717d213
--- /dev/null
+++ b/src/test/scala/com/googlesource/gerrit/plugins/analytics/wizard/AnalyticDashboardSetupSpec.scala
@@ -0,0 +1,21 @@
+package com.googlesource.gerrit.plugins.analytics.wizard
+
+import org.scalatest.{FlatSpec, Matchers}
+
+class AnalyticDashboardSetupSpec extends FlatSpec with Matchers {
+  behavior of "AnalyticDashboardSetup"
+
+  it should "create a config file with correct name" in {
+    var gotFilename: Option[String] = None
+    class MockWriter extends ConfigWriter {
+      override def write(filename: String, out: String): Unit = {
+        gotFilename = Some(filename)
+      }
+    }
+    implicit val writer = new MockWriter()
+
+    val ads = AnalyticDashboardSetup("aProject")
+    ads.createDashboardSetupFile()
+    gotFilename shouldBe Some(ads.configFileName)
+  }
+}