语法
内置语法
http://192.168.0.137:9191/pipeline-syntax/
https://jenkins.io/zh/doc/book/blueocean/creating-pipelines/
pipeline {
agent any
stages {
stage('Build') {
steps {
println "Build"
}
}
stage('Test') {
steps {
println "Test"
}
}
stage('Deploy') {
steps {
println "Deploy"
}
}
}
//
post { //这里定义的是后置处理
success {
// 构建成功
echo '构建完成,正在清理工作空间'
cleanWs();
echo '清理工作空间完成'
}
failure {
// 构建失败,这里使用sh是因为echo不支持使用参数
sh 'echo "构建失败,详情请查看$WORKSPACE"'
}
aborted {
// 构建被中止
echo '构建被中止'
}
}
}
pipeline {
agent any
stages {
stage('Build') {
steps {
println "Build"
}
}
stage('Test') {
steps {
println "Test"
}
}
stage('Deploy') {
steps {
println "Deploy"
}
}
}
//
post { //这里定义的是后置处理
success {
// 构建成功
echo '构建完成,正在清理工作空间'
cleanWs();
echo '清理工作空间完成'
}
failure {
// 构建失败,这里使用sh是因为echo不支持使用参数
sh 'echo "构建失败,详情请查看$WORKSPACE"'
}
aborted {
// 构建被中止
echo '构建被中止'
}
}
}
- 切换目录
stage('Build') {
steps {
dir('demo') { //切换目录到demo
//执行构建镜像命令,这里起作用的是maven的插件
//可以参考https://github.com/hellxz/SpringBoot-DockerDemo.git的使用方法,在docker-maven-plugin-2分支
sh 'mvn clean package docker:build -DskipTests'
}
}
}
stage('Build') {
steps {
dir('demo') { //切换目录到demo
//执行构建镜像命令,这里起作用的是maven的插件
//可以参考https://github.com/hellxz/SpringBoot-DockerDemo.git的使用方法,在docker-maven-plugin-2分支
sh 'mvn clean package docker:build -DskipTests'
}
}
}
- git clone
stage('Pull Git Demo') {
steps{
//清理工作空间
cleanWs();
//拉取代码
checkout([$class: 'GitSCM', branches: [[name: '*/docker-maven-plugin-2']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'demo']], submoduleCfg: [], userRemoteConfigs: [[url: 'https://github.com/hellxz/SpringBoot-DockerDemo.git']]])
}
}
stage('Pull Git Demo') {
steps{
//清理工作空间
cleanWs();
//拉取代码
checkout([$class: 'GitSCM', branches: [[name: '*/docker-maven-plugin-2']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'demo']], submoduleCfg: [], userRemoteConfigs: [[url: 'https://github.com/hellxz/SpringBoot-DockerDemo.git']]])
}
}
2.shell命令的标准输出或者状态
//获取标准输出
//第一种
result = sh returnStdout: true ,script: "<shell command>"
result = result.trim()
//第二种
result = sh (script: "<shell command>", returnStdout: true).trim()
//第三种
sh "<shell command> > commandResult"
result = readFile('commandResult').trim()
//获取执行状态
//第一种
result = sh returnStatus: true ,script: "<shell command>"
result = result.trim()
//第二种
result = sh (script: "<shell command>", returnStatus: true).trim()
//第三种
sh '<shell command>; echo $? > status'
def r = readFile('status').trim()
//获取标准输出
//第一种
result = sh returnStdout: true ,script: "<shell command>"
result = result.trim()
//第二种
result = sh (script: "<shell command>", returnStdout: true).trim()
//第三种
sh "<shell command> > commandResult"
result = readFile('commandResult').trim()
//获取执行状态
//第一种
result = sh returnStatus: true ,script: "<shell command>"
result = result.trim()
//第二种
result = sh (script: "<shell command>", returnStatus: true).trim()
//第三种
sh '<shell command>; echo $? > status'
def r = readFile('status').trim()
groovy语句写法为:
def exitValue = sh(script: "grep -i 'xxx' /etc/myfolder", returnStatus: true)
echo "return exitValue :${exitValue}"
if(exitValue != 0){
执行操作
}
如果grep命令执行没有报错,正常情况下exitValue为0,报错则为非0
def exitValue = sh(script: "grep -i 'xxx' /etc/myfolder", returnStatus: true)
echo "return exitValue :${exitValue}"
if(exitValue != 0){
执行操作
}
如果grep命令执行没有报错,正常情况下exitValue为0,报错则为非0
- 输出日志
stage('输出日志') {
steps {
script{
//调用方法得到日志 并 输出
def changeString = getChangeString()
echo "$changeString"
}
}
}
stage('输出日志') {
steps {
script{
//调用方法得到日志 并 输出
def changeString = getChangeString()
echo "$changeString"
}
}
}
3.输出保存到变量
StdOut
pipeline{
agent any
stages{
stage('sh输出'){
steps{
script{
out = sh(
label: 'listing directory',
returnStdout: true,
script: "ls /"
)
}
}
}
}
}
#这段话将运行 script 指定的命令,也就是 ls / 的标准输出 StdOut 赋值给 out 变量
pipeline{
agent any
stages{
stage('sh输出'){
steps{
script{
out = sh(
label: 'listing directory',
returnStdout: true,
script: "ls /"
)
}
}
}
}
}
#这段话将运行 script 指定的命令,也就是 ls / 的标准输出 StdOut 赋值给 out 变量
StdErr
out = sh(
label: 'listing directory',
returnStdout: true,
script: "ls /notExist"
)
这个命令将在标准错误 StdErr 输出下面的信息:
ls: cannot access /notExist: No such file or directory
#然而标准输出 StdOut 则为空。那么上面这种 Pipeline 写法有两个问题:
不能返回执行命令的标准错误信息,只能返回 StdOut 内容,异常情况下为空
不能抛错,使当前和后续 stage 停止,也不能中断整个任务,更不能将整个任务的状态标记为 Failure
out = sh(
label: 'listing directory',
returnStdout: true,
script: "ls /notExist"
)
这个命令将在标准错误 StdErr 输出下面的信息:
ls: cannot access /notExist: No such file or directory
#然而标准输出 StdOut 则为空。那么上面这种 Pipeline 写法有两个问题:
不能返回执行命令的标准错误信息,只能返回 StdOut 内容,异常情况下为空
不能抛错,使当前和后续 stage 停止,也不能中断整个任务,更不能将整个任务的状态标记为 Failure
目前的 Jenkins 版本,不提供输出标准错误 StdErr 的方法,不过可以通过下面的做法绕过:
- 标准错误合并输出到标准输出,再输出到文件
- 判断运行状态 returnStatus
pipeline{
agent any
stages{
stage('sh输出'){
steps{
script{
status = sh(
label: 'listing directory',
// 返回运行状态
returnStatus: true,
// 合并标准错误 StdErr 到文件和标准输出 StdOut
script: "ls /ff \>test.log 2>&1"
)
// 从文件读出标准错误 StdErr 信息
out = readFile(file: "test.log")
if (status != 0) {
// 使当前 stage 运行失败,同时输出错误信息。
error('TEST FAILED.')
}
}
}
}
}
}
pipeline{
agent any
stages{
stage('sh输出'){
steps{
script{
status = sh(
label: 'listing directory',
// 返回运行状态
returnStatus: true,
// 合并标准错误 StdErr 到文件和标准输出 StdOut
script: "ls /ff \>test.log 2>&1"
)
// 从文件读出标准错误 StdErr 信息
out = readFile(file: "test.log")
if (status != 0) {
// 使当前 stage 运行失败,同时输出错误信息。
error('TEST FAILED.')
}
}
}
}
}
}
4.重试次数
实现重试的方法,是在 stage 内部增加 options,如下面的 Jenkinsfile 所示。
stage('some node'){
agent {
label 'some agent'
}
options{
retry(3)
}
steps{
// 其他任务
}
}
stage('some node'){
agent {
label 'some agent'
}
options{
retry(3)
}
steps{
// 其他任务
}
}
5.如何及时中止pipeline
场景
使用Jenkins的流水线时,有时明明某些Python或Shell执行结果错误,但仍会继续运行下去,甚至于最终提示成功。这并不合我们的预期——出现错误及时停止。当然,还有那种小错误不影响构建的,希望继续执行下去的情况。
所以,场景有两个:
- 希望发现错误,及时中止执行的情况。
- 希望错误发生时,脚本仍继续执行的情况。
本文以上两种场景分别给出示例。
本文不考虑能被pipeline捕获的异常中断。
及时中止,如何做?
1、对于Jenkins流水线中,使用groovy语法实现的功能,可以考虑使用Java的异常。
示例:
stage('test'){
step{
script{
def res = someGroovyMethod()
if(res == false){
throw new RuntimeException('提示信息')
}
}
}
}
stage('test'){
step{
script{
def res = someGroovyMethod()
if(res == false){
throw new RuntimeException('提示信息')
}
}
}
}
2、对于流水线中调用Shell,可以考虑匹配返回值,抛异常。
示例:
stage('test'){
step{
script{
def res = sh(label:"测试分支是否存在:", script: """
echo 'hello world!'
""", returnStdout: true);
if(!res.contains("hello world")){
throw new RuntimeException('提示信息')
}
}
}
}
stage('test'){
step{
script{
def res = sh(label:"测试分支是否存在:", script: """
echo 'hello world!'
""", returnStdout: true);
if(!res.contains("hello world")){
throw new RuntimeException('提示信息')
}
}
}
}
除了
returnStdout
用于返回执行输出,还可以使用returnStatus
,returnStatus
与returnStdout
不能同时使用,returnStatus
表示脚本执行完毕的返回值是0还是非0,非0值即有问题的。
3、对于以上两种情况,只要能获取返回输出或状态,就可以终止流水线,使用 error
。
示例:
stage('test'){
step{
script{
def res = someGroovyMethod()
if(res == false){
error '提示信息'
}
}
}
}
stage('test'){
step{
script{
def res = someGroovyMethod()
if(res == false){
error '提示信息'
}
}
}
}
报错忽略,如何做?
1、使用异常捕获,try-catch block 或 try-catch-finally block。
示例:
stage('test'){
step{
script{
try{
someMethodMaybeThrowException()
} catch(Exception e){
// do something you want. e.g,print logs.
}
}
}
}
stage('test'){
step{
script{
try{
someMethodMaybeThrowException()
} catch(Exception e){
// do something you want. e.g,print logs.
}
}
}
}
2、使用Jenkins 流水线中的 catchError
忽略异常或可能中断构建的错误。
示例:
stage('test'){
step{
script{
//无论是否会报错,这个stage以及构建结果都不会因这个错误而失败。
catchError(buildResult: 'SUCCESS', catchInterruptions: false) {
someMethodMaybeThrowException()
}
//some post step will continued.
}
}
}
stage('test'){
step{
script{
//无论是否会报错,这个stage以及构建结果都不会因这个错误而失败。
catchError(buildResult: 'SUCCESS', catchInterruptions: false) {
someMethodMaybeThrowException()
}
//some post step will continued.
}
}
}
catchError
的玩法还有很多,典型应用场景是针对一些后置的操作,比如构建完成发消息给构建者,保证这个消息不会因为脚本执行中断而停止
6. try-catch
加上try-catch之后如果try中的语句出错就会被catch捕获输出错误信息,而不会终止程序
script{
try{
gradleHome = tool "GRADLE"
sh """
${gradleHome}/bin/gradle -v
"""
}catch(e){
println(e)
}
}
script{
try{
gradleHome = tool "GRADLE"
sh """
${gradleHome}/bin/gradle -v
"""
}catch(e){
println(e)
}
}
案例
import hudson.model.*;
println env.JOB_NAME
println env.BUILD_NUMBER
pipeline{
agent any
stages{
stage("git checkout") {
steps{
script {
checkout([$class: 'GitSCM',
branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [],
submoduleCfg: [],
userRemoteConfigs: [[credentialsId: 'e3e48ed7-dbce-4642-bb18-28e0c71ab962',
url: 'http://192.168.132.132/root/hello-world-greeting.git']]])
}
}
}
stage("Check file download") {
steps {
script {
try{
out = sh(script: "ls /opt ", returnStdout: true).toString().trim()
println out
if(out.contains("Python-3.7.1.tgz")) {
println "file download successfully."
}else {
sh("exit 1")
}
}
catch(Exception e) {
println "e"
error("fond error during check file download.")
}
}
}
}
}
}
import hudson.model.*;
println env.JOB_NAME
println env.BUILD_NUMBER
pipeline{
agent any
stages{
stage("git checkout") {
steps{
script {
checkout([$class: 'GitSCM',
branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [],
submoduleCfg: [],
userRemoteConfigs: [[credentialsId: 'e3e48ed7-dbce-4642-bb18-28e0c71ab962',
url: 'http://192.168.132.132/root/hello-world-greeting.git']]])
}
}
}
stage("Check file download") {
steps {
script {
try{
out = sh(script: "ls /opt ", returnStdout: true).toString().trim()
println out
if(out.contains("Python-3.7.1.tgz")) {
println "file download successfully."
}else {
sh("exit 1")
}
}
catch(Exception e) {
println "e"
error("fond error during check file download.")
}
}
}
}
}
}
7.获取状态
获取执行状态
// 执行脚本,并获取脚本的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'
}
// 执行脚本,并获取脚本的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'
}
8.在目录下执行
//例 在 **.git/QloudMartUI 目录下 执行编译命令
dir('QloudMartUI/qloudmart'){
sh 'npm install'
}
//例 在 **.git/QloudMartUI 目录下 执行编译命令
dir('QloudMartUI/qloudmart'){
sh 'npm install'
}