2

编辑:这是关于使用 Maven 进行持续交付并与 Jenkins 进行协调。Maven 绝对不是为此而设计的,这个问题是我们在不使用 Maven 版本的情况下获得高效工作流程的一部分。帮助表示赞赏。


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

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

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

  • META-INF/maven/.../pom.properties(因为它包含时间戳)
  • META-INF/MANIFEST.MF(包含 JDK 和用户)
  • jar 文件中的时间戳

我首先找到了解决这两个问题的方法,但后者有点困难。似乎 AbstractZipArchiver (它在 zipFile() 和 zipDir() 中完成所有工作)不是为了允许对存档的生成方式进行任何类型的扩展。

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

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

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

我应该如何处理这个?

4

1 回答 1

0

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

你描述的问题是:

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

我在 Maven 方面的经验告诉我,如果您尝试并坚持“Maven 方式”,那么开箱即用的工具就会很好地为您工作,但如果您偏离了方向,那么您将度过一段糟糕的时光。不幸的是,Maven 方式有时难以捉摸:-)

Maven 中的多模块项目非常有用,当您的模块系列具有不同的代码时,例如您有一个包含一堆接口的模块,以及一些提供实现的兄弟模块。在一个多模块项目中拥有十几个模块是不寻常的。所有模块都应该共享父模块的版本号(Maven 不强制执行此操作,我认为这很令人困惑)。

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

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

public interface Student {
    void study();
}

在某些兄弟模块中,它们会在其 POM 中声明对域模型的编译范围依赖项,您可能有实现。

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

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

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

如果:

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

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

在您的评论中,您说:

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

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

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

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

如果您可以重建一个发布工件,您将创建两个开发人员在他们的存储库中具有不同版本的可能性,并且您将根据您使用的工作站有不同的构建。不要这样做。

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

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

总之:

  • 检查你的模块化:一个巨大的多模块项目没有用。
  • 如果您不想不断地重建快照,则需要发布。
  • 永远不要向您的客户发布快照。
    • 遵循您的装配项目的依赖关系图并发布任何快照。
    • 发布组装项目,提升您的次要版本。
    • 确保您的客户在通信中提及您的组件的完整版本号。
于 2013-10-09T14:13:59.920 回答