Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-39968

git checkouts are not pipeline-parallel safe


      We have a specific workflow that enables us to discover that bug. However, it could and will probably happen to other people soon.

      When running scm checkouts in parallels in a Jenkins file, the changes discovered are discovered for every git checkout that runs at the same time.

      In our example, we run checkouts with 8 threads in parallel (background: https://roidelapluie.be/blog/2016/11/18/gitslave-jenkins/ ).

      One change is displayed in 8 different repositories, the 8 repositories that are checked out at the same time.

      The next checkouts do not contains the changes, so I guess it is kind of a global variable that is reset after the checkout.

      lock('checkout') {
          def checkouts = [:]
          def threads = 8
          stage('Super Repo') {
              checkout([$class: 'GitSCM',
                      branches: [[name: branch]],
                      doGenerateSubmoduleConfigurations: false,
                      extensions: [[$class: 'CleanCheckout'], [$class: 'ScmName', name: 'super']],
                      submoduleCfg: [],
                      userRemoteConfigs: [[url: "${gitBaseUrl}/${superRepo}"]]])
              def repos = readFile('.gitslave')
              def reposLines = repos.readLines()
              for (i = 0; i < threads; i++){
                  checkouts["Thread ${i}"] = []
              def idx = 0
              for (line in reposLines) {
                  def repoInfo = line.split(' ')
                  def repoUrl = repoInfo[0]
                  def repoPath = repoInfo[1]
                  def curatedRepoUrl = repoUrl.substring(4, repoUrl.length()-1)
                  def curatedRepoPath = repoPath.substring(1, repoPath.length()-1)
                  echo("Thread ${idx%threads}")
                  checkouts["Thread ${idx%threads}"] << [path: curatedRepoPath, url: "${gitBaseUrl}/${curatedRepoUrl}"]
          stage('GitSlave Repos') {
              def doCheckouts = [:]
              for (i = 0; i < threads; i++){
                  def j = i
                  doCheckouts["Thread ${j}"] = {
                      for (co in checkouts["Thread ${j}"]) {
                          retry(3) {
                              checkout([$class: 'GitSCM',
                                      branches: [[name: branch]],
                                      doGenerateSubmoduleConfigurations: false,
                                      extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: co.path], [$class: 'CleanCheckout'], [$class: 'ScmName', name: co.path]],
                                      submoduleCfg: [],
                                      userRemoteConfigs: [[url: co.url]]])
              parallel doCheckouts

            Unassigned Unassigned
            roidelapluie Julien Pivotto
            5 Vote for this issue
            10 Start watching this issue