从Jenkins工作流(Pipeline)插件中获取已登录Jenkins的用户名

34

我正在使用Cloudbees的Jenkins Pipeline插件(之前称为Workflow插件),我试图在Groovy脚本中获取用户名,但是我无法实现。

stage 'checkout svn'

node('master') {
      // Get the user name logged in Jenkins
}

通过“登录Jenkins的用户名”,您是指登录前端的用户吗?即手动(或自动)触发作业的用户?还是实际在执行环境中运行作业的用户?由于您只在问题的灰色部分进行了区分,因此该问题将受益于更清晰地区分这一点。 - Rick Moritz
@RickMoritz,你已经指出了我的意思,无论如何我已经更新了问题。 - Daniel Hernández
12个回答

60

你尝试安装过Build User Vars插件吗?如果是,那么您应该能够运行

node {
  wrap([$class: 'BuildUser']) {
    def user = env.BUILD_USER_ID
  }
}

或类似的东西。


3
谢谢 :) 很好用,我不知道那个插件,查看更新日志后我发现这是最新的更新,支持工作流插件!太棒了。 - Daniel Hernández
2
我正在尝试使用管道作业。维基上描述应该有一个“设置jenkins用户构建变量”的复选框,但似乎只在“自由风格项目”中可用。我还漏掉了什么吗? - dothebart
1
复选框仅适用于自由风格作业。但对于管道作业,以下是如何查找可用选项的方法。在“片段生成器”复选框或https://your-jenkins.example.com/workflow-cps-snippetizer/dslReference页面中滚动到“wrap: General Build Wrapper”。 - MarkHu
这是一个失效的链接。你有其他的样例链接吗? - Eddie
3
请注意,此插件列为:“用户构建变量插件”。 - dothebart
你真是太棒了。 - Bernardo Vale

21

这里有一个稍微简短一些的版本,不需要使用环境变量:

@NonCPS
def getBuildUser() {
    return currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
}

使用rawBuild需要它在@NonCPS块中。


仅供参考:如果用户在多分支扫描启动构建时点击“Scan Multibranch Pipeline Now”侧边栏链接,则此解决方案或类似解决方案将无法工作。它只能在用户手动点击“Build”或“Build with Parameters”时起作用。 - AKS
如果您想使用BUILD_USER设置构建描述,那么https://stackoverflow.com/questions/67304608/jenkinsfile-jenkins-build-user-getusername-nullpointerexception-cannot-invo中有更好的示例,用于查找/设置用户,当在MultiBranch Pipeline作业中单击“Scan MultiBranch Pipeline Now”侧边栏链接时。 - AKS

21

要让它与Jenkins Pipeline一起使用:

安装用户构建变量插件

然后运行以下命令:

pipeline {
  agent any

  stages {
    stage('build user') {
      steps {
        wrap([$class: 'BuildUser']) {
          sh 'echo "${BUILD_USER}"'
        }
      }
    }
  }
}

对我也起作用了,但对于我的管道来说,我不需要将命令包裹在步骤 { } 中,而且我将命令更改为使用脚本:我会在单独的响应中发布我的成功。 - cgseller
需要将它添加到脚本块中吗? - thclpr
1
这是旧的。我认为这不再需要做了。 - Mark A

12

假设环境中有 JOB_BASE_NAMEBUILD_ID,则可以在不使用插件的情况下完成此操作:

def job = Jenkins.getInstance().getItemByFullName(env.JOB_BASE_NAME, Job.class)
def build = job.getBuildByNumber(env.BUILD_ID as int)
def userId = build.getCause(Cause.UserIdCause).getUserId()

还有一个getUserName函数,它返回用户的全名。


警告:由于安全原因,包含此脚本的作业只能由Jenkins 2上的管理员运行。不过,您可以在“脚本批准”菜单中批准该脚本。 - jeebface
1
当我尝试这个时,我遇到了这个错误:org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance - Katie
JOB_BASE_NAME和BUILD_ID在我的环境中可用。我已经批准了所有脚本权限,但是当使用上述代码时,我遇到了以下错误...java.lang.NullPointerException:无法在空对象上调用getBuildByNumber()方法。 - bencampbell_14
@bencampbell_14 - 你可能在“job”值上有一个“null”。在第二行的“job”符号名称后面加上“?”。(也许在第三行的“build”后面也要加) - Alexander Stohr
Jenkinsfile:Jenkins Build User.getUsername()NullPointerException - 无法调用答案 - AKS
java.lang.NullPointerException: 无法在空对象上调用getBuildByNumber()方法 - JRichardsz

8

在没有构建用户插件的情况下,以下方法适用于我:

// get first entry of JSONArray
def buildCause = currentBuild.getBuildCauses()[0]
def buildPrincipal = [type:"unknown", name:""]

if (buildCause._class ==~ /.+BranchEventCause/) {
  def branchCause = currentBuild.getRawBuild().getCause(jenkins.branch.BranchEventCause)
  buildPrincipal = [type:"branch",name:buildCause.shortDescription]

} else
if (buildCause._class ==~ /.+TimerTriggerCause/) {
  def timerCause = currentBuild.getRawBuild().getCause(hudson.triggers.TimerTrigger.TimerTriggerCause)
  buildPrincipal = [type:"timer", name:"Timer event"]

} else
if (buildCause._class ==~ /.+UserIdCause/) {
  def buildUserCause = currentBuild.getRawBuild().getCause(hudson.model.Cause.UserIdCause)
  buildPrincipal = [type:"user", name:buildCause.userId]

} else
// ... other causes

我喜欢这个,因为如果你想选择一个用户来通知,当它是UserIdCause时,你使用它,但如果它是一个分支,使用GIT_COMMITTER。对于由计时器驱动的故障,通知谁可能是没有人,或者是devops... - Ajax

6
def jobUserId, jobUserName
//then somewhere
wrap([$class: 'BuildUser']) {
    jobUserId = "${BUILD_USER_ID}"
    jobUserName = "${BUILD_USER}"
}
//then
println("Started By: ${jobUserName}")

我们使用了这个插件:Build User Vars Plugin。还有更多的变量可用。

请问您能否提供更多关于如何实现它的细节?我对Jenkins还不熟悉,非常感谢您的帮助。 - Z.Liu
你能告诉我你具体要实现什么吗??我已经将近1.5年没有使用Jenkins了。这就是原因。 - Anand Varkey Philips
非常感谢您的回复,我已经实现了它。起初,我不知道如何使用“def jobUsername”,因为我想在共享库中使用它,然后我使用该函数获取用户并返回用户名。再次感谢。 - Z.Liu

2
//Below is a generic groovy function to get the XML metadata for a Jenkins build.
//curl the env.BUILD_URL/api/xml parse it with grep and return the string
//I did an or true on curl, but possibly there is a better way
//echo -e "some_string \c" will always return some_string without \n char     
//use the readFile() and return the string
def GetUserId(){
 sh """
 /usr/bin/curl -k -s -u \
 \$USERNAME:\$PASSWORD -o \
 /tmp/api.xml \
 \$BUILD_URL/api/xml || true 

 THE_USERID=`cat /tmp/api.xml | grep -oP '(?<=<userId>).*?(?=</userId>)'`
 echo -e "\$THE_USERID \\c" > /tmp/user_id.txt                               
 """
def some_userid = readFile("/tmp/user_id.txt")
some_userid
}

1
以下代码受到Juergen solution的启发,但我添加了更多可能的触发原因,并以格式化的方式显示它们:
String getTriggerReason() {
  def buildCause = currentBuild.getBuildCauses()[0]
  if (buildCause._class ==~ /.+(BranchEventCause|BranchIndexingCause)/) {
    if (env.JOB_BASE_NAME == 'master') {
      return 'Triggered by master commit'
    } else {
      return "Triggered by ${buildCause.shortDescription}"
    }
  }
  if (buildCause._class ==~ /.+TimerTriggerCause/) {
    return 'Triggered by timer'
  }
  if (buildCause._class ==~ /.+BuildUpstreamCause/) {
    return "Triggered by build #${buildCause.upstreamBuild}"
  }
  if (buildCause._class ==~ /.+UserIdCause/) {
    def userName = buildCause.userName.replaceFirst(/\s?\(.*/, '')
    return "Triggered by user ${userName}"
  }
  return 'Unknown trigger'
}

当提供类似的选项范围时: https://www.jenkins.io/doc/book/pipeline/syntax/#when - coz

1

编辑: 我重新阅读了问题 - 下面的内容只能获取到运行构建的用户(在技术上通常更有趣),而不是触发构建的用户(无论是REST-API还是WebUI)。如果您启用了Jenkins模拟,则我认为结果应该是等效的,否则这只会让您获得拥有构建机器上Jenkins代理的用户。

原始答案:

另一种方法是

sh 'export jenkins_user=$(whoami)'

缺点:依赖于Linux,难以在单个构建中跨多个代理进行移植(但是,每个从机的认证上下文可能不同)。
优点:无需安装插件(在共享/大型Jenkins实例上可能会很棘手)。

1

我修改了@shawn derik的回应,使其在我的管道中正常工作:

    stage("preserve build user") {
            wrap([$class: 'BuildUser']) {
                GET_BUILD_USER = sh ( script: 'echo "${BUILD_USER}"', returnStdout: true).trim()
            }
        }

然后,我可以通过传递它或在与${GET_BUILD_USER}相同的作用域中引用该变量。我安装了被引用的同一插件。


Shawn Derik再也没有回答了。可能用户名已更改。 解决方案只能在“Build User Vars”插件存在的情况下正常工作。 - Alexander Stohr
谢谢 - 是的,需要插件。 - cgseller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接