@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jira-deploy/core",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "repository": {
@@ -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(' 確保每次都會從 build 開始,先執行: Planning');
847
+ log.push(' 先執行 Planning,確保部署流程從可簽核狀態重新開始');
760
848
  await jira.transitionByName(issueKey, 'Planning');
761
- await notifier.notify(issueKey, '確保每次都會從 Planning 開始,準備進入部署流程');
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