跳到主要内容

多分支 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 界面创建

  1. 在 Jenkins 首页点击 New Item
  2. 输入任务名称,选择 Multibranch Pipeline
  3. 点击 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/def
  • feature/** 匹配 feature/abcfeature/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_IDPR 编号42
CHANGE_TARGETPR 目标分支develop
CHANGE_BRANCHPR 源分支feature/login
CHANGE_URLPR 链接https://github.com/...
CHANGE_TITLEPR 标题Add login feature
CHANGE_AUTHORPR 作者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 组织配置

  1. 创建 Organization Folder 类型的任务
  2. 配置 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

  1. 进入仓库 Settings → Webhooks → Add webhook
  2. 配置:
    • Payload URL: http://jenkins.example.com/github-webhook/
    • Content type: application/json
    • Events: 选择需要的触发事件

在 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 构建,实现代码合并前验证
  • 灵活配置:根据分支类型执行不同的构建逻辑
  • 组织级别:支持组织文件夹,自动发现所有仓库

下一步