Jenkins File in Git – Best Checkout Options

This post looks at options on how to define checkout options for Jenkins declarative pipeline jobs. Advanced options could be ‘shallow clone’, ‘check out specific branch’, ‘clean before/after checkout’ and more.

Storing Jenkins files in Git helps to simplify management of build jobs and makes them portable. But what is the best place to define specific checkout or clone behaviours?
In the Jenkins job definition? Or within the pipeline steps?

The answer will be different, depending on the scenario. First we need to understand what happens in a pipeline job.

Jenkins File in Git
  1. When the job starts, it retrieves the jenkinsfile from the repository. Even though the file is used from the specified branch, no branch is checked out locally.
  2. By default the Git plugin clones the repository with all options which are specified in the UI. This behavior can be disabled by specifying SkipDefaultCheckout() in the pipeline options. After this step the Git variables like GIT_COMMIT and GIT_URL are available in the pipeline.
  3. The pipeline executes all remaining steps.

Define Checkout Options in UI

It is easiest to define the checkout options in the Jenkins UI. This has the advantage that information like the Git URL and the commit hash are available in the pipeline without any further action. The following code snippet will log the information to the console.

            echo("GIT_URL: ${env.GIT_URL}")
            echo("GIT_BRANCH: ${env.GIT_BRANCH}")
            echo("GIT_LOCAL_BRANCH: ${env.GIT_LOCAL_BRANCH}")

For a complete list of variables check the Jenkins documentation.

Disadvantage: If the same pipeline file is used for multiple jobs, that means all checkout options have to be specified for each of these jobs.

Define Checkout Options in a Pipeline Step

When specifying checkout options in the pipeline file, the repository URL and credentials need to be specified twice: Once in the job definition to retrieve the pipeline file and again in the pipeline step. As far as I can tell, the configuration from the UI for the which specifies how to get the pipeline file from SCM is not available.

Downside: Even though it is likely that the GIT url will not change, the Jenkins credentials may change over time. It also means that the user remote configuration between job configuration and pipeline may drift. Users now have to check both places if there are issues checking out the code.

One mitigation could be to define the user remote credentials in a Jenkins shared library, but that comes with other challenges. Which pipelines are using the credentials? If the credentials/URL change, does this apply to all jobs?

The following snippet shows how to check out a repository with specific options in a declarative pipeline. Note that the GIT variables are not available directly as environment variables. Since a pipeline could run multiple checkout operations, the information for the checkout is stored in a specific variable. The checkout step is inside a script block to store the GIT parameters inside the variable ‘scmVars’.

script{
                scmVars = checkout([
                    $class: 'GitSCM', 
                    branches: [[name: "refs/remotes/origin/play"]], 
                    doGenerateSubmoduleConfigurations: false, 
                    extensions: [
                        [$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: true], 
                        [$class: 'LocalBranch', localBranch: "play"], 
                        [$class: 'CleanCheckout']], 
                    submoduleCfg: [],
                    userRemoteConfigs: [[credentialsId: 'github-credentials', url: 'https://github.com/angelae/....git']]
                ])
                }

                echo "SCM vars: ${scmVars}"

Conclusion

It is hard to find one good answer to the problem. Depending on the repository and pipeline use different options will be preferable.

A good default option is to start with defining the checkout options in the Jenkins job.

In the following circumstances it can make sense to move the checkout options into the pipeline file instead:

  1. The same pipeline is used in multiple different jobs, and due to repository size or other circumstances it is important that all jobs have the same checkout options. Keep in mind that the repository credentials also need to be specified for each job to retrieve the pipeline file.
  2. A big mono-repository contains multiple pipelines. Because of the repository size it may be required that all checkouts should be done with specific options, for instance shallow clone. In that case a checkout function in a Jenkins shared library allows to share options between jobs. The git URL and credentials will still need to be specified in each Jenkins job to retrieve the pipeline file, and once in the shared library.

Angela Evans

Senior Software Engineer at Diligent in Christchurch, New Zealand