pipeline语法讲解(jenkins)
必要的Groovy知识
支持命名参数
def createName(String givenName,String familyName){ return givenName + " " + familyName } //调用时可以这样 createName familyName = "Lee",givenName = "Bruce"
支持默认参数,比如:
def sayHello(String name = "humans"){ print "hello ${name}" } sayHello() // 此时括号不能省略
支持单引号、双引号。双引号支持插值,单引号不支持。比如:
def name = 'world' print "hello ${name}" //结果: hello world print 'hello ${name}' //结果: hello ${name}
支持三引号。三引号分为三单引号和三双引号。它们都支持换行,区别在于只有三双引号支持插值。比如:
def name = 'world' def aString = '''line one line two line three ${name} ''' def bString = """line one line two line three ${name} """
支持闭包。闭包的定义方法如下:
//定义闭包 def codeBlock = {print "hello closure"} //闭包还可以直接被当成函数调用 codeBlock() //结果打印: hello closure
还可以将闭包看作一个参数传递给另一个方法
// 定义一个pipeline函数,它接收一个闭包参数 def pipeline(closure){ closure() } //在调用pipeline函数时,可以这样 pipeline(codeBlock) //如果把闭包定义的语句去掉 pipeline({print "hello closure"}) pipeline { print "hello closure" } // 是不是很像Jenkins pipeline
闭包的另类用法。我们定义一个stage函数:
def stage(String name,closue){ println name closue() } //在正常情况下,我们这样使用state函数 stage("stage name",{println "closure"}) //最终打印 /** stage name closure **/ // 但是。Groovy提供了另一种写法 stage("stage name"){ print "closure" }
pipeline的组成
pipeline 最简结构
pipeline { agent any stages { stage ('build') { steps { echo 'Hello machangwei ' } } } }
步骤(插件)
https://github.com/jenkinsci/pipeline-plugin/blob/master/COMPATIBILITY.md
https://jenkins.io/doc/pipeline/steps/
post部分
pipeline执行失败后,发送邮件到指定邮箱
post { failure { mail to: 'team@example.com',subject: 'The Pipeline failed :(' } }
post 部分条件块:
- always
- changed
- fixed
- regression
- aborted
- failure
- success
- unstable
- cleanup
如下,提交
如下,post放错位置了。报错了,找不到post,要放到pipeline里面
构建失败,看下输出日志
没有这个方式
java.lang.NoSuchMethodError: No such DSL method 'post' found among steps [acceptGitLabMR
改正确,如下。修改后重新提交
pipeline { agent any stages { stage ('build') { steps { echo 'build stage' } post { always { echo "stage post always" } } } } post{ changed { echo "pipeline post changed" } always { echo "pipeline post always" } success { echo "pipeline post success" } //省略其它条件块 } }
构建完成之后,又多个post的运行
查看日志输出。post下面这几个都输出了
Started by GitLab push by Administrator Obtained Jenkinsfile from git http://10.0.0.13/root/javademo.git [Pipeline] Start of Pipeline [Pipeline] node Running on Jenkins in /var/lib/jenkins/workspace/hello-world-pipeline [Pipeline] { [Pipeline] stage [Pipeline] { (Declarative: Checkout SCM) [Pipeline] checkout The recommended git tool is: NONE using credential 104b2169-f64c-4c0d-a1d0-22e43914f73e > git rev-parse --resolve-git-dir /var/lib/jenkins/workspace/hello-world-pipeline/.git # timeout=10 Fetching changes from the remote Git repository > git config remote.origin.url http://10.0.0.13/root/javademo.git # timeout=10 Fetching upstream changes from http://10.0.0.13/root/javademo.git > git --version # timeout=10 > git --version # 'git version 1.8.3.1' using GIT_ASKPASS to set credentials > git fetch --tags --progress http://10.0.0.13/root/javademo.git +refs/heads/*:refs/remotes/origin/* # timeout=10 skipping resolution of commit remotes/origin/main, since it originates from another repository > git rev-parse refs/remotes/origin/main^{commit} # timeout=10 Checking out Revision 235687fb8f7a3bfb480e7078bbe1a202998107bc (refs/remotes/origin/main) > git config core.sparsecheckout # timeout=10 > git checkout -f 235687fb8f7a3bfb480e7078bbe1a202998107bc # timeout=10 Commit message: "Update Jenkinsfile" > git rev-list --no-walk e007a445ec58e5aaf3d5661d7aa83e0f1eb421c8 # timeout=10 [Pipeline] } [Pipeline] // stage [Pipeline] withEnv [Pipeline] { [Pipeline] stage [Pipeline] { (build) [Pipeline] echo build stage Post stage [Pipeline] echo stage post always [Pipeline] } [Pipeline] // stage [Pipeline] stage [Pipeline] { (Declarative: Post Actions) [Pipeline] echo pipeline post always [Pipeline] echo pipeline post changed [Pipeline] echo pipeline post success [Pipeline] } [Pipeline] // stage [Pipeline] } [Pipeline] // withEnv [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: SUCCESS
pipeline支持的指令
pipeline支持的指令有:
- environment
- tools
- input
- options
- parallel
- parameters
- triggers
- when
配置pipeline本身
options指令
省略,以后补充
在声明式pipeline中使用脚本。
script里面放Groovy代码。有代码逻辑的
pipeline { agent any stages { stage ('Example') { steps { script { def browsers = ['chrome','firefox'] for (int i = 0; i < browsers.size(); ++i) { echo "Testing the ${browsers[i]} browser" } } } } } }
测试结果,
pipeline内置基础步骤
@@@文件相关
deleteDir:删除当前目录
添加deleteDir(),之后,可以看到,原本工作目录下保存上一次的构建数据,但是加上这个之后,当完成Jenkins此次构建,然后删除了工作目录下的这个项目的数据
执行删除目录。
如下,上次的这个项目的构建数据还在,但是这次加了删除目录之后,这次构建的数据都被删除了,从工作目录中
dir:切换到目录
dir("var/logs"){ deleteDir() }
从工作目录下创建了一个目录var/logs,
切换运行在新的目录,不过这是个空目录
fileExists:判断文件是否存在
fileExists('/tmp/a.jar')
print打印布尔值,就会自动echo出来。但是直接pipeline这里echo这个值,好像报错,期待字符串,结果是布尔值
pipeline { agent any stages { stage ('build') { steps { echo 'Hello machangwei ' print fileExists('/tmp/a.jar') } } } }
创建文件
判断文件是否存在,这次是存在的,看打印是不是true
这次是true了
isUnix:判断是否为类UNIX系统
pwd:确认当前目录
writeFile:将内容写入指定文件中
pipeline { agent any stages { stage ('build') { steps { echo 'Hello machangwei ' script{ //"amVua2lucyBib29r" 是"jenkins book" 进行Base64编码后的值 writeFile(file:"base64File",text:"amVua2lucyBib29r",encoding: "Base64") def content = readFile(file: "base64File",encoding: "UTF-8") echo "${content}" //打印结果:jenkins book } } } } }
写入文件,然后从文件中读取内容并打印
Jenkins工作目录已经写入文件
------
把文件读取出来再写入到新文件mcwtest.txt
报错了,不过可以看的更多的步骤,在下面显示出来。有时间可以研究研究
[Pipeline] End of Pipeline java.lang.NoSuchMethodError: No such DSL method '$' found among steps [acceptGitLabMR, addGitLabMRComment, archive, bat, build, catchError, checkout, deleteDir, dir, echo, emailext, emailextrecipients, envVarsForTool, error, fileExists, findBuildScans, getContext, git, gitlabBuilds, gitlabCommitStatus, input, isUnix, junit, library, libraryResource, load, lock, mail, milestone, node, parallel, powershell, properties, publishChecks, pwd, pwsh, readFile, readTrusted, resolveScm, retry, script, sh, sleep, stage, stash, step, timeout, timestamps, tm, tool, unarchive, unstable, unstash, updateGitlabCommitStatus, validateDeclarativePipeline, waitUntil, warnError, withChecks, withContext, withCredentials, withEnv, withGradle, wrap, writeFile, ws] or symbols [GitUsernamePassword, agent, all, allBranchesSame, allOf, always, ant, antFromApache, antOutcome, antTarget, any, anyOf, apiToken, apiTokenProperty, architecture, archiveArtifacts, artifactManager, authorizationMatrix, batchFile, bitbucketServer, booleanParam, branch, brokenBuildSuspects, brokenTestsSuspects, buildButton, buildDiscarder, buildDiscarders, buildRetention, buildUser, buildingTag, builtInNode, caseInsensitive, caseSensitive, certificate, changeRequest, changelog, changeset, checkoutToSubdirectory, choice, choiceParam, cleanWs, clock, command, configFile, configFileProvider, consoleUrlProvider, contributor, credentials, cron, crumb, culprits, default, defaultFolderConfiguration, defaultView, demand, developers, disableConcurrentBuilds, disableResume, diskSpace, diskSpaceMonitor, downstream, dumb, durabilityHint, email-ext, envVars, envVarsFilter, environment, equals, executor, experimentalFlags, expression, extendedEmailPublisher, file, fileParam, filePath, fingerprint, fingerprints, frameOptions, freeStyle, freeStyleJob, fromScm, fromSource, git, gitBranchDiscovery, gitHooks, gitHubBranchDiscovery, gitHubBranchHeadAuthority, gitHubExcludeArchivedRepositories, gitHubExcludeForkedRepositories, gitHubExcludePrivateRepositories, gitHubExcludePublicRepositories, gitHubForkDiscovery, gitHubIgnoreDraftPullRequestFilter, gitHubPullRequestDiscovery, gitHubSshCheckout, gitHubTagDiscovery, gitHubTopicsFilter, gitHubTrustContributors, gitHubTrustEveryone, gitHubTrustNobody, gitHubTrustPermissions, gitLabConnection, gitParameter, gitTagDiscovery, gitUsernamePassword, github, githubProjectProperty, githubPush, gitlab, globalConfigFiles, gradle, headRegexFilter, headWildcardFilter, hyperlink, hyperlinkToModels, inbound, inheriting, inheritingGlobal, installSource, isRestartedRun, javadoc, jdk, jdkInstaller, jgit, jgitapache, jnlp, jobBuildDiscarder, jobName, junitTestResultStorage, label, lastDuration, lastFailure, lastGrantedAuthorities, lastStable, lastSuccess, legacy, legacySCM, list, local, location, logRotator, loggedInUsersCanDoAnything, mailer, masterBuild, maven, maven3Mojos, mavenErrors, mavenGlobalConfig, mavenMojos, mavenWarnings, modernSCM, myView, namedBranchesDifferent, node, nodeProperties, nodejs, nodejsci, nonInheriting, none, nonresumable, not, organizationFolder, overrideIndexTriggers, paneStatus, parallelsAlwaysFailFast, parameters, password, pattern, permanent, pipeline, pipelineTriggers, plainText, plugin, pollSCM, preserveStashes, previous, projectNamingStrategy, proxy, pruneTags, queueItemAuthenticator, quietPeriod, rateLimit, rateLimitBuilds, recipients, requestor, resourceRoot, responseTime, retainOnlyVariables, run, runParam, sSHLauncher, schedule, scmRetryCount, scriptApproval, scriptApprovalLink, search, security, shell, simpleBuildDiscarder, skipDefaultCheckout, skipStagesAfterUnstable, slave, sourceRegexFilter, sourceWildcardFilter, ssh, sshPublicKey, sshUserPrivateKey, standard, status, string, stringParam, suppressAutomaticTriggering, suppressFolderAutomaticTriggering, swapSpace, tag, teamSlugFilter, text, textParam, timestamper, timestamperConfig, timezone, tmpSpace, toolLocation, triggeredBy, unsecured, untrusted, upstream, upstreamDevelopers, userSeed, usernameColonPassword, usernamePassword, viewsTabBar, weather, withAnt, workspace, zip] or globals [currentBuild, env, params, pipeline, scm] at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:219)
readFile:读取文件内容
准备读取jenkinsfile并打印出来,
读取成功
将文件读出来,写入到另外一个文件
注意:在writeFile里面用变量,需要加引号,放到${}里面
pipeline { agent any stages { stage ('build') { steps { echo 'Hello machangwei ' script{ def content = readFile(file: "Jenkinsfile",encoding: "UTF-8") writeFile(file:"mcwtest.txt",text:"${content}",encoding: "UTF-8") } } } } }
提交触发执行
成功将文件读取出来并写入到一个新的文件中
@@@制品相关步骤
stash:保存临时文件
unstash:取出之前stash的文件
pipeline { agent any stages { stage ('stash') { agent { label "master" } steps { echo 'Hello machangwei ' script{ echo "$BUILD_NUMBER" writeFile file: "a.txt",text:"$BUILD_NUMBER" stash(name: "abc",includes: "a.txt") } } } stage ('unstash') { agent { label "node2" } steps { script{ unstash("abc") def content = readFile("a.txt") echo "$content" } } } } }
因为我这里就一个节点,agent改为any了
查看执行情况,把构建数字28打印了一下,然后保存到stash
unstash的时候,从文件里面读取到了28
这个a.txt文件并没有在工作目录下直接生成
@@@命令相关步骤
sh:执行shell命令
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" sh "pwd" sh "sh mcw.sh" } } } }
添加一个脚本,
[root@mcw15 ~]# vim /var/lib/jenkins/workspace/hello-world-pipeline/mcw.sh [root@mcw15 ~]# cat /var/lib/jenkins/workspace/hello-world-pipeline/mcw.sh echo "wo shi machangwei" [root@mcw15 ~]#
查看结果
bat、powershell步骤
@@@其它步骤
error:主动报错,终止当前pipeline
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" sh "pwd" error("there is an error") sh "sh mcw.sh" } } } }
直接从这里抛出异常,停止pipeline了。应该可以加个逻辑判断,那种情况下,可以直接停止pipeline。
tool:使用预定义的工具
timeout:代码块超时时间
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" timeout(time:10,unit:"SECONDS"){ sh "date" sh "sleep 20" sh "date" } } } } }
这里的10是十分钟
修改为10s
注意,这个10s,不能是字符串10,
查看,超时之后,后面的date等都不执行了,在超时的地方直接终止了,并且后面提示超时
Cancelling nested steps due to timeout Sending interrupt signal to process /var/lib/jenkins/workspace/hello-world-pipeline@tmp/durable-e5afb3b4/script.sh: line 1: 107381 Terminated sleep 20 script returned exit code 143
waitUntil:等待条件满足
10内不断重试,
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" timeout(time:10,unit:"SECONDS"){ waitUntil { script { def r = sh script: 'curl http://exmaple', returnStatus: true return (r == 0) } } } } } } }
不断重试
超时之后终止重试
换个域名,执行没有报错,所以没有重试,直接就完成pipeline了
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" timeout(time:10,unit:"SECONDS"){ waitUntil { script { def r = sh script: 'curl http://www.baidu.com', returnStatus: true return (r == 0) } } } } } } }
retry:重复执行块
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" retry(2){ script{ sh "date" sh script: 'curl http://exmaple', returnStatus: true sh "date" } } } } } }
重试两次
可以看到,这里脚本执行虽然有问题,但是依然是往下执行了的,而且pipeline也是执行成功的。
中间主动抛出异常
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" retry(2){ script{ sh "date" sh script: 'curl http://exmaple', returnStatus: true error('there is an error') sh "date" } } } } } }
重试之后还是抛出异常,那么pipeline算失败了,并且是尝试两次执行里面的代码,也就是重复执行两次retry里面的代码
sleep:让pipeline休眠一段时间
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" script{ sh "date" sleep(20) sh "date" } } } } }
休眠20s
可以看的休眠了20s
休眠一分钟的配置
pipeline { agent any stages { stage ('mcwtest') { steps { echo "mcw" script{ sh "date" sleep(time:'1', unit:"MINUTES") //休眠一分钟 sh "date" } } } } }
休眠一分钟
使用Workspace Cleanup插件清理空间
post {
always {
cleanWs()
}
}