diff --git a/jenkins/L0_MergeRequest.groovy b/jenkins/L0_MergeRequest.groovy index 1ef2aac37c97..6329397a58f3 100644 --- a/jenkins/L0_MergeRequest.groovy +++ b/jenkins/L0_MergeRequest.groovy @@ -749,7 +749,7 @@ def getGithubMRChangedFile(pipeline, githubPrApiUrl, function, filePath="") { } rawDataList.find { rawData -> if (rawData.get("filename") == filePath || rawData.get("previous_filename") == filePath) { - result = rawData.get("patch") + result = rawData.get("patch") ?: "" return true } return false @@ -769,7 +769,7 @@ def getGithubMRChangedFile(pipeline, githubPrApiUrl, function, filePath="") { rawDataList.each { rawData -> [rawData.get("filename"), rawData.get("previous_filename")] .findAll { it } - .each { changedFilePath -> result[changedFilePath] = rawData.get("patch") } + .each { changedFilePath -> result[changedFilePath] = rawData.get("patch") ?: "" } } } if (!rawDataList) { break } @@ -778,6 +778,90 @@ def getGithubMRChangedFile(pipeline, githubPrApiUrl, function, filePath="") { return result } +def getGitMirrorMRChangedFile(pipeline, globalVars, function, filePath="", filePaths=[]) { + def wrapperBuildNumber = globalVars[ACTION_INFO]?.get("parents")?.getAt(0)?.get("build_number")?.toString() + def headCommit = env.gitlabCommit?.toString() + def baseRef = "refs/heads/prjob/${wrapperBuildNumber}/base" + pipeline.withEnv(["GIT_DIFF_BASE_REF=${baseRef}"]) { + withCredentials([gitUsernamePassword(credentialsId: 'svc_tensorrt_gitlab_api_token', gitToolName: 'Default'),]) { + pipeline.sh "git -C ${LLM_ROOT} fetch --no-tags --depth=1 origin \"\${GIT_DIFF_BASE_REF}\"" + } + } + def baseCommit = pipeline.sh(script: "git -C ${LLM_ROOT} rev-parse FETCH_HEAD", returnStdout: true).trim() + pipeline.echo("Using internal Git mirror diff: ${baseCommit}...${headCommit}") + + def nameStatus = pipeline.sh( + script: "git -C ${LLM_ROOT} -c core.quotepath=false diff --name-status --find-renames ${baseCommit} ${headCommit}", + returnStdout: true + ) + def changedFiles = nameStatus.readLines().collect { line -> + def fields = line.split('\t', -1) + def paths = [] + for (int index = 1; index < fields.length; index++) { + if (fields[index]) { + paths.add(fields[index]) + } + } + [status: fields[0], paths: paths] + } + if (function == "getChangedFileList") { + return changedFiles.collectMany { changedFile -> + changedFile.status.startsWith("R") || changedFile.status.startsWith("C")? changedFile.paths.reverse(): changedFile.paths + } + } + + def renamePaths = [:] + changedFiles.findAll { changedFile -> + changedFile.status.startsWith("R") || changedFile.status.startsWith("C") + }.each { changedFile -> + changedFile.paths.each { changedFilePath -> renamePaths[changedFilePath] = changedFile.paths } + } + def cachedDiffs = [:] + def getFileDiff = { changedFilePath -> + if (cachedDiffs.containsKey(changedFilePath)) { + return cachedDiffs[changedFilePath] + } + def diffPaths = renamePaths.get(changedFilePath, [changedFilePath]) + def rawDiff = "" + pipeline.withEnv([ + "GIT_DIFF_PATH=${diffPaths[0]}", + "GIT_DIFF_RENAME_PATH=${diffPaths.size() > 1 ? diffPaths[1] : diffPaths[0]}", + ]) { + rawDiff = pipeline.sh( + script: "git -C ${LLM_ROOT} diff --unified=3 --inter-hunk-context=1 --find-renames ${baseCommit} ${headCommit} -- \":(literal)\${GIT_DIFF_PATH}\" \":(literal)\${GIT_DIFF_RENAME_PATH}\"", + returnStdout: true + ) + } + def lines = rawDiff.readLines() + def firstHunk = lines.findIndexOf { it.startsWith("@@") } + def diff = firstHunk < 0 ? "" : lines.drop(firstHunk).join("\n") + diffPaths.each { diffPath -> cachedDiffs[diffPath] = diff } + return diff + } + + if (function == "getOneFileChanges") { + return getFileDiff(filePath) + } + if (function == "getFileChanges") { + return filePaths.unique().collectEntries { changedFilePath -> [(changedFilePath): getFileDiff(changedFilePath)] } + } + pipeline.error("Unsupported PR diff operation: ${function}") +} + +def getGithubMRChangedFileWithFallback(pipeline, globalVars, function, filePath="", filePaths=[]) { + try { + return getGithubMRChangedFile(pipeline, globalVars[GITHUB_PR_API_URL], function, filePath) + } catch (InterruptedException e) { + throw e + } catch (Exception e) { + pipeline.echo("WARNING: [PR_DIFF_FALLBACK] GitHub PR files API failed for ${function}; " + + "trying the internal Git mirror. Error: ${e.toString()}") + def result = getGitMirrorMRChangedFile(pipeline, globalVars, function, filePath, filePaths) + pipeline.echo("WARNING: [PR_DIFF_FALLBACK] Internal Git mirror fallback succeeded for ${function}.") + return result + } +} + // Gate multi-GPU stages behind 'ci: full pre-merge approved' label. // Uses trtllm_utils.validatePRLabelApproval() from the shared lib to verify // both label existence and that the labeler is an active team member. @@ -843,7 +927,7 @@ def getMergeRequestChangedFileList(pipeline, globalVars) { try { def changedFileList = [] if (githubPrApiUrl != null) { - changedFileList = getGithubMRChangedFile(pipeline, githubPrApiUrl, "getChangedFileList") + changedFileList = getGithubMRChangedFileWithFallback(pipeline, globalVars, "getChangedFileList") } else { changedFileList = getGitlabMRChangedFile(pipeline, "getChangedFileList") } @@ -876,7 +960,7 @@ def getMergeRequestOneFileChanges(pipeline, globalVars, filePath) { def diff = "" if (githubPrApiUrl != null) { - diff = getGithubMRChangedFile(pipeline, githubPrApiUrl, "getOneFileChanges", filePath) + diff = getGithubMRChangedFileWithFallback(pipeline, globalVars, "getOneFileChanges", filePath) } else { diff = getGitlabMRChangedFile(pipeline, "getOneFileChanges", filePath) } @@ -977,7 +1061,7 @@ def getCbtsResult(pipeline, testFilter, globalVars) if (filesNeedingDiff) { def githubPrApiUrl = globalVars[GITHUB_PR_API_URL] def fileChanges = githubPrApiUrl != null - ? getGithubMRChangedFile(pipeline, githubPrApiUrl, "getFileChanges") + ? getGithubMRChangedFileWithFallback(pipeline, globalVars, "getFileChanges", "", filesNeedingDiff) : getGitlabMRChangedFile(pipeline, "getFileChanges") diffs = filesNeedingDiff.collectEntries { filePath -> // Null (patch omitted for binary / rename / too-large diffs) coerces to empty.