为了加快我们的开发工作流程,我们拆分测试并在多个代理上并行运行每个部分。然而,编译测试源似乎需要大部分时间用于测试步骤。
为了避免这种情况,我们使用 sbt 预编译测试test:compile并构建一个带有编译目标的docker镜像。
稍后,此映像在每个代理中用于运行测试。但是,即使存在已编译的类,它似乎也会重新编译测试和应用程序源。
有没有办法让 sbt 使用现有的编译目标?
更新:提供更多上下文
这个问题与 scala 和 sbt 严格相关(因此是 sbt 标签)。
我们的 CI 过程分为多个阶段。它大致是这样的。
第 1 阶段:使用 SBT 将 Scala 项目编译为 java bitcode 使用sbt compile我们在同一个测试中使用编译测试源sbt test:compile目标捆绑在 docker 映像中并推送到远程存储库,
第 2 阶段:我们使用多个代理来并行拆分和运行测试。测试从构建的 docker 镜像运行,所以环境是一样的。但是,sbt test即使存在已编译的 bitcode ,运行也会导致项目重新编译。
为了说明这一点,我基本上想在一台机器上编译并在另一台机器上运行已编译的测试源,而无需重新编译
更新
我不认为/sf/answers/2620850011/是同样的问题,因为与它不同,我不安装卷或在主机上构建。一切都在 docker 中编译和运行,但分为两个构建阶段。因此,文件修改时间和路径保持不变。
调试输出有这样的东西
Initial source changes:
removed:Set()
added: Set()
modified: Set()
Invalidated products: Set(/app/target/scala-2.12/classes/Class1.class, /app/target/scala-2.12/classes/graph/Class2.class, ...)
External API changes: API Changes: Set()
Modified binary dependencies: Set()
Initial directly invalidated classes: Set()
Sources indirectly invalidated by:
product: Set(/app/Class4.scala, /app/Class5.scala, ...)
binary dep: Set()
external source: Set()
All initially invalidated classes: Set()
All initially invalidated sources:Set(/app/Class4.scala, /app/Class5.scala, ...)
Recompiling all 304 sources: invalidated sources (266) exceeded 50.0% of all sources
Compiling 302 Scala sources and 2 Java sources to /app/target/scala-2.12/classes ...
Run Code Online (Sandbox Code Playgroud)
它没有初始源更改,但产品已失效。
更新:重现的最小项目
我创建了一个最小的 sbt 项目来重现该问题。 https://github.com/pulasthibandara/sbt-docker-recomplile
如您所见,除了在新步骤(新容器)的第二阶段运行之外,构建阶段之间没有任何变化。
虽然 /sf/answers/2620850011/指出了正确的方向,但潜在的问题和解决方案是不同的。
问题
当 SBT 在 docker 构建的不同阶段运行时,它似乎会重新编译所有内容。这是因为 docker 会压缩在每个阶段创建的图像,从而从源中去除 lastModifiedDate 的毫秒部分。
SBT 在确定源是否已更改时取决于 lastModifiedDate,并且由于其不同(毫秒部分),构建会触发完整的重新编译。
解决方案
Java 8:-Dsbt.io.jdktimestamps=true按照https://github.com/sbt/sbt/issues/4168#issuecomment-417655678 中的建议在运行 SBT 时进行设置 以解决此问题。
更新:遵循https://github.com/sbt/sbt/issues/4168#issuecomment-417658294 中的推荐
我通过SBT_OPTS在 docker 文件中设置env 变量解决了这个问题
ENV SBT_OPTS="${SBT_OPTS} -Dsbt.io.jdktimestamps=true"
Run Code Online (Sandbox Code Playgroud)
该测试项目已经更新了这个解决办法。