一、需求描述
最近在一臺測試服務器上安裝最新版本的Jenkins,然後學習Pipeline語法,一切都是正常的。最後編譯完成,發送通知的時候,因爲需要使用到${BUILD_NUMBER} 變量,如下所示是之前的語法:
【Jenkins學習 】如何編寫Python腳本來調用企業微信的api通知企業微信成員關於Jenkins的編譯結果?
之前是在正式環境老版本的jenkins上運行的,一切都沒有問題
現在這臺新的測試服務器上的新版本jenkins運行就報錯了,如下所示:
查看具體日誌,如下所示顯示。
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: BUILD_USER for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:270)
at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:291)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:295)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:271)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:271)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at WorkflowScript.run(WorkflowScript:46)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(ModelInterpreter.groovy:138)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(ModelInterpreter.groovy:684)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:418)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:416)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(ModelInterpreter.groovy:682)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:281)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.toolsBlock(ModelInterpreter.groovy:567)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.toolsBlock(ModelInterpreter.groovy:566)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:271)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withEnvBlock(ModelInterpreter.groovy:466)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withEnvBlock(ModelInterpreter.groovy:465)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:270)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withCredentialsBlock(ModelInterpreter.groovy:504)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withCredentialsBlock(ModelInterpreter.groovy:503)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:269)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:316)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inDeclarativeAgent(ModelInterpreter.groovy:608)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inDeclarativeAgent(ModelInterpreter.groovy:607)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:313)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.stageInput(ModelInterpreter.groovy:379)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.stageInput(ModelInterpreter.groovy:378)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:312)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inWrappers(ModelInterpreter.groovy:635)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inWrappers(ModelInterpreter.groovy:634)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:252)
at ___cps.transform___(Native Method)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:74)
at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66)
at sun.reflect.GeneratedMethodAccessor535.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
at com.cloudbees.groovy.cps.Next.step(Next.java:83)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:186)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:370)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:93)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:282)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:270)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:66)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE
因此我得想辦法獲取到 BUILD_USER 這個屬性。
二、分析問題
2.1 分析原有自帶的屬性
打開網站 http://xxx.xxx.xxx.xxx:8080/jenkins/env-vars.html/
如下所示,可以看到一堆的Jenkins變量,就是沒有 BUILD_USER 這個變量
The following variables are available to shell scripts
BRANCH_NAME
For a multibranch project, this will be set to the name of the branch being built, for example in case you wish to deploy to production from master but not from feature branches; if corresponding to some kind of change request, the name is generally arbitrary (refer to CHANGE_ID and CHANGE_TARGET).
CHANGE_ID
For a multibranch project corresponding to some kind of change request, this will be set to the change ID, such as a pull request number, if supported; else unset.
CHANGE_URL
For a multibranch project corresponding to some kind of change request, this will be set to the change URL, if supported; else unset.
CHANGE_TITLE
For a multibranch project corresponding to some kind of change request, this will be set to the title of the change, if supported; else unset.
CHANGE_AUTHOR
For a multibranch project corresponding to some kind of change request, this will be set to the username of the author of the proposed change, if supported; else unset.
CHANGE_AUTHOR_DISPLAY_NAME
For a multibranch project corresponding to some kind of change request, this will be set to the human name of the author, if supported; else unset.
CHANGE_AUTHOR_EMAIL
For a multibranch project corresponding to some kind of change request, this will be set to the email address of the author, if supported; else unset.
CHANGE_TARGET
For a multibranch project corresponding to some kind of change request, this will be set to the target or base branch to which the change could be merged, if supported; else unset.
BUILD_NUMBER
The current build number, such as "153"
BUILD_ID
The current build ID, identical to BUILD_NUMBER for builds created in 1.597+, but a YYYY-MM-DD_hh-mm-ss timestamp for older builds
BUILD_DISPLAY_NAME
The display name of the current build, which is something like "#153" by default.
JOB_NAME
Name of the project of this build, such as "foo" or "foo/bar".
JOB_BASE_NAME
Short Name of the project of this build stripping off folder paths, such as "foo" for "bar/foo".
BUILD_TAG
String of "jenkins-${JOB_NAME}-${BUILD_NUMBER}". Convenient to put into a resource file, a jar file, etc for easier identification.
EXECUTOR_NUMBER
The unique number that identifies the current executor (among executors of the same machine) that’s carrying out this build. This is the number you see in the "build executor status", except that the number starts from 0, not 1.
NODE_NAME
Name of the agent if the build is on an agent, or "master" if run on master
NODE_LABELS
Whitespace-separated list of labels that the node is assigned.
WORKSPACE
The absolute path of the directory assigned to the build as a workspace.
JENKINS_HOME
The absolute path of the directory assigned on the master node for Jenkins to store data.
JENKINS_URL
Full URL of Jenkins, like http://server:port/jenkins/ (note: only available if Jenkins URL set in system configuration)
BUILD_URL
Full URL of this build, like http://server:port/jenkins/job/foo/15/ (Jenkins URL must be set)
JOB_URL
Full URL of this job, like http://server:port/jenkins/job/foo/ (Jenkins URL must be set)
GIT_COMMIT
The commit hash being checked out.
GIT_PREVIOUS_COMMIT
The hash of the commit last built on this branch, if any.
GIT_PREVIOUS_SUCCESSFUL_COMMIT
The hash of the commit last successfully built on this branch, if any.
GIT_BRANCH
The remote branch name, if any.
GIT_LOCAL_BRANCH
The local branch name being checked out, if applicable.
GIT_URL
The remote URL. If there are multiple, will be GIT_URL_1, GIT_URL_2, etc.
GIT_COMMITTER_NAME
The configured Git committer name, if any.
GIT_AUTHOR_NAME
The configured Git author name, if any.
GIT_COMMITTER_EMAIL
The configured Git committer email, if any.
GIT_AUTHOR_EMAIL
The configured Git author email, if any.
SVN_REVISION
Subversion revision number that's currently checked out to the workspace, such as "12345"
SVN_URL
Subversion URL that's currently checked out to the workspace.
所以這個BUILD_USER 屬性應該不是原生自帶的,應該是裝了什麼插件纔有的。
2.2 Build User Vars Plugin 插件介紹
官網如下:
https://wiki.jenkins.io/display/JENKINS/Build+User+Vars+Plugin
Variable | Description |
---|---|
BUILD_USER | Full name (first name + last name) |
BUILD_USER_EMAIL | Email address |
BUILD_USER_FIRST_NAME | First name |
BUILD_USER_ID | Jenkins user ID |
BUILD_USER_LAST_NAME | Last name |
使用例子如下:
Pipeline Examples
node {
wrap([$class: 'BuildUser']) {
def user = env.BUILD_USER_ID
}
}
因此我們需要安裝 Build User Vars Plugin 插件,才能獲取到 BUILD_USER 這個變量,並且還得修改pipeline代碼。
三、安裝 Build User Vars Plugin 插件介紹
再次確認老版本的jenkins確實有安裝這個Build User Vars Plugin 插件
因此新版本的jenkins我們也安裝下這個Build User Vars Plugin 插件
進入 http://xxx.xxx.xxx.xxx:8888/jenkins/pluginManager/ 網站,進入插件管理界面
然後點擊【可選插件】
在右上角的過濾輸入框,輸入 user build vars plugin,如下所示:
過濾出插件之後,點擊安裝即可。
安裝過程中
安裝完畢
至此,這個Build User Vars Plugin插件就已經安裝好了。下面我們重新測試下是否可以獲取到BUILD_USER變量。
四、重新測試jenkins任務
4.1 修改PipeLine引用的Jenkinsfile文件
將最後一步通知的代碼從下面的代碼
#!/usr/bin/env groovy
pipeline {
agent any
parameters {
string(name: 'GLOBAL_RECEIVERS', defaultValue: '歐陽鵬', description: '要發送給企業微信的人員列表')
text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')
booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')
choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
}
stages {
stage('Preparation') {
steps {
echo 'Preparation..'
git '[email protected]:ouyangpeng/DelegationAdapter.git'
}
}
stage('Build') {
steps {
echo 'Building..'
sh "cd ${WORKSPACE} "
sh './gradlew assembleRelease'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
stage('Notification') {
steps {
echo 'Notification....'
sh "cd ${WORKSPACE} "
sh "python xutils.py jenkins ${JOB_NAME} ${BUILD_NUMBER} ${GIT_BRANCH} ${BUILD_USER} ${JOB_DESCRIPTION} ${GIT_COMMIT} ${CAUSE} ${BUILD_URL} ${PROJECT_URL} ${GLOBAL_RECEIVERS}"
}
}
}
}
修改爲 下面的代碼
#!/usr/bin/env groovy
pipeline {
agent any
parameters {
string(name: 'GLOBAL_RECEIVERS', defaultValue: '歐陽鵬', description: '要發送給企業微信的人員列表')
}
stages {
stage('Preparation') {
steps {
echo 'Preparation..'
git '[email protected]:ouyangpeng/DelegationAdapter.git'
}
}
stage('Build') {
steps {
echo 'Building..'
sh "cd ${WORKSPACE} "
sh './gradlew assembleRelease'
}
}
stage('Test') {
steps {
echo 'Testing..'
sh './gradlew check'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
post {
always {
echo 'This will always run'
archiveArtifacts artifacts: '*/*.apk'
wrap([$class: 'BuildUser']) {
sh 'echo "${BUILD_USER}"'
sh "python xutils.py jenkins ${JOB_NAME} ${BUILD_NUMBER} ${GIT_BRANCH} ${BUILD_USER} ${GIT_COMMIT} ${BUILD_URL} ${GLOBAL_RECEIVERS}"
}
}
success {
echo 'This will run only if successful'
}
failure {
echo 'This will run only if failed'
}
unstable {
echo 'This will run only if the run was marked as unstable'
}
changed {
echo 'This will run only if the state of the Pipeline has changed'
echo 'For example, if the Pipeline was previously failing but is now successful'
}
}
}
4.2 啓動任務
最後一步成功了,BUILD_USER 變量也成功打印出來了。