@jira-deploy/core 1.0.6 → 1.0.8
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 +2 -2
- package/tools/grayrelease.js +9 -11
- package/tools/jabber.js +29 -4
- package/tools/jabber.test.js +35 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jira-deploy/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"repository": {
|
|
@@ -30,6 +30,6 @@
|
|
|
30
30
|
"dotenv": "^16.3.0"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
|
-
"test": "node --test tools.test.js"
|
|
33
|
+
"test": "node --test tools.test.js tools/jabber.test.js"
|
|
34
34
|
}
|
|
35
35
|
}
|
package/tools/grayrelease.js
CHANGED
|
@@ -132,7 +132,7 @@ async function findTransitionByName(issueKey, transitionName, jira) {
|
|
|
132
132
|
));
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
async function waitForGrayReleaseResult(issueKey, fieldId, label, jira, onProgress = () => {}) {
|
|
135
|
+
async function waitForGrayReleaseResult(issueKey, fieldId, label, jira, onProgress = () => { }) {
|
|
136
136
|
const intervalMs = getPollIntervalMs();
|
|
137
137
|
const timeoutMs = getPollTimeoutMs();
|
|
138
138
|
const startedAt = Date.now();
|
|
@@ -983,7 +983,7 @@ async function executeAutoGrayReleaseFlow(issueKey, options, ctx) {
|
|
|
983
983
|
|
|
984
984
|
async function runGrayReleaseDeployStep(issueKey, systemCode, ctx, log) {
|
|
985
985
|
const { jira, notifier } = ctx;
|
|
986
|
-
const needSwitch = await needSwitchExecutionNode(issueKey, systemCode, jira);
|
|
986
|
+
const needSwitch = await needSwitchExecutionNode(issueKey, systemCode, jira, log);
|
|
987
987
|
|
|
988
988
|
if (needSwitch) {
|
|
989
989
|
log.push(' 執行: Switch Execution Node');
|
|
@@ -1011,7 +1011,7 @@ async function runGrayReleaseDeployStep(issueKey, systemCode, ctx, log) {
|
|
|
1011
1011
|
// 若超時則回傳「部署中」訊息,請使用者稍後繼續。
|
|
1012
1012
|
// 每 3 分鐘 輪詢一次
|
|
1013
1013
|
const DEPLOY_WAIT_MS = Math.min(getPollTimeoutMs(), 10 * 60 * 1000);
|
|
1014
|
-
const DEPLOY_POLL_MS = Math.min(getPollIntervalMs(),
|
|
1014
|
+
const DEPLOY_POLL_MS = Math.min(getPollIntervalMs(), 3 * 60 * 1000);
|
|
1015
1015
|
const deployDeadline = Date.now() + DEPLOY_WAIT_MS;
|
|
1016
1016
|
let deployCompleted = false;
|
|
1017
1017
|
let attempts = 0;
|
|
@@ -1132,7 +1132,7 @@ async function handleGrayReleaseApproval(issueKey, environment, systemCode, ctx)
|
|
|
1132
1132
|
await handleSendJabberMessage(
|
|
1133
1133
|
{
|
|
1134
1134
|
to: jabberTo,
|
|
1135
|
-
message: `[GrayRelease 簽核通知] ${issueKey} 需要您的簽核。環境: STG\n${process.env.JIRA_BASE_URL}/browse/${issueKey}`,
|
|
1135
|
+
message: `[GrayRelease 簽核通知] ${issueKey} 需要您的簽核。環境: STG,系統: ${systemCode}\n${process.env.JIRA_BASE_URL}/browse/${issueKey}`,
|
|
1136
1136
|
},
|
|
1137
1137
|
{},
|
|
1138
1138
|
);
|
|
@@ -1176,7 +1176,7 @@ async function handleGrayReleaseApproval(issueKey, environment, systemCode, ctx)
|
|
|
1176
1176
|
await handleSendJabberMessage(
|
|
1177
1177
|
{
|
|
1178
1178
|
to: jamesJabber,
|
|
1179
|
-
message: `[GrayRelease 簽核通知] ${issueKey} 需要您的簽核並留言確認。環境: UAT\n${process.env.JIRA_BASE_URL}/browse/${issueKey}`,
|
|
1179
|
+
message: `[GrayRelease 簽核通知] ${issueKey} 需要您的簽核並留言確認。環境: UAT,系統: ${systemCode}\n${process.env.JIRA_BASE_URL}/browse/${issueKey}`,
|
|
1180
1180
|
},
|
|
1181
1181
|
{},
|
|
1182
1182
|
);
|
|
@@ -1226,7 +1226,7 @@ async function handleGrayReleaseApproval(issueKey, environment, systemCode, ctx)
|
|
|
1226
1226
|
await handleSendJabberMessage(
|
|
1227
1227
|
{
|
|
1228
1228
|
to: solarJabber,
|
|
1229
|
-
message: `[GrayRelease 簽核通知] ${issueKey} 已由 James Yu 確認,需要您的最終簽核。環境: UAT\n${process.env.JIRA_BASE_URL}/browse/${issueKey}`,
|
|
1229
|
+
message: `[GrayRelease 簽核通知] ${issueKey} 已由 James Yu 確認,需要您的最終簽核。環境: UAT,系統: ${systemCode}\n${process.env.JIRA_BASE_URL}/browse/${issueKey}`,
|
|
1230
1230
|
},
|
|
1231
1231
|
{},
|
|
1232
1232
|
);
|
|
@@ -1249,7 +1249,7 @@ async function handleGrayReleaseApproval(issueKey, environment, systemCode, ctx)
|
|
|
1249
1249
|
* 判斷是否需要執行 Switch Execution Node
|
|
1250
1250
|
* 規則:查詢同系統上次 CD or GrayRelease 部署的環境群組,若與本次不同則需切換
|
|
1251
1251
|
*/
|
|
1252
|
-
async function needSwitchExecutionNode(issueKey, systemCode, jira) {
|
|
1252
|
+
async function needSwitchExecutionNode(issueKey, systemCode, jira, log) {
|
|
1253
1253
|
if (await hasRecentSwitchExecutionNodeComment(issueKey, systemCode, jira)) {
|
|
1254
1254
|
return false;
|
|
1255
1255
|
}
|
|
@@ -1263,10 +1263,11 @@ async function needSwitchExecutionNode(issueKey, systemCode, jira) {
|
|
|
1263
1263
|
const jql_cd = `project = CID AND (issuetype = CD OR issuetype = GrayRelease) AND text ~ "${systemCode}" AND status = Done AND issueKey != "${issueKey}" ORDER BY updated DESC`;
|
|
1264
1264
|
|
|
1265
1265
|
try {
|
|
1266
|
+
log.push(` before 查詢歷史 CD/GrayRelease 單,判斷是否需要切換 Execution Node`);
|
|
1266
1267
|
const cdResults = await jira.searchIssues(jql_cd, ['customfield_13436', 'updated'], 1);
|
|
1268
|
+
log.push(` after 查詢歷史 CD/GrayRelease 單,判斷是否需要切換 Execution Node`, cdResults);
|
|
1267
1269
|
const cdIssue = cdResults[0] ?? null;
|
|
1268
1270
|
|
|
1269
|
-
|
|
1270
1271
|
// 查不到歷史 → 保守執行 Switch
|
|
1271
1272
|
if (!cdIssue) {
|
|
1272
1273
|
return true;
|
|
@@ -1290,9 +1291,6 @@ async function waitForSwitchExecutionNode(issueKey, systemCode, jira) {
|
|
|
1290
1291
|
const deadline = Date.now() + waitMs;
|
|
1291
1292
|
|
|
1292
1293
|
while (true) {
|
|
1293
|
-
if (await hasRecentSwitchExecutionNodeComment(issueKey, systemCode, jira)) {
|
|
1294
|
-
return;
|
|
1295
|
-
}
|
|
1296
1294
|
|
|
1297
1295
|
if (Date.now() >= deadline) {
|
|
1298
1296
|
return;
|
package/tools/jabber.js
CHANGED
|
@@ -7,11 +7,36 @@ import fs from 'fs';
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import {error, ok} from './helpers.js';
|
|
9
9
|
|
|
10
|
-
function
|
|
10
|
+
function realpathOrNull(filePath) {
|
|
11
|
+
try {
|
|
12
|
+
return fs.realpathSync(filePath);
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function unique(values) {
|
|
19
|
+
return [...new Set(values.filter(Boolean))];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resolveJabberNotifyScriptPath({
|
|
23
|
+
env = process.env,
|
|
24
|
+
execPath = process.execPath,
|
|
25
|
+
cwd = process.cwd(),
|
|
26
|
+
} = {}) {
|
|
27
|
+
if (env.JABBER_NOTIFY_SCRIPT) {
|
|
28
|
+
return env.JABBER_NOTIFY_SCRIPT;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const resolvedExecPath = realpathOrNull(execPath);
|
|
11
32
|
const candidates = [
|
|
12
|
-
|
|
13
|
-
|
|
33
|
+
...unique([resolvedExecPath, execPath]).map((candidate) =>
|
|
34
|
+
path.resolve(path.dirname(candidate), 'scripts/jabber_notify.py')
|
|
35
|
+
),
|
|
36
|
+
path.resolve(cwd, 'packages/jira-core/scripts/jabber_notify.py'),
|
|
37
|
+
path.resolve(cwd, 'scripts/jabber_notify.py'),
|
|
14
38
|
];
|
|
39
|
+
|
|
15
40
|
return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0];
|
|
16
41
|
}
|
|
17
42
|
|
|
@@ -49,7 +74,7 @@ export function getJabberToolDefinitions() {
|
|
|
49
74
|
// ── Handler ───────────────────────────────────────────────────────
|
|
50
75
|
|
|
51
76
|
export async function handleSendJabberMessage(args, _ctx) {
|
|
52
|
-
const scriptPath =
|
|
77
|
+
const scriptPath = resolveJabberNotifyScriptPath();
|
|
53
78
|
|
|
54
79
|
// dryRun 模式:不實際發送,直接回傳預覽
|
|
55
80
|
if (args.dryRun) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {mkdtempSync, mkdirSync, writeFileSync} from 'node:fs';
|
|
4
|
+
import {tmpdir} from 'node:os';
|
|
5
|
+
import {join} from 'node:path';
|
|
6
|
+
|
|
7
|
+
import {resolveJabberNotifyScriptPath} from './jabber.js';
|
|
8
|
+
|
|
9
|
+
test('resolveJabberNotifyScriptPath ignores empty env and prefers packaged script beside binary', () => {
|
|
10
|
+
const root = mkdtempSync(join(tmpdir(), 'ares-jabber-'));
|
|
11
|
+
const binDir = join(root, 'app');
|
|
12
|
+
const scriptPath = join(binDir, 'scripts', 'jabber_notify.py');
|
|
13
|
+
mkdirSync(join(binDir, 'scripts'), {recursive: true});
|
|
14
|
+
writeFileSync(scriptPath, '#!/usr/bin/env python3\n');
|
|
15
|
+
|
|
16
|
+
assert.equal(
|
|
17
|
+
resolveJabberNotifyScriptPath({
|
|
18
|
+
env: {JABBER_NOTIFY_SCRIPT: ''},
|
|
19
|
+
execPath: join(binDir, 'ares'),
|
|
20
|
+
cwd: join(root, 'work'),
|
|
21
|
+
}),
|
|
22
|
+
scriptPath,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('resolveJabberNotifyScriptPath keeps explicit env override', () => {
|
|
27
|
+
assert.equal(
|
|
28
|
+
resolveJabberNotifyScriptPath({
|
|
29
|
+
env: {JABBER_NOTIFY_SCRIPT: '/custom/jabber_notify.py'},
|
|
30
|
+
execPath: '/opt/ares/ares',
|
|
31
|
+
cwd: '/tmp',
|
|
32
|
+
}),
|
|
33
|
+
'/custom/jabber_notify.py',
|
|
34
|
+
);
|
|
35
|
+
});
|