@catchmexz/fedin-vibe-mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/dist/common/errors.js +69 -0
- package/dist/common/modularTemplates.js +483 -0
- package/dist/common/pipelineTemplates.js +19 -0
- package/dist/common/types.js +42 -0
- package/dist/common/utils.js +347 -0
- package/dist/common/version.js +1 -0
- package/dist/index.js +217 -0
- package/dist/operations/appstack/appOrchestrations.js +235 -0
- package/dist/operations/appstack/appTags.js +147 -0
- package/dist/operations/appstack/appTemplates.js +67 -0
- package/dist/operations/appstack/applications.js +154 -0
- package/dist/operations/appstack/changeOrders.js +293 -0
- package/dist/operations/appstack/changeRequests.js +263 -0
- package/dist/operations/appstack/deploymentResources.js +265 -0
- package/dist/operations/appstack/globalVars.js +200 -0
- package/dist/operations/appstack/releaseWorkflows.js +178 -0
- package/dist/operations/appstack/variableGroups.js +216 -0
- package/dist/operations/codeup/branches.js +144 -0
- package/dist/operations/codeup/changeRequestComments.js +89 -0
- package/dist/operations/codeup/changeRequests.js +203 -0
- package/dist/operations/codeup/compare.js +26 -0
- package/dist/operations/codeup/files.js +483 -0
- package/dist/operations/codeup/repositories.js +83 -0
- package/dist/operations/codeup/types.js +372 -0
- package/dist/operations/flow/hostGroup.js +48 -0
- package/dist/operations/flow/pipeline.js +530 -0
- package/dist/operations/flow/pipelineJob.js +113 -0
- package/dist/operations/flow/serviceConnection.js +23 -0
- package/dist/operations/flow/types.js +377 -0
- package/dist/operations/git/git-repository.js +334 -0
- package/dist/operations/git/index.js +210 -0
- package/dist/operations/organization/members.js +94 -0
- package/dist/operations/organization/organization.js +73 -0
- package/dist/operations/organization/types.js +111 -0
- package/dist/operations/packages/artifacts.js +64 -0
- package/dist/operations/packages/repositories.js +35 -0
- package/dist/operations/packages/types.js +56 -0
- package/dist/operations/projex/project.js +206 -0
- package/dist/operations/projex/sprint.js +90 -0
- package/dist/operations/projex/types.js +390 -0
- package/dist/operations/projex/workitem.js +452 -0
- package/dist/tool-handlers/appstack-change-orders.js +55 -0
- package/dist/tool-handlers/appstack-change-requests.js +49 -0
- package/dist/tool-handlers/appstack-deployment-resources.js +43 -0
- package/dist/tool-handlers/appstack-global-vars.js +43 -0
- package/dist/tool-handlers/appstack-orchestrations.js +49 -0
- package/dist/tool-handlers/appstack-tags.js +43 -0
- package/dist/tool-handlers/appstack-templates.js +19 -0
- package/dist/tool-handlers/appstack-variable-groups.js +55 -0
- package/dist/tool-handlers/appstack.js +37 -0
- package/dist/tool-handlers/code-management.js +174 -0
- package/dist/tool-handlers/git/branch-operations.js +1 -0
- package/dist/tool-handlers/git/clone-repository.js +36 -0
- package/dist/tool-handlers/git/create-branch.js +26 -0
- package/dist/tool-handlers/git/get-repository-status.js +33 -0
- package/dist/tool-handlers/git/pull-repository.js +27 -0
- package/dist/tool-handlers/git/push-repository.js +37 -0
- package/dist/tool-handlers/git/switch-branch.js +25 -0
- package/dist/tool-handlers/index.js +43 -0
- package/dist/tool-handlers/organization.js +90 -0
- package/dist/tool-handlers/packages.js +32 -0
- package/dist/tool-handlers/pipeline.js +272 -0
- package/dist/tool-handlers/project-management.js +152 -0
- package/dist/tool-handlers/service-connections.js +16 -0
- package/dist/tool-registry/appstack-change-orders.js +40 -0
- package/dist/tool-registry/appstack-change-requests.js +35 -0
- package/dist/tool-registry/appstack-deployment-resources.js +30 -0
- package/dist/tool-registry/appstack-global-vars.js +30 -0
- package/dist/tool-registry/appstack-orchestrations.js +35 -0
- package/dist/tool-registry/appstack-tags.js +30 -0
- package/dist/tool-registry/appstack-templates.js +10 -0
- package/dist/tool-registry/appstack-variable-groups.js +40 -0
- package/dist/tool-registry/appstack.js +25 -0
- package/dist/tool-registry/code-management.js +89 -0
- package/dist/tool-registry/git-repository.js +41 -0
- package/dist/tool-registry/index.js +6 -0
- package/dist/tool-registry/organization.js +65 -0
- package/dist/tool-registry/packages.js +21 -0
- package/dist/tool-registry/pipeline.js +157 -0
- package/dist/tool-registry/project-management.js +108 -0
- package/dist/tool-registry/service-connections.js +10 -0
- package/package.json +39 -0
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import * as utils from "../../common/utils.js";
|
|
2
|
+
import { PipelineDetailSchema, PipelineListItemSchema, PipelineRunSchema, PipelineRunListItemSchema } from "./types.js";
|
|
3
|
+
import { generateModularPipeline } from "../../common/modularTemplates.js";
|
|
4
|
+
import { listServiceConnectionsFunc } from "./serviceConnection.js";
|
|
5
|
+
import { listHostGroupsFunc } from "./hostGroup.js";
|
|
6
|
+
/**
|
|
7
|
+
* 获取流水线详情
|
|
8
|
+
* @param organizationId 组织ID
|
|
9
|
+
* @param pipelineId 流水线ID
|
|
10
|
+
* @returns 流水线详情
|
|
11
|
+
*/
|
|
12
|
+
export async function getPipelineFunc(organizationId, pipelineId) {
|
|
13
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}`;
|
|
14
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
15
|
+
method: "GET",
|
|
16
|
+
});
|
|
17
|
+
return PipelineDetailSchema.parse(response);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 获取流水线列表
|
|
21
|
+
* @param organizationId 组织ID
|
|
22
|
+
* @param options 查询选项
|
|
23
|
+
* @returns 流水线列表
|
|
24
|
+
*/
|
|
25
|
+
export async function listPipelinesFunc(organizationId, options) {
|
|
26
|
+
const baseUrl = `/oapi/v1/flow/organizations/${organizationId}/pipelines`;
|
|
27
|
+
// 构建查询参数
|
|
28
|
+
const queryParams = {};
|
|
29
|
+
// 处理时间戳参数
|
|
30
|
+
// 如果传入的是日期字符串或Date对象,自动转换为毫秒时间戳
|
|
31
|
+
if (options?.createStartTime !== undefined) {
|
|
32
|
+
queryParams.createStartTime = utils.convertToTimestamp(options.createStartTime);
|
|
33
|
+
}
|
|
34
|
+
if (options?.createEndTime !== undefined) {
|
|
35
|
+
queryParams.createEndTime = utils.convertToTimestamp(options.createEndTime);
|
|
36
|
+
}
|
|
37
|
+
if (options?.executeStartTime !== undefined) {
|
|
38
|
+
queryParams.executeStartTime = utils.convertToTimestamp(options.executeStartTime);
|
|
39
|
+
}
|
|
40
|
+
if (options?.executeEndTime !== undefined) {
|
|
41
|
+
queryParams.executeEndTime = utils.convertToTimestamp(options.executeEndTime);
|
|
42
|
+
}
|
|
43
|
+
if (options?.pipelineName !== undefined) {
|
|
44
|
+
queryParams.pipelineName = options.pipelineName;
|
|
45
|
+
}
|
|
46
|
+
if (options?.statusList !== undefined) {
|
|
47
|
+
queryParams.statusList = options.statusList;
|
|
48
|
+
}
|
|
49
|
+
if (options?.perPage !== undefined) {
|
|
50
|
+
queryParams.perPage = options.perPage;
|
|
51
|
+
}
|
|
52
|
+
if (options?.page !== undefined) {
|
|
53
|
+
queryParams.page = options.page;
|
|
54
|
+
}
|
|
55
|
+
const url = utils.buildUrl(baseUrl, queryParams);
|
|
56
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
57
|
+
method: "GET",
|
|
58
|
+
});
|
|
59
|
+
const pagination = {
|
|
60
|
+
nextPage: null,
|
|
61
|
+
page: 1,
|
|
62
|
+
perPage: 10,
|
|
63
|
+
prevPage: null,
|
|
64
|
+
total: 0,
|
|
65
|
+
totalPages: 0
|
|
66
|
+
};
|
|
67
|
+
let items = [];
|
|
68
|
+
if (Array.isArray(response)) {
|
|
69
|
+
items = response.map(item => PipelineListItemSchema.parse(item));
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
items,
|
|
73
|
+
pagination
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 智能查询流水线列表,能够解析自然语言中的时间表达
|
|
78
|
+
* @param organizationId 组织ID
|
|
79
|
+
* @param timeReference 自然语言时间引用,如"今天"、"本周"、"上个月"
|
|
80
|
+
* @param options 其他查询选项
|
|
81
|
+
* @returns 流水线列表
|
|
82
|
+
*/
|
|
83
|
+
export async function smartListPipelinesFunc(organizationId, timeReference, options) {
|
|
84
|
+
// 解析时间引用获取开始和结束时间戳
|
|
85
|
+
const { startTime, endTime } = utils.parseDateReference(timeReference);
|
|
86
|
+
// 合并选项
|
|
87
|
+
const fullOptions = {
|
|
88
|
+
...options,
|
|
89
|
+
executeStartTime: startTime,
|
|
90
|
+
executeEndTime: endTime
|
|
91
|
+
};
|
|
92
|
+
return listPipelinesFunc(organizationId, fullOptions);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 运行流水线
|
|
96
|
+
* @param organizationId 组织ID
|
|
97
|
+
* @param pipelineId 流水线ID
|
|
98
|
+
* @param options 运行选项,可以是直接的JSON字符串或者自然语言描述的选项
|
|
99
|
+
* @returns 流水线运行ID
|
|
100
|
+
*/
|
|
101
|
+
export async function createPipelineRunFunc(organizationId, pipelineId, options) {
|
|
102
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}/runs`;
|
|
103
|
+
// 如果用户已经提供了格式化的params,直接使用
|
|
104
|
+
if (options?.params) {
|
|
105
|
+
const body = {
|
|
106
|
+
params: options.params
|
|
107
|
+
};
|
|
108
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
body: body,
|
|
111
|
+
});
|
|
112
|
+
return Number(response);
|
|
113
|
+
}
|
|
114
|
+
// 否则,基于用户提供的自然语言参数构建params
|
|
115
|
+
const paramsObject = {};
|
|
116
|
+
// 处理分支模式相关参数
|
|
117
|
+
if (options?.branchMode && options?.branches && options.branches.length > 0) {
|
|
118
|
+
paramsObject.branchModeBranchs = options.branches;
|
|
119
|
+
}
|
|
120
|
+
// 处理Release分支相关参数
|
|
121
|
+
if (options?.createReleaseBranch !== undefined) {
|
|
122
|
+
paramsObject.needCreateBranch = options.createReleaseBranch;
|
|
123
|
+
}
|
|
124
|
+
if (options?.releaseBranch) {
|
|
125
|
+
paramsObject.releaseBranch = options.releaseBranch;
|
|
126
|
+
}
|
|
127
|
+
// 处理环境变量
|
|
128
|
+
if (options?.environmentVariables && Object.keys(options.environmentVariables).length > 0) {
|
|
129
|
+
paramsObject.envs = options.environmentVariables;
|
|
130
|
+
}
|
|
131
|
+
// 处理特定仓库配置
|
|
132
|
+
if (options?.repositories && options.repositories.length > 0) {
|
|
133
|
+
// 初始化runningBranchs和runningTags对象
|
|
134
|
+
const runningBranchs = {};
|
|
135
|
+
const runningTags = {};
|
|
136
|
+
// 填充分支和标签信息
|
|
137
|
+
options.repositories.forEach(repo => {
|
|
138
|
+
if (repo.branch) {
|
|
139
|
+
runningBranchs[repo.url] = repo.branch;
|
|
140
|
+
}
|
|
141
|
+
if (repo.tag) {
|
|
142
|
+
runningTags[repo.url] = repo.tag;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
// 只有在有内容时才添加到params对象
|
|
146
|
+
if (Object.keys(runningBranchs).length > 0) {
|
|
147
|
+
paramsObject.runningBranchs = runningBranchs;
|
|
148
|
+
}
|
|
149
|
+
if (Object.keys(runningTags).length > 0) {
|
|
150
|
+
paramsObject.runningTags = runningTags;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// 如果有自然语言描述,尝试解析它
|
|
154
|
+
if (options?.description) {
|
|
155
|
+
// 此处可以添加更复杂的自然语言处理逻辑
|
|
156
|
+
// 当前实现是简单的关键词匹配
|
|
157
|
+
const description = options.description.toLowerCase();
|
|
158
|
+
// 检测分支模式
|
|
159
|
+
if ((description.includes('branch mode') || description.includes('分支模式')) &&
|
|
160
|
+
!paramsObject.branchModeBranchs &&
|
|
161
|
+
options?.branches?.length) {
|
|
162
|
+
paramsObject.branchModeBranchs = options.branches;
|
|
163
|
+
}
|
|
164
|
+
// 检测是否需要创建release分支
|
|
165
|
+
if ((description.includes('create release') || description.includes('创建release')) &&
|
|
166
|
+
paramsObject.needCreateBranch === undefined) {
|
|
167
|
+
paramsObject.needCreateBranch = true;
|
|
168
|
+
}
|
|
169
|
+
// 如果提到特定release分支但没有指定
|
|
170
|
+
if ((description.includes('release branch') || description.includes('release分支')) &&
|
|
171
|
+
!paramsObject.releaseBranch &&
|
|
172
|
+
options?.branches?.length) {
|
|
173
|
+
// 假设第一个分支就是release分支
|
|
174
|
+
paramsObject.releaseBranch = options.branches[0];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const body = {};
|
|
178
|
+
if (Object.keys(paramsObject).length > 0) {
|
|
179
|
+
body.params = JSON.stringify(paramsObject);
|
|
180
|
+
}
|
|
181
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
182
|
+
method: "POST",
|
|
183
|
+
body: body,
|
|
184
|
+
});
|
|
185
|
+
return Number(response);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* 获取最近一次流水线运行信息
|
|
189
|
+
* @param organizationId 组织ID
|
|
190
|
+
* @param pipelineId 流水线ID
|
|
191
|
+
* @returns 最近一次流水线运行信息
|
|
192
|
+
*/
|
|
193
|
+
export async function getLatestPipelineRunFunc(organizationId, pipelineId) {
|
|
194
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}/runs/latestPipelineRun`;
|
|
195
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
196
|
+
method: "GET",
|
|
197
|
+
});
|
|
198
|
+
return PipelineRunSchema.parse(response);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* 获取特定流水线运行实例
|
|
202
|
+
* @param organizationId 组织ID
|
|
203
|
+
* @param pipelineId 流水线ID
|
|
204
|
+
* @param pipelineRunId 流水线运行ID
|
|
205
|
+
* @returns 流水线运行实例信息
|
|
206
|
+
*/
|
|
207
|
+
export async function getPipelineRunFunc(organizationId, pipelineId, pipelineRunId) {
|
|
208
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}/runs/${pipelineRunId}`;
|
|
209
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
210
|
+
method: "GET",
|
|
211
|
+
});
|
|
212
|
+
return PipelineRunSchema.parse(response);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 获取流水线运行实例列表
|
|
216
|
+
* @param organizationId 组织ID
|
|
217
|
+
* @param pipelineId 流水线ID
|
|
218
|
+
* @param options 查询选项
|
|
219
|
+
* @returns 流水线运行实例列表和分页信息
|
|
220
|
+
*/
|
|
221
|
+
export async function listPipelineRunsFunc(organizationId, pipelineId, options) {
|
|
222
|
+
const baseUrl = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}/runs`;
|
|
223
|
+
// 构建查询参数
|
|
224
|
+
const queryParams = {};
|
|
225
|
+
if (options?.perPage !== undefined) {
|
|
226
|
+
queryParams.perPage = options.perPage;
|
|
227
|
+
}
|
|
228
|
+
if (options?.page !== undefined) {
|
|
229
|
+
queryParams.page = options.page;
|
|
230
|
+
}
|
|
231
|
+
if (options?.startTime !== undefined) {
|
|
232
|
+
queryParams.startTime = utils.convertToTimestamp(options.startTime);
|
|
233
|
+
}
|
|
234
|
+
if (options?.endTime !== undefined) {
|
|
235
|
+
queryParams.endTme = utils.convertToTimestamp(options.endTime);
|
|
236
|
+
}
|
|
237
|
+
if (options?.status !== undefined) {
|
|
238
|
+
queryParams.status = options.status;
|
|
239
|
+
}
|
|
240
|
+
if (options?.triggerMode !== undefined) {
|
|
241
|
+
queryParams.triggerMode = options.triggerMode;
|
|
242
|
+
}
|
|
243
|
+
const url = utils.buildUrl(baseUrl, queryParams);
|
|
244
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
245
|
+
method: "GET",
|
|
246
|
+
});
|
|
247
|
+
const pagination = {
|
|
248
|
+
nextPage: null,
|
|
249
|
+
page: options?.page ?? 1,
|
|
250
|
+
perPage: options?.perPage ?? 10,
|
|
251
|
+
prevPage: null,
|
|
252
|
+
total: 0,
|
|
253
|
+
totalPages: 0
|
|
254
|
+
};
|
|
255
|
+
let items = [];
|
|
256
|
+
if (Array.isArray(response)) {
|
|
257
|
+
items = response.map(item => PipelineRunListItemSchema.parse(item));
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
items,
|
|
261
|
+
pagination
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* 创建流水线
|
|
266
|
+
* @param organizationId 组织ID
|
|
267
|
+
* @param name 流水线名称
|
|
268
|
+
* @param content 流水线YAML描述
|
|
269
|
+
* @returns 流水线ID
|
|
270
|
+
*/
|
|
271
|
+
export async function createPipelineFunc(organizationId, name, content) {
|
|
272
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines`;
|
|
273
|
+
const body = {
|
|
274
|
+
name: name,
|
|
275
|
+
content: content
|
|
276
|
+
};
|
|
277
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
278
|
+
method: "POST",
|
|
279
|
+
body: body,
|
|
280
|
+
});
|
|
281
|
+
return Number(response);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* 基于结构化参数生成流水线YAML(不创建流水线)
|
|
285
|
+
* @param options 结构化的流水线配置选项
|
|
286
|
+
* @returns 生成的YAML字符串
|
|
287
|
+
*/
|
|
288
|
+
export async function generatePipelineYamlFunc(options) {
|
|
289
|
+
// 自动从repoUrl解析serviceName(如果用户没有明确指定)
|
|
290
|
+
let derivedServiceName = options.serviceName;
|
|
291
|
+
if (!derivedServiceName && options.repoUrl) {
|
|
292
|
+
// 从Git URL中提取项目名称
|
|
293
|
+
// 支持格式: git@codeup.aliyun.com:org/repo.git 或 https://codeup.aliyun.com/org/repo.git
|
|
294
|
+
const repoUrlMatch = options.repoUrl.match(/[\/:]([^\/]+)\.git$/);
|
|
295
|
+
if (repoUrlMatch) {
|
|
296
|
+
derivedServiceName = repoUrlMatch[1];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// 准备变量,确保版本号有双引号
|
|
300
|
+
const variables = {
|
|
301
|
+
// 基础配置
|
|
302
|
+
...(options.repoUrl && { repoUrl: options.repoUrl }),
|
|
303
|
+
...(options.branch && { branch: options.branch }),
|
|
304
|
+
...(derivedServiceName && { serviceName: derivedServiceName }),
|
|
305
|
+
...(options.serviceConnectionId && { serviceConnectionId: options.serviceConnectionId }),
|
|
306
|
+
...(options.packagesServiceConnection && { packagesServiceConnection: options.packagesServiceConnection }),
|
|
307
|
+
...(options.machineGroupId && { machineGroupId: options.machineGroupId }),
|
|
308
|
+
...(options.namespace && { namespace: options.namespace }),
|
|
309
|
+
...(options.dockerImage && { dockerImage: options.dockerImage }),
|
|
310
|
+
// 版本相关(确保双引号)
|
|
311
|
+
...(options.jdkVersion && { jdkVersion: `"${options.jdkVersion}"` }),
|
|
312
|
+
...(options.mavenVersion && { mavenVersion: `"${options.mavenVersion}"` }),
|
|
313
|
+
...(options.nodeVersion && { nodeVersion: `"${options.nodeVersion}"` }),
|
|
314
|
+
...(options.pythonVersion && { pythonVersion: `"${options.pythonVersion}"` }),
|
|
315
|
+
...(options.goVersion && { goVersion: `"${options.goVersion}"` }),
|
|
316
|
+
...(options.kubectlVersion && { kubectlVersion: `"${options.kubectlVersion}"` }),
|
|
317
|
+
// 构建物上传相关
|
|
318
|
+
...(options.uploadType && { uploadType: options.uploadType }),
|
|
319
|
+
...(options.artifactName && { artifactName: options.artifactName }),
|
|
320
|
+
...(options.artifactVersion && { artifactVersion: options.artifactVersion }),
|
|
321
|
+
...(options.packagesRepoId && { packagesRepoId: options.packagesRepoId }),
|
|
322
|
+
...(options.includePathInArtifact !== undefined && { includePathInArtifact: options.includePathInArtifact }),
|
|
323
|
+
// 部署相关
|
|
324
|
+
...(options.executeUser && { executeUser: options.executeUser }),
|
|
325
|
+
...(options.artifactDownloadPath && { artifactDownloadPath: options.artifactDownloadPath }),
|
|
326
|
+
...(options.kubernetesClusterId && { kubernetesClusterId: options.kubernetesClusterId }),
|
|
327
|
+
...(options.yamlPath && { yamlPath: options.yamlPath }),
|
|
328
|
+
// 命令
|
|
329
|
+
...(options.buildCommand && { buildCommand: options.buildCommand }),
|
|
330
|
+
...(options.testCommand && { testCommand: options.testCommand }),
|
|
331
|
+
...(options.deployCommand && { deployCommand: options.deployCommand }),
|
|
332
|
+
};
|
|
333
|
+
// 转换为模块化流水线选项
|
|
334
|
+
const deployTargets = options.deployTarget ? [options.deployTarget] : [];
|
|
335
|
+
// 使用模块化架构生成YAML
|
|
336
|
+
return generateModularPipeline({
|
|
337
|
+
keywords: [options.buildLanguage, options.buildTool],
|
|
338
|
+
buildLanguages: [options.buildLanguage],
|
|
339
|
+
buildTools: [options.buildTool],
|
|
340
|
+
deployTargets: deployTargets,
|
|
341
|
+
uploadType: options.uploadType || 'packages',
|
|
342
|
+
variables: variables
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* 基于结构化参数创建流水线
|
|
347
|
+
* @param organizationId 组织ID
|
|
348
|
+
* @param options 结构化的流水线配置选项
|
|
349
|
+
* @returns 创建结果,包含流水线ID和生成的YAML
|
|
350
|
+
*/
|
|
351
|
+
export async function createPipelineWithOptionsFunc(organizationId, options) {
|
|
352
|
+
// 获取默认服务连接ID(如果用户没有明确指定)
|
|
353
|
+
let defaultServiceConnectionId = null;
|
|
354
|
+
const hasServiceConnectionId = options.serviceConnectionId;
|
|
355
|
+
if (!hasServiceConnectionId) {
|
|
356
|
+
defaultServiceConnectionId = await getDefaultServiceConnectionId(organizationId);
|
|
357
|
+
}
|
|
358
|
+
// 获取默认Packages服务连接ID(如果用户没有明确指定且需要packages上传)
|
|
359
|
+
let defaultPackagesServiceConnectionId = null;
|
|
360
|
+
const hasPackagesServiceConnectionId = options.packagesServiceConnection;
|
|
361
|
+
const needsPackagesUpload = !options.uploadType || options.uploadType === 'packages';
|
|
362
|
+
if (!hasPackagesServiceConnectionId && needsPackagesUpload) {
|
|
363
|
+
defaultPackagesServiceConnectionId = await getDefaultPackagesServiceConnectionId(organizationId);
|
|
364
|
+
}
|
|
365
|
+
// 获取默认主机组ID(如果用户没有明确指定且需要VM部署)
|
|
366
|
+
let defaultMachineGroupId = null;
|
|
367
|
+
const hasMachineGroupId = options.machineGroupId;
|
|
368
|
+
const needsVMDeploy = options.deployTarget === 'vm';
|
|
369
|
+
if (!hasMachineGroupId && needsVMDeploy) {
|
|
370
|
+
defaultMachineGroupId = await getDefaultHostGroupId(organizationId);
|
|
371
|
+
}
|
|
372
|
+
// 自动从repoUrl解析serviceName(如果用户没有明确指定)
|
|
373
|
+
let derivedServiceName = options.serviceName;
|
|
374
|
+
if (!derivedServiceName && options.repoUrl) {
|
|
375
|
+
// 从Git URL中提取项目名称
|
|
376
|
+
// 支持格式: git@codeup.aliyun.com:org/repo.git 或 https://codeup.aliyun.com/org/repo.git
|
|
377
|
+
const repoUrlMatch = options.repoUrl.match(/[\/:]([^\/]+)\.git$/);
|
|
378
|
+
if (repoUrlMatch) {
|
|
379
|
+
derivedServiceName = repoUrlMatch[1];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// 准备模块化流水线生成的变量
|
|
383
|
+
const finalVariables = {
|
|
384
|
+
// 基础配置(直接使用用户提供的值)
|
|
385
|
+
...(options.repoUrl && { repoUrl: options.repoUrl }),
|
|
386
|
+
...(options.branch && { branch: options.branch }),
|
|
387
|
+
...(derivedServiceName && { serviceName: derivedServiceName }),
|
|
388
|
+
// 使用获取到的默认服务连接ID
|
|
389
|
+
...(defaultServiceConnectionId && !hasServiceConnectionId && { serviceConnectionId: defaultServiceConnectionId }),
|
|
390
|
+
// 使用获取到的默认Packages服务连接ID
|
|
391
|
+
...(defaultPackagesServiceConnectionId && !hasPackagesServiceConnectionId && { packagesServiceConnection: defaultPackagesServiceConnectionId }),
|
|
392
|
+
// 使用获取到的默认主机组ID
|
|
393
|
+
...(defaultMachineGroupId && !hasMachineGroupId && { machineGroupId: defaultMachineGroupId }),
|
|
394
|
+
// 用户明确指定的值优先级最高
|
|
395
|
+
...(options.serviceConnectionId && { serviceConnectionId: options.serviceConnectionId }),
|
|
396
|
+
...(options.packagesServiceConnection && { packagesServiceConnection: options.packagesServiceConnection }),
|
|
397
|
+
...(options.machineGroupId && { machineGroupId: options.machineGroupId }),
|
|
398
|
+
...(options.namespace && { namespace: options.namespace }),
|
|
399
|
+
...(options.dockerImage && { dockerImage: options.dockerImage }),
|
|
400
|
+
// 版本相关(确保双引号)
|
|
401
|
+
...(options.jdkVersion && { jdkVersion: `"${options.jdkVersion}"` }),
|
|
402
|
+
...(options.mavenVersion && { mavenVersion: `"${options.mavenVersion}"` }),
|
|
403
|
+
...(options.nodeVersion && { nodeVersion: `"${options.nodeVersion}"` }),
|
|
404
|
+
...(options.pythonVersion && { pythonVersion: `"${options.pythonVersion}"` }),
|
|
405
|
+
...(options.goVersion && { goVersion: `"${options.goVersion}"` }),
|
|
406
|
+
...(options.kubectlVersion && { kubectlVersion: `"${options.kubectlVersion}"` }),
|
|
407
|
+
// 构建物上传相关
|
|
408
|
+
...(options.uploadType && { uploadType: options.uploadType }),
|
|
409
|
+
...(options.artifactName && { artifactName: options.artifactName }),
|
|
410
|
+
...(options.artifactVersion && { artifactVersion: options.artifactVersion }),
|
|
411
|
+
...(options.packagesRepoId && { packagesRepoId: options.packagesRepoId }),
|
|
412
|
+
...(options.includePathInArtifact !== undefined && { includePathInArtifact: options.includePathInArtifact }),
|
|
413
|
+
// 部署相关
|
|
414
|
+
...(options.executeUser && { executeUser: options.executeUser }),
|
|
415
|
+
...(options.artifactDownloadPath && { artifactDownloadPath: options.artifactDownloadPath }),
|
|
416
|
+
...(options.kubernetesClusterId && { kubernetesClusterId: options.kubernetesClusterId }),
|
|
417
|
+
...(options.yamlPath && { yamlPath: options.yamlPath }),
|
|
418
|
+
// 命令
|
|
419
|
+
...(options.buildCommand && { buildCommand: options.buildCommand }),
|
|
420
|
+
...(options.testCommand && { testCommand: options.testCommand }),
|
|
421
|
+
...(options.deployCommand && { deployCommand: options.deployCommand }),
|
|
422
|
+
};
|
|
423
|
+
// 转换为模块化流水线选项
|
|
424
|
+
const deployTargets = options.deployTarget ? [options.deployTarget] : [];
|
|
425
|
+
// 使用模块化架构生成YAML
|
|
426
|
+
const generatedYaml = generateModularPipeline({
|
|
427
|
+
keywords: [options.buildLanguage, options.buildTool],
|
|
428
|
+
buildLanguages: [options.buildLanguage],
|
|
429
|
+
buildTools: [options.buildTool],
|
|
430
|
+
deployTargets: deployTargets,
|
|
431
|
+
uploadType: options.uploadType || 'packages',
|
|
432
|
+
variables: finalVariables
|
|
433
|
+
});
|
|
434
|
+
// 创建流水线
|
|
435
|
+
try {
|
|
436
|
+
const pipelineId = await createPipelineFunc(organizationId, options.name, generatedYaml);
|
|
437
|
+
return {
|
|
438
|
+
pipelineId,
|
|
439
|
+
generatedYaml
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
catch (error) {
|
|
443
|
+
// 如果是YAML校验失败或其他流水线创建错误,将详细信息透出给用户
|
|
444
|
+
console.error('Create pipeline failed:', error);
|
|
445
|
+
// 构造包含生成YAML的错误信息,方便用户排查
|
|
446
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
447
|
+
const enhancedError = new Error(`Create pipeline failed: ${errorMessage}\n\n` +
|
|
448
|
+
`YAML content:\n${generatedYaml}\n\n` +
|
|
449
|
+
`Suggestions:\n` +
|
|
450
|
+
`1. Check whether the YAML format is correct.\n` +
|
|
451
|
+
`2. Verify whether the serviceConnectionID、machineGroupID、kubernetesClusterID and other parameters are existed and valid.`);
|
|
452
|
+
// 保持原始错误的堆栈信息
|
|
453
|
+
if (error instanceof Error && error.stack) {
|
|
454
|
+
enhancedError.stack = error.stack;
|
|
455
|
+
}
|
|
456
|
+
throw enhancedError;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* 获取默认的服务连接ID(用于代码源配置)
|
|
461
|
+
* @param organizationId 组织ID
|
|
462
|
+
* @returns 服务连接ID
|
|
463
|
+
*/
|
|
464
|
+
async function getDefaultServiceConnectionId(organizationId) {
|
|
465
|
+
try {
|
|
466
|
+
// 获取Codeup类型的服务连接(代码源最常用)
|
|
467
|
+
const serviceConnections = await listServiceConnectionsFunc(organizationId, 'codeup');
|
|
468
|
+
if (serviceConnections && serviceConnections.length > 0) {
|
|
469
|
+
return serviceConnections[0].uuid || null;
|
|
470
|
+
}
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
console.error('获取Codeup服务连接失败:', error);
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* 获取默认的Packages服务连接ID(用于制品上传配置)
|
|
480
|
+
* @param organizationId 组织ID
|
|
481
|
+
* @returns Packages服务连接ID
|
|
482
|
+
*/
|
|
483
|
+
async function getDefaultPackagesServiceConnectionId(organizationId) {
|
|
484
|
+
try {
|
|
485
|
+
// 获取packages类型的服务连接
|
|
486
|
+
const serviceConnections = await listServiceConnectionsFunc(organizationId, 'packages');
|
|
487
|
+
if (serviceConnections && serviceConnections.length > 0) {
|
|
488
|
+
return serviceConnections[0].uuid || null;
|
|
489
|
+
}
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
console.error('获取Packages服务连接失败:', error);
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* 获取默认的主机组UUID(用于VM部署配置)
|
|
499
|
+
* @param organizationId 组织ID
|
|
500
|
+
* @returns null(暂不自动获取)
|
|
501
|
+
*/
|
|
502
|
+
async function getDefaultHostGroupId(organizationId) {
|
|
503
|
+
try {
|
|
504
|
+
const hostGroups = await listHostGroupsFunc(organizationId);
|
|
505
|
+
if (hostGroups && hostGroups.length > 0) {
|
|
506
|
+
return hostGroups[0].uuid || null;
|
|
507
|
+
}
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
console.error('获取主机组失败:', error);
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* 更新流水线内容(YAML)
|
|
517
|
+
* @param organizationId
|
|
518
|
+
* @param pipelineId
|
|
519
|
+
* @param name
|
|
520
|
+
* @param content
|
|
521
|
+
*/
|
|
522
|
+
export async function updatePipelineFunc(organizationId, pipelineId, name, content) {
|
|
523
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}`;
|
|
524
|
+
const body = { name, content };
|
|
525
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
526
|
+
method: "PUT",
|
|
527
|
+
body
|
|
528
|
+
});
|
|
529
|
+
return Boolean(response);
|
|
530
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 流水线任务相关操作
|
|
3
|
+
* 提供按照分类获取流水线执行的任务接口
|
|
4
|
+
*/
|
|
5
|
+
import * as utils from "../../common/utils.js";
|
|
6
|
+
import { PipelineJobItemSchema, PipelineJobHistoryItemSchema, PipelineJobRunLogSchema } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* 按任务分类获取流水线执行的任务
|
|
9
|
+
* @param organizationId Organization ID(组织ID)
|
|
10
|
+
* @param pipelineId Pipeline ID(流水线ID)
|
|
11
|
+
* @param category Task category, currently only supports DEPLOY(任务分类,当前仅支持DEPLOY)
|
|
12
|
+
* @returns 任务列表
|
|
13
|
+
*/
|
|
14
|
+
export async function listPipelineJobsByCategoryFunc(organizationId, pipelineId, category) {
|
|
15
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}/listTasksByCategory/${category}`;
|
|
16
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
17
|
+
method: "GET",
|
|
18
|
+
});
|
|
19
|
+
if (!Array.isArray(response)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
return response.map(job => PipelineJobItemSchema.parse(job));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 获取流水线任务的执行历史
|
|
26
|
+
* @param organizationId Organization ID(组织ID)
|
|
27
|
+
* @param pipelineId Pipeline ID(流水线ID)
|
|
28
|
+
* @param category Task category, currently only supports DEPLOY(任务分类,当前仅支持DEPLOY)
|
|
29
|
+
* @param identifier Task identifier(任务标识)
|
|
30
|
+
* @param page Page number, default 1
|
|
31
|
+
* @param perPage Number of items per page, default 10, max 30
|
|
32
|
+
* @returns Job history list and pagination information
|
|
33
|
+
*/
|
|
34
|
+
export async function listPipelineJobHistorysFunc(organizationId, pipelineId, category, identifier, page = 1, perPage = 10) {
|
|
35
|
+
const baseUrl = `/oapi/v1/flow/organizations/${organizationId}/pipelines/getComponentsWithoutButtons`;
|
|
36
|
+
const queryParams = {
|
|
37
|
+
pipelineId,
|
|
38
|
+
category,
|
|
39
|
+
identifier,
|
|
40
|
+
page,
|
|
41
|
+
perPage
|
|
42
|
+
};
|
|
43
|
+
const url = utils.buildUrl(baseUrl, queryParams);
|
|
44
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
45
|
+
method: "GET",
|
|
46
|
+
});
|
|
47
|
+
const pagination = {
|
|
48
|
+
nextPage: null,
|
|
49
|
+
page: page,
|
|
50
|
+
perPage: perPage,
|
|
51
|
+
prevPage: null,
|
|
52
|
+
total: 0,
|
|
53
|
+
totalPages: 0
|
|
54
|
+
};
|
|
55
|
+
if (response && 'headers' in response) {
|
|
56
|
+
const headers = response.headers;
|
|
57
|
+
if (headers['x-next-page']) {
|
|
58
|
+
pagination.nextPage = parseInt(headers['x-next-page']);
|
|
59
|
+
}
|
|
60
|
+
if (headers['x-page']) {
|
|
61
|
+
pagination.page = parseInt(headers['x-page']);
|
|
62
|
+
}
|
|
63
|
+
if (headers['x-per-page']) {
|
|
64
|
+
pagination.perPage = parseInt(headers['x-per-page']);
|
|
65
|
+
}
|
|
66
|
+
if (headers['x-prev-page']) {
|
|
67
|
+
pagination.prevPage = parseInt(headers['x-prev-page']);
|
|
68
|
+
}
|
|
69
|
+
if (headers['x-total']) {
|
|
70
|
+
pagination.total = parseInt(headers['x-total']);
|
|
71
|
+
}
|
|
72
|
+
if (headers['x-total-pages']) {
|
|
73
|
+
pagination.totalPages = parseInt(headers['x-total-pages']);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const items = Array.isArray(response)
|
|
77
|
+
? response.map(item => PipelineJobHistoryItemSchema.parse(item))
|
|
78
|
+
: [];
|
|
79
|
+
return {
|
|
80
|
+
items,
|
|
81
|
+
pagination
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 手动运行流水线任务
|
|
86
|
+
* @param organizationId Organization ID(组织ID)
|
|
87
|
+
* @param pipelineId Pipeline ID(流水线ID)
|
|
88
|
+
* @param pipelineRunId Pipeline run instance ID(流水线运行ID)
|
|
89
|
+
* @param jobId Job ID for the pipeline run task(流水线运行任务ID)
|
|
90
|
+
* @returns Whether the operation was successful
|
|
91
|
+
*/
|
|
92
|
+
export async function executePipelineJobRunFunc(organizationId, pipelineId, pipelineRunId, jobId) {
|
|
93
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}/pipelineRuns/${pipelineRunId}/jobs/${jobId}/start`;
|
|
94
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
95
|
+
method: "POST",
|
|
96
|
+
});
|
|
97
|
+
return Boolean(response);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 查询任务运行日志
|
|
101
|
+
* @param organizationId Organization ID(组织ID)
|
|
102
|
+
* @param pipelineId Pipeline ID(流水线ID)
|
|
103
|
+
* @param pipelineRunId Pipeline run instance ID(流水线运行ID)
|
|
104
|
+
* @param jobId Job ID of the pipeline run task(流水线运行任务ID)
|
|
105
|
+
* @returns Log content and metadata
|
|
106
|
+
*/
|
|
107
|
+
export async function getPipelineJobRunLogFunc(organizationId, pipelineId, pipelineRunId, jobId) {
|
|
108
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineId}/runs/${pipelineRunId}/job/${jobId}/log`;
|
|
109
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
110
|
+
method: "GET",
|
|
111
|
+
});
|
|
112
|
+
return PipelineJobRunLogSchema.parse(response);
|
|
113
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as utils from "../../common/utils.js";
|
|
2
|
+
import { ServiceConnectionSchema } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 获取服务连接列表
|
|
5
|
+
* @param organizationId 组织ID
|
|
6
|
+
* @param serviceConnectionType 服务连接类型
|
|
7
|
+
* @returns 服务连接列表
|
|
8
|
+
*/
|
|
9
|
+
export async function listServiceConnectionsFunc(organizationId, serviceConnectionType) {
|
|
10
|
+
const baseUrl = `/oapi/v1/flow/organizations/${organizationId}/serviceConnections`;
|
|
11
|
+
// 构建查询参数
|
|
12
|
+
const queryParams = {
|
|
13
|
+
sericeConnectionType: serviceConnectionType // 注意:API文档中拼写为 sericeConnectionType
|
|
14
|
+
};
|
|
15
|
+
const url = utils.buildUrl(baseUrl, queryParams);
|
|
16
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
17
|
+
method: "GET",
|
|
18
|
+
});
|
|
19
|
+
if (!Array.isArray(response)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
return response.map(item => ServiceConnectionSchema.parse(item));
|
|
23
|
+
}
|