【问题标题】:Jenkins pipeline - How to give choice parameters dynamically詹金斯管道 - 如何动态给出选择参数
【发布时间】:2021-08-28 18:56:51
【问题描述】:
pipeline {
  agent any
  stages {
    stage("foo") {
        steps {
            script {
                env.RELEASE_SCOPE = input message: 'User input required', ok: 'Release!',
                        parameters: [choice(name: 'RELEASE_SCOPE', choices: 'patch\nminor\nmajor', 
                                     description: 'What is the release scope?')]
            }
            echo "${env.RELEASE_SCOPE}"
        }
    }
  }
}

在上面的代码中,选择是硬编码的(补丁\nminor\nmajor)——我的要求是在下拉列表中动态给出选择值。 我从调用 api 获取值 - Artifacts list (.zip) file names from artifactory 在上面的例子中,当我们构建时它请求输入,但我想做一个“带参数的构建”

请就此提出建议/帮助。

【问题讨论】:

  • 你使用什么 api 或者 api 值存储在哪里?
  • 我正在使用人工 api 并且值存储在文件中 - 并通过读取文件将它们调用到变量中。我正在努力学习,需要更好的方法。我需要将值从 repo 填充到选择/主动选择参数
  • 这能回答你的问题吗? How to call REST from jenkins workflow

标签: jenkins jenkins-pipeline


【解决方案1】:

取决于你如何从 API 获取数据,它会有不同的选项,例如让我们假设你以字符串列表的形式获取数据(我们称之为 releaseScope),在这种情况下你的代码如下:

...
script {
    def releaseScopeChoices = ''
    releaseScope.each {
        releaseScopeChoices += it + '\n'
    }

    parameters: [choice(name: 'RELEASE_SCOPE', choices: ${releaseScopeChoices}, description: 'What is the release scope?')]
}
...


希望对您有所帮助。

【讨论】:

  • 非常感谢。可能这就是我需要的。这是我的 api 调用以及我过去如何存储值列表我有一个人工仓库,它有一个 zip 文件列表,我想在选择/活动选择参数中填充以下是我使用的代码
  • 管道 { 代理 { 标签 'Linuxnode' } 阶段 { 阶段(“调用 api”) { 步骤 { 脚本 { sh '''#!/usr/bin/sh VAR=$(curl -s -X POST -k -u uname:pwd \'artifactory.com/artifactory/api/search/aql\' -d \'items.find({"repo":"datasources-local"})\') echo $VAR | python -c \'导入 json,sys; obj=json.load(sys.stdin); for i in range(len(obj["results"])): print obj["results"][i]["name"]\' >> k.txt''' env.WORKSPACE = pwd() def p = readFile "${env.WORKSPACE}/k.txt" println(p) } }
  • 在上面的代码中 p - 变量将包含 zip 文件的列表 - 我想将它们填充到选择参数.. 请帮助解决这个问题。
  • 您正在尝试在 shell 脚本中完成所有工作,这很棒,但让我让您的生活更轻松一些 - Jenkins Pipeline 让您使用 Groovy ,所以考虑使用它,在您的情况下会很多更简单更好的代码并且都在同一个地方,你不需要使用系统变量。
  • 另外,如果答案正确,请标记为正确
【解决方案2】:

这是我们使用的精简版。我们将内容分离到共享库中,但我进行了一些合并以使其更容易。

Jenkinsfile 看起来像这样:

#!groovy
@Library('shared') _
def imageList = pipelineChoices.artifactoryArtifactSearchList(repoName, env.BRANCH_NAME)
imageList.add(0, 'build')
properties([
    buildDiscarder(logRotator(numToKeepStr: '20')),
    parameters([
        choice(name: 'ARTIFACT_NAME', choices: imageList.join('\n'), description: '')
    ])
])

查看工件的共享库,非常简单。 本质上是发出 GET 请求(并在其上提供身份验证凭据),然后过滤/拆分结果以减少到所需的值并将列表返回给 Jenkinsfile。

import com.cloudbees.groovy.cps.NonCPS
import groovy.json.JsonSlurper
import java.util.regex.Pattern
import java.util.regex.Matcher   

List artifactoryArtifactSearchList(String repoKey, String artifact_name, String artifact_archive, String branchName) {
    // URL components
    String baseUrl = "https://org.jfrog.io/org/api/search/artifact"
    String url = baseUrl + "?name=${artifact_name}&repos=${repoKey}"

    Object responseJson = getRequest(url)

    String regexPattern = "(.+)${artifact_name}-(\\d+).(\\d+).(\\d+).${artifact_archive}\$"

    Pattern regex = ~ regexPattern
    List<String> outlist = responseJson.results.findAll({ it['uri'].matches(regex) })
    List<String> artifactlist=[]

    for (i in outlist) {
        artifactlist.add(i['uri'].tokenize('/')[-1])
    }

    return artifactlist.reverse()
}

// Artifactory Get Request - Consume in other methods
Object getRequest(url_string){

    URL url = url_string.toURL()

    // Open connection
    URLConnection connection = url.openConnection()

    connection.setRequestProperty ("Authorization", basicAuthString())

    // Open input stream
    InputStream inputStream = connection.getInputStream()
    @NonCPS
    json_data = new groovy.json.JsonSlurper().parseText(inputStream.text)
    // Close the stream
    inputStream.close()

    return json_data
}

// Artifactory Get Request - Consume in other methods
Object basicAuthString() {
    // Retrieve password
    String username = "artifactoryMachineUsername"
    String credid = "artifactoryApiKey"
    @NonCPS
    credentials_store = jenkins.model.Jenkins.instance.getExtensionList(
        'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
        )
    credentials_store[0].credentials.each { it ->
        if (it instanceof org.jenkinsci.plugins.plaincredentials.StringCredentials) {
            if (it.getId() == credid) {
                apiKey = it.getSecret()
            }
        }
    }
    // Create authorization header format using Base64 encoding
    String userpass = username + ":" + apiKey;
    String basicAuth = "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(userpass.getBytes());

    return basicAuth

}

【讨论】:

  • 我正在尝试您提供的上述脚本.. 但我没有管理员权限来放入库中,并且在尝试使用 groovy 列出工件时出现“peer not authenticated”错误。我以前尝试使用 -k 选项进行 curl。如果你能给我一个没有库和主动选择参数的脚本,那就太好了
  • 只要在jenkinsfile中定义相同的方法,就不需要调用共享库了。
  • @metalisticpain 请您解释一下body.artifacts 的来源choices: body.artifacts.join('\n')。还有pipelineChoicesimageList.add(0, 'build')。我无法理解这些。谢谢
  • 几年后再看这段代码,我想你在我的例子中发现了一个错字。看起来我拼凑起来创建了一个小例子,但有些参考文献并不正确。 body.artifacts.join('\n') 应该是 imageList.join('\n') pipelineChoicesartifactoryArtifactSearchList 函数所在的共享库的文件名。这只是对它的调用。
  • imageList.add(0, 'build')build 添加到返回的列表中。所以说我的imageList返回['image1', 'image2'],然后我在索引0处添加build。所以它变成['build', 'image1', 'image2']。我这样做是因为选择参数的“默认”选项是第一个值。
【解决方案3】:

我可以在没有任何插件的情况下实现它:

对于使用声明式管道的 Jenkins 2.249.2, 以下模式使用动态下拉菜单提示用户 (供他选择分支):

(周围的 withCredentials 块是可选的,仅当您的脚本和 jenkins 配置确实使用凭据时才需要)

node {

    withCredentials([[$class: 'UsernamePasswordMultiBinding',
                  credentialsId: 'user-credential-in-gitlab',
                  usernameVariable: 'GIT_USERNAME',
                  passwordVariable: 'GITLAB_ACCESS_TOKEN']]) {
        BRANCH_NAMES = sh (script: 'git ls-remote -h https://${GIT_USERNAME}:${GITLAB_ACCESS_TOKEN}@dns.name/gitlab/PROJS/PROJ.git | sed \'s/\\(.*\\)\\/\\(.*\\)/\\2/\' ', returnStdout:true).trim()
    }
}
pipeline {

    agent any

    parameters {
        choice(
            name: 'BranchName',
            choices: "${BRANCH_NAMES}",
            description: 'to refresh the list, go to configure, disable "this build has parameters", launch build (without parameters)to reload the list and stop it, then launch it again (with parameters)'
        )
    }

    stages {
        stage("Run Tests") {
            steps {
                sh "echo SUCCESS on ${BranchName}"
            }
        }
    }
}

缺点是应该刷新 jenkins 配置并使用空白运行来使用脚本刷新列表... 解决方案(不是来自我):使用用于专门刷新值的附加参数可以减少此限制:

parameters {
        booleanParam(name: 'REFRESH_BRANCHES', defaultValue: false, description: 'refresh BRANCH_NAMES branch list and launch no step')
}

然后在阶段:

stage('a stage') {
   when {
      expression { 
         return ! params.REFRESH_BRANCHES.toBoolean()
      }
   }
   ...
}

【讨论】:

    【解决方案4】:

    这是我的解决方案。

    def envList
    def dockerId
    node {
        envList = "defaultValue\n" + sh (script: 'kubectl get namespaces --no-headers -o custom-columns=":metadata.name"', returnStdout: true).trim()
    }
    pipeline {
        agent any
        parameters {
            choice(choices: "${envList}", name: 'DEPLOYMENT_ENVIRONMENT', description: 'please choose the environment you want to deploy?')
            booleanParam(name: 'SECURITY_SCAN',defaultValue: false, description: 'container vulnerability scan')
        }
    

    【讨论】:

    • 是的,像我一样here 提示选择分支
    【解决方案5】:

    下面的 Jenkinsfile 示例包含用于从 AWS ECR 动态获取 Docker 映像列表的 AWS CLI 命令,但可以将其替换为您自己的命令。 Active Choices Plug-in 为必填项。

    注意!在“管理Jenkins”->“In-process Script Approval”中首次运行后需要批准parameters中指定的脚本,或者打开作业配置并保存批准 自动(可能需要管理员权限)。

    properties([
      parameters([[
        $class: 'ChoiceParameter',
        choiceType: 'PT_SINGLE_SELECT',
        name: 'image',
        description: 'Docker image',
        filterLength: 1,
        filterable: false,
        script: [
          $class: 'GroovyScript',
          fallbackScript: [classpath: [], sandbox: false, script: 'return ["none"]'],
          script: [
            classpath: [],
            sandbox: false,
            script: '''\
              def repository = "frontend"
              def aws_ecr_cmd = "aws ecr list-images" +
                                " --repository-name ${repository}" +
                                " --filter tagStatus=TAGGED" +
                                " --query imageIds[*].[imageTag]" +
                                " --region us-east-1 --output text"
              def aws_ecr_out = aws_ecr_cmd.execute() | "sort -V".execute()
              def images = aws_ecr_out.text.tokenize().reverse()
              return images
            '''.stripIndent()
          ]
        ]
      ]])
    ])
    
    pipeline {
      agent any
    
      stages {  
        stage('First stage') {
          steps {
            sh 'echo "${image}"'
          }
        }
      }
    }
    

    【讨论】:

    • 我不得不使用 $class: 'ChoiceParameterDefinition' 而不是 ,$class: 'ChoiceParameter',以避免出现以下错误:java.lang.UnsupportedOperationException: no known implementation of class hudson.model.ParameterDefinition被命名为 ChoiceParameter ( .... 即使我现在使用 def proc = 'git for-each-ref --format=\'%(refname:short)\' refs/heads/' 在我的组合中还没有任何值.execute() 来检索分支列表)另外我发现在专用管理页面中没有可用于批准的脚本
    【解决方案6】:
    choiceArray = [ "patch" , "minor" , "major" ]
    
    properties([
        parameters([
                choice(choices: choiceArray.collect { "$it\n" }.join(' ') ,
                        description: '',
                        name: 'SOME_CHOICE')
    
        ])
    ])
    

    【讨论】:

    • 他的选择是动态的。这意味着他需要拨打网络电话。这没有回答问题
    • 只有代码的答案很少有用。请提供解释
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-09
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多