一、需求描述

最近在一台测试服务器上安装最新版本的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

VariableDescription
BUILD_USERFull name (first name + last name)
BUILD_USER_EMAILEmail address
BUILD_USER_FIRST_NAMEFirst name
BUILD_USER_IDJenkins user ID
BUILD_USER_LAST_NAMELast 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文件

参考 https://stackoverflow.com/questions/35902664/get-username-logged-in-jenkins-from-jenkins-workflow-pipeline-plugin#35902865
在这里插入图片描述

将最后一步通知的代码从下面的代码

#!/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 'git@172.28.xxx.xxx: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 'git@172.28.xxx.xxx: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 变量也成功打印出来了。

在这里插入图片描述

在这里插入图片描述

五、参考资料

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐