From dbc8135610cdf5f9cfa829db009ca81761b9dce5 Mon Sep 17 00:00:00 2001 From: Sebastian Chmielewski Date: Thu, 17 Aug 2017 10:23:36 +0200 Subject: [PATCH 01/17] fix(coverage): fix sonar.source with semicolons add support for sonar.sources property containing multiple directories separated by semicolon --- .../com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala index 3e3c414..e006af6 100644 --- a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala +++ b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala @@ -145,7 +145,7 @@ class ScoverageSensor(settings: Settings, pathResolver: PathResolver, fileSystem log.info(LogUtil.f("Statement coverage for " + project.getKey + " is " + ("%1.2f" format projectCoverage.rate))) // Process children - processChildren(projectCoverage.children, context, sonarSources) + sonarSources.split(",").foreach(subdir => processChildren(projectCoverage.children, context, subdir)) } private def processDirectory(directoryCoverage: DirectoryStatementCoverage, context: SensorContext, parentDirectory: String) { From 1c7c452355dfa05be69e4a3e767ff8f6cea753d7 Mon Sep 17 00:00:00 2001 From: Sebastian Chmielewski Date: Thu, 17 Aug 2017 11:45:45 +0200 Subject: [PATCH 02/17] fix(coverage): fix for absolute vs relative paths fix for maven sending absolute paths and sonar-runner sending relative paths --- .../pathcleaner/BruteForceSequenceMatcher.scala | 15 +++++++++++---- .../scoverage/sensor/ScoverageSensor.scala | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala b/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala index 458e4e8..bab7f36 100644 --- a/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala +++ b/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala @@ -22,7 +22,8 @@ package com.buransky.plugins.scoverage.pathcleaner import java.io.File import org.apache.commons.io.FileUtils import BruteForceSequenceMatcher._ -import com.buransky.plugins.scoverage.util.PathUtil +import com.buransky.plugins.scoverage.util.{LogUtil, PathUtil} + import scala.collection.JavaConversions._ import org.sonar.api.utils.log.Loggers @@ -48,11 +49,12 @@ object BruteForceSequenceMatcher { */ class BruteForceSequenceMatcher(baseDir: File, sourcePath: String) extends PathSanitizer { + private val log = Loggers.get(classOf[BruteForceSequenceMatcher]) + private val sourceDir = initSourceDir() require(sourceDir.isAbsolute) require(sourceDir.isDirectory) - private val log = Loggers.get(classOf[BruteForceSequenceMatcher]) private val sourcePathLength = PathUtil.splitPath(sourceDir.getAbsolutePath).size private val filesMap = initFilesMap() @@ -71,8 +73,13 @@ class BruteForceSequenceMatcher(baseDir: File, sourcePath: String) extends PathS private[pathcleaner] def initSourceDir(): File = { sourcePath.split(",").headOption.map { first => - val sourceDir = new File(baseDir, first) - sourceDir + if(first.startsWith(File.separator)) { + log.warn("Absolute path given, trying to open:" + first) + new File(first) + } else { + log.warn(LogUtil.f("Relative path given, trying to open: " + first +" in dir " + baseDir )) + new File(baseDir, first) + } }.getOrElse(null) } diff --git a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala index e006af6..2535d14 100644 --- a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala +++ b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala @@ -184,7 +184,7 @@ class ScoverageSensor(settings: Settings, pathResolver: PathResolver, fileSystem val inputOption: Option[InputPath] = if (isFile) { val p = fileSystem.predicates() Option(fileSystem.inputFile(p.and( - p.hasRelativePath(path), + p.or(p.hasPath(path),p.hasRelativePath(path)), p.hasLanguage(Scala.key), p.hasType(InputFile.Type.MAIN)))) } else { From 9d181531dc5b4a3a15eba9aa859f8feb87138aa8 Mon Sep 17 00:00:00 2001 From: Sebastian Chmielewski Date: Thu, 17 Aug 2017 11:45:45 +0200 Subject: [PATCH 03/17] fix(coverage): fix exception on empty coverage fix exception while running sonar plugin and coverage is generated for empty module --- ...XmlScoverageReportConstructingParser.scala | 7 +++++-- ...coverageReportConstructingParserSpec.scala | 21 +++++++++++++++++++ .../scoverage/xml/data/XmlReportFile1.scala | 6 ++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParser.scala b/src/main/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParser.scala index d77c5e4..6eb0149 100644 --- a/src/main/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParser.scala +++ b/src/main/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParser.scala @@ -143,7 +143,10 @@ class XmlScoverageReportConstructingParser(source: Source, pathSanitizer: PathSa val childNodes = children.map(_.toStatementCoverage) childNodes match { - case Nil => coverage.get + case Nil => coverage match { + case None => FileStatementCoverage("Nothing", 0, 0, List.empty[CoveredStatement]) + case _ => coverage.get + } case _ => DirectoryStatementCoverage(name, childNodes) } } @@ -224,4 +227,4 @@ class XmlScoverageReportConstructingParser(source: Source, pathSanitizer: PathSa private def coveredStatements(statements: Iterable[CoveredStatement]) = statements.count(_.hitCount > 0) -} \ No newline at end of file +} diff --git a/src/test/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParserSpec.scala b/src/test/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParserSpec.scala index d4ab1e1..6f212f6 100644 --- a/src/test/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParserSpec.scala +++ b/src/test/scala/com/buransky/plugins/scoverage/xml/XmlScoverageReportConstructingParserSpec.scala @@ -34,6 +34,16 @@ import com.buransky.plugins.scoverage.NodeStatementCoverage class XmlScoverageReportConstructingParserSpec extends FlatSpec with Matchers { behavior of "parse source" + it must "parse empty coverage file correctly" in { + val sanitizer = new PathSanitizer() { + def getSourceRelativePath(path: Seq[String]): Option[Seq[String]] = { + // do nothing + Some(path) + } + } + assertReportFile(XmlReportFile1.emptyCoverage, 0, sanitizer)(assertEmptyCoverage) + } + it must "parse old broken Scoverage 0.95 file correctly" in { val sanitizer = new PathSanitizer() { def getSourceRelativePath(path: Seq[String]): Option[Seq[String]] = { @@ -130,4 +140,15 @@ class XmlScoverageReportConstructingParserSpec extends FlatSpec with Matchers { node.children } + + private def assertEmptyCoverage(projectCoverage: ProjectStatementCoverage): Unit = { + // Assert structure + projectCoverage.name should equal("") + + val projectChildren = projectCoverage.children.toList + projectChildren.length should equal(0) + projectCoverage.coveredStatementsCount should equal(0) + projectCoverage.statementCount should equal(0) + projectCoverage.coveredStatementsCount should equal(0) + } } diff --git a/src/test/scala/com/buransky/plugins/scoverage/xml/data/XmlReportFile1.scala b/src/test/scala/com/buransky/plugins/scoverage/xml/data/XmlReportFile1.scala index 82ec85c..abdb615 100644 --- a/src/test/scala/com/buransky/plugins/scoverage/xml/data/XmlReportFile1.scala +++ b/src/test/scala/com/buransky/plugins/scoverage/xml/data/XmlReportFile1.scala @@ -834,4 +834,10 @@ object XmlReportFile1 { | | """.stripMargin + + val emptyCoverage = + """ + | + |""".stripMargin } From a140f6104fe671ab6aa74f97c2f60290983868e4 Mon Sep 17 00:00:00 2001 From: Sebastian Chmielewski Date: Thu, 17 Aug 2017 12:50:59 +0200 Subject: [PATCH 04/17] feat(coverage): move language definition to Java move language definition to Java file so it can be referenced from other plugins. It didn't work with Scala class (missing Scala runtime on classpath?) Package name is consistent with Sonar convention. --- pom.xml | 22 +++- .../java/org/sonar/plugins/scala/Scala.java | 102 ++++++++++++++++++ .../scoverage/sensor/ScoverageSensor.scala | 6 +- .../sagacify/sonar/scala/ScalaPlugin.scala | 30 +----- .../sagacify/sonar/scala/ScalaSensor.scala | 2 + .../sensor/ScoverageSensorSpec.scala | 2 +- .../sonar/scala/BaseMetricSensorSpec.scala | 2 + .../sagacify/sonar/scala/MeasuresSpec.scala | 1 + .../sonar/scala/ScalaPluginSpec.scala | 1 + 9 files changed, 137 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/sonar/plugins/scala/Scala.java diff --git a/pom.xml b/pom.xml index 5bb397f..8afe56e 100644 --- a/pom.xml +++ b/pom.xml @@ -142,11 +142,31 @@ ${sonar.version} test + + com.google.guava + guava + 10.0.1 + + + + commons-lang + commons-lang + 2.6 + - src/main/scala + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.7 + 1.7 + + org.scoverage scoverage-maven-plugin diff --git a/src/main/java/org/sonar/plugins/scala/Scala.java b/src/main/java/org/sonar/plugins/scala/Scala.java new file mode 100644 index 0000000..93b62b5 --- /dev/null +++ b/src/main/java/org/sonar/plugins/scala/Scala.java @@ -0,0 +1,102 @@ +/* + * Sonar Scala Plugin + * Copyright (C) 2016-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.scala; + +import org.sonar.api.config.Settings; +import org.sonar.api.resources.AbstractLanguage; + +import scalariform.lexer.ScalaLexer; +import scalariform.lexer.Token; + +import com.google.common.collect.Lists; +import org.apache.commons.lang.StringUtils; + +import java.util.List; + +/** + * This language cover JavaServer Pages (Scala). + * + */ +public class Scala extends AbstractLanguage { + + /** + * Scala key + */ + public static final String KEY = "scala"; + + /** + * Scala language name + */ + public static final String NAME = "Scala"; + + + /** + * Key of the file suffix parameter + */ + public static final String FILE_SUFFIXES_KEY = "sonar.scala.file.suffixes"; + + /** + * Default Java files knows suffixes + */ + public static final String DEFAULT_FILE_SUFFIXES = ".scala"; + + /** + * Settings of the plugin. + */ + private final Settings settings; + + /** + * Default constructor + */ + public Scala(Settings settings) { + super(KEY, NAME); + this.settings = settings; + } + + /** + * {@inheritDoc} + * + * @see org.sonar.api.resources.AbstractLanguage#getFileSuffixes() + */ + @Override + public String[] getFileSuffixes() { + String[] suffixes = filterEmptyStrings(settings.getStringArray(FILE_SUFFIXES_KEY)); + if (suffixes.length == 0) { + suffixes = StringUtils.split(DEFAULT_FILE_SUFFIXES, ","); + } + return suffixes; + } + + private static String[] filterEmptyStrings(String[] stringArray) { + List nonEmptyStrings = Lists.newArrayList(); + for (String string : stringArray) { + if (StringUtils.isNotBlank(string.trim())) { + nonEmptyStrings.add(string.trim()); + } + } + return nonEmptyStrings.toArray(new String[nonEmptyStrings.size()]); + } + + + public static scala.collection.immutable.List tokenize(String sourceCode, String scalaVersion) { + return ScalaLexer.createRawLexer(sourceCode, false, scalaVersion).toList(); + } + +} \ No newline at end of file diff --git a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala index 2535d14..f72e5a5 100644 --- a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala +++ b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala @@ -19,7 +19,6 @@ */ package com.buransky.plugins.scoverage.sensor -import com.buransky.plugins.scoverage.language.Scala import com.buransky.plugins.scoverage.measure.ScalaMetrics import com.buransky.plugins.scoverage.pathcleaner.{BruteForceSequenceMatcher, PathSanitizer} import com.buransky.plugins.scoverage.util.LogUtil @@ -32,6 +31,7 @@ import org.sonar.api.measures.{CoverageMeasuresBuilder, Measure} import org.sonar.api.resources.{Project, Resource} import org.sonar.api.scan.filesystem.PathResolver import org.sonar.api.utils.log.Loggers +import org.sonar.plugins.scala.Scala import scala.collection.JavaConversions._ @@ -46,7 +46,7 @@ class ScoverageSensor(settings: Settings, pathResolver: PathResolver, fileSystem protected val SCOVERAGE_REPORT_PATH_PROPERTY = "sonar.scoverage.reportPath" protected lazy val scoverageReportParser: ScoverageReportParser = XmlScoverageReportParser() - override def shouldExecuteOnProject(project: Project): Boolean = fileSystem.languages().contains(Scala.key) + override def shouldExecuteOnProject(project: Project): Boolean = fileSystem.languages().contains(Scala.KEY) override def analyse(project: Project, context: SensorContext) { scoverageReportPath match { @@ -185,7 +185,7 @@ class ScoverageSensor(settings: Settings, pathResolver: PathResolver, fileSystem val p = fileSystem.predicates() Option(fileSystem.inputFile(p.and( p.or(p.hasPath(path),p.hasRelativePath(path)), - p.hasLanguage(Scala.key), + p.hasLanguage(Scala.KEY), p.hasType(InputFile.Type.MAIN)))) } else { Option(fileSystem.inputDir(pathResolver.relativeFile(fileSystem.baseDir(), path))) diff --git a/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala b/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala index 770758e..5140d7e 100644 --- a/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala +++ b/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala @@ -1,36 +1,14 @@ package com.sagacify.sonar.scala -import scala.collection.JavaConversions._ -import scala.collection.mutable.ListBuffer - +import org.sonar.plugins.scala.Scala import com.buransky.plugins.scoverage.measure.ScalaMetrics import com.buransky.plugins.scoverage.sensor.ScoverageSensor import com.buransky.plugins.scoverage.widget.ScoverageWidget -import com.ncredinburgh.sonar.scalastyle.ScalastyleQualityProfile -import com.ncredinburgh.sonar.scalastyle.ScalastyleRepository -import com.ncredinburgh.sonar.scalastyle.ScalastyleSensor -import org.sonar.api.config.Settings -import org.sonar.api.Extension -import org.sonar.api.resources.AbstractLanguage +import com.ncredinburgh.sonar.scalastyle.{ScalastyleQualityProfile, ScalastyleRepository, ScalastyleSensor} import org.sonar.api.SonarPlugin -import scalariform.lexer.ScalaLexer -import scalariform.lexer.Token - -/** - * Defines Scala as a language for SonarQube. - */ -class Scala(s: Settings) extends AbstractLanguage("scala", "Scala") { - - override def getFileSuffixes: Array[String] = Array("scala") -} - -object Scala { - - def tokenize(sourceCode: String, scalaVersion: String): List[Token] = - ScalaLexer.createRawLexer(sourceCode, false, scalaVersion).toList - -} +import scala.collection.JavaConversions._ +import scala.collection.mutable.ListBuffer /** * Plugin entry point. diff --git a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala index 02ff5bf..6f87b2d 100644 --- a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala +++ b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala @@ -1,5 +1,7 @@ package com.sagacify.sonar.scala +import org.sonar.plugins.scala.Scala + import scala.io.Source import scala.collection.JavaConversions._ diff --git a/src/test/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensorSpec.scala b/src/test/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensorSpec.scala index ead1de9..d18212e 100644 --- a/src/test/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensorSpec.scala +++ b/src/test/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensorSpec.scala @@ -22,7 +22,7 @@ // import java.io.File // import java.util -// import com.buransky.plugins.scoverage.language.Scala +// import org.sonar.plugins.scala.Scala // import com.buransky.plugins.scoverage.{FileStatementCoverage, DirectoryStatementCoverage, ProjectStatementCoverage, ScoverageReportParser} // import org.junit.runner.RunWith // import org.mockito.Mockito._ diff --git a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala index 3781a7f..36a820f 100644 --- a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala @@ -10,6 +10,8 @@ import org.mockito.Mockito.verifyNoMoreInteractions; import java.io.IOException; import java.nio.file.Paths +import org.sonar.plugins.scala.Scala + import scala.collection.JavaConversions._ import org.junit.Before; diff --git a/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala b/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala index 871c897..f4a0a62 100644 --- a/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala @@ -1,5 +1,6 @@ package com.sagacify.sonar.scala +import org.sonar.plugins.scala.Scala import org.scalatest._ // import scalariform.lexer.ScalaLexer // import scalariform.lexer.Token diff --git a/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala b/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala index 12960cc..721cc71 100755 --- a/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala @@ -18,6 +18,7 @@ */ package com.sagacify.sonar.scala +import org.sonar.plugins.scala.Scala import com.ncredinburgh.sonar.scalastyle.ScalastyleSensor import com.ncredinburgh.sonar.scalastyle.ScalastyleRepository import com.ncredinburgh.sonar.scalastyle.ScalastyleQualityProfile From 8fa49b615f61b8035706c7fcfcfe73b7caa237f7 Mon Sep 17 00:00:00 2001 From: Boyan Bonev Date: Fri, 2 Jun 2017 11:54:22 +0300 Subject: [PATCH 05/17] feat(classes): Add counting of Scala classes There was no support for collecting Scala class number so I added it. Tested with the unit tests and with SonarQube 6.3.1. Everything seemed OK. --- .../scala/com/sagacify/sonar/scala/Measures.scala | 15 +++++++++------ .../com/sagacify/sonar/scala/ScalaSensor.scala | 2 +- src/test/resources/ScalaFile2.scala | 3 +++ .../sonar/scala/BaseMetricSensorSpec.scala | 5 ++++- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/scala/com/sagacify/sonar/scala/Measures.scala b/src/main/scala/com/sagacify/sonar/scala/Measures.scala index 8403b05..56e425b 100644 --- a/src/main/scala/com/sagacify/sonar/scala/Measures.scala +++ b/src/main/scala/com/sagacify/sonar/scala/Measures.scala @@ -1,17 +1,20 @@ package com.sagacify.sonar.scala import scala.annotation.tailrec - import scalariform.lexer.ScalaLexer import scalariform.lexer.Token -import scalariform.lexer.Tokens.LINE_COMMENT -import scalariform.lexer.Tokens.MULTILINE_COMMENT -import scalariform.lexer.Tokens.XML_COMMENT -import scalariform.lexer.Tokens.WS -import scalariform.lexer.Tokens.EOF +import scalariform.lexer.Tokens._ object Measures { + final def count_classes(tokens: List[Token], i: Int = 0): Int = { + var count = 0 + tokens.foreach(token => if (token.tokenType == CLASS || token.tokenType == OBJECT) count += 1) + + count + } + + /* applied on raw source code */ /* applied on lines of code */ diff --git a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala index 02ff5bf..ceccb2a 100644 --- a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala +++ b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala @@ -36,7 +36,7 @@ class ScalaSensor(scala: Scala, fs: FileSystem) extends Sensor { CM.NCLOC, Measures.count_ncloc(tokens)) - // context.saveMeasure(input, CM.CLASSES, classes) + context.saveMeasure(inputFile, CM.CLASSES, Measures.count_classes(tokens)) // context.saveMeasure(input, CM.FUNCTIONS, methods) // context.saveMeasure(input, CM.ACCESSORS, accessors) // context.saveMeasure(input, CM.COMPLEXITY_IN_FUNCTIONS, complexityInMethods) diff --git a/src/test/resources/ScalaFile2.scala b/src/test/resources/ScalaFile2.scala index eb7cc9f..066bb7e 100644 --- a/src/test/resources/ScalaFile2.scala +++ b/src/test/resources/ScalaFile2.scala @@ -7,3 +7,6 @@ class ScalaFile2 { println("function called.") } } + +object ScalaFile2 { +} diff --git a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala index 3781a7f..0002182 100644 --- a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala @@ -67,6 +67,8 @@ class ScalaSensorSpec extends FlatSpec with Matchers { .saveMeasure(file, CM.FILES, 1) verify(sensorContext, times(1)) .saveMeasure(file, CM.COMMENT_LINES, 0) + verify(sensorContext, times(1)) + .saveMeasure(file, CM.CLASSES, 1) } } @@ -87,7 +89,8 @@ class ScalaSensorSpec extends FlatSpec with Matchers { .saveMeasure(file, CM.FILES, 1) verify(sensorContext, times(1)) .saveMeasure(file, CM.COMMENT_LINES, 1) - + verify(sensorContext, times(1)) + .saveMeasure(file, CM.CLASSES, 2) } } } From a2bb32cd789e9570ca07ec26ecd5d8fea4751100 Mon Sep 17 00:00:00 2001 From: Boyan Bonev Date: Wed, 14 Jun 2017 15:46:46 +0300 Subject: [PATCH 06/17] feat(method): Add support for Scala methods The count of the Scala methods was missing so I added support for this. Tested with unit test --- .../com/sagacify/sonar/scala/Measures.scala | 9 +++++-- .../sagacify/sonar/scala/ScalaSensor.scala | 26 ++++++++----------- src/test/resources/ScalaFile2.scala | 1 + .../sonar/scala/BaseMetricSensorSpec.scala | 4 +++ 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/main/scala/com/sagacify/sonar/scala/Measures.scala b/src/main/scala/com/sagacify/sonar/scala/Measures.scala index 56e425b..566a15a 100644 --- a/src/main/scala/com/sagacify/sonar/scala/Measures.scala +++ b/src/main/scala/com/sagacify/sonar/scala/Measures.scala @@ -6,14 +6,19 @@ import scalariform.lexer.Token import scalariform.lexer.Tokens._ object Measures { - - final def count_classes(tokens: List[Token], i: Int = 0): Int = { + def count_classes(tokens: List[Token]): Int = { var count = 0 tokens.foreach(token => if (token.tokenType == CLASS || token.tokenType == OBJECT) count += 1) count } + final def count_methods(tokens: List[Token]): Int = { + var count = 0 + tokens.foreach(token => if (token.tokenType == DEF) count += 1) + + count + } /* applied on raw source code */ diff --git a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala index ceccb2a..e12b1ce 100644 --- a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala +++ b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala @@ -29,22 +29,18 @@ class ScalaSensor(scala: Scala, fs: FileSystem) extends Sensor { val sourceCode = Source.fromFile(inputFile.file, charset).mkString val tokens = Scala.tokenize(sourceCode, version) - context.saveMeasure(inputFile, - CM.COMMENT_LINES, - Measures.count_comment_lines(tokens)) - context.saveMeasure(inputFile, - CM.NCLOC, - Measures.count_ncloc(tokens)) - + context.saveMeasure(inputFile, CM.COMMENT_LINES, Measures.count_comment_lines(tokens)) + context.saveMeasure(inputFile, CM.NCLOC, Measures.count_ncloc(tokens)) context.saveMeasure(inputFile, CM.CLASSES, Measures.count_classes(tokens)) - // context.saveMeasure(input, CM.FUNCTIONS, methods) - // context.saveMeasure(input, CM.ACCESSORS, accessors) - // context.saveMeasure(input, CM.COMPLEXITY_IN_FUNCTIONS, complexityInMethods) - // context.saveMeasure(input, CM.COMPLEXITY_IN_CLASSES, fileComplexity) - // context.saveMeasure(input, CM.COMPLEXITY, fileComplexity) - // context.saveMeasure(input, CM.PUBLIC_API, publicApiChecker.getPublicApi()) - // context.saveMeasure(input, CM.PUBLIC_DOCUMENTED_API_DENSITY, publicApiChecker.getDocumentedPublicApiDensity()) - // context.saveMeasure(input, CM.PUBLIC_UNDOCUMENTED_API, publicApiChecker.getUndocumentedPublicApi()) + context.saveMeasure(inputFile, CM.FUNCTIONS, Measures.count_methods(tokens)) + + // context.saveMeasure(inputFile, CM.ACCESSORS, accessors) + // context.saveMeasure(inputFile, CM.COMPLEXITY_IN_FUNCTIONS, complexityInMethods) + // context.saveMeasure(inputFile, CM.COMPLEXITY_IN_CLASSES, fileComplexity) + // context.saveMeasure(inputFile, CM.COMPLEXITY, fileComplexity) + // context.saveMeasure(inputFile, CM.PUBLIC_API, publicApiChecker.getPublicApi()) + // context.saveMeasure(inputFile, CM.PUBLIC_DOCUMENTED_API_DENSITY, publicApiChecker.getDocumentedPublicApiDensity()) + // context.saveMeasure(inputFile, CM.PUBLIC_UNDOCUMENTED_API, publicApiChecker.getUndocumentedPublicApi()) } } diff --git a/src/test/resources/ScalaFile2.scala b/src/test/resources/ScalaFile2.scala index 066bb7e..324d2bf 100644 --- a/src/test/resources/ScalaFile2.scala +++ b/src/test/resources/ScalaFile2.scala @@ -9,4 +9,5 @@ class ScalaFile2 { } object ScalaFile2 { + def func2 = "" } diff --git a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala index 0002182..869bc47 100644 --- a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala @@ -69,6 +69,8 @@ class ScalaSensorSpec extends FlatSpec with Matchers { .saveMeasure(file, CM.COMMENT_LINES, 0) verify(sensorContext, times(1)) .saveMeasure(file, CM.CLASSES, 1) + verify(sensorContext, times(1)) + .saveMeasure(file, CM.FUNCTIONS, 1) } } @@ -91,6 +93,8 @@ class ScalaSensorSpec extends FlatSpec with Matchers { .saveMeasure(file, CM.COMMENT_LINES, 1) verify(sensorContext, times(1)) .saveMeasure(file, CM.CLASSES, 2) + verify(sensorContext, times(1)) + .saveMeasure(file, CM.FUNCTIONS, 2) } } } From e4cc2df044b59895cc88f0facd668a7d0fe4d548 Mon Sep 17 00:00:00 2001 From: Scott Bartram Date: Wed, 8 Nov 2017 11:56:06 -0500 Subject: [PATCH 07/17] updated to current version of sonarqube and started fixing some of the tests --- pom.xml | 57 +++++++++------ .../sagacify/sonar/scala/ScalaPlugin.scala | 59 ++++++++------- .../scalastyle/ScalastyleRunnerSpec.scala | 8 ++- .../scalastyle/ScalastyleSensorSpec.scala | 2 +- .../sonar/scala/BaseMetricSensorSpec.scala | 72 ++++++++----------- .../sonar/scala/ScalaPluginSpec.scala | 40 ++++++----- 6 files changed, 125 insertions(+), 113 deletions(-) diff --git a/pom.xml b/pom.xml index 5bb397f..cc5e097 100644 --- a/pom.xml +++ b/pom.xml @@ -5,17 +5,17 @@ org.sonarsource.parent parent - 31 + 41 sonar-scala-plugin sonar-plugin - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT Sonar Scala Plugin Enables analysis of Scala projects into Sonar. - http://github.com/sagacify/sonar-scala - 2016 + http://github.com/sbartram/sonar-scala + 2017 @@ -40,24 +40,24 @@ - scm:git:git@github.com:sagacify/sonar-scala.git - scm:git:git@github.com:sagacify/sonar-scala.git - https://github.com/sagacify/sonar-scala + scm:git:git@github.com:sbartram/sonar-scala.git + scm:git:git@github.com:sbartram/sonar-scala.git + https://github.com/sbartram/sonar-scala HEAD - https://github.com/sagacify/sonar-scala/issues + https://github.com/sbartram/sonar-scala/issues - 5.4 + 6.5 scala Scala com.sagacify.sonar.scala.ScalaPlugin - 2.11.8 - 2.11 + 2.10.7 + 2.10 @@ -77,7 +77,7 @@ org.scalariform scalariform_${scala.major.version} - 0.1.8 + 0.2.6 org.scala-lang @@ -88,27 +88,27 @@ org.slf4j slf4j-api - 1.6.2 + 1.7.25 provided com.google.code.findbugs jsr305 - 3.0.0 + 3.0.2 commons-io commons-io - 2.5 + 2.6 org.scalatest scalatest_${scala.major.version} - 2.2.6 + 3.0.4 test @@ -117,6 +117,14 @@ + + + org.mockito + mockito-core + 2.12.0 + test + + org.sonarsource.sonarqube sonar-testing-harness @@ -127,7 +135,7 @@ org.scalastyle scalastyle_${scala.major.version} - 0.8.0 + 1.0.0 org.scala-lang @@ -142,16 +150,20 @@ ${sonar.version} test + + src/main/scala + + org.scoverage scoverage-maven-plugin - 1.1.1 - + 1.3.0 + @@ -161,6 +173,7 @@ true + org.scalatest @@ -180,11 +193,12 @@ + net.alchim31.maven scala-maven-plugin - 3.2.2 + 3.3.1 @@ -194,6 +208,9 @@ + + + diff --git a/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala b/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala index 770758e..c9b8634 100644 --- a/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala +++ b/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala @@ -1,25 +1,19 @@ package com.sagacify.sonar.scala -import scala.collection.JavaConversions._ -import scala.collection.mutable.ListBuffer - import com.buransky.plugins.scoverage.measure.ScalaMetrics import com.buransky.plugins.scoverage.sensor.ScoverageSensor import com.buransky.plugins.scoverage.widget.ScoverageWidget -import com.ncredinburgh.sonar.scalastyle.ScalastyleQualityProfile -import com.ncredinburgh.sonar.scalastyle.ScalastyleRepository -import com.ncredinburgh.sonar.scalastyle.ScalastyleSensor -import org.sonar.api.config.Settings -import org.sonar.api.Extension +import com.ncredinburgh.sonar.scalastyle.{ScalastyleQualityProfile, ScalastyleRepository, ScalastyleSensor} +import org.sonar.api.Plugin +import org.sonar.api.config.Configuration import org.sonar.api.resources.AbstractLanguage -import org.sonar.api.SonarPlugin -import scalariform.lexer.ScalaLexer -import scalariform.lexer.Token + +import scalariform.lexer.{ScalaLexer, Token} /** * Defines Scala as a language for SonarQube. */ -class Scala(s: Settings) extends AbstractLanguage("scala", "Scala") { +class Scala(s: Configuration) extends AbstractLanguage("scala", "Scala") { override def getFileSuffixes: Array[String] = Array("scala") @@ -35,20 +29,31 @@ object Scala { /** * Plugin entry point. */ -class ScalaPlugin extends SonarPlugin { - - override def getExtensions: java.util.List[Class[_]] = - ListBuffer[Class[_]] ( - classOf[Scala], - classOf[ScalaSensor], - classOf[ScalastyleRepository], - classOf[ScalastyleQualityProfile], - classOf[ScalastyleSensor], - classOf[ScalaMetrics], - classOf[ScoverageSensor], - classOf[ScoverageWidget] +class ScalaPlugin extends Plugin { + +// override def getExtensions: java.util.List[Class[_]] = +// ListBuffer[Class[_]] ( +// classOf[Scala], +// classOf[ScalaSensor], +// classOf[ScalastyleRepository], +// classOf[ScalastyleQualityProfile], +// classOf[ScalastyleSensor], +// classOf[ScalaMetrics], +// classOf[ScoverageSensor], +// classOf[ScoverageWidget] +// ) +// +// override val toString = getClass.getSimpleName + override def define(context: Plugin.Context) = { + context.addExtensions( + classOf[Scala], + classOf[ScalaSensor], + classOf[ScalastyleRepository], + classOf[ScalastyleQualityProfile], + classOf[ScalastyleSensor], + classOf[ScalaMetrics], + classOf[ScoverageSensor], + classOf[ScoverageWidget] ) - - override val toString = getClass.getSimpleName - + } } diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala index 4e48190..8534ce4 100644 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala @@ -21,7 +21,8 @@ package com.ncredinburgh.sonar.scalastyle import java.io.File import java.nio.charset.StandardCharsets -import org.mockito.Mockito._ +import org.mockito.Mockito +import org.mockito.ArgumentMatchers._ import org.scalastyle._ import org.scalastyle.StyleError import org.scalatest.mock.MockitoSugar @@ -40,8 +41,9 @@ class ScalastyleRunnerSpec extends FlatSpec with Matchers with MockitoSugar with val checker1 = ConfigurationChecker("org.scalastyle.scalariform.MultipleStringLiteralsChecker", ErrorLevel, true, Map(), None, None) val checker2 = ConfigurationChecker("org.scalastyle.file.HeaderMatchesChecker", ErrorLevel, true, Map("header" -> "// Expected Header Comment"), None, None) val configuration = ScalastyleConfiguration("sonar", true, List(checker1, checker2)) - val testeeSpy = spy(new ScalastyleRunner(mock[RulesProfile])) - doReturn(configuration).when(testeeSpy).config + val testeeSpy = Mockito.spy(new ScalastyleRunner(mock[RulesProfile])) + //Mockito.doReturn(configuration).when(testeeSpy).config + Mockito.when(testeeSpy.config).thenReturn(configuration) val charset = StandardCharsets.UTF_8.name } diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala index e49927e..683e754 100755 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala @@ -21,7 +21,7 @@ package com.ncredinburgh.sonar.scalastyle import java.io.File import java.nio.charset.StandardCharsets -import org.mockito.Matchers._ +import org.mockito.ArgumentMatchers._ import org.mockito.Mockito._ import org.scalastyle._ import org.scalastyle.file.FileLengthChecker diff --git a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala index 3781a7f..8c9f8b4 100644 --- a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala @@ -1,34 +1,22 @@ package com.sagacify.sonar.scala; -import org.scalatest._ -import org.mockito.Matchers.any; -import org.mockito.Matchers.eq; -import org.mockito.Mockito.mock; -import org.mockito.Mockito.times; -import org.mockito.Mockito.verify; -import org.mockito.Mockito.verifyNoMoreInteractions; - -import java.io.IOException; import java.nio.file.Paths -import scala.collection.JavaConversions._ -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.batch.fs.internal.DefaultFileSystem; -import org.sonar.api.config.Settings; +import org.mockito.Mockito.{mock, times, verify} +import org.scalatest._ +import org.sonar.api.batch.SensorContext +import org.sonar.api.batch.fs.internal.{DefaultFileSystem, TestInputFileBuilder} +import org.sonar.api.config.internal.MapSettings import org.sonar.api.measures.{CoreMetrics => CM} -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Project; +import org.sonar.api.resources.Project -import org.sonar.api.batch.fs.internal.DefaultInputFile; +import scala.collection.JavaConversions._; class ScalaSensorSpec extends FlatSpec with Matchers { val NUMBER_OF_FILES = 3; - val scala = new Scala(new Settings()) + val scala = new Scala(new MapSettings().asConfig()) def context = new { val fs = new DefaultFileSystem(Paths.get("./src/test/resources")) @@ -42,52 +30,50 @@ class ScalaSensorSpec extends FlatSpec with Matchers { "A ScalaSensor" should "execute on a scala project" in { val c = context - c.fs.add(new DefaultInputFile("p", "fake.scala").setLanguage("scala")); + // use TestInputFileBuilder here? + //c.fs.add(new DefaultInputFile("p", "fake.scala").setLanguage("scala")); + c.fs.add(TestInputFileBuilder.create("p", "fake.scala").setLanguage("scala").build()) assert(c.sensor.shouldExecuteOnProject(c.project)) } it should "only execute on a scala project" in { val c = context - c.fs.add(new DefaultInputFile("p", "fake.php").setLanguage("php")); + c.fs.add(TestInputFileBuilder.create("p", "fake.php").setLanguage("php").build()) assert(! c.sensor.shouldExecuteOnProject(c.project)) } it should "correctly measure ScalaFile1" in { val c = context - c.fs.add( - new DefaultInputFile("p", "ScalaFile1.scala").setLanguage("scala")); + c.fs.add(TestInputFileBuilder.create("p", "ScalaFile1.scala").setLanguage("scala").build()) val sensorContext = mock(classOf[SensorContext]) c.sensor.analyse(c.project, sensorContext) - val inputFiles = c.fs.inputFiles( - c.fs.predicates().hasLanguage(scala.getKey())) + val inputFiles = c.fs.inputFiles(c.fs.predicates().hasLanguage(scala.getKey())) - inputFiles.foreach{ file => - verify(sensorContext, times(1)) - .saveMeasure(file, CM.FILES, 1) - verify(sensorContext, times(1)) - .saveMeasure(file, CM.COMMENT_LINES, 0) + // use SensorContextTester here - } +// inputFiles.foreach{ file => +// verify(sensorContext, times(1)) +// .saveMeasure(file, CM.FILES, 1) +// verify(sensorContext, times(1)) +// .saveMeasure(file, CM.COMMENT_LINES, 0) +// } } it should "correctly measure ScalaFile2" in { val c = context - c.fs.add( - new DefaultInputFile("p", "ScalaFile2.scala").setLanguage("scala")); + c.fs.add(TestInputFileBuilder.create("p", "ScalaFile2.scala").setLanguage("scala").build()) val sensorContext = mock(classOf[SensorContext]) c.sensor.analyse(c.project, sensorContext) - val inputFiles = c.fs.inputFiles( - c.fs.predicates().hasLanguage(scala.getKey())) - - inputFiles.foreach{ file => - verify(sensorContext, times(1)) - .saveMeasure(file, CM.FILES, 1) - verify(sensorContext, times(1)) - .saveMeasure(file, CM.COMMENT_LINES, 1) + val inputFiles = c.fs.inputFiles(c.fs.predicates().hasLanguage(scala.getKey())) - } +// inputFiles.foreach{ file => +// verify(sensorContext, times(1)) +// .saveMeasure(file, CM.FILES, 1) +// verify(sensorContext, times(1)) +// .saveMeasure(file, CM.COMMENT_LINES, 1) +// } } } diff --git a/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala b/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala index 12960cc..8ad4b76 100755 --- a/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala @@ -30,23 +30,25 @@ class ScalastylePluginSpec extends FlatSpec with Matchers { val testee = new ScalaPlugin - "a scala plugin" should "provide a scala sensor" in { - assert(testee.getExtensions.contains(classOf[ScalaSensor])) - } - - it should "provide a scalastyle sensor" in { - assert(testee.getExtensions.contains(classOf[ScalastyleSensor])) - } - - it should "provide a scalastyle repository" in { - assert(testee.getExtensions.contains(classOf[ScalastyleRepository])) - } - - it should "provide a scala language" in { - assert(testee.getExtensions.contains(classOf[Scala])) - } - - it should "provide a scalastyle quality profile" in { - assert(testee.getExtensions.contains(classOf[ScalastyleQualityProfile])) - } + // TODO provide a context and check that after calling define() + +// "a scala plugin" should "provide a scala sensor" in { +// assert(testee.getExtensions.contains(classOf[ScalaSensor])) +// } +// +// it should "provide a scalastyle sensor" in { +// assert(testee.getExtensions.contains(classOf[ScalastyleSensor])) +// } +// +// it should "provide a scalastyle repository" in { +// assert(testee.getExtensions.contains(classOf[ScalastyleRepository])) +// } +// +// it should "provide a scala language" in { +// assert(testee.getExtensions.contains(classOf[Scala])) +// } +// +// it should "provide a scalastyle quality profile" in { +// assert(testee.getExtensions.contains(classOf[ScalastyleQualityProfile])) +// } } From ff7cb2835dabec7f6f5f8bb092abf5c67f21693e Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Thu, 4 Jan 2018 18:04:55 -0800 Subject: [PATCH 08/17] chore(tests): test updates --- .../sonar/scalastyle/ScalastyleRunner.scala | 4 ++-- .../com/sagacify/sonar/scala/ScalaPlugin.scala | 13 ------------- .../com/sagacify/sonar/scala/ScalaSensor.scala | 10 ++++------ .../ScalastyleDefaultQualityProfileSpec.scala | 2 +- .../sonar/scalastyle/ScalastyleRepositorySpec.scala | 4 ++-- .../sonar/scalastyle/ScalastyleResourcesSpec.scala | 2 +- .../sagacify/sonar/scala/BaseMetricSensorSpec.scala | 4 ++-- .../com/sagacify/sonar/scala/MeasuresSpec.scala | 7 ------- .../com/sagacify/sonar/scala/ScalaPluginSpec.scala | 4 ---- 9 files changed, 12 insertions(+), 38 deletions(-) diff --git a/src/main/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunner.scala b/src/main/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunner.scala index df5bd20..2b1e5c6 100755 --- a/src/main/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunner.scala +++ b/src/main/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunner.scala @@ -48,10 +48,10 @@ class ScalastyleRunner(rp: RulesProfile) { val messages = new ScalastyleChecker[FileSpec]().checkFiles(config, fileSpecs) // only errors and exceptions are of interest - messages.collect { _ match { + messages.collect { case e: StyleError[_] => e case ex: StyleException[_] => ex - }} + } } diff --git a/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala b/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala index c9b8634..685559a 100644 --- a/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala +++ b/src/main/scala/com/sagacify/sonar/scala/ScalaPlugin.scala @@ -31,19 +31,6 @@ object Scala { */ class ScalaPlugin extends Plugin { -// override def getExtensions: java.util.List[Class[_]] = -// ListBuffer[Class[_]] ( -// classOf[Scala], -// classOf[ScalaSensor], -// classOf[ScalastyleRepository], -// classOf[ScalastyleQualityProfile], -// classOf[ScalastyleSensor], -// classOf[ScalaMetrics], -// classOf[ScoverageSensor], -// classOf[ScoverageWidget] -// ) -// -// override val toString = getClass.getSimpleName override def define(context: Plugin.Context) = { context.addExtensions( classOf[Scala], diff --git a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala index 9e490c5..593c8c8 100644 --- a/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala +++ b/src/main/scala/com/sagacify/sonar/scala/ScalaSensor.scala @@ -1,7 +1,5 @@ package com.sagacify.sonar.scala -import org.sonar.plugins.scala.Scala - import scala.io.Source import scala.collection.JavaConversions._ @@ -31,10 +29,10 @@ class ScalaSensor(scala: Scala, fs: FileSystem) extends Sensor { val sourceCode = Source.fromFile(inputFile.file, charset).mkString val tokens = Scala.tokenize(sourceCode, version) - context.saveMeasure(inputFile, CM.COMMENT_LINES, Measures.count_comment_lines(tokens)) - context.saveMeasure(inputFile, CM.NCLOC, Measures.count_ncloc(tokens)) - context.saveMeasure(inputFile, CM.CLASSES, Measures.count_classes(tokens)) - context.saveMeasure(inputFile, CM.FUNCTIONS, Measures.count_methods(tokens)) + context.saveMeasure(inputFile, CM.COMMENT_LINES, double2Double(Measures.count_comment_lines(tokens))) + context.saveMeasure(inputFile, CM.NCLOC, double2Double(Measures.count_ncloc(tokens))) + context.saveMeasure(inputFile, CM.CLASSES, double2Double(Measures.count_classes(tokens))) + context.saveMeasure(inputFile, CM.FUNCTIONS, double2Double(Measures.count_methods(tokens))) // context.saveMeasure(inputFile, CM.ACCESSORS, accessors) // context.saveMeasure(inputFile, CM.COMPLEXITY_IN_FUNCTIONS, complexityInMethods) diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleDefaultQualityProfileSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleDefaultQualityProfileSpec.scala index c61a253..b244784 100644 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleDefaultQualityProfileSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleDefaultQualityProfileSpec.scala @@ -35,7 +35,7 @@ class ScalastyleDefaultQualityProfileSpec extends FlatSpec with Matchers with Mo val testee = new ScalastyleQualityProfile(TestRuleFinder) } - val rulesCount = 19 // rules without templates + val rulesCount = 18 // rules without templates "a scalastyle quality profile" should "create a default profile" in new Fixture { val rulesProfile = testee.createProfile(validationMessages) diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRepositorySpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRepositorySpec.scala index db5c63b..190dd61 100644 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRepositorySpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRepositorySpec.scala @@ -51,8 +51,8 @@ class ScalastyleRepositorySpec extends FlatSpec with Matchers with Inspectors wi } } - it should "consist of 63 rules" in { - rules.size() shouldEqual 63 + it should "consist of 69 rules" in { + rules.size() shouldEqual 69 } it should "set default severity to major" in { diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleResourcesSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleResourcesSpec.scala index fabeea5..084ba85 100644 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleResourcesSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleResourcesSpec.scala @@ -53,7 +53,7 @@ class ScalastyleResourcesSpec extends FlatSpec with Matchers with Inspectors wi } it should "return all defined checkers" in { - ScalastyleResources.allDefinedRules.size shouldEqual 63 + ScalastyleResources.allDefinedRules.size shouldEqual 69 } it should "give rules a description" in { diff --git a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala index 69b8ad2..d5bcd7b 100644 --- a/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/BaseMetricSensorSpec.scala @@ -44,7 +44,7 @@ class ScalaSensorSpec extends FlatSpec with Matchers { it should "correctly measure ScalaFile1" in { val c = context - c.fs.add(TestInputFileBuilder.create("p", "ScalaFile1.scala").setLanguage("scala").build()) + c.fs.add(TestInputFileBuilder.create("", "src/test/resources/ScalaFile1.scala").setLanguage("scala").build()) val sensorContext = mock(classOf[SensorContext]) c.sensor.analyse(c.project, sensorContext) @@ -66,7 +66,7 @@ class ScalaSensorSpec extends FlatSpec with Matchers { it should "correctly measure ScalaFile2" in { val c = context - c.fs.add(TestInputFileBuilder.create("p", "ScalaFile2.scala").setLanguage("scala").build()) + c.fs.add(TestInputFileBuilder.create("", "src/test/resources/ScalaFile2.scala").setLanguage("scala").build()) val sensorContext = mock(classOf[SensorContext]) c.sensor.analyse(c.project, sensorContext) diff --git a/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala b/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala index f4a0a62..7f6bd92 100644 --- a/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/MeasuresSpec.scala @@ -1,13 +1,6 @@ package com.sagacify.sonar.scala -import org.sonar.plugins.scala.Scala import org.scalatest._ -// import scalariform.lexer.ScalaLexer -// import scalariform.lexer.Token -// import scalariform.lexer.Tokens.LINE_COMMENT -// import scalariform.lexer.Tokens.MULTILINE_COMMENT -// import scalariform.lexer.Tokens.XML_COMMENT -// import scala.annotation.tailrec class MeasurersSpec extends FlatSpec with Matchers { diff --git a/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala b/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala index 8e0251a..5615f3d 100755 --- a/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala +++ b/src/test/scala/com/sagacify/sonar/scala/ScalaPluginSpec.scala @@ -18,10 +18,6 @@ */ package com.sagacify.sonar.scala -import org.sonar.plugins.scala.Scala -import com.ncredinburgh.sonar.scalastyle.ScalastyleSensor -import com.ncredinburgh.sonar.scalastyle.ScalastyleRepository -import com.ncredinburgh.sonar.scalastyle.ScalastyleQualityProfile import org.scalatest.{FlatSpec, Matchers} /** From 7f0b09fd8e64f548dbcfc5df6d2e48f5721bd030 Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Fri, 5 Jan 2018 09:55:40 -0800 Subject: [PATCH 09/17] chore(tests): functional with the latest sonar --- .../scalastyle/ScalastyleAdaptedQualityProfileSpec.scala | 4 ++-- .../sonar/scalastyle/ScalastyleRunnerSpec.scala | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleAdaptedQualityProfileSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleAdaptedQualityProfileSpec.scala index 219293d..bb33065 100644 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleAdaptedQualityProfileSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleAdaptedQualityProfileSpec.scala @@ -35,8 +35,8 @@ class ScalastyleQualityProfileSpec extends FlatSpec with Matchers with MockitoSu val testee = new ScalastyleQualityProfile(TestRuleFinderWithTemplates) } - val rulesCount = 38 - val parametersCount = 21 + val rulesCount = 42 + val parametersCount = 30 "a scalastyle quality profile" should "create a default profile" in new Fixture { val rulesProfile = testee.createProfile(validationMessages) diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala index 8534ce4..360a669 100644 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala @@ -22,10 +22,8 @@ import java.io.File import java.nio.charset.StandardCharsets import org.mockito.Mockito -import org.mockito.ArgumentMatchers._ import org.scalastyle._ -import org.scalastyle.StyleError -import org.scalatest.mock.MockitoSugar +import org.scalatest.mockito.MockitoSugar import org.scalatest.{FlatSpec, Matchers, PrivateMethodTester} import org.sonar.api.profiles.RulesProfile import org.sonar.api.rules.{Rule, RulePriority} @@ -42,8 +40,8 @@ class ScalastyleRunnerSpec extends FlatSpec with Matchers with MockitoSugar with val checker2 = ConfigurationChecker("org.scalastyle.file.HeaderMatchesChecker", ErrorLevel, true, Map("header" -> "// Expected Header Comment"), None, None) val configuration = ScalastyleConfiguration("sonar", true, List(checker1, checker2)) val testeeSpy = Mockito.spy(new ScalastyleRunner(mock[RulesProfile])) - //Mockito.doReturn(configuration).when(testeeSpy).config - Mockito.when(testeeSpy.config).thenReturn(configuration) + //Mockito.doReturn(configuration).when[ScalastyleRunner](testeeSpy).config + Mockito.when[ScalastyleConfiguration](testeeSpy.config).thenReturn(configuration) val charset = StandardCharsets.UTF_8.name } From 9ca80e4b19c5c60015558b3036099160817589bf Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Fri, 5 Jan 2018 11:06:39 -0800 Subject: [PATCH 10/17] chore(dependances): fixed license check issues --- pom.xml | 6 +++++- src/main/java/org/sonar/plugins/scala/Scala.java | 7 +++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index cc5e097..1e5de62 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ - GNU LGPL 3 + GNU LGPL v3 http://www.gnu.org/licenses/lgpl.txt repo @@ -51,6 +51,10 @@ + SonarQube Scala + 2009-2018 + SonarSource SA + mailto:info AT sonarsource DOT com 6.5 scala Scala diff --git a/src/main/java/org/sonar/plugins/scala/Scala.java b/src/main/java/org/sonar/plugins/scala/Scala.java index 93b62b5..30c28db 100644 --- a/src/main/java/org/sonar/plugins/scala/Scala.java +++ b/src/main/java/org/sonar/plugins/scala/Scala.java @@ -1,7 +1,7 @@ /* - * Sonar Scala Plugin - * Copyright (C) 2016-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com + * SonarQube Scala + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,7 +32,6 @@ /** * This language cover JavaServer Pages (Scala). - * */ public class Scala extends AbstractLanguage { From 069daffb1dbb677bef71b38b3c7f90cfde64b0a8 Mon Sep 17 00:00:00 2001 From: Spencer Wood Date: Fri, 5 Jan 2018 12:24:41 -0800 Subject: [PATCH 11/17] chore(tests): ScalaStyleSensorSpec passes --- pom.xml | 5 +++++ .../ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index 1e5de62..39ca35e 100644 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,11 @@ ${sonar.version} test + + com.google.guava + guava + 18.0 + org.scalastyle diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala index 683e754..ca0ec8e 100755 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleSensorSpec.scala @@ -69,6 +69,10 @@ class ScalastyleSensorSpec extends FlatSpec with Matchers with MockitoSugar with when(predicates.hasType(InputFile.Type.MAIN)).thenReturn(hasTypePred) when(predicates.hasLanguage(Constants.ScalaKey)).thenReturn(langPred) when(predicates.and(hasTypePred, langPred)).thenReturn(scalaFilesPred) + scalaFiles.foreach { sf => + when(predicates.hasPath(sf.getName)).thenReturn(scalaFilesPred) + } + when(fs.inputFile(scalaFilesPred)).thenReturn(mock[InputFile]) when(fs.files(scalaFilesPred)).thenReturn(scalaFiles) } } From b152bbee94e543681648028f4c075e7e3bcade78 Mon Sep 17 00:00:00 2001 From: Spencer Wood Date: Fri, 5 Jan 2018 13:55:15 -0800 Subject: [PATCH 12/17] chore(style): Using preferred mock pattern --- .../ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala index 360a669..6cb7a79 100644 --- a/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala +++ b/src/test/scala/com/ncredinburgh/sonar/scalastyle/ScalastyleRunnerSpec.scala @@ -40,8 +40,7 @@ class ScalastyleRunnerSpec extends FlatSpec with Matchers with MockitoSugar with val checker2 = ConfigurationChecker("org.scalastyle.file.HeaderMatchesChecker", ErrorLevel, true, Map("header" -> "// Expected Header Comment"), None, None) val configuration = ScalastyleConfiguration("sonar", true, List(checker1, checker2)) val testeeSpy = Mockito.spy(new ScalastyleRunner(mock[RulesProfile])) - //Mockito.doReturn(configuration).when[ScalastyleRunner](testeeSpy).config - Mockito.when[ScalastyleConfiguration](testeeSpy.config).thenReturn(configuration) + Mockito.doReturn(configuration, List(): _*).when(testeeSpy).config val charset = StandardCharsets.UTF_8.name } @@ -52,7 +51,6 @@ class ScalastyleRunnerSpec extends FlatSpec with Matchers with MockitoSugar with val messages = testeeSpy.run(charset, files).map(_.toString) messages should contain ("StyleError key=header.matches args=List() lineNumber=Some(1) column=None customMessage=None") - } it should "not report StyleError messages if there are no violations" in new Fixture { From 869b2367dd1f230e0781e6f5948eb6ea63516bc7 Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Fri, 5 Jan 2018 14:51:19 -0800 Subject: [PATCH 13/17] chore(dependances): updated documentation version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dbff0ec..be3484b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Sonarqube plugin for scala analysis # Set-up -Intended for sonarqube 5.4 +Intended for sonarqube 6.5 Download the latest relase into your sonar extentions/downloads folder. Restart sonarqube either using the update center or manually. From 17089d5377af4d32062bab7cb59224f13b8db987 Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Fri, 5 Jan 2018 15:44:08 -0800 Subject: [PATCH 14/17] chore(tests): end to end testing with sonar server --- circle.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/circle.yml b/circle.yml index fee6e3a..0143fbe 100644 --- a/circle.yml +++ b/circle.yml @@ -2,13 +2,21 @@ dependencies: override: - wget https://raw.githubusercontent.com/Sagacify/ci-tools/master/run-sonar.sh + - wget https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-6.5.zip + - unzip sonarqube-6.5.zip - chmod +x run-sonar.sh - ./run-sonar.sh check - ./run-sonar.sh install - mvn dependency:resolve +compile: + post: + - mvn package + - cp target/sonar-scala-plugin-*.jar sonarqube-6.5/extensions/plugins/ + # Launch the test into the docker image test: override: + - ./sonarqube-6.5/bin/linux-x86-64/sonar.sh start - mvn scoverage:report - ./run-sonar.sh run From 05b0466dc3703e26c252439f8ceb22db76a9b66a Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Fri, 5 Jan 2018 15:54:44 -0800 Subject: [PATCH 15/17] chore(tests): adding unit test information to CI --- circle.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 0143fbe..36b37c5 100644 --- a/circle.yml +++ b/circle.yml @@ -11,7 +11,7 @@ dependencies: compile: post: - - mvn package + - mvn -DskipTests=true package - cp target/sonar-scala-plugin-*.jar sonarqube-6.5/extensions/plugins/ # Launch the test into the docker image @@ -20,3 +20,6 @@ test: - ./sonarqube-6.5/bin/linux-x86-64/sonar.sh start - mvn scoverage:report - ./run-sonar.sh run + post: + - mkdir -p $CIRCLE_TEST_REPORTS/junit/ + - find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \; \ No newline at end of file From ef564ecfac705c2e499dd6039b989932e52eebdd Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Fri, 5 Jan 2018 15:57:56 -0800 Subject: [PATCH 16/17] chore(style): fixed spacing --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 36b37c5..68fb4bb 100644 --- a/circle.yml +++ b/circle.yml @@ -20,6 +20,6 @@ test: - ./sonarqube-6.5/bin/linux-x86-64/sonar.sh start - mvn scoverage:report - ./run-sonar.sh run - post: + post: - mkdir -p $CIRCLE_TEST_REPORTS/junit/ - find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \; \ No newline at end of file From 76bd58feccd03aec6b2f80829d3f7167b18a87c9 Mon Sep 17 00:00:00 2001 From: Peter Crossley Date: Mon, 29 Jan 2018 16:15:18 -0800 Subject: [PATCH 17/17] chore(dependances): updated to scala 2.11.8 --- pom.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 39ca35e..920ddf7 100644 --- a/pom.xml +++ b/pom.xml @@ -60,8 +60,9 @@ Scala com.sagacify.sonar.scala.ScalaPlugin - 2.10.7 - 2.10 + 2.11 + ${scala.major.version}.8 +