java - multi - ¿Cómo actualizar la versión de módulos secundarios en Maven?
spring boot multi module (4)
¿Cómo actualizar la versión de los módulos secundarios? Hay muchas preguntas de Stackoverflow como esta, pero no pude encontrar una que se ajuste a este escenario exacto ... me encantaría que se tratara de un duplicado.
Considere el siguiente proyecto.
parent
--mod1
--mod2
Al comienzo de un ciclo de lanzamiento de desarrollo, necesito actualizar el padre y los módulos a la misma versión. Si la versión del módulo principal y los módulos permanecieran igual durante toda la versión, simplemente omitiría la etiqueta <version>
de los módulos y ejecutaría las versions:set -DnewVersion=1.1.1
para iniciar el ciclo de desarrollo. Pero como resulta que los módulos no todos terminan el ciclo con la misma versión. A medida que los errores y las correcciones se materializan solo aquellos módulos con los errores y se actualizan. Por ejemplo, el padre y mod2 pueden estar en la versión 1.1.1-RC1, pero mod1 podría estar en 1.1.1-RC2.
Como tal necesito:
1) Incluya una etiqueta <version>
en los módulos para rastrear cada versión de los módulos de forma independiente.
2) Si mod2 requiere mod1 como una dependencia, debo asegurarme de que mod2 haga referencia a la última versión de mod1.
Esto lleva a las siguientes dos preguntas.
1) Al comienzo del ciclo, ¿cómo puedo configurar el padre y los módulos a la misma versión en un comando de Maven? version:set -DnewVersion=1.1.1
, pero esto solo actualiza la versión principal en todas las POM pero no en la versión del módulo. También probé las -N versions:update-child-modules
, pero creo que lo estoy usando mal porque no hace nada, solo se muestra omitido para todos los módulos.
2) Esto es un poco más difícil y coincide con el elemento 2 anterior. ¿Cómo actualizo la versión de mod1 y la referencia de mod2 a la versión de mod1 en un solo paso? Sé cómo hacerlo en 2 pasos:
padre 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>
Cuando mod1 alcanza hasta 1.1.1-RC2, actualizo el POM principal y el POM mod1 para reflejar esto. Estos son dos pasos. ¿De todos modos convertirlo en un solo paso?
Mi ejemplo fue pequeño pero en la vida real hay muchos módulos que hacen que este importante ahorro de tiempo, además tengo curiosidad.
1) Como dijo @rec, el plugin de Maven Release haría el truco
$ mvn release:prepare -DautoVersionSubmodules=true
$ mvn release:perform
2) Puedes definir la dependencia de mod2 a mod1 como:
<dependency>
<groupId>com.xxx</groupId>
<artifactId>mod1</artifactId>
<version>LATEST</version>
</dependency>
Más información: ¿Cómo le digo a Maven que use la última versión de una dependencia?
¡Probé ambas soluciones y funciona! Espero te ayude :)
1) También probé la versión: establecida en el pasado, pero nunca funcionó correctamente. Se supone que debe estar haciendo el mismo proceso que el lanzamiento: preparar, pero en realidad no lo hace. Entonces, lo que podrías probar es mvn release:prepare -DautoVersionSubmodules -DdryRun
. Se supone que eso hace todas las actualizaciones sin registrar nada en el repositorio y sin hacer ninguna etiqueta.
2) Creo que el proyecto ClearTK una vez siguió una estrategia similar a la tuya: mantuvieron un proyecto de múltiples módulos con cada módulo teniendo su propio ciclo de lanzamiento. Para mantenerse al tanto de la situación, implementaron un complemento personalizado de Maven para advertirles sobre las inconsistencias de la versión de dependencia.
https://github.com/ClearTK/cleartk/tree/master/consistent-versions-plugin
Si bien este complemento no haría las actualizaciones que usted solicita, al menos debería notificarle cuando las actualizaciones son necesarias. Para solucionar realmente su problema, puede considerar seguir la misma ruta que ClearTK e implementar su propio complemento de Maven (o hacer lo que finalmente hizo ClearTK: cambiar a un ciclo de lanzamiento sincronizado;))
Ok, esto es lo que se me ocurrió. Esto se basa en este artículo de continuous-releasing-of-maven-artifacts .
Padre 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>
Ejemplo de POM hijo con dependencia entre proyectos:
<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) Al comienzo del ciclo, ¿cómo puedo configurar el padre y los módulos a la misma versión en un comando de Maven?
Ya no es necesario. El POM principal puede permanecer en la misma versión, cambiando solo si el POM principal cambia. En cuyo caso puede usar la mvn version:set -DnewVersion=1.1.1
. Pero no es necesario para este enfoque.
En su lugar, puede configurar dinámicamente la versión utilizando la propiedad main.version
. Por ejemplo, mvn clean deploy -Dmain.version=1.1.1
Además, para forzar el paso dinámico del número de versión, puede omitir la propiedad main.version
predeterminada que main.version
en mi POM principal anterior.
2) ¿Cómo actualizo la versión de mod1 y la referencia de mod2 a la versión de mod1 en un solo paso?
Básicamente, esto se reduce a cómo gestionar las revisiones. Si no configuro la propiedad de revision
en el comando mvn, entonces todos los módulos usarán SNAPSHOT
como la revisión. Si configuro la propiedad de revision
en RC1
, todos los módulos obtendrán esa revisión. Además, si configuro la revision
en RC1
pero Module4.revision
en RC2
entonces Module4 obtiene RC2 y todos los demás módulos obtienen RC1. Esto cumple con la solicitud de los clientes de tener revisiones dinámicas por módulo.
Aquí hay unos ejemplos:
-
mvn clean deploy -Dmain.version=1.1.1
Establece todos los módulos en la versión1.1.1-SNAPSHOT
. -
mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1
Establece todos los módulos en la versión1.1.1-RC1
. -
mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1 -DModule4.revision=RC2
Establece todos los módulos en la versión1.1.1-RC1
excepto el Módulo 4 que se establece en la versión1.1.1-RC2
.
Hay una advertencia que debe ser mencionada. Si incrementa la versión de un módulo dependiente, por ejemplo, Módulo 1, a RC2, entonces también debe incrementar la versión de todos los módulos que lo usan, por ejemplo, Módulo 4 no debe incrementarse a RC2 (o la próxima versión) también. Esto es algo que el cliente ha tenido en cuenta y también es la razón por la que preferiría que todos los módulos tengan la misma versión. Pero realmente me gusta lo dinámico que salió. Esencialmente, la versión ahora se configura a través de la línea de comandos sin necesidad de actualizaciones a los archivos POM.
Pregunta 1)
La mejor manera de administrar el ciclo de vida y las versiones de la aplicación es usar el complemento de la versión.
Como ustedes saben, la filosofía de Maven es una convención sobre la configuración. La convención de Maven es usar versiones de instantáneas (aquellas que terminan con -SNAPSHOT) durante el desarrollo y asignar una versión que no sea de instantáneas solo para las versiones.
Digamos que estás desarrollando la versión 1.1.1. Mientras está en desarrollo, solo usa 1.1.1-SNAPSHOT. Maven se encargará de las actualizaciones de la instantánea. Si usa un repositorio de artefactos, puede usar -U para asegurarse de que siempre tenga la última versión de las instantáneas.
Cuando el lanzamiento está listo, el complemento de lanzamiento genera e implementa la versión 1.1.1 y actualiza los POM con la nueva versión de desarrollo, como 1.1.2-SNAPSHOT.
Sobre los proyectos multimódulos, hay dos escenarios: los módulos están relacionados pero son independientes (como varias aplicaciones web) o son módulos de una sola aplicación o biblioteca grande y comparten versiones. Pareces interesado en lo último.
La mejor manera en este caso es simplemente heredar el mismo módulo primario (quizás también raíz), incluida su versión. Hace referencia al grupo padre: artefacto: versión y no especifica una versión para los hijos. En general, también hereda el grupo, por lo que su hijo pom puede verse así:
<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>
Ahora solo debe cuidar a los niños que apuntan a la versión correcta del padre con la ayuda del complemento de lanzamiento.
Para ayudarlo a saber acerca de los niños, debe hacer que su padre pom también sea un pom raíz incluyendo la sección de módulos como se muestra más adelante.
Pregunta 2) Normalmente declaro propiedades en el padre con todas las versiones de todos los artefactos a los que se puede hacer referencia. Si varios módulos comparten la versión, solo necesitas una propiedad. El padre puede verse como:
<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>
Los niños pueden consultar otros módulos usando
<version>${myproject.version}</version>
Es una muy mala práctica declarar dependencias usando LATEST. Digamos que haces esto para la versión 1.1.1. Ahora está trabajando con la versión 1.1.2-SNAPSHOT y probablemente tenga artefactos con esta versión instalada en su repositorio local.
Ahora diga por alguna razón que necesita reconstruir la versión 1.1.1, por ejemplo debido a un error en la producción. Tu versión usará la nueva versión. Si tienes suerte, esto romperá la construcción. Si tienes mala suerte, incluso puede pasar desapercibido a la producción.
Por último, pero no menos importante, a algunas personas les gusta usar los valores de propiedad para declarar versiones secundarias. Esto está muy desaconsejado y se informará como una advertencia por parte de maven. Yo personalmente nunca lo hago. Las razones también están relacionadas con la reproducibilidad de las compilaciones y el hecho de que Maven asuma que una compilación de la versión nunca cambiará. Tener una versión de módulo que se pueda ajustar externamente no es realmente una buena idea.
EDITAR:
Caso cuando las versiones del módulo no están alineadas.
En realidad ambos escenarios pueden ser mixtos. Puedes tener, por ejemplo:
Padre
--- Componente 1
--- Componente2
--- Componente3
------ Comp3Module1
------ Como3Module2
------ Comp3Module3
Donde las versiones principales y las tres versiones del componente son diferentes y los tres módulos de component3 comparten su misma versión como se explicó anteriormente.
Pregunta 1) En este caso, cada módulo tiene su versión especificada infependentemente. Como se dijo antes, es una mala idea usar una propiedad para especificar la versión del módulo, por lo que solo puedo recomendar que se especifique literalmente las versiones. Como ya se dijo, para administrar el control de versiones, la mejor manera es usar el complemento de lanzamiento e integrarlo con el sistema de control de versiones, como SVN. Otras respuestas dan detalles sobre cómo usarlo, por lo que no lo explicaré más a menos que se solicite.
Pregunta 2) El enfoque recomendado es el mismo que se explica para el caso de compartir la misma versión, solo que necesita varias propiedades. El padre puede verse como:
<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>
Luego puede usar la administración de dependencias para centralizar la administración de versiones en el padre.
Por ejemplo, en pom padre,
<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>
Ahora, para hacer referencia a cualquier módulo de cualquier otro módulo, es tan fácil como:
<dependency>
<groupId>${myproject.group}</groupId>
<artifactId>component1</artifactId>
</dependency>
<dependency>
<groupId>${myproject.group}</groupId>
<artifactId>comp3module1</artifactId>
<type>ejb-client</type>
</dependency>
Las versiones se gestionan automáticamente desde el padre. No es necesario mantenerlos en dependencias de los niños, que también se vuelven menos verbales.