Merge branch 'stable-3.0' * stable-3.0: Adapt to Gerrit v3.0 test API Make year, month, day, hour extraction more resilient Move extract-issues to analytics.config Revert "Move extract-issues to analytics.config" Move extract-issues to analytics.config Change-Id: Ie93b13020f9470b010aefd4b76b9a7681594bd24
diff --git a/README.md b/README.md index 0f9f244..8338bcd 100644 --- a/README.md +++ b/README.md
@@ -70,7 +70,6 @@ - --until -e Ending timestamp (excluded) to consider - --aggregate -granularity -g one of email, email_year, email_month, email_day, email_hour defaulting to aggregation by email - --extract-branches -r enables splitting of aggregation by branch name and expose branch name in the payload -- --extract-issues -i enables the extraction of issues from commentLink NOTE: Timestamp format is consistent with Gerrit's query syntax, see /Documentation/user-search.html for details.
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index 89a6806..6c08a06 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -22,4 +22,16 @@ ``` Keep in mind that plugin configurations are written in [git-config style syntax](https://git-scm.com/docs/git-config#_syntax), - so you should be escaping regular expressions accordingly. \ No newline at end of file + so you should be escaping regular expressions accordingly. + +- `contributors.extract-issues` + + when set to true, enables the extraction of issues from commentLink + + Default: false + + example: + ```ini + [contributors] + extract-issues = true + ``` \ No newline at end of file
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/AnalyticsConfig.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/AnalyticsConfig.scala index 8035a43..fd31626 100644 --- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/AnalyticsConfig.scala +++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/AnalyticsConfig.scala
@@ -16,17 +16,22 @@ import com.google.gerrit.extensions.annotations.PluginName import com.google.gerrit.server.config.PluginConfigFactory -import com.google.inject.Inject +import com.google.inject.{ImplementedBy, Inject} import org.eclipse.jgit.lib.Config -class AnalyticsConfig @Inject() (val pluginConfigFactory: PluginConfigFactory, @PluginName val pluginName: String) { +@ImplementedBy(classOf[AnalyticsConfigImpl]) +trait AnalyticsConfig { + def botlikeFilenameRegexps: List[String] + def isExtractIssues: Boolean +} - lazy val pluginConfig: Config = pluginConfigFactory.getGlobalPluginConfig(pluginName) - - val Contributors = "contributors" - val BotlikeFilenameRegexp = "botlike-filename-regexp" - +class AnalyticsConfigImpl @Inject() (val pluginConfigFactory: PluginConfigFactory, @PluginName val pluginName: String) extends AnalyticsConfig{ lazy val botlikeFilenameRegexps: List[String] = pluginConfigBotLikeFilenameRegexp + lazy val isExtractIssues: Boolean = pluginConfig.getBoolean(Contributors, null, ExtractIssues, false) + private lazy val pluginConfig: Config = pluginConfigFactory.getGlobalPluginConfig(pluginName) + private val Contributors = "contributors" + private val BotlikeFilenameRegexp = "botlike-filename-regexp" + private val ExtractIssues = "extract-issues" private lazy val pluginConfigBotLikeFilenameRegexp = pluginConfig.getStringList(Contributors, null, BotlikeFilenameRegexp).toList }
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 8e048e2..f634725 100644 --- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala +++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/Contributors.scala
@@ -14,21 +14,17 @@ package com.googlesource.gerrit.plugins.analytics -import com.google.common.cache.{Cache, LoadingCache} -import com.google.gerrit.extensions.api.projects.CommentLinkInfo import com.google.gerrit.extensions.restapi.{BadRequestException, Response, RestReadView} import com.google.gerrit.server.git.GitRepositoryManager import com.google.gerrit.server.project.{ProjectCache, ProjectResource} import com.google.gerrit.server.restapi.project.ProjectsCollection import com.google.gerrit.sshd.{CommandMetaData, SshCommand} import com.google.inject.Inject -import com.google.inject.name.Named import com.googlesource.gerrit.plugins.analytics.common.DateConversions._ import com.googlesource.gerrit.plugins.analytics.common._ -import com.googlesource.gerrit.plugins.analytics.common.CommitsStatisticsCache.COMMITS_STATISTICS_CACHE -import org.eclipse.jgit.lib.ObjectId import org.kohsuke.args4j.{Option => ArgOption} +import scala.util.Try @CommandMetaData(name = "contributors", description = "Extracts the list of contributors to a project") class ContributorsCommand @Inject()(val executor: ContributorsService, @@ -76,13 +72,9 @@ } } - @ArgOption(name = "--extract-issues", aliases = Array("-i"), - usage = "Extract a list of issues and links using the Gerrit's commentLink configuration") - private var extractIssues: Boolean = false - override protected def run = gsonFmt.format(executor.get(projectRes, beginDate, endDate, - granularity.getOrElse(AggregationStrategy.EMAIL), extractBranches, extractIssues), stdout) + granularity.getOrElse(AggregationStrategy.EMAIL), extractBranches), stdout) } @@ -130,15 +122,11 @@ usage = "Do extra parsing to extract a list of all branches for each line") private var extractBranches: Boolean = false - @ArgOption(name = "--extract-issues", aliases = Array("-i"), - usage = "Extract a list of issues and links using the Gerrit's commentLink configuration") - private var extractIssues: Boolean = false - override def apply(projectRes: ProjectResource) = Response.ok( new GsonStreamedResult[UserActivitySummary](gson, executor.get(projectRes, beginDate, endDate, - granularity.getOrElse(AggregationStrategy.EMAIL), extractBranches, extractIssues))) + granularity.getOrElse(AggregationStrategy.EMAIL), extractBranches))) } class ContributorsService @Inject()(repoManager: GitRepositoryManager, @@ -148,15 +136,9 @@ commitsStatisticsCache: CommitsStatisticsCache) { import RichBoolean._ - import scala.collection.JavaConverters._ - def get(projectRes: ProjectResource, startDate: Option[Long], stopDate: Option[Long], - aggregationStrategy: AggregationStrategy, extractBranches: Boolean, extractIssues: Boolean) + aggregationStrategy: AggregationStrategy, extractBranches: Boolean) : TraversableOnce[UserActivitySummary] = { - val nameKey = projectRes.getNameKey - val commentLinks: List[CommentLinkInfo] = extractIssues.option { - projectCache.get(nameKey).getCommentLinks.asScala - }.toList.flatten ManagedResource.use(repoManager.openRepository(projectRes.getNameKey)) { repo => val stats = new Statistics(projectRes.getNameKey, commitsStatisticsCache) @@ -197,7 +179,7 @@ def apply(statisticsHandler: Statistics)(uca: AggregatedUserCommitActivity) : Iterable[UserActivitySummary] = { - implicit def stringToIntOrNull(x: String): Integer = if (x.isEmpty) null else new Integer(x) + def stringToIntOrNull(x: String): Integer = Try(new Integer(x)).getOrElse(null) uca.key.split("/", AggregationStrategy.MAX_MAPPING_TOKENS) match { case Array(email, year, month, day, hour, branch) => @@ -206,7 +188,8 @@ Option(branch).filter(_.nonEmpty).map(b => Array(b)).getOrElse(Array.empty) UserActivitySummary( - year, month, day, hour, uca.getName, email, stat.commits.size, + stringToIntOrNull(year), stringToIntOrNull(month), stringToIntOrNull(day), stringToIntOrNull(hour), + uca.getName, email, stat.commits.size, stat.numFiles, stat.numDistinctFiles, stat.addedLines, stat.deletedLines, stat.commits.toArray, maybeBranches, stat.issues.map(_.code) .toArray, stat.issues.map(_.link).toArray, uca.getLatest, stat
diff --git a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/CommitsStatisticsLoader.scala b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/CommitsStatisticsLoader.scala index 36a175b..1144901 100644 --- a/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/CommitsStatisticsLoader.scala +++ b/src/main/scala/com/googlesource/gerrit/plugins/analytics/common/CommitsStatisticsLoader.scala
@@ -20,7 +20,7 @@ import com.google.gerrit.server.git.GitRepositoryManager import com.google.gerrit.server.project.ProjectCache import com.google.inject.Inject -import com.googlesource.gerrit.plugins.analytics.{CommitInfo, IssueInfo} +import com.googlesource.gerrit.plugins.analytics.{AnalyticsConfig, CommitInfo, IssueInfo} import com.googlesource.gerrit.plugins.analytics.common.ManagedResource.use import org.eclipse.jgit.diff.{DiffFormatter, RawTextComparator} import org.eclipse.jgit.revwalk.RevWalk @@ -30,14 +30,20 @@ import scala.collection.JavaConverters._ import scala.util.matching.Regex -class CommitsStatisticsLoader @Inject() (gitRepositoryManager: GitRepositoryManager, projectCache: ProjectCache, botLikeExtractor: BotLikeExtractor) extends CacheLoader[CommitsStatisticsCacheKey, CommitsStatistics] { +class CommitsStatisticsLoader @Inject() ( + gitRepositoryManager: GitRepositoryManager, + projectCache: ProjectCache, + botLikeExtractor: BotLikeExtractor, + config: AnalyticsConfig +) extends CacheLoader[CommitsStatisticsCacheKey, CommitsStatistics] { override def load(cacheKey: CommitsStatisticsCacheKey): CommitsStatistics = { import RevisionBrowsingSupport._ val objectId = cacheKey.commitId val nameKey = new Project.NameKey(cacheKey.projectName) - val commentInfoList: Seq[CommentLinkInfo] = projectCache.get(nameKey).getCommentLinks.asScala + val commentInfoList: Seq[CommentLinkInfo] = + if(config.isExtractIssues) projectCache.get(nameKey).getCommentLinks.asScala else Seq.empty val replacers = commentInfoList.map(info => Replacer( info.`match`.r,
diff --git a/src/test/scala/com/googlesource/gerrit/plugins/analytics/common/BotLikeExtractorImplSpec.scala b/src/test/scala/com/googlesource/gerrit/plugins/analytics/common/BotLikeExtractorImplSpec.scala index e9f9c7a..5bb73c5 100644 --- a/src/test/scala/com/googlesource/gerrit/plugins/analytics/common/BotLikeExtractorImplSpec.scala +++ b/src/test/scala/com/googlesource/gerrit/plugins/analytics/common/BotLikeExtractorImplSpec.scala
@@ -46,7 +46,8 @@ extractor.isBotLike(Set("some/path/anyFile")).shouldBe(false) } - private def newBotLikeExtractorImpl(botLikeRegexps: List[String]) = new BotLikeExtractorImpl(new AnalyticsConfig(null, null) { + private def newBotLikeExtractorImpl(botLikeRegexps: List[String]) = new BotLikeExtractorImpl(new AnalyticsConfig { override lazy val botlikeFilenameRegexps = botLikeRegexps + override lazy val isExtractIssues: Boolean = false }) }
diff --git a/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/GerritTestDaemon.scala b/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/GerritTestDaemon.scala index f10c772..0024e1e 100644 --- a/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/GerritTestDaemon.scala +++ b/src/test/scala/com/googlesource/gerrit/plugins/analytics/test/GerritTestDaemon.scala
@@ -19,8 +19,10 @@ import com.google.gerrit.acceptance.{AbstractDaemonTest, GitUtil} import com.google.gerrit.extensions.annotations.PluginName +import com.google.gerrit.extensions.client.SubmitType import com.google.gerrit.reviewdb.client.Project import com.google.inject.{AbstractModule, Module} +import com.googlesource.gerrit.plugins.analytics.AnalyticsConfig import org.eclipse.jgit.api.MergeCommand.FastForwardMode import org.eclipse.jgit.api.{Git, MergeResult} import org.eclipse.jgit.internal.storage.file.FileRepository @@ -136,22 +138,27 @@ object GerritTestDaemon extends AbstractDaemonTest { baseConfig = new Config() + AbstractDaemonTest.temporaryFolder.create() def newProject(nameSuffix: String) = { resourcePrefix = "" - super.createProject(nameSuffix, allProjects, false) + super.createProjectOverAPI(nameSuffix, allProjects, false, SubmitType.MERGE_IF_NECESSARY) } def getRepository(projectName: Project.NameKey): FileRepository = repoManager.openRepository(projectName).asInstanceOf[FileRepository] - def adminAuthor = admin.getIdent + def adminAuthor = admin.newIdent def getInstance[T](clazz: Class[T]): T = server.getTestInjector.getInstance(clazz) override def createModule(): Module = new AbstractModule { override def configure(): Unit = { + bind(classOf[AnalyticsConfig]).toInstance(new AnalyticsConfig { + override def botlikeFilenameRegexps: List[String] = List.empty + override def isExtractIssues: Boolean = true + }) bind(classOf[String]).annotatedWith(classOf[PluginName]).toInstance("analytics") } }