Refactoring to allow additional commands
Factor out common operations than can be reused by additional commands.
Makes it clearer how the various modules are structured.
Change-Id: I8e0d1f012bfa810b62fcd5a20e0fec948157cf88
diff --git a/README.md b/README.md
index f360e7b..1097fd7 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@
REST Example:
```
- $ curl http://gerrit.mycompany.com/project/myproyject/analytics~contributors
+ $ curl http://gerrit.mycompany.com/projects/myproject/analytics~contributors
{"name":"John Doe","email":"john.doe@mycompany.com","num_commits":1,"commits":[{"sha1":"6a1f73738071e299f600017d99f7252d41b96b4b","date":"Apr 28, 2011 5:13:14 AM","merge":false}]}
{"name":"Matt Smith","email":"matt.smith@mycompany.com","num_commits":1,"commits":[{"sha1":"54527e7e3086758a23e3b069f183db6415aca304","date":"Sep 8, 2015 3:11:23 AM","merge":true}]}
@@ -70,7 +70,7 @@
SSH Example:
```
- $ ssh -p 29418 admin@gerrit.mycompany.com analytics contributors
+ $ ssh -p 29418 admin@gerrit.mycompany.com analytics contributors myproject
{"name":"John Doe","email":"john.doe@mycompany.com","num_commits":1,"commits":[{"sha1":"6a1f73738071e299f600017d99f7252d41b96b4b","date":"Apr 28, 2011 5:13:14 AM","merge":false}]}
{"name":"Matt Smith","email":"matt.smith@mycompany.com","num_commits":1,"commits":[{"sha1":"54527e7e3086758a23e3b069f183db6415aca304","date":"Sep 8, 2015 3:11:23 AM","merge":true}]}
diff --git a/build.sbt b/build.sbt
index dc579ab..211b55b 100644
--- a/build.sbt
+++ b/build.sbt
@@ -13,7 +13,6 @@
libraryDependencies ++= Seq(
"io.fabric8" % "gitective-core" % "0.9.19"
exclude("org.eclipse.jgit", "org.eclipse.jgit"),
-
"com.google.inject" % "guice" % "3.0" % Provided,
"com.google.gerrit" % "gerrit-plugin-api" % gerritApiVersion % Provided withSources(),
"com.google.code.gson" % "gson" % "2.7" % Provided,
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/CommitInfo.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/CommitInfo.scala
deleted file mode 100644
index d0ac124..0000000
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/CommitInfo.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (C) 2016 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
-
-case class CommitInfo(val sha1: String, val date: Long, val merge: Boolean)
\ No newline at end of file
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala
new file mode 100644
index 0000000..df3bbe9
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala
@@ -0,0 +1,71 @@
+// Copyright (C) 2016 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
+
+import com.google.gerrit.extensions.restapi.{Response, RestReadView}
+import com.google.gerrit.server.git.GitRepositoryManager
+import com.google.gerrit.server.project.{ProjectResource, ProjectsCollection}
+import com.google.gerrit.sshd.{CommandMetaData, SshCommand}
+import com.google.inject.Inject
+import com.googlesource.gerrit.plugins.analytics.common._
+import org.eclipse.jgit.lib.ObjectId
+import org.gitective.core.stat.{AuthorHistogramFilter, UserCommitActivity}
+
+
+@CommandMetaData(name = "contributors", description = "Extracts the list of contributors to a project")
+class ContributorsCommand @Inject()(val executor: ContributorsService,
+ val projects: ProjectsCollection,
+ val gsonFmt: GsonFormatter)
+ extends SshCommand with ProjectResourceParser {
+
+ override protected def run = gsonFmt.format(executor.get(projectRes), stdout)
+}
+
+class ContributorsResource @Inject()(val executor: ContributorsService,
+ val gson: GsonFormatter)
+ extends RestReadView[ProjectResource] {
+
+ override def apply(projectRes: ProjectResource) = Response.ok(
+ new GsonStreamedResult[UserActivitySummary](gson, executor.get(projectRes)))
+}
+
+class ContributorsService @Inject()(repoManager: GitRepositoryManager,
+ histogram: UserActivityHistogram,
+ gsonFmt: GsonFormatter) {
+
+ def get(projectRes: ProjectResource): TraversableOnce[UserActivitySummary] =
+ ManagedResource.use(repoManager.openRepository(projectRes.getNameKey)) {
+ histogram.get(_, new AuthorHistogramFilter)
+ .par
+ .map(UserActivitySummary.apply).toStream
+ }
+}
+
+case class CommitInfo(val sha1: String, val date: Long, val merge: Boolean)
+
+case class UserActivitySummary(name: String, email: String, numCommits: Int,
+ commits: Array[CommitInfo], lastCommitDate: Long)
+
+object UserActivitySummary {
+ def apply(uca: UserCommitActivity): UserActivitySummary =
+ UserActivitySummary(uca.getName, uca.getEmail, uca.getCount,
+ getCommits(uca.getIds, uca.getTimes, uca.getMerges), uca.getLatest)
+
+ private def getCommits(ids: Array[ObjectId], times: Array[Long], merges: Array[Boolean]):
+ Array[CommitInfo] = {
+ (ids, times, merges).zipped.map((id, time, merge) => CommitInfo(id.name, time, merge))
+ }
+}
+
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/ContributorsCommand.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/ContributorsCommand.scala
deleted file mode 100644
index a53c632..0000000
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/ContributorsCommand.scala
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (C) 2016 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
-
-import java.io.IOException
-
-import com.google.gerrit.extensions.restapi.UnprocessableEntityException
-import com.google.gerrit.server.project.{ProjectResource, ProjectsCollection}
-import com.google.gerrit.sshd.{CommandMetaData, SshCommand}
-import com.google.inject.Inject
-import org.kohsuke.args4j.Argument
-
-@CommandMetaData(name = "contributors", description = "Extracts the list of contributors to a project")
-class ContributorsCommand @Inject() (
- val projects: ProjectsCollection,
- val contributors: ContributorsResource,
- val gsonFmt: GsonFormatter) extends SshCommand {
-
- @Argument(usage = "project name", metaVar = "PROJECT", required = true)
- def setProject(project: String): Unit = {
- try {
- this.projectRes = projects.parse(project)
- } catch {
- case e: UnprocessableEntityException =>
- throw new IllegalArgumentException(e.getLocalizedMessage, e)
- case e: IOException =>
- throw new IllegalArgumentException("I/O Error while trying to access project " + project, e)
- }
- }
-
- private var projectRes: ProjectResource = null
- override protected def run(): Unit = {
- gsonFmt.format(contributors.get(projectRes), stdout)
- }
-}
\ No newline at end of file
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/ContributorsResource.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/ContributorsResource.scala
deleted file mode 100644
index 3d43a18..0000000
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/ContributorsResource.scala
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (C) 2016 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
-
-import java.io.{OutputStream, PrintWriter}
-
-import com.google.gerrit.extensions.restapi.{BinaryResult, Response, RestReadView}
-import com.google.gerrit.server.git.GitRepositoryManager
-import com.google.gerrit.server.project.ProjectResource
-import com.google.inject.Inject
-import com.googlesource.gerrit.plugins.analytics.ManagedResource.use
-
-class ContributorsResource @Inject()(val repoManager: GitRepositoryManager,
- val userSummary: UserSummaryExport,
- val gsonFmt: GsonFormatter) extends RestReadView[ProjectResource] {
-
- private[analytics] class JsonStreamedResult[T](val committers: TraversableOnce[T]) extends BinaryResult {
- override def writeTo(os: OutputStream) {
- use(new PrintWriter(os)) { gsonFmt.format(committers, _) }
- }
- }
-
- override def apply(projectRes: ProjectResource): Response[BinaryResult] =
- Response.ok(new JsonStreamedResult[UserActivitySummary](get(projectRes)))
-
- def get(projectRes: ProjectResource): TraversableOnce[UserActivitySummary] =
- use(repoManager.openRepository(projectRes.getNameKey)) { userSummary.getCommitters }
-}
\ No newline at end of file
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/Module.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Module.scala
index 1c804ad..df65ae4 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/Module.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Module.scala
@@ -21,9 +21,7 @@
class Module extends AbstractModule {
override protected def configure() {
-
install(new RestApiModule() {
-
override protected def configure() = {
get(PROJECT_KIND, "contributors").to(classOf[ContributorsResource])
}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/SshModule.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/SshModule.scala
index 5995de5..6a2b076 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/SshModule.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/SshModule.scala
@@ -17,6 +17,7 @@
import com.google.gerrit.sshd.PluginCommandModule
class SshModule extends PluginCommandModule {
+
override protected def configureCommands {
command(classOf[ContributorsCommand])
}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/UserActivitySummary.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/UserActivitySummary.scala
deleted file mode 100644
index bde6731..0000000
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/UserActivitySummary.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) 2016 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
-
-import org.eclipse.jgit.lib.ObjectId
-import org.gitective.core.stat.UserCommitActivity
-
-object UserActivitySummary {
- def fromUserActivity(uca: UserCommitActivity) =
- UserActivitySummary(uca.getName, uca.getEmail, uca.getCount,
- getCommits(uca.getIds, uca.getTimes, uca.getMerges), uca.getLatest)
-
- private def getCommits(ids: Array[ObjectId], times: Array[Long], merges: Array[Boolean]):
- Array[CommitInfo] = {
- (ids, times, merges).zipped.map((id, time, merge) => CommitInfo(id.name, time, merge))
- }
-}
-
-case class UserActivitySummary(name: String, email: String, numCommits: Int,
- commits: Array[CommitInfo], lastCommitDate: Long)
\ No newline at end of file
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/GsonFormatter.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/GsonFormatter.scala
similarity index 93%
rename from src/main/scala/com/googlesource/gerrit/plugins/analytics/GsonFormatter.scala
rename to src/main/scala/com/googlesource/gerrit/plugins/analytics/common/GsonFormatter.scala
index d400ad8..f9ab7a9 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/GsonFormatter.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/GsonFormatter.scala
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.googlesource.gerrit.plugins.analytics
+package com.googlesource.gerrit.plugins.analytics.common
import java.io.PrintWriter
@@ -28,7 +28,7 @@
val gson: Gson = gsonBuilder.create
for (value <- values) {
gson.toJson(value, out)
- out.println()
+ out.println
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/JsonStreamedResultBuilder.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/JsonStreamedResultBuilder.scala
new file mode 100644
index 0000000..991be59
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/JsonStreamedResultBuilder.scala
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 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.common
+
+import java.io.{OutputStream, PrintWriter}
+
+import com.google.gerrit.extensions.restapi.BinaryResult
+
+class GsonStreamedResult[T](val jsonFmt: GsonFormatter,
+ val committers: TraversableOnce[T]) extends BinaryResult {
+ override def writeTo(os: OutputStream) =
+ ManagedResource.use(new PrintWriter(os))(jsonFmt.format(committers, _))
+}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/ManagedResources.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ManagedResources.scala
similarity index 92%
rename from src/main/scala/com/googlesource/gerrit/plugins/analytics/ManagedResources.scala
rename to src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ManagedResources.scala
index 741f91c..83da961 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/ManagedResources.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ManagedResources.scala
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.googlesource.gerrit.plugins.analytics
+package com.googlesource.gerrit.plugins.analytics.common
object ManagedResource {
def use[A <: { def close(): Unit }, B](resource: A)(code: A ⇒ B): B =
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ProjectResourceParser.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ProjectResourceParser.scala
new file mode 100644
index 0000000..a375ff4
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ProjectResourceParser.scala
@@ -0,0 +1,23 @@
+package com.googlesource.gerrit.plugins.analytics.common
+
+import java.io.IOException
+
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException
+import com.google.gerrit.server.project.{ProjectResource, ProjectsCollection}
+import org.kohsuke.args4j.Argument
+
+trait ProjectResourceParser {
+ def projects: ProjectsCollection
+
+ var projectRes: ProjectResource = null
+
+ @Argument(usage = "project name", metaVar = "PROJECT", required = true)
+ def setProject(project: String): Unit = {
+ try {
+ this.projectRes = projects.parse(project)
+ } catch {
+ case e: Exception =>
+ throw new IllegalArgumentException("Error while trying to access project " + project, e)
+ }
+ }
+}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/UserSummaryExport.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/UserActivityHistogram.scala
similarity index 69%
rename from src/main/scala/com/googlesource/gerrit/plugins/analytics/UserSummaryExport.scala
rename to src/main/scala/com/googlesource/gerrit/plugins/analytics/common/UserActivityHistogram.scala
index d4a5142..cebc84e 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/UserSummaryExport.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/UserActivityHistogram.scala
@@ -12,21 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.googlesource.gerrit.plugins.analytics
+package com.googlesource.gerrit.plugins.analytics.common
import com.google.inject.Singleton
import org.eclipse.jgit.lib.Repository
import org.gitective.core.CommitFinder
-import org.gitective.core.stat.AuthorHistogramFilter
+import org.gitective.core.stat.CommitHistogramFilter
@Singleton
-class UserSummaryExport {
- def getCommitters(repo: Repository): TraversableOnce[UserActivitySummary] = {
+class UserActivityHistogram {
+ def get(repo: Repository, filter: CommitHistogramFilter) = {
val finder = new CommitFinder(repo)
- val filter = new AuthorHistogramFilter
finder.setFilter(filter).find
val histogram = filter.getHistogram
- val authorActivity = histogram.getUserActivity
- authorActivity.par.map(UserActivitySummary.fromUserActivity).toStream
+ histogram.getUserActivity
}
}
\ No newline at end of file