多分支流水线 #
多分支流水线(Multibranch Pipeline)是Jenkins的一个强大特性,能够自动发现Git仓库中的分支并创建对应的Pipeline任务。
什么是多分支流水线? #
多分支流水线可以:
- 自动发现Git仓库中的所有分支
- 为每个分支创建独立的Pipeline任务
- 支持Pull Request构建
- 自动清理已删除分支的任务
text
┌─────────────────────────────────────────────────────────────┐
│ Multibranch Pipeline │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ main │ │ develop │ │ feature/xxx │ │
│ │ │ │ │ │ │ │
│ │ Pipeline │ │ Pipeline │ │ Pipeline │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ release/1.0 │ │ PR #42 │ │
│ │ │ │ │ │
│ │ Pipeline │ │ Pipeline │ │
│ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
创建多分支流水线 #
步骤1:创建任务 #
- 点击 New Item
- 输入任务名称
- 选择 Multibranch Pipeline
- 点击 OK
步骤2:配置分支源 #
GitHub #
text
Branch Sources:
Add source: GitHub
Owner: organization-name
Repository: repo-name
Credentials: github-token
Git #
text
Branch Sources:
Add source: Git
Repository URL: https://github.com/user/repo.git
Credentials: github-creds
GitLab #
text
Branch Sources:
Add source: GitLab
Server: GitLab Server
Owner: group-name
Project: project-name
Credentials: gitlab-token
Bitbucket #
text
Branch Sources:
Add source: Bitbucket
Server: Bitbucket Server
Owner: team-name
Repository: repo-name
Credentials: bitbucket-creds
步骤3:配置构建策略 #
text
Build Configuration:
Mode: by Jenkinsfile
Script Path: Jenkinsfile
步骤4:配置扫描策略 #
text
Scan Multibranch Pipeline Triggers:
☑ Periodically if not otherwise run
Interval: 1 minute
分支发现策略 #
发现分支 #
groovy
properties([
pipelineTriggers([
branchDiscovery: [
strategyId: 1 // 排除也是PR的分支
]
])
])
策略选项:
| 策略 | 说明 |
|---|---|
| 1 | 排除也是PR的分支 |
| 2 | 只有被PR的分支 |
| 3 | 所有分支 |
发现PR #
text
Discover pull requests from origin:
Strategy: Merging the pull request with the current target branch revision
Discover pull requests from forks:
Strategy: Merging the pull request with the current target branch revision
Trust: Trusted users
PR策略:
| 策略 | 说明 |
|---|---|
| Merging | 合并PR后构建 |
| Head only | 只构建PR源分支 |
| Both | 两种方式都构建 |
过滤分支 #
text
Filter by name (with regular expressions):
Include: (feature|release|hotfix)/.*
Exclude: (test|temp)/.*
text
Filter by name:
Include: main, develop
Exclude: test-*
Jenkinsfile配置 #
基本结构 #
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
echo "Building branch: ${env.BRANCH_NAME}"
sh 'mvn clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Deploy') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
sh 'deploy-to-prod.sh'
}
}
}
}
分支条件判断 #
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Deploy to Dev') {
when {
branch 'develop'
}
steps {
sh 'deploy-to-dev.sh'
}
}
stage('Deploy to Staging') {
when {
branch pattern: 'release/*', comparator: 'GLOB'
}
steps {
sh 'deploy-to-staging.sh'
}
}
stage('Deploy to Prod') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
input message: 'Deploy to production?'
sh 'deploy-to-prod.sh'
}
}
}
}
PR条件判断 #
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Integration Test') {
when {
changeRequest()
}
steps {
sh 'mvn verify -P integration'
}
}
stage('Deploy') {
when {
allOf {
changeRequest target: 'main'
branch 'feature/*'
}
}
steps {
sh 'deploy-to-preview.sh'
}
}
}
}
changeRequest条件 #
groovy
when {
changeRequest()
}
when {
changeRequest id: '42'
}
when {
changeRequest target: 'main'
}
when {
changeRequest branch: 'feature/*'
}
when {
changeRequest author: 'john'
}
when {
changeRequest title: 'fix:.*'
}
when {
changeRequest url: 'https://github.com/*'
}
环境变量 #
多分支流水线提供额外的环境变量:
| 变量 | 说明 | 示例 |
|---|---|---|
| BRANCH_NAME | 分支名称 | main, feature/xxx |
| CHANGE_ID | PR编号 | 42 |
| CHANGE_URL | PR URL | https://github.com/… |
| CHANGE_TITLE | PR标题 | Fix bug |
| CHANGE_AUTHOR | PR作者 | john |
| CHANGE_TARGET | PR目标分支 | main |
| CHANGE_BRANCH | PR源分支 | feature/xxx |
使用示例 #
groovy
pipeline {
agent any
stages {
stage('Info') {
steps {
echo "Branch: ${env.BRANCH_NAME}"
script {
if (env.CHANGE_ID) {
echo "PR #${env.CHANGE_ID}"
echo "Title: ${env.CHANGE_TITLE}"
echo "Author: ${env.CHANGE_AUTHOR}"
echo "Target: ${env.CHANGE_TARGET}"
}
}
}
}
}
}
分支命名约定 #
常见分支模型 #
Git Flow #
text
main - 生产分支
develop - 开发分支
feature/* - 功能分支
release/* - 发布分支
hotfix/* - 热修复分支
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Deploy to Dev') {
when {
branch 'develop'
}
steps {
sh 'deploy.sh dev'
}
}
stage('Deploy to Staging') {
when {
branch pattern: 'release/*', comparator: 'GLOB'
}
steps {
sh 'deploy.sh staging'
}
}
stage('Deploy to Prod') {
when {
branch 'main'
}
steps {
input message: 'Deploy to production?'
sh 'deploy.sh prod'
}
}
stage('Hotfix Deploy') {
when {
branch pattern: 'hotfix/*', comparator: 'GLOB'
}
steps {
sh 'deploy-hotfix.sh'
}
}
}
}
GitHub Flow #
text
main - 主分支
feature/* - 功能分支
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Deploy Preview') {
when {
changeRequest()
}
steps {
sh "deploy-preview.sh ${env.CHANGE_ID}"
}
}
stage('Deploy Production') {
when {
branch 'main'
}
steps {
sh 'deploy-production.sh'
}
}
}
}
组织文件夹 #
GitHub组织 #
自动发现GitHub组织下的所有仓库:
- New Item → GitHub Organization
- 配置GitHub访问:
text
GitHub:
API URL: https://api.github.com
Credentials: github-token
Owner: organization-name
- 配置项目识别:
text
Project Recognizers:
☑ Pipeline Jenkinsfile
GitLab组 #
text
GitLab:
Server: GitLab Server
Credentials: gitlab-token
Group: group-name
Bitbucket团队 #
text
Bitbucket:
Server: Bitbucket Server
Credentials: bitbucket-creds
Team: team-name
高级配置 #
并行分支构建 #
groovy
options {
disableConcurrentBuilds()
}
分支特定配置 #
groovy
pipeline {
agent any
environment {
DEPLOY_ENV = 'dev'
}
stages {
stage('Set Environment') {
steps {
script {
switch(env.BRANCH_NAME) {
case 'main':
case 'master':
env.DEPLOY_ENV = 'prod'
break
case ~/release\/.*/:
env.DEPLOY_ENV = 'staging'
break
case 'develop':
env.DEPLOY_ENV = 'dev'
break
default:
env.DEPLOY_ENV = 'preview'
}
}
}
}
stage('Deploy') {
steps {
echo "Deploying to ${env.DEPLOY_ENV}"
sh "deploy.sh ${env.DEPLOY_ENV}"
}
}
}
}
通知配置 #
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
post {
success {
script {
if (env.CHANGE_ID) {
// PR构建成功,通知PR作者
emailext(
subject: "PR #${env.CHANGE_ID} Build Passed",
to: "${env.CHANGE_AUTHOR}@example.com",
body: "Your PR build passed!"
)
} else {
// 分支构建成功
slackSend(
channel: '#builds',
color: 'good',
message: "Branch ${env.BRANCH_NAME} build passed"
)
}
}
}
}
}
分支清理 #
自动清理 #
text
Orphaned Item Strategy:
☑ Discard old items
Max # of old items to keep: 10
Days to keep old items: 7
手动清理 #
groovy
pipeline {
agent any
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
}
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
}
Webhook触发 #
GitHub Webhook #
- 在GitHub仓库设置中添加Webhook
- URL:
http://jenkins-url/github-webhook/ - Content type:
application/json - 选择触发事件
GitLab Webhook #
- 在GitLab项目设置中添加Webhook
- URL:
http://jenkins-url/project/your-job - 选择触发事件
Bitbucket Webhook #
- 在Bitbucket仓库设置中添加Webhook
- URL:
http://jenkins-url/bitbucket-hook/
完整示例 #
完整的多分支流水线 #
groovy
pipeline {
agent any
tools {
maven 'Maven 3.8'
jdk 'JDK 11'
}
environment {
APP_NAME = 'myapp'
VERSION = "${BUILD_NUMBER}"
DOCKER_REGISTRY = 'registry.example.com'
}
options {
timeout(time: 30, unit: 'MINUTES')
buildDiscarder(logRotator(numToKeepStr: '20'))
disableConcurrentBuilds()
timestamps()
}
stages {
stage('Checkout') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
}
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
post {
success {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
stage('Integration Tests') {
steps {
sh 'mvn verify -P integration'
}
post {
always {
junit '**/target/failsafe-reports/*.xml'
}
}
}
}
}
stage('SonarQube') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
stage('Build Image') {
steps {
script {
def imageTag = "${DOCKER_REGISTRY}/${APP_NAME}:${VERSION}"
if (env.CHANGE_ID) {
imageTag = "${DOCKER_REGISTRY}/${APP_NAME}:pr-${env.CHANGE_ID}"
}
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry') {
def image = docker.build(imageTag)
image.push()
}
}
}
}
stage('Deploy Preview') {
when {
changeRequest()
}
steps {
script {
sh """
kubectl create namespace preview-${env.CHANGE_ID} || true
kubectl apply -f k8s/ -n preview-${env.CHANGE_ID}
kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:pr-${env.CHANGE_ID} -n preview-${env.CHANGE_ID}
"""
}
}
}
stage('Deploy to Dev') {
when {
branch 'develop'
}
steps {
sh """
kubectl apply -f k8s/ -n dev
kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${VERSION} -n dev
"""
}
}
stage('Deploy to Staging') {
when {
branch pattern: 'release/*', comparator: 'GLOB'
}
steps {
sh """
kubectl apply -f k8s/ -n staging
kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${VERSION} -n staging
"""
}
}
stage('Deploy to Production') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
input message: 'Deploy to production?',
ok: 'Deploy',
submitter: 'admin,release-team'
sh """
kubectl apply -f k8s/ -n production
kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${VERSION} -n production
"""
}
}
}
post {
always {
cleanWs()
}
success {
script {
def message = "Build ${BUILD_NUMBER} succeeded"
if (env.CHANGE_ID) {
message = "PR #${env.CHANGE_ID} build succeeded"
}
slackSend(
channel: '#builds',
color: 'good',
message: "${message}\nBranch: ${env.BRANCH_NAME}\nURL: ${BUILD_URL}"
)
}
}
failure {
script {
def message = "Build ${BUILD_NUMBER} failed"
if (env.CHANGE_ID) {
message = "PR #${env.CHANGE_ID} build failed"
}
slackSend(
channel: '#builds',
color: 'danger',
message: "${message}\nBranch: ${env.BRANCH_NAME}\nURL: ${BUILD_URL}"
)
}
}
}
}
下一步学习 #
小结 #
- 多分支流水线自动发现分支和PR
- 支持多种Git平台
- 可以配置分支过滤和命名策略
- 提供丰富的环境变量
- 支持组织级别的仓库发现
- 适合现代分支开发模式
最后更新:2026-03-28