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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32209755/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 19:50:30  来源:igfitidea点击:

How to update the version of child modules in Maven?

javamavenmodulemulti-module

提问by Jose Martinez

How to update the version of child modules? There are a lot of Stackoverflow questions like this but I was not able to find one that fit this exact scenario... would love if this is a duplicate.

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

Consider the following project.

考虑以下项目。

parent
  --mod1
  --mod2

At the beginning of a dev release cycle I need to update the parent and modules to the same version. If the version of the parent and modules stayed the same throughout the release then I would would just omit the <version>tag from the modules and execute versions:set -DnewVersion=1.1.1to kick off the dev cycle. But as it turns out the modules do not all end the cycle with the same version. As bugs and fixes materialize only those modules with the bugs and such get updated. For example the parent and mod2 might be at version 1.1.1-RC1, but mod1 might be at 1.1.1-RC2.

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

As such I need to:
1) Include a <version>tag in the modules to track each modules version independently.

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

2) If mod2 requires mod1 as a dependency I need to make sure mod2 references the latest version of mod1.

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

This leads to the following two questions.

这就引出了以下两个问题。

1) At the beginning of the cycle how can I set the parent and modules to the same version in one maven command? I tried version:set -DnewVersion=1.1.1, but this only updates the parent's version across all the POM's but not the module's version. I also tried -N versions:update-child-modules, but I think I am using it wrong because it does nothing, just shows skipped for all the modules.

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

2) This is a bit harder and matches to item 2 above. How do I update both mod1's version and mod2's reference to mod1's version in one step? I know how to do it in 2 steps:

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

parent pom:

父pom:

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

mod2 pom:

mod2 pom:

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

When mod1 bumps up to 1.1.1-RC2 I update the parent POM and mod1 POM to reflect this. These are two steps. Anyway to turn it into one step?

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

My example was small but in real life there are many modules which makes this important time saver, plus I'm curious.

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

采纳答案by Juan

Question 1)

问题 1)

The best way to manage application lifecycle and releases is to use the release plugin.

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

As you may know, Maven philosophy is convention over configuration. Maven convention is to use snapshot versions (those ending with -SNAPSHOT) during development and assigning a non snapshot version only for releases.

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

Say you're developing version 1.1.1. While under development, you just use 1.1.1-SNAPSHOT. Maven will take care of updates of the snapshot. If using an artifact repository, you can use -U to make sure you always have the last version of the snapshots.

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

When the release is ready, release plugin generates and deploys version 1.1.1 and updates POM's with the new development version, such as 1.1.2-SNAPSHOT.

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

About multimodule projects, there are two scenarios: modules are related but independent (such as several web applications) or they are modules of a single big application or library and they share versions. You seem interested in the latter.

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

The best way in this case is just to inherit the same parent (maybe also root) module, including its version. You reference parent group:artifact:version and you do not specify a version for the children. Generally you also inherit group, so your child pom can look like:

在这种情况下,最好的方法是继承相同的父(也可能是根)模块,包括其版本。您引用了 parent group: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>

Now you just need to take care of children pointing to the right version of the parent with the help of the release plugin.

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

To help it know about children, you should make your parent pom also a root pom by including the modules section as shown later.

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

Question 2) I usually declare properties in the parent with all versions of all artifacts which may be referenced. If several modules share version, you just need one property. The parent can look like:

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

Children can reference other modules using

孩子们可以参考其他模块使用

<version>${myproject.version}</version>

It is a very bad practise to declare dependencies using LATEST. Say you do this for version 1.1.1. Now you're working with version 1.1.2-SNAPSHOT and probably you have artifacts with this version installed in your local repo.

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

Now say for some reason you need to rebuild version 1.1.1, for instance because of a bug in production. Your build will use the new version. If you're lucky, this will break the build. If you're unlucky it may even go unnoticed to production.

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

Last but not least, some people like using property values to declare children versions. This is strongly discouraged and will be reported as a warning by maven. I personally don't ever do it. The reasons are also related to reproducibility of builds and the fact that maven assumes that a release build will never change. Having a module version be externally tweakable is not really a good idea.

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

EDIT:

编辑:

Case when module versions are not aligned.

模块版本不一致的情况。

Actually both scenarios can be mixed. You can have, for instance:

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

Parent

家长

---Component1

---组件1

---Component2

---组件2

---Component3

---组件3

------Comp3Module1

------Comp3Module1

------Como3Module2

------Como3Module2

------Comp3Module3

------Comp3Module3

Where parent and the three component versions are different and the three modules of component3 share its same version as explained before.

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

Question 1) In this case each module has its version infependently specified. As said before, it's a bad prsctise to use a property to specify module version, reason why I can only recommend to literally specify versions. As already said, to manage versioning, the best way is to use release plugin, and integrate it with the version control system, such as SVN. Other answers give details on how to use it, so I won't elaborate it further, unless requested.

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

Question 2) The recommended approach is the same explained for the case of sharing the same version, only that you need several properties. The parent can look like:

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

Then you can use dependency management to centralise version management in the parent.

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

For instance, in parent pom,

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

Now, to reference any module from any other module, it's as easy as:

现在,要从任何其他模块引用任何模块,就像:

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

Versions are automatically managed from the parent. You don't need to maintain them in children dependencies, which become also less verbose.

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

回答by rec

1) I've also tried the version:set in the past, but never got it working right. It's supposed to be doing the same process as release:prepare, but it actually doesn't. So what you could try is mvn release:prepare -DautoVersionSubmodules -DdryRun. That is supposed to make all the updates without checking anything into the repo and without making any tags.

1) 我也试过 version:set 过去,但从来没有让它正常工作。它应该执行与 release:prepare 相同的过程,但实际上并非如此。所以你可以尝试的是mvn release:prepare -DautoVersionSubmodules -DdryRun. 这应该进行所有更新,而无需将任何内容检查到 repo 中,也无需制作任何标签。

2) I believe the ClearTK project once followed a similar strategy as you do: they maintained a multi-module project with each module having its own release cycle. To stay on top of the situation, they implemented a custom maven plugin to warn them about dependency version inconsistencies.

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

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

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

While such a plugin would not make the updates that you request, it should at least notify you when updates are necessary. To really fix your problem, you might consider following a the same route as ClearTK did and implement your own Maven plugin (or you do what ClearTK eventually ended up doing: switching to a synced release cycle ;) )

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

回答by Jose Martinez

Ok this is what I came up with. This is based on this continuous-releasing-of-maven-artifactsarticle.

好的,这就是我想出的。这是基于这篇持续发布 Maven 工件的文章。

Parent POM:

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

Sample child POM with inter project dependency:

具有项目间依赖关系的示例子 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) At the beginning of the cycle how can I set the parent and modules to the same version in one maven command?

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

You no longer need to. The parent POM can remain at the same version, only changing if the parent POM changes. In which case you can use mvn version:set -DnewVersion=1.1.1. But you don't need to for this approach.

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

Instead you can dynamically set the version using the property main.version. E.g. mvn clean deploy -Dmain.version=1.1.1Also, to force dynamic passing of the version number, you can leave out the default main.versionproperty that I included in my parent POM above.

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

2) How do I update both mod1's version and mod2's reference to mod1's version in one step?

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

This basically boils down to how to manage revisions. If I do not set the revisionproperty in the mvn command, then all the modules will use SNAPSHOTas the revision. If I set the revisionproperty to RC1then all the modules will get that revision. Furthermore, if I set revisionto RC1but Module4.revisionto RC2then Module4 gets RC2 and all the other modules get RC1. This fulfills the clients request to have dynamic revisions on a per module basis.

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

Here are some examples:

这里有些例子:

  • mvn clean deploy -Dmain.version=1.1.1Sets all the modules to version 1.1.1-SNAPSHOT.
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1Sets all the modules to version 1.1.1-RC1.
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1 -DModule4.revision=RC2Sets all the modules to version 1.1.1-RC1except for Module4 which is set to version 1.1.1-RC2.
  • mvn clean deploy -Dmain.version=1.1.1将所有模块设置为 version 1.1.1-SNAPSHOT
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1将所有模块设置为 version 1.1.1-RC1
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1 -DModule4.revision=RC21.1.1-RC1除 Module4 设置为 version 之外的所有模块设置为 version 1.1.1-RC2

There is a caveat that must be mentioned. If you increment the version of a dependent module, for example Module1, to RC2, then you must also increment the version of all the modules that use it, for example Module4 must not be incremented to RC2 (or the next version) also. This is something that the client has been made aware of and it is also why I would prefer all the modules to have the same version. But I really do like how dynamic it came out. Essentially the version is now set via command line with no updates to POM files required.

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

回答by Andrés Oviedo

1) As @rec said, the maven release plugin would do the trick

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

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

2) You can define dependency from mod2 to mod1 like:

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

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

More info: How do I tell Maven to use the latest version of a dependency?

更多信息: 如何告诉 Maven 使用最新版本的依赖项?

I tested both solutions and it works! Hope it helps you :)

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