-->

Jenkins Pipeline - How do I use the 'tool'

2020-07-10 08:51发布

问题:

I have a custom tool defined within Jenkins via the Custom Tools plugin. If I create a freestyle project the Install custom tools option correctly finds and uses the tool (Salesforce DX) during execution.

However, I cannot find a way to do the same via a pipeline file. I have used the pipeline syntax snippet generator to get:

tool name: 'sfdx', type: 'com.cloudbees.jenkins.plugins.customtools.CustomTool'

I have put that into my stage definition:

stage('FetchMetadata') {
    print 'Collect Prod metadata via SFDX'
    tool name: 'sfdx', type: 'com.cloudbees.jenkins.plugins.customtools.CustomTool'
    sh('sfdx force:mdapi:retrieve -r metadata/ -u DevHub -k ./metadata/package.xml')
}

but I get an error message stating line 2: sfdx: command not found

Is there some other way I should be using this snippet?

Full Jenkinsfile for info:

node {
    currentBuild.result = 'SUCCESS'`

        try {
            stage('CheckoutRepo') {
                print 'Get the latest code from the MASTER branch'
                checkout scm
            }

            stage('FetchMetadata') {
                print 'Collect Prod metadata via SFDX'
                tool name: 'sfdx', type: 'com.cloudbees.jenkins.plugins.customtools.CustomTool'
                sh('sfdx force:mdapi:retrieve -r metadata/ -u DevHub -k ./metadata/package.xml')
            }

            stage('ConvertMetadata') {
                print 'Unzip retrieved metadata file'
                sh('unzip unpackaged.zip .')
                print 'Convert metadata to SFDX format'
                sh('/usr/local/bin/sfdx force:mdapi:convert -r metadata/unpackaged/ -d force-app/')
            }

            stage('CommitChanges') {
                sh('git add --all')
                print 'Check if any changes need committing'
                sh('if ! git diff-index --quiet HEAD --; then echo "changes found - pushing to repo"; git commit -m "Autocommit from Prod @ $(date +%H:%M:%S\' \'%d/%m/%Y)"; else echo "no changes found"; fi')
                sshagent(['xxx-xxx-xxx-xxx']) {
                    sh('git push -u origin master')
                }
            }
        }
        catch (err) {
            currentBuild.result = 'FAILURE'
            print 'Build failed'
            error(err)
        }
}

UPDATE I have made some progress using this example Jenkinsfile My stage now looks like this:

        stage('FetchMetadata') {
            print 'Collect Prod metadata via SFDX'
            def sfdxLoc =  tool 'sfdx'
            sh script: "cd topLevel; ${sfdxLoc}/sfdx force:mdapi:retrieve -r metadata/ -u DevHub -k ./metadata/package.xml"
        }

Unfortunately, although it looks like Jenkins is now finding and running the sfdx tool, I get a new error:

TypeError: Cannot read property 'run' of undefined
    at Object.<anonymous> (/var/lib/jenkins/.cache/sfdx/tmp/heroku-script-509584048:20:4)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3

回答1:

I ran into the same problem. I got to this workaround:

 environment {
    GROOVY_HOME = tool name: 'Groovy-2.4.9', type: 'hudson.plugins.groovy.GroovyInstallation'
}
stages {
    stage('Run Groovy') {
        steps {
            bat "${groovy_home}/bin/groovy <script.name>"
        }
    }
}

Somehow the tool path is not added to PATH by default (as was customary on my 1.6 Jenkins server install). Adding the ${groovy_home} when executing the bat command fixes that for me. This way of calling a tool is basically lent from the scripted pipeline syntax. I am using this for all my custom tools (not only groovy).

The tool part:

tool name: 'Groovy-2.4.9', type: 'hudson.plugins.groovy.GroovyInstallation'

was generated by the snippet generator like you did.

According to the Jenkins users mailing list, work is still ongoing for a definitive solution, so my solution really is a work around.



回答2:

This is my first time commenting on stack overflow, but I've been looking for this answer for a few days and I think I have a potential solution. Checking out Fholst answer, I'd like to expand on it. That environment stanza I think may work for declarative syntax, but on a scripted pipeline you must use the withEnv() equivalent, and pass in the tools via a gString: i.e. ${tool 'nameOfToolDefinedInGlobalTools'}. For my particular use case, for reasons beyond my control, we do not have maven installed on our jenkins host machine, but there is one defined within the global tools configuration. This means I need to add mvn to the path before executing my sh commands within my steps. What I have been able to do is this:

        withEnv(["PATH+MVN=${tool 'NameOfMavenTool'}/bin"]){
            sh '''
                echo "PATH = ${PATH}"
            '''
        }

This should give you what you need. Please ignore the triple single quotes on the sh line, I actually have several environment variables loaded and simply removed them from my snippet.

Hope this helps anyone who has been searching for this solution for days. I feel your pain. Cobbled this together from looking through the console output of a declarative pipeline script (if you use tools{} stanza it will show you how it builds those environment variables and wraps your subsequent declarative steps) and the following link: https://go.cloudbees.com/docs/cloudbees-documentation/use/automating-projects/jenkinsfile/



回答3:

You may be having a problem because of the path to your sfdx install folder if you are on Windows. The Dreamhouse Jenkinsfile was written for a linux shell or Mac terminal so some changes are necessary to make it work on Windows.

${sfdxLoc}/sfdx

Should be

\"${sfdxLoc}/sfdx\"

So that the command line handles any spaces properly.

https://wipdeveloper.com/2017/06/22/salesforce-dx-jenkins-jenkinsfile/