多分支 Pipeline
多分支 Pipeline(Multibranch Pipeline)是 Jenkins 自动化构建的核心功能之一,它能够根据代码仓库的分支结构自动创建和管理 Pipeline 任务。当团队成员创建新分支或提交 Pull Request 时,Jenkins 会自动为这些分支创建对应的构建任务,无需手动配置。
为什么需要多分支 Pipeline?
在传统的单分支 Pipeline 中,每个分支都需要手动创建 Jenkins 任务。当项目有多个功能分支、发布分支,以及大量的 Pull Request 时,手动管理这些任务既繁琐又容易出错。
多分支 Pipeline 解决了这些问题:
自动化分支管理:Jenkins 自动扫描代码仓库,为每个包含 Jenkinsfile 的分支创建构建任务。分支删除时,对应的任务也会自动清理。
Pull Request 支持:自动为 Pull Request 创建构建任务,在代码合并前进行验证,确保代码质量。
统一的 Pipeline 定义:所有分支使用同一份 Jenkinsfile,确保构建流程的一致性。
简化团队协作:开发者无需请求 Jenkins 管理员创建任务,只需在分支中添加 Jenkinsfile 即可触发自动构建。
创建多分支 Pipeline
通过 Web 界面创建
- 在 Jenkins 首页点击 New Item
- 输入任务名称,选择 Multibranch Pipeline
- 点击 OK 进入配置页面
配置项说明:
Branch Sources:指定代码仓库来源。支持 Git、GitHub、Bitbucket、GitLab 等多种源。
# Git 源配置示例
Branch Sources:
- Git:
Project Repository: https://github.com/example/my-project.git
Credentials: github-credentials
Includes: *
Excludes:
Build Configuration:指定 Jenkinsfile 的位置。
Mode: by Jenkinsfile
Script Path: Jenkinsfile # 默认值,可自定义路径
Scan Multibranch Pipeline Triggers:配置仓库扫描计划。
Periodically if not otherwise run:
Interval: 5 minutes
配置示例:
# 完整配置示例
Branch Sources:
- GitHub:
API Endpoint: https://api.github.com
Credentials: github-credentials
Repository Owner: my-org
Repository: my-project
# 过滤分支
Behaviors:
- Discover branches
- Discover pull requests from origin
- Discover pull requests from forks:
Strategy: Trust nobody
Property Strategy:
Filter by name:
Include: main, develop, release/*
Exclude:
Build Configuration:
Mode: by Jenkinsfile
Script Path: Jenkinsfile
Scan Triggers:
Periodically: 5 minutes
Orphaned Item Strategy:
Max # of old items to keep: 10
通过 Job DSL 创建
如果使用 Job DSL 插件,可以通过代码定义多分支 Pipeline:
multibranchPipelineJob('my-project') {
branchSources {
git {
remote('https://github.com/example/my-project.git')
credentialsId('github-credentials')
includes('main develop release/* feature/*')
}
}
orphanedItemStrategy {
discardOldItems {
daysToKeep(7)
numToKeep(10)
}
}
factory {
workflowBranchProjectFactory {
scriptPath('Jenkinsfile')
}
}
triggers {
periodic(5)
}
}
分支发现策略
多分支 Pipeline 支持多种分支发现策略,可以根据项目需求灵活配置。
Git 分支发现
基本配置:
branchSources {
git {
remote('https://github.com/example/repo.git')
credentialsId('git-credentials')
// 包含特定分支
includes('main develop release/* feature/*')
// 排除特定分支
excludes('feature/experimental-*')
}
}
通配符说明:
*匹配任意字符(不包括/)**匹配任意字符(包括/)feature/*匹配feature/abc,但不匹配feature/abc/deffeature/**匹配feature/abc和feature/abc/def
GitHub 分支发现
GitHub 源提供更丰富的发现策略:
branchSources {
github {
repositoryUrl('https://github.com/example/repo')
credentialsId('github-credentials')
// 发现策略
traits {
// 发现所有分支
branchDiscoveryTrait()
// 发现 PR(来自同一仓库)
originPullRequestDiscoveryTrait {
strategyId(1) // 1: PR head, 2: PR merge
}
// 发现 PR(来自 Fork)
forkPullRequestDiscoveryTrait {
strategyId(1)
// 信任策略
trustTeamForks()
// 或不信任任何 Fork
// trustNobody()
}
// 通过正则过滤分支
headWildcardFilter {
includes('main develop feature/*')
excludes('')
}
// PR 过滤
pullRequestDiscoveryFilter {
strategy(1) // 1: PR head, 2: PR merge
}
}
}
}
GitLab 分支发现
branchSources {
gitLab {
projectPath('my-group/my-project')
serverUrl('https://gitlab.example.com')
credentialsId('gitlab-credentials')
traits {
branchDiscoveryTrait()
mergeRequestDiscoveryTrait {
strategyId(1)
}
}
}
}
环境变量
多分支 Pipeline 提供额外的环境变量,用于识别当前构建的分支信息。
分支相关变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
BRANCH_NAME | 分支名称 | main, feature/login, PR-42 |
CHANGE_ID | PR 编号 | 42 |
CHANGE_TARGET | PR 目标分支 | develop |
CHANGE_BRANCH | PR 源分支 | feature/login |
CHANGE_URL | PR 链接 | https://github.com/... |
CHANGE_TITLE | PR 标题 | Add login feature |
CHANGE_AUTHOR | PR 作者 | developer |
在 Pipeline 中使用
pipeline {
agent any
stages {
stage('Info') {
steps {
echo "Branch: ${env.BRANCH_NAME}"
script {
if (env.CHANGE_ID) {
echo "This is a Pull Request: #${env.CHANGE_ID}"
echo "Target: ${env.CHANGE_TARGET}"
echo "Source: ${env.CHANGE_BRANCH}"
} else {
echo "This is a branch build"
}
}
}
}
stage('Deploy') {
when {
expression { env.BRANCH_NAME == 'main' }
}
steps {
sh './deploy.sh production'
}
}
stage('Deploy to Staging') {
when {
expression { env.BRANCH_NAME == 'develop' }
}
steps {
sh './deploy.sh staging'
}
}
}
}
根据分支配置行为
多分支 Pipeline 的一个强大特性是能够根据不同的分支类型执行不同的操作。
分支特定的构建行为
pipeline {
agent none
stages {
stage('Build') {
agent { label 'linux' }
steps {
sh 'mvn clean package'
}
}
stage('Test') {
agent { label 'linux' }
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
}
stage('Integration Tests') {
// 仅在 main 和 develop 分支运行集成测试
when {
anyOf {
branch 'main'
branch 'develop'
}
}
steps {
sh 'mvn verify -Pintegration-test'
}
}
}
}
stage('Deploy to Staging') {
agent { label 'deploy' }
// 仅在 develop 分支部署到测试环境
when {
branch 'develop'
}
steps {
sh './deploy.sh staging'
}
}
stage('Deploy to Production') {
agent { label 'deploy' }
// 仅在 main 分支部署到生产环境
when {
branch 'main'
}
steps {
input message: 'Deploy to Production?'
sh './deploy.sh production'
}
}
stage('Code Review') {
agent { label 'linux' }
// PR 构建时运行代码质量检查
when {
expression { env.CHANGE_ID != null }
}
steps {
sh 'mvn sonar:sonar'
}
}
}
}
使用 when 指令判断分支类型
// 判断是否为 PR 构建
when {
expression { env.CHANGE_ID != null }
}
// 判断是否为 release 分支
when {
branch pattern: "release/\\d+\\.\\d+", comparator: "REGEXP"
}
// 判断是否为 feature 分支
when {
branch pattern: "feature/*"
}
// 组合条件
when {
anyOf {
branch 'main'
branch 'develop'
expression { env.CHANGE_ID != null }
}
}
组织文件夹
组织文件夹(Organization Folder)是比多分支 Pipeline 更高层次的抽象,它可以自动发现整个组织下的所有仓库。
GitHub 组织配置
- 创建 Organization Folder 类型的任务
- 配置 GitHub 组织:
Organizations:
- GitHub:
API Endpoint: https://api.github.com
Credentials: github-credentials
Owner: my-organization
Behaviors:
- Discover repositories:
Strategy: All
# 或仅发现特定仓库
# Strategy: Regex
# Regex: ^service-.*
- Filter by name:
Include: .*
Exclude: ^internal-.*
Project Recognizers:
- Pipeline Jenkinsfile
GitLab 组配置
Organizations:
- GitLab:
Server: https://gitlab.example.com
Credentials: gitlab-credentials
Group: my-group
Include subgroups: true
Project recognizers:
- Pipeline Jenkinsfile
Bitbucket 团队配置
Organizations:
- Bitbucket:
Server: https://bitbucket.example.com
Credentials: bitbucket-credentials
Owner: my-team
孤儿项目清理
当分支被删除或合并后,对应的 Jenkins 任务成为"孤儿项目"。配置孤儿项目清理策略可以自动清理这些任务。
Orphaned Item Strategy:
Discard old items:
Days to keep: 7 # 保留天数
Max # of items to keep: 20 # 最大保留数量
或通过 Job DSL:
orphanedItemStrategy {
discardOldItems {
daysToKeep(7)
numToKeep(20)
}
}
Webhook 触发
配置 Webhook 可以在代码推送时立即触发多分支 Pipeline 扫描,无需等待定时扫描。
GitHub Webhook
在 GitHub 仓库配置 Webhook:
- 进入仓库 Settings → Webhooks → Add webhook
- 配置:
- Payload URL:
http://jenkins.example.com/github-webhook/ - Content type:
application/json - Events: 选择需要的触发事件
- Payload URL:
在 Jenkins 中启用:
确保安装了 GitHub Branch Source Plugin,多分支 Pipeline 会自动响应 Webhook。
GitLab Webhook
# GitLab 项目配置
Settings → Webhooks:
URL: http://jenkins.example.com/project/my-project
Secret Token: your-secret-token
Trigger: Push events, Merge request events
Bitbucket Webhook
# Bitbucket 仓库配置
Repository settings → Webhooks:
Title: Jenkins
URL: http://jenkins.example.com/bitbucket-scmsource-hook/notify
Triggers: Push, Pull Request
多分支 Pipeline 最佳实践
Jenkinsfile 放置
将 Jenkinsfile 放在项目根目录,这是默认位置,也最符合团队习惯:
my-project/
├── Jenkinsfile
├── pom.xml
├── src/
└── README.md
如果需要自定义路径:
factory {
workflowBranchProjectFactory {
scriptPath('ci/Jenkinsfile')
}
}
分支命名规范
建立清晰的分支命名规范,便于配置过滤规则:
main # 主分支
develop # 开发分支
release/1.0.0 # 发布分支
feature/login # 功能分支
bugfix/auth-error # 修复分支
hotfix/critical # 紧急修复分支
对应的过滤配置:
includes('main develop release/* feature/* bugfix/* hotfix/*')
PR 构建验证
在 PR 构建中执行代码质量检查和测试:
pipeline {
agent any
stages {
stage('PR Validation') {
when {
expression { env.CHANGE_ID != null }
}
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Code Quality') {
steps {
sh 'mvn sonar:sonar'
}
}
}
}
stage('Branch Build') {
when {
expression { env.CHANGE_ID == null }
}
steps {
echo "Building branch: ${env.BRANCH_NAME}"
}
}
}
}
环境隔离
为不同分支使用不同的部署环境:
def getEnvironment() {
if (env.BRANCH_NAME == 'main') {
return 'production'
} else if (env.BRANCH_NAME == 'develop') {
return 'staging'
} else if (env.BRANCH_NAME.startsWith('feature/')) {
return 'development'
} else {
return 'none'
}
}
pipeline {
agent any
environment {
DEPLOY_ENV = "${getEnvironment()}"
}
stages {
stage('Build') {
steps {
echo "Building for ${env.DEPLOY_ENV}"
}
}
stage('Deploy') {
when {
expression { env.DEPLOY_ENV != 'none' }
}
steps {
sh "./deploy.sh ${env.DEPLOY_ENV}"
}
}
}
}
常见问题
问题 1:分支未被发现
可能原因:
- 分支中缺少
Jenkinsfile - 分支名称被排除规则过滤
- 凭据权限不足
解决方案:
- 检查分支中是否有
Jenkinsfile - 检查分支发现配置中的 include/exclude 规则
- 验证凭据是否有读取仓库的权限
- 手动触发扫描查看日志
问题 2:PR 构建权限问题
问题:来自 Fork 的 PR 无法触发构建
解决方案: 配置 Fork PR 发现策略:
forkPullRequestDiscoveryTrait {
strategyId(1)
trustEveryone() // 信任所有人(谨慎使用)
// 或仅信任团队成员
// trustTeamForks()
// 或信任特定用户
// trustPermission()
}
问题 3:孤儿项目未清理
解决方案: 检查孤儿项目清理配置:
orphanedItemStrategy {
discardOldItems {
daysToKeep(7)
numToKeep(20)
}
}
手动清理:
// 在 Script Console 执行
Jenkins.instance.getAllItems(org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject).each { job ->
job.getSCMSources().each { source ->
source.fetch(job, null).each { branch ->
def name = branch.name
def jobName = job.getItem(name)
if (jobName == null) {
println "Orphan: ${job.name}/${name}"
}
}
}
}
小结
多分支 Pipeline 是现代 CI/CD 工作流的基础:
- 自动化管理:根据分支自动创建和管理构建任务
- PR 支持:支持 Pull Request 构建,实现代码合并前验证
- 灵活配置:根据分支类型执行不同的构建逻辑
- 组织级别:支持组织文件夹,自动发现所有仓库