Aggregate contributors stats by day/month/year
Adapt CommitHistogram to take care of various levels
of aggregations, including HOUR, DAY, MONTH, YEAR.
Output records include the key field holding
<useremail>[/<year>[/<month>[/<day>[/<hour>]]]]
so that consumers can understand which aggregation level has been used.
Aggregation is enabled with --aggregate --g aliases
Omitting --aggregate will default to aggregation by email which is
almost identical to previous version (except for the added field key).
Change-Id: I047a4d11e695afff56dd28a0b9c8d73e001b7782
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala
index 184f550..5b267f0 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
@@ -22,9 +22,7 @@
import com.googlesource.gerrit.plugins.analytics.common.DateConversions._
import com.googlesource.gerrit.plugins.analytics.common._
import org.eclipse.jgit.lib.ObjectId
-import org.gitective.core.stat.UserCommitActivity
import org.kohsuke.args4j.{Option => ArgOption}
-import org.slf4j.LoggerFactory
@CommandMetaData(name = "contributors", description = "Extracts the list of contributors to a project")
@@ -35,7 +33,8 @@
private var beginDate: Option[Long] = None
- @ArgOption(name = "--since", aliases = Array("--after", "-b"), usage = "(included) begin timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
+ @ArgOption(name = "--since", aliases = Array("--after", "-b"),
+ usage = "(included) begin timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
def setBeginDate(date: String) {
try {
beginDate = Some(date)
@@ -46,7 +45,8 @@
private var endDate: Option[Long] = None
- @ArgOption(name = "--until", aliases = Array("--before", "-e"), usage = "(excluded) end timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
+ @ArgOption(name = "--until", aliases = Array("--before", "-e"),
+ usage = "(excluded) end timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
def setEndDate(date: String) {
try {
endDate = Some(date)
@@ -55,8 +55,22 @@
}
}
+ private var granularity: Option[AggregationStrategy] = None
+
+ @ArgOption(name = "--aggregate", aliases = Array("-g"),
+ usage = "Type of aggregation requested. ")
+ def setGranularity(value: String) {
+ try {
+ granularity = Some(AggregationStrategy.apply(value))
+ } catch {
+ case e: Exception => throw die(s"Invalid granularity ${e.getMessage}")
+ }
+ }
+
+
override protected def run =
- gsonFmt.format(executor.get(projectRes, beginDate, endDate), stdout)
+ gsonFmt.format(executor.get(projectRes, beginDate, endDate,
+ granularity.getOrElse(AggregationStrategy.EMAIL)), stdout)
}
@@ -66,7 +80,8 @@
private var beginDate: Option[Long] = None
- @ArgOption(name = "--since", aliases = Array("--after", "-b"), metaVar = "QUERY", usage = "(included) begin timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
+ @ArgOption(name = "--since", aliases = Array("--after", "-b"), metaVar = "QUERY",
+ usage = "(included) begin timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
def setBeginDate(date: String) {
try {
beginDate = Some(date)
@@ -77,7 +92,8 @@
private var endDate: Option[Long] = None
- @ArgOption(name = "--until", aliases = Array("--before", "-e"), metaVar = "QUERY", usage = "(excluded) end timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
+ @ArgOption(name = "--until", aliases = Array("--before", "-e"), metaVar = "QUERY",
+ usage = "(excluded) end timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
def setEndDate(date: String) {
try {
endDate = Some(date)
@@ -86,18 +102,34 @@
}
}
+ private var granularity: Option[AggregationStrategy] = None
+
+ @ArgOption(name = "--granularity", aliases = Array("--aggregate", "-g"), metaVar = "QUERY",
+ usage = "(excluded) end timestamp. Must be in the format 2006-01-02[ 15:04:05[.890][ -0700]]")
+ def setGranularity(value: String) {
+ try {
+ granularity = Some(AggregationStrategy.apply(value))
+ } catch {
+ case e: Exception => throw new BadRequestException(s"Invalid granularity ${e.getMessage}")
+ }
+ }
+
override def apply(projectRes: ProjectResource) =
Response.ok(
- new GsonStreamedResult[UserActivitySummary](gson, executor.get(projectRes, beginDate, endDate)))
+ new GsonStreamedResult[UserActivitySummary](gson,
+ executor.get(projectRes, beginDate, endDate,
+ granularity.getOrElse(AggregationStrategy.EMAIL))))
}
class ContributorsService @Inject()(repoManager: GitRepositoryManager,
histogram: UserActivityHistogram,
gsonFmt: GsonFormatter) {
- def get(projectRes: ProjectResource, startDate: Option[Long], stopDate: Option[Long]): TraversableOnce[UserActivitySummary] = {
+ def get(projectRes: ProjectResource, startDate: Option[Long], stopDate: Option[Long],
+ aggregationStrategy: AggregationStrategy): TraversableOnce[UserActivitySummary] = {
ManagedResource.use(repoManager.openRepository(projectRes.getNameKey)) {
- histogram.get(_, new AuthorHistogramFilterByDates(startDate, stopDate))
+ histogram.get(_, new AggregatedHistogramFilterByDates(startDate, stopDate,
+ aggregationStrategy))
.par
.map(UserActivitySummary.apply).toStream
}
@@ -106,13 +138,29 @@
case class CommitInfo(sha1: String, date: Long, merge: Boolean)
-case class UserActivitySummary(name: String, email: String, numCommits: Int,
- commits: Array[CommitInfo], lastCommitDate: Long)
+case class UserActivitySummary(year: Integer,
+ month: Integer,
+ day: Integer,
+ hour: Integer,
+ name: String,
+ email: String,
+ numCommits: Integer,
+ 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)
+ def apply(uca: AggregatedUserCommitActivity): UserActivitySummary = {
+ val INCLUDESEMPTY = -1
+
+ implicit def stringToIntOrNull(x: String): Integer = if (x.isEmpty) null else new Integer(x)
+
+ uca.key.split("/", INCLUDESEMPTY) match {
+ case a@Array(email, year, month, day, hour) =>
+ UserActivitySummary(year, month, day, hour, uca.getName, uca.getEmail, uca.getCount,
+ getCommits(uca.getIds, uca.getTimes, uca.getMerges), uca.getLatest)
+ case _ => throw new Exception(s"invalid key format found ${uca.key}")
+ }
+ }
private def getCommits(ids: Array[ObjectId], times: Array[Long], merges: Array[Boolean]):
Array[CommitInfo] = {
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 df65ae4..935a198 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/Module.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Module.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
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 6a2b076..48a48b4 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/SshModule.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/SshModule.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregatedCommitHistogram.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregatedCommitHistogram.scala
new file mode 100644
index 0000000..5420a28
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregatedCommitHistogram.scala
@@ -0,0 +1,61 @@
+// 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.common
+
+import java.util.Date
+
+import com.googlesource.gerrit.plugins.analytics.common.AggregatedCommitHistogram.AggregationStrategyMapping
+import org.eclipse.jgit.lib.PersonIdent
+import org.eclipse.jgit.revwalk.RevCommit
+import org.gitective.core.stat.{CommitHistogram, CommitHistogramFilter, UserCommitActivity}
+
+class AggregatedUserCommitActivity(val key: String, val name: String, val email: String)
+ extends UserCommitActivity(name, email)
+
+class AggregatedCommitHistogram(val aggregationStrategyForUser: AggregationStrategyMapping)
+ extends CommitHistogram {
+
+ override def include(commit: RevCommit, user: PersonIdent): AggregatedCommitHistogram = {
+ val key = aggregationStrategyForUser(user, commit.getAuthorIdent.getWhen)
+ val activity = Option(users.get(key)) match {
+ case None =>
+ val newActivity = new AggregatedUserCommitActivity(key,
+ user.getName, user.getEmailAddress)
+ users.put(key, newActivity)
+ newActivity
+ case Some(foundActivity) => foundActivity
+ }
+ activity.include(commit, user)
+ this
+ }
+
+ def getAggregatedUserActivity: Array[AggregatedUserCommitActivity] = {
+ users.values.toArray(new Array[AggregatedUserCommitActivity](users.size))
+ }
+}
+
+object AggregatedCommitHistogram {
+ type AggregationStrategyMapping = (PersonIdent, Date) => String
+
+ def apply(aggregationStrategy: AggregationStrategyMapping) =
+ new AggregatedCommitHistogram(aggregationStrategy)
+}
+
+abstract class AbstractCommitHistogramFilter(aggregationStrategyMapping: AggregationStrategyMapping)
+ extends CommitHistogramFilter {
+ val AbstractHistogram = new AggregatedCommitHistogram(aggregationStrategyMapping)
+
+ override def getHistogram = AbstractHistogram
+}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AuthorHistogramFilterByDates.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregatedHistogramFilterByDates.scala
similarity index 64%
rename from src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AuthorHistogramFilterByDates.scala
rename to src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregatedHistogramFilterByDates.scala
index b9cf786..cf90d4a 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AuthorHistogramFilterByDates.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregatedHistogramFilterByDates.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
@@ -14,28 +14,27 @@
package com.googlesource.gerrit.plugins.analytics.common
-import java.util.Date
-
+import com.googlesource.gerrit.plugins.analytics.common.AggregatedCommitHistogram.AggregationStrategyMapping
import org.eclipse.jgit.revwalk.{RevCommit, RevWalk}
-import org.gitective.core.stat.CommitHistogramFilter
/**
* Commit filter that includes commits only on the specified interval
* starting from and to excluded
*/
-class AuthorHistogramFilterByDates(val from: Option[Long] = None, val to: Option[Long] = None)
- extends CommitHistogramFilter {
+class AggregatedHistogramFilterByDates(val from: Option[Long] = None, val to: Option[Long] = None,
+ val aggregationStrategy: AggregationStrategy = AggregationStrategy.EMAIL)
+ extends AbstractCommitHistogramFilter(aggregationStrategy.mapping) {
override def include(walker: RevWalk, commit: RevCommit) = {
val commitDate = commit.getCommitterIdent.getWhen.getTime
val author = commit.getAuthorIdent
if (from.fold(true)(commitDate >=) && to.fold(true)(commitDate <)) {
- histogram.include(commit, author)
+ getHistogram.include(commit, author)
true
} else {
false
}
}
- override def clone = new AuthorHistogramFilterByDates(from, to)
+ override def clone = new AggregatedHistogramFilterByDates(from, to, aggregationStrategy)
}
\ No newline at end of file
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregationStrategy.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregationStrategy.scala
new file mode 100644
index 0000000..a7e559f
--- /dev/null
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/AggregationStrategy.scala
@@ -0,0 +1,53 @@
+// 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.common
+
+import java.security.InvalidParameterException
+import java.time.{LocalDateTime, ZoneOffset}
+import java.util.Date
+
+import com.googlesource.gerrit.plugins.analytics.common.AggregatedCommitHistogram.AggregationStrategyMapping
+
+sealed case class AggregationStrategy(name: String, mapping: AggregationStrategyMapping)
+
+object AggregationStrategy {
+ val values = List(EMAIL, EMAIL_HOUR, EMAIL_DAY, EMAIL_MONTH, EMAIL_YEAR)
+
+ def apply(name: String): AggregationStrategy =
+ values.find(_.name == name.toUpperCase) match {
+ case Some(g) => g
+ case None => throw new InvalidParameterException(
+ s"Must be one of: ${values.map(_.name).mkString(",")}")
+ }
+
+ implicit class PimpedDate(val d: Date) extends AnyVal {
+ def utc: LocalDateTime = d.toInstant.atZone(ZoneOffset.UTC).toLocalDateTime
+ }
+
+ object EMAIL extends AggregationStrategy("EMAIL",
+ (p, _) => s"${p.getEmailAddress}////")
+
+ object EMAIL_YEAR extends AggregationStrategy("EMAIL_YEAR",
+ (p, d) => s"${p.getEmailAddress}/${d.utc.getYear}///")
+
+ object EMAIL_MONTH extends AggregationStrategy("EMAIL_MONTH",
+ (p, d) => s"${p.getEmailAddress}/${d.utc.getYear}/${d.utc.getMonthValue}//")
+
+ object EMAIL_DAY extends AggregationStrategy("EMAIL_DAY",
+ (p, d) => s"${p.getEmailAddress}/${d.utc.getYear}/${d.utc.getMonthValue}/${d.utc.getDayOfMonth}/")
+
+ object EMAIL_HOUR extends AggregationStrategy("EMAIL_HOUR",
+ (p, d) => s"${p.getEmailAddress}/${d.utc.getYear}/${d.utc.getMonthValue}/${d.utc.getDayOfMonth}/${d.utc.getHour}")
+}
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/DateConversions.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/DateConversions.scala
index 4aa31a7..3da8249 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/DateConversions.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/DateConversions.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/GsonFormatter.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/GsonFormatter.scala
index f9ab7a9..ba80bf2 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/GsonFormatter.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/GsonFormatter.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
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
index 991be59..004259e 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/JsonStreamedResultBuilder.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/JsonStreamedResultBuilder.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ManagedResources.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ManagedResources.scala
index 83da961..5cf2b74 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ManagedResources.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ManagedResources.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
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
index a375ff4..711d5ac 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ProjectResourceParser.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/ProjectResourceParser.scala
@@ -1,3 +1,17 @@
+// 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.common
import java.io.IOException
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/UserActivityHistogram.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/UserActivityHistogram.scala
index cebc84e..5b5a70b 100644
--- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/UserActivityHistogram.scala
+++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/UserActivityHistogram.scala
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Android Open Source Project
+// 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.
@@ -21,10 +21,10 @@
@Singleton
class UserActivityHistogram {
- def get(repo: Repository, filter: CommitHistogramFilter) = {
+ def get(repo: Repository, filter: AbstractCommitHistogramFilter) = {
val finder = new CommitFinder(repo)
finder.setFilter(filter).find
val histogram = filter.getHistogram
- histogram.getUserActivity
+ histogram.getAggregatedUserActivity
}
}
\ No newline at end of file
diff --git a/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AuthorHistogramFilterByDatesSpec.scala b/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AggregatedHistogramFilterByDatesSpec.scala
similarity index 81%
rename from src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AuthorHistogramFilterByDatesSpec.scala
rename to src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AggregatedHistogramFilterByDatesSpec.scala
index 6f4a8bc..b525c7a 100644
--- a/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AuthorHistogramFilterByDatesSpec.scala
+++ b/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AggregatedHistogramFilterByDatesSpec.scala
@@ -16,22 +16,23 @@
import java.util.Date
-import com.googlesource.gerrit.plugins.analytics.common.AuthorHistogramFilterByDates
+import com.googlesource.gerrit.plugins.analytics.common.{AggregationStrategy, AggregatedHistogramFilterByDates}
import org.eclipse.jgit.lib.PersonIdent
import org.gitective.core.CommitFinder
import org.scalatest.{BeforeAndAfterEach, FlatSpec, Matchers}
-class AuthorHistogramFilterByDatesSpec extends FlatSpec with GitTestCase with BeforeAndAfterEach with Matchers {
+class AggregatedHistogramFilterByDatesSpec extends FlatSpec with GitTestCase with BeforeAndAfterEach with Matchers {
+
"Author history filter" should
"select one commit without intervals restriction" in {
add("file.txt", "some content")
- val filter = new AuthorHistogramFilterByDates
+ val filter = new AggregatedHistogramFilterByDates
new CommitFinder(testRepo).setFilter(filter).find
val userActivity = filter.getHistogram.getUserActivity
- filter.getHistogram.getUserActivity should have size (1)
+ filter.getHistogram.getUserActivity should have size 1
val activity = userActivity.head
activity.getCount should be(1)
activity.getName should be(author.getName)
@@ -47,14 +48,14 @@
secondCommitTs should be > firstCommitTs
- val filter = new AuthorHistogramFilterByDates(from = Some(secondCommitTs))
+ val filter = new AggregatedHistogramFilterByDates(from = Some(secondCommitTs))
new CommitFinder(testRepo).setFilter(filter).find
val userActivity = filter.getHistogram.getUserActivity
- userActivity should have size (1)
+ userActivity should have size 1
val activity = userActivity.head
- activity.getTimes should have size (1)
+ activity.getTimes should have size 1
activity.getName should be(person.getName)
activity.getEmail should be(person.getEmailAddress)
}
@@ -68,14 +69,14 @@
secondCommitTs should be > firstCommitTs
- val filter = new AuthorHistogramFilterByDates(to = Some(secondCommitTs))
+ val filter = new AggregatedHistogramFilterByDates(to = Some(secondCommitTs))
new CommitFinder(testRepo).setFilter(filter).find
val userActivity = filter.getHistogram.getUserActivity
- userActivity should have size (1)
+ userActivity should have size 1
val activity = userActivity.head
- activity.getTimes should have size (1)
+ activity.getTimes should have size 1
activity.getName should be(person.getName)
activity.getEmail should be(person.getEmailAddress)
}
@@ -92,14 +93,14 @@
middleCommitTs should be > firstCommitTs
lastCommitTs should be > middleCommitTs
- val filter = new AuthorHistogramFilterByDates(from = Some(middleCommitTs), to = Some(lastCommitTs))
+ val filter = new AggregatedHistogramFilterByDates(from = Some(middleCommitTs), to = Some(lastCommitTs))
new CommitFinder(testRepo).setFilter(filter).find
val userActivity = filter.getHistogram.getUserActivity
- userActivity should have size (1)
+ userActivity should have size 1
val activity = userActivity.head
- activity.getTimes should have size (1)
+ activity.getTimes should have size 1
activity.getName should be(person.getName)
activity.getEmail should be(person.getEmailAddress)
}
diff --git a/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AggregationSpec.scala b/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AggregationSpec.scala
new file mode 100644
index 0000000..bbb691d
--- /dev/null
+++ b/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/AggregationSpec.scala
@@ -0,0 +1,199 @@
+// 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.test
+
+import java.util.Date
+
+import com.googlesource.gerrit.plugins.analytics.common.{AggregatedHistogramFilterByDates, AggregatedUserCommitActivity, AggregationStrategy}
+import org.eclipse.jgit.revwalk.RevCommit
+import org.gitective.core.CommitFinder
+import org.scalatest.{FlatSpec, Inspectors, Matchers}
+import AggregationStrategy._
+
+class AggregationSpec extends FlatSpec with Matchers with GitTestCase with Inspectors {
+
+ import com.googlesource.gerrit.plugins.analytics.common.DateConversions._
+
+ def commit(committer: String, when: String, content: String): RevCommit = {
+ val date = new Date(isoStringToLongDate(when))
+ val person = newPersonIdent(committer, committer, date)
+ add("afile.txt", content, author = person, committer = author)
+ }
+
+ def aggregateBy(strategy: AggregationStrategy) = {
+ val filter = new AggregatedHistogramFilterByDates(aggregationStrategy = strategy)
+ new CommitFinder(testRepo).setFilter(filter).find
+ filter.getHistogram.getAggregatedUserActivity
+ }
+
+ "AggregatedHistogramFilter by email and year" should "aggregate two commits from the same author the same year" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("john", "2017-10-05", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_YEAR)
+
+ userActivity should have size 1
+ userActivity.head.getCount should be(2)
+ userActivity.head.email should be("john")
+ }
+
+ it should "keep as separate rows activity from the same author on two different year" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("john", "2018-09-01", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_YEAR)
+
+ userActivity should have size 2
+ forAll(userActivity) {
+ activity => {
+ activity.email should be("john")
+ activity.getCount should be(1)
+ 1
+ }
+ }
+ }
+
+ it should "keep as separate rows activity from two different authors on the same year" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("bob", "2017-12-05", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_YEAR)
+
+ userActivity should have size 2
+ userActivity.map(_.email) should contain allOf("john", "bob")
+ forAll(userActivity) {
+ _.getCount should be(1)
+ }
+ }
+
+ "AggregatedHistogramFilter by email and month" should "aggregate two commits from the same author the same month" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("john", "2017-08-05", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_MONTH)
+
+ userActivity should have size 1
+ userActivity.head.getCount should be(2)
+ userActivity.head.email should be("john")
+ }
+
+ it should "keep as separate rows activity from the same author on two different months" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("john", "2017-09-01", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_MONTH)
+
+ userActivity should have size 2
+ forAll(userActivity) {
+ activity => {
+ activity.email should be("john")
+ activity.getCount should be(1)
+ 1
+ }
+ }
+ }
+
+ it should "keep as separate rows activity from two different authors on the same month" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("bob", "2017-08-05", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_MONTH)
+
+ userActivity should have size 2
+ userActivity.map(_.email) should contain allOf("john", "bob")
+ forAll(userActivity) {
+ _.getCount should be(1)
+ }
+ }
+
+ "AggregatedHistogramFilter by email and day" should "aggregate two commits of the same author the same day" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("john", "2017-08-01", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_DAY)
+
+ userActivity should have size 1
+ userActivity.head.getCount should be(2)
+ userActivity.head.email should be("john")
+ }
+
+ it should "keep as separate rows activity from the same author on two different days" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("john", "2017-08-02", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_DAY)
+
+ userActivity should have size 2
+ forAll(userActivity) {
+ activity => {
+ activity.email should be("john")
+ activity.getCount should be
+ 1
+ }
+ }
+ }
+
+ it should "keep as separate rows activity from two different authors on the same day" in {
+ commit("john", "2017-08-01", "first commit")
+ commit("bob", "2017-08-01", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_DAY)
+
+ userActivity should have size 2
+ userActivity.map(_.email) should contain allOf("john", "bob")
+ forAll(userActivity) {
+ _.getCount should be(1)
+ }
+ }
+
+ "AggregatedHistogramFilter by email and hour" should "aggregate two commits of the same author on the same hour" in {
+ commit("john", "2017-08-01 10:15:03", "first commit")
+ commit("john", "2017-08-01 10:45:01", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_HOUR)
+
+ userActivity should have size 1
+ userActivity.head.email should be("john")
+ userActivity.head.getCount should be(2)
+ }
+
+ it should "keep separate commits from the same author on different hours" in {
+ commit("john", "2017-08-01 10:15:03", "first commit")
+ commit("john", "2017-08-01 11:30:01", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_HOUR)
+
+ userActivity should have size 2
+ forAll(userActivity) {
+ activity => {
+ activity.email should be("john")
+ activity.getCount should be(1)
+ }
+ }
+ }
+
+ it should "keep separate commits from different authors on the same hour" in {
+ commit("john", "2017-08-01 10:15:03", "first commit")
+ commit("bob", "2017-08-01 10:20:00", "second commit")
+
+ val userActivity = aggregateBy(EMAIL_HOUR)
+
+ userActivity should have size 2
+ forAll(userActivity) {
+ _.getCount should be(1)
+ }
+ userActivity.map(_.email) should contain allOf("john", "bob")
+ }
+}