@jira-deploy/core 1.0.13 → 1.0.15
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/package.json +1 -1
- package/tools/grayrelease.js +95 -4
- package/tools/index.js +5 -0
package/package.json
CHANGED
package/tools/grayrelease.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* - auto_grayrelease
|
|
6
6
|
* - deploy_grayrelease
|
|
7
7
|
* - get_grayrelease_status
|
|
8
|
+
* - wait_build_result
|
|
8
9
|
* - continue_grayrelease
|
|
9
10
|
*/
|
|
10
11
|
import {
|
|
@@ -332,6 +333,34 @@ export function getGrayReleaseToolDefinitions() {
|
|
|
332
333
|
},
|
|
333
334
|
},
|
|
334
335
|
},
|
|
336
|
+
{
|
|
337
|
+
name: 'wait_build_result',
|
|
338
|
+
description:
|
|
339
|
+
'輪詢等待 Jira issue 的 Build 結果欄位變成 pass 或 fail。通常接在 build_ticket 成功觸發 Jenkins build 後使用,確認 pass 後再呼叫 deploy_grayrelease;不可用 deploy_grayrelease 取代等待 build pass。',
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: 'object',
|
|
342
|
+
required: ['issueKey'],
|
|
343
|
+
properties: {
|
|
344
|
+
issueKey: {
|
|
345
|
+
type: 'string',
|
|
346
|
+
description: '要等待 build 結果的 issue key,例如 GrayRelease 單 CID-822',
|
|
347
|
+
},
|
|
348
|
+
resultFieldId: {
|
|
349
|
+
type: 'string',
|
|
350
|
+
description: '(選填) Build 結果欄位 ID,預設 customfield_13432',
|
|
351
|
+
default: GRAY_RELEASE_FIELD_IDS.buildResult,
|
|
352
|
+
},
|
|
353
|
+
pollIntervalMs: {
|
|
354
|
+
type: 'number',
|
|
355
|
+
description: '輪詢間隔毫秒,預設讀 POLL_INTERVAL_MS',
|
|
356
|
+
},
|
|
357
|
+
timeoutMs: {
|
|
358
|
+
type: 'number',
|
|
359
|
+
description: '最長等待毫秒,預設讀 POLL_TIMEOUT_MS',
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
},
|
|
335
364
|
{
|
|
336
365
|
name: 'continue_grayrelease',
|
|
337
366
|
description:
|
|
@@ -614,6 +643,65 @@ export async function handleGetGrayReleaseStatus(args, { jira }) {
|
|
|
614
643
|
}
|
|
615
644
|
}
|
|
616
645
|
|
|
646
|
+
export async function handleWaitBuildResult(args, ctx) {
|
|
647
|
+
const { issueKey } = args;
|
|
648
|
+
const { jira } = ctx;
|
|
649
|
+
const fieldId = args.resultFieldId ?? GRAY_RELEASE_FIELD_IDS.buildResult;
|
|
650
|
+
const intervalMs = args.pollIntervalMs ?? getPollIntervalMs();
|
|
651
|
+
const timeoutMs = args.timeoutMs ?? getPollTimeoutMs();
|
|
652
|
+
const startedAt = Date.now();
|
|
653
|
+
const deadline = Date.now() + timeoutMs;
|
|
654
|
+
let attempts = 0;
|
|
655
|
+
let lastValue;
|
|
656
|
+
let currentStatus;
|
|
657
|
+
|
|
658
|
+
try {
|
|
659
|
+
while (true) {
|
|
660
|
+
attempts++;
|
|
661
|
+
const issue = await jira.getIssue(issueKey);
|
|
662
|
+
currentStatus = issue.fields.status?.name;
|
|
663
|
+
const fields = await jira.getIssueFields(issueKey, [fieldId]);
|
|
664
|
+
const raw = fields[fieldId];
|
|
665
|
+
lastValue = raw?.value ?? raw;
|
|
666
|
+
|
|
667
|
+
progress(ctx, {
|
|
668
|
+
phase: 'polling',
|
|
669
|
+
title: '等待 Build 結果',
|
|
670
|
+
detail: `${fieldId}: ${lastValue ?? 'empty'}`,
|
|
671
|
+
issueKey,
|
|
672
|
+
currentStatus,
|
|
673
|
+
attempts,
|
|
674
|
+
elapsedMs: Date.now() - startedAt,
|
|
675
|
+
timeoutMs,
|
|
676
|
+
nextPollMs: intervalMs,
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
if (isPassingResult(lastValue)) {
|
|
680
|
+
return ok({
|
|
681
|
+
issueKey,
|
|
682
|
+
fieldId,
|
|
683
|
+
result: lastValue,
|
|
684
|
+
buildResult: lastValue,
|
|
685
|
+
currentStatus,
|
|
686
|
+
attempts,
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
if (isFailingResult(lastValue)) {
|
|
691
|
+
return error(`Build 失敗,${fieldId}: ${lastValue}`);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
if (Date.now() >= deadline) {
|
|
695
|
+
return error(`Build 結果等待逾時,${fieldId}: ${lastValue ?? 'empty'}`);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
await sleep(intervalMs);
|
|
699
|
+
}
|
|
700
|
+
} catch (err) {
|
|
701
|
+
return error(`wait_build_result 失敗: ${err.message}`);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
617
705
|
/**
|
|
618
706
|
* 執行 GrayRelease 部署流程,不觸發 rebuild。
|
|
619
707
|
*/
|
|
@@ -756,10 +844,10 @@ async function executeGrayReleaseDeployFlow(issueKey, ctx) {
|
|
|
756
844
|
}
|
|
757
845
|
|
|
758
846
|
log.push(`🚀 開始執行 GrayRelease Deploy - 環境: ${environment.toUpperCase()}`);
|
|
759
|
-
log.push('
|
|
847
|
+
log.push(' 先執行 Planning,確保部署流程從可簽核狀態重新開始');
|
|
760
848
|
await jira.transitionByName(issueKey, 'Planning');
|
|
761
|
-
await notifier.notify(issueKey, '
|
|
762
|
-
|
|
849
|
+
await notifier.notify(issueKey, '開始執行 GrayRelease deploy 流程,先回到 Planning');
|
|
850
|
+
|
|
763
851
|
while (true) {
|
|
764
852
|
const issue = await jira.getIssue(issueKey);
|
|
765
853
|
const currentStatus = issue.fields.status.name;
|
|
@@ -867,6 +955,9 @@ async function executeAutoGrayReleaseFlow(issueKey, options, ctx) {
|
|
|
867
955
|
}
|
|
868
956
|
|
|
869
957
|
log.push(`🚀 開始執行 GrayRelease 流程 - 環境: ${environment.toUpperCase()}`);
|
|
958
|
+
log.push(' 先執行 PLANNING,確保流程從頭開始');
|
|
959
|
+
await jira.transitionByName(issueKey, 'Planning');
|
|
960
|
+
await notifier.notify(issueKey, '開始自動執行 GrayRelease 流程,從 PLANNING 開始');
|
|
870
961
|
|
|
871
962
|
while (true) {
|
|
872
963
|
const issue = await jira.getIssue(issueKey);
|
|
@@ -1154,7 +1245,7 @@ async function handleGrayReleaseApproval(issueKey, environment, systemCode, ctx)
|
|
|
1154
1245
|
|
|
1155
1246
|
// UAT: assign first reviewer → 等待留言 → 轉 final approver → 等待 approve
|
|
1156
1247
|
if (env === 'uat') {
|
|
1157
|
-
const {commentReviewerAlias, finalApproverAlias} = getGrayReleaseUatApprovers();
|
|
1248
|
+
const { commentReviewerAlias, finalApproverAlias } = getGrayReleaseUatApprovers();
|
|
1158
1249
|
const commentReviewerAccountId = resolveAccountId(commentReviewerAlias);
|
|
1159
1250
|
if (!commentReviewerAccountId) {
|
|
1160
1251
|
throw new Error(`找不到 UAT 第一階段簽核人 accountId,請設定 GRAYRELEASE_UAT_COMMENT_REVIEWER_ALIAS 或 release.grayReleaseUatApprovers.commentReviewerAlias`);
|
package/tools/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
handleAutoGrayRelease,
|
|
21
21
|
handleDeployGrayRelease,
|
|
22
22
|
handleGetGrayReleaseStatus,
|
|
23
|
+
handleWaitBuildResult,
|
|
23
24
|
handleContinueGrayRelease,
|
|
24
25
|
} from './grayrelease.js';
|
|
25
26
|
import {
|
|
@@ -44,6 +45,7 @@ const READ_ONLY_TOOL_NAMES = new Set([
|
|
|
44
45
|
'get_release_manager',
|
|
45
46
|
'wait_for_comment',
|
|
46
47
|
'get_grayrelease_status',
|
|
48
|
+
'wait_build_result',
|
|
47
49
|
]);
|
|
48
50
|
|
|
49
51
|
function withToolAnnotations(tools) {
|
|
@@ -412,6 +414,9 @@ export async function executeTool(name, args, deps) {
|
|
|
412
414
|
case 'get_grayrelease_status':
|
|
413
415
|
return handleGetGrayReleaseStatus(args, { jira });
|
|
414
416
|
|
|
417
|
+
case 'wait_build_result':
|
|
418
|
+
return handleWaitBuildResult(args, { jira, progress });
|
|
419
|
+
|
|
415
420
|
case 'continue_grayrelease':
|
|
416
421
|
return handleContinueGrayRelease(args, { jira, notifier, progress });
|
|
417
422
|
|