【问题标题】:SBT: How to make one task depend on another in multi-project builds, and not run in the root project?SBT:如何在多项目构建中使一项任务依赖于另一项任务,而不是在根项目中运行?
【发布时间】:2018-02-03 11:58:55
【问题描述】:

对于我的多项目构建,我正在尝试创建一个验证任务,它只会导致 scct:test 然后按顺序执行 scalastyle。我希望 scct:test 为所有子项目执行,但不是顶级项目。 (如果它为顶级项目执行,我会从 scct 得到“等待覆盖率报告超时”,因为该项目中没有源代码也没有测试。)我想做的是创建 verify 作为任务对 scct:test 和 scalastyle 的依赖。这被证明是相当巴洛克式的。这是我的顶级项目/目录中的 Build.scala:

object MyBuild extends Build {
  val verifyTask = TaskKey[Unit]("verify", "Compiles, runs tests via scct:test and then runs scalastyle")
  val scctTestTask = (test in ScctPlugin.Scct).scopedKey
  val scalastyleTask = PluginKeys.scalastyleTarget.scopedKey

  lazy val root = Project("rootProject",
                      file("."),
                      settings =  Defaults.defaultSettings ++
                                  ScalastylePlugin.Settings ++
                                  ScctPlugin.instrumentSettings ++
                                  ScctPlugin.mergeReportSettings ++
                                  Seq(
                                    verifyTask in Global := {},
                                    verifyTask <<= verifyTask.dependsOn(scctTestTask, scalastyleTask)
                                  )
              ) aggregate(lift_webapp, selenium_tests)

  lazy val subproject_1 = Project(id = "subproject_1", base = file("subproject_1"))

  lazy val subproject_2 = Project(id = "subproject_2", base = file("subproject_2"))
}

然而,验证任务似乎只存在于根项目;当我运行它时,我看不到子项目中正在运行相同的任务。这与我想要的完全相反;我想发出sbt verify 并让 scct:test 和 scalastyle 在每个子项目中运行,但不在顶级项目中。我该怎么做呢?

【问题讨论】:

    标签: scala sbt


    【解决方案1】:

    方案一:在子项目中定义verifyTask

    首先要注意的是,如果您希望某些任务(verify、test 等)在某些项目中运行,您需要将它们定义为子项目的范围。因此,在您的情况下,最直接的做法是在 subproject_1 和 subproject_2 中定义 verifyTask。

    lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.0.4"
    
    lazy val verify = taskKey[Unit]("verify")
    def verifySettings = Seq(
      skip in verify := false,
      verify := (Def.taskDyn {
        val sk = (skip in verify).value
        if (sk) Def.task { println("skipping verify...") }
        else (test in Test)
      }).value
    )
    
    lazy val root = (project in file("."))
      .aggregate(sub1, sub2)
      .settings(
        verifySettings,
        scalaVersion in ThisBuild := "2.12.4",
        skip in verify := true
      )
    
    lazy val sub1 = (project in file("sub1"))
      .settings(
        verifySettings,
        libraryDependencies += scalaTest % Test
      )
    
    lazy val sub2 = (project in file("sub2"))
      .settings(
        verifySettings,
        libraryDependencies += scalaTest % Test
      )
    

    解决方案 2:ScopeFilter

    最近有一个Reddit thread 提到了这个问题,所以我会发布我在那里所做的事情。 如果你想手动聚合一些子项目,还有一种叫做ScopeFilter的技术。

    请注意,我在这里使用的是 sbt 1.x,但它应该可以与 sbt 0.13 一起使用一些小的改动。

    lazy val packageAll = taskKey[Unit]("package all the projects")
    lazy val myTask = inputKey[Unit]("foo")
    
    lazy val root = (project in file("."))
      .aggregate(sub1, sub2)
      .settings(
        scalaVersion in ThisBuild := "2.12.4",
        packageAll := {
          (packageBin in Compile).all(nonRootsFilter).value
          ()
        },
        myTask := {
          packageAll.value
        }
      )
    
    lazy val sub1 = (project in file("sub1"))
    
    lazy val sub2 = (project in file("sub2"))
    
    def nonRootsFilter = {
      import sbt.internal.inc.ReflectUtilities
      def nonRoots: List[ProjectReference] =
        allProjects filter {
          case LocalProject(p) => p != "root"
          case _               => false
        }
      def allProjects: List[ProjectReference] =
        ReflectUtilities.allVals[Project](this).values.toList map { p =>
          p: ProjectReference
        }
      ScopeFilter(inProjects(nonRoots: _*), inAnyConfiguration)
    }
    

    在上面,myTask 依赖于packageAll,它为所有非根子项目聚合了(packageBin in Compile)。

    sbt:root> myTask
    [info] Packaging /Users/xxx/packageall/sub1/target/scala-2.12/sub1_2.12-0.1.0-SNAPSHOT.jar ...
    [info] Done packaging.
    [info] Packaging /Users/xxx/packageall/sub2/target/scala-2.12/sub2_2.12-0.1.0-SNAPSHOT.jar ...
    [info] Done packaging.
    [success] Total time: 0 s, completed Feb 2, 2018 7:23:23 PM
    

    【讨论】:

      【解决方案2】:

      我可能是错的,但您只是为当前项目定义验证任务依赖项。

      也许你可以试试:

      Seq(
         verifyTask in Global := {},
         verifyTask <<= (verifyTask in Global).dependsOn(scctTestTask, scalastyleTask)
      )
      

      或者您可以将 verifyTask 设置添加到所有模块。

      【讨论】:

      • 确实,我正在为当前项目定义任务依赖关系,但我的印象是聚合将任务向下传播到聚合项目。但是谢谢你的提示,我会试试的。关于将 verifyTask 添加到所有模块,确实如此,但这是我在本练习中试图避免的。
      • 不幸的是,这个建议似乎并没有比我最初做的更好。
      猜你喜欢
      • 2020-05-15
      • 2015-08-11
      • 1970-01-01
      • 2018-05-05
      • 1970-01-01
      • 1970-01-01
      • 2020-07-24
      • 2015-06-14
      • 2020-12-27
      相关资源
      最近更新 更多