在 Jenkins 管道中解析 XML 文件 [英] Parsing an XML file within a Jenkins pipeline

查看:29
本文介绍了在 Jenkins 管道中解析 XML 文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:

当我的 Jenkins 环境中只有一个主节点时,我发回了这个问题.这使得序列化成为一个较小的问题,因为没有其他节点可以与之通信,因此这里的代码不会在多节点环境中按预期运行(例如,readFile 只会从主节点读取文件节点).

I posted this question back when I only had a master node in my Jenkins environment. This made serialization a lesser issue as there were no other nodes to communicate with, thus the code here will not run as expected on a multi-node environment (for instance, readFile will only read files from the master node).

根据我的经验,最好使用其他格式(JSON、YAML、Groovy,这些在 Jenkins 中均受本机支持)或使用外部工具(例如 Linux 上的 xmllint)编写配置,如果您无法控制文件的格式.

In my experience it's better to have your configuration written in other formats (JSON, YAML, Groovy which are all supported natively in Jenkins), or use external tools (such as xmllint on Linux) if you don't have control over the file's format.

原始问题:

我有一个 XML 文件,我想将其用作管道脚本的输入.问题是 XMLParser 是不可序列化的,所以我把它放在一个 NonCPS 函数中,但我因此丢失了 Node 对象.

I have an XML file which I'd like to use as input for a pipeline script. Problem is the XMLParser isn't serializable so I put it in a NonCPS function, but I lost the Node object because of that.

这是管道脚本:

def buildPlanPath = 'C:\buildPlan_test.xml'

@NonCPS
groovy.util.Node getBuildPlan(path) {
    new XmlParser().parseText(readFile(path))
}
    
node {
    //def buildPlan = new XmlParser().parseText(readFile(buildPlanPath))
    groovy.util.Node buildPlan = getBuildPlan(buildPlanPath)

    println buildPlan.getClass()
    println buildPlan
    println buildPlan.branch
}

这是一个输入样本:

<branch name='mybranch'>
    <stage>
        <job name='job11' />
        <job name='job12' />
    </stage>
    <stage>
        <job name='job21' />
        <job name='job22' />
        <job name='job23' />
    </stage>
    <stage>
        <job name='job31' />
    </stage>
</branch>

结果如下:

Started by user admin
[Pipeline] node
Running on master in C:Jenkinsworkspacepipeline-develop
[Pipeline] {
[Pipeline] readFile
[Pipeline] echo
class java.lang.String
[Pipeline] echo
<branch name='mybranch'>
  <stage>
    <job name='job11' />
    <job name='job12' />
  </stage>
  <stage>
    <job name='job21' />
    <job name='job22' />
    <job name='job23' />
  </stage>
  <stage>
    <job name='job31' />
  </stage>
</branch>
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: branch for class: java.lang.String
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:458)
    at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.getProperty(DefaultInvoker.java:25)
    at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:17)
    at WorkflowScript.run(WorkflowScript:16)
    at ___cps.transform___(Native Method)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:62)
    at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:54)
    at sun.reflect.GeneratedMethodAccessor327.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
    at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
    at com.cloudbees.groovy.cps.Next.step(Next.java:58)
    at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:154)
    at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:164)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:276)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$000(CpsThreadGroup.java:78)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:185)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:183)
    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:47)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Finished: FAILURE

我使用 Jenkins 2.7 和管道 2.1,这是目前最新的.

I'm using Jenkins 2.7 with pipeline 2.1, which are currently the latest.

推荐答案

最后我认为我的做法是错误的:我决定将 XML 文件转换为单独的 groovy 脚本并在管道中加载

In the end I think my approach was wrong: I decided to convert the XML file into a separate groovy script and load it within the pipeline

更新:为了清楚起见,最近人们开始编辑我的答案,但事实是我只是放弃了将配置存储在 XML 文件中并选择了 groovy 脚本,这给了我更大的灵活性.我知道这可能不是一种常见做法,但它适合我的需求.

Update: Recently people started editing my answer for clarity, but the fact is that I just ditched storing my configuration in XML files and opted for groovy scripts, which gave me more flexibility. I understand it may not be a common practice, but it suits my needs.

例如 - 而不是:

config.xml:
<settings>
  <floopi>2</floopi>
</settings>

我用过:

config.groovy:
[
  floopi: 2
]

在管道脚本中:

stage('init') {
    def settings = load('config.groovy')
    echo "floopi: ${settings.floopi}"
}

我希望这是一个更好的答案:)

I hope that's a better answer :)

这篇关于在 Jenkins 管道中解析 XML 文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆