@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.
- package/constants/defaults.js +1 -1
- package/constants/environments.js +1 -1
- package/constants/field-ids.js +5 -2
- package/dry-run.js +4 -0
- package/jira-client.js +13 -0
- package/package.json +1 -1
- package/poller.js +16 -3
- package/tools/cd.js +9 -5
- package/tools/grayrelease.js +1046 -15
- package/tools/index.js +322 -104
- package/tools/library.js +2 -1
- package/tools/release.js +48 -21
- package/tools/workflows.js +20 -0
- package/tools.test.js +932 -27
package/constants/defaults.js
CHANGED
|
@@ -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
|
|
package/constants/field-ids.js
CHANGED
|
@@ -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
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
|
|
58
|
+
elapsedMs,
|
|
45
59
|
attempts,
|
|
46
60
|
};
|
|
47
61
|
}
|
|
48
62
|
|
|
49
|
-
|
|
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:
|
|
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: '
|
|
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
|
|
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 單已建立。系統: ${
|
|
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}`);
|