@fieldwangai/agentflow 0.1.137 → 0.1.141
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/bin/lib/catalog-flows.mjs +17 -3
- package/bin/lib/composer-node-schema.mjs +4 -0
- package/bin/lib/i18n.mjs +2 -2
- package/bin/lib/jenkins.mjs +380 -0
- package/bin/lib/locales/en.json +22 -0
- package/bin/lib/locales/zh.json +22 -0
- package/bin/lib/paths.mjs +1 -0
- package/bin/lib/prd-workflow-collaboration.mjs +139 -1
- package/bin/lib/recent-runs.mjs +16 -0
- package/bin/lib/run-node-statuses-from-disk.mjs +41 -3
- package/bin/lib/scheduler.mjs +59 -25
- package/bin/lib/ui-server.mjs +721 -63
- package/bin/pipeline/pre-process-node.mjs +122 -11
- package/bin/pipeline/run-log.mjs +2 -2
- package/bin/pipeline/write-result.mjs +4 -4
- package/builtin/nodes/tool_jenkins_build.md +64 -0
- package/builtin/pipelines/jenkins-build-notify/flow.yaml +217 -0
- package/builtin/web-ui/dist/assets/WorkflowAssistantThread-ubxHcM7p.js +6 -0
- package/builtin/web-ui/dist/assets/index-B6TWUomI.css +1 -0
- package/builtin/web-ui/dist/assets/index-DQzcZp7S.js +590 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/skills/agentflow-workflow-report/SKILL.md +3 -0
- package/skills/agentflow-workflow-report/references/protocol.md +8 -5
- package/builtin/web-ui/dist/assets/index-CQsrSc3u.css +0 -1
- package/builtin/web-ui/dist/assets/index-DQvqqAeQ.js +0 -590
|
@@ -51,6 +51,13 @@ import {
|
|
|
51
51
|
import { buildGitContext, inferGitRepoRootFromWorktree, loadGitWorktree, normalizeGitContext, unloadGitWorktree } from "../lib/git-worktree.mjs";
|
|
52
52
|
import { createGitLabMergeRequest } from "../lib/gitlab-mr.mjs";
|
|
53
53
|
import { sendWecomAppMarkdown, sendWecomGroupMarkdown } from "../lib/wecom.mjs";
|
|
54
|
+
import {
|
|
55
|
+
advanceJenkinsBuild,
|
|
56
|
+
createJenkinsSkillInvoker,
|
|
57
|
+
normalizeJenkinsBuildConfig,
|
|
58
|
+
readJenkinsBuildState,
|
|
59
|
+
writeJenkinsBuildState,
|
|
60
|
+
} from "../lib/jenkins.mjs";
|
|
54
61
|
|
|
55
62
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
56
63
|
|
|
@@ -500,6 +507,106 @@ async function emitWecomMarkdownNode(workspaceRoot, flowName, uuid, instanceId,
|
|
|
500
507
|
return emitLocalNoopPrompt(workspaceRoot, runDir, instanceId, "wecom-markdown", `${result.message}\n`);
|
|
501
508
|
}
|
|
502
509
|
|
|
510
|
+
function emitJenkinsBuildNode(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
511
|
+
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
512
|
+
const data = getResolvedValues(workspaceRoot, flowName, uuid, instanceId);
|
|
513
|
+
if (!data.ok) throw new Error("getResolvedValues failed");
|
|
514
|
+
const inputs = data.resolvedInputs || {};
|
|
515
|
+
const config = normalizeJenkinsBuildConfig(inputs);
|
|
516
|
+
const statePath = path.join(runDir, "state", `${instanceId}.jenkins.json`);
|
|
517
|
+
const priorState = readJenkinsBuildState(statePath);
|
|
518
|
+
if (priorState?.job && priorState.job !== config.job) {
|
|
519
|
+
throw new Error(`checkpoint job mismatch: ${priorState.job} != ${config.job}`);
|
|
520
|
+
}
|
|
521
|
+
let invoker = null;
|
|
522
|
+
const invoke = (operation, args) => {
|
|
523
|
+
if (!invoker) {
|
|
524
|
+
invoker = createJenkinsSkillInvoker({
|
|
525
|
+
workspaceRoot,
|
|
526
|
+
credentialRef: config.credentialRef,
|
|
527
|
+
env: process.env,
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return invoker(operation, args);
|
|
531
|
+
};
|
|
532
|
+
const result = advanceJenkinsBuild({
|
|
533
|
+
state: priorState,
|
|
534
|
+
config,
|
|
535
|
+
invoke,
|
|
536
|
+
persistState: (state) => writeJenkinsBuildState(statePath, state),
|
|
537
|
+
nowMs: Date.now(),
|
|
538
|
+
cancelled: readCancelFlag(runDir),
|
|
539
|
+
});
|
|
540
|
+
writeJenkinsBuildState(statePath, result.state);
|
|
541
|
+
writeOutputSlot(runDir, instanceId, execId, "status", result.outputs?.status || result.state?.status || "");
|
|
542
|
+
writeOutputSlot(runDir, instanceId, execId, "url", result.outputs?.url || result.state?.url || result.state?.buildUrl || "");
|
|
543
|
+
writeOutputSlot(runDir, instanceId, execId, "qrUrl", result.outputs?.qrUrl || result.state?.qrUrl || "");
|
|
544
|
+
|
|
545
|
+
const message = result.message || result.state?.message || "Jenkins Build";
|
|
546
|
+
if (result.kind === "failed") {
|
|
547
|
+
writeResult(
|
|
548
|
+
workspaceRoot,
|
|
549
|
+
flowName,
|
|
550
|
+
uuid,
|
|
551
|
+
instanceId,
|
|
552
|
+
{ status: "failed", message },
|
|
553
|
+
{ execId, preserveBody: false, body: JSON.stringify({ status: "ERROR", message }, null, 2) },
|
|
554
|
+
);
|
|
555
|
+
throw new Error(message);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const promptPath = emitLocalNoopPrompt(
|
|
559
|
+
workspaceRoot,
|
|
560
|
+
runDir,
|
|
561
|
+
instanceId,
|
|
562
|
+
result.kind === "waiting" ? "jenkins-waiting" : "jenkins-complete",
|
|
563
|
+
`${message}\n`,
|
|
564
|
+
);
|
|
565
|
+
if (result.kind === "waiting") {
|
|
566
|
+
const waitId = `${uuid}:${instanceId}:jenkins-build`;
|
|
567
|
+
writeWaitState(runDir, {
|
|
568
|
+
waitId,
|
|
569
|
+
status: "waiting",
|
|
570
|
+
reason: "tool_jenkins_build",
|
|
571
|
+
resumeMode: "rerun",
|
|
572
|
+
flowName,
|
|
573
|
+
uuid,
|
|
574
|
+
instanceId,
|
|
575
|
+
execId,
|
|
576
|
+
phase: result.state?.phase || "queued",
|
|
577
|
+
buildNumber: result.state?.buildNumber || "",
|
|
578
|
+
wakeAt: result.wakeAt,
|
|
579
|
+
createdAt: priorState?.createdAt || new Date().toISOString(),
|
|
580
|
+
});
|
|
581
|
+
writeResult(
|
|
582
|
+
workspaceRoot,
|
|
583
|
+
flowName,
|
|
584
|
+
uuid,
|
|
585
|
+
instanceId,
|
|
586
|
+
{ status: "pending", message },
|
|
587
|
+
{ execId, preserveBody: false, body: JSON.stringify({ phase: result.state?.phase, wakeAt: result.wakeAt }, null, 2) },
|
|
588
|
+
);
|
|
589
|
+
} else {
|
|
590
|
+
writeResult(
|
|
591
|
+
workspaceRoot,
|
|
592
|
+
flowName,
|
|
593
|
+
uuid,
|
|
594
|
+
instanceId,
|
|
595
|
+
{ status: "success", message },
|
|
596
|
+
{
|
|
597
|
+
execId,
|
|
598
|
+
preserveBody: false,
|
|
599
|
+
body: JSON.stringify({
|
|
600
|
+
status: result.outputs?.status || result.state?.status || "",
|
|
601
|
+
url: result.outputs?.url || result.state?.url || "",
|
|
602
|
+
qrUrl: result.outputs?.qrUrl || result.state?.qrUrl || "",
|
|
603
|
+
}, null, 2),
|
|
604
|
+
},
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
return { promptPath, lifecycle: result.kind };
|
|
608
|
+
}
|
|
609
|
+
|
|
503
610
|
function emitCdWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
504
611
|
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
505
612
|
const { inputs, workspaceContext } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
|
|
@@ -1203,26 +1310,29 @@ async function main() {
|
|
|
1203
1310
|
return;
|
|
1204
1311
|
}
|
|
1205
1312
|
|
|
1206
|
-
if (definitionId === "tool_git_checkout" || definitionId === "tool_git_worktree_load" || definitionId === "tool_git_worktree_unload" || definitionId === "tool_gitlab_create_mr" || definitionId === "tool_wecom_send_group_markdown" || definitionId === "tool_wecom_send_app_markdown" || definitionId === "control_cd_workspace" || definitionId === "control_user_workspace" || definitionId === "control_load_skills" || definitionId === "tool_print") {
|
|
1313
|
+
if (definitionId === "tool_git_checkout" || definitionId === "tool_git_worktree_load" || definitionId === "tool_git_worktree_unload" || definitionId === "tool_gitlab_create_mr" || definitionId === "tool_jenkins_build" || definitionId === "tool_wecom_send_group_markdown" || definitionId === "tool_wecom_send_app_markdown" || definitionId === "control_cd_workspace" || definitionId === "control_user_workspace" || definitionId === "control_load_skills" || definitionId === "tool_print") {
|
|
1207
1314
|
try {
|
|
1208
|
-
const
|
|
1315
|
+
const localResult =
|
|
1209
1316
|
definitionId === "tool_git_checkout"
|
|
1210
|
-
? emitGitCheckoutNode(workspaceRoot, flowName, uuid, instanceId, execId, resultPathRel)
|
|
1317
|
+
? { promptPath: emitGitCheckoutNode(workspaceRoot, flowName, uuid, instanceId, execId, resultPathRel) }
|
|
1211
1318
|
: definitionId === "tool_git_worktree_load"
|
|
1212
|
-
? emitGitWorktreeLoadNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1319
|
+
? { promptPath: emitGitWorktreeLoadNode(workspaceRoot, flowName, uuid, instanceId, execId) }
|
|
1213
1320
|
: definitionId === "tool_git_worktree_unload"
|
|
1214
|
-
? emitGitWorktreeUnloadNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1321
|
+
? { promptPath: emitGitWorktreeUnloadNode(workspaceRoot, flowName, uuid, instanceId, execId) }
|
|
1215
1322
|
: definitionId === "tool_gitlab_create_mr"
|
|
1216
|
-
? await emitGitLabCreateMrNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1323
|
+
? { promptPath: await emitGitLabCreateMrNode(workspaceRoot, flowName, uuid, instanceId, execId) }
|
|
1324
|
+
: definitionId === "tool_jenkins_build"
|
|
1325
|
+
? emitJenkinsBuildNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1217
1326
|
: definitionId === "tool_wecom_send_group_markdown" || definitionId === "tool_wecom_send_app_markdown"
|
|
1218
|
-
? await emitWecomMarkdownNode(workspaceRoot, flowName, uuid, instanceId, execId, definitionId)
|
|
1327
|
+
? { promptPath: await emitWecomMarkdownNode(workspaceRoot, flowName, uuid, instanceId, execId, definitionId) }
|
|
1219
1328
|
: definitionId === "control_cd_workspace"
|
|
1220
|
-
? emitCdWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1329
|
+
? { promptPath: emitCdWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId) }
|
|
1221
1330
|
: definitionId === "control_user_workspace"
|
|
1222
|
-
? emitUserWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1331
|
+
? { promptPath: emitUserWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId) }
|
|
1223
1332
|
: definitionId === "control_load_skills"
|
|
1224
|
-
? emitLoadSkillsNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1225
|
-
: emitToolPrintNode(workspaceRoot, flowName, uuid, instanceId, execId);
|
|
1333
|
+
? { promptPath: emitLoadSkillsNode(workspaceRoot, flowName, uuid, instanceId, execId) }
|
|
1334
|
+
: { promptPath: emitToolPrintNode(workspaceRoot, flowName, uuid, instanceId, execId) };
|
|
1335
|
+
const promptPath = localResult.promptPath;
|
|
1226
1336
|
writeCacheJsonForNode(workspaceRoot, flowName, uuid, instanceId, execId);
|
|
1227
1337
|
logToRunTag(workspaceRoot, flowName, uuid, "pre-process", { event: "runtime-context-node", instanceId, definitionId });
|
|
1228
1338
|
console.log(JSON.stringify({
|
|
@@ -1233,6 +1343,7 @@ async function main() {
|
|
|
1233
1343
|
subagent: "agentflow-node-executor",
|
|
1234
1344
|
optionalPromptPath: promptPath,
|
|
1235
1345
|
definitionId,
|
|
1346
|
+
...(localResult.lifecycle ? { nodeLifecycle: localResult.lifecycle } : {}),
|
|
1236
1347
|
}));
|
|
1237
1348
|
return;
|
|
1238
1349
|
} catch (e) {
|
package/bin/pipeline/run-log.mjs
CHANGED
|
@@ -21,11 +21,11 @@ const LOG_FILE = "logs/log.txt";
|
|
|
21
21
|
* @param {string} tag - 来源标识:get-ready-nodes | check-cache | pre-process | post-process | result
|
|
22
22
|
* @param {string|object} message - 文本或对象(对象会 JSON.stringify)
|
|
23
23
|
*/
|
|
24
|
-
export function logToRunTag(workspaceRoot, flowName, uuid, tag, message) {
|
|
24
|
+
export function logToRunTag(workspaceRoot, flowName, uuid, tag, message, opts = {}) {
|
|
25
25
|
if (!workspaceRoot || !flowName || !uuid) return;
|
|
26
26
|
const text = typeof message === "string" ? message : JSON.stringify(message);
|
|
27
27
|
try {
|
|
28
|
-
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
28
|
+
const runDir = opts.runDir || getRunDir(workspaceRoot, flowName, uuid);
|
|
29
29
|
const logPath = path.join(runDir, LOG_FILE);
|
|
30
30
|
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
31
31
|
const line = `[${new Date().toISOString()}] [${tag}] ${text}\n`;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* import { writeResult } from "./write-result.mjs";
|
|
13
13
|
* writeResult(workspaceRoot, flowName, uuid, instanceId, fields, options?)
|
|
14
14
|
* fields: { status, message, finishedAt?, outputPath?, branch?, cacheNotMetReason?, elapsedMs? }
|
|
15
|
-
* options: { preserveBody?: boolean, body?: string, execId?: number }
|
|
15
|
+
* options: { preserveBody?: boolean, body?: string, execId?: number, runDir?: string }
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import fs from "fs";
|
|
@@ -53,10 +53,10 @@ function getExistingBody(resultPath) {
|
|
|
53
53
|
* @param {string} uuid - 本次 run 的 uuid
|
|
54
54
|
* @param {string} instanceId - 节点 instance id
|
|
55
55
|
* @param {{ status: string, message: string, finishedAt?: string, outputPath?: string, branch?: string, cacheNotMetReason?: string, elapsedMs?: number }} fields - 必填 status、message;可选其余(elapsedMs 为节点执行耗时毫秒,供 UI 展示)
|
|
56
|
-
* @param {{ preserveBody?: boolean, body?: string, execId?: number }} [options] - preserveBody:保留已有正文;body:指定正文内容;execId:本轮 execId,缺省则从 memory
|
|
56
|
+
* @param {{ preserveBody?: boolean, body?: string, execId?: number, runDir?: string }} [options] - preserveBody:保留已有正文;body:指定正文内容;execId:本轮 execId,缺省则从 memory 读取;runDir:多用户调度时使用已解析的精确运行目录
|
|
57
57
|
*/
|
|
58
58
|
export function writeResult(workspaceRoot, flowName, uuid, instanceId, fields, options = {}) {
|
|
59
|
-
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
59
|
+
const runDir = options.runDir || getRunDir(workspaceRoot, flowName, uuid);
|
|
60
60
|
const execId = options.execId ?? loadExecId(workspaceRoot, flowName, uuid, instanceId);
|
|
61
61
|
const resultBasename = intermediateResultBasename(instanceId, execId);
|
|
62
62
|
const resultPath = path.join(runDir, intermediateDirForNode(instanceId), resultBasename);
|
|
@@ -114,7 +114,7 @@ export function writeResult(workspaceRoot, flowName, uuid, instanceId, fields, o
|
|
|
114
114
|
branch: branch ?? undefined,
|
|
115
115
|
cacheNotMetReason: cacheNotMetReason ?? undefined,
|
|
116
116
|
resultPathRel: path.relative(runDir, resultPath),
|
|
117
|
-
});
|
|
117
|
+
}, { runDir });
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
function main() {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: durable Jenkins build
|
|
3
|
+
description: |
|
|
4
|
+
Trigger one Jenkins job and durably monitor it until completion.
|
|
5
|
+
|
|
6
|
+
The node persists queue/build checkpoints and never keeps a process blocked while waiting.
|
|
7
|
+
Scheduler re-enters the same node at `pollInterval`; an existing queueId/buildNumber is reused,
|
|
8
|
+
so a resumed run does not trigger the job again. Jenkins FAILURE/ABORTED/TIMEOUT are business
|
|
9
|
+
outcomes and continue to downstream notification nodes. Authentication, configuration, and
|
|
10
|
+
repeated platform request errors fail the AgentFlow node.
|
|
11
|
+
|
|
12
|
+
Credentials are read from environment configuration. `credentialRef: team-ci` selects
|
|
13
|
+
`JENKINS_TEAM_CI_BASE_URL`, `JENKINS_TEAM_CI_USERNAME`, and `JENKINS_TEAM_CI_TOKEN`, falling
|
|
14
|
+
back to the standard `JENKINS_BASE_URL`, `JENKINS_USERNAME`, and `JENKINS_TOKEN` variables.
|
|
15
|
+
displayName: Jenkins Build
|
|
16
|
+
input:
|
|
17
|
+
- type: node
|
|
18
|
+
name: prev
|
|
19
|
+
default: ""
|
|
20
|
+
- type: text
|
|
21
|
+
name: job
|
|
22
|
+
default: ""
|
|
23
|
+
required: true
|
|
24
|
+
showOnNode: true
|
|
25
|
+
- type: text
|
|
26
|
+
name: parameters
|
|
27
|
+
default: "{}"
|
|
28
|
+
description: "Jenkins Job 参数 JSON object。"
|
|
29
|
+
showOnNode: true
|
|
30
|
+
- type: text
|
|
31
|
+
name: credentialRef
|
|
32
|
+
default: ""
|
|
33
|
+
description: "Project Deployment 中配置的 Jenkins 凭证引用;不在 flow.yaml 中填写 token。"
|
|
34
|
+
showOnNode: false
|
|
35
|
+
- type: text
|
|
36
|
+
name: pollInterval
|
|
37
|
+
default: "30s"
|
|
38
|
+
showOnNode: false
|
|
39
|
+
- type: text
|
|
40
|
+
name: timeout
|
|
41
|
+
default: "2h"
|
|
42
|
+
showOnNode: false
|
|
43
|
+
output:
|
|
44
|
+
- type: node
|
|
45
|
+
name: next
|
|
46
|
+
default: ""
|
|
47
|
+
- type: text
|
|
48
|
+
name: status
|
|
49
|
+
default: ""
|
|
50
|
+
required: true
|
|
51
|
+
showOnNode: true
|
|
52
|
+
- type: text
|
|
53
|
+
name: url
|
|
54
|
+
default: ""
|
|
55
|
+
required: true
|
|
56
|
+
description: "优先返回安装包 URL;没有安装包时返回 Jenkins Build URL。"
|
|
57
|
+
showOnNode: true
|
|
58
|
+
- type: text
|
|
59
|
+
name: qrUrl
|
|
60
|
+
default: ""
|
|
61
|
+
description: "解析到二维码时返回,否则为空。"
|
|
62
|
+
showOnNode: true
|
|
63
|
+
---
|
|
64
|
+
Trigger Jenkins job `${job}` with `${parameters}`, wait durably, then output `${status}`, `${url}`, and optional `${qrUrl}`.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
instances:
|
|
2
|
+
start:
|
|
3
|
+
definitionId: control_start
|
|
4
|
+
label: Start
|
|
5
|
+
role: normal
|
|
6
|
+
input: []
|
|
7
|
+
output:
|
|
8
|
+
- type: node
|
|
9
|
+
name: next
|
|
10
|
+
value: ""
|
|
11
|
+
body: ""
|
|
12
|
+
job:
|
|
13
|
+
definitionId: provide_str
|
|
14
|
+
label: Jenkins Job
|
|
15
|
+
role: normal
|
|
16
|
+
input: []
|
|
17
|
+
output:
|
|
18
|
+
- type: text
|
|
19
|
+
name: value
|
|
20
|
+
value: ""
|
|
21
|
+
body: ""
|
|
22
|
+
parameters:
|
|
23
|
+
definitionId: provide_str
|
|
24
|
+
label: Build Parameters
|
|
25
|
+
role: normal
|
|
26
|
+
input: []
|
|
27
|
+
output:
|
|
28
|
+
- type: text
|
|
29
|
+
name: value
|
|
30
|
+
value: "{}"
|
|
31
|
+
body: ""
|
|
32
|
+
credential_ref:
|
|
33
|
+
definitionId: provide_str
|
|
34
|
+
label: Credential Ref
|
|
35
|
+
role: normal
|
|
36
|
+
input: []
|
|
37
|
+
output:
|
|
38
|
+
- type: text
|
|
39
|
+
name: value
|
|
40
|
+
value: ""
|
|
41
|
+
body: ""
|
|
42
|
+
webhook_key:
|
|
43
|
+
definitionId: provide_str
|
|
44
|
+
label: WeCom Webhook Key
|
|
45
|
+
role: normal
|
|
46
|
+
input: []
|
|
47
|
+
output:
|
|
48
|
+
- type: text
|
|
49
|
+
name: value
|
|
50
|
+
value: ""
|
|
51
|
+
body: ""
|
|
52
|
+
jenkins_build:
|
|
53
|
+
definitionId: tool_jenkins_build
|
|
54
|
+
label: Jenkins Build
|
|
55
|
+
role: normal
|
|
56
|
+
input:
|
|
57
|
+
- type: node
|
|
58
|
+
name: prev
|
|
59
|
+
value: ""
|
|
60
|
+
- type: text
|
|
61
|
+
name: job
|
|
62
|
+
value: ""
|
|
63
|
+
- type: text
|
|
64
|
+
name: parameters
|
|
65
|
+
value: "{}"
|
|
66
|
+
- type: text
|
|
67
|
+
name: credentialRef
|
|
68
|
+
value: ""
|
|
69
|
+
- type: text
|
|
70
|
+
name: pollInterval
|
|
71
|
+
value: "30s"
|
|
72
|
+
- type: text
|
|
73
|
+
name: timeout
|
|
74
|
+
value: "2h"
|
|
75
|
+
output:
|
|
76
|
+
- type: node
|
|
77
|
+
name: next
|
|
78
|
+
value: ""
|
|
79
|
+
- type: text
|
|
80
|
+
name: status
|
|
81
|
+
value: ""
|
|
82
|
+
- type: text
|
|
83
|
+
name: url
|
|
84
|
+
value: ""
|
|
85
|
+
- type: text
|
|
86
|
+
name: qrUrl
|
|
87
|
+
value: ""
|
|
88
|
+
body: ""
|
|
89
|
+
format_notification:
|
|
90
|
+
definitionId: tool_nodejs
|
|
91
|
+
label: Format Build Notification
|
|
92
|
+
role: normal
|
|
93
|
+
input:
|
|
94
|
+
- type: node
|
|
95
|
+
name: prev
|
|
96
|
+
value: ""
|
|
97
|
+
- type: text
|
|
98
|
+
name: status
|
|
99
|
+
value: ""
|
|
100
|
+
- type: text
|
|
101
|
+
name: url
|
|
102
|
+
value: ""
|
|
103
|
+
- type: text
|
|
104
|
+
name: qrUrl
|
|
105
|
+
value: ""
|
|
106
|
+
output:
|
|
107
|
+
- type: node
|
|
108
|
+
name: next
|
|
109
|
+
value: ""
|
|
110
|
+
- type: text
|
|
111
|
+
name: markdown
|
|
112
|
+
value: ""
|
|
113
|
+
script: >-
|
|
114
|
+
node -e "const fs=require('fs');const [status,url,qr,out]=process.argv.slice(1);const lines=['## Jenkins 构建结果','> 状态:'+status];if(url)lines.push('[查看构建或产物]('+url+')');if(qr)lines.push('[查看二维码]('+qr+')');fs.writeFileSync(out,lines.join('\n\n'));" ${status} ${url} ${qrUrl} ${markdown}
|
|
115
|
+
body: ""
|
|
116
|
+
notify:
|
|
117
|
+
definitionId: tool_wecom_send_group_markdown
|
|
118
|
+
label: WeCom Notification
|
|
119
|
+
role: normal
|
|
120
|
+
input:
|
|
121
|
+
- type: node
|
|
122
|
+
name: prev
|
|
123
|
+
value: ""
|
|
124
|
+
- type: text
|
|
125
|
+
name: markdown
|
|
126
|
+
value: ""
|
|
127
|
+
- type: text
|
|
128
|
+
name: webhookUrl
|
|
129
|
+
value: ""
|
|
130
|
+
- type: text
|
|
131
|
+
name: webhookKey
|
|
132
|
+
value: ""
|
|
133
|
+
output:
|
|
134
|
+
- type: node
|
|
135
|
+
name: next
|
|
136
|
+
value: ""
|
|
137
|
+
- type: bool
|
|
138
|
+
name: sent
|
|
139
|
+
value: ""
|
|
140
|
+
- type: text
|
|
141
|
+
name: message
|
|
142
|
+
value: ""
|
|
143
|
+
- type: text
|
|
144
|
+
name: response
|
|
145
|
+
value: ""
|
|
146
|
+
body: ""
|
|
147
|
+
end:
|
|
148
|
+
definitionId: control_end
|
|
149
|
+
label: End
|
|
150
|
+
role: normal
|
|
151
|
+
input:
|
|
152
|
+
- type: node
|
|
153
|
+
name: prev
|
|
154
|
+
value: ""
|
|
155
|
+
output: []
|
|
156
|
+
body: ""
|
|
157
|
+
edges:
|
|
158
|
+
- source: start
|
|
159
|
+
target: jenkins_build
|
|
160
|
+
sourceHandle: output-0
|
|
161
|
+
targetHandle: input-0
|
|
162
|
+
- source: job
|
|
163
|
+
target: jenkins_build
|
|
164
|
+
sourceHandle: output-0
|
|
165
|
+
targetHandle: input-1
|
|
166
|
+
- source: parameters
|
|
167
|
+
target: jenkins_build
|
|
168
|
+
sourceHandle: output-0
|
|
169
|
+
targetHandle: input-2
|
|
170
|
+
- source: credential_ref
|
|
171
|
+
target: jenkins_build
|
|
172
|
+
sourceHandle: output-0
|
|
173
|
+
targetHandle: input-3
|
|
174
|
+
- source: jenkins_build
|
|
175
|
+
target: format_notification
|
|
176
|
+
sourceHandle: output-0
|
|
177
|
+
targetHandle: input-0
|
|
178
|
+
- source: jenkins_build
|
|
179
|
+
target: format_notification
|
|
180
|
+
sourceHandle: output-1
|
|
181
|
+
targetHandle: input-1
|
|
182
|
+
- source: jenkins_build
|
|
183
|
+
target: format_notification
|
|
184
|
+
sourceHandle: output-2
|
|
185
|
+
targetHandle: input-2
|
|
186
|
+
- source: jenkins_build
|
|
187
|
+
target: format_notification
|
|
188
|
+
sourceHandle: output-3
|
|
189
|
+
targetHandle: input-3
|
|
190
|
+
- source: format_notification
|
|
191
|
+
target: notify
|
|
192
|
+
sourceHandle: output-0
|
|
193
|
+
targetHandle: input-0
|
|
194
|
+
- source: format_notification
|
|
195
|
+
target: notify
|
|
196
|
+
sourceHandle: output-1
|
|
197
|
+
targetHandle: input-1
|
|
198
|
+
- source: webhook_key
|
|
199
|
+
target: notify
|
|
200
|
+
sourceHandle: output-0
|
|
201
|
+
targetHandle: input-3
|
|
202
|
+
- source: notify
|
|
203
|
+
target: end
|
|
204
|
+
sourceHandle: output-0
|
|
205
|
+
targetHandle: input-0
|
|
206
|
+
ui:
|
|
207
|
+
nodePositions:
|
|
208
|
+
start: { x: -460, y: 60 }
|
|
209
|
+
job: { x: -450, y: 180 }
|
|
210
|
+
parameters: { x: -450, y: 300 }
|
|
211
|
+
credential_ref: { x: -450, y: 420 }
|
|
212
|
+
webhook_key: { x: 350, y: 360 }
|
|
213
|
+
jenkins_build: { x: -120, y: 100 }
|
|
214
|
+
format_notification: { x: 210, y: 100 }
|
|
215
|
+
notify: { x: 530, y: 100 }
|
|
216
|
+
end: { x: 830, y: 100 }
|
|
217
|
+
description: Jenkins 构建完成后发送企业微信通知
|