Como digo ao Maven para usar a versão mais recente de uma dependência?

788

No Maven, as dependências geralmente são configuradas assim:

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

Agora, se você estiver trabalhando com bibliotecas que possuem lançamentos frequentes, a atualização constante da tag <versão> pode ser um pouco irritante. Existe alguma maneira de dizer ao Maven para sempre usar a versão mais recente disponível (no repositório)?

Anders Sandvig
fonte
@ Martin Estou ciente da convenção xyz-SNAPSHOT, mas estava pensando nas bibliotecas lançadas nas versões finais para o repositório (ou seja, passando de dream-library-1.2.3.jar para dream-library-1.2.4.jar , e assim por diante).
Anders Sandvig
176
Realmente não recomendo esta prática (nem uso de intervalos de versões) para a reprodutibilidade de compilação. Uma compilação que começa a falhar repentinamente por um motivo desconhecido é muito mais irritante do que atualizar manualmente um número de versão.
Pascal Thivent
12
@PascalThivent Atualizar manualmente um número de release em um pom é uma dor se você estiver fazendo lançamentos contínuos. Eu uso o plug-in de versões combinado com o plug-in scm para superar isso (veja minha resposta).
Adam Gent
4
@ PascalThivent Ambos são irritantes, mas de uma maneira diferente. Eu gostaria de escolher entre os dois dependentes da minha situação e não ser forçado a usar um, porque alguém decidiu que este seria melhor.
piegames 02/02

Respostas:

745

NOTA:

Esta resposta se aplica apenas ao Maven 2! As mencionadas LATESTe RELEASEmetaversões foram descartadas no Maven 3 "por uma questão de construções reproduzíveis" , há mais de 6 anos. Consulte esta solução compatível com Maven 3 .


Se você sempre deseja usar a versão mais recente, o Maven possui duas palavras-chave que podem ser usadas como alternativa aos intervalos de versão. Você deve usar essas opções com cuidado, pois não está mais no controle dos plugins / dependências que está usando.

Quando você depende de um plug-in ou de uma dependência, pode usar o valor de uma versão de LATEST ou RELEASE. LATEST refere-se à versão mais recente lançada ou de captura instantânea de um artefato específico, o artefato implementado mais recentemente em um repositório específico. RELEASE refere-se à última versão não instantânea no repositório. Em geral, não é uma prática recomendada projetar software que dependa de uma versão não específica de um artefato. Se você estiver desenvolvendo software, convém usar RELEASE ou LATEST como uma conveniência para não precisar atualizar os números de versão quando uma nova versão de uma biblioteca de terceiros for lançada. Ao liberar o software, você deve sempre garantir que seu projeto dependa de versões específicas para reduzir as chances de sua compilação ou seu projeto serem afetados por uma liberação de software que não esteja sob seu controle.

Consulte a seção POM Syntax do livro Maven para obter mais detalhes. Ou consulte este documento em intervalos de versão de dependência , onde:

  • Um colchete ( [& ]) significa "fechado" (inclusive).
  • Um parêntese ( (& )) significa "aberto" (exclusivo).

Aqui está um exemplo que ilustra as várias opções. No repositório do Maven, com.foo:my-foo possui os seguintes metadados:

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

Se for necessária uma dependência desse artefato, você terá as seguintes opções ( é claro que outros intervalos de versão podem ser especificados, apenas mostrando os relevantes aqui):

Declare uma versão exata (sempre será resolvida para 1.0.1):

<version>[1.0.1]</version>

Declare uma versão explícita (sempre resolverá a 1.0.1, a menos que ocorra uma colisão, quando o Maven selecionar uma versão correspondente):

<version>1.0.1</version>

Declare um intervalo de versão para todos os 1.x (atualmente resolverá para 1.1.1):

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

Declare um intervalo de versão em aberto (será resolvido para 2.0.0):

<version>[1.0.0,)</version>

Declare a versão como ÚLTIMA (será resolvida para 2.0.0) (removida do maven 3.x)

<version>LATEST</version>

Declare a versão como RELEASE (será resolvida para 1.1.1) (removida do maven 3.x):

<version>RELEASE</version>

Observe que, por padrão, suas próprias implantações atualizarão a entrada "mais recente" nos metadados do Maven, mas para atualizar a entrada "release", é necessário ativar o "perfil de liberação" do super POM do Maven . Você pode fazer isso com "-Prelease-profile" ou "-DperformRelease = true"


Vale ressaltar que qualquer abordagem que permita ao Maven escolher as versões de dependência (LATEST, RELEASE e intervalos de versão) pode deixá-lo aberto para criar problemas de tempo, pois versões posteriores podem ter um comportamento diferente (por exemplo, o plug-in de dependência alterou anteriormente o padrão valor de verdadeiro a falso, com resultados confusos).

Portanto, geralmente é uma boa ideia definir versões exatas nos lançamentos. Como a resposta de Tim aponta, o maven-version-plugin é uma ferramenta útil para atualizar as versões de dependência, particularmente as versões: use-latest-versions e versions: use-latest-releases goals.

Vendedor rico
fonte
76
Oi rico! Parece RELEASE e mais recentes marcadores versão são não suportados no Maven 3.x .
Pascal Thivent
16
Essa depreciação parece aplicar-se apenas aos plugins em vez de dependências normais se eu entendi o documento corretamente
Mond Raymond
9
@ RichSeller hey Rich; Passei um pouco de tempo nisso antes de descobrir que isso não está mais disponível no Maven 3.0;) Você consideraria editar a resposta para que ela comece com uma atualização informando a depreciação do Maven 3.0? Muito obrigado!
Miquel
6
Acredito que um bom equilíbrio seria bloquear a versão principal, mas obter a versão menor (ou patch) mais recente (a que for usada para correções de bugs apenas no artefato em que você está dependendo). Com a sintaxe atual Esta parece ser só é possível com uma gama como (nota: começa com suportes e termina com parênteses):[1.1,2.0)
Amr Mostafa
2
FWIW ... link atualizado para Maven3 Compatibilidade Notas: cwiki.apache.org/confluence/display/MAVEN/...
dyodji
384

Agora eu sei que esse tópico é antigo, mas lendo a pergunta e a resposta fornecida pelo OP, parece que o Maven Versions Plugin pode ter sido realmente uma resposta melhor para sua pergunta:

Em particular, os seguintes objetivos podem ser úteis:

  • versões: use-latest-versões procura no pom todas as versões que foram uma versão mais recente e as substitui pela versão mais recente.
  • versões: use-latest-releases procura no pom todas as versões que não sejam do SNAPSHOT que foram uma versão mais recente e as substitui pela versão mais recente.
  • Versões: update-properties atualiza as propriedades definidas em um projeto para que correspondam à versão mais recente disponível de dependências específicas. Isso pode ser útil se um conjunto de dependências tiver que ser bloqueado para uma versão.

Os outros objetivos a seguir também são fornecidos:

  • versões: exibir-dependência-atualizações varre as dependências de um projeto e produz um relatório dessas dependências que possuem versões mais recentes disponíveis.
  • versões: display-plugin-updates verifica os plug-ins de um projeto e produz um relatório desses plug-ins que possuem versões mais recentes disponíveis.
  • versões: update-parent atualiza a seção pai de um projeto para que faça referência à versão mais recente disponível. Por exemplo, se você usar um POM raiz corporativo, esse objetivo poderá ser útil se você precisar garantir que está usando a versão mais recente do POM raiz corporativo.
  • versões: update-child-modules atualiza a seção pai dos módulos filhos de um projeto para que a versão corresponda à versão do projeto atual. Por exemplo, se você possui um pom agregador que também é o pai dos projetos que ele agrega e as versões filho e pai ficam fora de sincronia, esse mojo pode ajudar a corrigir as versões dos módulos filhos. (Observe que pode ser necessário chamar o Maven com a opção -N para executar esse objetivo, se o seu projeto estiver com problemas tão graves que não puder ser construído por causa da incompatibilidade de versão).
  • versões: o lock-snapshots procura no pom todas as versões -SNAPSHOT e as substitui pela versão atual do registro de data e hora desse -SNAPSHOT, por exemplo, -20090327.172306-4
  • versões: unlock-snapshots procura no pom todas as versões de snapshot bloqueado de carimbo de data e hora e as substitui por -SNAPSHOT.
  • versões: resolver-intervalos localiza dependências usando intervalos de versões e resolve o intervalo para a versão específica que está sendo usada.
  • versões: use-releases procura no pom todas as versões -SNAPSHOT que foram lançadas e as substitui pela versão correspondente.
  • versões: use-next-releases procura no pom todas as versões que não sejam do SNAPSHOT que foram uma versão mais recente e as substitui pela próxima versão.
  • versões: use-next-versions procura no pom todas as versões que foram uma versão mais recente e as substitui pela próxima versão.
  • versões: confirmar remove os arquivos pom.xml.versionsBackup. Forma metade do "SCM do pobre homem" incorporado.
  • versões: revert restaura os arquivos pom.xml dos arquivos pom.xml.versionsBackup. Forma metade do "SCM do pobre homem" incorporado.

Apenas pensei em incluí-lo para qualquer referência futura.

Tim
fonte
10
Nesse contexto, qual é a diferença entre "release" e "version".
precisa
1
@ BenNoland, acredito que a diferença neste caso é que a próxima versão pode não precisar ser um artefato de lançamento. Por exemplo, dado um artefato com versão 1.0.0-SNAPSHOT, 1.0.0 e 1.0.1-SNAPSHOT, e uma referência de pom a 1.0.0-SNAPSHOT, versões: próximas versões e versões: as próximas versões serão resolvidas para 1.0.0 , enquanto as versões: versões mais recentes e versões: lançamentos mais recentes serão resolvidos para 1.0.1-SNAPSHOT e 1.0.0, respeitosamente.
precisa
1
Você pode resolver algumas incertezas entre versões / releases / snapshots nesta tabela muito agradável aqui: goo.gl/iDq6PK
Ev0oD
1
Imprimir todas as metas possíveis e não relacionadas não é útil.
MariuszS
2
Eu pensaria em versões: use-latest-versões resolve a maioria dos problemas do OP.
Alex R
172

Por favor, dê uma olhada nesta página (seção "Intervalos de versão de dependência"). O que você pode querer fazer é algo como

<version>[1.2.3,)</version>

Esses intervalos de versão são implementados no Maven2.

Martin Klinke
fonte
Por algum motivo, essa opção não funcionou para mim; ele escolheu uma versão dentro do intervalo, mas não a mais nova.
sorin
4
Você pode ter uma visão mais detalhada de como o Maven compara os números de versão - se você não se conforma a um padrão estrito, o Maven compara como strings e não como números.
Thorbjørn Ravn Andersen
Essa página está no Codehaus e se descreve como coisas "que ainda não foram implementadas para o Maven 2.0" ... A documentação do Maven em si não diz nada sobre os intervalos de versão. Estou esquecendo de algo? Quando os intervalos de versão foram introduzidos? Onde eles estão descritos na documentação oficial?
Shannon
1
Você está errado, o intervalo de versões significa que todas as versões estão OK da 1.2.3 para superior. Esta não é a versão mais recente.
MariuszS
@sorin Talvez você tenha outras dependências em seu projeto que também dependem do artefato em questão? Tente mvn dependency:tree -Dverbosedescobrir isso. Isso poderia explicar a versão inesperada.
Eugene Beresovsky
83

Ao contrário de outros, acho que há muitas razões pelas quais você pode sempre querer a versão mais recente. Especialmente se você estiver fazendo uma implantação contínua (às vezes temos 5 lançamentos em um dia) e não quiser fazer um projeto com vários módulos.

O que faço é fazer com que o Hudson / Jenkins faça o seguinte para cada build:

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

Ou seja, eu uso o plug-in de versões e o plug-in scm para atualizar as dependências e depois faço check-in no controle de origem. Sim, deixei meus CI fazerem check-ins de SCM (o que você precisa fazer de qualquer maneira para o plugin maven release).

Você desejará configurar o plug-in de versões para atualizar apenas o que deseja:

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

Eu uso o plug-in de liberação para fazer a liberação que cuida de -SNAPSHOT e valida a existência de uma versão do -SNAPSHOT (que é importante).

Se você fizer o que eu faço, obterá a versão mais recente para todas as compilações de snapshots e a versão mais recente para compilações de release. Suas compilações também serão reproduzíveis.

Atualizar

Percebi alguns comentários perguntando alguns detalhes desse fluxo de trabalho. Eu direi que não usamos mais esse método e a grande razão pela qual o plug-in maven version é incorreto e, em geral, é inerentemente defeituoso.

É falha porque, para executar o plug-in de versões para ajustar as versões, todas as versões existentes precisam existir para que o pom funcione corretamente. Ou seja, o plug-in de versões não pode atualizar para a versão mais recente de nada, se não conseguir encontrar a versão mencionada no pom. Isso é realmente bastante irritante, pois geralmente limpamos versões antigas por motivos de espaço em disco.

Você realmente precisa de uma ferramenta separada do maven para ajustar as versões (para que não dependa do arquivo pom para executar corretamente). Eu escrevi essa ferramenta na linguagem humilde que é o Bash. O script atualizará as versões como o plugin da versão e verificará o pom novamente no controle de origem. Também funciona 100x mais rápido que o plugin mvn version. Infelizmente, ele não está escrito de maneira a ser usado pelo público, mas se as pessoas estiverem interessadas, eu poderia fazê-lo e colocá-lo em uma essência ou github.

Voltando ao fluxo de trabalho, como alguns comentários perguntaram sobre isso, é o que fazemos:

  1. Temos mais ou menos 20 projetos em seus próprios repositórios, com seus próprios trabalhos de Jenkins
  2. Quando lançamos o plugin maven release é usado. O fluxo de trabalho disso é coberto na documentação do plug-in. O plug-in do maven release meio que é péssimo (e eu estou sendo gentil), mas funciona. Um dia, planejamos substituir esse método por algo mais ideal.
  3. Quando um dos projetos é lançado, o jenkins executa um trabalho especial que chamaremos de atualização de todas as versões (como o jenkins sabe que o lançamento é uma maneira complicada, em parte porque o plug-in do maven jenkins também é muito ruim).
  4. O trabalho de atualização de todas as versões conhece todos os 20 projetos. Na verdade, é um agregador para ser específico com todos os projetos na seção de módulos em ordem de dependência. Jenkins executa o nosso groovy / bash foo mágico que puxa todos os projetos, atualiza as versões para as últimas e depois faz check-in dos poms (novamente feito em ordem de dependência, com base na seção de módulos).
  5. Para cada projeto, se o pom foi alterado (por causa de uma alteração de versão em alguma dependência), ele é verificado e, imediatamente, fazemos ping no jenkins para executar o trabalho correspondente para esse projeto (isso é para preservar a ordem de dependência da compilação, caso contrário você estará à mercê do planejador SCM Poll).

Neste ponto, sou da opinião de que é bom ter a versão automática e de lançamento uma ferramenta separada da sua compilação geral.

Agora você pode pensar que é meio ruim por causa dos problemas listados acima, mas isso seria bastante difícil com uma ferramenta de construção que não possui uma declarativa fácil de analisar sintaxe extensível (também conhecida como XML).

De fato, adicionamos atributos XML personalizados através de namespaces para ajudar a sugerir scripts bash / groovy (por exemplo, não atualize esta versão).

Adam Gent
fonte
5
Obrigado por incluir uma motivação (implantação contínua) em sua resposta.
David J. Liszewski
10
Eu acho que o ponto importante aqui que as compilações são reproduzíveis com esse método, enquanto que, ao usar intervalos de versões ou -LATEST, elas não são!
Marcel.guenther
Gostaria de secundar a solução usando uma ferramenta externa que faz alterações no projeto pom antes de executar a compilação. Também estamos usando essa abordagem, pois o plug-in de intervalo de versão é inerentemente corrigido, por exemplo, levando em consideração datas e não apenas versões.
Daniel Hajduk
37

A sintaxe das dependências está localizada na documentação da Especificação de Requisitos de Versão de Dependência . Aqui está a integridade:

O versionelemento Dependencies define os requisitos de versão, usados ​​para calcular a versão de dependência efetiva. Os requisitos de versão têm a seguinte sintaxe:

  • 1.0: Requisito "Soft" na versão 1.0 (apenas uma recomendação, se corresponder a todos os outros intervalos para a dependência)
  • [1.0]: Requisito "rígido" no 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 ou x> = 1,2; vários conjuntos são separados por vírgula
  • (,1.1),(1.1,): exclui 1.1 (por exemplo, se for conhecido que não funciona em combinação com esta biblioteca)

No seu caso, você poderia fazer algo como <version>[1.2.3,)</version>

mkobit
fonte
15

Você possivelmente depende de versões de desenvolvimento que obviamente mudam bastante durante o desenvolvimento?

Em vez de incrementar a versão das liberações de desenvolvimento, você pode simplesmente usar uma versão de instantâneo que você sobrescreve quando necessário, o que significa que você não precisaria alterar a tag da versão em todas as alterações menores. Algo como 1.0-SNAPSHOT ...

Mas talvez você esteja tentando conseguir outra coisa;)

Martin Klinke
fonte
7

Quem já está usando LATEST, verifique se possui -U, caso contrário, o snapshot mais recente não será obtido.

mvn -U dependency:copy -Dartifact=com.foo:my-foo:LATEST
// pull the latest snapshot for my-foo from all repositories
enfiado
fonte
mesmo usando o am -ui recebendoCouldn't download artifact: Failed to resolve version for com.app:common:jar:LATEST
Robert
7

No momento em que essa pergunta foi feita, havia algumas distorções com os intervalos de versão no maven, mas eles foram resolvidos nas versões mais recentes do maven. Este artigo captura muito bem como os intervalos de versões funcionam e as práticas recomendadas para entender melhor como o maven entende as versões: https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855

clarificação
fonte
2
Embora isso possa teoricamente responder à pergunta, seria preferível incluir aqui as partes essenciais da resposta e fornecer o link para referência.
Karl Richter
6

A verdade é que mesmo no 3.x ainda funciona, surpreendentemente, os projetos são construídos e implantados. Mas a palavra-chave LATEST / RELEASE causando problemas no m2e e no eclipse por todo o lado, os projetos TAMBÉM dependem da dependência implementada por meio do LATEST / RELEASE falha ao reconhecer a versão.

Isso também causará problemas se você tentar definir a versão como propriedade e referenciá-la em outro local.

Portanto, a conclusão é usar o plugin versões-maven, se possível.

Junchen Liu
fonte
5

Às vezes, você não deseja usar intervalos de versões, porque parece que eles são "lentos" para resolver suas dependências, especialmente quando há entrega contínua em vigor e há várias versões - principalmente durante o desenvolvimento pesado.

Uma solução alternativa seria usar o plugin de versões maven . Por exemplo, você pode declarar uma propriedade:

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

e adicione o plugin-versões-maven-ao seu arquivo 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>

Então, para atualizar a dependência, você deve executar os objetivos:

mvn versions:update-properties validate

Se houver uma versão mais recente que a 1.1.1, ela informará:

[INFO] Updated ${myname.version} from 1.1.1 to 1.3.2
Markon
fonte
3

Se você quiser que o Maven use a versão mais recente de uma dependência, use o Versions Maven Plugin e como usar esse plugin, Tim já deu uma boa resposta, siga a resposta dele .

Mas como desenvolvedor, não vou recomendar esse tipo de prática. PORQUE?

responda por que já é dado por Pascal Thivent no comentário da pergunta

Realmente não recomendo esta prática (nem uso de intervalos de versões) por uma questão de reprodutibilidade de compilação. Uma compilação que começa a falhar repentinamente por um motivo desconhecido é muito mais irritante do que atualizar manualmente um número de versão.

Vou recomendar este tipo de prática:

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

é fácil de manter e fácil de depurar. Você pode atualizar seu POM rapidamente.

Arayan Singh
fonte
se você usar o version-maven-plugin, a compilação ainda será reproduzível. A atualização da versão maven pode ser feita em um commit separado (como você pode ver na minha resposta, você precisa especificar um objetivo separado, isso simplesmente não acontece magicamente na compilação).
Markon 8/08/19
1

MINHA solução no maven 3.5.4, use nexus, no eclipse:

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

depois no eclipse:, atl + F5e escolha oforce update of snapshots/release

funciona para mim.

yilin
fonte
Não funcionará na linha de comando, embora por razões habilmente declaradas acima em vários posts. Muitos de nós precisam obedecer às compilações automatizadas e, portanto, nossos POMs precisam trabalhar quando executados na linha de comando, não apenas no Eclipse.
Bigbadmouse 16/10/19
Eu estou usando Maven 3.5.4 e tenho esse quando se usa 'mais recente': é ou ÚLTIMAS ou RELEASE (ambos estão sendo reprovado) @ linha 154, coluna 13
Leonardo Leonardo