Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jenkins pipeline - How to give choice parameters dynamically

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}"
        }
    }
  }
}

In this above code, The choice are hardcoded (patch\nminor\nmajor) -- My requirement is to dynamically give choice values in the dropdown. I get the values from calling api - Artifacts list (.zip) file names from artifactory In the above example, It request input when we do the build, But i want to do a "Build with parameters"

Please suggest/help on this.

like image 942
Springhills Avatar asked Mar 28 '18 03:03

Springhills


3 Answers

Depends how you get data from API there will be different options for it, for example let's imagine that you get data as a List of Strings (let's call it releaseScope), in that case your code be following:

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

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


hope it will help.

like image 72
BigGinDaHouse Avatar answered Nov 15 '22 08:11

BigGinDaHouse


This is a cutdown version of what we use. We separate stuff into shared libraries but I have consolidated a bit to make it easier.

Jenkinsfile looks something like this:

#!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: '')
    ])
])

Shared library that looks at artifactory, its pretty simple. Essentially make GET Request (And provide auth creds on it) then filter/split result to whittle down to desired values and return list to 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

}
like image 26
metalisticpain Avatar answered Nov 15 '22 09:11

metalisticpain


I could achieve it without any plugin:

With Jenkins 2.249.2 using a declarative pipeline, the following pattern prompt the user with a dynamic dropdown menu (for him to choose a branch):

(the surrounding withCredentials bloc is optional, required only if your script and jenkins configuration do use credentials)

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}"
            }
        }
    }
}

The drawback is that one should refresh the jenkins configration and use a blank run for the list be refreshed using the script ... Solution (not from me): This limitation can be made less anoying using an aditional parameters used to specifically refresh the values:

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

then wihtin stage:

stage('a stage') {
   when {
      expression { 
         return ! params.REFRESH_BRANCHES.toBoolean()
      }
   }
   ...
}
like image 38
user1767316 Avatar answered Nov 15 '22 07:11

user1767316