【问题标题】:What is the Maven way for automatic project versions when doing continuous delivery?进行持续交付时,自动项目版本的 Maven 方式是什么?
【发布时间】:2013-08-29 15:36:14
【问题描述】:

我有一个 Web 应用程序,只要功能准备就绪,我们就会将其部署到生产环境中,有时可能是一天几次,有时可能是发布之间的几周。

目前,我们不会为我们的项目增加版本号,并且所有内容都在版本0.0.1-SNAPSHOT 上运行了一年多。 我想知道为 Web 应用程序进行持续交付的 Maven 方式是什么。在每次提交时提高版本号似乎有点过头了,而且永远不会像我们现在所做的那样提高版本号,这似乎也是错误的。

对于这种类型的 Maven 使用,推荐的最佳做法是什么?

问题其实有两个方面:

  • 在单个 pom.xml 文件中推进项目版本号(可以有很多)。
  • 更新所有依赖组件中的版本号以使用彼此的最新版本。

【问题讨论】:

    标签: java maven continuous-integration maven-3 continuous-delivery


    【解决方案1】:

    我推荐以下演示文稿,讨论使用 Maven 进行持续交付的实际情况:

    关键点是每个构建都是一个潜在的版本,所以不要使用快照。

    【讨论】:

    • 我将此标记为正确答案,因为 You Tube 视频在准确回答这个问题方面表现出色。但是,我确实不得不暂停并倒带几次才能获得一些更好的分数。我已经在自己的回答中总结了视频中推荐的流程。
    • 视频非常好,可以帮助您加载。 @ 23m35s 在视频中,我会指出 Maven 应该进行大部分短期运行的健全性验证,例如单元测试、覆盖检查、集成测试等……但是持续交付并不止于此。对于较大的 SOA 类型的组织,将您的管道分解为谨慎的阶段实际上是非常好的实践,例如使用模拟端点的功能测试、性能测试、大型集成测试、UAT 测试、合规性验证、静态代码分析、安全审查等。
    • 很棒的视频。我唯一关心的是人们对发布回购中的所有“发布候选者”做了什么,这些“候选发布者”从未正式发布?我们为 SNAPSHOT 设置了清理计划,但是发布工件会永远保留。我看到这在 Maven 存储库方面使用了大量磁盘空间。
    • @Patrick 发布候选版在获得批准之前不是发布版。如果它们超过 2 个月,我有一个清除工作会删除它们。如果他们还没有被释放,那么他们永远不会:-)
    • 您链接到的 youtube 视频上的演示者实际上明确表示您应该避免使用“maven-release-plugin”。见这里:youtu.be/McTZtyb9M38?t=2179
    【解决方案2】:

    这是我根据 Mark O'Connor 的回答链接的视频的总结。

    • 该解决方案需要像 git 这样的 DVCS 和像 Jenkins 这样的 CI 服务器。
    • 不要在持续交付管道中使用快照构建,也不要使用 maven 发布插件。
    • 1.0-SNAPSHOT 等快照版本会转换为1.0.buildNumber 等真实版本,其中buildNumber 是 Jenkins 作业编号。

    算法步骤:

    1. Jenkins用源码克隆了git repo,说源码有版本1.0-SNAPSHOT
    2. Jenkins 创建了一个名为1.0.JENKINS-JOB-NUMBER 的git 分支,因此快照版本变成了真实版本1.0.124
    3. Jenkins 调用 maven 版本插件将 pom.xml 文件中的版本号从 1.0-SNAPSHOT 更改为 1.0.JENKINS-JOB-NUMBER
    4. Jenkins 调用mvn install
    5. 如果mvn install 成功,那么 Jenkins 将提交分支1.0.JENKINS-JOB-NUMBER,并在 git 中使用适当的标签创建一个真正的非快照版本,以便稍后重现。如果 mvn install 失败,那么 Jenkins 只会删除新创建的分支并导致构建失败。

    我强烈推荐 Mark 的回答中链接的视频。

    【讨论】:

    • 如何处理一个多模块的maven项目?您是否只是发布整个项目和所有具有相同版本的子项?如果我有项目 A 依赖于 B 并且我在项目 B 中进行了提交,则为 B 触发上述步骤,然后为项目 A 触发上述步骤,但是 A 怎么知道 B 的版本?
    • 它是一个多模块项目,然后经验告诉我,有一个单一的版本是有意义的——它与版本插件一致。如果某些模块不经常更改,它们也可能是从工件存储库中提取的单独组件 - 例如,log4j、sl4fj ...
    • 好吧,就我而言,它甚至不是一个多模块。我有依赖于项目 B 的项目 A。项目 B 有自己的 Jenkins 工作,并且可能有一个生成已发布工件的提交。然后,项目 A 需要在 pom.xml 中引用该发布的工件。您是否建议在项目 B 的构建成功并且工件可用时手动更新项目 A?项目 B 是一个核心项目,项目 A 是一个 Web 应用程序,因此它们是耦合的,但在更新项目 A 对项目 B 的依赖项时会有很大的开销,尤其是当您在使用 SNAPSHOT 依赖项查看更改的 IDE 中进行开发时。
    【解决方案3】:

    从 Maven 3.2.1 开始支持持续交付友好版本:https://issues.apache.org/jira/browse/MNG-5576 您可以在版本中使用 3 个预定义变量:

    ${changelist}
    ${revision}
    ${sha1}
    

    所以你基本上做的是:

    1. 将您的版本设置为例如1.0.0-${revision}。 (您可以在多模块项目中使用mvn versions:set 快速正确地完成它。)
    2. 放置一个属性<revision>SNAPSHOT</revision> 用于本地开发。
    3. 在您的 CI 环境中运行 mvn clean install -Drevision=${BUILD_NUMBER} 或类似的东西,甚至是 mvn clean verify -Drevision=${BUILD_NUMBER}

    您可以使用例如https://wiki.jenkins-ci.org/display/JENKINS/Version+Number+Plugin 来生成有趣的内部版本号。

    一旦您发现构建稳定(例如通过验收测试),您就可以将版本推送到 Nexus 或其他存储库。任何不稳定的构建都会被丢弃。

    【讨论】:

    • 这更容易处理。没有版本更改 + 提交以使这项工作......我只是将我的设置为 <version>1.0${revision}</version> 和属性 <revision>-SNAPSHOT</revision>,然后在 CI 构建期间我使用 mvn clean deploy -Drevision=".$TRAVIS_BUILD_ID"。它会导致 patch 版本unusual 但总是在增加以满足 semver...
    【解决方案4】:

    关于如何处理maven版本号和持续交付(CD)有一些很棒的讨论和建议(我会在我的部分答案之后添加它们)。

    首先我对 SNAPSHOT 版本的看法。在maven中的一个SNAPSHOT显示这个目前正在开发到SNAPSHOT后缀之前的特定版本。因此,Nexus 或 maven-release-plugin 等工具对 SNAPSHOTS 进行了特殊处理。对于 Nexus,它们存储在单独的存储库中,并且允许使用相同的 SNAPSHOT 发布版本更新多个工件。所以一个 SNAPSHOT 可以在你不知道的情况下改变(因为你永远不会在你的 pom 中增加任何数字)。因此,我不建议在项目中使用 SNAPSHOT 依赖项,尤其是在 CD 世界中,因为构建不再可靠。

    由于以上原因,当您的项目被其他人使用时,将SNAPSHOT作为项目版本会出现问题。

    对我来说,SNAPSHOT 的另一个问题是它不再是真正可追溯或可重现的。当我在生产中看到 0.0.1-SNAPSHOT 版本时,我需要进行一些搜索以找出它是从哪个版本构建的。当我在文件系统上找到该软件的版本时,我需要查看 pom.properties 或 MANIFEST 文件,看看这是旧垃圾还是最新最好的版本。

    为避免手动更改版本号(尤其是当您一天构建多个构建时),让构建服务器为您更改版本号。因此,对于开发,我会选择

    <major>.<minor>-SNAPSHOT
    

    版本,但在构建新版本时,构建服务器可以用更独特和可追溯的东西替换 SNAPSHOT。

    例如以下之一:

    <major>.<minor>-b<buildNumber>
    <major>.<minor>-r<scmNumber>
    

    因此,主要和次要数字可用于营销问题,或者仅表明已达到一个新的重要里程碑,并且可以在需要时手动更改。 buildNumber(来自您的持续集成服务器的编号)或 scmNumber(Subversion 或 GIT 的修订版)使每个版本都独一无二且可追溯。使用 buildNumber 或 Subversion 修订版时,项目版本甚至是可排序的(不使用 GIT 编号)。使用 buildNumber 或 scmNumber 也很容易查看此版本中的更改。

    另一个例子是stackoverflow的版本控制

    <year>.<month>.<day>.<buildNumber>
    

    这里缺少链接:

    【讨论】:

    • 管道中的第一个链接版本控制已损坏
    • 似乎已被删除。我没有在网络缓存中找到替换链接或内容:(。
    • 这个答案更多的是关于版本名称格式及其含义。已经有足够好的正式规范called "semantic versioning" - 只需添加SNAPSHOT 表示“尚未发布”版本。而且版本的格式不是在 Maven 中确实是个问题,some restrictions。问题是让这个过程轻松,最好是自动(至少直到像X.Y.Z这样的语义=手动版本发布完成)。更新多个相互依赖的pom.xml 文件的部分问题。
    【解决方案5】:

    不要这样做!

    <Major>.<minor>-<build>
    

    会在后面咬你,因为 Maven 将连字符后的任何内容都视为 LEXICAL。这意味着版本 1 在词法上将高于 10。

    这很糟糕,就好像你在 maven 中要求最新版本的东西,那么上面的点就赢了。

    解决方案是在内部版本号之前使用小数点而不是连字符。

    这样做!

    <Major>.<minor>.<build>
    

    在本地有 SNAPSHOT 版本是可以的,但作为构建的一部分,最好使用

    mvn versions:set -DnewVersion=${major}.${minor}.${build.number}
    

    有一些方法可以从 pom 中获取主要/次要版本,例如在调用版本:set 之前使用 help:evaluate 和管道到环境变量。这很脏,但我真的摸不着头脑(以及我团队中的其他人)以使其更简单,而且(当时)Maven 还不够成熟来处理这个问题。我相信 Maven 2.3.1 可能会有所帮助,因此这些信息可能不再相关。

    一群开发人员在同一个major.minor 版本上发布是可以的 - 但始终要注意,小的更改不会造成破坏,而主要版本的更改会有一些破坏性的API 更改,或者功能/行为的弃用.

    从持续交付的角度来看,每个构建都是潜在可发布的,因此每次签入都应该创建一个构建。

    【讨论】:

    • mojo.codehaus.org/versions-maven-plugin/version-rules.html 暗示,根据我自己的测试,这是不正确的。默认的 Maven 版本控制方案是 &lt;major&gt;.&lt;minor&gt;.&lt;incremental&gt;-&lt;buildNumber|qualifier&gt;(其中大部分是可选的)。只要破折号后面的部分是数字,就不会在词法上进行比较。我用mvn versions:use-latest-versionsand e.g. 测试了这个。 1.4-11 被正确检测为比 1.4-2 更新。
    • 你用什么版本的 Maven 测试了这个?另外,您是否也尝试安装 1.4.21 版本,然后尝试了解 Maven 版本范围解析的工作原理?听到你的发现会很有趣,因为我肯定在 2.2.1 中遇到了这个问题,我通过查看 Maven 的源代码验证了这一点。另外,我不认为这些规则实际上适用于除版本插件之外的任何东西,我说的是依赖解析。
    • 关注docs.oracle.com/middleware/1212/core/MAVEN/…@philipp 是正确的。在 ${major}.${minor}.${build.number} 和 ${major}.${minor}.${build.number}-${patchNumber} 中使用增量数字是安全的,但不是 $ {major}.${minor}.${build.number}.${patchNumber}
    【解决方案6】:

    【讨论】:

      【解决方案7】:

      在我的网络应用工作中,我们目前使用这种版本控制模式:

      &lt;jenkins build num&gt;-&lt;git-short-hash&gt;

      示例:247-262e37b9。

      这很好,因为它为您提供了一个始终唯一的版本,并且可以追溯到生成它的 jenkins 构建和 git 修订版。

      在 Maven 3.2.1+ 中,他们最终消除了使用 ${property} 作为版本的警告,这样就可以很容易地构建这些。只需将所有 pom 更改为使用 &lt;version&gt;${revision}&lt;/version&gt; 并使用 -Drevision=whatever 构建。唯一的问题是,在您发布的 pom 中,版本将保留在实际 pom 文件中的${revision},这可能会导致各种奇怪的问题。为了解决这个问题,我编写了一个简单的 maven 插件 (https://github.com/jeffskj/cd-versions-maven-plugin),它在文件中进行变量替换。

      【讨论】:

      • 该插件似乎是更新 pom.xml 文件本身版本的解决方案。然而,下一个问题是更新参与发布的所有依赖组件的dependencies 部分中的版本,以便它们实际上使用彼此的最新版本。我在多模块/反应器构建中有 this problem when automatic update is unreliable(它更新外部组件,而不仅仅是内部组件)。所以,短期解决方案留在SHAPSHOTs。 对您如何解决此问题有何评论?
      • 你基本上不应该使用快照版本。在构建之前更新依赖的版本。
      • 将所有 thr 模块保持在同一版本。在根模块依赖管理部分将模块设置为${project.version}。然后简单的mvn versions:set -DnewVersion=whatever 将完成诀窍并按反应堆顺序更改版本,包括父母等。
      猜你喜欢
      • 2016-11-02
      • 2014-08-22
      • 1970-01-01
      • 2016-02-22
      • 1970-01-01
      • 2018-05-13
      • 1970-01-01
      • 2023-02-11
      • 2016-11-08
      相关资源
      最近更新 更多