jenkinsci / jenkinsci/git-plugin
[JENKINS-39968] git checkouts are not pipeline-parallel safe
- Dominant language
- Java
- Stars
- 694
- Forks
- 1.1k
- Avg merge
- 1h 29m
- Merged PRs (30d)
- 3
Description
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 = 8stage('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}"]
idx++
}
}
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
}
---
Originally reported by
roidelapluie, imported from: git checkouts are not pipeline-parallel safe
Raw content of original issue
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 = 8stage('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}"]
idx++
}
}
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
}
2 attachments
- [parallelcheckout.png](https://issues.jenkins.io/secure/attachment/34959/parallelcheckout.png)
> 
- [parallelcheckout2.png](https://issues.jenkins.io/secure/attachment/34958/parallelcheckout2.png)
> 
Contributor guide
Assessment
This issue has not been assessed yet.