@jira-deploy/core 1.0.11 → 1.0.13

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/tools/ci.test.js DELETED
@@ -1,154 +0,0 @@
1
- /**
2
- * handleGetNextCIVersion 單元測試
3
- * 執行:node --test src/tools/ci.test.js
4
- */
5
- import {test, mock} from 'node:test';
6
- import assert from 'node:assert/strict';
7
-
8
- // helpers.js 內部 import '../constants'(directory import)在 ESM 直接執行時不支援,
9
- // 用 mock.module 提前替換,避免 ERR_UNSUPPORTED_DIR_IMPORT。
10
- await mock.module('./helpers.js', {
11
- namedExports: {
12
- ok: (data) => ({content: [{type: 'text', text: JSON.stringify(data, null, 2)}]}),
13
- error: (msg) => ({content: [{type: 'text', text: `❌ 錯誤: ${msg}`}]}),
14
- today: () => new Date().toISOString().slice(0, 10),
15
- },
16
- });
17
-
18
- const {handleGetNextCIVersion, handleCreateCITicket} = await import('./ci.js');
19
-
20
- // ── Mock helpers ─────────────────────────────────────────────────
21
-
22
- function makePom(version) {
23
- return `<project>
24
- <parent><groupId>com.example</groupId><artifactId>parent</artifactId><version>0.0.1</version></parent>
25
- <artifactId>assembly</artifactId>
26
- <version>${version}-SNAPSHOT</version>
27
- </project>`;
28
- }
29
-
30
- function makeJira(pomContent) {
31
- return {getBitbucketFileContent: async () => pomContent};
32
- }
33
-
34
- function makeJiraThrows(msg) {
35
- return {
36
- getBitbucketFileContent: async () => {
37
- throw new Error(msg);
38
- },
39
- };
40
- }
41
-
42
- function parseOk(result) {
43
- return JSON.parse(result.content[0].text);
44
- }
45
-
46
- // ── Tests ────────────────────────────────────────────────────────
47
-
48
- test('IBK - 正常解析 pom.xml 版本號', async () => {
49
- const result = await handleGetNextCIVersion(
50
- {systemCode: 'IBK', branch: 'master'},
51
- {jira: makeJira(makePom('0.0.12'))},
52
- );
53
- const data = parseOk(result);
54
- assert.equal(data.systemCode, 'IBK');
55
- assert.equal(data.summaryVersion, '0.0.12');
56
- assert.equal(data.branch, 'master');
57
- });
58
-
59
- test('CWA - 正常解析 pom.xml 版本號', async () => {
60
- const result = await handleGetNextCIVersion(
61
- {systemCode: 'CWA', branch: 'master'},
62
- {jira: makeJira(makePom('1.2.3'))},
63
- );
64
- assert.equal(parseOk(result).summaryVersion, '1.2.3');
65
- });
66
-
67
- test('systemCode 不存在 SYSTEM_TO_CI_REPO_MAP → 回傳 error', async () => {
68
- const result = await handleGetNextCIVersion(
69
- {systemCode: 'NPM', branch: 'master'},
70
- {jira: makeJira('')},
71
- );
72
- const text = result.content[0].text;
73
- assert.match(text, /❌/);
74
- assert.match(text, /SYSTEM_TO_CI_REPO_MAP/);
75
- });
76
-
77
- test('pom.xml 沒有 <version> 標籤 → 回傳 error', async () => {
78
- const result = await handleGetNextCIVersion(
79
- {systemCode: 'IBK', branch: 'master'},
80
- {jira: makeJira('<project><name>no-version</name></project>')},
81
- );
82
- const text = result.content[0].text;
83
- assert.match(text, /❌/);
84
- assert.match(text, /pom\.xml/);
85
- });
86
-
87
- test('Bitbucket 拋例外 → 回傳 error', async () => {
88
- const result = await handleGetNextCIVersion(
89
- {systemCode: 'IBK', branch: 'master'},
90
- {jira: makeJiraThrows('network timeout')},
91
- );
92
- const text = result.content[0].text;
93
- assert.match(text, /❌/);
94
- assert.match(text, /network timeout/);
95
- });
96
-
97
- // ── handleCreateCITicket tests ────────────────────────────────────
98
-
99
- function makeFullJira(pomVersion = '0.0.12') {
100
- const linked = [];
101
- return {
102
- getBitbucketFileContent: async () => `<project>
103
- <parent><version>0.0.1</version></parent>
104
- <version>${pomVersion}-SNAPSHOT</version>
105
- </project>`,
106
- createIssue: async () => ({id: 'TEST-ID', key: 'CID-TEST'}),
107
- linkIssue: async (from, to, type) => {
108
- linked.push({from, to, type});
109
- },
110
- _linked: linked,
111
- };
112
- }
113
-
114
- function makeNotifier() {
115
- const logs = [];
116
- return {
117
- notify: async (key, msg) => {
118
- logs.push(msg);
119
- },
120
- _logs: logs,
121
- };
122
- }
123
-
124
- test('create_ci_ticket - relatesTo 單一 key 呼叫一次 linkIssue', async () => {
125
- const jira = makeFullJira();
126
- const notifier = makeNotifier();
127
- const result = await handleCreateCITicket(
128
- {systemCode: 'IBK', relatesTo: ['CID-1708']},
129
- {jira, notifier},
130
- );
131
- const data = parseOk(result);
132
- assert.equal(data.issueKey, 'CID-TEST');
133
- assert.equal(jira._linked.length, 1);
134
- assert.equal(jira._linked[0].to, 'CID-1708');
135
- });
136
-
137
- test('create_ci_ticket - relatesTo 多個 key 各呼叫一次 linkIssue', async () => {
138
- const jira = makeFullJira();
139
- const notifier = makeNotifier();
140
- await handleCreateCITicket(
141
- {systemCode: 'IBK', relatesTo: ['CID-1178', 'CID-1182']},
142
- {jira, notifier},
143
- );
144
- assert.equal(jira._linked.length, 2);
145
- assert.equal(jira._linked[0].to, 'CID-1178');
146
- assert.equal(jira._linked[1].to, 'CID-1182');
147
- });
148
-
149
- test('create_ci_ticket - 無 relatesTo 不呼叫 linkIssue', async () => {
150
- const jira = makeFullJira();
151
- const notifier = makeNotifier();
152
- await handleCreateCITicket({systemCode: 'IBK'}, {jira, notifier});
153
- assert.equal(jira._linked.length, 0);
154
- });
@@ -1,54 +0,0 @@
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 {dirname, join} from 'node:path';
6
- import {fileURLToPath} from 'node:url';
7
-
8
- import {resolveJabberNotifyScriptPath} from './jabber.js';
9
-
10
- const corePackageScriptPath = join(
11
- dirname(fileURLToPath(import.meta.url)),
12
- '..',
13
- 'scripts',
14
- 'jabber_notify.py',
15
- );
16
-
17
- test('resolveJabberNotifyScriptPath ignores empty env and prefers script shipped with core package', () => {
18
- const root = mkdtempSync(join(tmpdir(), 'ares-jabber-'));
19
- const binDir = join(root, 'app');
20
- const scriptPath = join(binDir, 'scripts', 'jabber_notify.py');
21
- mkdirSync(join(binDir, 'scripts'), {recursive: true});
22
- writeFileSync(scriptPath, '#!/usr/bin/env python3\n');
23
-
24
- assert.equal(
25
- resolveJabberNotifyScriptPath({
26
- env: {JABBER_NOTIFY_SCRIPT: ''},
27
- execPath: join(binDir, 'ares'),
28
- cwd: join(root, 'work'),
29
- }),
30
- corePackageScriptPath,
31
- );
32
- });
33
-
34
- test('resolveJabberNotifyScriptPath keeps explicit env override', () => {
35
- assert.equal(
36
- resolveJabberNotifyScriptPath({
37
- env: {JABBER_NOTIFY_SCRIPT: '/custom/jabber_notify.py'},
38
- execPath: '/opt/ares/ares',
39
- cwd: '/tmp',
40
- }),
41
- '/custom/jabber_notify.py',
42
- );
43
- });
44
-
45
- test('resolveJabberNotifyScriptPath falls back to script shipped with core package', () => {
46
- assert.equal(
47
- resolveJabberNotifyScriptPath({
48
- env: {JABBER_NOTIFY_SCRIPT: ''},
49
- execPath: '/opt/node/bin/node',
50
- cwd: '/tmp/not-the-repo',
51
- }),
52
- corePackageScriptPath,
53
- );
54
- });
@@ -1,137 +0,0 @@
1
- /**
2
- * handleWaitForComment 單元測試
3
- * 執行:node --test src/tools/release.test.js
4
- */
5
- import { test } from 'node:test'
6
- import assert from 'node:assert/strict'
7
- import { handleWaitForComment } from './release.js'
8
-
9
- // ── helpers ───────────────────────────────────────────────────────
10
- // ok() → { content: [{ type:'text', text: JSON }] }
11
- // error() → same shape but text starts with ❌
12
-
13
- function parseOk(result) {
14
- return JSON.parse(result.content[0].text)
15
- }
16
-
17
- function isError(result) {
18
- return result.content[0].text.startsWith('❌')
19
- }
20
-
21
- function errorText(result) {
22
- return result.content[0].text
23
- }
24
-
25
- /** 製作一個 jira mock,getComments 第 callsUntilMatch 次回傳含關鍵字的 comment */
26
- function makeJira({ callsUntilMatch = 1, keyword = 'Approved', author = 'BK00178' } = {}) {
27
- let calls = 0
28
- return {
29
- getComments: async () => {
30
- calls++
31
- if (calls >= callsUntilMatch) {
32
- return [
33
- {
34
- body: `${keyword} by manager`,
35
- author: { name: author, displayName: 'James Yu' },
36
- },
37
- ]
38
- }
39
- return []
40
- },
41
- }
42
- }
43
-
44
- /** 製作永遠回空的 jira mock(用於 timeout 測試) */
45
- function makeJiraEmpty() {
46
- return { getComments: async () => [] }
47
- }
48
-
49
- const BASE_ARGS = {
50
- issueKey: 'CID-9999',
51
- keyword: 'Approved',
52
- intervalMs: 0, // 零延遲,測試瞬間完成
53
- }
54
-
55
- // ── Tests ─────────────────────────────────────────────────────────
56
-
57
- test('dryRun 模式 → 立即回傳 found:true,不呼叫 Jira', async () => {
58
- let called = false
59
- const jira = {
60
- getComments: async () => {
61
- called = true
62
- return []
63
- },
64
- }
65
- const result = await handleWaitForComment({ ...BASE_ARGS, dryRun: true }, { jira })
66
- const data = parseOk(result)
67
- assert.equal(data.found, true)
68
- assert.equal(data.dryRun, true)
69
- assert.equal(data.attempts, 1)
70
- assert.equal(data.elapsedMs, 0)
71
- assert.equal(called, false, 'dryRun 時不應呼叫 jira.getComments')
72
- })
73
-
74
- test('第一次 poll 就找到關鍵字 → found:true', async () => {
75
- const result = await handleWaitForComment(BASE_ARGS, { jira: makeJira({ callsUntilMatch: 1 }) })
76
- const data = parseOk(result)
77
- assert.equal(data.found, true)
78
- assert.equal(data.issueKey, 'CID-9999')
79
- assert.equal(data.keyword, 'Approved')
80
- assert.equal(data.attempts, 1)
81
- })
82
-
83
- test('第 3 次 poll 才找到關鍵字 → found:true,attempts === 3', async () => {
84
- const result = await handleWaitForComment(BASE_ARGS, {
85
- jira: makeJira({ callsUntilMatch: 3 }),
86
- })
87
- const data = parseOk(result)
88
- assert.equal(data.found, true)
89
- assert.equal(data.attempts, 3)
90
- })
91
-
92
- test('關鍵字大小寫不分 → 能匹配', async () => {
93
- const jira = makeJira({ keyword: 'APPROVED' })
94
- const result = await handleWaitForComment(
95
- { ...BASE_ARGS, keyword: 'approved' },
96
- { jira },
97
- )
98
- assert.equal(parseOk(result).found, true)
99
- })
100
-
101
- test('author filter 相符 → found:true', async () => {
102
- const result = await handleWaitForComment(
103
- { ...BASE_ARGS, authorAccountId: 'BK00178' },
104
- { jira: makeJira({ author: 'BK00178' }) },
105
- )
106
- assert.equal(parseOk(result).found, true)
107
- })
108
-
109
- test('author filter 不相符 → timeout error(超短 timeout)', async () => {
110
- // comment 存在但 author 不符,永遠匹配不到
111
- const jira = makeJira({ author: 'SOMEONE_ELSE' })
112
- const result = await handleWaitForComment(
113
- { ...BASE_ARGS, authorAccountId: 'BK00178', timeoutMs: 20, intervalMs: 5 },
114
- { jira },
115
- )
116
- assert.ok(isError(result), '應回傳 error')
117
- assert.match(result.content[0].text, /Timeout/)
118
- })
119
-
120
- test('永遠找不到關鍵字 → timeout error', async () => {
121
- const result = await handleWaitForComment(
122
- { ...BASE_ARGS, timeoutMs: 20, intervalMs: 5 },
123
- { jira: makeJiraEmpty() },
124
- )
125
- assert.ok(isError(result), '應回傳 error')
126
- assert.match(result.content[0].text, /Timeout/)
127
- assert.match(result.content[0].text, /Approved/)
128
- })
129
-
130
- test('timeout error 包含輪詢次數資訊', async () => {
131
- const result = await handleWaitForComment(
132
- { ...BASE_ARGS, timeoutMs: 20, intervalMs: 5 },
133
- { jira: makeJiraEmpty() },
134
- )
135
- assert.ok(isError(result), '應回傳 error')
136
- assert.match(errorText(result), /次輪詢/)
137
- })