@@ -28,6 +28,11 @@ object ScoverageSbtPlugin extends AutoPlugin {
2828 coverageExcludedPackages := " " ,
2929 coverageExcludedFiles := " " ,
3030 coverageMinimum := 0 , // default is no minimum
31+ coverageMinimumBranchTotal := 0 ,
32+ coverageMinimumStmtPerPackage := 0 ,
33+ coverageMinimumBranchPerPackage := 0 ,
34+ coverageMinimumStmtPerFile := 0 ,
35+ coverageMinimumBranchPerFile := 0 ,
3136 coverageFailOnMinimum := false ,
3237 coverageHighlighting := true ,
3338 coverageOutputXML := true ,
@@ -122,7 +127,7 @@ object ScoverageSbtPlugin extends AutoPlugin {
122127 sourceEncoding((Compile / scalacOptions).value),
123128 log)
124129
125- checkCoverage(cov, log, coverageMinimum .value, coverageFailOnMinimum.value)
130+ checkCoverage(cov, log, coverageMinima .value, coverageFailOnMinimum.value)
126131 case None => log.warn(" No coverage data, skipping reports" )
127132 }
128133 }
@@ -148,7 +153,7 @@ object ScoverageSbtPlugin extends AutoPlugin {
148153 val cfmt = cov.statementCoverageFormatted
149154 log.info(s " Aggregation complete. Coverage was [ $cfmt] " )
150155
151- checkCoverage(cov, log, coverageMinimum .value, coverageFailOnMinimum.value)
156+ checkCoverage(cov, log, coverageMinima .value, coverageFailOnMinimum.value)
152157 case None =>
153158 log.info(" No subproject data to aggregate, skipping reports" )
154159 }
@@ -242,28 +247,51 @@ object ScoverageSbtPlugin extends AutoPlugin {
242247
243248 private def checkCoverage (coverage : Coverage ,
244249 log : Logger ,
245- min : Double ,
250+ min : CoverageMinima ,
246251 failOnMin : Boolean ): Unit = {
252+ val ok : Boolean = checkCoverage(coverage, " Total" , log, min.total) &&
253+ coverage.packages.forall(x => checkCoverage(x, s " Package: ${x.name}" , log, min.perPackage)) &&
254+ coverage.files.forall(x => checkCoverage(x, s " File: ${x.filename}" , log, min.perFile))
255+
256+ if (! ok && failOnMin)
257+ throw new RuntimeException (" Coverage minimum was not reached" )
258+
259+ log.info(s " All done. Coverage was [ ${coverage.statementCoverageFormatted}%] " )
260+ }
247261
248- val cper = coverage.statementCoveragePercent
249- val cfmt = coverage.statementCoverageFormatted
262+ private def checkCoverage (metrics : CoverageMetrics ,
263+ metric : String ,
264+ log : Logger ,
265+ min : CoverageMinimum ): Boolean = {
266+ checkCoverage(s " Branch: $metric" , log, min.branch, metrics.branchCoveragePercent) &&
267+ checkCoverage(s " Stmt: $metric" , log, min.statement, metrics.statementCoveragePercent)
268+ }
250269
270+ private def checkCoverage (metric : String ,
271+ log : Logger ,
272+ min : Double ,
273+ cper : Double ): Boolean = {
251274 // check for default minimum
252- if (min > 0 ) {
275+ if (min <= 0 ) {
276+ true
277+ } else {
253278 def is100 (d : Double ) = Math .abs(100 - d) <= 0.00001
254279
255280 if (is100(min) && is100(cper)) {
256- log.info(s " 100% Coverage ! " )
257- } else if (min > cper) {
258- log.error(s " Coverage is below minimum [ $cfmt% < $min%] " )
259- if (failOnMin)
260- throw new RuntimeException (" Coverage minimum was not reached" )
281+ log.debug(s " 100% Coverage: $metric" )
282+ true
261283 } else {
262- log.info(s " Coverage is above minimum [ $cfmt% > $min%] " )
284+ val ok : Boolean = min <= cper
285+ val minfmt = scoverage.DoubleFormat .twoFractionDigits(min)
286+ val cfmt = scoverage.DoubleFormat .twoFractionDigits(cper)
287+ if (ok) {
288+ log.debug(s " Coverage is above minimum [ $cfmt% > $minfmt%]: $metric" )
289+ } else {
290+ log.error(s " Coverage is below minimum [ $cfmt% < $minfmt%]: $metric" )
291+ }
292+ ok
263293 }
264294 }
265-
266- log.info(s " All done. Coverage was [ $cfmt%] " )
267295 }
268296
269297 private def sourceEncoding (scalacOptions : Seq [String ]): Option [String ] = {
0 commit comments