1. 程式人生 > 實用技巧 >對Jenkinsfile語法說不,開源專案Jenkins Json Build挺你

對Jenkinsfile語法說不,開源專案Jenkins Json Build挺你

對Jenkinsfile語法說不,開源專案Jenkins Json Build挺你

專案背景

我所在的組織專案數量眾多,使用的語言和框架也很多,比如Java、ReactNative、C# .NET、Android、iOS等,部署環境也是多種多樣比如Tomcat、K8S、IIS、客戶端應用是區域網內企業證書安裝等,我們沒有專門的配置管理員或構建部署專員,都是開發人員自己在Jenkins中寫構建指令碼,每個專案都有自己的構建指令碼(Scripted Pipelines),但型別相同的專案比如都是Java或都是.NET專案之間,構建指令碼其實都很類似,都是靠幾個已存在的構建指令碼改寫出來的,其實開發人員對編寫Jenkins構建指令碼瞭解也不多,另外因為沒有規則和約束,更沒有程式碼複用的機制,構建部署工作很混亂和難以管理。

專案解決的問題

在上述情況下我們開發了Jenkins-Json-Build專案,該專案適合於有一些程式設計經驗的人員在不需要了解Jenkins構建指令碼如何編寫的情況下,通過簡單的配置Json檔案,就可以輕鬆完成一個專案的獲取原始碼、單元測試、程式碼檢查、編譯構建、部署等步驟,實現一個典型的CI過程,又因為此專案使用了Jenkins共享類庫(Shared Libraries)機制,構建指令碼複用率得到了大幅度提高,並且開發人員可以方便的擴充套件更多的功能,滿足不同構建部署場景的需要,此專案非常適合那些開發人員自己管理構建部署的團隊,通過Jenkins-Json-Build專案組織對構建部署過程進行了統一的管理和監督,又讓每個專案有足夠的靈活性和自主權滿足各自專案構建部署的特殊性。

一個Java專案構建示例

構建伺服器上需要安裝的軟體

構建伺服器上需要安裝Java、Maven和Sonar-Scanner(此項可選)。

構建需要依賴的Jenkins外掛

  • JUnit
  • JaCoCo

Jenkinsfile檔案內容

因為採用pipeline script from SCM構建方式,所以用Declarative Pipeline方式在Jenkinsfile中編寫構建指令碼:

@Library('shared-library') _

pipeline {
  agent any
  parameters { //定義構建引數
    choice choices: ['-'], description: '請選擇部署方式', name: 'deploy-choice'
  }
  stages {
    stage('初始化') {
      steps {
        script{
          //載入原始碼倉庫根目錄下的jenkins-project.json構建配置檔案
          runWrapper.loadJSON('/jenkins-project.json')
          runWrapper.runSteps('初始化')
        }
      }
    }
    stage('單元測試') {
      steps {
        script{
          //執行單元測試步驟
          runWrapper.runSteps('單元測試')
        }
      }
    }
    stage('程式碼檢查') {
      steps {
        script{
          //執行程式碼檢查步驟,比如SonarQube
          runWrapper.runSteps('程式碼檢查')
        }
      }
    }
    stage('編譯構建') {
      steps {
        script{
          //執行編譯步驟
          runWrapper.runSteps('編譯構建')
        }
      }
    }
    stage('部署') {
      steps {
        script{
          //根據選擇的部署方式執行部署步驟
          runWrapper.runStepForEnv('部署','deploy-choice')
        }
      }
    }
  }
}

上述Jenkinsfile檔案可用於所有型別的專案構建,實際使用的時候一般還會用到以下三個Jenkins外掛:

JSON配置檔案內容

{
  "初始化": {
    "檢查Java環境": {
      "Type": "COMMAND_STDOUT",
      "Success-IndexOf": "java version \"1.8.0_211\"",
      "Script": {
        "輸出Java版本": "java -version 2>&1"
      }
    },
    "檢查Maven環境": {
      "Type": "COMMAND_STDOUT",
      "Success-IndexOf": "Apache Maven 3.6.3",
      "Script": {
        "輸出Maven版本": "mvn -v"
      }
    },
    "檢查SonarScanner環境": {
      "Type": "COMMAND_STDOUT",
      "Success-IndexOf": "SonarScanner 4.4.0.2170",
      "Script": {
        "輸出SonarScanner版本": "sonar-scanner -v"
      }
    },
    "繫結構建引數": {
      "Type": "BUILD_PARAMETER_DROP_DOWN_MENU",
      "StepsName": "部署",
      "ParamName": "deploy-choice"
    }
  },
  "單元測試": {
    "執行Maven單元測試指令碼": {
      "Type": "COMMAND_STATUS",
      "Script": {
        "Maven單元測試": "cd ${PROJECT_PATH};mvn clean test"
      }
    },
    "執行JUnit外掛": {
      "Type": "JUNIT_PLUG_IN",
      "JunitReportPath": "**/${PROJECT_DIR}/**/target/**/TEST-*.xml"
    },
    "執行Jacoco外掛": {
      "Type": "JACOCO_PLUG_IN",
      "classPattern":"${PROJECT_PATH}/target/classes",
      "InclusionPattern":"${PROJECT_PATH}/**",
      "LineCoverage":"95",
      "InstructionCoverage":"0",
      "MethodCoverage":"100",
      "BranchCoverage":"95",
      "ClassCoverage":"100",
      "ComplexityCoverage":"0"
    }
  },
  "程式碼檢查": {
    "執行SQ程式碼掃描": {
      "Type": "SONAR_QUBE"
    }
  },
  "編譯構建": {
    "執行Maven構建": {
      "Type": "COMMAND_STATUS",
      "Script": {
        "Maven構建": "cd ${PROJECT_PATH};mvn clean package -U -DskipTests"
      }
    }
  },
  "部署": {
    "模擬部署指令碼-1": {
      "Type": "COMMAND_STATUS",
      "Script": {
        "拷貝檔案": "echo 模擬拷貝檔案"
      }
    },
    "模擬部署指令碼-2": {
      "Type": "COMMAND_STATUS",
      "Script": {
        "HTTP傳輸檔案": "echo HTTP傳輸檔案"
      }
    }
  }
}

配置說明:

"檢查Java環境": {
      "Type": "COMMAND_STDOUT",
      "Success-IndexOf": "java version \"1.8.0_211\"",
      "Script": {
        "輸出Java版本": "java -version 2>&1"
      }

該型別的節點不是必須的(但看幾年前寫的配置檔案時很有用,對需要的構建環境一目瞭然),目的是檢查構建伺服器是否具備需要的構建環境,在命令的標準輸出內未含有Success-IndexOf節點定義的字串則執行失敗,對應的另一個節點名稱是Fail-IndexOf,標準輸出如果含有Fail-IndexOf定義的字串則執行失敗,兩者選擇其一使用。

"繫結構建引數": {
      "Type": "BUILD_PARAMETER_DROP_DOWN_MENU",
      "StepsName": "部署",
      "ParamName": "deploy-choice"
    }

將部署節點(Steps)內的具體構建步驟(Step)列表,繫結到名為deploy-choice的下拉選單構建引數上。

"執行JUnit外掛": {
      "Type": "JUNIT_PLUG_IN",
      "JunitReportPath": "**/${PROJECT_DIR}/**/target/**/TEST-*.xml"
    }

使用Jenkins的JUnit外掛生成Junit和TestNG的測試報告。

"執行Jacoco外掛": {
      "Type": "JACOCO_PLUG_IN",
      "classPattern":"${PROJECT_PATH}/target/classes",
      "InclusionPattern":"${PROJECT_PATH}/**",
      "LineCoverage":"95",
      "InstructionCoverage":"0",
      "MethodCoverage":"100",
      "BranchCoverage":"95",
      "ClassCoverage":"100",
      "ComplexityCoverage":"0"
    }

使用Jenkins的Jacoco外掛檢查單元測試覆蓋度。

"程式碼檢查": {
    "執行SQ程式碼掃描": {
      "Type": "SONAR_QUBE"
    }
  }

執行SonarQube程式碼檢查,需要在專案根目錄下要建立sonar-project.properties配置檔案,以Java專案的配置檔案為例:

# must be unique in a given SonarQube instance
sonar.projectKey=Jenkins:Test-Java-Build

sonar.projectVersion=1.0

# Path is relative to the sonar-project.properties file. Defaults to .
sonar.sources=src
sonar.sourceEncoding=UTF-8
sonar.java.binaries=./target/classes
"執行Maven構建": {
      "Type": "COMMAND_STATUS",
      "Script": {
        "Maven構建": "cd ${PROJECT_PATH};mvn clean package -U -DskipTests"
      }
    }

該節點就是執行命令,這裡具體構建命令是用mvn clean package -U -DskipTests命令完成的。

經過上述配置檔案的執行,我們可以很簡單的完成所有的構建步驟:

這裡篇幅有限,更多內容請到專案倉庫檢視比如:

  • 構建JS專案
  • 構建ReactNative專案
  • 構建Android專案
  • 構建iOS專案
  • 構建.NET專案
  • 構建多個子專案
  • 構建成功和失敗處理
  • 在K8S內建立Pod進行構建

歡迎大家去關注、交流更多的關於Jenkins構建的問題和經驗

專案倉庫地址:Jenkins Json Build