返回总目录页

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()
    }
}

 

posted @ 2024-07-24 08:31  马昌伟  阅读(6)  评论(0编辑  收藏  举报
博主链接地址:https://www.cnblogs.com/machangwei-8/