Claude Code Plugins

Community-maintained marketplace

Feedback

46-pipeline-template-module

@TencentBlueKing/bk-ci
2.5k
0

流水线模板模块架构指南,涵盖模板创建、版本管理、实例化、权限控制、研发商店集成。当用户需要开发模板功能、实现模板复用、管理模板版本或进行批量实例化时使用。

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name 46-pipeline-template-module
description 流水线模板模块架构指南,涵盖模板创建、版本管理、实例化、权限控制、研发商店集成。当用户需要开发模板功能、实现模板复用、管理模板版本或进行批量实例化时使用。

流水线模板模块架构指南

概述

流水线模板(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 新增模板功能

  1. API 层:在 api/template/v2/ 下定义接口
  2. POJO 层:在 pojo/template/v2/ 下定义请求/响应对象
  3. Service 层:在 service/template/v2/ 下实现业务逻辑
  4. DAO 层:在 dao/template/ 下实现数据访问
  5. 权限控制:调用 PipelineTemplatePermissionService 进行权限校验

10.2 版本管理扩展

如需新增版本操作类型:

  1. PipelineVersionAction 枚举中添加新操作
  2. 实现 PipelineTemplateVersionReqConverter 转换器
  3. 实现 PipelineTemplateVersionCreateHandler 处理器
  4. 可选:实现 PTemplateVersionPostProcessor 后处理器

10.3 商店集成扩展

  1. 在 Store 模块的 template/service/ 下实现服务
  2. 调用 Process 模块的模板服务进行模板操作
  3. 维护商店特有的元数据(分类、标签、评论等)

十一、常见问题

Q1: V1 和 V2 版本如何选择?

  • 新功能开发优先使用 V2 版本
  • V1 版本用于兼容老数据和简单场景
  • V2 版本支持草稿、PAC、完善的版本管理

Q2: 模板实例化失败如何排查?

  1. 检查模板是否存在且版本正确
  2. 检查用户是否有创建流水线权限
  3. 检查模板参数是否完整
  4. 查看 T_TEMPLATE_INSTANCE_ITEM 表中的错误信息

Q3: 如何实现模板的批量更新?

使用异步实例化接口:

  1. 调用 createAsyncTemplateInstances 创建异步任务
  2. 系统通过 MQ 事件异步处理每个实例
  3. 通过 getTemplateInstanceStatus 查询进度

Q4: 模板权限如何配置?

  1. 项目级别开关:enableTemplatePermissionManage
  2. 权限类型:CREATE、EDIT、DELETE、LIST
  3. 与蓝鲸权限中心集成,支持 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 转换失败怎么办?

  1. 检查 YAML 语法是否正确
  2. 确认使用的是支持的 YAML 版本(v2/v3)
  3. 查看 PipelineTemplateGenerator.transfer() 的异常日志
  4. 使用 fallbackOnError=true 可以在转换失败时返回原始 Model

Q7: 如何启用模板的 PAC 功能?

  1. 在代码仓库中创建 .ci/templates/xxx.yml 文件
  2. 配置 Webhook 触发器
  3. 推送代码后自动创建/更新模板
  4. 模板的 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 分布式锁,理解模板并发控制