CI/CD

Jenkins pipeline中优雅的执行shell/pyth

2020-04-05  本文已影响0人  bitingwind

背景

单纯的声明或者脚本式的流水线语法,能力非常有限,只能搭建起整体运行框架。具体每个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中,这要比维护在机器上有两个特点

  1. 迁移性更好
  2. 维护,调试都更方便,支持参数式指定脚本分支,更灵活
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

参考

  1. 《Jenkins2 权威指南》
  2. groovy http://docs.groovy-lang.org/latest/html/documentation/core-operators.html#_conditional_operators
  3. https://jenkins.io/doc/
  4. https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script
上一篇 下一篇

猜你喜欢

热点阅读