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

时间:2015-08-25 16:52:39

标签: java maven module multi-module

如何更新子模块的版本?有很多类似这样的Stackoverflow问题,但我找不到适合这种情况的问题...如果这是重复的话会很喜欢。

考虑以下项目。

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版本的引用?我知道如何分两步完成:

父母:

<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以反映这一点。这是两个步骤。无论如何把它变成一步?

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

3 个答案:

答案 0 :(得分:5)

问题1)

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

正如您所知,Maven哲学是对配置的约定。 Maven约定是在开发期间使用快照版本(以-SNAPSHOT结尾的版本),并仅为版本分配非快照版本。

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

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

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

在这种情况下,最好的方法是继承相同的父模块(也可能是root模块),包括其版本。您引用父组:artifact:version并且您没有为子项指定版本。通常你也会继承组,所以你的孩子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>

现在你只需要在发布插件的帮助下照顾孩子指向正确的父版本。

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

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

<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>

儿童可以使用

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

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

现在说出于某种原因你需要重建版本1.1.1,例如因为生产中的错误。您的构建将使用新版本。如果你很幸运,这将破坏构建。如果你不走运,它甚至可能不会被注意到生产。

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

编辑:

模块版本未对齐的情况。

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

---的Component1

--- COMPONENT2

--- Component3

------ Comp3Module1

------ Como3Module2

------ Comp3Module3

父母和三个组件版本不同,组件3的三个模块共享其相同的版本。

问题1) 在这种情况下,每个模块的版本都是无关紧要的。 如前所述,使用属性指定模块版本是一个不好的方法,这也是我只能建议按字面指定版本的原因。 如前所述,要管理版本控制,最好的方法是使用发布插件,并将其与版本控制系统(如SVN)集成。 其他答案提供了如何使用它的详细信息,因此除非有要求,否则我不会进一步详细说明。

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

<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>

然后,您可以使用依赖关系管理在父级中集中版本管理。

例如,在父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>

从父级自动管理版本。你不需要将它们保存在儿童依赖中,这种依赖性也会变得不那么冗长。

答案 1 :(得分:1)

好的,这就是我想出来的。这是基于这篇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设置为RC1Module4.revision设置为RC2,则Module4将获得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文件。

答案 2 :(得分:0)

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?

我测试了两种解决方案,但它确实有效!希望它可以帮助你:)