Skip to content

Instantly share code, notes, and snippets.

@sptz45
Last active October 14, 2019 07:54
Show Gist options
  • Save sptz45/b6e7884360521c18c1e2695474ba9a35 to your computer and use it in GitHub Desktop.
Save sptz45/b6e7884360521c18c1e2695474ba9a35 to your computer and use it in GitHub Desktop.
// WIP based on the similar sbt plugin in Alpakka
package com.tzavellas
import scala.collection.immutable
import scala.sys.process._
import sbt._
import sbt.Keys._
object TestChanged extends AutoPlugin {
override def trigger = allRequirements
override def requires = plugins.JvmPlugin
val diffTarget = settingKey[String]("The branch to diff against")
val subprojectRoot = settingKey[String]("The root directory for sub-projects")
val onlyScala = settingKey[Boolean]("Whether only changed Scala files trigger tests")
val changedDirectories = taskKey[immutable.Set[String]]("List of touched modules in this PR branch")
val changedSubprojects = taskKey[immutable.Set[String]]("List of touched modules in this PR branch")
val testChanged = taskKey[Unit]("Test all subprojects with changes compared to master")
private val scalaFileExtensions = Seq(".java", ".scala", ".sbt", ".routes")
override lazy val buildSettings = Seq(
diffTarget := "origin/production",
subprojectRoot := "",
onlyScala := true,
changedDirectories := {
val log = streams.value.log
val target = diffTarget.value
val diffOutput = s"git diff $target --name-only".!!.split("\n")
val changedDirectories =
diffOutput
.map(_.trim)
.filter(f => !onlyScala.value || scalaFileExtensions.exists(f.endsWith))
.map(f =>
if (subprojectRoot.value.isEmpty) f.takeWhile(_ != '/')
else if (!f.startsWith(subprojectRoot.value)) f.takeWhile(_ != '/')
else subprojectRoot.value + "/" + f.replaceAll(subprojectRoot.value + "/", "").takeWhile(_ != '/'))
.map(new File(_))
.map(file => if (file.isDirectory) file.toString else ".")
.toSet
log.info("Detected changes in directories: " + changedDirectories.mkString("[", ", ", "]"))
changedDirectories
},
changedSubprojects := {
val log = streams.value.log
val transitiveClasspath = buildDependencies.value.classpathTransitive
val changedDirs = changedDirectories.value
val changedSubprojects = transitiveClasspath.filter { case (pr, deps) =>
shouldBuild(pr.project, changedDirs) ||
deps.exists(dep => shouldBuild(dep.project, changedDirs))
}.map(_._1.project).toSet
log.info("Detected changes in subprojects: " + changedSubprojects.mkString("[", ", ", "]"))
changedSubprojects
}
)
override lazy val projectSettings = Seq(
testChanged := Def.taskDyn {
val skip = Def.setting { task(()) }
if (changedSubprojects.value.contains(name.value)) test in Test
else skip
}.value
)
private def shouldBuild(projectName: String, changedDirectories: Set[String]) =
changedDirectories.exists(_.endsWith(projectName)) || // project files changed
changedDirectories.contains(".") || changedDirectories.contains("project") // sbt changed
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment