流水线模板模块架构指南
概述
流水线模板(Pipeline Template)是 BK-CI 的核心功能模块之一,允许用户将流水线配置抽象为可复用的模板,支持模板的创建、版本管理、实例化、权限控制以及与研发商店的集成。
核心价值
- 配置复用:将通用的流水线配置抽象为模板,避免重复配置
- 标准化管理:通过模板统一管理流水线标准,确保一致性
- 版本控制:支持模板版本管理,可追溯历史变更
- 批量操作:支持批量实例化和更新,提高效率
- 商店集成:支持模板发布到研发商店,实现跨项目共享
系统架构
┌─────────────────────────────────────────────────────────────────────────┐
│ 流水线模板模块 │
├─────────────────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ API 接口层 │ │ 业务服务层 │ │ 数据访问层 │ │
│ │ (V1 + V2) │ │ (Service) │ │ (DAO) │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 数据库表 │ │
│ │ T_TEMPLATE | T_TEMPLATE_PIPELINE | T_PIPELINE_TEMPLATE_INFO │ │
│ │ T_PIPELINE_TEMPLATE_RESOURCE_VERSION | T_TEMPLATE_INSTANCE_* │ │
│ └─────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 权限控制 │ │ 研发商店集成 │ │ 事件驱动 │ │
│ │ (RBAC) │ │ (Store) │ │ (MQ) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
一、版本架构
系统存在两个版本的实现,V2 版本是新架构,功能更完善:
| 版本 |
特点 |
适用场景 |
| V1 |
原始实现,功能基础 |
兼容老版本,简单场景 |
| V2 |
新架构,支持草稿、PAC、完善的版本管理 |
新功能开发,复杂场景 |
模板类型
// 文件: process/api-process/.../pojo/template/TemplateType.kt
enum class TemplateType(val value: String) {
CUSTOMIZE("customize"), // 自定义模板 - 项目内创建
CONSTRAINT("constraint"), // 约束模板 - 来自研发商店
PUBLIC("public") // 公共模板 - 系统级公共模板
}
二、目录结构
2.1 API 接口层
src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/
├── api/template/ # V1 版本 API
│ ├── UserPTemplateResource.kt # 用户模板接口
│ ├── UserTemplateInstanceResource.kt # 模板实例化接口
│ ├── UserPipelineTemplateResource.kt # 流水线模板接口
│ ├── UserTemplateAtomResource.kt # 模板插件接口
│ ├── ServicePTemplateResource.kt # 服务间调用接口
│ ├── ServiceTemplateInstanceResource.kt # 服务间实例接口
│ └── v2/ # V2 版本 API
│ ├── UserPipelineTemplateV2Resource.kt # V2 用户模板接口
│ ├── UserPipelineTemplateInstanceV2Resource.kt # V2 实例化接口
│ ├── ServicePipelineTemplateV2Resource.kt # V2 服务间接口
│ ├── OpPipelineTemplateResource.kt # V2 运营管理接口
│ └── UserTemplateAtomV2Resource.kt # V2 插件检查接口
├── api/op/
│ └── OpPipelineTemplateResource.kt # 运营管理模板接口
├── api/builds/
│ └── BuildTemplateAcrossResource.kt # 跨项目模板访问
└── api/service/
└── ServiceTemplateAcrossResource.kt # 服务间跨项目模板
2.2 POJO 数据模型
src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/pojo/template/
├── TemplateType.kt # 模板类型枚举
├── TemplateModel.kt # 模板模型
├── TemplateModelDetail.kt # 模板模型详情
├── TemplateVersion.kt # 模板版本信息
├── TemplateId.kt # 模板ID
├── TemplateInstanceCreate.kt # 实例创建请求
├── TemplateInstanceUpdate.kt # 实例更新请求
├── TemplateInstanceParams.kt # 实例参数
├── TemplatePipeline.kt # 模板流水线
├── TemplateWithPermission.kt # 带权限的模板
├── TemplateCompareModel.kt # 模板对比模型
├── CopyTemplateReq.kt # 复制模板请求
├── SaveAsTemplateReq.kt # 另存为模板请求
├── MarketTemplateRequest.kt # 商店模板请求
└── v2/ # V2 版本 POJO
├── PipelineTemplateInfoV2.kt # V2 模板基础信息
├── PipelineTemplateResource.kt # V2 模板资源(版本)
├── PipelineTemplateDetailsResponse.kt # V2 模板详情响应
├── PipelineTemplateVersionInfo.kt # V2 版本信息
├── PipelineTemplateCustomCreateReq.kt # V2 自定义创建请求
├── PipelineTemplateCopyCreateReq.kt # V2 复制创建请求
├── PipelineTemplateMarketCreateReq.kt # V2 商店导入请求
├── PipelineTemplateDraftSaveReq.kt # V2 草稿保存请求
├── PipelineTemplateDraftReleaseReq.kt # V2 草稿发布请求
├── PipelineTemplateInstancesRequest.kt # V2 批量实例化请求
├── PipelineTemplateCompareResponse.kt # V2 版本对比响应
└── TemplateInstanceType.kt # 实例类型枚举
2.3 业务服务层
src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/template/
├── TemplateFacadeService.kt # V1 核心门面服务 (120KB)
├── TemplateCommonService.kt # 模板通用服务
├── TemplateSettingService.kt # 模板设置服务
├── TemplateAtomService.kt # 模板插件服务
├── TemplatePACService.kt # 模板 PAC 服务
└── v2/ # V2 版本服务
├── PipelineTemplateFacadeService.kt # V2 核心门面服务 (71KB)
├── PipelineTemplateInstanceService.kt # V2 实例化服务 (41KB)
├── PipelineTemplatePersistenceService.kt # V2 持久化服务 (38KB)
├── PipelineTemplateMigrateService.kt # V2 迁移服务 (38KB)
├── PipelineTemplateGenerator.kt # 模板生成器
├── PipelineTemplateMarketFacadeService.kt # 商店模板服务
├── PipelineTemplateInfoService.kt # 模板信息服务
├── PipelineTemplateResourceService.kt # 模板资源服务
├── PipelineTemplateRelatedService.kt # 模板关联服务
├── PipelineTemplateSettingService.kt # V2 模板设置服务
├── PipelineTemplateCommonService.kt # V2 通用服务
├── PipelineTemplateAtomService.kt # V2 插件服务
├── PipelineTemplateVersionValidator.kt # 版本校验器
├── PipelineTemplateModelInitializer.kt # 模型初始化器
├── PipelineTemplateInstanceListener.kt # 实例化事件监听器
└── version/ # 版本管理
├── PipelineTemplateVersionManager.kt # 版本管理器
├── PipelineTemplateVersionCreateContext.kt # 版本创建上下文
├── PipelineTemplateVersionDeleteContext.kt # 版本删除上下文
├── convert/ # 请求转换器
│ ├── PipelineTemplateCustomCreateReqConverter.kt
│ ├── PipelineTemplateCopyCreateReqConverter.kt
│ ├── PipelineTemplateMarketCreateReqConverter.kt
│ ├── PipelineTemplateDraftSaveReqConverter.kt
│ ├── PipelineTemplateDraftReleaseReqConverter.kt
│ └── PipelineTemplateDraftRollbackReqConverter.kt
├── hander/ # 版本处理器
│ ├── PipelineTemplateVersionCreateHandler.kt
│ ├── PipelineTemplateDraftSaveHandler.kt
│ ├── PipelineTemplateDraftReleaseHandler.kt
│ ├── PipelineTemplateReleaseCreateHandler.kt
│ ├── PipelineTemplateBranchCreateHandler.kt
│ └── PipelineTemplateVersionDeleteHandler.kt
└── processor/ # 版本后处理器
├── PTemplateVersionCreatePostProcessor.kt
├── PTemplateVersionDeletePostProcessor.kt
├── PTemplateCompatibilityVersionPostProcessor.kt
├── PTemplateMarketInstallVersionPostProcessor.kt
└── PTemplateOperationLogVersionPostProcessor.kt
2.4 数据访问层
src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/
├── engine/dao/template/ # V1 版本 DAO
│ ├── TemplateDao.kt # 核心模板 DAO (25KB)
│ └── TemplatePipelineDao.kt # 模板流水线 DAO (16KB)
└── dao/template/ # V2 版本 DAO
├── PipelineTemplateInfoDao.kt # V2 模板信息 DAO (16KB)
├── PipelineTemplateResourceDao.kt # V2 模板资源 DAO (23KB)
├── PipelineTemplateSettingDao.kt # V2 模板设置 DAO (13KB)
├── PipelineTemplateRelatedDao.kt # V2 模板关联 DAO (15KB)
└── PipelineTemplateMigrationDao.kt # V2 迁移 DAO
2.5 权限控制
src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/template/
├── PipelineTemplatePermissionService.kt # 权限服务接口
├── AbstractPipelineTemplatePermissionService.kt # 抽象实现
├── RbacPipelineTemplatePermissionService.kt # RBAC 权限实现
├── MockPipelineTemplatePermissionService.kt # Mock 实现
└── config/
└── PipelineTemplatePermConfiguration.kt # 权限配置
三、数据库表结构
3.1 V1 版本表
T_TEMPLATE - 模板信息表
CREATE TABLE IF NOT EXISTS `T_TEMPLATE` (
`VERSION` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '版本号',
`ID` varchar(32) NOT NULL COMMENT '模板ID',
`TEMPLATE_NAME` varchar(64) NOT NULL COMMENT '模板名称',
`PROJECT_ID` varchar(34) NOT NULL COMMENT '项目ID',
`VERSION_NAME` varchar(64) NOT NULL COMMENT '版本名称',
`CREATOR` varchar(64) NOT NULL COMMENT '创建者',
`CREATED_TIME` datetime(3) DEFAULT NULL COMMENT '创建时间',
`TEMPLATE` mediumtext COMMENT '模板内容(JSON)',
`TYPE` varchar(32) NOT NULL DEFAULT 'CUSTOMIZE' COMMENT '模板类型',
`CATEGORY` varchar(128) DEFAULT NULL COMMENT '分类',
`LOGO_URL` varchar(512) DEFAULT NULL COMMENT 'Logo地址',
`SRC_TEMPLATE_ID` varchar(32) DEFAULT NULL COMMENT '源模板ID',
`STORE_FLAG` bit(1) DEFAULT b'0' COMMENT '是否来自商店',
`WEIGHT` int(11) DEFAULT '0' COMMENT '权重',
`LATEST_FLAG` bit(1) DEFAULT b'0' COMMENT '是否最新版本',
`DRAFT_FLAG` bit(1) DEFAULT b'0' COMMENT '是否草稿',
PRIMARY KEY (`VERSION`),
KEY `IDX_PROJECT_ID` (`PROJECT_ID`),
KEY `IDX_ID` (`ID`),
KEY `IDX_SRC_TEMPLATE_ID` (`SRC_TEMPLATE_ID`)
);
T_TEMPLATE_PIPELINE - 模板流水线关联表
CREATE TABLE IF NOT EXISTS `T_TEMPLATE_PIPELINE` (
`PIPELINE_ID` varchar(34) NOT NULL COMMENT '流水线ID',
`INSTANCE_TYPE` varchar(32) NOT NULL DEFAULT 'CONSTRAINT' COMMENT '实例类型',
`ROOT_TEMPLATE_ID` varchar(32) DEFAULT NULL COMMENT '根模板ID',
`VERSION` bigint(20) NOT NULL COMMENT '模板版本',
`VERSION_NAME` varchar(64) NOT NULL COMMENT '版本名称',
`TEMPLATE_ID` varchar(32) NOT NULL COMMENT '模板ID',
`CREATOR` varchar(64) NOT NULL COMMENT '创建者',
`UPDATOR` varchar(64) NOT NULL COMMENT '更新者',
`CREATED_TIME` datetime NOT NULL COMMENT '创建时间',
`UPDATED_TIME` datetime NOT NULL COMMENT '更新时间',
`BUILD_NO` text COMMENT '构建号信息',
`PARAM` mediumtext COMMENT '参数',
`DELETED` bit(1) DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`PIPELINE_ID`),
KEY `IDX_TEMPLATE_ID` (`TEMPLATE_ID`),
KEY `IDX_ROOT_TEMPLATE_ID` (`ROOT_TEMPLATE_ID`)
);
3.2 V2 版本表
T_PIPELINE_TEMPLATE_INFO - 模板基础信息表
CREATE TABLE IF NOT EXISTS `T_PIPELINE_TEMPLATE_INFO` (
`TEMPLATE_ID` varchar(34) NOT NULL COMMENT '模板ID',
`PROJECT_ID` varchar(64) NOT NULL COMMENT '项目ID',
`TEMPLATE_NAME` varchar(255) NOT NULL COMMENT '模板名称',
`TEMPLATE_TYPE` varchar(32) NOT NULL DEFAULT 'CUSTOMIZE' COMMENT '模板类型',
`CREATOR` varchar(64) NOT NULL COMMENT '创建者',
`CREATE_TIME` datetime(3) NOT NULL COMMENT '创建时间',
`LATEST_VERSION` bigint(20) DEFAULT NULL COMMENT '最新版本号',
`RELEASE_VERSION` bigint(20) DEFAULT NULL COMMENT '发布版本号',
`DRAFT_VERSION` bigint(20) DEFAULT NULL COMMENT '草稿版本号',
`DELETE` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`TEMPLATE_ID`),
KEY `IDX_PROJECT_ID` (`PROJECT_ID`)
);
T_PIPELINE_TEMPLATE_RESOURCE_VERSION - 模板资源版本表
CREATE TABLE IF NOT EXISTS `T_PIPELINE_TEMPLATE_RESOURCE_VERSION` (
`TEMPLATE_ID` varchar(34) NOT NULL COMMENT '模板ID',
`VERSION` bigint(20) NOT NULL COMMENT '版本号',
`VERSION_NAME` varchar(64) NOT NULL COMMENT '版本名称',
`PROJECT_ID` varchar(64) NOT NULL COMMENT '项目ID',
`CREATOR` varchar(64) NOT NULL COMMENT '创建者',
`CREATE_TIME` datetime(3) NOT NULL COMMENT '创建时间',
`MODEL` mediumtext COMMENT '模型内容(JSON)',
`STATUS` varchar(32) DEFAULT NULL COMMENT '版本状态',
`BRANCH_ACTION` varchar(32) DEFAULT NULL COMMENT '分支操作',
`DESCRIPTION` varchar(1024) DEFAULT NULL COMMENT '版本描述',
`YAML` mediumtext COMMENT 'YAML内容',
`YAML_VERSION` varchar(34) DEFAULT NULL COMMENT 'YAML版本',
`BASE_VERSION` bigint(20) DEFAULT NULL COMMENT '基础版本',
`DEBUG_BUILD_ID` varchar(64) DEFAULT NULL COMMENT '调试构建ID',
`REFER_FLAG` bit(1) DEFAULT NULL COMMENT '引用标志',
`REFER_TEMPLATE_ID` varchar(34) DEFAULT NULL COMMENT '引用模板ID',
PRIMARY KEY (`TEMPLATE_ID`, `VERSION`),
KEY `IDX_PROJECT_ID` (`PROJECT_ID`)
);
T_TEMPLATE_INSTANCE_BASE - 实例化基础表
CREATE TABLE IF NOT EXISTS `T_TEMPLATE_INSTANCE_BASE` (
`ID` varchar(32) NOT NULL COMMENT '主键ID',
`TEMPLATE_ID` varchar(32) DEFAULT NULL COMMENT '模板ID',
`TEMPLATE_VERSION` bigint(20) DEFAULT NULL COMMENT '模板版本',
`USE_TEMPLATE_SETTINGS_FLAG` bit(1) DEFAULT b'1' COMMENT '使用模板设置',
`PROJECT_ID` varchar(64) NOT NULL COMMENT '项目ID',
`TOTAL_ITEM_NUM` int(11) NOT NULL COMMENT '总实例数',
`SUCCESS_ITEM_NUM` int(11) NOT NULL DEFAULT '0' COMMENT '成功实例数',
`FAIL_ITEM_NUM` int(11) NOT NULL DEFAULT '0' COMMENT '失败实例数',
`STATUS` varchar(32) NOT NULL COMMENT '状态',
`CREATOR` varchar(50) NOT NULL COMMENT '创建者',
`MODIFIER` varchar(50) NOT NULL COMMENT '修改者',
`UPDATE_TIME` datetime(3) NOT NULL COMMENT '更新时间',
`CREATE_TIME` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`ID`),
KEY `IDX_TEMPLATE_ID` (`TEMPLATE_ID`),
KEY `IDX_PROJECT_ID` (`PROJECT_ID`)
);
T_TEMPLATE_INSTANCE_ITEM - 实例化项表
CREATE TABLE IF NOT EXISTS `T_TEMPLATE_INSTANCE_ITEM` (
`ID` varchar(32) NOT NULL COMMENT '主键ID',
`BASE_ID` varchar(32) NOT NULL COMMENT '基础ID',
`PIPELINE_ID` varchar(34) DEFAULT NULL COMMENT '流水线ID',
`PIPELINE_NAME` varchar(255) NOT NULL COMMENT '流水线名称',
`BUILD_NO_INFO` varchar(512) DEFAULT NULL COMMENT '构建号信息',
`STATUS` varchar(32) NOT NULL COMMENT '状态',
`PARAM` mediumtext COMMENT '参数',
`CREATE_TIME` datetime(3) NOT NULL COMMENT '创建时间',
`UPDATE_TIME` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`ID`),
KEY `IDX_BASE_ID` (`BASE_ID`),
KEY `IDX_PIPELINE_ID` (`PIPELINE_ID`)
);
四、核心功能实现
4.1 模板创建
V1 版本创建流程
// 文件: process/biz-process/.../service/template/TemplateFacadeService.kt
@Service
class TemplateFacadeService {
fun createTemplate(
projectId: String,
userId: String,
template: Model,
templateType: TemplateType = TemplateType.CUSTOMIZE
): String {
// 1. 权限校验
pipelineTemplatePermissionService.checkPipelineTemplatePermission(
userId = userId,
projectId = projectId,
permission = AuthPermission.CREATE
)
// 2. 模板名称校验
if (templateDao.countByName(dslContext, projectId, template.name) > 0) {
throw ErrorCodeException(errorCode = ProcessMessageCode.ERROR_TEMPLATE_NAME_IS_EXISTS)
}
// 3. 生成模板ID
val templateId = UUIDUtil.generate()
// 4. 保存模板
templateDao.create(
dslContext = dslContext,
templateId = templateId,
projectId = projectId,
templateName = template.name,
versionName = INIT_TEMPLATE_VERSION_NAME,
userId = userId,
template = JsonUtil.toJson(template),
type = templateType.name
)
// 5. 注册权限资源
pipelineTemplatePermissionService.createResource(
userId = userId,
projectId = projectId,
templateId = templateId,
templateName = template.name
)
return templateId
}
}
V2 版本创建流程
// 文件: process/biz-process/.../service/template/v2/PipelineTemplateFacadeService.kt
@Service
class PipelineTemplateFacadeService {
fun create(
userId: String,
projectId: String,
request: PipelineTemplateCustomCreateReq
): PipelineTemplateCreateResp {
// 1. 权限校验
pipelineTemplatePermissionService.checkPipelineTemplatePermission(
userId = userId,
projectId = projectId,
permission = AuthPermission.CREATE
)
// 2. 调用版本管理器
val result = pipelineTemplateVersionManager.deployTemplate(
userId = userId,
projectId = projectId,
request = request
)
// 3. 注册权限资源
pipelineTemplatePermissionService.createResource(
userId = userId,
projectId = projectId,
templateId = result.templateId,
templateName = request.name
)
return PipelineTemplateCreateResp(
templateId = result.templateId,
version = result.version
)
}
}
4.2 模板实例化
模板实例化是将模板转换为具体流水线的过程:
// 文件: process/biz-process/.../service/template/v2/PipelineTemplateInstanceService.kt
@Service
class PipelineTemplateInstanceService {
/**
* 批量实例化模板
*/
fun createTemplateInstances(
userId: String,
projectId: String,
templateId: String,
version: Long,
request: PipelineTemplateInstancesRequest
): List<PipelineTemplateInstanceItem> {
// 1. 校验创建流水线权限
pipelinePermissionService.validPipelinePermission(
userId = userId,
projectId = projectId,
permission = AuthPermission.CREATE
)
// 2. 获取模板详情
val templateDetail = pipelineTemplateFacadeService.getTemplateDetail(
userId = userId,
projectId = projectId,
templateId = templateId,
version = version
)
// 3. 遍历创建流水线实例
return request.instances.map { instance ->
createInstance(
userId = userId,
projectId = projectId,
templateDetail = templateDetail,
instance = instance
)
}
}
private fun createInstance(
userId: String,
projectId: String,
templateDetail: PipelineTemplateDetailsResponse,
instance: PipelineTemplateInstanceItem
): PipelineTemplateInstanceItem {
// 1. 合并模板参数和实例参数
val model = mergeTemplateAndInstanceParams(
templateModel = templateDetail.model,
instanceParams = instance.params
)
// 2. 创建流水线
val pipelineId = pipelineInfoFacadeService.create(
userId = userId,
projectId = projectId,
model = model,
channelCode = ChannelCode.BS
)
// 3. 建立模板-流水线关联
templatePipelineDao.create(
dslContext = dslContext,
pipelineId = pipelineId,
templateId = templateDetail.templateId,
version = templateDetail.version,
versionName = templateDetail.versionName,
userId = userId
)
return instance.copy(pipelineId = pipelineId)
}
}
4.3 版本管理
V2 版本采用策略模式实现版本管理:
// 文件: process/biz-process/.../service/template/v2/version/PipelineTemplateVersionManager.kt
@Service
class PipelineTemplateVersionManager(
private val versionReqConverters: List<PipelineTemplateVersionReqConverter>,
private val versionCreateHandlers: List<PipelineTemplateVersionCreateHandler>,
private val pipelineTemplateVersionValidator: PipelineTemplateVersionValidator,
private val versionDeleteHandler: PipelineTemplateVersionDeleteHandler
) {
/**
* 部署模板(创建/更新版本)
*/
fun deployTemplate(
userId: String,
projectId: String,
templateId: String? = null,
version: Long? = null,
request: PipelineTemplateVersionReq
): DeployTemplateResult {
// 1. 转换请求为上下文
val context = getConverter(request).convert(
userId = userId,
projectId = projectId,
templateId = templateId,
version = version,
request = request
)
// 2. 校验版本
pipelineTemplateVersionValidator.validate(context = context)
// 3. 调用对应处理器
return getHandler(context).handle(context = context)
}
/**
* 删除版本
*/
fun deleteVersion(
userId: String,
projectId: String,
templateId: String,
version: Long?,
versionName: String? = null
) {
val context = PipelineTemplateVersionDeleteContext(
userId = userId,
projectId = projectId,
templateId = templateId,
version = version,
versionAction = PipelineVersionAction.DELETE_VERSION
)
versionDeleteHandler.handle(context = context)
}
private fun getHandler(context: PipelineTemplateVersionCreateContext): PipelineTemplateVersionCreateHandler {
return versionCreateHandlers.find { it.support(context) }
?: throw IllegalArgumentException("Unsupported version event")
}
private fun getConverter(request: PipelineTemplateVersionReq): PipelineTemplateVersionReqConverter {
return versionReqConverters.find { it.support(request) }
?: throw IllegalArgumentException("Unsupported version request")
}
}
版本处理器类型
| 处理器 |
功能 |
触发场景 |
PipelineTemplateDraftSaveHandler |
保存草稿 |
编辑模板后保存草稿 |
PipelineTemplateDraftReleaseHandler |
发布草稿 |
将草稿发布为正式版本 |
PipelineTemplateReleaseCreateHandler |
创建发布版本 |
直接创建正式版本 |
PipelineTemplateBranchCreateHandler |
创建分支版本 |
PAC 场景下的分支版本 |
PipelineTemplateVersionDeleteHandler |
删除版本 |
删除指定版本 |
4.4 权限控制
// 文件: process/biz-process/.../permission/template/PipelineTemplatePermissionService.kt
interface PipelineTemplatePermissionService {
/**
* 校验模板权限
*/
fun checkPipelineTemplatePermission(
userId: String,
projectId: String,
templateId: String? = null,
permission: AuthPermission,
message: String? = null
)
/**
* 创建权限资源
*/
fun createResource(
userId: String,
projectId: String,
templateId: String,
templateName: String
)
/**
* 删除权限资源
*/
fun deleteResource(
projectId: String,
templateId: String
)
/**
* 获取有权限的模板列表
*/
fun filterTemplates(
userId: String,
projectId: String,
permission: AuthPermission,
templateIds: List<String>
): List<String>
/**
* 是否启用模板权限管理
*/
fun enableTemplatePermissionManage(projectId: String): Boolean
}
RBAC 权限实现
// 文件: process/biz-process/.../permission/template/RbacPipelineTemplatePermissionService.kt
@Service
class RbacPipelineTemplatePermissionService(
private val client: Client,
private val authPermissionApi: AuthPermissionApi,
private val authResourceApi: AuthResourceApi
) : AbstractPipelineTemplatePermissionService() {
override fun checkPipelineTemplatePermission(
userId: String,
projectId: String,
templateId: String?,
permission: AuthPermission,
message: String?
) {
// 调用权限中心校验
val hasPermission = authPermissionApi.validateUserResourcePermission(
userId = userId,
serviceCode = AuthServiceCode.PIPELINE,
resourceType = AuthResourceType.PIPELINE_TEMPLATE,
projectCode = projectId,
resourceCode = templateId ?: "*",
permission = permission
)
if (!hasPermission) {
throw PermissionForbiddenException(message ?: "无模板操作权限")
}
}
override fun createResource(
userId: String,
projectId: String,
templateId: String,
templateName: String
) {
authResourceApi.createResource(
userId = userId,
serviceCode = AuthServiceCode.PIPELINE,
resourceType = AuthResourceType.PIPELINE_TEMPLATE,
projectCode = projectId,
resourceCode = templateId,
resourceName = templateName
)
}
}
五、PAC (Pipeline as Code) 模板
5.1 PAC 概述
PAC(Pipeline as Code)是 BK-CI 的核心特性,允许用户通过 YAML 文件定义和管理流水线模板。模板 PAC 支持:
- YAML 定义模板:使用 YAML 格式定义模板配置
- Git 仓库托管:模板 YAML 文件存储在 Git 仓库中
- Webhook 自动同步:代码推送自动触发模板更新
- 分支版本管理:支持基于 Git 分支的版本管理
- 双向转换:Model ↔ YAML 双向转换
5.2 模板类型(PAC 视角)
// 文件: common/common-pipeline/.../template/PipelineTemplateType.kt
enum class PipelineTemplateType(val value: String) {
PIPELINE("pipeline"), // 完整流水线模板
STAGE("stage"), // Stage 级别模板
JOB("job"), // Job 级别模板
STEP("step"), // Step 级别模板
VARIABLE("variable") // 变量模板
}
5.3 PAC 核心服务
5.3.1 TemplatePACService(V1 PAC 服务)
// 文件: process/biz-process/.../service/template/TemplatePACService.kt
@Service
class TemplatePACService(
private val templateDao: TemplateDao,
private val transferYamlService: PipelineTransferYamlService,
private val templateCommonService: TemplateCommonService
) {
/**
* 预览模板(返回 Model + YAML + 高亮标记)
*/
fun previewTemplate(
userId: String,
projectId: String,
templateId: String,
highlightType: HighlightType?
): TemplatePreviewDetail {
// 1. 获取模板
val template = templateDao.getLatestTemplate(dslContext, projectId, templateId)
val model: Model = objectMapper.readValue(template.template)
// 2. 获取设置
val setting = pipelineRepositoryService.getSetting(projectId, templateId)
// 3. Model 转 YAML
val yaml = transferYamlService.transfer(
userId = userId,
projectId = projectId,
actionType = TransferActionType.FULL_MODEL2YAML,
data = TransferBody(PipelineModelAndSetting(model, setting))
).yamlWithVersion?.yamlStr
// 4. 生成高亮标记(用于 UI 展示)
val highlightMarkList = buildHighlightMarks(yaml, highlightType)
return TemplatePreviewDetail(
template = model,
templateYaml = yaml,
setting = setting,
hasPermission = hasPermission,
highlightMarkList = highlightMarkList
)
}
}
5.3.2 PTemplateYamlResourceService(YAML 资源服务)
// 文件: process/biz-process/.../yaml/resource/PTemplateYamlResourceService.kt
@Service
class PTemplateYamlResourceService(
private val pipelineTemplateFacadeService: PipelineTemplateFacadeService,
private val pipelineTemplateInfoService: PipelineTemplateInfoService
) : IPipelineYamlResourceService {
/**
* 通过 YAML 创建模板(Git Webhook 触发)
*/
override fun createYamlPipeline(
userId: String,
projectId: String,
yaml: String,
event: PipelineYamlFileEvent
): DeployPipelineResult {
with(event) {
val isDefaultBranch = ref == defaultBranch
val yamlFileName = GitActionCommon.getCiTemplateName(filePath)
// 调用 V2 服务创建 YAML 模板
val result = pipelineTemplateFacadeService.createYamlTemplate(
userId = userId,
projectId = projectId,
yaml = yaml,
yamlFileName = yamlFileName,
branchName = ref,
isDefaultBranch = isDefaultBranch,
description = commit!!.commitMsg,
yamlFileInfo = PipelineYamlFileInfo(repoHashId, filePath)
)
return DeployPipelineResult(
pipelineId = result.templateId,
pipelineName = result.templateName,
version = result.version.toInt(),
versionName = result.versionName
)
}
}
/**
* 通过 YAML 更新模板
*/
override fun updateYamlPipeline(
userId: String,
projectId: String,
pipelineId: String,
yaml: String,
event: PipelineYamlFileEvent
): DeployPipelineResult {
// 类似创建逻辑,调用 updateYamlTemplate
}
/**
* 分支失活(分支删除时调用)
*/
override fun updateBranchAction(
userId: String,
projectId: String,
pipelineId: String,
branchName: String,
branchVersionAction: BranchVersionAction
) {
pipelineTemplateFacadeService.inactiveBranch(
userId = userId,
projectId = projectId,
templateId = pipelineId,
branch = branchName
)
}
}
5.3.3 PipelineYamlResourceManager(统一管理器)
// 文件: process/biz-process/.../yaml/resource/PipelineYamlResourceManager.kt
@Service
class PipelineYamlResourceManager(
private val pipelineYamlResourceService: PipelineYamlResourceService,
@Lazy private val pTemplateYamlResourceService: PTemplateYamlResourceService
) {
/**
* 根据 isTemplate 标志选择对应的服务
*/
fun getService(isTemplate: Boolean): IPipelineYamlResourceService {
return if (isTemplate) {
pTemplateYamlResourceService // 模板 YAML 服务
} else {
pipelineYamlResourceService // 流水线 YAML 服务
}
}
fun createYamlPipeline(userId: String, projectId: String, yaml: String, event: PipelineYamlFileEvent) =
getService(event.isTemplate).createYamlPipeline(userId, projectId, yaml, event)
fun updateYamlPipeline(userId: String, projectId: String, pipelineId: String, yaml: String, event: PipelineYamlFileEvent) =
getService(event.isTemplate).updateYamlPipeline(userId, projectId, pipelineId, yaml, event)
}
5.4 YAML Webhook 请求处理
5.4.1 PipelineTemplateYamlWebhookReq(请求对象)
// 文件: process/api-process/.../pojo/template/v2/PipelineTemplateYamlWebhookReq.kt
@Schema(title = "模版yaml文件推送请求")
data class PipelineTemplateYamlWebhookReq(
@get:Schema(title = "模板YAML", required = true)
val yaml: String,
@get:Schema(title = "yaml文件名", required = true)
val yamlFileName: String,
@get:Schema(title = "分支名", required = true)
val branchName: String,
@get:Schema(title = "是否默认分支", required = true)
val isDefaultBranch: Boolean,
@get:Schema(title = "描述", required = true)
val description: String? = null,
@get:Schema(title = "yaml文件信息", required = true)
val yamlFileInfo: PipelineYamlFileInfo? = null
) : PipelineTemplateVersionReq // 继承版本请求接口
5.4.2 PipelineTemplateYamlWebhookReqConverter(请求转换器)
// 文件: process/biz-process/.../version/convert/PipelineTemplateYamlWebhookReqConverter.kt
@Service
class PipelineTemplateYamlWebhookReqConverter(
private val pipelineTemplateGenerator: PipelineTemplateGenerator,
private val pipelineTemplateInfoService: PipelineTemplateInfoService
) : PipelineTemplateVersionReqConverter {
override fun support(request: PipelineTemplateVersionReq) =
request is PipelineTemplateYamlWebhookReq
override fun convert(
userId: String,
projectId: String,
templateId: String?,
version: Long?,
request: PipelineTemplateVersionReq
): PipelineTemplateVersionCreateContext {
request as PipelineTemplateYamlWebhookReq
// 1. YAML 转 Model
val transferResult = pipelineTemplateGenerator.transfer(
userId = userId,
projectId = projectId,
storageType = PipelineStorageType.YAML,
yaml = request.yaml
)
// 2. 根据是否默认分支决定版本状态
val (status, versionAction) = if (request.isDefaultBranch) {
Pair(VersionStatus.RELEASED, PipelineVersionAction.CREATE_RELEASE)
} else {
Pair(VersionStatus.BRANCH, PipelineVersionAction.CREATE_BRANCH)
}
// 3. 模板名称优先级:setting > model > fileName
val templateName = transferResult.templateSetting.pipelineName
.takeIf { it.isNotBlank() }
?: (transferResult.templateModel as? Model)?.name?.ifBlank { request.yamlFileName }
?: request.yamlFileName
// 4. 构建上下文
return PipelineTemplateVersionCreateContext(
userId = userId,
projectId = projectId,
templateId = templateId ?: pipelineTemplateGenerator.generateTemplateId(),
versionAction = versionAction,
newTemplate = templateId == null,
enablePac = true, // 标记为 PAC 模板
yamlFileInfo = request.yamlFileInfo,
branchName = request.branchName
)
}
}
5.5 Model ↔ YAML 转换
5.5.1 PipelineTemplateGenerator(模板生成器)
// 文件: process/biz-process/.../service/template/v2/PipelineTemplateGenerator.kt
@Service
class PipelineTemplateGenerator(
private val transferService: PipelineTransferYamlService
) {
/**
* 双向转换:Model ↔ YAML
*/
fun transfer(
userId: String,
projectId: String,
storageType: PipelineStorageType,
templateType: PipelineTemplateType?,
templateModel: ITemplateModel?,
templateSetting: PipelineSetting?,
params: List<BuildFormProperty>?,
yaml: String?,
fallbackOnError: Boolean = false
): PTemplateModelTransferResult {
return if (storageType == PipelineStorageType.YAML) {
// YAML → Model
transferYamlToModel(userId, projectId, templateType, params, yaml)
} else {
// Model → YAML
transferModelToYamlWithFallback(
userId, projectId, templateType,
templateModel, templateSetting, params, fallbackOnError
)
}
}
/**
* YAML → Model 转换
*/
private fun transferYamlToModel(...): PTemplateModelTransferResult {
val transferResult = transferService.transfer(
userId = userId,
projectId = projectId,
actionType = TransferActionType.TEMPLATE_YAML2MODEL_PIPELINE,
data = TransferBody(oldYaml = yaml)
)
return PTemplateModelTransferResult(
templateType = templateType ?: PipelineTemplateType.PIPELINE,
templateModel = transferResult.templateModelAndSetting?.templateModel,
templateSetting = transferResult.templateModelAndSetting?.setting,
yamlWithVersion = transferResult.yamlWithVersion
)
}
/**
* Model → YAML 转换(带异常兜底)
*/
private fun transferModelToYamlWithFallback(...): PTemplateModelTransferResult {
val actionType = getTransferActionType(templateType)
// TransferActionType 根据模板类型选择:
// PIPELINE → TEMPLATE_MODEL2YAML_PIPELINE
// STAGE → TEMPLATE_MODEL2YAML_STAGE
// JOB → TEMPLATE_MODEL2YAML_JOB
// STEP → TEMPLATE_MODEL2YAML_STEP
return try {
val result = transferService.transfer(
actionType = actionType,
data = TransferBody(
templateModelAndSetting = TemplateModelAndSetting(templateModel, templateSetting)
)
)
PTemplateModelTransferResult(yamlWithVersion = result.yamlWithVersion, ...)
} catch (ex: Exception) {
if (fallbackOnError) {
// 兜底:返回原始 Model,YAML 为空
PTemplateModelTransferResult(yamlWithVersion = null, ...)
} else {
throw ex
}
}
}
}
5.5.2 TransferActionType(转换动作类型)
// 转换动作类型枚举
enum class TransferActionType {
// 模板 YAML → Model
TEMPLATE_YAML2MODEL_PIPELINE,
// 模板 Model → YAML(按模板类型)
TEMPLATE_MODEL2YAML_PIPELINE,
TEMPLATE_MODEL2YAML_STAGE,
TEMPLATE_MODEL2YAML_JOB,
TEMPLATE_MODEL2YAML_STEP,
// 完整转换(包含设置)
FULL_MODEL2YAML,
FULL_YAML2MODEL
}
5.6 PAC 版本状态
// 版本状态枚举
enum class VersionStatus {
COMMITTING, // 草稿状态
RELEASED, // 已发布(默认分支)
BRANCH // 分支版本(非默认分支)
}
| 状态 |
触发场景 |
说明 |
RELEASED |
推送到默认分支 |
正式发布版本 |
BRANCH |
推送到非默认分支 |
分支版本,可用于测试 |
COMMITTING |
UI 保存草稿 |
草稿状态,未发布 |
5.7 PAC 版本生成
// 文件: PipelineTemplateGenerator.kt
/**
* 生成分支版本
*/
fun generateBranchVersion(
projectId: String,
templateId: String,
branchName: String
): PTemplateResourceOnlyVersion {
val latestResource = pipelineTemplateResourceService.getLatestVersionResource(projectId, templateId)
// 如果已存在同名分支版本,基于分支版本创建
val branchResource = pipelineTemplateResourceService.getLatestBranchResource(
projectId, templateId, branchName
)
return PTemplateResourceOnlyVersion(
version = generateTemplateVersion(),
number = latestResource.number + 1,
versionName = branchName, // 分支版本名 = 分支名
baseVersion = branchResource?.version ?: latestResource.version
)
}
/**
* 草稿发布时的 PAC 版本生成
*/
fun generateDraftReleaseVersionWithPac(
projectId: String,
templateId: String,
draftResource: PipelineTemplateResource,
repoHashId: String,
targetAction: CodeTargetAction?,
targetBranch: String?
): Pair<VersionStatus, PTemplateResourceOnlyVersion> {
return when (targetAction) {
// 直接提交到主分支 → 发布版本
CodeTargetAction.COMMIT_TO_MASTER -> {
Pair(VersionStatus.RELEASED, generateReleaseVersion(...))
}
// 提交到源分支 → 分支版本
CodeTargetAction.COMMIT_TO_SOURCE_BRANCH -> {
Pair(VersionStatus.BRANCH, ...)
}
// 新建分支并提交 → 分支版本
CodeTargetAction.CHECKOUT_BRANCH_AND_REQUEST_MERGE -> {
val versionName = "bk-ci-template-$templateId-${draftResource.number}"
Pair(VersionStatus.BRANCH, ...)
}
// 提交到指定分支
CodeTargetAction.COMMIT_TO_BRANCH -> {
// 如果是默认分支 → 发布版本
// 否则 → 分支版本
}
}
}
5.8 PAC 目录结构
src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/
├── yaml/
│ ├── resource/
│ │ ├── IPipelineYamlResourceService.kt # YAML 资源服务接口
│ │ ├── PipelineYamlResourceService.kt # 流水线 YAML 服务
│ │ ├── PTemplateYamlResourceService.kt # 模板 YAML 服务
│ │ └── PipelineYamlResourceManager.kt # 统一管理器
│ ├── mq/
│ │ └── PipelineYamlFileEvent.kt # YAML 文件事件
│ ├── PipelineYamlFileManager.kt # YAML 文件管理
│ ├── PipelineYamlFacadeService.kt # YAML 门面服务
│ └── PipelineYamlSyncService.kt # YAML 同步服务
├── service/template/
│ ├── TemplatePACService.kt # V1 PAC 服务
│ └── v2/
│ ├── PipelineTemplateGenerator.kt # 模板生成器(含转换)
│ └── version/convert/
│ └── PipelineTemplateYamlWebhookReqConverter.kt # Webhook 转换器
└── common/common-pipeline-yaml/ # YAML 解析公共库
└── src/main/kotlin/.../yaml/
├── v2/parsers/template/
│ ├── TemplateYamlMapper.kt # YAML 映射
│ └── TemplateYamlUtil.kt # YAML 工具
└── v3/parsers/template/
├── TemplateYamlMapper.kt
└── TemplateYamlUtil.kt
5.9 PAC 完整流程
┌─────────────────────────────────────────────────────────────────────────────┐
│ PAC 模板创建/更新流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────────┐ ┌─────────────────────────┐ │
│ │ Git Push │───▶│ Webhook Event │───▶│ PipelineYamlFileEvent │ │
│ │ (YAML文件) │ │ (代码仓库触发) │ │ (isTemplate=true) │ │
│ └─────────────┘ └──────────────────┘ └───────────┬─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ PipelineYamlResourceManager │ │
│ │ (根据 isTemplate 路由) │ │
│ └───────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ PTemplateYamlResourceService │ │
│ │ (模板 YAML 资源服务) │ │
│ └───────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ PipelineTemplateFacadeService.createYamlTemplate() │ │
│ │ 构建 PipelineTemplateYamlWebhookReq │ │
│ └───────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ PipelineTemplateVersionManager │ │
│ │ deployTemplate() │ │
│ └───────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────┼────────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌────────────────────┐ ┌───────────────────┐ │
│ │ Converter │───▶│ Validator │───▶│ Handler │ │
│ │ (YAML→Model)│ │ (校验模板) │ │ (创建/更新版本) │ │
│ └─────────────┘ └────────────────────┘ └─────────┬─────────┘ │
│ │ │
│ ┌───────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 默认分支? │ │
│ │ ├── YES → VersionStatus.RELEASED → 正式版本 │ │
│ │ └── NO → VersionStatus.BRANCH → 分支版本 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
5.10 PAC 最佳实践
5.10.1 模板 YAML 文件命名
- 文件路径:
.ci/templates/xxx.yml 或 .ci/templates/xxx.yaml
- 模板名称默认从 YAML 中的
name 字段获取,若无则使用文件名
5.10.2 分支策略
| 分支类型 |
版本状态 |
使用场景 |
| 默认分支(main/master) |
RELEASED |
正式发布,可被实例化 |
| 特性分支 |
BRANCH |
开发测试,不影响正式版本 |
| PR 分支 |
BRANCH |
代码审查,合并后自动发布 |
5.10.3 enablePac 标志
// 模板信息中的 PAC 标志
data class PipelineTemplateInfoV2(
val id: String,
val projectId: String,
val name: String,
val enablePac: Boolean = false, // 是否启用 PAC
// ...
)
enablePac = true:模板由 YAML 文件管理,UI 编辑会同步到代码仓库
enablePac = false:传统模板,仅在 BK-CI 内管理
六、研发商店集成
6.1 Store 模块模板服务
src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/template/
├── service/
│ ├── MarketTemplateService.kt # 商店模板服务接口
│ ├── MarketTemplateServiceImpl.kt # 商店模板服务实现
│ ├── TemplateReleaseService.kt # 模板发布服务接口
│ ├── TemplateReleaseServiceImpl.kt # 模板发布服务实现
│ ├── OpTemplateService.kt # 运营模板服务接口
│ └── OpTemplateServiceImpl.kt # 运营模板服务实现
└── dao/
├── MarketTemplateDao.kt # 商店模板 DAO
├── TemplateCategoryRelDao.kt # 模板分类关联 DAO
└── TemplateLabelRelDao.kt # 模板标签关联 DAO
6.2 商店模板数据库表
-- Store 模块的模板表
CREATE TABLE IF NOT EXISTS `T_TEMPLATE` (
`ID` varchar(32) NOT NULL COMMENT '主键ID',
`TEMPLATE_NAME` varchar(200) NOT NULL COMMENT '模板名称',
`TEMPLATE_CODE` varchar(64) NOT NULL COMMENT '模板代码',
`CLASSIFY_ID` varchar(32) NOT NULL COMMENT '分类ID',
`VERSION` varchar(20) NOT NULL COMMENT '版本号',
`TEMPLATE_TYPE` tinyint(4) NOT NULL DEFAULT '1' COMMENT '模板类型',
`TEMPLATE_STATUS` tinyint(4) NOT NULL COMMENT '模板状态',
`TEMPLATE_STATUS_MSG` varchar(1024) DEFAULT NULL COMMENT '状态信息',
`LOGO_URL` varchar(256) DEFAULT NULL COMMENT 'Logo地址',
`SUMMARY` varchar(256) DEFAULT NULL COMMENT '简介',
`DESCRIPTION` text COMMENT '描述',
`PUBLISHER` varchar(50) NOT NULL COMMENT '发布者',
`PUB_DESCRIPTION` text COMMENT '发布描述',
`PUBLIC_FLAG` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否公开',
`LATEST_FLAG` bit(1) NOT NULL COMMENT '是否最新',
`CREATOR` varchar(50) NOT NULL COMMENT '创建者',
`MODIFIER` varchar(50) NOT NULL COMMENT '修改者',
`CREATE_TIME` datetime NOT NULL COMMENT '创建时间',
`UPDATE_TIME` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`ID`),
UNIQUE KEY `UNI_TEMPLATE_CODE_VERSION` (`TEMPLATE_CODE`, `VERSION`)
);
6.3 模板安装流程
// 从商店安装模板到项目
fun installTemplateFromStore(
userId: String,
projectId: String,
templateCode: String,
version: String
): String {
// 1. 获取商店模板信息
val storeTemplate = marketTemplateService.getTemplateByCode(templateCode, version)
// 2. 获取模板模型
val templateModel = storeTemplate.templateModel
// 3. 创建项目模板(类型为 CONSTRAINT)
val templateId = templateFacadeService.createTemplate(
projectId = projectId,
userId = userId,
template = templateModel,
templateType = TemplateType.CONSTRAINT
)
// 4. 记录安装历史
templateVersionInstallHistoryDao.create(
projectId = projectId,
templateId = templateId,
templateCode = templateCode,
version = version,
userId = userId
)
return templateId
}
七、事件驱动机制
7.1 模板相关事件
// 文件: process/biz-base/.../engine/pojo/event/
// 模板实例化事件
data class PipelineTemplateInstanceEvent(
val source: String,
val projectId: String,
val templateId: String,
val version: Long,
val instanceBaseId: String,
val userId: String
) : IEvent
// 模板迁移事件
data class PipelineTemplateMigrateEvent(
val source: String,
val projectId: String,
val templateId: String,
val userId: String
) : IEvent
// 模板触发器升级事件
data class PipelineTemplateTriggerUpgradesEvent(
val source: String,
val projectId: String,
val templateId: String,
val version: Long,
val userId: String
) : IEvent
7.2 事件监听器
// 文件: process/biz-process/.../service/template/v2/PipelineTemplateInstanceListener.kt
@Service
class PipelineTemplateInstanceListener(
private val pipelineTemplateInstanceService: PipelineTemplateInstanceService
) {
@StreamListener(PipelineTemplateInstanceEvent.TOPIC)
fun onTemplateInstance(event: PipelineTemplateInstanceEvent) {
// 处理异步批量实例化
pipelineTemplateInstanceService.processAsyncInstance(
projectId = event.projectId,
templateId = event.templateId,
version = event.version,
instanceBaseId = event.instanceBaseId,
userId = event.userId
)
}
}
八、分布式锁
8.1 模板相关锁
// 文件: process/biz-base/.../engine/control/lock/
// 实例计数锁 - 防止并发实例化时计数错误
class PipelineTemplateInstanceCountLock(
private val redisOperation: RedisOperation,
private val templateId: String
) : BaseLock(redisOperation, "template:instance:count:$templateId")
// 触发器升级锁 - 防止并发升级触发器
class PipelineTemplateTriggerUpgradesLock(
private val redisOperation: RedisOperation,
private val templateId: String
) : BaseLock(redisOperation, "template:trigger:upgrade:$templateId")
// 文件: process/biz-process/.../service/template/v2/
// V2 实例化锁
class PipelineTemplateInstanceLock(
private val redisOperation: RedisOperation,
private val templateId: String,
private val pipelineId: String
) : BaseLock(redisOperation, "template:v2:instance:$templateId:$pipelineId")
// V2 模型锁
class PipelineTemplateModelLock(
private val redisOperation: RedisOperation,
private val templateId: String
) : BaseLock(redisOperation, "template:v2:model:$templateId")
九、OpenAPI 接口
9.1 API 网关接口
src/backend/ci/core/openapi/api-openapi/src/main/kotlin/com/tencent/devops/openapi/api/apigw/
├── v3/
│ ├── ApigwTemplateResourceV3.kt # V3 模板接口
│ ├── ApigwTemplateInstanceResourceV3.kt # V3 实例化接口
│ └── ApigwMarketTemplateResourceV3.kt # V3 商店模板接口
└── v4/
├── ApigwTemplateResourceV4.kt # V4 模板接口
├── ApigwTemplateInstanceResourceV4.kt # V4 实例化接口
└── ApigwMarketTemplateResourceV4.kt # V4 商店模板接口
9.2 主要 API 端点
| 方法 |
路径 |
说明 |
| POST |
/v4/projects/{projectId}/templates |
创建模板 |
| GET |
/v4/projects/{projectId}/templates |
获取模板列表 |
| GET |
/v4/projects/{projectId}/templates/{templateId} |
获取模板详情 |
| PUT |
/v4/projects/{projectId}/templates/{templateId} |
更新模板 |
| DELETE |
/v4/projects/{projectId}/templates/{templateId} |
删除模板 |
| POST |
/v4/projects/{projectId}/templates/{templateId}/instances |
实例化模板 |
| GET |
/v4/projects/{projectId}/templates/{templateId}/instances |
获取实例列表 |
| GET |
/v4/projects/{projectId}/templates/{templateId}/versions |
获取版本列表 |
十、最佳实践
10.1 新增模板功能
- API 层:在
api/template/v2/ 下定义接口
- POJO 层:在
pojo/template/v2/ 下定义请求/响应对象
- Service 层:在
service/template/v2/ 下实现业务逻辑
- DAO 层:在
dao/template/ 下实现数据访问
- 权限控制:调用
PipelineTemplatePermissionService 进行权限校验
10.2 版本管理扩展
如需新增版本操作类型:
- 在
PipelineVersionAction 枚举中添加新操作
- 实现
PipelineTemplateVersionReqConverter 转换器
- 实现
PipelineTemplateVersionCreateHandler 处理器
- 可选:实现
PTemplateVersionPostProcessor 后处理器
10.3 商店集成扩展
- 在 Store 模块的
template/service/ 下实现服务
- 调用 Process 模块的模板服务进行模板操作
- 维护商店特有的元数据(分类、标签、评论等)
十一、常见问题
Q1: V1 和 V2 版本如何选择?
- 新功能开发优先使用 V2 版本
- V1 版本用于兼容老数据和简单场景
- V2 版本支持草稿、PAC、完善的版本管理
Q2: 模板实例化失败如何排查?
- 检查模板是否存在且版本正确
- 检查用户是否有创建流水线权限
- 检查模板参数是否完整
- 查看
T_TEMPLATE_INSTANCE_ITEM 表中的错误信息
Q3: 如何实现模板的批量更新?
使用异步实例化接口:
- 调用
createAsyncTemplateInstances 创建异步任务
- 系统通过 MQ 事件异步处理每个实例
- 通过
getTemplateInstanceStatus 查询进度
Q4: 模板权限如何配置?
- 项目级别开关:
enableTemplatePermissionManage
- 权限类型:CREATE、EDIT、DELETE、LIST
- 与蓝鲸权限中心集成,支持 RBAC 模型
Q5: PAC 模板和普通模板有什么区别?
| 特性 |
PAC 模板 |
普通模板 |
| 存储方式 |
Git 仓库 YAML 文件 |
BK-CI 数据库 |
| 编辑方式 |
代码编辑器 / IDE |
BK-CI UI |
| 版本管理 |
Git 分支 |
BK-CI 版本号 |
| 同步机制 |
Webhook 自动同步 |
手动保存 |
| 协作方式 |
Git 工作流(PR/MR) |
BK-CI 权限控制 |
| 回滚方式 |
Git revert |
BK-CI 版本回滚 |
Q6: PAC 模板的 YAML 转换失败怎么办?
- 检查 YAML 语法是否正确
- 确认使用的是支持的 YAML 版本(v2/v3)
- 查看
PipelineTemplateGenerator.transfer() 的异常日志
- 使用
fallbackOnError=true 可以在转换失败时返回原始 Model
Q7: 如何启用模板的 PAC 功能?
- 在代码仓库中创建
.ci/templates/xxx.yml 文件
- 配置 Webhook 触发器
- 推送代码后自动创建/更新模板
- 模板的
enablePac 标志会自动设为 true
Q8: 分支版本和正式版本的关系?
- 推送到默认分支(main/master)→ 创建
RELEASED 正式版本
- 推送到其他分支 → 创建
BRANCH 分支版本
- 分支版本可用于测试,不影响正式版本
- 分支合并到默认分支后,自动发布为正式版本
十二、相关 Skill
| Skill |
说明 |
22-yaml-pipeline-transfer |
YAML 流水线转换,理解 Model ↔ YAML 转换机制 |
28-pipeline-model-architecture |
流水线模型架构,理解模板的模型结构 |
29-process-module-architecture |
Process 模块架构,理解模板所在模块 |
30-auth-module-architecture |
权限模块架构,理解模板权限控制 |
33-store-module-architecture |
研发商店架构,理解模板商店集成 |
08-event-driven-architecture |
事件驱动架构,理解异步实例化机制 |
10-distributed-lock |
分布式锁,理解模板并发控制 |