tdecollab 0.1.2 → 0.2.0
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 +6 -0
- package/dist/chunk-2IQ4QMK3.js +749 -0
- package/dist/chunk-2IQ4QMK3.js.map +1 -0
- package/dist/chunk-SJ7KPK6Q.js +58 -0
- package/dist/chunk-SJ7KPK6Q.js.map +1 -0
- package/dist/chunk-T73I3OT6.js +964 -0
- package/dist/chunk-T73I3OT6.js.map +1 -0
- package/dist/cli.js +599 -7
- package/dist/cli.js.map +1 -1
- package/dist/image-downloader-D57KFAIQ.js +123 -0
- package/dist/image-downloader-D57KFAIQ.js.map +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/server-HS774DWY.js +9 -0
- package/package.json +2 -2
- package/dist/chunk-3TQ2OSYU.js +0 -287
- package/dist/chunk-3TQ2OSYU.js.map +0 -1
- package/dist/chunk-N44NISLJ.js +0 -361
- package/dist/chunk-N44NISLJ.js.map +0 -1
- package/dist/server-H24WSQEE.js +0 -8
- /package/dist/{server-H24WSQEE.js.map → server-HS774DWY.js.map} +0 -0
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-SJ7KPK6Q.js";
|
|
4
|
+
|
|
5
|
+
// src/confluence/api/content.ts
|
|
6
|
+
var ConfluenceContentApi = class {
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
}
|
|
10
|
+
async getPage(id, expand) {
|
|
11
|
+
const expandParam = expand ? expand.join(",") : "body.storage,version,space,metadata.labels";
|
|
12
|
+
const response = await this.client.get(`/rest/api/content/${id}`, {
|
|
13
|
+
params: { expand: expandParam }
|
|
14
|
+
});
|
|
15
|
+
return response.data;
|
|
16
|
+
}
|
|
17
|
+
async getPageByTitle(spaceKey, title, expand) {
|
|
18
|
+
const expandParam = expand ? expand.join(",") : "body.storage,version,space";
|
|
19
|
+
const response = await this.client.get("/rest/api/content", {
|
|
20
|
+
params: {
|
|
21
|
+
spaceKey,
|
|
22
|
+
title,
|
|
23
|
+
expand: expandParam,
|
|
24
|
+
limit: 1
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
if (response.data.results && response.data.results.length > 0) {
|
|
28
|
+
return response.data.results[0];
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
async createPage(params) {
|
|
33
|
+
const data = {
|
|
34
|
+
type: "page",
|
|
35
|
+
title: params.title,
|
|
36
|
+
space: { key: params.spaceKey },
|
|
37
|
+
body: {
|
|
38
|
+
storage: {
|
|
39
|
+
value: params.body,
|
|
40
|
+
representation: "storage"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
if (params.parentId) {
|
|
45
|
+
data.ancestors = [{ id: params.parentId }];
|
|
46
|
+
}
|
|
47
|
+
const response = await this.client.post("/rest/api/content", data);
|
|
48
|
+
if (params.labels && params.labels.length > 0) {
|
|
49
|
+
await this.addLabels(response.data.id, params.labels);
|
|
50
|
+
}
|
|
51
|
+
return response.data;
|
|
52
|
+
}
|
|
53
|
+
async updatePage(params) {
|
|
54
|
+
const data = {
|
|
55
|
+
version: { number: params.version + 1 },
|
|
56
|
+
title: params.title,
|
|
57
|
+
type: "page",
|
|
58
|
+
body: {
|
|
59
|
+
storage: {
|
|
60
|
+
value: params.body,
|
|
61
|
+
representation: "storage"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const response = await this.client.put(`/rest/api/content/${params.id}`, data);
|
|
66
|
+
return response.data;
|
|
67
|
+
}
|
|
68
|
+
async deletePage(id) {
|
|
69
|
+
await this.client.delete(`/rest/api/content/${id}`);
|
|
70
|
+
}
|
|
71
|
+
async getChildPages(id, start = 0, limit = 25) {
|
|
72
|
+
const response = await this.client.get(`/rest/api/content/${id}/child/page`, {
|
|
73
|
+
params: { start, limit }
|
|
74
|
+
});
|
|
75
|
+
return response.data.results;
|
|
76
|
+
}
|
|
77
|
+
// Label helper inside content api or separate?
|
|
78
|
+
// Let's implement basic label addition here since it's used in create.
|
|
79
|
+
// Actually, label logic is in label.ts, but due to circular dependency or convenience...
|
|
80
|
+
// Let's implement it here privately or import it.
|
|
81
|
+
// Better to keep it separate as per plan, but `this.client` is available here.
|
|
82
|
+
// I'll implement a simple one here or use the separate class later.
|
|
83
|
+
// For now, simple implementation to support createPage.
|
|
84
|
+
async addLabels(id, labels) {
|
|
85
|
+
const data = labels.map((name) => ({ prefix: "global", name }));
|
|
86
|
+
await this.client.post(`/rest/api/content/${id}/label`, data);
|
|
87
|
+
}
|
|
88
|
+
// Attachment 관련 메서드
|
|
89
|
+
async getAttachments(pageId, filename) {
|
|
90
|
+
const response = await this.client.get(`/rest/api/content/${pageId}/child/attachment`, {
|
|
91
|
+
params: {
|
|
92
|
+
filename,
|
|
93
|
+
expand: "version"
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return response.data.results;
|
|
97
|
+
}
|
|
98
|
+
async downloadAttachment(downloadUrl) {
|
|
99
|
+
const response = await this.client.get(downloadUrl, {
|
|
100
|
+
responseType: "arraybuffer"
|
|
101
|
+
});
|
|
102
|
+
return Buffer.from(response.data);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// src/confluence/api/space.ts
|
|
107
|
+
var ConfluenceSpaceApi = class {
|
|
108
|
+
constructor(client) {
|
|
109
|
+
this.client = client;
|
|
110
|
+
}
|
|
111
|
+
async getSpaces(type = "global", start = 0, limit = 25) {
|
|
112
|
+
const response = await this.client.get("/rest/api/space", {
|
|
113
|
+
params: { type, start, limit }
|
|
114
|
+
});
|
|
115
|
+
return response.data.results;
|
|
116
|
+
}
|
|
117
|
+
async getSpace(spaceKey) {
|
|
118
|
+
const response = await this.client.get(`/rest/api/space/${spaceKey}`);
|
|
119
|
+
return response.data;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/confluence/api/search.ts
|
|
124
|
+
var ConfluenceSearchApi = class {
|
|
125
|
+
constructor(client) {
|
|
126
|
+
this.client = client;
|
|
127
|
+
}
|
|
128
|
+
async searchByCql(cql, start = 0, limit = 25, expand) {
|
|
129
|
+
const expandParam = expand ? expand.join(",") : "body.storage,version,space,metadata.labels";
|
|
130
|
+
const response = await this.client.get("/rest/api/content/search", {
|
|
131
|
+
params: {
|
|
132
|
+
cql,
|
|
133
|
+
start,
|
|
134
|
+
limit,
|
|
135
|
+
expand: expandParam
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return response.data;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// src/common/http-client.ts
|
|
143
|
+
import axios from "axios";
|
|
144
|
+
|
|
145
|
+
// src/common/errors.ts
|
|
146
|
+
var TdeCollabError = class extends Error {
|
|
147
|
+
constructor(message) {
|
|
148
|
+
super(message);
|
|
149
|
+
this.name = this.constructor.name;
|
|
150
|
+
Error.captureStackTrace(this, this.constructor);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
var ApiError = class extends TdeCollabError {
|
|
154
|
+
constructor(statusCode, message, data) {
|
|
155
|
+
super(`API \uC694\uCCAD \uC2E4\uD328 (${statusCode}): ${message}`);
|
|
156
|
+
this.statusCode = statusCode;
|
|
157
|
+
this.data = data;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
var AuthError = class extends TdeCollabError {
|
|
161
|
+
constructor(message = "\uC778\uC99D\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4") {
|
|
162
|
+
super(message);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
var NotFoundError = class extends TdeCollabError {
|
|
166
|
+
constructor(resource, id) {
|
|
167
|
+
super(`${resource} '${id}'\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
var ConflictError = class extends TdeCollabError {
|
|
171
|
+
constructor(message) {
|
|
172
|
+
super(message);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/common/http-client.ts
|
|
177
|
+
function createHttpClient(config) {
|
|
178
|
+
const client = axios.create({
|
|
179
|
+
baseURL: config.baseUrl,
|
|
180
|
+
timeout: 3e4,
|
|
181
|
+
// 30초 타임아웃
|
|
182
|
+
headers: {
|
|
183
|
+
"Content-Type": "application/json"
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
client.interceptors.request.use((reqConfig) => {
|
|
187
|
+
if (config.auth.username && config.auth.token) {
|
|
188
|
+
const token = Buffer.from(`${config.auth.username}:${config.auth.token}`).toString("base64");
|
|
189
|
+
reqConfig.headers.Authorization = `Basic ${token}`;
|
|
190
|
+
} else if (config.auth.token) {
|
|
191
|
+
if (!reqConfig.headers.Authorization && !reqConfig.headers["PRIVATE-TOKEN"]) {
|
|
192
|
+
reqConfig.headers.Authorization = `Bearer ${config.auth.token}`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return reqConfig;
|
|
196
|
+
});
|
|
197
|
+
client.interceptors.response.use(
|
|
198
|
+
(response) => {
|
|
199
|
+
logger.debug(`[HTTP] ${response.status} ${response.config.method?.toUpperCase()} ${response.config.url}`);
|
|
200
|
+
return response;
|
|
201
|
+
},
|
|
202
|
+
(error) => {
|
|
203
|
+
if (error.response) {
|
|
204
|
+
const status = error.response.status;
|
|
205
|
+
const method = error.config?.method?.toUpperCase();
|
|
206
|
+
const url = error.config?.url;
|
|
207
|
+
const message = error.response.data?.message || error.message;
|
|
208
|
+
logger.error(`[HTTP] ${status} ${method} ${url} - ${message}`);
|
|
209
|
+
if (status === 401 || status === 403) {
|
|
210
|
+
throw new AuthError(`\uC778\uC99D \uC2E4\uD328: ${message}`);
|
|
211
|
+
}
|
|
212
|
+
if (status === 404) {
|
|
213
|
+
throw new NotFoundError("\uB9AC\uC18C\uC2A4", url || "unknown");
|
|
214
|
+
}
|
|
215
|
+
if (status === 409) {
|
|
216
|
+
throw new ConflictError(`\uCDA9\uB3CC \uBC1C\uC0DD: ${message}`);
|
|
217
|
+
}
|
|
218
|
+
throw new ApiError(status, message, error.response.data);
|
|
219
|
+
} else if (error.request) {
|
|
220
|
+
logger.error(`[HTTP] No Response: ${error.message}`);
|
|
221
|
+
throw new ApiError(0, `\uC11C\uBC84\uB85C\uBD80\uD130 \uC751\uB2F5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: ${error.message}`);
|
|
222
|
+
} else {
|
|
223
|
+
logger.error(`[HTTP] Request Error: ${error.message}`);
|
|
224
|
+
throw new ApiError(0, `\uC694\uCCAD \uC124\uC815 \uC911 \uC624\uB958 \uBC1C\uC0DD: ${error.message}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
return client;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/confluence/api/client.ts
|
|
232
|
+
function createConfluenceClient(config) {
|
|
233
|
+
return createHttpClient(config);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/confluence/converters/md-to-storage.ts
|
|
237
|
+
import MarkdownIt from "markdown-it";
|
|
238
|
+
var MarkdownToStorageConverter = class {
|
|
239
|
+
md;
|
|
240
|
+
constructor() {
|
|
241
|
+
this.md = new MarkdownIt({
|
|
242
|
+
html: true,
|
|
243
|
+
linkify: true,
|
|
244
|
+
breaks: true
|
|
245
|
+
});
|
|
246
|
+
this.md.renderer.rules.fence = (tokens, idx) => {
|
|
247
|
+
const token = tokens[idx];
|
|
248
|
+
const code = token.content.trim();
|
|
249
|
+
const lang = token.info.trim();
|
|
250
|
+
return `<ac:structured-macro ac:name="code" ac:schema-version="1">
|
|
251
|
+
<ac:parameter ac:name="language">${lang || "text"}</ac:parameter>
|
|
252
|
+
<ac:plain-text-body><![CDATA[${code}]]></ac:plain-text-body>
|
|
253
|
+
</ac:structured-macro>`;
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
convert(markdown) {
|
|
257
|
+
return this.md.render(markdown);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
// src/confluence/converters/storage-to-md.ts
|
|
262
|
+
var StorageToMarkdownConverter = class {
|
|
263
|
+
convert(storageHtml, imageUrlMap) {
|
|
264
|
+
let md = storageHtml;
|
|
265
|
+
if (imageUrlMap && imageUrlMap.size > 0) {
|
|
266
|
+
imageUrlMap.forEach((localPath, originalTag) => {
|
|
267
|
+
const filename = localPath.split("/").pop() || "image";
|
|
268
|
+
const altText = filename.replace(/\.[^.]+$/, "");
|
|
269
|
+
const markdownImage = ``;
|
|
270
|
+
md = md.replace(originalTag, markdownImage);
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
md = md.replace(
|
|
274
|
+
/<ac:image[^>]*>[\s\S]*?<ri:attachment\s+ri:filename="([^"]+)"[\s\S]*?<\/ac:image>/g,
|
|
275
|
+
(match, filename) => {
|
|
276
|
+
return ``;
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
md = md.replace(
|
|
280
|
+
/<ac:image[^>]*>[\s\S]*?<ri:url\s+ri:value="([^"]+)"[\s\S]*?<\/ac:image>/g,
|
|
281
|
+
(match, url) => {
|
|
282
|
+
const filename = url.split("/").pop() || "image";
|
|
283
|
+
return ``;
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
md = md.replace(
|
|
287
|
+
/<img\s+[^>]*\/?>/g,
|
|
288
|
+
(match) => {
|
|
289
|
+
const srcMatch = /src="([^"]+)"/.exec(match);
|
|
290
|
+
const altMatch = /alt="([^"]*)"/.exec(match);
|
|
291
|
+
if (srcMatch) {
|
|
292
|
+
const src = srcMatch[1];
|
|
293
|
+
const altText = altMatch ? altMatch[1] : src.split("/").pop() || "image";
|
|
294
|
+
return ``;
|
|
295
|
+
}
|
|
296
|
+
return match;
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
md = md.replace(/<ac:structured-macro[^>]*ac:name="code"[^>]*>[\s\S]*?<ac:parameter[^>]*ac:name="language">([^<]*)<\/ac:parameter>[\s\S]*?<ac:plain-text-body><!\[CDATA\[([\s\S]*?)\]\]><\/ac:plain-text-body>[\s\S]*?<\/ac:structured-macro>/g, (match, lang, code) => {
|
|
300
|
+
return `\`\`\`${lang}
|
|
301
|
+
${code}
|
|
302
|
+
\`\`\``;
|
|
303
|
+
});
|
|
304
|
+
md = md.replace(/<h1>(.*?)<\/h1>/g, "# $1\n");
|
|
305
|
+
md = md.replace(/<h2>(.*?)<\/h2>/g, "## $1\n");
|
|
306
|
+
md = md.replace(/<h3>(.*?)<\/h3>/g, "### $1\n");
|
|
307
|
+
md = md.replace(/<p>(.*?)<\/p>/g, "$1\n\n");
|
|
308
|
+
md = md.replace(/<strong>(.*?)<\/strong>/g, "**$1**");
|
|
309
|
+
md = md.replace(/<b>(.*?)<\/b>/g, "**$1**");
|
|
310
|
+
md = md.replace(/<em>(.*?)<\/em>/g, "*$1*");
|
|
311
|
+
md = md.replace(/<i>(.*?)<\/i>/g, "*$1*");
|
|
312
|
+
md = md.replace(/<ul>([\s\S]*?)<\/ul>/g, (match, content) => {
|
|
313
|
+
return content.replace(/<li>(.*?)<\/li>/g, "- $1\n");
|
|
314
|
+
});
|
|
315
|
+
md = md.replace(/<ol>([\s\S]*?)<\/ol>/g, (match, content) => {
|
|
316
|
+
let i = 1;
|
|
317
|
+
return content.replace(/<li>(.*?)<\/li>/g, () => `${i++}. $1
|
|
318
|
+
`);
|
|
319
|
+
});
|
|
320
|
+
md = md.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/"/g, '"');
|
|
321
|
+
return md.trim();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// src/common/config.ts
|
|
326
|
+
import dotenv from "dotenv";
|
|
327
|
+
dotenv.config();
|
|
328
|
+
function getEnvOrThrow(key, description) {
|
|
329
|
+
const value = process.env[key];
|
|
330
|
+
if (!value) {
|
|
331
|
+
const errorMsg = `\uD658\uACBD\uBCC0\uC218 '${key}'\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (${description})`;
|
|
332
|
+
logger.error(errorMsg);
|
|
333
|
+
throw new Error(errorMsg);
|
|
334
|
+
}
|
|
335
|
+
return value;
|
|
336
|
+
}
|
|
337
|
+
function loadConfluenceConfig() {
|
|
338
|
+
const baseUrl = getEnvOrThrow("CONFLUENCE_BASE_URL", "Confluence \uAE30\uBCF8 URL");
|
|
339
|
+
const username = process.env.CONFLUENCE_USERNAME;
|
|
340
|
+
const token = getEnvOrThrow("CONFLUENCE_API_TOKEN", "Confluence API \uD1A0\uD070");
|
|
341
|
+
return {
|
|
342
|
+
baseUrl,
|
|
343
|
+
auth: {
|
|
344
|
+
username,
|
|
345
|
+
token
|
|
346
|
+
// API 토큰은 일반적으로 패스워드 필드에 사용되지만, 여기서는 token으로 저장하여 범용성 확보
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function loadJiraConfig() {
|
|
351
|
+
const baseUrl = getEnvOrThrow("JIRA_BASE_URL", "JIRA \uAE30\uBCF8 URL");
|
|
352
|
+
const username = process.env.JIRA_USERNAME;
|
|
353
|
+
const token = getEnvOrThrow("JIRA_API_TOKEN", "JIRA API \uD1A0\uD070");
|
|
354
|
+
return {
|
|
355
|
+
baseUrl,
|
|
356
|
+
auth: {
|
|
357
|
+
username,
|
|
358
|
+
token
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function loadGitlabConfig() {
|
|
363
|
+
const baseUrl = process.env.GITLAB_BASE_URL || "https://gitlab.com";
|
|
364
|
+
const token = getEnvOrThrow("GITLAB_PRIVATE_TOKEN", "GitLab Private Token");
|
|
365
|
+
return {
|
|
366
|
+
baseUrl,
|
|
367
|
+
auth: {
|
|
368
|
+
token
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/jira/api/issue.ts
|
|
374
|
+
var JiraIssueApi = class {
|
|
375
|
+
constructor(client) {
|
|
376
|
+
this.client = client;
|
|
377
|
+
}
|
|
378
|
+
async getIssue(issueKey, fields, expand) {
|
|
379
|
+
const params = {};
|
|
380
|
+
if (fields && fields.length > 0) {
|
|
381
|
+
params.fields = fields.join(",");
|
|
382
|
+
}
|
|
383
|
+
if (expand && expand.length > 0) {
|
|
384
|
+
params.expand = expand.join(",");
|
|
385
|
+
}
|
|
386
|
+
const response = await this.client.get(`/rest/api/2/issue/${issueKey}`, { params });
|
|
387
|
+
return response.data;
|
|
388
|
+
}
|
|
389
|
+
async createIssue(params) {
|
|
390
|
+
const fields = {
|
|
391
|
+
project: { key: params.projectKey },
|
|
392
|
+
summary: params.summary,
|
|
393
|
+
issuetype: { name: params.issueType }
|
|
394
|
+
};
|
|
395
|
+
if (params.description) fields.description = params.description;
|
|
396
|
+
if (params.assignee) fields.assignee = { name: params.assignee };
|
|
397
|
+
if (params.priority) fields.priority = { name: params.priority };
|
|
398
|
+
if (params.labels) fields.labels = params.labels;
|
|
399
|
+
if (params.components) {
|
|
400
|
+
fields.components = params.components.map((name) => ({ name }));
|
|
401
|
+
}
|
|
402
|
+
if (params.parentKey) {
|
|
403
|
+
fields.parent = { key: params.parentKey };
|
|
404
|
+
}
|
|
405
|
+
if (params.customFields) {
|
|
406
|
+
Object.assign(fields, params.customFields);
|
|
407
|
+
}
|
|
408
|
+
const response = await this.client.post("/rest/api/2/issue", { fields });
|
|
409
|
+
return response.data;
|
|
410
|
+
}
|
|
411
|
+
async updateIssue(issueKey, params) {
|
|
412
|
+
const fields = {};
|
|
413
|
+
if (params.summary) fields.summary = params.summary;
|
|
414
|
+
if (params.description !== void 0) fields.description = params.description;
|
|
415
|
+
if (params.assignee !== void 0) fields.assignee = params.assignee ? { name: params.assignee } : null;
|
|
416
|
+
if (params.priority) fields.priority = { name: params.priority };
|
|
417
|
+
if (params.labels) fields.labels = params.labels;
|
|
418
|
+
if (params.components) {
|
|
419
|
+
fields.components = params.components.map((name) => ({ name }));
|
|
420
|
+
}
|
|
421
|
+
if (params.customFields) {
|
|
422
|
+
Object.assign(fields, params.customFields);
|
|
423
|
+
}
|
|
424
|
+
await this.client.put(`/rest/api/2/issue/${issueKey}`, { fields });
|
|
425
|
+
}
|
|
426
|
+
async deleteIssue(issueKey, deleteSubtasks = false) {
|
|
427
|
+
await this.client.delete(`/rest/api/2/issue/${issueKey}`, {
|
|
428
|
+
params: { deleteSubtasks }
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
// src/jira/api/search.ts
|
|
434
|
+
var JiraSearchApi = class {
|
|
435
|
+
constructor(client) {
|
|
436
|
+
this.client = client;
|
|
437
|
+
}
|
|
438
|
+
async searchByJql(jql, startAt = 0, maxResults = 50, fields) {
|
|
439
|
+
const params = {
|
|
440
|
+
jql,
|
|
441
|
+
startAt,
|
|
442
|
+
maxResults
|
|
443
|
+
};
|
|
444
|
+
if (fields && fields.length > 0) {
|
|
445
|
+
params.fields = fields.join(",");
|
|
446
|
+
}
|
|
447
|
+
const response = await this.client.get("/rest/api/2/search", { params });
|
|
448
|
+
return response.data;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// src/jira/api/transition.ts
|
|
453
|
+
var JiraTransitionApi = class {
|
|
454
|
+
constructor(client) {
|
|
455
|
+
this.client = client;
|
|
456
|
+
}
|
|
457
|
+
async getTransitions(issueKey) {
|
|
458
|
+
const response = await this.client.get(`/rest/api/2/issue/${issueKey}/transitions`);
|
|
459
|
+
return response.data.transitions;
|
|
460
|
+
}
|
|
461
|
+
async doTransition(issueKey, transitionId, fields) {
|
|
462
|
+
const data = {
|
|
463
|
+
transition: { id: transitionId }
|
|
464
|
+
};
|
|
465
|
+
if (fields) {
|
|
466
|
+
data.fields = fields;
|
|
467
|
+
}
|
|
468
|
+
await this.client.post(`/rest/api/2/issue/${issueKey}/transitions`, data);
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
// src/jira/api/comment.ts
|
|
473
|
+
var JiraCommentApi = class {
|
|
474
|
+
constructor(client) {
|
|
475
|
+
this.client = client;
|
|
476
|
+
}
|
|
477
|
+
async getComments(issueKey, startAt = 0, maxResults = 50) {
|
|
478
|
+
const response = await this.client.get(`/rest/api/2/issue/${issueKey}/comment`, {
|
|
479
|
+
params: { startAt, maxResults }
|
|
480
|
+
});
|
|
481
|
+
return response.data;
|
|
482
|
+
}
|
|
483
|
+
async addComment(issueKey, body) {
|
|
484
|
+
const response = await this.client.post(`/rest/api/2/issue/${issueKey}/comment`, { body });
|
|
485
|
+
return response.data;
|
|
486
|
+
}
|
|
487
|
+
async updateComment(issueKey, commentId, body) {
|
|
488
|
+
const response = await this.client.put(
|
|
489
|
+
`/rest/api/2/issue/${issueKey}/comment/${commentId}`,
|
|
490
|
+
{ body }
|
|
491
|
+
);
|
|
492
|
+
return response.data;
|
|
493
|
+
}
|
|
494
|
+
async deleteComment(issueKey, commentId) {
|
|
495
|
+
await this.client.delete(`/rest/api/2/issue/${issueKey}/comment/${commentId}`);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
// src/jira/api/project.ts
|
|
500
|
+
var JiraProjectApi = class {
|
|
501
|
+
constructor(client) {
|
|
502
|
+
this.client = client;
|
|
503
|
+
}
|
|
504
|
+
async getProjects() {
|
|
505
|
+
const response = await this.client.get("/rest/api/2/project");
|
|
506
|
+
return response.data;
|
|
507
|
+
}
|
|
508
|
+
async getProject(projectKey) {
|
|
509
|
+
const response = await this.client.get(`/rest/api/2/project/${projectKey}`);
|
|
510
|
+
return response.data;
|
|
511
|
+
}
|
|
512
|
+
async getBoards(projectKeyOrId, type) {
|
|
513
|
+
const params = {};
|
|
514
|
+
if (projectKeyOrId) params.projectKeyOrId = projectKeyOrId;
|
|
515
|
+
if (type) params.type = type;
|
|
516
|
+
const response = await this.client.get("/rest/agile/1.0/board", { params });
|
|
517
|
+
return response.data;
|
|
518
|
+
}
|
|
519
|
+
async getSprints(boardId, state) {
|
|
520
|
+
const params = {};
|
|
521
|
+
if (state) params.state = state;
|
|
522
|
+
const response = await this.client.get(`/rest/agile/1.0/board/${boardId}/sprint`, {
|
|
523
|
+
params
|
|
524
|
+
});
|
|
525
|
+
return response.data;
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// src/jira/api/client.ts
|
|
530
|
+
function createJiraClient(config) {
|
|
531
|
+
return createHttpClient(config);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/gitlab/api/project.ts
|
|
535
|
+
var GitlabProjectApi = class {
|
|
536
|
+
constructor(client) {
|
|
537
|
+
this.client = client;
|
|
538
|
+
}
|
|
539
|
+
async getProjects(params) {
|
|
540
|
+
const response = await this.client.get("/projects", {
|
|
541
|
+
params: {
|
|
542
|
+
search: params?.search,
|
|
543
|
+
owned: params?.owned,
|
|
544
|
+
membership: params?.membership,
|
|
545
|
+
per_page: params?.perPage || 20
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
return response.data;
|
|
549
|
+
}
|
|
550
|
+
async getProject(projectId) {
|
|
551
|
+
const response = await this.client.get(`/projects/${encodeURIComponent(projectId)}`);
|
|
552
|
+
return response.data;
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// src/gitlab/api/merge-request.ts
|
|
557
|
+
var GitlabMergeRequestApi = class {
|
|
558
|
+
constructor(client) {
|
|
559
|
+
this.client = client;
|
|
560
|
+
}
|
|
561
|
+
async getMergeRequests(projectId, params) {
|
|
562
|
+
const response = await this.client.get(`/projects/${projectId}/merge_requests`, {
|
|
563
|
+
params: {
|
|
564
|
+
state: params?.state || "opened",
|
|
565
|
+
scope: params?.scope,
|
|
566
|
+
labels: params?.labels,
|
|
567
|
+
per_page: params?.perPage || 20
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
return response.data;
|
|
571
|
+
}
|
|
572
|
+
async getMergeRequest(projectId, mrIid) {
|
|
573
|
+
const response = await this.client.get(
|
|
574
|
+
`/projects/${projectId}/merge_requests/${mrIid}`
|
|
575
|
+
);
|
|
576
|
+
return response.data;
|
|
577
|
+
}
|
|
578
|
+
async getMergeRequestChanges(projectId, mrIid) {
|
|
579
|
+
const response = await this.client.get(
|
|
580
|
+
`/projects/${projectId}/merge_requests/${mrIid}/changes`
|
|
581
|
+
);
|
|
582
|
+
return response.data;
|
|
583
|
+
}
|
|
584
|
+
async createMergeRequest(projectId, data) {
|
|
585
|
+
const response = await this.client.post(`/projects/${projectId}/merge_requests`, data);
|
|
586
|
+
return response.data;
|
|
587
|
+
}
|
|
588
|
+
async updateMergeRequest(projectId, mrIid, data) {
|
|
589
|
+
const response = await this.client.put(
|
|
590
|
+
`/projects/${projectId}/merge_requests/${mrIid}`,
|
|
591
|
+
data
|
|
592
|
+
);
|
|
593
|
+
return response.data;
|
|
594
|
+
}
|
|
595
|
+
async mergeMergeRequest(projectId, mrIid, params) {
|
|
596
|
+
const response = await this.client.put(
|
|
597
|
+
`/projects/${projectId}/merge_requests/${mrIid}/merge`,
|
|
598
|
+
params
|
|
599
|
+
);
|
|
600
|
+
return response.data;
|
|
601
|
+
}
|
|
602
|
+
async getMergeRequestNotes(projectId, mrIid) {
|
|
603
|
+
const response = await this.client.get(
|
|
604
|
+
`/projects/${projectId}/merge_requests/${mrIid}/notes`
|
|
605
|
+
);
|
|
606
|
+
return response.data;
|
|
607
|
+
}
|
|
608
|
+
async addMergeRequestNote(projectId, mrIid, body) {
|
|
609
|
+
const response = await this.client.post(
|
|
610
|
+
`/projects/${projectId}/merge_requests/${mrIid}/notes`,
|
|
611
|
+
{ body }
|
|
612
|
+
);
|
|
613
|
+
return response.data;
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
// src/gitlab/api/pipeline.ts
|
|
618
|
+
var GitlabPipelineApi = class {
|
|
619
|
+
constructor(client) {
|
|
620
|
+
this.client = client;
|
|
621
|
+
}
|
|
622
|
+
async getPipelines(projectId, params) {
|
|
623
|
+
const response = await this.client.get(`/projects/${projectId}/pipelines`, {
|
|
624
|
+
params: {
|
|
625
|
+
status: params?.status,
|
|
626
|
+
ref: params?.ref,
|
|
627
|
+
per_page: params?.perPage || 20
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
return response.data;
|
|
631
|
+
}
|
|
632
|
+
async getPipeline(projectId, pipelineId) {
|
|
633
|
+
const response = await this.client.get(
|
|
634
|
+
`/projects/${projectId}/pipelines/${pipelineId}`
|
|
635
|
+
);
|
|
636
|
+
return response.data;
|
|
637
|
+
}
|
|
638
|
+
async getPipelineJobs(projectId, pipelineId) {
|
|
639
|
+
const response = await this.client.get(
|
|
640
|
+
`/projects/${projectId}/pipelines/${pipelineId}/jobs`
|
|
641
|
+
);
|
|
642
|
+
return response.data;
|
|
643
|
+
}
|
|
644
|
+
async getMergeRequestPipelines(projectId, mrIid) {
|
|
645
|
+
const response = await this.client.get(
|
|
646
|
+
`/projects/${projectId}/merge_requests/${mrIid}/pipelines`
|
|
647
|
+
);
|
|
648
|
+
return response.data;
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
// src/gitlab/api/branch.ts
|
|
653
|
+
var GitlabBranchApi = class {
|
|
654
|
+
constructor(client) {
|
|
655
|
+
this.client = client;
|
|
656
|
+
}
|
|
657
|
+
async getBranches(projectId, params) {
|
|
658
|
+
const response = await this.client.get(`/projects/${projectId}/repository/branches`, {
|
|
659
|
+
params: {
|
|
660
|
+
search: params?.search,
|
|
661
|
+
per_page: params?.perPage || 20
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
return response.data;
|
|
665
|
+
}
|
|
666
|
+
async getBranch(projectId, branchName) {
|
|
667
|
+
const response = await this.client.get(
|
|
668
|
+
`/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`
|
|
669
|
+
);
|
|
670
|
+
return response.data;
|
|
671
|
+
}
|
|
672
|
+
async createBranch(projectId, branchName, ref) {
|
|
673
|
+
const response = await this.client.post(`/projects/${projectId}/repository/branches`, {
|
|
674
|
+
branch: branchName,
|
|
675
|
+
ref
|
|
676
|
+
});
|
|
677
|
+
return response.data;
|
|
678
|
+
}
|
|
679
|
+
async deleteBranch(projectId, branchName) {
|
|
680
|
+
await this.client.delete(
|
|
681
|
+
`/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// src/gitlab/api/repository.ts
|
|
687
|
+
var GitlabRepositoryApi = class {
|
|
688
|
+
constructor(client) {
|
|
689
|
+
this.client = client;
|
|
690
|
+
}
|
|
691
|
+
async getFile(projectId, filePath, ref) {
|
|
692
|
+
const encodedPath = encodeURIComponent(filePath);
|
|
693
|
+
const response = await this.client.get(
|
|
694
|
+
`/projects/${projectId}/repository/files/${encodedPath}`,
|
|
695
|
+
{ params: { ref: ref || "HEAD" } }
|
|
696
|
+
);
|
|
697
|
+
const file = response.data;
|
|
698
|
+
if (file.encoding === "base64") {
|
|
699
|
+
file.content = Buffer.from(file.content, "base64").toString("utf-8");
|
|
700
|
+
}
|
|
701
|
+
return file;
|
|
702
|
+
}
|
|
703
|
+
async getTree(projectId, params) {
|
|
704
|
+
const response = await this.client.get(`/projects/${projectId}/repository/tree`, {
|
|
705
|
+
params: {
|
|
706
|
+
path: params?.path,
|
|
707
|
+
ref: params?.ref,
|
|
708
|
+
recursive: params?.recursive,
|
|
709
|
+
per_page: params?.perPage || 100
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
return response.data;
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
// src/gitlab/api/client.ts
|
|
717
|
+
function createGitlabClient(config) {
|
|
718
|
+
const client = createHttpClient({
|
|
719
|
+
...config,
|
|
720
|
+
baseUrl: `${config.baseUrl}/api/v4`
|
|
721
|
+
});
|
|
722
|
+
client.defaults.headers.common["PRIVATE-TOKEN"] = config.auth.token;
|
|
723
|
+
return client;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
export {
|
|
727
|
+
ConfluenceContentApi,
|
|
728
|
+
ConfluenceSpaceApi,
|
|
729
|
+
ConfluenceSearchApi,
|
|
730
|
+
createConfluenceClient,
|
|
731
|
+
MarkdownToStorageConverter,
|
|
732
|
+
StorageToMarkdownConverter,
|
|
733
|
+
loadConfluenceConfig,
|
|
734
|
+
loadJiraConfig,
|
|
735
|
+
loadGitlabConfig,
|
|
736
|
+
JiraIssueApi,
|
|
737
|
+
JiraSearchApi,
|
|
738
|
+
JiraTransitionApi,
|
|
739
|
+
JiraCommentApi,
|
|
740
|
+
JiraProjectApi,
|
|
741
|
+
createJiraClient,
|
|
742
|
+
GitlabProjectApi,
|
|
743
|
+
GitlabMergeRequestApi,
|
|
744
|
+
GitlabPipelineApi,
|
|
745
|
+
GitlabBranchApi,
|
|
746
|
+
GitlabRepositoryApi,
|
|
747
|
+
createGitlabClient
|
|
748
|
+
};
|
|
749
|
+
//# sourceMappingURL=chunk-2IQ4QMK3.js.map
|