You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-11-06 09:09:19 +02:00
feat(codeql) merge commit git reference (#3877)
Sets git reference and gitRemoteCommitId. Jenkins has 2 strategies - 'Merging the pull request with the current target branch revision' and 'The current pull request revision'. When 'Merging the pull request with the current target branch revision' is run, Jenkins creates a local merge commit and runs a job for that particular merge commitId. This commitId is then used for codeql to upload sarif, on upload it throws an error as the merge commit does not exist in github. To resolve this we have introduces a new variable 'gitRemoteCommitId' in commonPipelineEnvironment which gives the remote merge commit id.
This commit is contained in:
@@ -107,6 +107,10 @@ func uploadResults(config *codeqlExecuteScanOptions, utils codeqlExecuteScanUtil
|
||||
return errors.New("failed running upload-results as github token was not specified")
|
||||
}
|
||||
|
||||
if config.CommitID == "NA" {
|
||||
return errors.New("failed running upload-results as gitCommitId is not available")
|
||||
}
|
||||
|
||||
var repoInfo RepoInfo
|
||||
err := getGitRepoInfo(config.Repository, &repoInfo)
|
||||
if err != nil {
|
||||
|
||||
@@ -303,7 +303,7 @@ func codeqlExecuteScanMetadata() config.StepData {
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "git/commitId",
|
||||
Param: "git/remoteCommitId",
|
||||
},
|
||||
},
|
||||
Scope: []string{},
|
||||
|
||||
@@ -32,6 +32,11 @@ func TestRunCodeqlExecuteScan(t *testing.T) {
|
||||
assert.Error(t, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils()))
|
||||
})
|
||||
|
||||
t.Run("GitCommitID is NA on upload results", func(t *testing.T) {
|
||||
config := codeqlExecuteScanOptions{BuildTool: "maven", UploadResults: true, ModulePath: "./", CommitID: "NA"}
|
||||
assert.Error(t, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils()))
|
||||
})
|
||||
|
||||
t.Run("Upload results with token", func(t *testing.T) {
|
||||
config := codeqlExecuteScanOptions{BuildTool: "maven", ModulePath: "./", UploadResults: true, GithubToken: "test"}
|
||||
assert.Equal(t, nil, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils()))
|
||||
|
||||
@@ -110,7 +110,7 @@ spec:
|
||||
description: "SHA of commit that was analyzed."
|
||||
resourceRef:
|
||||
- name: commonPipelineEnvironment
|
||||
param: git/commitId
|
||||
param: git/remoteCommitId
|
||||
type: string
|
||||
containers:
|
||||
- image: ""
|
||||
|
||||
@@ -4,6 +4,63 @@ boolean insideWorkTree() {
|
||||
return sh(returnStatus: true, script: 'git rev-parse --is-inside-work-tree 1>/dev/null 2>&1') == 0
|
||||
}
|
||||
|
||||
boolean isMergeCommit(){
|
||||
def cmd = 'git rev-parse --verify HEAD^2'
|
||||
return sh(returnStatus: true, script: cmd) == 0
|
||||
}
|
||||
|
||||
String getGitMergeCommitId(String gitChangeId){
|
||||
if(!scm){
|
||||
throw new Exception('scm content not found')
|
||||
}
|
||||
|
||||
def remoteConfig = scm.getUserRemoteConfigs()
|
||||
if(!remoteConfig || remoteConfig.size() == 0 || !remoteConfig[0].getCredentialsId()){
|
||||
throw new Exception('scm remote configuration not found')
|
||||
}
|
||||
|
||||
|
||||
def scmCredId = remoteConfig[0].getCredentialsId()
|
||||
try{
|
||||
withCredentials([gitUsernamePassword(credentialsId: scmCredId, gitToolName: 'git-tool')]) {
|
||||
sh 'git fetch origin "+refs/pull/'+gitChangeId+'/*:refs/remotes/origin/pull/'+gitChangeId+'/*"'
|
||||
}
|
||||
} catch (Exception e) {
|
||||
echo 'Error in running git fetch'
|
||||
throw e
|
||||
}
|
||||
|
||||
String commitId
|
||||
def cmd = "git rev-parse refs/remotes/origin/pull/"+gitChangeId+"/merge"
|
||||
try {
|
||||
commitId = sh(returnStdout: true, script: cmd).trim()
|
||||
} catch (Exception e) {
|
||||
echo 'Exception occurred getting the git merge commitId'
|
||||
throw e
|
||||
}
|
||||
|
||||
return commitId
|
||||
}
|
||||
|
||||
boolean compareParentsOfMergeAndHead(String mergeCommitId){
|
||||
try {
|
||||
String mergeCommitParents = sh(returnStdout: true, script: "git rev-parse ${mergeCommitId}^@ | tac").trim()
|
||||
String headCommitParents = sh(returnStdout: true, script: "git rev-parse HEAD^@").trim()
|
||||
if(mergeCommitParents.equals(headCommitParents)){
|
||||
return true
|
||||
}
|
||||
} catch (Exception e) {
|
||||
echo 'Error comparing merge commit parents and local merge commit parents'
|
||||
throw e
|
||||
}
|
||||
|
||||
|
||||
echo "GH merge parents: ${mergeCommitParents}"
|
||||
echo "Local merge parents: ${headCommitParents}"
|
||||
echo 'Github merge parents and local merge parents do not match; PR was updated since Jenkins job started. Try re-running the job.'
|
||||
return false
|
||||
}
|
||||
|
||||
boolean isWorkTreeDirty() {
|
||||
|
||||
if(!insideWorkTree()) error 'Method \'isWorkTreeClean\' called outside a git work tree.'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import com.sap.piper.DefaultValueCache
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.GitUtils
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
@@ -297,38 +298,120 @@ class SetupCommonPipelineEnvironmentTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void "Set scmInfo parameter sets commit id"() {
|
||||
|
||||
def GitUtils gitUtils = new GitUtils() {
|
||||
boolean isMergeCommit(){
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
helper.registerAllowedMethod("fileExists", [String], { String path ->
|
||||
return path.endsWith('.pipeline/config.yml')
|
||||
})
|
||||
|
||||
def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_URL: 'https://github.com/testOrg/testRepo.git']
|
||||
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo)
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo, gitUtils: gitUtils)
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitCommitId, is('dummy_git_commit_id'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Set scmInfo parameter sets git reference for branch"() {
|
||||
|
||||
def GitUtils gitUtils = new GitUtils() {
|
||||
boolean isMergeCommit(){
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
helper.registerAllowedMethod("fileExists", [String], { String path ->
|
||||
return path.endsWith('.pipeline/config.yml')
|
||||
})
|
||||
|
||||
def dummyScmInfo = [GIT_BRANCH: 'origin/testbranch']
|
||||
def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'origin/testbranch']
|
||||
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo)
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo, gitUtils: gitUtils)
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/heads/testbranch'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Set scmInfo parameter sets git reference for pull request"() {
|
||||
void "sets gitReference and gitRemoteCommit for pull request"() {
|
||||
|
||||
def GitUtils gitUtils = new GitUtils() {
|
||||
boolean isMergeCommit(){
|
||||
return false
|
||||
}
|
||||
|
||||
String getGitMergeCommitId(String gitChangeId){
|
||||
return "dummy_merge_git_commit_id"
|
||||
}
|
||||
}
|
||||
|
||||
helper.registerAllowedMethod("fileExists", [String], { String path ->
|
||||
return path.endsWith('.pipeline/config.yml')
|
||||
})
|
||||
|
||||
def dummyScmInfo = [GIT_BRANCH: 'PR-42']
|
||||
def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'PR-42']
|
||||
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo)
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo, gitUtils: gitUtils)
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/pull/42/head'))
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitRemoteCommitId, is('dummy_git_commit_id'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "sets gitReference and gitRemoteCommit for pull request for merge strategy"() {
|
||||
|
||||
def GitUtils gitUtils = new GitUtils() {
|
||||
boolean isMergeCommit(){
|
||||
return true
|
||||
}
|
||||
|
||||
String getGitMergeCommitId(String gitChangeId){
|
||||
return "dummy_merge_git_commit_id"
|
||||
}
|
||||
|
||||
boolean compareParentsOfMergeAndHead(String gitMergeCommitId){
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
helper.registerAllowedMethod("fileExists", [String], { String path ->
|
||||
return path.endsWith('.pipeline/config.yml')
|
||||
})
|
||||
|
||||
def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'PR-42']
|
||||
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo, gitUtils: gitUtils)
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/pull/42/merge'))
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitRemoteCommitId, is('dummy_merge_git_commit_id'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Set merge commit id as NA"() {
|
||||
|
||||
def GitUtils gitUtils = new GitUtils() {
|
||||
boolean isMergeCommit(){
|
||||
return true
|
||||
}
|
||||
|
||||
String getGitMergeCommitId(String gitChangeId){
|
||||
return "dummy_merge_git_commit_id"
|
||||
}
|
||||
|
||||
boolean compareParentsOfMergeAndHead(String gitMergeCommitId){
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
helper.registerAllowedMethod("fileExists", [String], { String path ->
|
||||
return path.endsWith('.pipeline/config.yml')
|
||||
})
|
||||
|
||||
def dummyScmInfo = [GIT_COMMIT: 'dummy_git_commit_id', GIT_BRANCH: 'PR-42']
|
||||
|
||||
stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo, gitUtils: gitUtils)
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/pull/42/merge'))
|
||||
assertThat(nullScript.commonPipelineEnvironment.gitRemoteCommitId, is('NA'))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -369,4 +452,3 @@ class SetupCommonPipelineEnvironmentTest extends BasePiperTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,6 +137,24 @@ class GitUtilsTest extends BasePiperTest {
|
||||
assertThat(log.size(),is(equalTo(0)))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsMergeCommitTrue() {
|
||||
shellRule.setReturnValue('git rev-parse --verify HEAD^2', 0)
|
||||
assertTrue(gitUtils.isMergeCommit())
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsMergeCommitFalse() {
|
||||
shellRule.setReturnValue('git rev-parse --verify HEAD^2', 1)
|
||||
assertFalse(gitUtils.isMergeCommit())
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetGitMergeCommitIdException() {
|
||||
thrown.expect(Exception)
|
||||
gitUtils.getGitMergeCommitId("1")
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleTestRepository() {
|
||||
def result, gitMap, stashName, config = [
|
||||
|
||||
@@ -24,8 +24,14 @@ class commonPipelineEnvironment implements Serializable {
|
||||
//Stores the current buildResult
|
||||
String buildResult = 'SUCCESS'
|
||||
|
||||
//stores the gitCommitId as well as additional git information for the build during pipeline run
|
||||
//stores the gitCommitId and gitRemoteCommitId as additional git information for the build during pipeline run
|
||||
/*
|
||||
Incase of 'Merging the pull request with the current target branch revision' stratergy in jenkins,
|
||||
the jenkins creates its own local merge commit which is stored in gitCommitId.
|
||||
gitRemoteCommitId will contain the actual remote merge commitId on git rather than local commitId
|
||||
*/
|
||||
String gitCommitId
|
||||
String gitRemoteCommitId
|
||||
String gitHeadCommitId
|
||||
String gitCommitMessage
|
||||
String gitSshUrl
|
||||
@@ -86,6 +92,7 @@ class commonPipelineEnvironment implements Serializable {
|
||||
containerProperties = [:]
|
||||
|
||||
gitCommitId = null
|
||||
gitRemoteCommitId = null
|
||||
gitHeadCommitId = null
|
||||
gitCommitMessage = null
|
||||
gitSshUrl = null
|
||||
@@ -202,6 +209,7 @@ class commonPipelineEnvironment implements Serializable {
|
||||
[filename: '.pipeline/commonPipelineEnvironment/github/repository', property: 'githubRepo'],
|
||||
[filename: '.pipeline/commonPipelineEnvironment/git/branch', property: 'gitBranch'],
|
||||
[filename: '.pipeline/commonPipelineEnvironment/git/commitId', property: 'gitCommitId'],
|
||||
[filename: '.pipeline/commonPipelineEnvironment/git/remoteCommitId', property: 'gitRemoteCommitId'],
|
||||
[filename: '.pipeline/commonPipelineEnvironment/git/headCommitId', property: 'gitHeadCommitId'],
|
||||
[filename: '.pipeline/commonPipelineEnvironment/git/httpsUrl', property: 'gitHttpsUrl'],
|
||||
[filename: '.pipeline/commonPipelineEnvironment/git/ref', property: 'gitRef'],
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.sap.piper.GenerateDocumentation
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.analytics.InfluxData
|
||||
import com.sap.piper.GitUtils
|
||||
|
||||
import groovy.transform.Field
|
||||
|
||||
@@ -118,7 +119,9 @@ void call(Map parameters = [:]) {
|
||||
if (scmInfo) {
|
||||
setGitUrlsOnCommonPipelineEnvironment(script, scmInfo.GIT_URL)
|
||||
script.commonPipelineEnvironment.setGitCommitId(scmInfo.GIT_COMMIT)
|
||||
setGitRefOnCommonPipelineEnvironment(script, scmInfo.GIT_BRANCH)
|
||||
|
||||
def gitUtils = parameters.gitUtils ?: new GitUtils()
|
||||
setGitRefOnCommonPipelineEnvironment(script, scmInfo.GIT_COMMIT, scmInfo.GIT_BRANCH, gitUtils)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,7 +264,7 @@ private void setGitUrlsOnCommonPipelineEnvironment(script, String gitUrl) {
|
||||
script.commonPipelineEnvironment.setGithubRepo(gitRepo)
|
||||
}
|
||||
|
||||
private void setGitRefOnCommonPipelineEnvironment(script, String gitBranch) {
|
||||
private void setGitRefOnCommonPipelineEnvironment(script, String gitCommit, String gitBranch, def gitUtils) {
|
||||
if(!gitBranch){
|
||||
return
|
||||
}
|
||||
@@ -270,10 +273,31 @@ private void setGitRefOnCommonPipelineEnvironment(script, String gitBranch) {
|
||||
gitBranch = gitBranch.split("/")[1]
|
||||
}
|
||||
|
||||
//TODO: refs for merge pull requests
|
||||
if (gitBranch.contains("PR")) {
|
||||
script.commonPipelineEnvironment.setGitRef("refs/pull/" + gitBranch.split("-")[1] + "/head")
|
||||
} else {
|
||||
script.commonPipelineEnvironment.setGitRef("refs/heads/" + gitBranch)
|
||||
}
|
||||
if (!gitBranch.contains("PR")) {
|
||||
script.commonPipelineEnvironment.setGitRef("refs/heads/" + gitBranch)
|
||||
script.commonPipelineEnvironment.setGitRemoteCommitId(gitCommit)
|
||||
return
|
||||
}
|
||||
|
||||
boolean isMergeCommit = gitUtils.isMergeCommit()
|
||||
def mergeOrHead = isMergeCommit?"merge":"head"
|
||||
def changeId = gitBranch.split("-")[1]
|
||||
script.commonPipelineEnvironment.setGitRef("refs/pull/" + changeId + "/" + mergeOrHead)
|
||||
|
||||
if(!isMergeCommit){
|
||||
script.commonPipelineEnvironment.setGitRemoteCommitId(gitCommit)
|
||||
return
|
||||
}
|
||||
|
||||
try{
|
||||
String gitRemoteCommitId = gitUtils.getGitMergeCommitId(changeId)
|
||||
if(gitRemoteCommitId?.trim() && gitUtils.compareParentsOfMergeAndHead(gitRemoteCommitId)){
|
||||
script.commonPipelineEnvironment.setGitRemoteCommitId(gitRemoteCommitId)
|
||||
return
|
||||
}
|
||||
}catch(Exception e){
|
||||
echo "Exception in getting git merge commit id or comparing git merge commit parents: ${e}"
|
||||
}
|
||||
|
||||
script.commonPipelineEnvironment.setGitRemoteCommitId("NA")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user