@jira-deploy/mcp 1.0.0 → 1.0.12
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/.env.example +8 -6
- package/README.md +15 -14
- package/package.json +8 -4
- package/src/env.js +11 -0
- package/src/index.js +5 -41
- package/src/server.js +64 -0
- package/src/utility-tools.js +45 -35
package/.env.example
CHANGED
|
@@ -11,7 +11,10 @@ JIRA_USER_EMAIL=your-email@company.com
|
|
|
11
11
|
JIRA_API_TOKEN=your_jira_api_token
|
|
12
12
|
|
|
13
13
|
# 預設專案 key(可在開單時 override)
|
|
14
|
-
JIRA_PROJECT_KEY=
|
|
14
|
+
JIRA_PROJECT_KEY=PROJ
|
|
15
|
+
|
|
16
|
+
# Tenant-specific workflow config. Prefer a local JSON file for large configs.
|
|
17
|
+
JIRA_DEPLOY_CONFIG_PATH=
|
|
15
18
|
|
|
16
19
|
# 輪詢設定
|
|
17
20
|
POLL_INTERVAL_MS=30000
|
|
@@ -28,11 +31,10 @@ CONF_TOKEN=your-confluence-token
|
|
|
28
31
|
# Jabber (XMPP)
|
|
29
32
|
# Prefer storing the password in macOS Keychain and leave JABBER_PASSWORD empty.
|
|
30
33
|
# Set JABBER_PASSWORD only for CI or quick overrides.
|
|
31
|
-
JABBER_SERVER=
|
|
32
|
-
JABBER_USER=
|
|
33
|
-
JABBER_DOMAIN=
|
|
34
|
+
JABBER_SERVER=xmpp.example.internal
|
|
35
|
+
JABBER_USER=your_jabber_user
|
|
36
|
+
JABBER_DOMAIN=example.internal
|
|
34
37
|
JABBER_PASSWORD=
|
|
35
38
|
JABBER_KEYCHAIN_SERVICE=jabber-copilot
|
|
36
|
-
JABBER_KEYCHAIN_ACCOUNT=
|
|
39
|
+
JABBER_KEYCHAIN_ACCOUNT=your_jabber_user
|
|
37
40
|
JABBER_TO=
|
|
38
|
-
JABBER_NOTIFY_SCRIPT=src/scripts/jabber_notify.py
|
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ npm install -g @jira-deploy/mcp
|
|
|
29
29
|
npx -y @jira-deploy/mcp
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
MCP app 維持走 npm / npx 發布與安裝,不提供 binary
|
|
32
|
+
MCP app 維持走 npm / npx 發布與安裝,不提供 standalone binary 安裝。
|
|
33
33
|
|
|
34
34
|
### 本地開發 / 從 monorepo 啟動
|
|
35
35
|
|
|
@@ -60,7 +60,8 @@ cp .env.example .env
|
|
|
60
60
|
"BITBUCKET_URL": "https://bitbucket.example.com",
|
|
61
61
|
"BITBUCKET_API_TOKEN": "your_bitbucket_api_token",
|
|
62
62
|
"CONF_BASE_URL": "https://confluence.example.com",
|
|
63
|
-
"CONF_TOKEN": "your_confluence_token"
|
|
63
|
+
"CONF_TOKEN": "your_confluence_token",
|
|
64
|
+
"JIRA_DEPLOY_CONFIG_PATH": "/path/to/jira-deploy-config.json"
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
}
|
|
@@ -75,12 +76,12 @@ cp .env.example .env
|
|
|
75
76
|
安裝好並接入 MCP client 後,可以直接在 Chat 裡說:
|
|
76
77
|
|
|
77
78
|
```text
|
|
78
|
-
幫我開一張
|
|
79
|
-
把
|
|
80
|
-
等
|
|
81
|
-
把
|
|
82
|
-
查
|
|
83
|
-
查
|
|
79
|
+
幫我開一張 APP STG 上版單
|
|
80
|
+
把 PROJ-123 切到 Pending Approval
|
|
81
|
+
等 PROJ-123 被 approve
|
|
82
|
+
把 PROJ-123 切到 Approved
|
|
83
|
+
查 PROJ-123 的狀態跟留言
|
|
84
|
+
查 demo-web 這個 PR 的 diff
|
|
84
85
|
查 Confluence Release Manager 值班表
|
|
85
86
|
```
|
|
86
87
|
|
|
@@ -132,17 +133,17 @@ Confluence:
|
|
|
132
133
|
開一張 A平台 STG 上版單,版號 v1.2.3
|
|
133
134
|
|
|
134
135
|
# 2. 切狀態等待審核
|
|
135
|
-
把
|
|
136
|
+
把 PROJ-123 切到 Pending Approval
|
|
136
137
|
|
|
137
138
|
# 3. 等待 Approve(Copilot 會輪詢)
|
|
138
|
-
等
|
|
139
|
+
等 PROJ-123 被 approve
|
|
139
140
|
|
|
140
141
|
# 4. Approve 後切狀態(觸發 Jira Automation → Jenkins)
|
|
141
|
-
把
|
|
142
|
+
把 PROJ-123 切到 Approved
|
|
142
143
|
|
|
143
144
|
# 5. 等部署完成後收尾
|
|
144
|
-
在
|
|
145
|
-
把
|
|
145
|
+
在 PROJ-123 加留言「STG 部署完成,build: https://jenkins/...」
|
|
146
|
+
把 PROJ-123 切到 Done
|
|
146
147
|
```
|
|
147
148
|
|
|
148
149
|
## 平台設定
|
|
@@ -152,7 +153,7 @@ Confluence:
|
|
|
152
153
|
```js
|
|
153
154
|
export const PLATFORMS = {
|
|
154
155
|
'a平台': {
|
|
155
|
-
projectKey: '
|
|
156
|
+
projectKey: 'PROJ',
|
|
156
157
|
issueType: 'Task',
|
|
157
158
|
components: ['A Platform'],
|
|
158
159
|
labels: ['deploy', 'stg'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jira-deploy/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "MCP Server for Jira deploy ticket workflow",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
"jira-deploy-mcp": "./src/index.js"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"src
|
|
16
|
+
"src/env.js",
|
|
17
|
+
"src/index.js",
|
|
18
|
+
"src/server.js",
|
|
19
|
+
"src/utility-tools.js",
|
|
17
20
|
"README.md",
|
|
18
21
|
".env.example"
|
|
19
22
|
],
|
|
@@ -24,10 +27,11 @@
|
|
|
24
27
|
"dependencies": {
|
|
25
28
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
26
29
|
"dotenv": "^16.3.0",
|
|
27
|
-
"@jira-deploy/core": "1.0.
|
|
30
|
+
"@jira-deploy/core": "1.0.12"
|
|
28
31
|
},
|
|
29
32
|
"scripts": {
|
|
30
33
|
"start": "node src/index.js",
|
|
31
|
-
"dev": "node --watch src/index.js"
|
|
34
|
+
"dev": "node --watch src/index.js",
|
|
35
|
+
"test": "node --test src/*.test.js"
|
|
32
36
|
}
|
|
33
37
|
}
|
package/src/env.js
ADDED
package/src/index.js
CHANGED
|
@@ -1,51 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {config} from 'dotenv';
|
|
3
2
|
import {fileURLToPath} from 'url';
|
|
4
3
|
import {dirname, join} from 'path';
|
|
5
|
-
import {
|
|
6
|
-
import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
-
import {
|
|
8
|
-
CallToolRequestSchema,
|
|
9
|
-
ListToolsRequestSchema,
|
|
10
|
-
} from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
-
import {JiraClient, Notifier, getToolDefinitions, executeTool} from '@jira-deploy/core';
|
|
12
|
-
import {getUtilityToolDefinitions, executeUtilityTool} from './utility-tools.js';
|
|
4
|
+
import {loadMcpEnv} from './env.js';
|
|
13
5
|
|
|
14
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
|
|
7
|
+
loadMcpEnv({packageEnvPath: join(__dirname, '..', '.env')});
|
|
16
8
|
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
const server = new Server(
|
|
21
|
-
{name: '@jira-deploy/mcp', version: '1.0.0'},
|
|
22
|
-
{capabilities: {tools: {}}}
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
26
|
-
tools: [...getToolDefinitions(), ...getUtilityToolDefinitions()],
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
30
|
-
const {name, arguments: args} = request.params;
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
const utilityResult = await executeUtilityTool(name, args ?? {});
|
|
34
|
-
if (utilityResult) return utilityResult;
|
|
35
|
-
return await executeTool(name, args ?? {}, {jira, notifier});
|
|
36
|
-
} catch (err) {
|
|
37
|
-
return {
|
|
38
|
-
content: [
|
|
39
|
-
{
|
|
40
|
-
type: 'text',
|
|
41
|
-
text: JSON.stringify({error: err.message}),
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
isError: true,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
});
|
|
9
|
+
const {StdioServerTransport} = await import('@modelcontextprotocol/sdk/server/stdio.js');
|
|
10
|
+
const {createMcpServer} = await import('./server.js');
|
|
48
11
|
|
|
12
|
+
const server = createMcpServer();
|
|
49
13
|
const transport = new StdioServerTransport();
|
|
50
14
|
await server.connect(transport);
|
|
51
15
|
console.error('[@jira-deploy/mcp] MCP Server ready');
|
package/src/server.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {Server} from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import {
|
|
3
|
+
CallToolRequestSchema,
|
|
4
|
+
ListToolsRequestSchema,
|
|
5
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import {JiraClient, Notifier, getToolDefinitions, executeTool} from '@jira-deploy/core';
|
|
7
|
+
import {getUtilityToolDefinitions, executeUtilityTool} from './utility-tools.js';
|
|
8
|
+
|
|
9
|
+
const NON_JIRA_CORE_TOOL_NAMES = new Set([
|
|
10
|
+
'get_release_manager',
|
|
11
|
+
'send_jabber_message',
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export function createJiraDeps() {
|
|
15
|
+
const jira = new JiraClient();
|
|
16
|
+
return {jira, notifier: new Notifier(jira)};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function listTools() {
|
|
20
|
+
return {
|
|
21
|
+
tools: [...getToolDefinitions(), ...getUtilityToolDefinitions()],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function callTool(
|
|
26
|
+
request,
|
|
27
|
+
{
|
|
28
|
+
createDeps = createJiraDeps,
|
|
29
|
+
executeToolImpl = executeTool,
|
|
30
|
+
executeUtilityToolImpl = executeUtilityTool,
|
|
31
|
+
} = {},
|
|
32
|
+
) {
|
|
33
|
+
const {name, arguments: args} = request.params;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const utilityResult = await executeUtilityToolImpl(name, args ?? {});
|
|
37
|
+
if (utilityResult) return utilityResult;
|
|
38
|
+
|
|
39
|
+
const deps = NON_JIRA_CORE_TOOL_NAMES.has(name) ? {} : createDeps();
|
|
40
|
+
return await executeToolImpl(name, args ?? {}, deps);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: 'text',
|
|
46
|
+
text: JSON.stringify({error: err.message}),
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
isError: true,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function createMcpServer(options = {}) {
|
|
55
|
+
const server = new Server(
|
|
56
|
+
{name: '@jira-deploy/mcp', version: '1.0.3'},
|
|
57
|
+
{capabilities: {tools: {}}},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => listTools());
|
|
61
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => callTool(request, options));
|
|
62
|
+
|
|
63
|
+
return server;
|
|
64
|
+
}
|
package/src/utility-tools.js
CHANGED
|
@@ -143,19 +143,29 @@ function stripHtml(html) {
|
|
|
143
143
|
.trim();
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
function readOnlyTool(tool) {
|
|
147
|
+
return {
|
|
148
|
+
...tool,
|
|
149
|
+
annotations: {
|
|
150
|
+
...tool.annotations,
|
|
151
|
+
readOnlyHint: true,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
146
156
|
export function getUtilityToolDefinitions() {
|
|
147
157
|
return [
|
|
148
|
-
{
|
|
158
|
+
readOnlyTool({
|
|
149
159
|
name: 'jira_get_issue',
|
|
150
160
|
description:
|
|
151
161
|
'Get a Jira issue by key. Returns summary, status, type, priority, assignee, description, comments, linked issues, and attachments.',
|
|
152
162
|
inputSchema: {
|
|
153
163
|
type: 'object',
|
|
154
164
|
required: ['issueKey'],
|
|
155
|
-
properties: {issueKey: {type: 'string', description: 'Jira issue key, e.g.
|
|
165
|
+
properties: {issueKey: {type: 'string', description: 'Jira issue key, e.g. PROJ-123'}},
|
|
156
166
|
},
|
|
157
|
-
},
|
|
158
|
-
{
|
|
167
|
+
}),
|
|
168
|
+
readOnlyTool({
|
|
159
169
|
name: 'jira_search_issues',
|
|
160
170
|
description: 'Search Jira issues using JQL. Returns key, summary, status, type, priority, and assignee.',
|
|
161
171
|
inputSchema: {
|
|
@@ -166,8 +176,8 @@ export function getUtilityToolDefinitions() {
|
|
|
166
176
|
maxResults: {type: 'number', default: 20, description: 'Max results to return'},
|
|
167
177
|
},
|
|
168
178
|
},
|
|
169
|
-
},
|
|
170
|
-
{
|
|
179
|
+
}),
|
|
180
|
+
readOnlyTool({
|
|
171
181
|
name: 'bitbucket_list_prs',
|
|
172
182
|
description: 'List pull requests for a Bitbucket repository.',
|
|
173
183
|
inputSchema: {
|
|
@@ -180,8 +190,8 @@ export function getUtilityToolDefinitions() {
|
|
|
180
190
|
limit: {type: 'number', default: 25},
|
|
181
191
|
},
|
|
182
192
|
},
|
|
183
|
-
},
|
|
184
|
-
{
|
|
193
|
+
}),
|
|
194
|
+
readOnlyTool({
|
|
185
195
|
name: 'bitbucket_get_pr',
|
|
186
196
|
description: 'Get Bitbucket pull request details and recent activity.',
|
|
187
197
|
inputSchema: {
|
|
@@ -193,8 +203,8 @@ export function getUtilityToolDefinitions() {
|
|
|
193
203
|
prId: {type: 'number'},
|
|
194
204
|
},
|
|
195
205
|
},
|
|
196
|
-
},
|
|
197
|
-
{
|
|
206
|
+
}),
|
|
207
|
+
readOnlyTool({
|
|
198
208
|
name: 'bitbucket_get_pr_changes',
|
|
199
209
|
description: 'Get the list of changed files in a Bitbucket pull request.',
|
|
200
210
|
inputSchema: {
|
|
@@ -206,8 +216,8 @@ export function getUtilityToolDefinitions() {
|
|
|
206
216
|
prId: {type: 'number'},
|
|
207
217
|
},
|
|
208
218
|
},
|
|
209
|
-
},
|
|
210
|
-
{
|
|
219
|
+
}),
|
|
220
|
+
readOnlyTool({
|
|
211
221
|
name: 'bitbucket_get_pr_diff',
|
|
212
222
|
description: 'Get Bitbucket pull request diff content for code review.',
|
|
213
223
|
inputSchema: {
|
|
@@ -226,8 +236,8 @@ export function getUtilityToolDefinitions() {
|
|
|
226
236
|
},
|
|
227
237
|
},
|
|
228
238
|
},
|
|
229
|
-
},
|
|
230
|
-
{
|
|
239
|
+
}),
|
|
240
|
+
readOnlyTool({
|
|
231
241
|
name: 'bitbucket_get_pr_comments',
|
|
232
242
|
description: 'Get all comments on a Bitbucket pull request, including inline anchors.',
|
|
233
243
|
inputSchema: {
|
|
@@ -239,7 +249,7 @@ export function getUtilityToolDefinitions() {
|
|
|
239
249
|
prId: {type: 'number'},
|
|
240
250
|
},
|
|
241
251
|
},
|
|
242
|
-
},
|
|
252
|
+
}),
|
|
243
253
|
{
|
|
244
254
|
name: 'bitbucket_add_pr_comment',
|
|
245
255
|
description: 'Add a general comment to a Bitbucket pull request.',
|
|
@@ -273,7 +283,7 @@ export function getUtilityToolDefinitions() {
|
|
|
273
283
|
},
|
|
274
284
|
},
|
|
275
285
|
},
|
|
276
|
-
{
|
|
286
|
+
readOnlyTool({
|
|
277
287
|
name: 'bitbucket_get_file',
|
|
278
288
|
description: 'Get raw file content from a Bitbucket repository.',
|
|
279
289
|
inputSchema: {
|
|
@@ -286,8 +296,8 @@ export function getUtilityToolDefinitions() {
|
|
|
286
296
|
branch: {type: 'string', default: 'master'},
|
|
287
297
|
},
|
|
288
298
|
},
|
|
289
|
-
},
|
|
290
|
-
{
|
|
299
|
+
}),
|
|
300
|
+
readOnlyTool({
|
|
291
301
|
name: 'confluence_search',
|
|
292
302
|
description: 'Search Confluence pages using CQL.',
|
|
293
303
|
inputSchema: {
|
|
@@ -298,8 +308,8 @@ export function getUtilityToolDefinitions() {
|
|
|
298
308
|
limit: {type: 'number', default: 10},
|
|
299
309
|
},
|
|
300
310
|
},
|
|
301
|
-
},
|
|
302
|
-
{
|
|
311
|
+
}),
|
|
312
|
+
readOnlyTool({
|
|
303
313
|
name: 'confluence_get_page',
|
|
304
314
|
description: 'Get full readable content of a Confluence page by ID.',
|
|
305
315
|
inputSchema: {
|
|
@@ -307,8 +317,8 @@ export function getUtilityToolDefinitions() {
|
|
|
307
317
|
required: ['pageId'],
|
|
308
318
|
properties: {pageId: {type: 'string'}},
|
|
309
319
|
},
|
|
310
|
-
},
|
|
311
|
-
{
|
|
320
|
+
}),
|
|
321
|
+
readOnlyTool({
|
|
312
322
|
name: 'confluence_get_children',
|
|
313
323
|
description: 'Get child pages of a Confluence page.',
|
|
314
324
|
inputSchema: {
|
|
@@ -316,8 +326,8 @@ export function getUtilityToolDefinitions() {
|
|
|
316
326
|
required: ['pageId'],
|
|
317
327
|
properties: {pageId: {type: 'string'}, limit: {type: 'number', default: 25}},
|
|
318
328
|
},
|
|
319
|
-
},
|
|
320
|
-
{
|
|
329
|
+
}),
|
|
330
|
+
readOnlyTool({
|
|
321
331
|
name: 'confluence_list_spaces',
|
|
322
332
|
description: 'List available Confluence spaces.',
|
|
323
333
|
inputSchema: {
|
|
@@ -325,8 +335,8 @@ export function getUtilityToolDefinitions() {
|
|
|
325
335
|
required: [],
|
|
326
336
|
properties: {limit: {type: 'number', default: 20}},
|
|
327
337
|
},
|
|
328
|
-
},
|
|
329
|
-
{
|
|
338
|
+
}),
|
|
339
|
+
readOnlyTool({
|
|
330
340
|
name: 'confluence_get_page_storage',
|
|
331
341
|
description: 'Get raw Confluence storage-format HTML for a page.',
|
|
332
342
|
inputSchema: {
|
|
@@ -334,7 +344,7 @@ export function getUtilityToolDefinitions() {
|
|
|
334
344
|
required: ['pageId'],
|
|
335
345
|
properties: {pageId: {type: 'string'}},
|
|
336
346
|
},
|
|
337
|
-
},
|
|
347
|
+
}),
|
|
338
348
|
{
|
|
339
349
|
name: 'confluence_create_page',
|
|
340
350
|
description: 'Create a new Confluence page under a parent page. Body must be storage-format HTML.',
|
|
@@ -363,7 +373,7 @@ export function getUtilityToolDefinitions() {
|
|
|
363
373
|
},
|
|
364
374
|
},
|
|
365
375
|
},
|
|
366
|
-
{
|
|
376
|
+
readOnlyTool({
|
|
367
377
|
name: 'confluence_list_versions',
|
|
368
378
|
description: 'List historical versions of a Confluence page.',
|
|
369
379
|
inputSchema: {
|
|
@@ -375,8 +385,8 @@ export function getUtilityToolDefinitions() {
|
|
|
375
385
|
start: {type: 'number', default: 0},
|
|
376
386
|
},
|
|
377
387
|
},
|
|
378
|
-
},
|
|
379
|
-
{
|
|
388
|
+
}),
|
|
389
|
+
readOnlyTool({
|
|
380
390
|
name: 'confluence_get_page_version',
|
|
381
391
|
description: 'Get readable body and metadata of a historical Confluence page version.',
|
|
382
392
|
inputSchema: {
|
|
@@ -384,8 +394,8 @@ export function getUtilityToolDefinitions() {
|
|
|
384
394
|
required: ['pageId', 'version'],
|
|
385
395
|
properties: {pageId: {type: 'string'}, version: {type: 'number'}},
|
|
386
396
|
},
|
|
387
|
-
},
|
|
388
|
-
{
|
|
397
|
+
}),
|
|
398
|
+
readOnlyTool({
|
|
389
399
|
name: 'confluence_get_calendar_events',
|
|
390
400
|
description:
|
|
391
401
|
'Query Confluence Team Calendar events. Useful for finding Release Manager / Sign off staff.',
|
|
@@ -397,7 +407,7 @@ export function getUtilityToolDefinitions() {
|
|
|
397
407
|
date: {type: 'string', description: 'YYYY-MM-DD'},
|
|
398
408
|
},
|
|
399
409
|
},
|
|
400
|
-
},
|
|
410
|
+
}),
|
|
401
411
|
];
|
|
402
412
|
}
|
|
403
413
|
|
|
@@ -875,8 +885,8 @@ async function confluenceGetCalendarEvents({subCalendarId, date}) {
|
|
|
875
885
|
return ok({
|
|
876
886
|
date,
|
|
877
887
|
total: 1,
|
|
878
|
-
events: [{what: 'Sign off staff', who: '
|
|
879
|
-
signOffStaff: {name: '
|
|
888
|
+
events: [{what: 'Sign off staff', who: 'Demo User (demo-user)'}],
|
|
889
|
+
signOffStaff: {name: 'Demo User (demo-user)'},
|
|
880
890
|
dryRun: true,
|
|
881
891
|
});
|
|
882
892
|
}
|