Maven中如何更新子模块的版本?

How to update the version of child modules in Maven?

如何更新子模块的版本?有很多像这样的 Whosebug 问题,但我找不到适合这种情况的问题...如果这是重复的,我会很高兴。

考虑以下项目。

parent
  --mod1
  --mod2

在开发发布周期开始时,我需要将父模块和模块更新到同一版本。如果父模块和模块的版本在整个发布过程中保持不变,那么我将只省略模块中的 <version> 标记并执行 versions:set -DnewVersion=1.1.1 以启动开发周期。但事实证明,这些模块并不是都以相同的版本结束循环。随着错误和修复的出现,只有那些有错误的模块才会得到更新。例如,parent 和 mod2 可能是版本 1.1.1-RC1,但 mod1 可能是 1.1.1-RC2。

因此我需要:
1) 在模块中包含一个 <version> 标签以独立跟踪每个模块版本。

2) 如果 mod2 需要 mod1 作为依赖项,我需要确保 mod2 引用最新版本的 mod1。

由此引出以下两个问题。

1) 在循环开始时,如何在一个 maven 命令中将父模块和模块设置为同一版本?我试过 version:set -DnewVersion=1.1.1,但这只会更新所有 POM 的父版本,但不会更新模块的版本。我也试过 -N versions:update-child-modules,但我认为我用错了,因为它什么都不做,只是显示所有模块都已跳过。

2) 这有点难,与上面的第 2 项匹配。如何一步更新 mod1 的版本和 mod2 对 mod1 版本的引用?我知道如何分两步完成:

父 pom:

<properties>
    <!-- update this manually if mod1's version no longer matches parent -->
    <mod1.version>${project.version}</mod1.version>
</properties>

mod2 pom:

    <dependency>
        <groupId>com.xxx</groupId>
        <artifactId>mod1</artifactId>
        <version>${mod1.version}</version>
    </dependency>

当 mod1 升级到 1.1.1-RC2 时,我更新父 POM 和 mod1 POM 以反映这一点。这是两个步骤。无论如何把它变成一步?

我的例子很小,但在现实生活中有很多模块可以节省这个重要的时间,而且我很好奇。

1) 我过去也尝试过 version:set,但一直没能正常工作。它本应执行与 release:prepare 相同的过程,但实际上并非如此。所以你可以尝试的是mvn release:prepare -DautoVersionSubmodules -DdryRun。这应该是在不检查任何内容到 repo 并且不制作任何标签的情况下进行所有更新。

2) 我相信 ClearTK 项目曾经遵循与您类似的策略:他们维护一个多模块项目,每个模块都有自己的发布周期。为了掌握情况,他们实施了一个自定义的 maven 插件来警告他们依赖版本不一致。

https://github.com/ClearTK/cleartk/tree/master/consistent-versions-plugin

虽然这样的插件不会进行您请求的更新,但它至少应该在需要更新时通知您。要真正解决您的问题,您可以考虑遵循与 ClearTK 相同的路线并实施您自己的 Maven 插件(或者您执行 ClearTK 最终完成的操作:切换到同步发布周期;))

好的,这就是我想到的。这是基于这篇 continuous-releasing-of-maven-artifacts 文章。

父 POM:

<properties>
    <!-- versions of modules -->
    <main.version>1.0</main.version>
    <revision>SNAPSHOT</revision> <!-- default revision -->
    <Module1.revision>${revision}</Module1.revision>
    <Module2.revision>${revision}</Module2.revision>
    <Module3.revision>${revision}</Module3.revision>
    <Module4.revision>${revision}</Module4.revision>
    <Module5.revision>${revision}</Module5.revision>
    <Module1.version>${main.version}-${Module1.revision}</Module1.version>
    <Module2.version>${main.version}-${Module2.revision}</Module2.version>
    <Module3.version>${main.version}-${Module3.revision}</Module3.version>
    <Module4.version>${main.version}-${Module4.revision}</Module4.version>
    <Module5.version>${main.version}-${Module5.revision}</Module5.version>
</properties>

具有项目间依赖性的示例子 POM:

    <groupId>com.xyz</groupId>
    <artifactId>Module4</artifactId>
    <packaging>jar</packaging>
    <version>${Module4.version}</version>

    <parent>
        <groupId>com.xyz</groupId>
        <artifactId>ParentProject</artifactId>
        <version>1.0</version>
    </parent>   

    <dependencies>
        <dependency>
            <groupId>com.xyz</groupId>
            <artifactId>Module1</artifactId>
            <version>${Module1.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xyz</groupId>
            <artifactId>Module2</artifactId>
            <version>${Module2.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xyz</groupId>
            <artifactId>Module3</artifactId>
            <version>${Module3.version}</version>
            <type>jar</type>
        </dependency>
    <dependencies>

1) 在循环开始时,如何在一个 maven 命令中将父模块和模块设置为相同版本?

您不再需要。父 POM 可以保持相同的版本,只有在父 POM 更改时才会更改。在这种情况下,您可以使用 mvn version:set -DnewVersion=1.1.1。但是您不需要使用这种方法。

相反,您可以使用 属性 main.version 动态设置版本。例如。 mvn clean deploy -Dmain.version=1.1.1 此外,要强制动态传递版本号,您可以省略我在上面的父 POM 中包含的默认值 main.version 属性。

2) 如何一步更新 mod1 的版本和 mod2 对 mod1 版本的引用?

这基本上归结为如何管理修订。如果我在 mvn 命令中不设置 revision 属性,那么所有模块将使用 SNAPSHOT 作为修订版。如果我将 revision 属性 设置为 RC1 那么所有模块都将获得该修订版。此外,如果我将 revision 设置为 RC1,但将 Module4.revision 设置为 RC2,则模块 4 获得 RC2,所有其他模块获得 RC1。这满足了客户对每个模块进行动态修订的要求。

这里有一些例子:

  • mvn clean deploy -Dmain.version=1.1.1 将所有模块设置为版本 1.1.1-SNAPSHOT
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1 将所有模块设置为版本 1.1.1-RC1
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1 -DModule4.revision=RC2 将所有模块设置为版本 1.1.1-RC1,除了 Module4 设置为版本 1.1.1-RC2.

有一个警告必须提及。如果将依赖模块(例如 Module1)的版本增加到 RC2,则还必须增加使用它的所有模块的版本,例如 Module4 也不能增加到 RC2(或下一个版本)。这是客户已经意识到的事情,也是我希望所有模块都具有相同版本的原因。但我真的很喜欢它的动态。基本上,现在通过命令行设置版本,无需更新 POM 文件。

1) 正如@rec 所说,maven 发布插件可以解决问题

$ mvn release:prepare -DautoVersionSubmodules=true
$ mvn release:perform

2) 您可以定义从 mod2 到 mod1 的依赖关系,例如:

<dependency>
    <groupId>com.xxx</groupId>
    <artifactId>mod1</artifactId>
    <version>LATEST</version>
</dependency>

更多信息:How do I tell Maven to use the latest version of a dependency?

我测试了这两种解决方案并且有效!希望对你有帮助:)

问题 1)

管理应用程序生命周期和发布的最佳方式是使用发布插件。

您可能知道,Maven 的哲学是约定优于配置。 Maven 惯例是在开发期间使用快照版本(以 -SNAPSHOT 结尾的版本)并仅为发布分配非快照版本。

假设您正在开发 1.1.1 版。在开发过程中,您只需使用 1.1.1-SNAPSHOT。 Maven 将负责快照的更新。如果使用工件存储库,您可以使用 -U 来确保您始终拥有最新版本的快照。

发布准备就绪后,发布插件会生成并部署版本 1.1.1,并使用新的开发版本更新 POM,例如 1.1.2-SNAPSHOT。

关于多模块项目,有两种情况:模块相关但独立(例如多个Web应用程序)或者它们是单个大型应用程序或库的模块并且它们共享版本。你似乎对后者感兴趣。

在这种情况下最好的方法就是继承相同的 parent(也可能是 root)模块,包括它的版本。您引用 parent group:artifact:version 并且没有指定 children 的版本。通常你也继承组,所以你的 child pom 可以看起来像:

<parent>
   <groupId>com.mycompany.myproject</groupId>
   <artifactId>myproject-parent</artifactId>
   <version>1.1.1-SNAPSHOT</version>
   <relativePath>../myproject-parent</relativePath>
</parent>
<artifactId>myproject-module1</artifactId>

现在您只需要在发布插件的帮助下处理 children 指向 parent 的正确版本。

为了帮助它了解 children,您应该通过包含模块部分使您的 parent pom 也成为根 pom,如下所示。

问题2) 我通常在 parent 中声明属性,其中包含可能引用的所有工件的所有版本。如果几个模块共享版本,你只需要一个属性。 parent 可以看起来像:

<groupId>com.mycompany.myproject</groupId>
<artifactId>myproject-parent</artifactId>
<version>1.1.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
   <myproject.version>1.1.1-SNAPSHOT</myproject.version>
</properties>

.......

<modules>
   <module>../myproject-module1</module>
   ...
</modules>

Children可以使用

引用其他模块
<version>${myproject.version}</version>

使用 LATEST 声明依赖项是一种非常糟糕的做法。假设您为版本 1.1.1 执行此操作。现在您正在使用 1.1.2-SNAPSHOT 版本,并且您可能在本地存储库中安装了此版本的工件。

现在说由于某种原因您需要重建版本 1.1.1,例如因为生产中的错误。您的构建将使用新版本。如果幸运的话,这会破坏构建。如果你运气不好,它甚至可能会被忽视。

最后但同样重要的是,有些人喜欢使用 属性 值来声明 children 版本。强烈建议不要这样做,maven 会将其报告为警告。我个人从不这样做。原因还与构建的可重复性以及 Maven 假定发布构建永远不会改变的事实有关。让模块版本可以从外部调整并不是一个好主意。

编辑:

模块版本不一致的情况。

实际上这两种情况可以混合使用。 你可以有,例如:

Parent

---组件1

---组件2

---组件3

------Comp3Module1

------Como3模块2

------Comp3模块3

其中parent和三个组件版本不同,component3的三个模块共享相同的版本,如前所述。

问题 1) 在这种情况下,每个模块都有其独立指定的版本。 如前所述,使用 属性 指定模块版本是一种不好的做法,这就是我只能建议按字面指定版本的原因。 前面已经说过,要管理版本控制,最好的方法是使用发布插件,并将其与版本控制系统集成,例如 SVN。 其他答案详细介绍了如何使用它,所以我不会进一步详细说明,除非要求。

问题2) 推荐的方法与共享相同版本的情况相同,只是您需要多个属性。 parent 可以看起来像:

<properties>
   <myproject.group>com.mycompany.myproject</myproject.group>
   <component1.version>1.1.1-RC1</component1.version>
   <component2.version>1.1.1-RC2</component2.version>
   <component3.version>2.0.0</component3.version>
<properties>

然后你可以使用依赖管理来集中版本管理在parent。

例如,在 parent pom 中,

<dependencyManagement>
   <dependencies>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>component1</artifactId>
         <version>${component1.version}</version>
      </dependency>
      <dependency>
        <groupId>${myproject.group}</groupId>
         <artifactId>component2</artifactId>
         <version>${component2.version}</version>
         <type>war</type>
      </dependency>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>comp3module1</artifactId>
         <version>${component3.version}</version>
        <type>ejb</type>
      </dependency>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>comp3module1</artifactId>
         <version>${component3.version}</version>
        <type>ejb-client</type>
      </dependency>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>comp3module2</artifactId>
         <version>${component3.version}</version>
        <type>war</version>
      </dependency>
   </dependencies>
</dependencyManagement>

现在,要从任何其他模块引用任何模块,很简单:

<dependency>
   <groupId>${myproject.group}</groupId>
   <artifactId>component1</artifactId>
</dependency>
<dependency>
   <groupId>${myproject.group}</groupId>
   <artifactId>comp3module1</artifactId>
   <type>ejb-client</type>
</dependency>

版本是从 parent 自动管理的。您不需要在 children 依赖项中维护它们,这也变得不那么冗长。