@jira-deploy/core 1.0.2 → 1.0.4

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.
@@ -100,7 +100,7 @@ export const NOTES_TEMPLATES = {
100
100
  5. 若需搭配不同分支的 Jenkins pipeline 執行,請設定 CID_jenkinsfile_branch,預設為 master。
101
101
  6. 有任何額外參數請以 json 格式填入 CID_extra_vars 欄位。
102
102
  7. 集群佈署僅支援相同環境與相同 CID_extra_vars 佈署。
103
- 8. 集群佈署時,CID_deploy_result 代表整個佈署流程的開始或成功與否。
103
+ 8. 集群佈署時,customfield_13433(CID_deploy_result) 代表整個佈署流程的開始或成功與否。
104
104
  9. 若佈署時出現任一失敗則將終止整個集群佈署。
105
105
  10. CID_grayrelease_version 版本號不支援 '/',請務必注意以 '-' 取代。`,
106
106
  };
@@ -22,7 +22,7 @@ export const DEPT_CODES = {
22
22
  export const SUPPORTED_ENVS = {
23
23
  library: ['dev', 'stg', 'uat', 'prd'],
24
24
  ci: ['dev', 'stg'],
25
- cd: ['stg', 'uat', 'prd/dr', 'prd', 'dr'],
25
+ cd: ['dev', 'stg', 'uat', 'prd/dr', 'prd', 'dr'],
26
26
  grayRelease: ['dev', 'stg', 'uat'],
27
27
  };
28
28
 
@@ -3,7 +3,7 @@
3
3
  * 所有 customfield_XXXXX 在這裡集中管理
4
4
  */
5
5
 
6
- import {ASSIGNEE_DEFAULTS} from './defaults.js';
6
+ import { ASSIGNEE_DEFAULTS } from './defaults.js';
7
7
 
8
8
  // ============ 共用欄位 (所有 Issue Type 都用) ============
9
9
  export const SHARED_FIELD_IDS = {
@@ -24,7 +24,7 @@ export const SHARED_FIELD_IDS = {
24
24
  authManagerSign: 'customfield_13904',
25
25
  releaseInfo: 'customfield_13906',
26
26
  };
27
-
27
+
28
28
  // ============ CD 專用欄位 ============
29
29
  export const CD_FIELD_IDS = {
30
30
  ...SHARED_FIELD_IDS,
@@ -60,4 +60,7 @@ export const GRAY_RELEASE_FIELD_IDS = {
60
60
  grayReleaseVersion: 'customfield_14700',
61
61
  clusterList: 'customfield_14701',
62
62
  grayReleaseNotes: 'customfield_14511',
63
+ // Field names resolved to customfield IDs at runtime.
64
+ buildResult: 'customfield_13432',
65
+ deployResult: 'customfield_13433',
63
66
  };
package/dry-run.js CHANGED
@@ -24,15 +24,19 @@
24
24
  * node src/dry-run.js create_ci_ticket '{"systemCode":"IBK","relatesTo":["CID-1708"]}'
25
25
  * node src/dry-run.js create_ci_ticket '{"systemCode":"IBK","relatesTo":["CID-1178","CID-1182"]}'
26
26
  * node src/dry-run.js build_ticket '{"issueKey":"CID-1709"}' --live
27
+ * node src/dry-run.js wait_to_dev '{"issueKey":"CID-1709"}' --live
27
28
  * node src/dry-run.js wait_to_stg '{"issueKey":"CID-1709"}' --live
28
29
  *
29
30
  * # CD 票
31
+ * node src/dry-run.js create_cd_ticket '{"systemCode":"IBK","environment":"dev","ciTicket":"CID-1709"}'
30
32
  * node src/dry-run.js create_cd_ticket '{"systemCode":"IBK","environment":"stg","ciTicket":"CID-1709"}'
31
33
  * node src/dry-run.js create_cd_ticket '{"systemCode":"CWA","environment":"prd","ciTicket":"CID-1709","metaTest":true}'
32
34
  * node src/dry-run.js create_cd_ticket '{"systemCode":"IBK","environment":"prd","ciTicket":"CID-1709","metaTest":true}' --live
35
+ * node src/dry-run.js prepare_cd_deployment '{"issueKey":"CID-1710","environment":"dev"}' --live
33
36
  * node src/dry-run.js prepare_cd_deployment '{"issueKey":"CID-1710","environment":"stg"}' --live
34
37
  *
35
38
  * # Deployment sub-task 觸發(新)
39
+ * node src/dry-run.js trigger_deployment '{"cdIssueKey":"CID-1710","environment":"dev"}' --live
36
40
  * node src/dry-run.js trigger_deployment '{"cdIssueKey":"CID-1710","environment":"stg"}' --live
37
41
  * node src/dry-run.js trigger_deployment '{"cdIssueKey":"CID-1713","environment":"uat"}' --live
38
42
  * node src/dry-run.js trigger_deployment '{"cdIssueKey":"CID-1716","environment":"stg","applyForClose":true}' --live
package/jira-client.js CHANGED
@@ -21,6 +21,7 @@ export class JiraClient {
21
21
  },
22
22
  });
23
23
  this.dryRun = DRY_RUN;
24
+ this.fieldIdByName = new Map();
24
25
  }
25
26
 
26
27
  // 建立 issue
@@ -93,6 +94,18 @@ export class JiraClient {
93
94
  return res.data.fields;
94
95
  }
95
96
 
97
+ async getFieldIdByName(fieldName) {
98
+ if (this.fieldIdByName.has(fieldName)) {
99
+ return this.fieldIdByName.get(fieldName);
100
+ }
101
+
102
+ const res = await this.http.get('/field');
103
+ const field = (res.data ?? []).find((item) => item.id === fieldName || item.name === fieldName);
104
+ const fieldId = field?.id ?? fieldName;
105
+ this.fieldIdByName.set(fieldName, fieldId);
106
+ return fieldId;
107
+ }
108
+
96
109
  // 依 ID 直接切換狀態(不查名稱,適合 race condition 處理)
97
110
  async transitionById(issueKey, transitionId) {
98
111
  if (this.dryRun) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jira-deploy/core",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "repository": {
package/poller.js CHANGED
@@ -21,6 +21,7 @@ export class Poller {
21
21
  async waitForStatus(issueKey, targetStatus, options = {}) {
22
22
  const intervalMs = options.intervalMs ?? parseInt(process.env.POLL_INTERVAL_MS ?? '30000');
23
23
  const timeoutMs = options.timeoutMs ?? parseInt(process.env.POLL_TIMEOUT_MS ?? '3600000');
24
+ const progress = typeof options.onProgress === 'function' ? options.onProgress : () => {};
24
25
 
25
26
  const startTime = Date.now();
26
27
  let attempts = 0;
@@ -34,20 +35,32 @@ export class Poller {
34
35
  attempts++;
35
36
  const issue = await this.jira.getIssue(issueKey);
36
37
  const currentStatus = issue.fields.status.name;
38
+ const elapsedMs = Date.now() - startTime;
37
39
 
38
40
  console.error(`[Poller] attempt #${attempts} — current: "${currentStatus}"`);
41
+ progress({
42
+ phase: 'polling',
43
+ title: `等待 ${issueKey} 狀態`,
44
+ detail: `target=${targetStatus}`,
45
+ issueKey,
46
+ currentStatus,
47
+ targetStatus,
48
+ attempts,
49
+ elapsedMs,
50
+ timeoutMs,
51
+ nextPollMs: intervalMs,
52
+ });
39
53
 
40
54
  if (currentStatus.toLowerCase() === targetStatus.toLowerCase()) {
41
55
  return {
42
56
  issueKey,
43
57
  status: currentStatus,
44
- elapsedMs: Date.now() - startTime,
58
+ elapsedMs,
45
59
  attempts,
46
60
  };
47
61
  }
48
62
 
49
- const elapsed = Date.now() - startTime;
50
- if (elapsed >= timeoutMs) {
63
+ if (elapsedMs >= timeoutMs) {
51
64
  throw new Error(
52
65
  `Timeout waiting for "${issueKey}" to reach "${targetStatus}". ` +
53
66
  `Last status: "${currentStatus}" after ${attempts} attempts.`,
package/tools/cd.js CHANGED
@@ -27,7 +27,9 @@ export function getCDToolDefinitions() {
27
27
  return [
28
28
  {
29
29
  name: 'create_cd_ticket',
30
- description: '建立 CD Deploy 上版單。專用工具,提前驗證必填欄位和叢集配置',
30
+ description:
31
+ '建立 CD Deploy 上版單。只有使用者明確要求或確認要建立 CD Deploy/CD 單時才使用;' +
32
+ '模糊 deploy/部署且上下文是 GrayRelease 時,應先詢問是否改用 deploy_grayrelease,不可直接開 CD 單。',
31
33
  inputSchema: {
32
34
  type: 'object',
33
35
  required: ['systemCode', 'environment'],
@@ -40,7 +42,7 @@ export function getCDToolDefinitions() {
40
42
  environment: {
41
43
  type: 'string',
42
44
  enum: Object.keys(ENV_CODES),
43
- description: '部署環境,必填,預設為 stg',
45
+ description: '部署環境,必填。若使用者未指定且不是已確認的 workflow,應先詢問,不可因 deploy/部署模糊指令自行補 stg',
44
46
  },
45
47
  isClusterDeploy: {
46
48
  type: 'boolean',
@@ -54,11 +56,11 @@ export function getCDToolDefinitions() {
54
56
  ciTicket: {
55
57
  type: 'string',
56
58
  description:
57
- '關聯的 CI 單 issue key,例如 CID-1677。自動:① 取 release_version 填入 summary/CID_deploy_version ② 查 CI 所有 relates Library 單,各自取 CID_branch 找 LBPRJ 版本頁 → 加 Web Link',
59
+ '關聯的 CI 單 issue key,例如 CID-1677;必須是 CI 單,不可使用 GrayRelease 單。自動:① 取 release_version 填入 summary/CID_deploy_version ② 查 CI 所有 relates Library 單,各自取 CID_branch 找 LBPRJ 版本頁 → 加 Web Link',
58
60
  },
59
61
  linkedCiKey: {
60
62
  type: 'string',
61
- description: '關聯的 CI 單 issue key;等同 ciTicket,保留給 agent/CLI workflow 使用',
63
+ description: '關聯的 CI 單 issue key;等同 ciTicket,保留給 agent/CLI workflow 使用;不可使用 GrayRelease 單',
62
64
  },
63
65
  clusterDeploy: {
64
66
  type: 'string',
@@ -274,7 +276,7 @@ export async function handleCreateCDTicket(args, {jira, notifier}) {
274
276
 
275
277
  await notifier.notify(
276
278
  issue.key,
277
- `CD Deploy 單已建立。系統: ${args.systemCode}, 環境: ${args.environment}, Cluster: ${args.clusterDeploy}`,
279
+ `CD Deploy 單已建立。系統: ${normalizedArgs.systemCode}, 環境: ${normalizedArgs.environment}, Cluster: ${serverList.join(',')}`,
278
280
  );
279
281
  return ok({
280
282
  issueKey: issue.key,
@@ -283,6 +285,8 @@ export async function handleCreateCDTicket(args, {jira, notifier}) {
283
285
  type: 'CD Deploy',
284
286
  system: normalizedArgs.systemCode,
285
287
  environment: normalizedArgs.environment,
288
+ clusterDeploy: serverList,
289
+ isClusterDeploy: normalizedArgs.isClusterDeploy,
286
290
  });
287
291
  } catch (err) {
288
292
  return error(`無法建立 CD 單: ${err.message}`);