水刺无纺布 發表於 2025-10-14 22:20:00

Jenkins Share Library教程 —— 高级实战与最佳实践教程

<p><img src="https://img2024.cnblogs.com/blog/718867/202510/718867-20251014221934586-111374678.png" alt="image" loading="lazy"></p>
<h3 id="写在前面">写在前面</h3>
<p>搞了近一天的PPT,讲真写英文PPT,确实比中文难多了,中午都没休息,最后还是在同事的帮忙下才搞完。</p>
<p>值得说的是,我今天算是见到了,做PPT强的人,是真的强,从色彩搭配到一些图形选择上,真的很丝滑,没一点多余动作,我看他调PPT就像给我化妆一样,一点点的变好看了。</p>
<p>见证成品那一刻,我就真的有那种,“哇,居然可以这么好看的感觉!”,心生羡慕!</p>
<hr>
<h3 id="项目结构">项目结构</h3>
<p>经过昨天的学习,你现在已经掌握了基础的 Shared Library 概念,接下来我们直接进入 <strong>高级实战 + 最佳实践案例</strong>。</p>
<p>我会一步步讲给你听,像带你写项目一样,所有代码都能直接放进 Jenkins 跑起来。</p>
<p>在你的共享库 Git 仓库中创建以下结构:</p>
<pre><code>jenkins-shared-lib-advanced/
├── vars/
│   ├── ciPipeline.groovy
│   ├── notifySlack.groovy
│   ├── deployApp.groovy
├── src/org/example/
│   └── Utils.groovy
└── resources/templates/
    └── slackMessage.txt
</code></pre>
<p>我们会用这套结构完成:</p>
<ul>
<li>参数化构建</li>
<li>错误处理(try/catch)</li>
<li>构建 + 测试 + 部署 + 通知</li>
<li>可重用 pipeline 封装</li>
</ul>
<hr>
<h3 id="编写工具类">编写工具类</h3>
<p>📄 <code>src/org/example/Utils.groovy</code></p>
<pre><code class="language-groovy">package org.example

class Utils {
    static void printHeader(script, String msg) {
      script.echo "========== ${msg} =========="
    }

    static String getTimestamp() {
      return new Date().format("yyyy-MM-dd HH:mm:ss")
    }
}

</code></pre>
<p>说明:</p>
<ul>
<li>所有公共函数写这里(类似工具包)。</li>
<li>用 <code>import org.example.Utils</code> 即可调用。</li>
</ul>
<p><strong>Jenkinsfile 调用方式</strong></p>
<pre><code class="language-groovy">@Library('my-shared-lib') _
import org.example.Utils

pipeline {
    agent any
    stages {
      stage('Demo') {
            steps {
                script {
                  Utils.printHeader(this, "开始构建")
                  echo "时间:${Utils.getTimestamp()}"
                }
            }
      }
    }
}

</code></pre>
<p>运行后,你会在控制台输出看到:</p>
<p><img src="https://img2024.cnblogs.com/blog/718867/202510/718867-20251013214609010-1482133647.png" alt="image" loading="lazy"></p>
<hr>
<h3 id="slack-通知函数">Slack 通知函数</h3>
<p>📄 <code>vars/notifySlack.groovy</code></p>
<pre><code class="language-groovy">// vars/sendSlack.groovy
def call(Map config = [:]) {
    def message = config.message ?: "Build finished"
    def status= config.status?: "SUCCESS"
    def color   = config.color   ?: (status == "SUCCESS" ? "good" : "danger")
    def channel = config.channel ?: '#builds'

    echo "📢 Sending Slack message to ${channel}: ${message} (${status})"

    slackSend(
      channel: channel,
      message: message,
      color: color
    )
}
</code></pre>
<p><strong>说明:</strong></p>
<ul>
<li>Jenkins要安装<code>Slack Notification Plugin</code>插件</li>
<li><code>config</code> 是参数化对象,可传入 message、status 等。</li>
<li>这里先用 <code>echo</code> 模拟发送 Slack 通知。</li>
</ul>
<p><strong>Jenkinsfile 调用方式</strong></p>
<pre><code class="language-groovy">@Library('my-shared-lib') _

pipeline {
    agent any

    // 可选:启用彩色日志
    options {
      ansiColor('xterm')// 需要安装 AnsiColor 插件
    }

    environment {
      BUILD_TITLE = 'CI Pipeline'
      SLACK_CHANNEL = '#builds'
    }

    stages {
      stage('Build') {
            steps {
                script {
                  echo "🏗️Building..."
                  // 实际构建命令
                  // sh 'make build'
                }
            }
      }

      stage('Test') {
            steps {
                script {
                  echo "🧪 Running tests..."
                  // sh 'exit 1'// 模拟失败,实际替换为 sh 'make test'
                }
            }
      }
    }

    post {
      always {
            script {
                def buildStatus = currentBuild.result ?: 'SUCCESS'
                def color = buildStatus == 'SUCCESS' ? 'good' : 'danger'
                def buildUrl = env.BUILD_URL// 或 currentBuild.rawBuild.absoluteUrl
                def message = "Pipeline ${buildStatus}: &lt;${buildUrl}|${env.JOB_NAME} #${env.BUILD_NUMBER}&gt;"

                sendSlack(
                  message: message,
                  status: buildStatus,
                  color: color
                )
            }
      }
      success {
            echo "\u001B[32m✅ ${env.BUILD_TITLE} 成功!\u001B[0m"
      }
      failure {
            echo "\u001B[31m❌ ${env.BUILD_TITLE} 失败!\u001B[0m"
      }
    }
}
</code></pre>
<p>运行后,你会在控制台输出看到:</p>
<p><img src="https://img2024.cnblogs.com/blog/718867/202510/718867-20251014205931143-2073234569.png" alt="image" loading="lazy"></p>
<hr>
<h3 id="部署函数">部署函数</h3>
<p>📄 <code>vars/deployApp.groovy</code></p>
<pre><code class="language-groovy">def call(Map config = [:]) {
    def envName = config.env ?: 'staging'
    echo "🚀 Deploying application to ${envName}..."
    sh "echo 'Deploy to ${envName} successful!'"
}
</code></pre>
<p><strong>Jenkinsfile 调用方式</strong></p>
<pre><code class="language-groovy">@Library('my-shared-lib') _

pipeline {
    agent any

    stages {
      stage('deploy') {
            steps {
                script {
                  echo "🏗️Building..."
                  deployApp(
                        envName: 'prod'
                  )
                }
            }
      }

    }

}
</code></pre>
<p>运行后,你会在控制台输出看到:</p>
<p><img src="https://img2024.cnblogs.com/blog/718867/202510/718867-20251014210834625-692478750.png" alt="image" loading="lazy"></p>
<hr>
<h3 id="核心封装-pipeline">核心封装 Pipeline</h3>
<p>📄 <code>vars/ciPipeline.groovy</code></p>
<pre><code class="language-groovy">import org.example.Utils

def call(Map config = [:], Closure body = null) {
    pipeline {
      agent any
      parameters {
            string(name: 'BRANCH', defaultValue: 'main', description: 'Git branch to build')
            choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: 'Environment to deploy')
      }

      stages {
            stage('Init') {
                steps {
                  script {
                        Utils.printHeader(this,"CI Started")
                        echo "Branch: ${params.BRANCH}"
                  }
                }
            }

            stage('Build') {
                steps {
                  script {
                        try {
                            Utils.printHeader(this,"Build Stage")
                            echo 'mvn clean install'
                        } catch (err) {
                            sendSlack(message: "Build failed!", status: "FAILURE")
                            error("Build failed: ${err}")
                        }
                  }
                }
            }

            stage('Test') {
                steps {
                  script {
                        try {
                            Utils.printHeader(this,"Test Stage")
                            echo 'mvn compile test'
                        } catch (err) {
                            sendSlack(message: "Tests failed!", status: "FAILURE")
                            error("Tests failed: ${err}")
                        }
                  }
                }
            }

            stage('Deploy') {
                when {
                  expression { return params.DEPLOY_ENV != 'dev' }
                }
                steps {
                  script {
                        try {
                            deployApp(env: params.DEPLOY_ENV)
                            sendSlack(message: "Deployment to ${params.DEPLOY_ENV} successful")
                        } catch (err) {
                            sendSlack(message: "Deployment failed!", status: "FAILURE")
                            error("Deployment failed: ${err}")
                        }
                  }
                }
            }

            stage('Custom Steps') {
                steps {
                  script {
                        if (body != null) {
                            Utils.printHeader(this,"Running custom steps")
                            body()
                        }
                  }
                }
            }
      }

      post {
            always {
                script {
                  sendSlack(
                        message: "Pipeline completed at ${Utils.getTimestamp()}",
                        status: currentBuild.result ?: 'SUCCESS'
                  )
                }
            }
      }
    }
}
</code></pre>
<p>💡 功能亮点:</p>
<ul>
<li>支持 Jenkins 参数(BRANCH、DEPLOY_ENV)</li>
<li>内置错误捕获与 Slack 通知</li>
<li>可注入自定义阶段(body)</li>
<li>自动后置通知(post always)</li>
</ul>
<p><strong>调用示例 Jenkinsfile</strong></p>
<pre><code class="language-groovy">@Library('my-shared-lib') _
ciPipeline(env: 'prod') {
    stage('Custom Verification') {
      echo '🔍 Running custom security scan...'
      echo '"Scan complete."'
    }
}
</code></pre>
<p>运行后,你会在控制台输出看到:</p>
<p><img src="https://img2024.cnblogs.com/blog/718867/202510/718867-20251014214426297-1120102220.png" alt="image" loading="lazy"></p>
<p><img src="https://img2024.cnblogs.com/blog/718867/202510/718867-20251014214507593-359259330.png" alt="image" loading="lazy"></p>
<hr>
<h3 id="最佳实践建议">最佳实践建议</h3>
<table>
<thead>
<tr>
<th>类别</th>
<th>最佳实践</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>📁 目录结构</td>
<td><code>vars/</code> 放函数入口,<code>src/</code> 放类</td>
<td>让代码更干净、易维护</td>
</tr>
<tr>
<td>🧱 命名规则</td>
<td>函数名用动词开头,如 <code>deployApp()</code>、<code>runTests()</code></td>
<td>一目了然</td>
</tr>
<tr>
<td>🔄 参数管理</td>
<td>用 <code>Map config</code> + 默认值方式</td>
<td>兼容性强</td>
</tr>
<tr>
<td>🧩 错误处理</td>
<td><code>try/catch + notifySlack</code></td>
<td>保证失败有反馈</td>
</tr>
<tr>
<td>🔔 通知</td>
<td>用 post 块统一收尾</td>
<td>防止遗漏通知</td>
</tr>
<tr>
<td>🧪 测试</td>
<td>本地用 Jenkinsfile Runner 测试 Shared Library</td>
<td>避免推错到主库</td>
</tr>
<tr>
<td>🧬 版本管理</td>
<td>用 tag 固定版本 <code>@Library('lib@v1.2.0')</code></td>
<td>稳定性保障</td>
</tr>
</tbody>
</table>
<hr>
<h3 id="写在最后">写在最后</h3>
<p>这也许是最近一直想做的事情把,把自己练习和所学,从语雀中移到博客来,坚持输出,如果可以我希望明天的阅读量是200,HH,比昨天强就行。</p>
<p>当然,最近也在尝试收心,收回自己的注意力和能量,虽然说不太明白,但是总体感觉算是舒服把,先甭管别的,感动自己再说吧!</p>
<p>最后,感谢屏幕前认真阅读的你,如果文章对您有帮助,老规矩,还请帮忙点赞转发,谢谢啦!</p>
<p>今天就到这里啦,晚安,好梦!</p>


</div>
<div id="MySignature" role="contentinfo">
    <p><span style="font-family: 微软雅黑; font-size: 22px; font-weight: normal; font-style: italic; text-decoration: none"><strong>优秀不够,你是否无可替代</strong></span></p>
<p><span style="font-family: 微软雅黑; font-size: 18px; font-weight: normal; font-style: italic; text-decoration: none"><strong>
软件测试交流QQ群:721256703,期待你的加入!!</strong></span></p>
<p><span style="font-family: 微软雅黑; font-size: 18px; font-weight: normal; font-style: italic; text-decoration: none"><strong>欢迎关注我的微信公众号:软件测试君 </strong></span></p>
<img src="https://www.cnblogs.com/images/cnblogs_com/longronglang/1061549/o_QQ%E6%88%AA%E5%9B%BE20190728134401.jpg" height="200" width="450"><br><br><br>
来源:https://www.cnblogs.com/longronglang/p/19139489
頁: [1]
查看完整版本: Jenkins Share Library教程 —— 高级实战与最佳实践教程