在 Jenkins 中从 Maven POM 获取项目版本

Posted

技术标签:

【中文标题】在 Jenkins 中从 Maven POM 获取项目版本【英文标题】:Getting Project Version from Maven POM in Jenkins 【发布时间】:2012-04-11 05:14:33 【问题描述】:

在处理 POM 后,Jenkins 构建是否可以知道项目的 Maven 版本号?

我有一些项目的版本控制由 Maven 控制,在构建后的工作中,我们想创建一个 Debian 包并调用一些 shell 脚本。我需要的是 Maven 曾经可用作 Jenkins 环境变量的版本号,以便我可以将其传递给构建后操作。

明确地说,我不需要知道如何让 Jenkins 将版本号传递给 Maven;相反,我希望 Maven 将版本号传递给 Jenkins!

【问题讨论】:

只是一个建议:这个怎么样:mojo.codehaus.org/deb-maven-plugin 【参考方案1】:

基于@Akom`s answer,拥有 POM_VERSION 的前置步骤是:

    带有属性的“注入环境变量” 归档 your_property_file。请注意,如果您选择“将环境变量注入构建过程”,则该文件需要存在于 jenkins 工作区中。 在一个 pre 步骤中运行,执行以下 shell bash 脚本。

脚本

mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version -l project_version
# grep for the version pattern rather than not mentioning '\['
echo "POM_VERSION=$(grep -E  '^[0-9.]+(-SNAPSHOT)?$' project_version)" > your_property_file

【讨论】:

【参考方案2】:

使用“执行系统 ​​Groovy 脚本”如下:

import jenkins.util.*;
import jenkins.model.*;

def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def projectManager = build.getProject()
def file = projectManager.getWorkspace().child("pom.xml");
def project = new XmlSlurper().parseText(file.readToString())

def param = new hudson.model.StringParameterValue("currentVersion", project.version.toString())
currentBuild.addAction(new hudson.model.ParametersAction(param));

通过使用 Execute System Groovy 脚本,您可以直接访问构建,您可以从中获取项目以及在本例中为 pom.xml 的“子”文件。

您不必创建新文件,正如您所见,它提供了对工作区中每个文件的非常强大的访问权限。

【讨论】:

感谢您提供此代码 sn-p,它可能会提供一些有限的短期帮助。一个正确的解释would greatly improve 它的长期价值通过展示为什么这是一个很好的解决问题的方法,并将使它对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。【参考方案3】:

我在声明性管道作业中使用Pipeline Utility Steps 插件来获取 Maven 版本。在下面的示例中,我使用脚本变量而不是环境变量,因为它可以在阶段之间修改和传递。

def TAG_SELECTOR = "UNINTIALIZED"
pipeline 
    agent any
    stages 
        stage('Build') 
            steps 
                sh "mvn --batch-mode -U deploy"
                script 
                    TAG_SELECTOR = readMavenPom().getVersion()
                
                echo("TAG_SELECTOR=$TAG_SELECTOR")
            
        
    

注意:管理jenkins > In-process Script Approval中创建作业后必须批准getVersion()方法。 p>

另见:

readMavenPom documentation

【讨论】:

超级简单,优雅,可靠! (请注意,您不需要在 Groovy 中使用完整的语法 getVersion(),您可以简单地使用 .version。) 管理员可能需要grant approval for the readMavenPom().getVersion()【参考方案4】:

解决方案:

POM_VERSION=$( \
    xmlstarlet sel \
    -N x='http://maven.apache.org/POM/4.0.0' \
    -t \
    -v '//x:project/x:version/text()' \
    pom.xml \
)

说明:

您可以使用命令行 XPath 工具在单行中执行此操作,例如“How to execute XPath one-liners from shell?”中提到的那些。我选择了XMLStarlet,但它们都有相似的语法。

解析 POM 时,您必须考虑命名空间。文档here 帮助我解决了这个问题。

为了在 XPath 中获取元素的文本,您可以使用 XPath: select text node 中解释的 text() 函数。

我的 POM 如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.foo.bar</groupId>
    <artifactId>foobar</artifactId>
    <version>1.0.6-SNAPSHOT</version>
    <packaging>jar</packaging>

这里的缺点是,如果命名空间发生变化,则必须更改命令。

【讨论】:

【参考方案5】:

正如其他答案已经指出的那样,如果您使用的是 Maven 项目类型,则可以访问 $POM_VERSION 变量。但如果你不是,你可以使用这个步骤序列(丑陋但可靠)。这样做依赖于相同版本的 maven 来确定 pom 版本(同时处理复杂的父/子 pom 继承,其中 甚至可能不存在于子级)。

    Maven 迈出这个目标:

    org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version -l version.log

    Shell 步骤:(您可能需要根据层次结构调整 version.log 的路径)

    echo "POM_VERSION=$(grep -v '\[' version.log)" &gt; props.properties

    注入环境变量步骤(环境注入器插件):

    属性文件路径:props.properties

现在您可以像使用 Maven 项目一样使用 $POM_VERSION

这是做什么的:使用 maven 打印出版本和一堆输出,然后 greps 输出的混乱只留下版本,使用属性文件格式将其写入文件,然后将其注入构建环境.这比像mvn ..... | grep -v '\[' 这样的单行代码更好的原因是,使用 Maven 步骤不会对已安装的 maven 版本做出假设,并且将通过与任何其他 maven 步骤相同的自动安装来处理。

【讨论】:

这里的 grep 过滤器存在一个问题:如果存储库中没有插件,您还会在 POM_VERSION 中获得“正在下载...”行。例如:+ echo 'POM_VERSION=Downloading: ... echo "POM_VERSION=$(xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml)" &gt; props.properties 是获取 POM 的另一种方法。它不可移植,依赖于 xmllint。【参考方案6】:

在“执行 Shell”中执行 Maven 插件“exec-maven-plugin”作为“条件步骤”对我有用:

mvn -q -Dexec.executable="echo" -Dexec.args='$projects.version' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec

在 Jenkins 中集成:

-> "Add post-build step"
    -> "Conditional steps (single or multiple)"
        -> "Execute Shell:"

导出 MY_POM_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='$projects.version' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` && [[ "$MY_POM_VERSION" == "THE_VERSION_TO_BE_MATCHED" ]] && 回声 “CONDITION_IS_MET”

    -> "Steps to run if condition is met"
        -> Add any build step you need

注意事项:

THE_VERSION_TO_BE_MATCHED 必须与您的版本交换 '&& echo "CONDITION_IS_MET"' 仅用于调试目的。出于同样的目的,您可以在 mvn 命令后添加一个 '&& echo "MY_POM_VERSION=$MY_POM_VERSION"' 以了解发生了什么。

这种方法比“grep”更可靠,如果没有安装 Jenkins Ruby 插件,它可能是一种替代方法。

【讨论】:

【参考方案7】:

您可以使用 https://issues.jenkins-ci.org/browse/JENKINS-18272 引入的 $POM_VERSION 变量

【讨论】:

太棒了!验证您需要 Jenkins maven 插件 v2.3 或更高版本才能使 `$POM_VERSION` 工作,我认为它需要是 Maven 项目类型。 这对我不起作用。 Jenkins 中的 Maven Interation 插件是 2.5 版,但它仍然显示: $ENV, var="POM_VERSION": bad replacement 如果我尝试直接或通过上述方式使用此变量。内部版本号集插件框中的“$POM_VERSION.$BUILD_NUMBER”中的宏“POM_VERSION”无法识别。 请记住,POM_VERSION 不考虑任何可能已传递给 maven 构建过程的环境变量。例如:$CUSTOM_VERSION 将为空或具有默认值。 POM_VERSION 被错误缓存由于这个错误issues.jenkins-ci.org/browse/JENKINS-24869【参考方案8】:

你也可以这样做:

MAVEN_VERSION=`grep A -2 -B 2 "<your_project_name>" pom.xml | grep version | cut -d\> -f 2 | cut -d\< -f 1`-commit-"`echo $GIT_COMMIT`"

解释:假设你的项目名称在一个或两个以上/以下版本中,就像一个普通的 pom:

<groupId>org.apache.bigtop</groupId>
<artifactId>bigpetstore</artifactId>
<version>1.0-SNAPSHOT</version>

然后您可以轻松地 grep 获取 artifactId,使用“之前/之后”grep 操作将版本与它一起吸入,然后 grep 版本并使用简单的 unix“剪切”命令拼接出两者之间的内容“版本”标签。

我喜欢 Jenkins-groovy 集成,但这要容易得多,甚至可以在您无法控制的构建服务器上工作(即,因为 bash 是通用的)。

【讨论】:

这就像一个魅力,但获取了多个版本信息,因为 auf 依赖项也包含一个版本标签。在对我有用的 grep 和管道之前添加一个头 MAVEN_VERSION=head "&lt;your_project_name&gt;" pom.xml | grep A -2 -B 2 | grep version | cut -d\&gt; -f 2 | cut -d\&lt; -f 1-commit-"echo $GIT_COMMIT" @JoeDred 我仍然有多个版本。但是我的“另一个版本”不是来自依赖项,而是来自属性: cz.px.iisiis-core-ngjar2.1.1-SNAPSHOT7​​.7.5UTF-81.8 1.8 输出为 2.1.1-SNAPSHOT 7.7。 5 @agad 也许您应该将管道的行限制为第一个 grep。 Head 采用可选参数 -n 或 --lines。试试 head --help,它显示了它是如何使用的。【参考方案9】:

经过大量挖掘(我从未意识到 Jenkins 的文档记录有多么糟糕!)我找到了一个非常简单的解决方案。

    安装 Groovy 插件 将Post Step 添加到Execute **system** Groovy script 类型的Maven 构建中 粘贴到 Groovy 的以下 sn-p 中:

脚本:

import hudson.model.*;
import hudson.util.*;

def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def mavenVer = currentBuild.getParent().getModules().toArray()[0].getVersion();
def newParamAction = new hudson.model.ParametersAction(new hudson.model.StringParameterValue("MAVEN_VERSION", mavenVer));
currentBuild.addAction(newParamAction);

名为MAVEN_VERSION 的构建环境变量现在可以以通常的方式($MAVEN_VERSION)替换到其他构建后步骤中。我将它用于 Git 标记等。

【讨论】:

如果您将def mavenVer = 行更新为later followup - def mavenVer = currentBuild.getParent().getModules().toArray()[0].getVersion(); 中的内容,这就像一个魅力。 当“def mavenVer...”替换为上一条注释中的代码时确实有效。 这与POM_VERSION 有相同的问题,由于这个错误问题。jenkins-ci.org/browse/JENKINS-24869 这仅适用于 SYSTEM Groovy 脚本以访问 Jenkins 的 JVM 对象(如构建执行和参数操作)。但是,在 SYSTEM 中执行有一个缺点:它将在 master 上执行,这意味着如果您的构建在 slave 上执行,则将找不到 pom.xml,因为工作空间位于 slave 上,并且无法从 master 访问。跨度> 【参考方案10】:

有同样的需求并按照 Groovy 解析 pom 的建议解决了。

import jenkins.util.*;
import jenkins.model.*;

def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def workspace = currentBuild.getModuleRoot().absolutize().toString();

def project = new XmlSlurper().parse(new File("$workspace/pom.xml"))

def param = new hudson.model.StringParameterValue("project.version", project.version.toString())
currentBuild.addAction(new hudson.model.ParametersAction(param));

将此脚本添加为“执行系统 ​​Groovy 脚本”类型的后期步骤(因此不需要安装 Groovy)并将代码粘贴到“Groovy 命令”中。

【讨论】:

见project-version-from-maven-to-sonar-using-hudson 之后我尝试在 shell 脚本步骤中使用 $project.version,但它失败了:bad substituion,在我将 project.version 重命名为 project_version 之后 - 它有效。似乎詹金斯不允许在变量名称中使用dot 这在 Jenkins 2.46+ 中似乎不起作用。尽管 Groovy 可以很好地提取版本,但在我的 Freestyle 项目的其余部分中,project.version 环境变量是空的。 Jenkins 2+ 中是否有一些改变会使它过时?我随后尝试以$project.version 的身份访问该变量【参考方案11】:

我们使用了Groovy Postbuild Plugin。

    String regex = '.*\\[INFO\\] Building .+ (.+)';
    def matcher = manager.getLogMatcher(regex);
    if (matcher == null) 
        version = null;
     else 
        version =  matcher.group(1);
    

将此添加到 Jenkins 以供以后使用有点棘手。试一试,虽然我记得这让我们有些头疼。 (对不起,我们很久以前就这样做了)

def addBuildParameter(String key, String value) 
    manager.build.addAction(new hudson.model.ParametersAction(new hudson.model.StringParameterValue(key,value))); 

【讨论】:

您如何让version 可用于工作中的其他步骤? 嗨,主持人,我扩大了答案。祝你好运! 此解决方案最适合使用变量在 POM 文件中动态填充版本号的情况。在这些情况下,使用 POM_VERSION 或解析 pom.xml 文件将不起作用。 有一种迭代方式,例如:while(matcher.find()) ?

以上是关于在 Jenkins 中从 Maven POM 获取项目版本的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Maven 中从 pom.xml 调用 testng.xml 文件

Maven 无法在 jenkins 解析 POM

Maven 与 Jenkins - 更新依赖项的父 pom 版本

jenkins指定pom打包

Webdriver+testNG+ReportNG+Maven+SVN+Jenkins自动化测试框架的pom.xml配置

如何通过maven测试Jenkins项目下的特定模块?