pipeline-plugin-development

模块定位: 本指南详细介绍蓝盾(BK-CI)流水线插件的开发规范、配置方法、多语言实现示例、发布流程和调试技巧,帮助开发者快速上手插件开发。

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "pipeline-plugin-development" with this command: npx skills add tencentblueking/bk-ci/tencentblueking-bk-ci-pipeline-plugin-development

流水线插件开发完整指南

模块定位: 本指南详细介绍蓝盾(BK-CI)流水线插件的开发规范、配置方法、多语言实现示例、发布流程和调试技巧,帮助开发者快速上手插件开发。

一、插件开发概述

1.1 什么是流水线插件

流水线插件(Atom)是蓝盾流水线中的最小执行单元,用于完成特定的构建任务,如代码拉取、编译、测试、部署等。

1.2 支持的开发语言

语言 推荐度 SDK

Java ⭐⭐⭐⭐⭐ java-atom-sdk

Python ⭐⭐⭐⭐ python-atom-sdk

NodeJS ⭐⭐⭐ @tencent/nodejs_atom_sdk

Golang ⭐⭐⭐ golang-atom-sdk

1.3 插件开发流程

┌─────────────────────────────────────────────────────────────────────────┐ │ 插件开发完整流程 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ 1. 初始化插件 2. 开发插件 3. 发布插件 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 登录工作台 │ ──► │ 编写 task.json│ ──► │ 提交构建 │ │ │ │ 新增插件 │ │ 开发业务逻辑 │ │ 测试验证 │ │ │ │ 克隆代码库 │ │ 本地调试 │ │ 审核发布 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘

二、task.json 配置规范

2.1 整体结构

{ "atomCode": "myAtom", // 插件唯一标识(必填) "defaultLocaleLanguage": "zh_CN", // 默认语言(非必填) "execution": { // 执行配置(必填) "language": "python", "demands": [], "target": "demo" }, "inputGroups": [], // 输入字段分组(非必填) "input": {}, // 输入字段定义(必填) "output": {}, // 输出字段定义(非必填) "config": {} // 插件控制特性(非必填) }

注意: task.json 内容长度最大为 64KB

2.2 execution 执行配置

属性名 说明 格式 必填

language

开发语言 字符串 是

target

执行入口命令 字符串 是

demands

执行前置依赖命令 数组 否

runtimeVersion

运行时版本 字符串 否

finishKillFlag

执行完成后是否杀进程 布尔 否

os

操作系统相关配置 数组 否

2.2.1 runtimeVersion 配置值

语言 配置值 备注

python python2

默认

python python3

推荐

nodejs 10.* ~ 18.*

默认 10.*

java 8

默认

java 17

新版本

2.2.2 os 跨平台配置示例

{ "execution": { "language": "golang", "os": [ { "osName": "linux", "osArch": "amd64", "target": "./app", "demands": [], "defaultFlag": true }, { "osName": "windows", "osArch": "386", "target": "./app.exe", "demands": [], "defaultFlag": false }, { "osName": "darwin", "osArch": "arm64", "target": "./app", "demands": [], "defaultFlag": false } ] } }

2.3 input 输入字段配置

2.3.1 支持的 UI 组件类型

组件 type 组件名称 获取到的值格式

vuex-input

单行文本框 字符串

vuex-textarea

多行文本框 字符串

atom-ace-editor

代码编辑框 字符串

selector

下拉框(只选不输入) 单选: 字符串; 多选: ["str1", "str2"]

select-input

可输入下拉框 同上

devops-select

可输入下拉框(仅变量) 同上

atom-checkbox-list

复选框列表 ["id1", "id2"]

atom-checkbox

复选框(布尔) "true" 或 "false"

enum-input

单选 Radio 字符串

time-picker

日期选择器 字符串

staff-input

人名选择器(项目成员) 字符串

company-staff-input

人名选择器(公司成员) 字符串

tips

提示信息 无

parameter

不定参数列表 JSON 字符串

dynamic-parameter

动态参数列表 JSON 字符串

dynamic-parameter-simple

动态参数(简易版) JSON 字符串

2.3.2 输入字段公共属性

属性名 说明 格式 必填

label

中文名 字符串 是

type

组件类型 字符串 是

default

默认值 根据组件类型 否

placeholder

占位提示 字符串 否

groupName

所属分组 字符串 否

desc

字段说明 字符串 否

required

是否必填 布尔 否

disabled

是否禁用 布尔 否

hidden

是否隐藏 布尔 否

isSensitive

是否敏感信息 布尔 否

rely

条件显示/隐藏 对象 否

rule

值校验规则 对象 否

2.3.3 完整输入字段示例

{ "input": { "repositoryUrl": { "label": "代码库地址", "type": "vuex-input", "placeholder": "请输入 Git 仓库地址", "desc": "支持 HTTP/HTTPS/SSH 协议", "required": true, "rule": { "regex": "^(https?|git)://" } }, "branch": { "label": "分支", "type": "select-input", "default": "master", "optionsConf": { "searchable": true, "multiple": false, "url": "/repository/api/user/repositories/{projectId}/branches", "paramId": "name", "paramName": "name" } }, "enableCache": { "label": "", "type": "atom-checkbox", "text": "启用缓存", "default": true }, "buildType": { "label": "构建类型", "type": "enum-input", "default": "release", "list": [ {"label": "Debug", "value": "debug"}, {"label": "Release", "value": "release"} ] }, "advancedOptions": { "label": "高级选项", "type": "vuex-input", "rely": { "operation": "AND", "expression": [ {"key": "enableCache", "value": true} ] } } } }

2.4 output 输出字段配置

{ "output": { "buildResult": { "type": "string", "description": "构建结果", "isSensitive": false }, "artifactPath": { "type": "artifact", "description": "构建产物路径" }, "reportHtml": { "type": "report", "description": "测试报告" } } }

输出类型说明:

类型 说明 限制

string

字符串变量 长度不超过 4KB

artifact

构件文件 自动归档到仓库

report

报告文件 支持 HTML 渲染

2.5 config 插件控制特性

{ "config": { "canPauseBeforeRun": false, "defaultTimeout": 60, "defaultFailPolicy": "MANUALLY_CONTINUE", "defaultRetryPolicy": ["AUTO_RETRY"], "retryTimes": 3 } }

2.6 内置变量

变量名 说明

{projectId}

项目英文 ID

{pipelineId}

流水线 ID

{buildId}

构建 ID

三、多语言开发示例

3.1 Python 插件开发

3.1.1 目录结构

my-python-atom/ ├── task.json ├── setup.py ├── requirements.txt └── demo/ ├── init.py └── command_line.py

3.1.2 task.json

{ "atomCode": "myPythonAtom", "execution": { "language": "python", "demands": [], "target": "demo" }, "input": { "inputDemo": { "label": "输入示例", "type": "vuex-input", "required": true } }, "output": { "outputDemo": { "type": "string", "description": "输出示例" } } }

3.1.3 setup.py

from setuptools import setup, find_packages

setup( name="myPythonAtom", packages=find_packages(), install_requires=["python-atom-sdk"], entry_points={ "console_scripts": [ "demo = demo.command_line:main" ] } )

3.1.4 command_line.py

-- coding: utf-8 --

import python_atom_sdk as sdk

def main(): sdk.log.info("插件开始执行")

# 获取输入参数
input_params = sdk.get_input()
input_demo = input_params.get("inputDemo", "")
sdk.log.info(f"输入参数: {input_demo}")

# 业务逻辑处理
result = f"处理结果: {input_demo}"

# 设置输出
output_data = {
    "status": sdk.status.SUCCESS,
    "message": "执行成功",
    "errorCode": 0,
    "type": sdk.output_template_type.DEFAULT,
    "data": {
        "outputDemo": {
            "type": sdk.output_field_type.STRING,
            "value": result
        }
    }
}
sdk.set_output(output_data)

sdk.log.info("插件执行完成")
exit(0)

if name == "main": main()

3.2 Java 插件开发

3.2.1 目录结构

my-java-atom/ ├── task.json ├── pom.xml ├── settings.xml └── src/main/ ├── java/com/example/atom/ │ ├── AtomParam.java │ └── DemoAtom.java └── resources/META-INF/services/ └── com.tencent.bk.devops.atom.spi.TaskAtom

3.2.2 task.json

{ "atomCode": "myJavaAtom", "defaultLocaleLanguage": "zh_CN", "execution": { "language": "java", "minimumVersion": "1.8", "demands": [], "target": "java -jar myJavaAtom-jar-with-dependencies.jar" }, "input": { "desc": { "label": "描述", "type": "vuex-input", "placeholder": "请输入描述信息", "required": true } }, "output": { "testResult": { "type": "string", "description": "执行结果" } } }

3.2.3 pom.xml

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"> <modelVersion>4.0.0</modelVersion>

&#x3C;parent>
    &#x3C;groupId>com.tencent.bk.devops.atom&#x3C;/groupId>
    &#x3C;artifactId>sdk-dependencies&#x3C;/artifactId>
    &#x3C;version>1.0.0&#x3C;/version>
&#x3C;/parent>

&#x3C;artifactId>myJavaAtom&#x3C;/artifactId>
&#x3C;version>1.0.0&#x3C;/version>

&#x3C;properties>
    &#x3C;sdk.version>1.1.58&#x3C;/sdk.version>
    &#x3C;java.version>1.8&#x3C;/java.version>
&#x3C;/properties>

&#x3C;dependencies>
    &#x3C;dependency>
        &#x3C;groupId>com.tencent.bk.devops.atom&#x3C;/groupId>
        &#x3C;artifactId>java-atom-sdk&#x3C;/artifactId>
        &#x3C;version>${sdk.version}&#x3C;/version>
    &#x3C;/dependency>
&#x3C;/dependencies>

&#x3C;build>
    &#x3C;finalName>${project.name}&#x3C;/finalName>
    &#x3C;plugins>
        &#x3C;plugin>
            &#x3C;groupId>org.apache.maven.plugins&#x3C;/groupId>
            &#x3C;artifactId>maven-assembly-plugin&#x3C;/artifactId>
        &#x3C;/plugin>
    &#x3C;/plugins>
&#x3C;/build>

</project>

3.2.4 AtomParam.java

package com.example.atom;

import com.tencent.bk.devops.atom.pojo.AtomBaseParam; import lombok.Data; import lombok.EqualsAndHashCode;

@Data @EqualsAndHashCode(callSuper = true) public class AtomParam extends AtomBaseParam { private String desc; }

3.2.5 DemoAtom.java

package com.example.atom;

import com.tencent.bk.devops.atom.AtomContext; import com.tencent.bk.devops.atom.common.Status; import com.tencent.bk.devops.atom.pojo.AtomResult; import com.tencent.bk.devops.atom.pojo.StringData; import com.tencent.bk.devops.atom.spi.AtomService; import com.tencent.bk.devops.atom.spi.TaskAtom; import org.slf4j.Logger; import org.slf4j.LoggerFactory;

@AtomService(paramClass = AtomParam.class) public class DemoAtom implements TaskAtom<AtomParam> {

private static final Logger logger = LoggerFactory.getLogger(DemoAtom.class);

@Override
public void execute(AtomContext&#x3C;AtomParam> atomContext) {
    // 获取参数
    AtomParam param = atomContext.getParam();
    AtomResult result = atomContext.getResult();
    
    logger.info("输入参数: {}", param.getDesc());
    
    // 参数校验
    if (param.getDesc() == null || param.getDesc().isEmpty()) {
        result.setStatus(Status.failure);
        result.setMessage("描述不能为空");
        return;
    }
    
    // 业务逻辑
    logger.groupStart("执行任务");
    String output = "处理结果: " + param.getDesc();
    logger.info(output);
    logger.groupEnd("执行任务");
    
    // 设置输出
    result.setStatus(Status.success);
    result.getData().put("testResult", new StringData(output));
}

}

3.2.6 SPI 配置文件

src/main/resources/META-INF/services/com.tencent.bk.devops.atom.spi.TaskAtom :

com.example.atom.DemoAtom

3.3 NodeJS 插件开发

3.3.1 目录结构

my-nodejs-atom/ ├── task.json ├── package.json ├── rollup.config.js ├── index.js └── .gitignore

3.3.2 task.json

{ "atomCode": "myNodejsAtom", "execution": { "language": "nodejs", "demands": [], "target": "node dist/bundle.js" }, "input": { "inputDemo": { "label": "输入示例", "type": "vuex-input", "required": true } }, "output": { "outputDemo": { "type": "string", "description": "输出示例" } } }

3.3.3 package.json

{ "name": "myNodejsAtom", "version": "1.0.0", "main": "./dist/bundle.js", "dependencies": { "@tencent/nodejs_atom_sdk": "^1.1.12" }, "devDependencies": { "@babel/core": "^7.4.5", "@babel/preset-env": "^7.4.5", "rollup": "^1.16.2", "rollup-plugin-babel": "^4.3.3" } }

3.3.4 rollup.config.js

import babel from 'rollup-plugin-babel'

export default { input: 'index.js', output: { file: 'dist/bundle.js', format: 'cjs' }, plugins: [babel()] }

3.3.5 index.js

import { getInputParams, setOutput, BK_ATOM_STATUS, BK_OUTPUT_TEMPLATE_TYPE } from '@tencent/nodejs_atom_sdk'

const params = getInputParams() console.log('输入参数:', params)

const inputDemo = params.inputDemo || '' const result = 处理结果: ${inputDemo}

setOutput({ "type": BK_OUTPUT_TEMPLATE_TYPE.DEFAULT, "status": BK_ATOM_STATUS.SUCCESS, "data": { "outputDemo": { "type": "string", "value": result } } })

3.4 Golang 插件开发

3.4.1 目录结构

my-golang-atom/ ├── task.json ├── go.mod ├── go.sum └── main.go

3.4.2 task.json

{ "atomCode": "myGolangAtom", "execution": { "language": "golang", "demands": [], "target": "./app" }, "input": { "greeting": { "label": "欢迎词", "type": "vuex-input", "default": "Hello", "required": true }, "userName": { "label": "用户名", "type": "vuex-input", "required": true } }, "output": { "result": { "type": "string", "description": "输出结果" } } }

3.4.3 go.mod

module xxx/bkdevops/myGolangAtom

go 1.14

require xxx/bkdevops/golang-atom-sdk v1.1.9

3.4.4 main.go

package main

import ( "fmt" sdk "xxx/bkdevops/golang-atom-sdk" )

func main() { // 获取输入参数 input := sdk.GetInput() greeting := input["greeting"] userName := input["userName"]

fmt.Printf("输入参数: greeting=%s, userName=%s\n", greeting, userName)

// 业务逻辑
result := fmt.Sprintf("%s, %s!", greeting, userName)

// 设置输出
output := sdk.Output{
    Status:  sdk.StatusSuccess,
    Message: "执行成功",
    Type:    sdk.OutputTypeDefault,
    Data: map[string]sdk.DataField{
        "result": {
            Type:  "string",
            Value: result,
        },
    },
}
sdk.SetOutput(output)

}

四、插件输出规范

4.1 输出数据结构

{ "status": "success", "message": "执行成功", "errorType": 1, "errorCode": 0, "platformCode": "", "platformErrorCode": 0, "type": "default", "data": { "outputVar1": { "type": "string", "value": "输出值" }, "outputVar2": { "type": "artifact", "value": ["/path/to/file1", "/path/to/file2"], "artifactoryType": "PIPELINE", "path": "/test/" }, "outputVar3": { "type": "report", "reportType": "INTERNAL", "label": "测试报告", "path": "/workspace/report", "target": "index.html" } } }

4.2 status 状态值

值 说明

success

执行成功

failure

执行失败

4.3 输出类型详解

4.3.1 string 类型

{ "outputVar": { "type": "string", "value": "输出字符串,长度不超过4KB" } }

4.3.2 artifact 类型(构件归档)

{ "buildArtifact": { "type": "artifact", "value": ["/workspace/output/app.apk", "/workspace/output/app.ipa"], "artifactoryType": "PIPELINE", "path": "/release/" } }

属性 说明

value

文件绝对路径数组

artifactoryType

PIPELINE (流水线仓库)或 CUSTOM_DIR (自定义仓库)

path

自定义仓库时的相对路径

4.3.3 report 类型(报告归档)

{ "testReport": { "type": "report", "reportType": "INTERNAL", "label": "单元测试报告", "path": "/workspace/test-report", "target": "index.html" } }

属性 说明

reportType

INTERNAL (内置报告)或 THIRDPARTY (第三方链接)

label

报告别名

path

报告目录绝对路径

target

入口文件(相对于 path)

url

第三方报告链接(reportType=THIRDPARTY 时)

五、错误码规范

5.1 错误类型(errorType)

值 类型 说明

1 USER 用户配置错误(参数不合法等)

2 THIRD_PARTY 第三方平台错误

3 PLUGIN 插件逻辑错误(默认)

5.2 通用错误码(100 开头)

错误码 说明 message 规范

100001 输入参数非法 输入参数[xxx]非法:<具体要求>

100002 网络连接超时 接口[xxx],连接超时

100003 插件异常 未知的插件异常:<报错信息>

100004 缺少必要参数 缺少必要参数xxx

100400 HTTP 400 接口[xxx],返回码[400]

100401 HTTP 401 接口[xxx],返回码[401]

100403 HTTP 403 接口[xxx],返回码[403]

100404 HTTP 404 接口[xxx],返回码[404]

100500 HTTP 500 接口[xxx],返回码[500]

100502 HTTP 502 接口[xxx],返回码[502]

5.3 插件自定义错误码

  • 统一以 8 开头

  • 在插件代码库下增加 error.json 文件声明:

[ { "errorCode": 800001, "errorMsgZhCn": "配置文件不存在", "errorMsgEn": "Config file not found" }, { "errorCode": 800002, "errorMsgZhCn": "编译失败", "errorMsgEn": "Build failed" } ]

5.4 第三方平台错误上报

当 errorType=2 时,需要填写:

{ "errorType": 2, "errorCode": 106001, "platformCode": "tgit", "platformErrorCode": 500, "message": "调用工蜂接口失败:/api/v4/projects,返回码[500]" }

已注册的第三方平台标识:

平台 标识 errorCode 前缀

蓝盾 bkci 101

CodeCC bkci_codecc 102

制品库 bkci_repo 103

编译加速 bkci_turbo 104

作业平台 bk_job 105

工蜂 tgit 106

TAPD tapd 107

智研 zhiyan 108

七彩石 rainbow 109

腾讯云 COS cloud_cos 110

六、插件发布流程

6.1 发布流程图

┌─────────────────────────────────────────────────────────────────────────┐ │ 插件发布流程 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 提交发布 │ ─► │ 系统构建 │ ─► │ 测试验证 │ ─► │ 审核发布 │ │ │ │ │ │ │ │ │ │ │ │ │ │ 填写信息 │ │ 自动打包 │ │ 创建流水线 │ │ 首次需审核 │ │ │ │ 选择版本 │ │ 上传制品 │ │ 验证功能 │ │ 升级免审核 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ COMMITTING BUILDING TESTING AUDITING │ │ │ │ │ │ ▼ ▼ │ │ BUILD_FAIL AUDIT_REJECT │ │ │ │ │ ▼ │ │ RELEASED │ │ │ └─────────────────────────────────────────────────────────────────────────┘

6.2 发布类型

类型 说明 版本号变化

新上架 首次发布 1.0.0

非兼容式升级 输入输出不兼容 主版本号 +1

兼容式功能更新 新增功能,兼容旧版 次版本号 +1

兼容式问题修正 Bug 修复 修正号 +1

历史大版本 Bug fix 修复历史版本 修正号 +1

6.3 版本号规范

遵循 SemVer 规范:主版本号.次版本号.修正号

  • 主版本号:不兼容的 API 修改

  • 次版本号:向下兼容的功能性新增

  • 修正号:向下兼容的问题修正

七、本地调试指南

7.1 调试准备

在代码库根目录创建以下文件(不要提交到代码库):

7.1.1 input.json

{ "inputParam1": "测试值1", "inputParam2": "测试值2" }

7.1.2 .sdk.json

{ "buildType": "DOCKER", "projectId": "test-project", "agentId": "1", "secretKey": "test-secret", "gateway": "xxx.xxx.xxx.xxx", "buildId": "test-build-id", "vmSeqId": "1" }

注意: 本地调试时不能调用蓝盾后台服务(需要在流水线中执行才有权限)

7.2 Python 插件调试

安装 SDK

pip install python-atom-sdk

打包插件

python ./setup.py sdist

安装插件

pip install dist/XXX.tar.gz

在 input.json 所在目录执行入口命令

demo

7.3 Java 插件调试

打包

mvn clean package

运行

java -jar target/myJavaAtom-jar-with-dependencies.jar

7.4 NodeJS 插件调试

安装依赖

npm install

打包

rollup -c rollup.config.js

运行(需要先在根目录创建 mock 目录,将 input.json 放入)

node dist/bundle.js

7.5 Golang 插件调试

运行

go run main.go

或构建后运行

go build -o app main.go ./app

八、最佳实践

8.1 参数校验

Python 示例

def validate_params(input_params): required_fields = ["repositoryUrl", "branch"] for field in required_fields: if not input_params.get(field): return False, f"缺少必要参数: {field}" return True, ""

8.2 错误处理

// Java 示例 try { // 业务逻辑 } catch (IOException e) { result.setErrorInfo( Status.failure, 100002, // 网络错误 ErrorType.THIRD_PARTY, new String[]{"接口调用失败: " + e.getMessage()} ); }

8.3 日志输出

Python 示例 - 使用日志分组

sdk.log.info("开始执行任务") sdk.log.group_start("编译阶段") sdk.log.info("正在编译...") sdk.log.group_end("编译阶段")

8.4 敏感信息处理

  • 在 task.json 中将敏感字段设置 isSensitive: true

  • 敏感信息不会在日志中明文显示

  • 使用插件私有设置管理账号密码等敏感数据

九、常见问题

Q: task.json 修改后流水线没有生效? A: 需要重新构建插件,并刷新流水线页面清除缓存。

Q: 如何获取上一个插件的输出变量? A: 在参数类中定义同名参数即可自动接收。

Q: 插件执行报错 "Plugin File Sha1 is wrong!"? A: 联系插件作者重新发布插件版本。

Q: 如何让插件支持多操作系统? A: 在 execution.os 中配置不同操作系统的执行命令。

Q: 插件输出变量长度限制? A: string 类型输出不能超过 4KB。

版本: 1.0.0 | 更新日期: 2025-12-26

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

frontend-vue-development

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

backend-microservice-development

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

managing-devops-pipeline

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

go-agent-development

No summary provided by upstream source.

Repository SourceNeeds Review