@jira-deploy/mcp 1.0.15 → 1.0.17
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/README.md +9 -9
- package/package.json +2 -2
- package/src/env.js +103 -0
- package/src/index.js +4 -1
- package/src/utility-tools.js +33 -30
package/README.md
CHANGED
|
@@ -29,6 +29,12 @@ npm install -g @jira-deploy/mcp
|
|
|
29
29
|
npx -y @jira-deploy/mcp
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
如果要使用 JSON config,可透過 `--config` 明確傳入:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx -y @jira-deploy/mcp --config ~/.ares/config.json
|
|
36
|
+
```
|
|
37
|
+
|
|
32
38
|
MCP app 維持走 npm / npx 發布與安裝,不提供 standalone binary 安裝。
|
|
33
39
|
|
|
34
40
|
### 本地開發 / 從 monorepo 啟動
|
|
@@ -53,23 +59,17 @@ cp .env.example .env
|
|
|
53
59
|
"servers": {
|
|
54
60
|
"jira-deploy": {
|
|
55
61
|
"command": "npx",
|
|
56
|
-
"args": ["-y", "@jira-deploy/mcp"],
|
|
62
|
+
"args": ["-y", "@jira-deploy/mcp", "--config", "/path/to/config.json"],
|
|
57
63
|
"env": {
|
|
58
64
|
"JIRA_BASE_URL": "https://your-org.atlassian.net",
|
|
59
|
-
"JIRA_API_TOKEN": "your_jira_api_token"
|
|
60
|
-
"BITBUCKET_URL": "https://bitbucket.example.com",
|
|
61
|
-
"BITBUCKET_API_TOKEN": "your_bitbucket_api_token",
|
|
62
|
-
"CONF_BASE_URL": "https://confluence.example.com",
|
|
63
|
-
"CONF_TOKEN": "your_confluence_token",
|
|
64
|
-
"JIRA_DEPLOY_CONFIG_PATH": "/path/to/jira-deploy-config.json"
|
|
65
|
+
"JIRA_API_TOKEN": "your_jira_api_token"
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
```
|
|
70
71
|
|
|
71
|
-
建議把 Jira
|
|
72
|
-
不要 commit 到 git(`.env` 已在 .gitignore)。
|
|
72
|
+
建議把 Jira、Bitbucket、Confluence、Jabber 的機密設定放在 JSON config、系統環境變數或 `.env` 檔,不要 commit 到 git(`.env` 已在 .gitignore)。`--config` 的值會優先於 shell env;未使用 `--config` 時,MCP 仍可讀取既有 env。
|
|
73
73
|
|
|
74
74
|
## 使用者端使用方式
|
|
75
75
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jira-deploy/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.17",
|
|
4
4
|
"description": "MCP Server for Jira deploy ticket workflow",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
29
29
|
"dotenv": "^16.3.0",
|
|
30
|
-
"@jira-deploy/core": "1.0.
|
|
30
|
+
"@jira-deploy/core": "1.0.17"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"start": "node src/index.js",
|
package/src/env.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {config} from 'dotenv';
|
|
2
|
+
import {readFileSync} from 'node:fs';
|
|
2
3
|
|
|
3
4
|
export function loadMcpEnv({
|
|
4
5
|
packageEnvPath,
|
|
@@ -9,3 +10,105 @@ export function loadMcpEnv({
|
|
|
9
10
|
configImpl({path: packageEnvPath});
|
|
10
11
|
}
|
|
11
12
|
}
|
|
13
|
+
|
|
14
|
+
const CONFIG_ENV_MAP = [
|
|
15
|
+
['jira.baseUrl', 'JIRA_BASE_URL'],
|
|
16
|
+
['jira.apiToken', 'JIRA_API_TOKEN'],
|
|
17
|
+
['jira.deployConfigPath', 'JIRA_DEPLOY_CONFIG_PATH'],
|
|
18
|
+
['jira.projectKey', 'JIRA_PROJECT_KEY'],
|
|
19
|
+
['jira.releaseProjectKey', 'JIRA_RELEASE_PROJECT_KEY'],
|
|
20
|
+
['bitbucket.url', 'BITBUCKET_URL'],
|
|
21
|
+
['bitbucket.baseUrl', 'BITBUCKET_BASE_URL'],
|
|
22
|
+
['bitbucket.apiToken', 'BITBUCKET_API_TOKEN'],
|
|
23
|
+
['confluence.baseUrl', 'CONF_BASE_URL'],
|
|
24
|
+
['confluence.token', 'CONF_TOKEN'],
|
|
25
|
+
['poll.intervalMs', 'POLL_INTERVAL_MS'],
|
|
26
|
+
['poll.timeoutMs', 'POLL_TIMEOUT_MS'],
|
|
27
|
+
['jabber.notifyScript', 'JABBER_NOTIFY_SCRIPT'],
|
|
28
|
+
['jabber.server', 'JABBER_SERVER'],
|
|
29
|
+
['jabber.user', 'JABBER_USER'],
|
|
30
|
+
['jabber.domain', 'JABBER_DOMAIN'],
|
|
31
|
+
['jabber.keychainService', 'JABBER_KEYCHAIN_SERVICE'],
|
|
32
|
+
['jabber.keychainAccount', 'JABBER_KEYCHAIN_ACCOUNT'],
|
|
33
|
+
['jabber.to', 'JABBER_TO'],
|
|
34
|
+
['jabber.room', 'JABBER_ROOM'],
|
|
35
|
+
['jabber.port', 'JABBER_PORT'],
|
|
36
|
+
['jabber.resource', 'JABBER_RESOURCE'],
|
|
37
|
+
['jabber.nick', 'JABBER_NICK'],
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
function isPlainObject(value) {
|
|
41
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getPathValue(object, path) {
|
|
45
|
+
return path.split('.').reduce((current, segment) => (
|
|
46
|
+
isPlainObject(current) && Object.hasOwn(current, segment) ? current[segment] : undefined
|
|
47
|
+
), object);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function hasConfigValue(value) {
|
|
51
|
+
return value !== undefined && value !== null && value !== '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function stringifyConfigValue(value) {
|
|
55
|
+
if (typeof value === 'boolean') {
|
|
56
|
+
return value ? 'true' : 'false';
|
|
57
|
+
}
|
|
58
|
+
return String(value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function parseMcpArgs(args = process.argv.slice(2)) {
|
|
62
|
+
const remainingArgs = [];
|
|
63
|
+
let configPath = null;
|
|
64
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
65
|
+
const arg = args[index];
|
|
66
|
+
if (arg === '--config') {
|
|
67
|
+
configPath = args[index + 1] ?? null;
|
|
68
|
+
index += 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
remainingArgs.push(arg);
|
|
72
|
+
}
|
|
73
|
+
return {configPath, remainingArgs};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function mcpJsonConfigToCoreEnv(configValue) {
|
|
77
|
+
const nextEnv = {};
|
|
78
|
+
if (!isPlainObject(configValue)) {
|
|
79
|
+
return nextEnv;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const [configPath, envKey] of CONFIG_ENV_MAP) {
|
|
83
|
+
const value = getPathValue(configValue, configPath);
|
|
84
|
+
if (hasConfigValue(value)) {
|
|
85
|
+
nextEnv[envKey] = stringifyConfigValue(value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (typeof configValue.dryRun === 'boolean') {
|
|
90
|
+
nextEnv.DRY_RUN = stringifyConfigValue(configValue.dryRun);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (isPlainObject(configValue.env)) {
|
|
94
|
+
for (const [key, value] of Object.entries(configValue.env)) {
|
|
95
|
+
if (hasConfigValue(value)) {
|
|
96
|
+
nextEnv[key] = stringifyConfigValue(value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return nextEnv;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function loadMcpRuntimeConfig({
|
|
105
|
+
configPath,
|
|
106
|
+
readConfig = (path) => JSON.parse(readFileSync(path, 'utf8')),
|
|
107
|
+
} = {}) {
|
|
108
|
+
if (!configPath) {
|
|
109
|
+
return {};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
env: mcpJsonConfigToCoreEnv(readConfig(configPath)),
|
|
113
|
+
};
|
|
114
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {fileURLToPath} from 'url';
|
|
3
3
|
import {dirname, join} from 'path';
|
|
4
|
-
import {loadMcpEnv} from './env.js';
|
|
4
|
+
import {loadMcpEnv, loadMcpRuntimeConfig, parseMcpArgs} from './env.js';
|
|
5
5
|
|
|
6
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
loadMcpEnv({packageEnvPath: join(__dirname, '..', '.env')});
|
|
8
|
+
const {configPath} = parseMcpArgs();
|
|
9
|
+
const {configureRuntimeConfig} = await import('@jira-deploy/core/runtime-config');
|
|
10
|
+
configureRuntimeConfig(loadMcpRuntimeConfig({configPath}));
|
|
8
11
|
|
|
9
12
|
const {StdioServerTransport} = await import('@modelcontextprotocol/sdk/server/stdio.js');
|
|
10
13
|
const {createMcpServer} = await import('./server.js');
|
package/src/utility-tools.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import https from 'https';
|
|
3
|
+
import {getRuntimeConfigValue} from '@jira-deploy/core/runtime-config';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
function isDryRun() {
|
|
6
|
+
return getRuntimeConfigValue('DRY_RUN') === 'true';
|
|
7
|
+
}
|
|
5
8
|
|
|
6
9
|
function ok(data) {
|
|
7
10
|
return {content: [{type: 'text', text: JSON.stringify(data, null, 2)}]};
|
|
@@ -12,9 +15,9 @@ function text(data) {
|
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
function requiredEnv(names, label) {
|
|
15
|
-
const values = Object.fromEntries(names.map((name) => [name,
|
|
18
|
+
const values = Object.fromEntries(names.map((name) => [name, getRuntimeConfigValue(name)]));
|
|
16
19
|
const missing = names.filter((name) => !values[name]);
|
|
17
|
-
if (missing.length > 0 && !
|
|
20
|
+
if (missing.length > 0 && !isDryRun()) {
|
|
18
21
|
throw new Error(`${label} requires env vars: ${missing.join(', ')}`);
|
|
19
22
|
}
|
|
20
23
|
return values;
|
|
@@ -109,18 +112,18 @@ function requestText(baseUrl, path, {token, timeoutMs = 15000} = {}) {
|
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
function jiraConfig() {
|
|
112
|
-
const baseUrl =
|
|
113
|
-
const token =
|
|
114
|
-
if (!
|
|
115
|
+
const baseUrl = getRuntimeConfigValue('JIRA_BASE_URL');
|
|
116
|
+
const token = getRuntimeConfigValue('JIRA_API_TOKEN') ?? getRuntimeConfigValue('JIRA_TOKEN');
|
|
117
|
+
if (!isDryRun() && (!baseUrl || !token)) {
|
|
115
118
|
throw new Error('Jira utility tools require JIRA_BASE_URL and JIRA_API_TOKEN');
|
|
116
119
|
}
|
|
117
120
|
return {baseUrl, token};
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
function bitbucketConfig() {
|
|
121
|
-
const baseUrl =
|
|
122
|
-
const token =
|
|
123
|
-
if (!
|
|
124
|
+
const baseUrl = getRuntimeConfigValue('BITBUCKET_URL') ?? getRuntimeConfigValue('BITBUCKET_BASE_URL');
|
|
125
|
+
const token = getRuntimeConfigValue('BITBUCKET_API_TOKEN') ?? getRuntimeConfigValue('BITBUCKET_TOKEN');
|
|
126
|
+
if (!isDryRun() && (!baseUrl || !token)) {
|
|
124
127
|
throw new Error('Bitbucket utility tools require BITBUCKET_URL and BITBUCKET_API_TOKEN');
|
|
125
128
|
}
|
|
126
129
|
return {baseUrl, token};
|
|
@@ -128,7 +131,7 @@ function bitbucketConfig() {
|
|
|
128
131
|
|
|
129
132
|
function confluenceConfig() {
|
|
130
133
|
requiredEnv(['CONF_BASE_URL', 'CONF_TOKEN'], 'Confluence utility tools');
|
|
131
|
-
return {baseUrl:
|
|
134
|
+
return {baseUrl: getRuntimeConfigValue('CONF_BASE_URL'), token: getRuntimeConfigValue('CONF_TOKEN')};
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
function stripHtml(html) {
|
|
@@ -459,7 +462,7 @@ export async function executeUtilityTool(name, args = {}) {
|
|
|
459
462
|
}
|
|
460
463
|
|
|
461
464
|
async function jiraGetIssue({issueKey}) {
|
|
462
|
-
if (
|
|
465
|
+
if (isDryRun()) {
|
|
463
466
|
return ok({key: issueKey, fields: {summary: '[DRY] Mock issue', status: {name: 'To Do'}}});
|
|
464
467
|
}
|
|
465
468
|
const {baseUrl, token} = jiraConfig();
|
|
@@ -496,7 +499,7 @@ async function jiraGetIssue({issueKey}) {
|
|
|
496
499
|
}
|
|
497
500
|
|
|
498
501
|
async function jiraSearchIssues({jql, maxResults = 20}) {
|
|
499
|
-
if (
|
|
502
|
+
if (isDryRun()) return ok({total: 0, issues: []});
|
|
500
503
|
const {baseUrl, token} = jiraConfig();
|
|
501
504
|
const data = await requestJson(
|
|
502
505
|
baseUrl,
|
|
@@ -515,7 +518,7 @@ async function jiraSearchIssues({jql, maxResults = 20}) {
|
|
|
515
518
|
}
|
|
516
519
|
|
|
517
520
|
async function bitbucketListPrs({projectKey, repoSlug, state = 'OPEN', limit = 25}) {
|
|
518
|
-
if (
|
|
521
|
+
if (isDryRun()) return ok({total: 0, prs: []});
|
|
519
522
|
const {baseUrl, token} = bitbucketConfig();
|
|
520
523
|
const data = await requestJson(
|
|
521
524
|
baseUrl,
|
|
@@ -535,7 +538,7 @@ async function bitbucketListPrs({projectKey, repoSlug, state = 'OPEN', limit = 2
|
|
|
535
538
|
}
|
|
536
539
|
|
|
537
540
|
async function bitbucketGetPr({projectKey, repoSlug, prId}) {
|
|
538
|
-
if (
|
|
541
|
+
if (isDryRun()) return ok({id: prId, title: '[DRY] Mock PR', state: 'OPEN'});
|
|
539
542
|
const {baseUrl, token} = bitbucketConfig();
|
|
540
543
|
const [pr, activities] = await Promise.all([
|
|
541
544
|
requestJson(baseUrl, `/rest/api/1.0/projects/${projectKey}/repos/${repoSlug}/pull-requests/${prId}`, {token}),
|
|
@@ -568,7 +571,7 @@ async function bitbucketGetPr({projectKey, repoSlug, prId}) {
|
|
|
568
571
|
}
|
|
569
572
|
|
|
570
573
|
async function bitbucketGetPrChanges({projectKey, repoSlug, prId}) {
|
|
571
|
-
if (
|
|
574
|
+
if (isDryRun()) return ok({total: 0, files: []});
|
|
572
575
|
const {baseUrl, token} = bitbucketConfig();
|
|
573
576
|
const data = await requestJson(
|
|
574
577
|
baseUrl,
|
|
@@ -591,7 +594,7 @@ async function bitbucketGetPrDiff({
|
|
|
591
594
|
contextLines = 3,
|
|
592
595
|
excludePatterns = ['__snapshots__', 'messages_en.json', 'messages_ko.json'],
|
|
593
596
|
}) {
|
|
594
|
-
if (
|
|
597
|
+
if (isDryRun()) return ok({diffs: []});
|
|
595
598
|
const {baseUrl, token} = bitbucketConfig();
|
|
596
599
|
const pathParam = path ? `&path=${encodeURIComponent(path)}` : '';
|
|
597
600
|
const data = await requestJson(
|
|
@@ -634,7 +637,7 @@ async function bitbucketGetPrDiff({
|
|
|
634
637
|
}
|
|
635
638
|
|
|
636
639
|
async function bitbucketGetPrComments({projectKey, repoSlug, prId}) {
|
|
637
|
-
if (
|
|
640
|
+
if (isDryRun()) return ok({total: 0, comments: []});
|
|
638
641
|
const {baseUrl, token} = bitbucketConfig();
|
|
639
642
|
const data = await requestJson(
|
|
640
643
|
baseUrl,
|
|
@@ -662,7 +665,7 @@ async function bitbucketGetPrComments({projectKey, repoSlug, prId}) {
|
|
|
662
665
|
|
|
663
666
|
async function bitbucketAddPrComment({projectKey, repoSlug, prId, text: commentText, parentId}) {
|
|
664
667
|
const {baseUrl, token} = bitbucketConfig();
|
|
665
|
-
if (
|
|
668
|
+
if (isDryRun()) return ok({success: true, dryRun: true, text: commentText});
|
|
666
669
|
const result = await requestJson(
|
|
667
670
|
baseUrl,
|
|
668
671
|
`/rest/api/1.0/projects/${projectKey}/repos/${repoSlug}/pull-requests/${prId}/comments`,
|
|
@@ -682,7 +685,7 @@ async function bitbucketAddPrInlineComment({
|
|
|
682
685
|
fileType = 'TO',
|
|
683
686
|
}) {
|
|
684
687
|
const {baseUrl, token} = bitbucketConfig();
|
|
685
|
-
if (
|
|
688
|
+
if (isDryRun()) return ok({success: true, dryRun: true, text: commentText, filePath, line});
|
|
686
689
|
const result = await requestJson(
|
|
687
690
|
baseUrl,
|
|
688
691
|
`/rest/api/1.0/projects/${projectKey}/repos/${repoSlug}/pull-requests/${prId}/comments`,
|
|
@@ -699,7 +702,7 @@ async function bitbucketAddPrInlineComment({
|
|
|
699
702
|
}
|
|
700
703
|
|
|
701
704
|
async function bitbucketGetFile({projectKey, repoSlug, filePath, branch = 'master'}) {
|
|
702
|
-
if (
|
|
705
|
+
if (isDryRun()) return text('[DRY] Mock file content');
|
|
703
706
|
const {baseUrl, token} = bitbucketConfig();
|
|
704
707
|
const encodedPath = filePath.split('/').map(encodeURIComponent).join('/');
|
|
705
708
|
const content = await requestText(
|
|
@@ -711,7 +714,7 @@ async function bitbucketGetFile({projectKey, repoSlug, filePath, branch = 'maste
|
|
|
711
714
|
}
|
|
712
715
|
|
|
713
716
|
async function confluenceSearch({query, limit = 10}) {
|
|
714
|
-
if (
|
|
717
|
+
if (isDryRun()) return ok({total: 0, results: []});
|
|
715
718
|
const {baseUrl, token} = confluenceConfig();
|
|
716
719
|
const data = await requestJson(
|
|
717
720
|
baseUrl,
|
|
@@ -732,7 +735,7 @@ async function confluenceSearch({query, limit = 10}) {
|
|
|
732
735
|
}
|
|
733
736
|
|
|
734
737
|
async function confluenceGetPage({pageId}) {
|
|
735
|
-
if (
|
|
738
|
+
if (isDryRun()) return ok({id: pageId, title: '[DRY] Mock page', body: 'dry'});
|
|
736
739
|
const {baseUrl, token} = confluenceConfig();
|
|
737
740
|
const data = await requestJson(
|
|
738
741
|
baseUrl,
|
|
@@ -755,7 +758,7 @@ async function confluenceGetPage({pageId}) {
|
|
|
755
758
|
}
|
|
756
759
|
|
|
757
760
|
async function confluenceGetChildren({pageId, limit = 25}) {
|
|
758
|
-
if (
|
|
761
|
+
if (isDryRun()) return ok({total: 0, children: []});
|
|
759
762
|
const {baseUrl, token} = confluenceConfig();
|
|
760
763
|
const data = await requestJson(
|
|
761
764
|
baseUrl,
|
|
@@ -772,7 +775,7 @@ async function confluenceGetChildren({pageId, limit = 25}) {
|
|
|
772
775
|
}
|
|
773
776
|
|
|
774
777
|
async function confluenceListSpaces({limit = 20}) {
|
|
775
|
-
if (
|
|
778
|
+
if (isDryRun()) return ok({total: 0, spaces: []});
|
|
776
779
|
const {baseUrl, token} = confluenceConfig();
|
|
777
780
|
const data = await requestJson(baseUrl, `/rest/api/space?limit=${limit}&expand=description.plain`, {
|
|
778
781
|
token,
|
|
@@ -787,7 +790,7 @@ async function confluenceListSpaces({limit = 20}) {
|
|
|
787
790
|
}
|
|
788
791
|
|
|
789
792
|
async function confluenceGetPageStorage({pageId}) {
|
|
790
|
-
if (
|
|
793
|
+
if (isDryRun()) return ok({id: pageId, title: '[DRY] Mock page', version: 1, body: '<p>dry</p>'});
|
|
791
794
|
const {baseUrl, token} = confluenceConfig();
|
|
792
795
|
const data = await requestJson(baseUrl, `/rest/api/content/${pageId}?expand=body.storage,version,title`, {
|
|
793
796
|
token,
|
|
@@ -802,7 +805,7 @@ async function confluenceGetPageStorage({pageId}) {
|
|
|
802
805
|
|
|
803
806
|
async function confluenceCreatePage({spaceKey, parentId, title, body}) {
|
|
804
807
|
const {baseUrl, token} = confluenceConfig();
|
|
805
|
-
if (
|
|
808
|
+
if (isDryRun()) return ok({id: 'DRY', title, url: `${baseUrl}/pages/viewpage.action?pageId=DRY`});
|
|
806
809
|
const data = await requestJson(baseUrl, '/rest/api/content', {
|
|
807
810
|
method: 'POST',
|
|
808
811
|
token,
|
|
@@ -820,7 +823,7 @@ async function confluenceCreatePage({spaceKey, parentId, title, body}) {
|
|
|
820
823
|
|
|
821
824
|
async function confluenceUpdatePage({pageId, title, body, minorEdit = false}) {
|
|
822
825
|
const {baseUrl, token} = confluenceConfig();
|
|
823
|
-
if (
|
|
826
|
+
if (isDryRun()) return ok({id: pageId, title: title || '[DRY] Mock page', version: 2, dryRun: true});
|
|
824
827
|
const current = await requestJson(baseUrl, `/rest/api/content/${pageId}?expand=version,title`, {token});
|
|
825
828
|
const nextVersion = (current.version?.number || 0) + 1;
|
|
826
829
|
const resolvedTitle = title || current.title;
|
|
@@ -844,7 +847,7 @@ async function confluenceUpdatePage({pageId, title, body, minorEdit = false}) {
|
|
|
844
847
|
}
|
|
845
848
|
|
|
846
849
|
async function confluenceListVersions({pageId, limit = 25, start = 0}) {
|
|
847
|
-
if (
|
|
850
|
+
if (isDryRun()) return ok({total: 0, start, limit, versions: []});
|
|
848
851
|
const {baseUrl, token} = confluenceConfig();
|
|
849
852
|
const data = await requestJson(
|
|
850
853
|
baseUrl,
|
|
@@ -862,7 +865,7 @@ async function confluenceListVersions({pageId, limit = 25, start = 0}) {
|
|
|
862
865
|
}
|
|
863
866
|
|
|
864
867
|
async function confluenceGetPageVersion({pageId, version}) {
|
|
865
|
-
if (
|
|
868
|
+
if (isDryRun()) return ok({id: pageId, title: '[DRY] Mock page', version, body: 'dry'});
|
|
866
869
|
const {baseUrl, token} = confluenceConfig();
|
|
867
870
|
const data = await requestJson(
|
|
868
871
|
baseUrl,
|
|
@@ -881,7 +884,7 @@ async function confluenceGetPageVersion({pageId, version}) {
|
|
|
881
884
|
}
|
|
882
885
|
|
|
883
886
|
async function confluenceGetCalendarEvents({subCalendarId, date}) {
|
|
884
|
-
if (
|
|
887
|
+
if (isDryRun()) {
|
|
885
888
|
return ok({
|
|
886
889
|
date,
|
|
887
890
|
total: 1,
|