Как получить версию проекта Maven в командной строке bash
Ранее я выпустил вопрос о том, как изменить версию проекта Maven из командной строки, что привело меня к новой проблеме.
Ранее я был в состоянии получить номер версии, так как версия была сохранена как свойство, которое было легко найти и проанализировать из командной строки (bash). Теперь, когда для этого используется элемент pom.xml, он больше не является уникальным, поскольку все зависимости и, возможно, некоторые другие тоже используют это. Я думаю, что нет способа получить номер текущей версии с помощью bash-скрипта без внешних инструментов для разбора xml или какой-либо очень контекстно-зависимой команды sed.
На мой взгляд, самым чистым решением для Maven было бы раздать эту информацию о версии. Я думал о написании собственного плагина maven для извлечения различных свойств, но я решил сначала спросить здесь.
Итак, есть ли простой способ получить значение ${project.version}
в командной строке? Заранее спасибо.
Решение
Спасибо вам за помощь. Мне пришлось cd
в каталог вручную, но это можно сделать легко. В моем скрипте Bash у меня есть
version=`cd $project_loc && mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | sed -n -e '/^\[.*\]/ !{ /^[0-9]/ { p; q } }'`
Что дает мне текущую версию, которую я могу продвинуть. Грэппинг может быть проще, но я подумал, что хотел бы использовать как можно более надёжно, поэтому я доволен первой строкой, которая начинается с числа, и попытаюсь обработать это как номер версии.
# Advances the last number of the given version string by one.
function advance_version () {
local v=$1
# Get the last number. First remove any suffixes (such as '-SNAPSHOT').
local cleaned=`echo $v | sed -e 's/[^0-9][^0-9]*$//'`
local last_num=`echo $cleaned | sed -e 's/[0-9]*\.//g'`
local next_num=$(($last_num+1))
# Finally replace the last number in version string with the new one.
echo $v | sed -e "s/[0-9][0-9]*\([^0-9]*\)$/$next_num/"
}
И я использую это, просто позвонив
new_version=$(advance_version $version)
Надеюсь, это кому-нибудь поможет.
34 ответа
Плагин помощи Maven как-то уже предлагает что-то для этого:
help:evaluate
оценивает выражения Maven, заданные пользователем в интерактивном режиме.
Вот как вы можете вызвать его в командной строке, чтобы получить ${project.version}
:
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
-Dexpression=project.version
Решение Тома с плагином Exec Maven гораздо лучше, но все же сложнее, чем нужно. Для меня это так просто, как:
MVN_VERSION=$(mvn -q \
-Dexec.executable=echo \
-Dexec.args='${project.version}' \
--non-recursive \
exec:exec)
Я провел некоторые исследования и обнаружил следующее:
Maven обвиняют в том, что он не может быть легко интегрирован в сценарии работы системы, поскольку он не следует некоторым рекомендациям относительно инструментов CLI. (ссылка: https://youtu.be/1ILEw6Qca3U?t=372)
Вдохновленный предыдущим утверждением, я решил взглянуть на исходный код maven, а также на плагин maven-help-plugin. Кажется, что они немного исправили ключ -q maven (я использую версию 3.5.3), так что теперь, если вы пропустите его, вы не получите все надоедливые логи, которые не позволяют использовать maven. в рамках автоматизированных сценариев. Таким образом, вы должны быть в состоянии использовать что-то вроде этого:
mvn help:evaluate -Dexpression=project.version -q
Проблема в том, что эта команда ничего не печатает, потому что по умолчанию плагин справки выводится через регистратор, который был отключен ключом -q. (последняя доступная версия плагина - 3.1.0, выпущенная 3 июня 2018 г.)
Карл Хайнц Марбез ( https://github.com/khmarbaise) исправил это, добавив необязательный параметр, который позволяет вызывать его следующим образом:
mvn help:evaluate -Dexpression=project.version -q -DforceStdout
Описание фиксации доступно по адресу: ( https://github.com/apache/maven-help-plugin/commit/316656983d780c04031bbadd97d4ab245c84d014)
Это самое чистое решение, которое я нашел:
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout
Преимущества:
- Это отлично работает на всех операционных системах и всех оболочек.
- Никаких внешних инструментов!
- [важно] Это работает, даже если версия проекта унаследована от родительской
pom.xml
Заметка:
maven-help-plugin
версия3.2.0
(и выше) имеетforceStdout
вариант. Вы можете заменить3.2.0
в приведенной выше команде с более новой версией из списка доступных версий mvn-help-plugin из artifactory, если таковая имеется.- Вариант
-q
подавляет подробные сообщения ([INFO]
,[WARN]
так далее.)
Если вы хотите получить groupId
а также artifactId
а также проверьте этот ответ.
Верхний ответ, по моему мнению, довольно мусор, вы должны использовать кучу grep, чтобы взломать вывод консоли maven. Почему бы не использовать правильный инструмент для работы? Использование синтаксиса xpath - лучший подход к получению номера версии, поскольку это предполагаемый метод доступа к структуре данных XML. Выражение ниже пересекает pom, используя "локальное имя" элементов, другими словами, игнорируя объявления пространства имен, которые могут присутствовать или не присутствовать в xml.
xmllint --xpath "//*[local-name()='project']/*[local-name()='version']/text()" pom.xml
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['
Это позволит избежать необходимости извлечения записей журнала из выходных данных:
mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q
python -c "import xml.etree.ElementTree as ET; \
print(ET.parse(open('pom.xml')).getroot().find( \
'{http://maven.apache.org/POM/4.0.0}version').text)"
Пока у вас есть Python 2.5 или выше, это должно работать. Если у вас более низкая версия, установите python-lxml
и измените импорт на lxml.etree. Этот метод быстрый и не требует загрузки дополнительных плагинов. Он также работает с искаженными файлами pom.xml, которые не проверяются с помощью xmllint, например, те, которые мне нужно проанализировать. Проверено на Mac и Linux.
Я продолжал сталкиваться с дополнительными случаями, когда использовал некоторые другие ответы здесь, так что вот еще одна альтернатива.
version=$(printf 'VER\t${project.version}' | mvn help:evaluate | grep '^VER' | cut -f2)
Существует также один вариант без необходимости Maven:
grep -oPm1 "(?<=<version>)[^<]+" "pom.xml"
Это, безусловно, самое простое решение для вырезания и вставки в bash:
VERSION=$(mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q)
echo $VERSION
это перекликается
1.4
Если вы не возражаете записать версию во временный файл, есть другое решение (без grep/sed), которое мне подходит. (РЕДАКТИРОВАТЬ: см . Ответ Rjrjr для гораздо более простого решения без каких-либо временных файловых хлопот)
Я использую плагин Exec Maven вместе с echo
двоичный файл. В отличие от плагина справки Maven, плагин Exec позволяет перенаправлять вывод в файл, который можно использовать для обхода grep/sed, и даже позволяет анализировать странные вещи, такие как строки многострочных версий (с блоком CDATA в теге версии), по крайней мере, в определенной степени.
#!/usr/bin/env sh
MVN_VERSION=""
VERSION_FILE=$( mktemp mvn_project_version_XXXXX )
trap "rm -f -- \"$VERSION_FILE\"" INT EXIT
mvn -Dexec.executable="echo" \
-Dexec.args='${project.version}' \
-Dexec.outputFile="$VERSION_FILE" \
--non-recursive \
--batch-mode \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec > /dev/null 2>&1 ||
{ echo "Maven invocation failed!" 1>&2; exit 1; }
# if you just care about the first line of the version, which will be
# sufficent for pretty much every use case I can imagine, you can use
# the read builtin
[ -s "$VERSION_FILE" ] && read -r MVN_VERSION < "$VERSION_FILE"
# Otherwise, you could use cat.
# Note that this still has issues when there are leading whitespaces
# in the multiline version string
#MVN_VERSION=$( cat "$VERSION_FILE" )
printf "Maven project version: %s\n" "$MVN_VERSION"
Просто для записи, можно настроить ведение журнала Simple SLF4J в Maven непосредственно в командной строке для вывода только того, что нам нужно, с помощью настройки:
org.slf4j.simpleLogger.defaultLogLevel=WARN
а такжеorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO
как указано на http://www.slf4j.org/api/org/slf4j/impl/SimpleLogger.html
MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version
В результате можно просто запустить tail -1
и получить:
$ MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version | tail -1
1.0.0-SNAPSHOT
Обратите внимание, что это однострочник. MAVEN_OPTS
переписываются только для этого конкретного mvn
выполнение.
Простое решение только для Maven
mvn -q -N org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
-Dexec.executable='echo' \
-Dexec.args='${project.version}'
А за бонусные баллы разбирается часть версии
mvn -q -N org.codehaus.mojo:build-helper-maven-plugin:3.0.0:parse-version \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
-Dexec.executable='echo' \
-Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}'
Я заметил некоторые поддельные Downloaded:
строки, выходящие на выходе, которые нарушали мое первоначальное назначение. Вот фильтр, на котором я остановился; Надеюсь, поможет!
version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n')
РЕДАКТИРОВАТЬ
Не уверен на 100%, почему, но при запуске этого сценария в Jenkins после сборки он получал [INFO]version
например, [INFO]0.3.2
,
Я выгрузил вывод в файл и пропустил его через мой первый фильтр напрямую из BASH, он отлично работает... так что, опять же, я не уверен, что происходит на земле Дженкинс.
Чтобы получить 100% в Дженкинс, я добавил продолжение sed
фильтр; вот мой последний
version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n' | sed -E 's/\[.*\]//g')
РЕДАКТИРОВАТЬ
Последнее замечание здесь.. Я узнал tr
все еще приводил к таким вещам, как /r/n0.3.2
(опять только при запуске через Дженкинс). Перешли на awk
и проблема ушла! Мой окончательный рабочий результат
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version \
| egrep -v '^\[|Downloading:' | sed 's/[^0-9\.]//g' | awk 1 ORS=''
Недавно я разработал плагин Release Candidate Maven, который решает эту проблему, чтобы вам не приходилось прибегать к каким-либо хакерским сценариям оболочки и анализировать выходные данные maven-help-plugin
,
Например, чтобы распечатать версию вашего проекта Maven в терминале, запустите:
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version
который дает вывод, аналогичный maven-help-plugin
:
[INFO] Detected version: '1.0.0-SNAPSHOT'
1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Однако вы также можете указать произвольный формат вывода (чтобы версия могла быть выбрана из журнала сервером CI, таким как TeamCity):
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
-DoutputTemplate="##teamcity[setParameter name='env.PROJECT_VERSION' value='{{ version }}']"
Что приводит к:
[INFO] Detected version: '1.0.0-SNAPSHOT'
##teamcity[setParameter name='env.PROJECT_VERSION' value='1.0.0-SNAPSHOT']
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Чтобы сохранить выходные данные в файл (чтобы его мог использовать CI-сервер, такой как Jenkins):
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
-DoutputTemplate="PROJECT_VERSION={{ version }}" \
-DoutputUri="file://\${project.basedir}/version.properties"
Результирующий version.properties
Файл будет выглядеть следующим образом:
PROJECT_VERSION=1.0.0-SNAPSHOT
Помимо всего вышеперечисленного, Release Candidate также позволяет вам установить версию вашего проекта (что вы, вероятно, будете делать на своем CI-сервере) на основе версии API, которую вы определили в своем POM.
Если вы хотите увидеть пример использования Release Candidate как части жизненного цикла Maven, взгляните на pom.xml
моего другого проекта с открытым исходным кодом - Build Monitor for Jenkins.
Простое в понимании решение "все в одном", которое выводит версию проекта maven и подавляет посторонний вывод [INFO]
а также Download
Сообщения:
mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['
То же самое, но разбить на две строки:
mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
-Dexpression=project.version | grep -v '\['
Выходы: 4.3-SNAPSHOT
Итак, используя ваш project.version
в простом скрипте bash:
projectVersion=`mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['`
cd "target/"$projectVersion"-build"
Другие решения на этой странице, похоже, не объединяют все уловки в одно.
Я нашел правильный баланс для меня. После mvn package
плагин maven-архиватора создает target/maven-archiver/pom.properties
с таким содержанием
version=0.0.1-SNAPSHOT
groupId=somegroup
artifactId=someArtifact
и я использую Bash только для его выполнения
. ./target/maven-archiver/pom.properties
затем
echo $version
0.0.1-SNAPSHOT
Конечно, запуск этого файла вовсе не безопасен, но его можно легко преобразовать в сценарий perl или bash для чтения и установки переменной окружения из этого файла.
Это работало для меня, в автономном режиме и вне зависимости от mvn:
VERSION=$(grep --max-count=1 '<version>' <your_path>/pom.xml | awk -F '>' '{ print $2 }' | awk -F '<' '{ print $1 }')
echo $VERSION
Должно быть проще, так как эта ошибка исправлена в maven-help-plugin 3.0.0: MPH-99 Evaluate не выводит в тихом режиме.
Добавьте следующий плагин в свой
pom.xml
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>generate-version-file</id>
<phase>prepare-package</phase>
<goals>
<goal>evaluate</goal>
</goals>
<configuration>
<expression>project.version</expression>
<output>${project.build.directory}/version.txt</output>
</configuration>
<execution>
</executions>
</plugin>
...
Это создаст
target/version.txt
файл как обычная часть вашей сборки.
Все, что вам нужно сделать, чтобы передать это в оболочку, это следующее:
#!/bin/sh
value=`cat target/version.txt`
echo "$value"
#!/bin/bash
value=$(<target/version.txt)
echo "$value"
Либо у вас есть mvn
дать вам ответ (как предлагает большинство ответов), или вы извлекаете ответ из pom.xml
, Единственным недостатком второго подхода является то, что вы можете очень легко извлечь значение <version/>
тег, но он будет иметь смысл только в том случае, если он буквальный, то есть не является свойством Maven. Я все равно выбрал этот подход, потому что:
mvn
это способ многословия, и я просто не люблю фильтровать его вывод.- начало
mvn
очень медленно по сравнению с чтениемpom.xml
, - Я всегда использую буквальные значения в
<version/>
,
mvn-version
это zsh
сценарий оболочки, который использует xmlstarlet
читать pom.xml
и распечатайте версию проекта (если он существует) или версию родительского проекта (если он существует):
$ mvn-version .
1.0.0-SNAPSHOT
Преимущество в том, что это намного быстрее, чем бег mvn
:
$ time mvn-version .
1.1.0-SNAPSHOT
mvn-version . 0.01s user 0.01s system 75% cpu 0.019 total
$ time mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
> -Dexpression=project.version
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate 4.17s user 0.21s system 240% cpu 1.823 total
Разница на моей машине больше двух порядков.
Основываясь на вопросе, я использую этот сценарий ниже для автоматического увеличения номера моей версии во всех родительских / подмодулях maven:
#!/usr/bin/env bash
# Advances the last number of the given version string by one.
function advance\_version () {
local v=$1
\# Get the last number. First remove any suffixes (such as '-SNAPSHOT').
local cleaned=\`echo $v | sed \-e 's/\[^0-9\]\[^0-9\]\*$//'\`
local last\_num=\`echo $cleaned | sed \-e 's/\[0-9\]\*\\.//g'\`
local next\_num=$(($last\_num+1))
\# Finally replace the last number in version string with the new one.
echo $v | sed \-e "s/\[0-9\]\[0-9\]\*\\(\[^0-9\]\*\\)$/$next\_num/"
}
version=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)
new\_version=$(advance\_version $version)
mvn versions:set -DnewVersion=${new\_version} -DprocessAllModules -DgenerateBackupPoms=false
Плагин Exec работает без разбора вывода, потому что вывод может быть перенаправлен в файл и вставлен обратно в рабочую среду через плагин EnvInject:
Самый быстрый способ получить только текст без обрезки
mvn help:evaluate -q -DforceStdout -D"expression=project.version"
Альтернативой может быть синтаксический анализ с помощью yq (https://github.com/kislyuk/yq) следующим образом:
cat pom.xml | xq -r '.project.version'
Обратите внимание, что исполняемый файл - это xq, а не yq
Чтобы получить xq, установите yq вот так
pip install yq
В контейнерах докеров, где доступен только busybox, я использую awk.
version=$(
awk '
/<dependenc/{exit}
/<parent>/{parent++};
/<version>/{
if (parent == 1) {
sub(/.*<version>/, "");
sub(/<.*/, "");
parent_version = $0;
} else {
sub(/.*<version>/, "");
sub(/<.*/, "");
version = $0;
exit
}
}
/<\/parent>/{parent--};
END {
print (version == "") ? parent_version : version
}' pom.xml
)
Примечания:
- Если версия артефакта не указана, вместо нее печатается родительская версия.
- Зависимости должны идти после артефакта и родительской версии. (Это можно легко преодолеть, но мне это не нужно.)
Мне нужно именно это требование во время моей работы в Трэвисе, но с несколькими значениями. Я начинаю с этого решения, но при многократном вызове это очень медленно (мне нужно 5 выражений).
Я написал простой плагин maven для извлечения значений pom.xml в файл.sh.
https://github.com/famaridon/ci-tools-maven-plugin
mvn com.famaridon:ci-tools-maven-plugin:0.0.1-SNAPSHOT:environment -Dexpressions=project.artifactId,project.version,project.groupId,project.build.sourceEncoding
Произведем это:
#!/usr/bin/env bash
CI_TOOLS_PROJECT_ARTIFACTID='ci-tools-maven-plugin';
CI_TOOLS_PROJECT_VERSION='0.0.1-SNAPSHOT';
CI_TOOLS_PROJECT_GROUPID='com.famaridon';
CI_TOOLS_PROJECT_BUILD_SOURCEENCODING='UTF-8';
теперь вы можете просто указать источник файла
source .target/ci-tools-env.sh
Радоваться, веселиться.
mvn help:evaluate -Dexpression=project.version | sed -e 1h -e '2,3{H;g}' -e '/\[INFO\] BUILD SUCCESS/ q' -e '1,2d' -e '{N;D}' | sed -e '1q'
Я просто добавляю маленький sed
Улучшение фильтра, которое я недавно реализовал для извлечения project.version
из Maven выхода.
VERSION=$(mvn -version | grep 'Apache Maven' | grep -o '[0-9].[0-9].[0-9]')
echo $VERSION