Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine multiple reports into one in case of multi module project #938

Open
varnit24 opened this issue Aug 13, 2021 · 2 comments
Open

Combine multiple reports into one in case of multi module project #938

varnit24 opened this issue Aug 13, 2021 · 2 comments
Labels
enhancement New feature or request

Comments

@varnit24
Copy link

varnit24 commented Aug 13, 2021

Summary

In case of multi-module sbt projects, if we run each module one by one it generates multiple mutation testing reports. It would be great if we can combine those reports and generate one instead

@hugo-vrijswijk hugo-vrijswijk added the enhancement New feature or request label Aug 27, 2021
@hugo-vrijswijk
Copy link
Member

Hi @varnit24! This would be a great feature to have. What do you think would be a good workflow for aggregating multiple reports? Stryker4s now writes a file in a timestamped location inside the configured base-dir. When aggregating projects, we don't know for sure where are the reports are written to, unless saved in some way or always written to the same location.

@kokorin
Copy link

kokorin commented May 3, 2022

I managed to aggregate struker4s reports in multi-module SBT project with custom SBT Plugin:

import com.fasterxml.jackson.databind.{ DeserializationFeature, ObjectMapper }
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import mutationtesting.Thresholds
import sbt.Keys.commands
import sbt.{ AutoPlugin, Command, Def }

import java.nio.file.{ Files, Paths, StandardCopyOption }

// scalastyle:off

object Aggregator {
  def aggregate(first: MutationReport, second: MutationReport): MutationReport =
    MutationReport(
      `$schema` = first.`$schema`,
      schemaVersion = first.schemaVersion,
      thresholds = first.thresholds,
      projectRoot = first.projectRoot,
      files = first.files ++ second.files,
      config = first.config
    )
}

case class MutationReport(
  `$schema`: String,
  schemaVersion: String,
  thresholds: Thresholds,
  projectRoot: String,
  files: Map[String, Object],
  config: Map[String, Object]
)

/** Adds command to aggegate Stryker reports for sub-modules
  */
object StrykerAggregatePlugin extends AutoPlugin {
  override def trigger = allRequirements

  def strykerAggregate = Command.command("strykerAggregate") { state =>
    val baseDir    = Paths.get("./target/stryker4s-report")
    val reportDirs = baseDir.toFile.listFiles().filter(f => Files.isDirectory(f.toPath))
    val reports    = reportDirs
      .map(_.toPath.resolve("report.json"))
      .filter(Files.exists(_))
      .map(_.toFile)

    val mapper = new ObjectMapper()
      .registerModule(DefaultScalaModule)
      .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

    val report = reports.map { r =>
      println(s"Reading ${r}")
      mapper.readValue(r, classOf[MutationReport])
    }
      .reduce(Aggregator.aggregate)

    reportDirs.head
      .listFiles()
      .filterNot(_.toString.endsWith("report.json"))
      .filterNot(_.toString.endsWith("report.js"))
      .foreach { src =>
        val dst = baseDir.resolve(src.getName)
        println(s"Copying $src to $dst")
        Files.copy(src.toPath, baseDir.resolve(src.getName), StandardCopyOption.REPLACE_EXISTING)
      }

    val data = mapper.writeValueAsString(report)
    Files.write(
      baseDir.resolve("report.js"),
      s"document.querySelector('mutation-test-report-app').report = $data".getBytes
    )

    state
  }

  override def projectSettings: Seq[Def.Setting[_]] = Seq(
    commands ++= Seq(strykerAggregate)
  )
}

Note: SBT plugin above requires Jackson dependency. To add it create project/build.sbt with the following content:

inThisBuild(
  Seq(
    libraryDependencies ++= Seq(
      "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.13.2",
      "io.stryker-mutator"                  %% "stryker4s-core"            % "0.13.1"
    )
  )
)

Plugin usage:

sbt clean
sbt "project module1" stryker
sbt "project module2" stryker
sbt "project ..." stryker
sbt "project moduleN" stryker
sbt strykerAggregate

Aggregated report will be created directly in target/stryker4s-report/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants