背景
单纯的声明或者脚本式的流水线语法,能力非常有限,只能搭建起整体运行框架。具体每个step的实现细节,多是使用脚本进行的。
鉴于groovy 与 pipeline语法的不稳定性,我的原则是,python/shell 脚本能解决的,不在pipeline中用groovy多做逻辑
如何在pipeline 更好的使用脚本,这里写了几个实践。
groovy脚本使用
这里给一个普通的完整声明式流水线的demo,执行脚本,我们可以直接在steps中执行groovy脚本,也可以用script关键字,形成整体的groovy脚本代码块儿,以便于整体运用,抽象复用等。
这里要注意的是,使用groovy,有一些细节语法问题。
官方groovy语法请参考,使用时阅读,可避免不必要的问题
http://docs.groovy-lang.org/latest/html/documentation/core-operators.html#_conditional_operators
pipeline {
agent any
stages {
stage('Example') {
steps {
// groovy 脚本
sh 'echo hello'
echo 'Hello World'
script {
// groovy 脚本
def browsers = ['chrome', 'firefox']
for (int i = 0; i < browsers.size(); ++i) {
echo "Testing the ${browsers[i]} browser"
}
}
}
}
}
}
在groovy脚本中使用shell
shell脚本是依托在steps中的groovy脚本而被调用。
无输出shell脚本运行
在pipeline中,我们通常用 sh 来执行shell,具体语法见 https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script
无输出的shell 语法如下
// 单引号需要拼接 容易出错 不推荐使用
sh 'mkdir -p ' + VARIABLE
// 三引号支持变量等内容,引号嵌套等 推荐使用
sh """cp ${VARIABLE}/ 'abc' "123" ${VARIABLE_1}/${VARIABLE_2}"""
有输出的shell脚本
获取执行状态
// 执行脚本,并获取脚本的exit状态,针对不同状态,做逻辑
def run_status = sh (
script: """cd ${ROOT_BIN_PATH} && \
./run.sh ${env.var1} '${str_param_1}' """,
returnStatus:true
)
print run_status
// 失败强制退出
if (run_status != 0) {
print '脚本执行失败,强制退出'
sh 'exit 1'
}
获取标准输出
// 这里以判断空文件举例,获取行数
def is_empty_file = sh (
script: """cat ${PROJECT_ROOT_PATH}/${record_filename}.txt | wc -l""",
returnStdout: true
).trim()
print 'is_empty_file: ' + is_empty_file
if ( is_empty_file == '0') {
print '此次录制生成数据文件为空文件,不能上传生成或者更新case!可在reporter 里面查看原先的请求数据文件。'
sh 'exit 1'
}
使用python 脚本
从远端git拉取并执行python脚本
如果我们把脚本维护在常用仓库里面,这样可以作为依赖包用于pipeline中,这要比维护在机器上有两个特点
- 迁移性更好
- 维护,调试都更方便,支持参数式指定脚本分支,更灵活
script {
// 对照版本的分支,如果传入的是master 默认替换成最新上线的commit
if (express) {
dir ('./script') {
// 利用git 获取python工具脚本
git branch: 'master', credentialsId: 'your_git_credential', url: 'git@repository.git'
script {
env.result = sh(script: """echo `python ./path/act.py ${param}` | awk '{print \$NF}' """, returnStdout: true, returnStatus: false).trim()
print '结果: ' + env.result
}
}
}
}
groovy解析json,更丰富的与python脚本交互
如果python脚本产生的数据比较复杂,这里建议在python脚本中序列化成json,保存在文件中,后者这机print到标准输出,以供groovy使用
这里给下解析的串联
python文本 举例
#!/usr/bin/python
import json
a = {}
a['name'] = 'John Doe'
# 方式1 输出到标准输出
print(json.dumps(a))
# 方式2 输出到文件
format_json_str = json.dumps(a, default=lambda o: o.__dict__, indent=2).decode('unicode-escape')
with open(./python_result.json, 'a+') as f:
f.write(format_json_str)
groovy文本
// 引用在文件最上面,不放在script中
import groovy.json.JsonSlurper
def json_output = sh(script: """python ./act.py""", returnStdout: true).trim()
def result_json = new JsonSlurper()
// 方法1
def result_map = jsonSlurper.parseText(json_output)
// 方法2
def result_map = readJSON file:'./python_result.json'
print result_map.name