Jenkins Share Library教程 —— 企業級 Jenkins Shared Library 實戰示例
寫在前面
好久不見~最近狀態稍緩,更新也慢了些,這篇文章同樣讓大家等了挺久,先跟大家說聲抱歉。
如果你認真讀了前面幾篇,還跟著實踐了,那到這里,咱們就要正式開啟真正的 “進階階段” 啦!
確實,大多數公司內部的 Jenkins Shared Library 不只是簡單的“封裝幾個 stage”而已,它們往往包含:
- workspace 清理機制(避免磁盤爆滿)
- 緩存/依賴重用邏輯
- 多分支/多環境配置
- 動態參數和條件邏輯
- 流水線鉤子(pre/post hooks)
- 高級通知系統(Slack、郵件、飛書、Teams)
下面,我們可以一起寫一個更“企業級”的案例,會讓你看懂為什么公司那套 Shared Library 那么復雜了。
目標:構建一個帶 workspace 清理、緩存管理、錯誤恢復、通知系統的可復用 CI Pipeline。
一、項目結構
jenkins-shared-lib-enterprise/
├── vars/
│ ├── enterprisePipeline.groovy # 主入口 Pipeline
│ ├── workspaceManager.groovy # 清理與準備工作區
│ ├── notifyManager.groovy # 通知模塊
│ ├── gitHelper.groovy # Git 拉取與分支操作
├── src/org/company/
│ ├── Utils.groovy # 工具類(時間戳、日志、重試等)
│ └── ConfigLoader.groovy # YAML/JSON 配置讀取器
└── resources/templates/
└── notifyTemplate.txt
二、清理函數
?? vars/cleanWorkspace.groovy
def call(Map config = [:]) {
def cleanBeforeBuild = config.get('clean', true)
def keepPatterns = config.get('keep', ['.git', '.gradle'])
if (!cleanBeforeBuild) {
echo "?? Skipping workspace cleanup."
echo "? Workspace ready at: ${pwd()}"
return
}
echo "?? Cleaning workspace, preserving: ${keepPatterns}"
def os = getOS()
if (os == 'Windows') {
cleanWindows(keepPatterns)
} else {
cleanUnix(keepPatterns)
}
echo "? Workspace ready at: ${pwd()}"
}
// 判斷操作系統
private String getOS() {
def osName = System.getProperty('os.name').toLowerCase()
return osName.contains('windows') ? 'Windows' : 'Unix'
}
// Unix/Linux/macOS 清理方式
private void cleanUnix(List keepPatterns) {
def patternStr = keepPatterns.join('|')
sh """
echo "Running on Unix/Linux..."
ls -A1 | grep -v -E '^(${patternStr})\$' | xargs rm -rf || true
"""
}
// Windows 清理方式(使用 cmd 或 PowerShell)
private void cleanWindows(List keepPatterns) {
// 轉成小寫用于比較
def keepSet = keepPatterns.collect { it.toLowerCase() } as Set
// 獲取當前目錄下所有文件/目錄(包括隱藏)
def files = new File(pwd()).listFiles()
if (!files) return
files.each { file ->
def name = file.name.toLowerCase()
if (!keepSet.contains(name)) {
echo "??? Deleting: ${file.name}"
deleteFileOrDir(file)
}
}
}
// 安全刪除文件或目錄(遞歸)
private void deleteFileOrDir(File file) {
try {
if (file.directory) {
file.deleteDir() // 遞歸刪除目錄
} else {
file.delete()
}
} catch (Exception e) {
echo "?? Failed to delete ${file.name}: ${e.message}"
}
}
功能說明:
-
默認在每次構建前清理工作區(但保留
.git、.gradle等緩存目錄) -
公司里這樣做是為了避免:
- Jenkins 節點磁盤爆滿
- 前次構建殘留文件導致構建異常
Jenkinsfile 調用方式
@Library('my-shared-lib') _
pipeline {
agent any
stages {
stage('Cleanup') {
steps {
script {
cleanWorkspace(
clean: true,
keep: ['.git', '.gradle', 'settings.gradle']
)
}
}
}
// ... 其他階段
}
}
運行后,你會在控制臺輸出看到:
三、通知模塊
?? vars/notifyManager.groovy
def call(Map args = [:]) {
def status = args.status ?: 'SUCCESS'
def message = args.message ?: "Build completed."
def color = status == 'SUCCESS' ? 'good' : (status == 'FAILURE' ? 'danger' : 'warning')
def project = env.JOB_NAME
def buildUrl = env.BUILD_URL
def fullMessage = """
[${status}] ${project}
${message}
?? ${buildUrl}
"""
echo "?? Notify: ${fullMessage.trim()}"
}
Jenkinsfile 調用方式
@Library('my-shared-lib') _
pipeline {
agent any // 可以是 linux、windows、docker 等
stages {
stage('Cleanup') {
steps {
script {
notifyManager(
status: 'SUCCESS',
message: 'Build completed.'
)
}
}
}
// ... 其他階段
}
}
運行后,你會在控制臺輸出看到:
四、Git 操作封裝
?? vars/gitHelper.groovy
// vars/gitCheckout.groovy
def call(Map config = [:]) {
def repo = config.repo
def branch = config.get('branch', 'main')
def credentialsId = config.get('credentialsId', 'git-credentials')
if (!repo) {
error "? gitCheckout: 'repo' parameter is required!"
}
echo "?? Checking out ${repo} (branch: ${branch})"
checkout([
$class: 'GitSCM',
branches: [[name: branch]],
userRemoteConfigs: [[
url: repo,
credentialsId: credentialsId
]]
])
}
Jenkinsfile 調用方式
@Library('my-shared-lib') _
pipeline {
agent any
options {
skipDefaultCheckout() // ?? 關鍵!跳過默認的 SCM 步驟
}
parameters {
string(name: 'GIT_REPO', defaultValue: 'your giturl', description: 'Git repository URL')
string(name: 'GIT_BRANCH', defaultValue: 'master', description: 'Branch to build')
}
stages {
stage('Checkout Code') {
steps {
script {
def repo = params.GIT_REPO
def branch = params.GIT_BRANCH
echo "?? 開始拉取代碼:${repo} (分支:${branch})"
// 調用 vars/gitHelper.groovy
gitHelper(
repo: repo,
branch: branch,
credentialsId: 'gitee-credentials' // 替換為你的實際憑據 ID
)
}
}
}
stage('Debug') {
steps {
echo "?? 當前路徑:${pwd()}"
bat 'git branch -a'
bat 'git log --oneline -5'
}
}
}
post {
failure {
echo "? 構建失??!"
}
}
}
運行后,你會在控制臺輸出看到:
五、核心 Pipeline
?? vars/enterprisePipeline.groovy
import com.company.Utils
def call(Map config = [:], Closure customStages = null) {
echo "repo: ${config.repo}, branch: ${config.branch}"
// 初始化
Utils.printHeader(this, "Initializing Pipeline")
cleanWorkspace([clean: true, keep: ['.git']])
gitHelper([repo: config.repo, branch: config.branch])
// 構建
Utils.printHeader(this, "Build Stage")
try {
bat config.buildCommand ?: 'mvn clean package -DskipTests'
} catch (err) {
notifyManager([status: 'FAILURE', message: "Build failed: ${err.message}"])
error("Build failed.")
}
// 測試
Utils.printHeader(this, "Test Stage")
try {
bat config.testCommand ?: 'mvn compile test'
} catch (err) {
notifyManager([status: 'FAILURE', message: "Tests failed: ${err.message}"])
error("Tests failed.")
}
// 自定義階段
if (customStages != null) {
Utils.printHeader(this, "Custom Stages")
customStages()
}
// 部署
if (config.deploy == true) {
Utils.printHeader(this, "Deploy Stage")
// bat config.deployCommand ?: './deploy.sh'
notifyManager([status: 'SUCCESS', message: "Deployed successfully!"])
}
// 收尾
def result = currentBuild.result ?: 'SUCCESS'
notifyManager([status: result, message: "Pipeline finished with status: ${result}"])
Utils.printHeader(this, "Cleaning workspace after build")
cleanWorkspace([clean: true])
}
Jenkinsfile 調用方式
@Library('my-shared-lib') _
pipeline {
agent any
tools {
maven 'maven'
}
parameters {
string(name: 'REPO_URL', defaultValue: 'your giturl', description: 'Git倉庫地址')
string(name: 'BRANCH', defaultValue: 'master', description: '分支')
}
stages {
stage('企業流水線') {
steps {
script {
enterprisePipeline([
repo: params.REPO_URL,
branch: params.BRANCH
])
}
}
}
}
}
運行后,你會在控制臺輸出看到:
寫在最后
本文以 Maven 項目為示例,核心思路可遷移至其他語言項目,后續仍有擴展空間,感興趣者可自行探索。
感謝你的認真閱讀!若文章對你有價值,歡迎文末留言交流,也請幫忙點贊轉發,謝謝支持!
優秀不夠,你是否無可替代
軟件測試交流QQ群:721256703,期待你的加入?。?/strong>
歡迎關注我的微信公眾號:軟件測試君


浙公網安備 33010602011771號