You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pipeline Groovy脚本如何支持含$的SonarQube分支名?

问题:SonarQube含$的分支名在Pipeline脚本中被截断

我的Groovy Pipeline脚本用于获取SonarQube分支及对应代码行数,运行正常,但遇到名为branch-$branch的分支时,遍历分支列表时该分支的curl请求里分支名被截断为branch-,无法获取数据。已经尝试branch_name = p_branches.name.toString()但无效,且无法修改分支名称,求解决方法。

原脚本

stage('Extract Output') {
        steps {
            script {
                 
                // Sonar branches API Endpoint
                String branches_url = base_url+"/api/project_branches/list"
                
                String sonar_branches = sh(script: 'curl -s -u user:pswd -X GET -F "project=sonar.project" '+branches_url, returnStdout: true).trim()
                def jsonSonarBranches = readJSON text: sonar_branches

                p_branches = jsonSonarBranches.branches
                branch_name = p_branches.name
                branch_LAD = p_branches.analysisDate

                echo "${branch_name}"
                echo "------------------"

                // LOC API Endpoint
                String measures_url = base_url+"/api/measures/component"
                
                int index = 0
                for(String branch: branch_name){
                    brnch_lad = branch_LAD.get(index)

                    String project_measures = sh(script: 'curl -s -u usr:paswd -X GET -F "component=sonar.project" -F "metricKeys=ncloc" -F "branch='+branch+'" '+measures_url, returnStdout: true).trim()
                    def jsonProjectMeasures = readJSON text: project_measures
                    
                    // components json: value = loc
                    proj_component = jsonProjectMeasures.component.measures
                    p_measures = proj_component.value

                    if(brnch_lad == null){
                        brnch_lad = 'N/A'
                        p_measures = 'N/A'
                        echo "PROJECT_KEY:sonar.project BRANCH:${branch} LAD:${brnch_lad} LOC:${p_measures}"
                    } 
                    else if(p_measures.isEmpty()) {
                        p_measures = 'N/A'
                        echo "PROJECT_KEY:sonar.project BRANCH:${branch} LAD:${brnch_lad} LOC:${p_measures}"  
                    }
                    else if(p_measures == null){
                        p_measures = 'N/A'
                        echo "PROJECT_KEY:sonar.project BRANCH:${branch} LAD:${brnch_lad} LOC:${p_measures}"
                    }
                    else {
                        int index_measures = 0
                        p_loc = p_measures.get(index_measures)
                        echo "PROJECT_KEY:sonar.project BRANCH:${branch} LAD:${brnch_lad} LOC:${p_loc}"
                    
                        index_measures++
                    }

                    index++
                }
                echo "--------------------------------------------------------------------------------------------------------"
            }
        }
    }

执行结果

  • echo "${branch_name}"输出:
[branch-123, branch-master, branch-origin/pr, branch-$branch]
  • branch-$branch分支对应的curl请求输出:
+ curl -s -u **** -X GET -F component=sonar.project -F metricKeys=ncloc -F branch=branch- https://sonarqube.com/api/measures/component

原因分析

问题出在shell命令的字符串拼接上:当用单引号包裹shell脚本时,branch='+branch+'会把branch-$branch中的$branch解析为shell环境变量,但这个变量不存在,所以被替换为空字符串,最终分支名变成branch-。


解决方案

有两种可靠的处理方式,推荐第二种(更通用,能处理所有特殊字符):

方法1:转义分支名中的$符号

在拼接shell命令前,把分支名里的$替换为\$,让shell把它当作普通字符处理:

// 替换分支名中的$为\$
def escapedBranch = branch.replace('$', '\\$')
String project_measures = sh(script: 'curl -s -u usr:paswd -X GET -F "component=sonar.project" -F "metricKeys=ncloc" -F "branch='+escapedBranch+'" '+measures_url, returnStdout: true).trim()

方法2:使用curl的--data-urlencode参数(推荐)

--data-urlencode会自动处理所有URL特殊字符(包括$、/、&等),无需手动转义:

String project_measures = sh(script: "curl -s -u usr:paswd -X GET ${measures_url} -F 'component=sonar.project' -F 'metricKeys=ncloc' --data-urlencode 'branch=${branch}'", returnStdout: true).trim()

注意这里用双引号包裹整个shell命令,让Groovy先解析${branch}变量,再传递给curl处理。


修改后的完整脚本片段
stage('Extract Output') {
        steps {
            script {
                 
                // Sonar branches API Endpoint
                String branches_url = base_url+"/api/project_branches/list"
                
                String sonar_branches = sh(script: 'curl -s -u user:pswd -X GET -F "project=sonar.project" '+branches_url, returnStdout: true).trim()
                def jsonSonarBranches = readJSON text: sonar_branches

                p_branches = jsonSonarBranches.branches
                branch_name = p_branches.name
                branch_LAD = p_branches.analysisDate

                echo "${branch_name}"
                echo "------------------"

                // LOC API Endpoint
                String measures_url = base_url+"/api/measures/component"
                
                int index = 0
                for(String branch: branch_name){
                    brnch_lad = branch_LAD.get(index)

                    // 使用--data-urlencode处理特殊字符
                    String project_measures = sh(script: "curl -s -u usr:paswd -X GET ${measures_url} -F 'component=sonar.project' -F 'metricKeys=ncloc' --data-urlencode 'branch=${branch}'", returnStdout: true).trim()
                    def jsonProjectMeasures = readJSON text: project_measures
                    
                    // components json: value = loc
                    proj_component = jsonProjectMeasures.component?.measures ?: []
                    p_measures = proj_component.value ?: []

                    if(brnch_lad == null){
                        brnch_lad = 'N/A'
                        p_measures = 'N/A'
                        echo "PROJECT_KEY:sonar.project BRANCH:${branch} LAD:${brnch_lad} LOC:${p_measures}"
                    } 
                    else if(p_measures.isEmpty()) {
                        p_measures = 'N/A'
                        echo "PROJECT_KEY:sonar.project BRANCH:${branch} LAD:${brnch_lad} LOC:${p_measures}"  
                    }
                    else {
                        p_loc = p_measures[0] ?: 'N/A'
                        echo "PROJECT_KEY:sonar.project BRANCH:${branch} LAD:${brnch_lad} LOC:${p_loc}"
                    }

                    index++
                }
                echo "--------------------------------------------------------------------------------------------------------"
            }
        }
    }

(额外优化了空指针判断,避免脚本因API返回异常失败)


内容的提问来源于stack exchange,提问作者ckmb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 11:21:06