¿Cómo le digo a Maven que use la última versión de una dependencia?

788

En Maven, las dependencias generalmente se configuran así:

<dependency>
  <groupId>wonderful-inc</groupId>
  <artifactId>dream-library</artifactId>
  <version>1.2.3</version>
</dependency>

Ahora, si está trabajando con bibliotecas que tienen lanzamientos frecuentes, actualizar constantemente la etiqueta <version> puede ser algo molesto. ¿Hay alguna forma de decirle a Maven que use siempre la última versión disponible (del repositorio)?

Anders Sandvig
fuente
@ Martin Conozco la convención xyz-SNAPSHOT, pero estaba pensando en las bibliotecas que se lanzan en las versiones finales al repositorio (es decir, pasar de dream-library-1.2.3.jar a dream-library-1.2.4.jar , y así).
Anders Sandvig
176
Realmente no recomiendo esta práctica (ni el uso de rangos de versiones) en aras de la reproducibilidad de compilación. Una compilación que comienza a fallar repentinamente por una razón desconocida es mucho más molesta que actualizar manualmente un número de versión.
Pascal Thivent
12
@PascalThivent Actualizar manualmente un número de publicación en un pom es un fastidio si está realizando publicaciones continuas. Utilizo el complemento de versiones combinado con el complemento scm para superar esto (ver mi respuesta).
Adam Gent
44
@PascalThivent Ambos son molestos, pero de una manera diferente. Me gustaría elegir entre ambos dependiendo de mi situación y no estar obligado a usar uno porque alguien más decidió que este sería mejor.
piegames

Respuestas:

745

NOTA:

¡Esta respuesta se aplica solo a Maven 2! Las mencionadas LATESTy las RELEASEmetaversiones se han eliminado en Maven 3 "por el bien de las compilaciones reproducibles" , hace más de 6 años. Consulte esta solución compatible con Maven 3 .


Si siempre desea usar la versión más nueva, Maven tiene dos palabras clave que puede usar como alternativa a los rangos de versión. Debe usar estas opciones con cuidado ya que ya no tiene el control de los complementos / dependencias que está usando.

Cuando depende de un complemento o una dependencia, puede usar el valor de versión LATEST o RELEASE. ÚLTIMO se refiere a la última versión lanzada o instantánea de un artefacto en particular, el artefacto implementado más recientemente en un repositorio particular. RELEASE se refiere a la última versión no instantánea en el repositorio. En general, no es una mejor práctica diseñar software que dependa de una versión no específica de un artefacto. Si está desarrollando software, es posible que desee usar RELEASE o LATEST como una conveniencia para no tener que actualizar los números de versión cuando se publique una nueva versión de una biblioteca de terceros. Cuando lanza software, siempre debe asegurarse de que su proyecto dependa de versiones específicas para reducir las posibilidades de que su versión o proyecto se vea afectado por una versión de software que no esté bajo su control.

Consulte la sección Sintaxis POM del libro de Maven para más detalles. O vea este documento sobre los rangos de versión de dependencia , donde:

  • Un corchete ( [& ]) significa "cerrado" (inclusive).
  • Un paréntesis ( (& )) significa "abierto" (exclusivo).

Aquí hay un ejemplo que ilustra las diversas opciones. En el repositorio de Maven, com.foo:my-foo tiene los siguientes metadatos:

<?xml version="1.0" encoding="UTF-8"?><metadata>
  <groupId>com.foo</groupId>
  <artifactId>my-foo</artifactId>
  <version>2.0.0</version>
  <versioning>
    <release>1.1.1</release>
    <versions>
      <version>1.0</version>
      <version>1.0.1</version>
      <version>1.1</version>
      <version>1.1.1</version>
      <version>2.0.0</version>
    </versions>
    <lastUpdated>20090722140000</lastUpdated>
  </versioning>
</metadata>

Si se requiere una dependencia de ese artefacto, tiene las siguientes opciones ( por supuesto, se pueden especificar otros rangos de versión , solo mostrando los relevantes aquí):

Declare una versión exacta (siempre se resolverá a 1.0.1):

<version>[1.0.1]</version>

Declare una versión explícita (siempre se resolverá a 1.0.1 a menos que ocurra una colisión, cuando Maven seleccionará una versión coincidente):

<version>1.0.1</version>

Declare un rango de versión para todos los 1.x (actualmente se resolverá en 1.1.1):

<version>[1.0.0,2.0.0)</version>

Declare un rango de versión abierta (se resolverá a 2.0.0):

<version>[1.0.0,)</version>

Declare la versión como ÚLTIMA (se resolverá a 2.0.0) (eliminada de maven 3.x)

<version>LATEST</version>

Declare la versión como RELEASE (se resolverá en 1.1.1) (eliminada de maven 3.x):

<version>RELEASE</version>

Tenga en cuenta que, de manera predeterminada, sus propias implementaciones actualizarán la entrada "más reciente" en los metadatos de Maven, pero para actualizar la entrada "versión", debe activar el "perfil de versión" desde el super POM de Maven . Puede hacerlo con "-Prelease-profile" o "-DperformRelease = true"


Vale la pena enfatizar que cualquier enfoque que permita a Maven elegir las versiones de dependencia (ÚLTIMO, LIBERACIÓN y rangos de versión) puede dejarlo abierto a problemas de tiempo de compilación, ya que las versiones posteriores pueden tener un comportamiento diferente (por ejemplo, el complemento de dependencia ha cambiado previamente un valor predeterminado valor de verdadero a falso, con resultados confusos).

Por lo tanto, generalmente es una buena idea definir versiones exactas en los lanzamientos. Como señala la respuesta de Tim , el complemento de versiones de Maven es una herramienta útil para actualizar las versiones de dependencia, en particular las versiones: use-latest-version y versiones: use-latest-releases .

Vendedor rico
fuente
76
Hola rico Parece que el RELEASE y la última versión son marcadores ya no se admite en Maven 3.x .
Pascal Thivent
16
Esa desaprobación parece aplicarse solo a los complementos en lugar de las dependencias normales si entiendo el documento correctamente
Mond Raymond
99
@RichSeller hey Rich; Pasé un poco de tiempo en esto antes de darme cuenta de que esto ya no está disponible en Maven 3.0;) ¿Consideraría editar la respuesta para que comience con una actualización que indique la depreacción de Maven 3.0? ¡Gracias un montón!
Miquel
66
Creo que un buen equilibrio sería bloquear la versión principal, pero obtener la última versión menor (o parche) (la que se use para corregir errores solo en el artifcat del que depende). Con la sintaxis actual, esto parece ser posible solo con un rango como (nota: comienza con paréntesis y termina con parens):[1.1,2.0)
Amr Mostafa
2
FWIW ... enlace actualizado a las Notas de compatibilidad de Maven3
dyodji
384

Ahora sé que este tema es antiguo, pero al leer la pregunta y la respuesta proporcionada por el OP, parece que el complemento Maven Versions podría haber sido una mejor respuesta a su pregunta:

En particular, los siguientes objetivos podrían ser útiles:

  • versiones: use-latest- version busca en el pom todas las versiones que hayan sido una versión más nueva y las reemplaza por la última.
  • versiones: use-latest-releases busca en el pom todas las versiones que no sean SNAPSHOT que hayan sido una versión más reciente y las reemplaza con la versión más reciente.
  • versiones: update-properties actualiza las propiedades definidas en un proyecto para que correspondan a la última versión disponible de dependencias específicas. Esto puede ser útil si un conjunto de dependencias debe estar bloqueado en una sola versión.

También se proporcionan los siguientes objetivos:

  • versiones: display-dependency-updates analiza las dependencias de un proyecto y produce un informe de las dependencias que tienen versiones más nuevas disponibles.
  • versiones: display-plugin-updates escanea los complementos de un proyecto y produce un informe de aquellos complementos que tienen versiones más nuevas disponibles.
  • versiones: update-parent actualiza la sección padre de un proyecto para que haga referencia a la última versión disponible. Por ejemplo, si utiliza un POM raíz corporativo, este objetivo puede ser útil si necesita asegurarse de que está utilizando la última versión del POM raíz corporativo.
  • versiones: update-child-modules actualiza la sección principal de los módulos secundarios de un proyecto para que la versión coincida con la versión del proyecto actual. Por ejemplo, si tiene un pom agregador que también es el principal para los proyectos que agrega y las versiones secundarias y principales se desincronizan, este mojo puede ayudar a corregir las versiones de los módulos secundarios. (Tenga en cuenta que es posible que necesite invocar a Maven con la opción -N para ejecutar este objetivo si su proyecto está tan dañado que no se puede construir debido a la falta de coincidencia de la versión).
  • versiones: las instantáneas de bloqueo busca en el pom todas las versiones -SNAPSHOT y las reemplaza con la versión de marca de tiempo actual de -SNAPSHOT, por ejemplo -20090327.172306-4
  • versiones: unlock-snapshots busca en el pom todas las versiones de instantáneas bloqueadas con marca de tiempo y las reemplaza con -SNAPSHOT.
  • versiones: resolve-rangos encuentra dependencias utilizando rangos de versión y resuelve el rango a la versión específica que se utiliza.
  • versiones: use-releases busca en el pom todas las versiones -SNAPSHOT que se han lanzado y las reemplaza por la versión de lanzamiento correspondiente.
  • versiones: use-next-releases busca en el pom todas las versiones que no sean SNAPSHOT que hayan sido una versión más reciente y las reemplaza con la siguiente versión de lanzamiento.
  • versiones: use-next-versiones busca en el pom todas las versiones que hayan sido una versión más nueva y las reemplaza con la siguiente versión.
  • versiones: commit elimina los archivos pom.xml.versionsBackup. Forma la mitad del "Poor Man's SCM" incorporado.
  • versiones: revert restaura los archivos pom.xml de los archivos pom.xml.versionsBackup. Forma la mitad del "Poor Man's SCM" incorporado.

Solo pensé en incluirlo para cualquier referencia futura.

Tim
fuente
10
En este contexto, ¿cuál es la diferencia entre "lanzamiento" y "versión".
Ben Noland
1
@BenNoland, creo que la diferencia en este caso es que la próxima versión puede no ser un artefacto de lanzamiento. Por ejemplo, dado un artefacto versionado 1.0.0-SNAPSHOT, 1.0.0 y 1.0.1-SNAPSHOT, y una referencia pom a 1.0.0-SNAPSHOT, versiones: next-versiones y versiones: next-releases se resolverán a 1.0.0 , mientras que las versiones: últimas versiones y versiones: últimos lanzamientos se resolverán en 1.0.1-SNAPSHOT y 1.0.0 respetuosamente.
Ryan Beesley
1
Puede resolver algunas incertidumbres entre versiones / lanzamientos / instantáneas en esta bonita tabla aquí: goo.gl/iDq6PK
Ev0oD
1
Imprimir todos los objetivos posibles y no relacionados no es útil.
MariuszS
2
Creo que las versiones: use-latest-version resuelve la mayoría de los problemas del OP.
Alex R
172

Consulte esta página (sección "Rangos de versión de dependencia"). Lo que tal vez quieras hacer es algo como

<version>[1.2.3,)</version>

Estos rangos de versiones se implementan en Maven2.

Martin Klinke
fuente
Por alguna razón, esta opción no funcionó para mí, eligió una versión dentro del rango, pero no la más nueva.
sorin
44
Es posible que desee ver más de cerca cómo Maven compara los números de versión; si no se ajusta a un patrón estricto, Maven compara como cadenas y no como números.
Thorbjørn Ravn Andersen
Esa página está en Codehaus, y se describe a sí misma como cosas "que aún no se han implementado para Maven 2.0" ... La documentación de Maven en sí misma no dice nada sobre los rangos de versiones. ¿Me estoy perdiendo de algo? ¿Cuándo se introdujeron los rangos de versión? ¿Dónde se describen en la documentación oficial?
Shannon
1
Estás equivocado, el rango de versiones significa que todas las versiones están bien desde 1.2.3 a versiones superiores. Esta no es la última versión en absoluto.
MariuszS
@sorin ¿Quizás tuvo otras dependencias en su proyecto que también dependen del artefacto en cuestión? Intenta mvn dependency:tree -Dverboseresolver eso. Esto podría explicar la versión inesperada.
Eugene Beresovsky
83

A diferencia de otros, creo que hay muchas razones por las que siempre puedes desear la última versión. Particularmente si está realizando una implementación continua (a veces tenemos como 5 lanzamientos en un día) y no quiere hacer un proyecto de varios módulos.

Lo que hago es hacer que Hudson / Jenkins haga lo siguiente para cada compilación:

mvn clean versions:use-latest-versions scm:checkin deploy -Dmessage="update versions" -DperformRelease=true

Es decir, uso el complemento de versiones y el complemento scm para actualizar las dependencias y luego lo registro en el control de origen. Sí, dejé que mi CI hiciera registros de SCM (lo que debe hacer de todos modos para el complemento de lanzamiento de Maven).

Deberá configurar el complemento de versiones para actualizar solo lo que desee:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>versions-maven-plugin</artifactId>
    <version>1.2</version>
    <configuration>
        <includesList>com.snaphop</includesList>
        <generateBackupPoms>false</generateBackupPoms>
        <allowSnapshots>true</allowSnapshots>
    </configuration>
</plugin>

Utilizo el complemento de lanzamiento para hacer el lanzamiento que se encarga de -SNAPSHOT y valida que hay una versión de lanzamiento de -SNAPSHOT (que es importante).

Si hace lo que hago, obtendrá la última versión para todas las compilaciones de instantáneas y la última versión de lanzamiento para las compilaciones de lanzamiento. Sus compilaciones también serán reproducibles.

Actualizar

Noté algunos comentarios preguntando algunos detalles de este flujo de trabajo. Diré que ya no usamos este método y la gran razón por la cual el complemento de versiones de Maven es defectuoso y, en general, es inherentemente defectuoso.

Es defectuoso porque para ejecutar el complemento de versiones para ajustar las versiones, todas las versiones existentes deben existir para que el pom se ejecute correctamente. Es decir, el complemento de versiones no puede actualizarse a la última versión de nada si no puede encontrar la versión a la que se hace referencia en el pom. Esto es bastante molesto ya que a menudo limpiamos versiones antiguas por razones de espacio en disco.

Realmente necesita una herramienta separada de maven para ajustar las versiones (por lo que no depende del archivo pom para ejecutarse correctamente). He escrito tal herramienta en el lenguaje humilde que es Bash. El script actualizará las versiones como el complemento de versión y volverá a verificar el pom en el control de origen. También funciona como 100 veces más rápido que el complemento de versiones mvn. Desafortunadamente, no está escrito de manera pública, pero si la gente está interesada, podría hacerlo y ponerlo en una esencia o github.

Volviendo al flujo de trabajo cuando algunos comentarios preguntaron sobre esto es lo que hacemos:

  1. Tenemos más o menos 20 proyectos en sus propios repositorios con sus propios trabajos de jenkins
  2. Cuando lanzamos, se utiliza el complemento de lanzamiento de Maven. El flujo de trabajo de eso está cubierto en la documentación del complemento. El complemento de lanzamiento de Maven apesta (y estoy siendo amable) pero funciona. Un día planeamos reemplazar este método con algo más óptimo.
  3. Cuando se lanza uno de los proyectos, jenkins ejecuta un trabajo especial y llamaremos al trabajo de actualización de todas las versiones (cómo jenkins sabe que es un lanzamiento es una manera complicada en parte porque el complemento de lanzamiento de maven jenkins también es bastante malo).
  4. El trabajo de actualización de todas las versiones conoce los 20 proyectos. En realidad, es un pom agregador para ser específico con todos los proyectos en la sección de módulos en orden de dependencia. Jenkins ejecuta nuestro magic groovy / bash foo que hará que todos los proyectos actualicen las versiones a la última y luego registre los poms (nuevamente hecho en orden de dependencia según la sección de módulos).
  5. Para cada proyecto si el pom ha cambiado (debido a un cambio de versión en alguna dependencia), se registra y luego inmediatamente hacemos ping a jenkins para ejecutar el trabajo correspondiente para ese proyecto (esto es para preservar el orden de dependencia de compilación, de lo contrario, está a merced del planificador de encuestas SCM).

En este punto, creo que es bueno tener el lanzamiento y la versión automática de una herramienta separada de su compilación general de todos modos.

Ahora puede pensar que Maven apesta debido a los problemas enumerados anteriormente, pero esto en realidad sería bastante difícil con una herramienta de compilación que no tiene una sintaxis extensible declarativa fácil de analizar (también conocida como XML).

De hecho, agregamos atributos XML personalizados a través de espacios de nombres para ayudar a insinuar los scripts bash / groovy (por ejemplo, no actualice esta versión).

Adam Gent
fuente
55
Gracias por incluir una motivación (despliegue continuo) en su respuesta.
David J. Liszewski
10
Creo que el punto importante aquí es que las compilaciones son reproducibles con este método, mientras que, al usar rangos de versión o -LATEST, ¡no lo son!
marc.guenther
Me gustaría secundar la solución usando una herramienta externa que realiza cambios en el proyecto pom antes de ejecutar build. También estamos utilizando este enfoque ya que el plugin de rango de versiones está intrínsecamente dañado, por ejemplo, teniendo en cuenta las fechas y no solo las versiones.
Daniel Hajduk
37

La sintaxis de dependencias se encuentra en la documentación de Especificación de requisitos de versión de dependencia . Aquí está para completar:

El versionelemento de dependencias define los requisitos de versión, utilizados para calcular la versión de dependencia efectiva. Los requisitos de versión tienen la siguiente sintaxis:

  • 1.0: Requisito "suave" en 1.0 (solo una recomendación, si coincide con todos los demás rangos para la dependencia)
  • [1.0]: Requisito "duro" en 1.0
  • (,1.0]: x <= 1.0
  • [1.2,1.3]: 1.2 <= x <= 1.3
  • [1.0,2.0): 1.0 <= x <2.0
  • [1.5,): x> = 1.5
  • (,1.0],[1.2,): x <= 1.0 o x> = 1.2; varios conjuntos están separados por comas
  • (,1.1),(1.1,): esto excluye 1.1 (por ejemplo, si se sabe que no funciona en combinación con esta biblioteca)

En tu caso, podrías hacer algo como <version>[1.2.3,)</version>

mkobit
fuente
15

¿Posiblemente dependas de versiones de desarrollo que obviamente cambian mucho durante el desarrollo?

En lugar de incrementar la versión de las versiones de desarrollo, podría usar una versión de instantánea que sobrescriba cuando sea necesario, lo que significa que no tendría que cambiar la etiqueta de versión en cada cambio menor. Algo así como 1.0-SNAPSHOT ...

Pero tal vez estás tratando de lograr algo más;)

Martin Klinke
fuente
7

Quien esté usando ÚLTIMO, asegúrese de tener -U, de lo contrario, no se extraerá la última instantánea.

mvn -U dependency:copy -Dartifact=com.foo:my-foo:LATEST
// pull the latest snapshot for my-foo from all repositories
trung
fuente
incluso usando el -UI que estoy recibiendoCouldn't download artifact: Failed to resolve version for com.app:common:jar:LATEST
Robert
7

En el momento en que se planteó esta pregunta, había algunos problemas con los rangos de versión en maven, pero estos se han resuelto en versiones más recientes de maven. Este artículo captura muy bien cómo funcionan los rangos de versiones y las mejores prácticas para comprender mejor cómo Maven entiende las versiones: https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855

bclarance
fuente
2
Si bien esto puede responder teóricamente la pregunta, sería preferible incluir aquí las partes esenciales de la respuesta y proporcionar el enlace para referencia.
Karl Richter
6

La verdad es que incluso en 3.x todavía funciona, sorprendentemente, los proyectos se construyen y se implementan. Pero la palabra clave LATEST / RELEASE que causa problemas en m2e y eclipse por todas partes, TAMBIÉN los proyectos dependen de la dependencia que se implementó a través de LATEST / RELEASE no reconocen la versión.

También causará problemas si intenta definir la versión como propiedad y hacer referencia a ella en otro lugar.

Entonces, la conclusión es usar las versiones-maven-plugin si puedes.

Junchen Liu
fuente
5

A veces no desea usar rangos de versiones, porque parece que son "lentos" para resolver sus dependencias, especialmente cuando hay una entrega continua y hay toneladas de versiones, principalmente durante el desarrollo pesado.

Una solución alternativa sería utilizar las versiones-maven-plugin . Por ejemplo, puede declarar una propiedad:

<properties>
    <myname.version>1.1.1</myname.version>
</properties>

y agregue las versiones-maven-plugin a su archivo pom:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>versions-maven-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <properties>
                    <property>
                        <name>myname.version</name>
                        <dependencies>
                            <dependency>
                                <groupId>group-id</groupId>
                                <artifactId>artifact-id</artifactId>
                                <version>latest</version>
                            </dependency>
                        </dependencies>
                    </property>
                </properties>
            </configuration>
        </plugin>
    </plugins>
</build>

Luego, para actualizar la dependencia, debe ejecutar los objetivos:

mvn versions:update-properties validate

Si hay una versión más nueva que la 1.1.1, te dirá:

[INFO] Updated ${myname.version} from 1.1.1 to 1.3.2
Marcar en
fuente
3

Si desea que Maven use la última versión de una dependencia, puede usar el complemento Versions Maven y cómo usar este complemento, Tim ya ha dado una buena respuesta, siga su respuesta .

Pero como desarrollador, no recomendaré este tipo de prácticas. ¿POR QUÉ?

respuesta a por qué ya lo dio Pascal Thivent en el comentario de la pregunta

Realmente no recomiendo esta práctica (ni el uso de rangos de versiones) en aras de la reproducibilidad de compilación. Una compilación que comienza a fallar repentinamente por una razón desconocida es mucho más molesta que actualizar manualmente un número de versión.

Recomendaré este tipo de práctica:

<properties>
    <spring.version>3.1.2.RELEASE</spring.version>
</properties>

<dependencies>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

</dependencies>

Es fácil de mantener y fácil de depurar. Puede actualizar su POM en poco tiempo.

Arayan Singh
fuente
Si utiliza versiones-maven-plugin, la compilación sigue siendo reproducible. La actualización de la versión de Maven se puede hacer en una confirmación separada (como puede ver en mi respuesta, debe especificar un objetivo separado, simplemente no sucede mágicamente en la compilación).
Markon el
1

MI solución en maven 3.5.4, usa nexus, en eclipse:

<dependency>
    <groupId>yilin.sheng</groupId>
    <artifactId>webspherecore</artifactId>
    <version>LATEST</version> 
</dependency>

luego en eclipse:, atl + F5y elija elforce update of snapshots/release

esto funciona para mi.

yilin
fuente
Sin embargo, no funcionará en la línea de comando por las razones mencionadas anteriormente en varias publicaciones. Muchos de nosotros tenemos que cumplir con las compilaciones automatizadas, por lo que nuestros POM tienen que funcionar cuando se ejecutan en la línea de comandos, no solo en Eclipse.
bigbadmouse
Estoy usando maven 3.5.4 y obtuve esto cuando uso 'último': es ÚLTIMO o LIBERACIÓN (ambos están en desuso) @ línea 154, columna 13
Leonardo Leonardo