【发布时间】:2012-12-02 01:46:00
【问题描述】:
我有一个相当普通的Scala project 目前正在使用 Maven 构建。我想同时支持 Scala 2.9.x 和即将推出的 2.10,它们不兼容二进制或源代码。如有必要,我愿意接受转换为 SBT,但我遇到了一些挑战。
我对这个项目的要求是:
单一源树(无分支)。我相信尝试为每个 Scala 版本支持多个并发“主”分支将是错过分支之间错误修复的最快方法。
版本特定的源目录。由于 Scala 版本不兼容源代码,因此我需要能够为特定版本的源代码指定辅助源目录。
版本特定的源 jar。最终用户应该能够为他们的 Scala 版本下载正确的源 jar,以及正确的版本特定源。
集成部署。我目前使用 Maven 发布插件将新版本部署到 Sonatype OSS 存储库,并希望有一个类似的简单发布工作流。
最终用户 Maven 支持。我的最终用户通常是 Maven 用户,因此准确反映依赖关系的功能性 POM 至关重要。
阴影 jar 支持。我需要能够生成一个 JAR,其中包含我的依赖项的子集并从已发布的 POM 中删除阴影依赖项。
我尝试过的事情:
-
Maven 配置文件。我创建了一组 Maven 配置文件来控制用于构建的 Scala 版本,使用 Maven build-helper 插件来选择版本特定的源代码树。在发布之前一直运行良好;
使用分类器来限定版本效果不好,因为源 jar 还需要自定义分类器('source-2.9.2' 等),并且大多数 IDE 工具不知道如何定位他们。
我尝试使用 Maven 属性将 SBT 样式的 _${scala.version} 后缀添加到工件名称,但 Maven 不喜欢工件名称中的属性。
-
SBT。一旦你可以理解它,它就会很好地工作(尽管有大量文档,但这不是一项小任务)。缺点是似乎没有与 Maven 阴影插件等效的插件。我看过:
Proguard。该插件未针对 SBT 0.12.x 进行更新,并且不会从源代码构建,因为它依赖于另一个已更改 groupIds 的 SBT 插件,并且在旧名称下没有 0.12.x 版本。我还没有弄清楚如何指示 SBT 忽略/替换插件依赖项。
一个罐子。这使用自定义类加载从嵌入式 jar 中运行 Main 类,这不是预期的结果;我希望我的项目的类文件与我的阴影依赖项中的(可能重命名的)类文件一起放在 jar 中。
SBT 程序集插件。这可以在一定程度上起作用,但 POM 文件似乎包含我试图遮蔽的依赖项,这对我的最终用户没有帮助。
我接受可能没有解决方案可以满足我对 Scala 的要求,和/或我可能需要编写自己的 Maven 或 Scala 插件来实现目标。但如果可以的话,我想找到一个现有的解决方案。
更新
我已经接近接受@Jon-Ander 的优秀answer,但我还有一个优秀的作品,那就是统一的发布流程。我的build.sbt is on GitHub 的当前状态。 (我将在稍后的答案中复制它以供后代使用)。
sbt-release 插件不支持多版本构建(即,+ release 的行为不像人们所希望的那样),这是有道理的,因为发布标记的过程并不真正需要跨版本。但我希望流程的两个部分是多版本的:测试和发布。
我希望发生的事情类似于两阶段 maven-release-plugin 过程。第一阶段将执行更新 Git 和运行测试的管理工作,在这种情况下,这意味着运行 + test 以便测试所有版本、标记、更新到快照,然后将结果推送到上游。
第二阶段将检查标记版本和+ publish,这将重新运行测试并将标记版本推送到 Sonatype 存储库。
我怀疑我可以编写releaseProcess 值来执行这些操作,但我不确定我是否可以在build.sbt 中支持多个releaseProcess 值。它可能可以与一些额外的范围一起使用,但是 SBT 的那部分对我来说仍然是奇怪的。
我目前所做的是将releaseProcess 更改为不发布。然后我必须手动检查标记的版本并在事后运行+ publish,这接近我想要的但确实妥协,特别是因为测试仅在发布过程中在当前的 scala 版本上运行。我可以接受一个不像 maven 插件那样的两阶段流程,但确实实现了多版本测试和发布。
任何可以帮助我完成最后一英里的额外反馈将不胜感激。
【问题讨论】:
-
我质疑你的前两个要点。版本特定的源目录是一种手动维护(因此容易出错)内部分支的形式。我的建议是:不要那样做,而是使用 VCS 来简化分支和合并(git 是显而易见的,但不是唯一的选择)。然后你会发现谜题的其余部分变得更容易解决。
-
我同意使用正确的 VCS 可以使分支和合并的过程更容易,但并不能消除人们忘记切换分支以测试更改的人为问题。我可以设想一个为我执行此操作的构建脚本,如有必要,我会将其视为一个选项。不过,抽象地说,我喜欢为不同的功能状态保留分支,而不是为了平台支持。
-
这是“必要的”,因为它是迄今为止最简单、最可靠的处理方式,并且只需要一点设置时间(如果您使用的是 SVN 和需要切换到 Git 或类似的东西,但仍然值得)。
-
它最初只需要一点设置,但它对开发有持续的影响。 每个更改必须首先在一个分支中实现,在那里测试,合并到另一个分支,再次测试,合并回来,回归等等。在抽象的情况下,这种方法是好的和纯粹的,但在白天 -今天的发展过程是昂贵的。我并不是说这种方法最终不会“更好”,尽管有税,但现在测试单个提交的所有变体的单命令构建具有更大的吸引力。
-
我为 shapeless 所做的方法是修复主线上的错误,然后合并回 2.9.x 分支。因为差异只是由于 Scala 版本控制,所以合并通常是微不足道的。在从分支发布之前,可以很容易地自动化测试是否已完成合并。
标签: scala maven maven-plugin sbt