【问题标题】:Extract version ID from POM in a Jenkins pipeline从 Jenkins 管道中的 POM 中提取版本 ID
【发布时间】:2016-10-02 21:14:25
【问题描述】:

我创建了一个管道并使用嵌入式 groovy 管道脚本定义,但似乎无法从 POM 获取项目的版本 ID。我尝试了这个在 groovy 控制台中工作但在 Jenkins 构建管道脚本中工作的方法:

def project = new XmlSlurper().parse(new File("pom.xml"))
def pomv = project.version.toString()

根据文档,Jenkins 有一个 $POM_VERSION,但是当我将它分配给一个变量并回显它时,该值没有任何内容。

def pomv = "$POM_VERSION"

def pomv = '$POM_VERSION"

【问题讨论】:

标签: maven jenkins jenkins-pipeline


【解决方案1】:

您总是可以使用 maven 来查询版本,例如像这样:

echo sh(returnStdout: true, 
        script: 'mvn org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate ' +
                 '-Dexpression=project.version -q -DforceStdout ' +
                 '--batch-mode -U -e -Dsurefire.useFile=false'
        ).trim()
# Note: Use "./mvnw" with Maven wrapper

在哪里

  • -Dexpression=project.version -q -DforceStdout 是强制性的(请参阅here 了解详情),并且
  • --batch-mode -U -e -Dsurefire.useFile=false 推荐用于 CI 使用(详见here)。

这也在共享库ces-build-lib 中实现。这里很方便

echo mvn.version

Getting Started with Pipeline 页面显示了另一个选项。不过,它有一些缺点(见下文和 cmets):

def version() {
    def matcher = readFile('pom.xml') =~ '<version>(.+?)</version>'
    matcher ? matcher[0][1] : null
}

这始终与在pom.xml 中找到的第一个&lt;version&gt; 标记相匹配。在大多数情况下,这 应该 是 maven 模块或其父模块的版本。不过,它可能是父版本的版本。

【讨论】:

  • 如果你依赖于父 POM,则使用 matcher[1][1],因为 matcher[0][1] 匹配父 POM 的版本。
  • 这个答案在我的任何 POM 中都不起作用,因为总是有多个 标签。
  • @Jolta 感谢您的提示。我编辑了帖子。这对你有用吗?
  • 我认为不能保证“在 pom.xml 中找到的第一个 标记”是工件版本。假设人们以某种​​顺序放置 XML 标记,那么您将大有把握,而格式根本不需要这种顺序。正如您自己所说,它很可能是父工件版本,这可能会给出完全错误的结果。解析 XML 似乎是编辑 POM 的唯一安全方法。
  • 您的第一个解决方案(调用 sh(mvn... 并捕获控制台)为我开箱即用。感谢有趣的 mvn 命令行。也许您可以详细说明为什么需要使用过的 CLI 选项。对我来说,“-U -e -Dsurefire.useFile=false”的真正作用并不明显。
【解决方案2】:

在 Jenkins 2.138.3 中有两种不同类型的管道。

声明式和脚本式管道。

“声明式管道是管道DSL的新扩展(它基本上是一个只有一步的管道脚本,一个带有参数的管道步骤(称为指令),这些指令应该遵循特定的语法。这种新格式的要点是它更严格,因此对于管道新手来说应该更容易,允许图形编辑等等。 脚本化管道是高级需求的后备方案。”

jenkins pipeline: agent vs node?

这是一个声明式管道的示例:

pipeline {

    agent any


    environment {
    //Use Pipeline Utility Steps plugin to read information from pom.xml into env variables
    IMAGE = readMavenPom().getArtifactId()
    VERSION = readMavenPom().getVersion()
    }


    stages {

        stage('Test') {
            steps {
                echo "${VERSION}"
            }

        }

    }

}

脚本流水线示例

node('master') {

  stage('Test') {
    IMAGE = readMavenPom().getArtifactId()
    VERSION = readMavenPom().getVersion()
    echo "IMAGE: ${IMAGE}"
    echo "VERSION: ${VERSION}"
  }

}

这里有一些不错的链接:

声明式 https://github.com/jenkinsci/pipeline-examples/blob/master/declarative-examples/jenkinsfile-examples/mavenDocker.groovy

脚本 https://bulldogjob.com/articles/726-exploring-jenkins-pipelines-a-simple-delivery-flow

【讨论】:

    【解决方案3】:

    我刚刚在不使用 grep 的情况下增强了 @haridsv 解决方案:

    #!/usr/bin/env
    def call(String mvnBin = 'mvn',String pom_file = 'pom.xml') {
    
    return sh(
            script: mvnBin+''' -N -f '''+pom_file+''' org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version -q -DforceStdout''',
            returnStdout: true).trim()
    }
    

    您最好不要使用 readMavenPom,因为它将被弃用(请参阅 PR https://github.com/jenkinsci/pipeline-utility-steps-plugin/pull/47/commits/eeebaa891a006c083ce10f883b7c1264533bb692 )。您可以将其复制并粘贴到文件中,例如 evaluateMavenPomVersion.groovy :-)

    【讨论】:

      【解决方案4】:

      似乎readMavenPom 是最直接的答案,但由于它需要安装额外的管道插件,这里是另一个使用本机 maven 方法而不是加载 xml 的方法(基于 this answer

      def mvn_project_version(pom_file) {
          return sh(
              script: """mvn -N -f $pom_file org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version |
                         grep -Ev '(^\\s*\\[|Download\\w+:)'""",
              returnStdout: true).trim()
      }
      

      由于使用了grep 命令,这可能无法在某些不兼容 posix 的平台上运行,但您始终可以在 Groovy 中处理输出,而不是通过 grep 进行管道处理。

      【讨论】:

        【解决方案5】:

        像这样使用readMavenPom

        pom = readMavenPom file: 'pom.xml'
        pom.version
        

        请参阅Model 参考以获取属性(如上述版本)。

        为此,必须安装Pipeline Utility Steps plugin

        【讨论】:

        • 这个工作...需要安装 Pipeline Utility 插件才能工作
        • 不幸的是,这个函数不适用于诸如修订 (maven.apache.org/maven-ci-friendly.html) 之类的 maven 功能,并且它将被贬低以及写成 writeMavenPom (github.com/jenkinsci/pipeline-utility-steps-plugin/pull/47/…)
        • 即使它被标记为已弃用,我更喜欢它而不是为此调用 mvn help:evaluate,因为它更快并且不需要我的 pom.xml 有效(因为它引用了一个内部父 POM,它是Maven Central 不知道 - 在我阅读版本的地方,我无法访问必要的 settings.xml)。
        【解决方案6】:

        我刚从Jenkisfile 开始,我遇到了和你一样的问题。由于默认配置禁止XmlSlurperXmlParser,因此我在下面的函数中创建了提取maven 版本的函数:

        String readProjectVersion(String pom) {
            //Take value of the <project> tag
            def matcher = pom.trim() =~ /(?s)<project[^>]*>(.*)<\/project>/
            def pomWithoutProject = matcher[0][1].trim()
        
            //remove every tag except <version>, since only project version is not encapsulated in the other tag e.g. dependency, parent, plugin
            def nonVersionMatcher = pomWithoutProject =~ /(?s)\s*(?!<version>)<([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>(.*?)<\/\1>\s*/
            def versionTag = nonVersionMatcher.replaceAll("").trim()
            //Take value of the <version> tag
            def versionTagMatcher = versionTag =~ /<version>(.*)<\/version>/
            if (versionTagMatcher.matches()) {
                return versionTagMatcher[0][1]
            }
            //no version tag, version should be inherited from parent version
            def parentVersionMatcher = pomWithoutProject =~ /(?s)\s*<parent>.*<version>(.*)<\/version>.*<\/parent>\s*/
            return parentVersionMatcher[0][1]
        }
        

        我已经针对声明了父级、版本是第一个语句、版本是最后一个语句以及在嵌套标签中存在版本(如 dependencyplugin 等)的文件测试了此解决方案。

        【讨论】:

          【解决方案7】:

          我通常使用地图来执行此操作。

           def pomFile = readFile(pomName)
           def pom = new XmlParser().parseText(pomFile)
           def gavMap = [:]
           gavMap['groupId'] =  pom['groupId'].text().trim()
           gavMap['artifactId'] =  pom['artifactId'].text().trim()
           gavMap['version'] =  pom['version'].text().trim()
          

          【讨论】:

          • 不知道为什么这被否决了。这将允许您获得第一个版本并避免父版本
          • 在 '21 中,这需要在 script { } 块中,并且还需要在 /scriptApproval 中获得以下批准,这会引入安全问题; method groovy.util.NodeList text method groovy.util.XmlParser parseText java.lang.String new groovy.util.XmlParser ,不过效果很好。
          【解决方案8】:

          您可以尝试可用的readMavenPom 功能。

          更多信息在这里:https://jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#readmavenpom-read-a-maven-project-file

          【讨论】:

          • 请注意,您需要安装 Pipeline Utility Steps 插件才能获得此步骤。
          • Pipeline Utility Steps 插件说它需要 Pipeline:Groovy 插件 1.11,它已经有将近 2 年的历史了,远远落后于当前的 2.30(左右)。这让我很紧张。
          猜你喜欢
          • 1970-01-01
          • 2019-02-10
          • 2012-04-11
          • 1970-01-01
          • 1970-01-01
          • 2017-07-04
          • 1970-01-01
          • 2015-09-24
          • 1970-01-01
          相关资源
          最近更新 更多