Skip to content

Commit

Permalink
Merge remote-tracking branch 'RadoBuransky/sonar-scoverage-plugin/mas…
Browse files Browse the repository at this point in the history
…ter' into staging
  • Loading branch information
Augustin Borsu committed May 1, 2016
2 parents ab1f41c + 20af12d commit d22b995
Show file tree
Hide file tree
Showing 56 changed files with 3,178 additions and 2 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ Restart sonarqube either using the update center or manually.

The rules in scalastyle are almost all deactivated. They must be activated and either make scala rules inherit scalastyle rules or change the project's rules.

For more information about either scalastyle rules or scoverage results please consult their upstream documentation first:

* [NCR-CoDE/sonar-scalastyle](https://github.com/NCR-CoDE/sonar-scalastyle)
* [RadoBuransky/sonar-scoverage-plugin](https://github.com/RadoBuransky/sonar-scoverage-plugin)

# Build from source
```mvn package```

Expand All @@ -19,7 +24,7 @@ sonar-runner -D sonar.projectKey=Sagacify:sonar-scala
```

# Contributing
Any contribution in the form of a pull request or a signed patch will be accepted.
Contributions wre accepted in the form of a pull request or a signed patch.
Please follow the semantic changelog to format your commits [cfr]((https://github.com/Sagacify/komitet-gita-bezopasnosti).
All changes are submitted to automated tests that must pass for the pull-request to be merged.

Expand Down Expand Up @@ -47,5 +52,7 @@ Here is a list of the main ones.

[NCR-CoDE/sonar-scalastyle](https://github.com/NCR-CoDE/sonar-scalastyle)

[RadoBuransky/sonar-scoverage-plugin](https://github.com/RadoBuransky/sonar-scoverage-plugin)

# Integration
Sonar-scala integrates the latest code from the [Sonar Scalastyle Plugin](https://github.com/NCR-CoDE/sonar-scalastyle) directly. All thise files must keep their original license. Also their history was pulled along with them. Any further change upstream should be incorporated using cherry-picks or merges.
For ease of use, Sonar Scala directly integrates the latest code from the [Sonar Scalastyle Plugin](https://github.com/NCR-CoDE/sonar-scalastyle) and [Sonar Scoverage Plugin](https://github.com/RadoBuransky/sonar-scoverage-plugin). This is possible as all three projects are released under the LGPL3 license. Nevertheless, all merged files are to keep their original copyright, classpath, and commit history. Any further change upstream should be incorporated using cherry-picks or merges.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<% measure=measure('scoverage')
if measure
%>
<div class="dashbox">
<h3>
Statement coverage : <%= format_measure(measure, :suffix => ' %') %>
<%= dashboard_configuration.selected_period? ? format_variation(measure) : trend_icon(measure) -%>
</h3>
</div>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.buransky.plugins.scoverage

import com.buransky.plugins.scoverage.language.Scala
import org.sonar.api.resources.Languages
import org.sonar.api.{Extension, ExtensionProvider, ServerExtension}

import scala.collection.JavaConversions._
import scala.collection.mutable.ListBuffer

class ScoverageExtensionProvider(languages: Languages) extends ExtensionProvider with ServerExtension {
override def provide(): java.util.List[Class[_ <: Extension]] = {
val result = ListBuffer[Class[_ <: Extension]]()

if (languages.get(Scala.key) == null) {
// Fix issue with multiple Scala plugins:
// https://github.com/RadoBuransky/sonar-scoverage-plugin/issues/31
result += classOf[Scala]
}

result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Sonar Scoverage Plugin
* Copyright (C) 2013 Rado Buransky
* [email protected]
*
* 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 02
*/
package com.buransky.plugins.scoverage

import com.buransky.plugins.scoverage.measure.ScalaMetrics
import com.buransky.plugins.scoverage.sensor.ScoverageSensor
import com.buransky.plugins.scoverage.widget.ScoverageWidget
import org.sonar.api.{Extension, SonarPlugin}

import scala.collection.JavaConversions._
import scala.collection.mutable.ListBuffer

/**
* Plugin entry point.
*
* @author Rado Buransky
*/
class ScoveragePlugin extends SonarPlugin {
override def getExtensions: java.util.List[Class[_ <: Extension]] =
ListBuffer(
classOf[ScoverageExtensionProvider],
classOf[ScalaMetrics],
classOf[ScoverageSensor],
classOf[ScoverageWidget]
)

override val toString = getClass.getSimpleName
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Sonar Scoverage Plugin
* Copyright (C) 2013 Rado Buransky
* [email protected]
*
* 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 02
*/
package com.buransky.plugins.scoverage

import com.buransky.plugins.scoverage.pathcleaner.PathSanitizer

/**
* Interface for Scoverage report parser.
*
* @author Rado Buransky
*/
trait ScoverageReportParser {
def parse(reportFilePath: String, pathSanitizer: PathSanitizer): ProjectStatementCoverage
}

/**
* Common Scoverage exception.
*
* @author Rado Buransky
*/
case class ScoverageException(message: String, source: Throwable = null)
extends Exception(message, source)
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Sonar Scoverage Plugin
* Copyright (C) 2013 Rado Buransky
* [email protected]
*
* 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 02
*/
package com.buransky.plugins.scoverage

/**
* Statement coverage represents rate at which are statements of a certain source code unit
* being covered by tests.
*
* @author Rado Buransky
*/
sealed trait StatementCoverage {
/**
* Percentage rate ranging from 0 up to 100%.
*/
lazy val rate: Double =
if (statementCount == 0)
0.0
else
(coveredStatementsCount.toDouble / statementCount.toDouble) * 100.0

/**
* Total number of all statements within the source code unit,
*/
def statementCount: Int

/**
* Number of statements covered by unit tests.
*/
def coveredStatementsCount: Int

require(statementCount >= 0, "Statements count cannot be negative! [" + statementCount + "]")
require(coveredStatementsCount >= 0, "Statements count cannot be negative! [" +
coveredStatementsCount + "]")
require(coveredStatementsCount <= statementCount,
"Number of covered statements cannot be more than total number of statements! [" +
statementCount + ", " + coveredStatementsCount + "]")
}

/**
* Allows to build tree structure from state coverage values.
*/
trait NodeStatementCoverage extends StatementCoverage {
def name: String
def children: Iterable[NodeStatementCoverage]
def statementSum: Int = children.map(_.statementSum).sum
def coveredStatementsSum: Int = children.map(_.coveredStatementsSum).sum
}

/**
* Root node. In multi-module projects it can contain other ProjectStatementCoverage
* elements as children.
*/
case class ProjectStatementCoverage(name: String, children: Iterable[NodeStatementCoverage])
extends NodeStatementCoverage {
// projects' coverage values are defined as sums of their child values
val statementCount = statementSum
val coveredStatementsCount = coveredStatementsSum
}

/**
* Physical directory in file system.
*/
case class DirectoryStatementCoverage(name: String, children: Iterable[NodeStatementCoverage])
extends NodeStatementCoverage {
// directories' coverage values are defined as sums of their DIRECT child values
val statementCount = children.filter(_.isInstanceOf[FileStatementCoverage]).map(_.statementCount).sum
val coveredStatementsCount = children.filter(_.isInstanceOf[FileStatementCoverage]).map(_.coveredStatementsCount).sum
}

/**
* Scala source code file.
*/
case class FileStatementCoverage(name: String, statementCount: Int, coveredStatementsCount: Int,
statements: Iterable[CoveredStatement]) extends NodeStatementCoverage {
// leaf implementation sums==values
val children = List.empty[NodeStatementCoverage]
override val statementSum = statementCount
override val coveredStatementsSum = coveredStatementsCount
}

/**
* Position a Scala source code file.
*/
case class StatementPosition(line: Int, pos: Int)

/**
* Coverage information about the Scala statement.
*
* @param start Starting position of the statement.
* @param end Ending position of the statement.
* @param hitCount How many times has the statement been hit by unit tests. Zero means
* that the statement is not covered.
*/
case class CoveredStatement(start: StatementPosition, end: StatementPosition, hitCount: Int)

/**
* Aggregated statement coverage for a given source code line.
*/
case class CoveredLine(line: Int, hitCount: Int)

object StatementCoverage {
/**
* Utility method to transform statement coverage to line coverage. Pessimistic logic is used
* meaning that line hit count is minimum of hit counts of all statements on the given line.
*
* Example: If a line contains two statements, one is covered by 3 hits, the other one is
* without any hits, then the whole line is treated as uncovered.
*
* @param statements Statement coverage.
* @return Line coverage.
*/
def statementCoverageToLineCoverage(statements: Iterable[CoveredStatement]): Iterable[CoveredLine] = {
// Handle statements that end on a different line than start
val multilineStatements = statements.filter { s => s.start.line != s.end.line }
val extraStatements = multilineStatements.flatMap { s =>
for (i <- (s.start.line + 1) to s.end.line)
yield CoveredStatement(StatementPosition(i, 0), StatementPosition(i, 0), s.hitCount)
}

// Group statements by starting line
val lineStatements = (statements ++ extraStatements).groupBy(_.start.line)

// Pessimistic approach: line hit count is a minimum of hit counts of all statements on the line
lineStatements.map { lineStatement =>
CoveredLine(lineStatement._1, lineStatement._2.map(_.hitCount).min)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Sonar Scoverage Plugin
* Copyright (C) 2013 Rado Buransky
* [email protected]
*
* 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 02
*/
package com.buransky.plugins.scoverage.language

import org.sonar.api.resources.AbstractLanguage

/**
* Scala language.
*
* @author Rado Buransky
*/
class Scala extends AbstractLanguage(Scala.key, Scala.name) {
val getFileSuffixes = Array(Scala.fileExtension)
}

object Scala {
val key = "scala"
val name = "Scala"
val fileExtension = "scala"
}
Loading

0 comments on commit d22b995

Please sign in to comment.