如何让 Jenkins 将 Maven -SNAPSHOT jar 工件的两个不同版本视为持续交付的一部分



>EDIT:这是关于使用 Maven 进行持续交付并与 Jenkins 进行编排。 Maven 绝对不是为此而设计的,这个问题是我们努力在不使用 Maven 版本的情况下获得高效工作流程的一部分。 感谢帮助。


我们在主要版本中使用 Maven -SNAPSHOT,以确保客户始终获得给定版本的最新代码,这运行良好。 出于技术原因,我们有两个独立的 Maven 作业 - 一个用于将源代码编译到 jar,另一个用于将适当的 jar 组合到给定的部署。 这也很好用。

然后,我们让 Jenkins 编排何时调用各个步骤,这就是它变得有点棘手的地方,因为如果我们在第一步中执行正常的mvn clean install,这意味着所有快照工件都会被重新编译,这反过来又使 Jenkins 认为所有快照都发生了变化(因为它们的指纹 - 又名 MD5 校验和 - 改变了(,即使用于生成工件的源没有改变, 触发所有下游构建,而不仅仅是依赖项确实更改的构建。

到目前为止,我已经确定这些东西在构建之间有所不同:

  • META-INF/maven/.../pom.properties(因为它包含一个时间戳(
  • 元信息/清单。MF(包含 JDK 和用户(
  • JAR 文件中的时间戳

我首先找到了解决两者的方法,但后者有点困难。 看起来 AbstractZipArchiver(它在 zipFile(( 和 zipDir(( 中完成所有工作(并没有被编写为允许对存档的生成方式进行任何类型的扩展。

现在我可以想象四种方法(但非常欢迎更多的想法(:

  • 创建当前 maven-jar-plugin 实现的衍生物,允许使用 timestamp=<number> 属性,然后将其用于插入 jar 文件的所有条目。 如果未设置,则保留当前行为。
  • 修改 Jenkins 指纹图灵方案,使其了解 jar 文件,只查看条目内容,而不是它们的元数据。
  • 将插件附加到负责touch具有特定时间戳的文件的prepare-package阶段。 这要求当时所有文件都存在(这意味着不允许 jar 插件接触 MANIFEST。MF 文件(
  • 将一个额外的插件附加到"包"阶段,该阶段重写完成的jar文件,在此过程中将所有zip条目时间戳清零。

同样,目标是使maven SNAPSHOT工件完全独立于时间,因此给定相同的源,您将获得具有相同MD5校验和的工件。 但是,我也相信这可能对发布版本有益。

我应该如何处理这个问题?

根据我的评论,我仍然认为答案是不做您建议的任何事情,而是优先使用版本而不是您实际上发布给客户的工件的快照

您描述的问题是:

  • 你有一个多模块项目,需要很长时间才能构建,因为你有超过 100 个模块,
  • 有两个快照工件,您认为它们应该是相同的(因为源代码和元数据在构建时是相同的(,但它们具有不同的校验和。
我在Maven

上的经验告诉我,如果你尝试并坚持"Maven Way",工具开箱即用,但如果你偏离了,那么你就会过得很糟糕。 不幸的是,Maven Way有时难以捉摸:-(

Maven 中的多模块项目非常有用,当您拥有一系列模块,其代码各不相同时,例如,您有一个包含一堆接口的模块,以及一些提供实现的同级模块。 在一个多模块项目中有十几个模块是不寻常的。 所有模块都应该共享父模块的版本号(Maven 不强制执行这一点,在我看来这令人困惑(。

生成多模块项目的快照版本时,将生成所有模块的快照,即使特定模块中的代码未更改也是如此。 因此,您可以查看存储库中的一系列模块,并知道在编译时满足了模块间代码引用。

例如,在域模型模块中,您可能有一个接口:

public interface Student {
    void study();
}

在某些同级模块中,这些模块将在其 POM 中声明对域模型的编译范围的依赖项,您可能具有实现。

如果要更改域模型模块中的接口:

public interface Student {
    void study();
    void drink(Beer beer);
}

并重新构建多模块项目,构建将失败。 依赖模块将无法构建,即使它们的代码和 POM 保持不变。 在多模块项目中,只有在所有子模块都成功构建时才安装或部署工件,因此重建快照通常是非常可取的 - 它告诉您有关模块间依赖关系的一些信息。

如果:

  • 您的模块数量过多,和/或
  • 这些模块不能合理地共享相同的版本号,和/或
  • 你不需要任何关于模块之间代码引用的保证,

那么你的模块化是不正确的。 不要使用多模块项目作为构建系统(你有 Jenkins(,而是使用它来表达代码模块之间的关系。

在您的评论中,您说:

RELEASE 工件在由 Jenkins 重建时的行为方式相同。

发布工件的要点是你不要重建它们 - 它们是确定的!如果你使用像Artifactory这样的东西,你会发现你不能多次部署发布工件 - 如果你尝试这样做,你的Jenkins作业应该会失败。

这是Maven的基本原则。 Maven的目标之一是,如果两个开发人员在不同的工作站上尝试相同的版本,他们将构建功能相同的工件。 如果您正在构建一个表示对另一个工件的依赖关系(可能出于编译目的,或者因为它被组装到 .war 等(的工件,那么:

  • 如果依赖项是快照,Maven 可能会从存储库中查找较新版本。
  • 如果依赖项是发行版,则假定本地存储库中的版本是确定的。

如果可以重新生成发布工件,则可能会有两个开发人员在其存储库中具有不同的版本,并且根据您使用的工作站,您将具有不同的版本。 别这样。

另一个关键细节是发布工件不能依赖于快照工件,同样,您将失去各种保证。

版本是确定的,听起来您希望程序集依赖于确定的工件。 Jenkins 使标记和发布多模块项目变得非常简单。

总结:

  • 检查您的模块化:一个巨大的多模块项目是没有用的。
  • 如果您不想不断重建快照,则需要进行发布。
  • 切勿向客户发布快照。
    • 遵循程序集项目的依赖项关系图并发布任何快照。
    • 发布程序集项目,增加次要版本。
    • 确保您的客户在通信中参考程序集的完整版本号。

最新更新