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
package/dist/cli.js
CHANGED
|
@@ -3,11 +3,26 @@ import {
|
|
|
3
3
|
ConfluenceContentApi,
|
|
4
4
|
ConfluenceSearchApi,
|
|
5
5
|
ConfluenceSpaceApi,
|
|
6
|
+
GitlabBranchApi,
|
|
7
|
+
GitlabMergeRequestApi,
|
|
8
|
+
GitlabPipelineApi,
|
|
9
|
+
GitlabProjectApi,
|
|
10
|
+
GitlabRepositoryApi,
|
|
11
|
+
JiraCommentApi,
|
|
12
|
+
JiraIssueApi,
|
|
13
|
+
JiraProjectApi,
|
|
14
|
+
JiraSearchApi,
|
|
15
|
+
JiraTransitionApi,
|
|
6
16
|
MarkdownToStorageConverter,
|
|
7
17
|
StorageToMarkdownConverter,
|
|
8
18
|
createConfluenceClient,
|
|
9
|
-
|
|
10
|
-
|
|
19
|
+
createGitlabClient,
|
|
20
|
+
createJiraClient,
|
|
21
|
+
loadConfluenceConfig,
|
|
22
|
+
loadGitlabConfig,
|
|
23
|
+
loadJiraConfig
|
|
24
|
+
} from "./chunk-2IQ4QMK3.js";
|
|
25
|
+
import "./chunk-SJ7KPK6Q.js";
|
|
11
26
|
|
|
12
27
|
// src/cli.ts
|
|
13
28
|
import { Command } from "commander";
|
|
@@ -29,10 +44,10 @@ function registerConfluenceCommands(program2) {
|
|
|
29
44
|
}
|
|
30
45
|
};
|
|
31
46
|
const pageCmd = confluenceCmd.command("page").description("\uD398\uC774\uC9C0 \uAD00\uB9AC");
|
|
32
|
-
pageCmd.command("get <pageId>").description("\uD398\uC774\uC9C0 \uC870\uD68C").option("-r, --raw", "Raw Storage Format \uCD9C\uB825").option("-q, --quiet", "\uBA54\uD0C0\uB370\uC774\uD130 \uC0DD\uB7B5").action(async (pageId, options) => {
|
|
47
|
+
pageCmd.command("get <pageId>").description("\uD398\uC774\uC9C0 \uC870\uD68C").option("-r, --raw", "Raw Storage Format \uCD9C\uB825").option("-q, --quiet", "\uBA54\uD0C0\uB370\uC774\uD130 \uC0DD\uB7B5").option("-d, --download-images", "\uC774\uBBF8\uC9C0 \uB2E4\uC6B4\uB85C\uB4DC").option("--image-dir <path>", "\uC774\uBBF8\uC9C0 \uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC", "./images").option("-o, --output <file>", "Markdown\uC744 \uD30C\uC77C\uB85C \uC800\uC7A5").action(async (pageId, options) => {
|
|
33
48
|
const client = initClient();
|
|
34
49
|
const api = new ConfluenceContentApi(client);
|
|
35
|
-
const
|
|
50
|
+
const config = loadConfluenceConfig();
|
|
36
51
|
try {
|
|
37
52
|
const page = await api.getPage(pageId);
|
|
38
53
|
if (!options.quiet) {
|
|
@@ -41,21 +56,41 @@ function registerConfluenceCommands(program2) {
|
|
|
41
56
|
console.log(`Space: ${page.space?.name} (${page.space?.key})`);
|
|
42
57
|
console.log(`URL: ${page._links?.base}${page._links?.webui}`);
|
|
43
58
|
}
|
|
59
|
+
let content = "";
|
|
44
60
|
if (options.raw) {
|
|
45
61
|
if (!options.quiet) console.log(chalk.dim("--- Content (Storage Format) ---"));
|
|
46
62
|
if (page.body?.storage?.value) {
|
|
47
|
-
|
|
63
|
+
content = page.body.storage.value;
|
|
48
64
|
} else {
|
|
49
65
|
if (!options.quiet) console.log(chalk.yellow("(No content)"));
|
|
50
66
|
}
|
|
51
67
|
} else {
|
|
52
68
|
if (!options.quiet) console.log(chalk.dim("--- Content (Markdown) ---"));
|
|
53
69
|
if (page.body?.storage?.value) {
|
|
54
|
-
|
|
70
|
+
let imageUrlMap;
|
|
71
|
+
if (options.downloadImages) {
|
|
72
|
+
const { ImageDownloader } = await import("./image-downloader-D57KFAIQ.js");
|
|
73
|
+
const downloader = new ImageDownloader(api, {
|
|
74
|
+
outputDir: path.resolve(process.cwd(), options.imageDir),
|
|
75
|
+
pageId: page.id,
|
|
76
|
+
baseUrl: config.baseUrl
|
|
77
|
+
});
|
|
78
|
+
console.log(chalk.blue("\uC774\uBBF8\uC9C0 \uB2E4\uC6B4\uB85C\uB4DC \uC911..."));
|
|
79
|
+
imageUrlMap = await downloader.downloadAllImages(page.body.storage.value);
|
|
80
|
+
}
|
|
81
|
+
const storageToMd = new StorageToMarkdownConverter();
|
|
82
|
+
content = storageToMd.convert(page.body.storage.value, imageUrlMap);
|
|
55
83
|
} else {
|
|
56
84
|
if (!options.quiet) console.log(chalk.yellow("(No content)"));
|
|
57
85
|
}
|
|
58
86
|
}
|
|
87
|
+
if (options.output) {
|
|
88
|
+
const outputPath = path.resolve(process.cwd(), options.output);
|
|
89
|
+
fs.writeFileSync(outputPath, content, "utf-8");
|
|
90
|
+
console.log(chalk.green(`\uD30C\uC77C \uC800\uC7A5 \uC644\uB8CC: ${outputPath}`));
|
|
91
|
+
} else {
|
|
92
|
+
console.log(content);
|
|
93
|
+
}
|
|
59
94
|
} catch (e) {
|
|
60
95
|
console.error(chalk.red(`Error: ${e.message}`));
|
|
61
96
|
}
|
|
@@ -131,14 +166,571 @@ function registerConfluenceCommands(program2) {
|
|
|
131
166
|
});
|
|
132
167
|
}
|
|
133
168
|
|
|
169
|
+
// src/jira/commands/index.ts
|
|
170
|
+
import chalk2 from "chalk";
|
|
171
|
+
import Table2 from "cli-table3";
|
|
172
|
+
function registerJiraCommands(program2) {
|
|
173
|
+
const jiraCmd = program2.command("jira").description("JIRA \uAD00\uB9AC");
|
|
174
|
+
const initClient = () => {
|
|
175
|
+
try {
|
|
176
|
+
const config = loadJiraConfig();
|
|
177
|
+
return createJiraClient(config);
|
|
178
|
+
} catch (e) {
|
|
179
|
+
console.error(chalk2.red(`\uC124\uC815 \uB85C\uB4DC \uC2E4\uD328: ${e.message}`));
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const issueCmd = jiraCmd.command("issue").description("\uC774\uC288 \uAD00\uB9AC");
|
|
184
|
+
issueCmd.command("get <issueKey>").description("\uC774\uC288 \uC870\uD68C").action(async (issueKey) => {
|
|
185
|
+
const client = initClient();
|
|
186
|
+
const api = new JiraIssueApi(client);
|
|
187
|
+
try {
|
|
188
|
+
const issue = await api.getIssue(issueKey);
|
|
189
|
+
const f = issue.fields;
|
|
190
|
+
console.log(chalk2.bold(`[${issue.key}] ${f.summary}`));
|
|
191
|
+
console.log(chalk2.gray(`Status: ${f.status?.name || "N/A"}`));
|
|
192
|
+
console.log(`Type: ${f.issuetype?.name || "N/A"}`);
|
|
193
|
+
console.log(`Priority: ${f.priority?.name || "N/A"}`);
|
|
194
|
+
console.log(`Assignee: ${f.assignee?.displayName || "\uBBF8\uBC30\uC815"}`);
|
|
195
|
+
console.log(`Reporter: ${f.reporter?.displayName || "N/A"}`);
|
|
196
|
+
console.log(`Labels: ${f.labels?.join(", ") || "\uC5C6\uC74C"}`);
|
|
197
|
+
console.log(`Created: ${f.created || "N/A"}`);
|
|
198
|
+
console.log(`Updated: ${f.updated || "N/A"}`);
|
|
199
|
+
if (f.description) {
|
|
200
|
+
console.log(chalk2.dim("\n--- Description ---"));
|
|
201
|
+
console.log(f.description);
|
|
202
|
+
}
|
|
203
|
+
if (f.subtasks && f.subtasks.length > 0) {
|
|
204
|
+
console.log(chalk2.dim("\n--- Subtasks ---"));
|
|
205
|
+
f.subtasks.forEach((st) => {
|
|
206
|
+
console.log(` - [${st.key}] ${st.fields.summary} (${st.fields.status.name})`);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
} catch (e) {
|
|
210
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
issueCmd.command("create").requiredOption("-p, --project <key>", "\uD504\uB85C\uC81D\uD2B8 \uD0A4").requiredOption("-s, --summary <summary>", "\uC774\uC288 \uC81C\uBAA9").requiredOption("-t, --type <type>", "\uC774\uC288 \uC720\uD615 (Task, Bug, Story \uB4F1)").option("-d, --description <desc>", "\uC774\uC288 \uC124\uBA85").option("-a, --assignee <name>", "\uB2F4\uB2F9\uC790").option("--priority <priority>", "\uC6B0\uC120\uC21C\uC704").option("-l, --labels <labels>", "\uB77C\uBCA8 (\uC27C\uD45C \uAD6C\uBD84)").option("--parent <key>", "\uC0C1\uC704 \uC774\uC288 \uD0A4 (Sub-task)").description("\uC774\uC288 \uC0DD\uC131").action(async (options) => {
|
|
214
|
+
const client = initClient();
|
|
215
|
+
const api = new JiraIssueApi(client);
|
|
216
|
+
try {
|
|
217
|
+
const issue = await api.createIssue({
|
|
218
|
+
projectKey: options.project,
|
|
219
|
+
summary: options.summary,
|
|
220
|
+
issueType: options.type,
|
|
221
|
+
description: options.description,
|
|
222
|
+
assignee: options.assignee,
|
|
223
|
+
priority: options.priority,
|
|
224
|
+
labels: options.labels?.split(",").map((l) => l.trim()),
|
|
225
|
+
parentKey: options.parent
|
|
226
|
+
});
|
|
227
|
+
const config = loadJiraConfig();
|
|
228
|
+
console.log(chalk2.green(`\uC774\uC288 \uC0DD\uC131 \uC644\uB8CC: ${issue.key}`));
|
|
229
|
+
console.log(`URL: ${config.baseUrl}/browse/${issue.key}`);
|
|
230
|
+
} catch (e) {
|
|
231
|
+
console.error(chalk2.red(`\uC0DD\uC131 \uC2E4\uD328: ${e.message}`));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
issueCmd.command("update <issueKey>").option("-s, --summary <summary>", "\uC81C\uBAA9").option("-d, --description <desc>", "\uC124\uBA85").option("-a, --assignee <name>", "\uB2F4\uB2F9\uC790").option("--priority <priority>", "\uC6B0\uC120\uC21C\uC704").option("-l, --labels <labels>", "\uB77C\uBCA8 (\uC27C\uD45C \uAD6C\uBD84)").description("\uC774\uC288 \uC218\uC815").action(async (issueKey, options) => {
|
|
235
|
+
const client = initClient();
|
|
236
|
+
const api = new JiraIssueApi(client);
|
|
237
|
+
try {
|
|
238
|
+
await api.updateIssue(issueKey, {
|
|
239
|
+
summary: options.summary,
|
|
240
|
+
description: options.description,
|
|
241
|
+
assignee: options.assignee,
|
|
242
|
+
priority: options.priority,
|
|
243
|
+
labels: options.labels?.split(",").map((l) => l.trim())
|
|
244
|
+
});
|
|
245
|
+
console.log(chalk2.green(`\uC774\uC288 \uC218\uC815 \uC644\uB8CC: ${issueKey}`));
|
|
246
|
+
} catch (e) {
|
|
247
|
+
console.error(chalk2.red(`\uC218\uC815 \uC2E4\uD328: ${e.message}`));
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
issueCmd.command("transition <issueKey>").option("-l, --list", "\uAC00\uB2A5\uD55C \uD2B8\uB79C\uC9C0\uC158 \uC870\uD68C").option("-t, --transition <id>", "\uD2B8\uB79C\uC9C0\uC158 \uC2E4\uD589").description("\uC774\uC288 \uC0C1\uD0DC \uBCC0\uACBD").action(async (issueKey, options) => {
|
|
251
|
+
const client = initClient();
|
|
252
|
+
const api = new JiraTransitionApi(client);
|
|
253
|
+
try {
|
|
254
|
+
if (options.list || !options.transition) {
|
|
255
|
+
const transitions = await api.getTransitions(issueKey);
|
|
256
|
+
const table = new Table2({
|
|
257
|
+
head: ["ID", "Name", "To"],
|
|
258
|
+
style: { head: ["cyan"] }
|
|
259
|
+
});
|
|
260
|
+
transitions.forEach((t) => table.push([t.id, t.name, t.to.name]));
|
|
261
|
+
console.log(table.toString());
|
|
262
|
+
} else {
|
|
263
|
+
await api.doTransition(issueKey, options.transition);
|
|
264
|
+
console.log(chalk2.green(`\uD2B8\uB79C\uC9C0\uC158 \uC644\uB8CC: ${issueKey}`));
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
jiraCmd.command("search <jql>").option("-n, --max <number>", "\uCD5C\uB300 \uACB0\uACFC \uC218", "20").description("JQL \uAC80\uC0C9").action(async (jql, options) => {
|
|
271
|
+
const client = initClient();
|
|
272
|
+
const api = new JiraSearchApi(client);
|
|
273
|
+
try {
|
|
274
|
+
const result = await api.searchByJql(jql, 0, parseInt(options.max));
|
|
275
|
+
console.log(chalk2.bold(`\uAC80\uC0C9 \uACB0\uACFC: ${result.issues.length}\uAC74 (\uCD1D ${result.total}\uAC74)`));
|
|
276
|
+
const table = new Table2({
|
|
277
|
+
head: ["Key", "Summary", "Status", "Assignee"],
|
|
278
|
+
style: { head: ["cyan"] }
|
|
279
|
+
});
|
|
280
|
+
result.issues.forEach(
|
|
281
|
+
(i) => table.push([
|
|
282
|
+
i.key,
|
|
283
|
+
i.fields.summary.substring(0, 60),
|
|
284
|
+
i.fields.status?.name || "N/A",
|
|
285
|
+
i.fields.assignee?.displayName || "\uBBF8\uBC30\uC815"
|
|
286
|
+
])
|
|
287
|
+
);
|
|
288
|
+
console.log(table.toString());
|
|
289
|
+
} catch (e) {
|
|
290
|
+
console.error(chalk2.red(`\uAC80\uC0C9 \uC2E4\uD328: ${e.message}`));
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
const commentCmd = jiraCmd.command("comment").description("\uCF54\uBA58\uD2B8 \uAD00\uB9AC");
|
|
294
|
+
commentCmd.command("list <issueKey>").description("\uCF54\uBA58\uD2B8 \uBAA9\uB85D \uC870\uD68C").action(async (issueKey) => {
|
|
295
|
+
const client = initClient();
|
|
296
|
+
const api = new JiraCommentApi(client);
|
|
297
|
+
try {
|
|
298
|
+
const result = await api.getComments(issueKey);
|
|
299
|
+
result.comments.forEach((c) => {
|
|
300
|
+
console.log(chalk2.bold(`[${c.id}] ${c.author.displayName} (${c.created})`));
|
|
301
|
+
console.log(c.body);
|
|
302
|
+
console.log(chalk2.dim("---"));
|
|
303
|
+
});
|
|
304
|
+
} catch (e) {
|
|
305
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
commentCmd.command("add <issueKey> <body>").description("\uCF54\uBA58\uD2B8 \uCD94\uAC00").action(async (issueKey, body) => {
|
|
309
|
+
const client = initClient();
|
|
310
|
+
const api = new JiraCommentApi(client);
|
|
311
|
+
try {
|
|
312
|
+
const comment = await api.addComment(issueKey, body);
|
|
313
|
+
console.log(chalk2.green(`\uCF54\uBA58\uD2B8 \uCD94\uAC00 \uC644\uB8CC (ID: ${comment.id})`));
|
|
314
|
+
} catch (e) {
|
|
315
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
const projectCmd = jiraCmd.command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB9AC");
|
|
319
|
+
projectCmd.command("list").description("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C").action(async () => {
|
|
320
|
+
const client = initClient();
|
|
321
|
+
const api = new JiraProjectApi(client);
|
|
322
|
+
try {
|
|
323
|
+
const projects = await api.getProjects();
|
|
324
|
+
const table = new Table2({
|
|
325
|
+
head: ["Key", "Name", "Lead"],
|
|
326
|
+
style: { head: ["cyan"] }
|
|
327
|
+
});
|
|
328
|
+
projects.forEach(
|
|
329
|
+
(p) => table.push([p.key, p.name, p.lead?.displayName || "N/A"])
|
|
330
|
+
);
|
|
331
|
+
console.log(table.toString());
|
|
332
|
+
} catch (e) {
|
|
333
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
projectCmd.command("get <projectKey>").description("\uD504\uB85C\uC81D\uD2B8 \uC0C1\uC138 \uC870\uD68C").action(async (projectKey) => {
|
|
337
|
+
const client = initClient();
|
|
338
|
+
const api = new JiraProjectApi(client);
|
|
339
|
+
try {
|
|
340
|
+
const project = await api.getProject(projectKey);
|
|
341
|
+
console.log(chalk2.bold(`${project.name} (${project.key})`));
|
|
342
|
+
console.log(`Lead: ${project.lead?.displayName || "N/A"}`);
|
|
343
|
+
if (project.issueTypes) {
|
|
344
|
+
console.log(
|
|
345
|
+
`Issue Types: ${project.issueTypes.map((t) => t.name).join(", ")}`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
} catch (e) {
|
|
349
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
const boardCmd = jiraCmd.command("board").description("Agile \uBCF4\uB4DC \uAD00\uB9AC");
|
|
353
|
+
boardCmd.command("list").option("-p, --project <key>", "\uD504\uB85C\uC81D\uD2B8 \uD0A4").description("\uBCF4\uB4DC \uBAA9\uB85D \uC870\uD68C").action(async (options) => {
|
|
354
|
+
const client = initClient();
|
|
355
|
+
const api = new JiraProjectApi(client);
|
|
356
|
+
try {
|
|
357
|
+
const result = await api.getBoards(options.project);
|
|
358
|
+
const table = new Table2({
|
|
359
|
+
head: ["ID", "Name", "Type"],
|
|
360
|
+
style: { head: ["cyan"] }
|
|
361
|
+
});
|
|
362
|
+
result.values.forEach((b) => table.push([b.id.toString(), b.name, b.type]));
|
|
363
|
+
console.log(table.toString());
|
|
364
|
+
} catch (e) {
|
|
365
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
boardCmd.command("sprints <boardId>").option("-s, --state <state>", "\uC0C1\uD0DC \uD544\uD130 (active, closed, future)").description("\uC2A4\uD504\uB9B0\uD2B8 \uBAA9\uB85D \uC870\uD68C").action(async (boardId, options) => {
|
|
369
|
+
const client = initClient();
|
|
370
|
+
const api = new JiraProjectApi(client);
|
|
371
|
+
try {
|
|
372
|
+
const result = await api.getSprints(parseInt(boardId), options.state);
|
|
373
|
+
const table = new Table2({
|
|
374
|
+
head: ["ID", "Name", "State", "Goal"],
|
|
375
|
+
style: { head: ["cyan"] }
|
|
376
|
+
});
|
|
377
|
+
result.values.forEach(
|
|
378
|
+
(s) => table.push([s.id.toString(), s.name, s.state, s.goal || ""])
|
|
379
|
+
);
|
|
380
|
+
console.log(table.toString());
|
|
381
|
+
} catch (e) {
|
|
382
|
+
console.error(chalk2.red(`Error: ${e.message}`));
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/gitlab/commands/index.ts
|
|
388
|
+
import chalk3 from "chalk";
|
|
389
|
+
import Table3 from "cli-table3";
|
|
390
|
+
function registerGitlabCommands(program2) {
|
|
391
|
+
const gitlabCmd = program2.command("gitlab").description("GitLab \uAD00\uB9AC");
|
|
392
|
+
const initClient = () => {
|
|
393
|
+
try {
|
|
394
|
+
const config = loadGitlabConfig();
|
|
395
|
+
return createGitlabClient(config);
|
|
396
|
+
} catch (e) {
|
|
397
|
+
console.error(chalk3.red(`\uC124\uC815 \uB85C\uB4DC \uC2E4\uD328: ${e.message}`));
|
|
398
|
+
process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
const projectCmd = gitlabCmd.command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB9AC");
|
|
402
|
+
projectCmd.command("list").option("-s, --search <query>", "\uD504\uB85C\uC81D\uD2B8\uBA85 \uAC80\uC0C9").option("--owned", "\uC18C\uC720 \uD504\uB85C\uC81D\uD2B8\uB9CC").option("--membership", "\uBA64\uBC84\uC2ED \uD504\uB85C\uC81D\uD2B8\uB9CC").description("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C").action(async (options) => {
|
|
403
|
+
const client = initClient();
|
|
404
|
+
const api = new GitlabProjectApi(client);
|
|
405
|
+
try {
|
|
406
|
+
const projects = await api.getProjects({
|
|
407
|
+
search: options.search,
|
|
408
|
+
owned: options.owned,
|
|
409
|
+
membership: options.membership
|
|
410
|
+
});
|
|
411
|
+
const table = new Table3({
|
|
412
|
+
head: ["ID", "Name", "Visibility", "Default Branch", "Last Activity"],
|
|
413
|
+
style: { head: ["cyan"] }
|
|
414
|
+
});
|
|
415
|
+
projects.forEach(
|
|
416
|
+
(p) => table.push([
|
|
417
|
+
p.id.toString(),
|
|
418
|
+
p.name_with_namespace,
|
|
419
|
+
p.visibility,
|
|
420
|
+
p.default_branch || "N/A",
|
|
421
|
+
p.last_activity_at?.substring(0, 10) || "N/A"
|
|
422
|
+
])
|
|
423
|
+
);
|
|
424
|
+
console.log(table.toString());
|
|
425
|
+
} catch (e) {
|
|
426
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
projectCmd.command("get <projectId>").description("\uD504\uB85C\uC81D\uD2B8 \uC0C1\uC138 \uC870\uD68C").action(async (projectId) => {
|
|
430
|
+
const client = initClient();
|
|
431
|
+
const api = new GitlabProjectApi(client);
|
|
432
|
+
try {
|
|
433
|
+
const p = await api.getProject(parseInt(projectId));
|
|
434
|
+
console.log(chalk3.bold(p.name_with_namespace));
|
|
435
|
+
console.log(`ID: ${p.id}`);
|
|
436
|
+
console.log(`Path: ${p.path_with_namespace}`);
|
|
437
|
+
console.log(`Default Branch: ${p.default_branch}`);
|
|
438
|
+
console.log(`Visibility: ${p.visibility}`);
|
|
439
|
+
console.log(`Web URL: ${p.web_url}`);
|
|
440
|
+
console.log(`SSH URL: ${p.ssh_url_to_repo}`);
|
|
441
|
+
console.log(`HTTP URL: ${p.http_url_to_repo}`);
|
|
442
|
+
console.log(`Last Activity: ${p.last_activity_at}`);
|
|
443
|
+
if (p.description) console.log(`Description: ${p.description}`);
|
|
444
|
+
} catch (e) {
|
|
445
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
const mrCmd = gitlabCmd.command("mr").description("Merge Request \uAD00\uB9AC");
|
|
449
|
+
mrCmd.command("list <projectId>").option("-s, --state <state>", "\uC0C1\uD0DC \uD544\uD130 (opened/closed/merged/all)", "opened").option("--scope <scope>", "\uBC94\uC704 (created_by_me/assigned_to_me)").description("MR \uBAA9\uB85D \uC870\uD68C").action(async (projectId, options) => {
|
|
450
|
+
const client = initClient();
|
|
451
|
+
const api = new GitlabMergeRequestApi(client);
|
|
452
|
+
try {
|
|
453
|
+
const mrs = await api.getMergeRequests(parseInt(projectId), {
|
|
454
|
+
state: options.state,
|
|
455
|
+
scope: options.scope
|
|
456
|
+
});
|
|
457
|
+
const table = new Table3({
|
|
458
|
+
head: ["IID", "Title", "State", "Source \u2192 Target", "Author"],
|
|
459
|
+
style: { head: ["cyan"] }
|
|
460
|
+
});
|
|
461
|
+
mrs.forEach(
|
|
462
|
+
(m) => table.push([
|
|
463
|
+
`!${m.iid}`,
|
|
464
|
+
m.title.substring(0, 50),
|
|
465
|
+
m.state,
|
|
466
|
+
`${m.source_branch} \u2192 ${m.target_branch}`,
|
|
467
|
+
m.author?.name || "N/A"
|
|
468
|
+
])
|
|
469
|
+
);
|
|
470
|
+
console.log(table.toString());
|
|
471
|
+
} catch (e) {
|
|
472
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
mrCmd.command("get <projectId> <mrIid>").option("-c, --changes", "\uBCC0\uACBD \uD30C\uC77C \uD3EC\uD568").description("MR \uC0C1\uC138 \uC870\uD68C").action(async (projectId, mrIid, options) => {
|
|
476
|
+
const client = initClient();
|
|
477
|
+
const api = new GitlabMergeRequestApi(client);
|
|
478
|
+
try {
|
|
479
|
+
const mr = options.changes ? await api.getMergeRequestChanges(parseInt(projectId), parseInt(mrIid)) : await api.getMergeRequest(parseInt(projectId), parseInt(mrIid));
|
|
480
|
+
console.log(chalk3.bold(`[!${mr.iid}] ${mr.title}`));
|
|
481
|
+
console.log(`State: ${mr.state}`);
|
|
482
|
+
console.log(`Source: ${mr.source_branch} \u2192 Target: ${mr.target_branch}`);
|
|
483
|
+
console.log(`Author: ${mr.author?.name || "N/A"}`);
|
|
484
|
+
console.log(`Assignee: ${mr.assignee?.name || "\uBBF8\uBC30\uC815"}`);
|
|
485
|
+
console.log(`Merge Status: ${mr.merge_status}`);
|
|
486
|
+
console.log(`Has Conflicts: ${mr.has_conflicts}`);
|
|
487
|
+
console.log(`Pipeline: ${mr.pipeline?.status || "N/A"}`);
|
|
488
|
+
console.log(`URL: ${mr.web_url}`);
|
|
489
|
+
if (mr.description) {
|
|
490
|
+
console.log(chalk3.dim("\n--- Description ---"));
|
|
491
|
+
console.log(mr.description);
|
|
492
|
+
}
|
|
493
|
+
if (mr.changes && mr.changes.length > 0) {
|
|
494
|
+
console.log(chalk3.dim(`
|
|
495
|
+
--- Changes (${mr.changes.length}\uAC1C \uD30C\uC77C) ---`));
|
|
496
|
+
mr.changes.forEach((c) => {
|
|
497
|
+
const prefix = c.new_file ? "[NEW]" : c.deleted_file ? "[DEL]" : c.renamed_file ? "[REN]" : "[MOD]";
|
|
498
|
+
console.log(` ${prefix} ${c.new_path}`);
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
} catch (e) {
|
|
502
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
mrCmd.command("create <projectId>").requiredOption("--source <branch>", "\uC18C\uC2A4 \uBE0C\uB79C\uCE58").requiredOption("--target <branch>", "\uD0C0\uAC9F \uBE0C\uB79C\uCE58").requiredOption("--title <text>", "MR \uC81C\uBAA9").option("-d, --description <text>", "MR \uC124\uBA85").description("MR \uC0DD\uC131").action(async (projectId, options) => {
|
|
506
|
+
const client = initClient();
|
|
507
|
+
const api = new GitlabMergeRequestApi(client);
|
|
508
|
+
try {
|
|
509
|
+
const mr = await api.createMergeRequest(parseInt(projectId), {
|
|
510
|
+
source_branch: options.source,
|
|
511
|
+
target_branch: options.target,
|
|
512
|
+
title: options.title,
|
|
513
|
+
description: options.description
|
|
514
|
+
});
|
|
515
|
+
console.log(chalk3.green(`MR \uC0DD\uC131 \uC644\uB8CC: !${mr.iid}`));
|
|
516
|
+
console.log(`URL: ${mr.web_url}`);
|
|
517
|
+
} catch (e) {
|
|
518
|
+
console.error(chalk3.red(`\uC0DD\uC131 \uC2E4\uD328: ${e.message}`));
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
mrCmd.command("merge <projectId> <mrIid>").option("--squash", "\uC2A4\uCFFC\uC2DC \uBA38\uC9C0").option("--remove-source-branch", "\uC18C\uC2A4 \uBE0C\uB79C\uCE58 \uC0AD\uC81C").description("MR \uBA38\uC9C0").action(async (projectId, mrIid, options) => {
|
|
522
|
+
const client = initClient();
|
|
523
|
+
const api = new GitlabMergeRequestApi(client);
|
|
524
|
+
try {
|
|
525
|
+
const mr = await api.mergeMergeRequest(parseInt(projectId), parseInt(mrIid), {
|
|
526
|
+
squash: options.squash,
|
|
527
|
+
should_remove_source_branch: options.removeSourceBranch
|
|
528
|
+
});
|
|
529
|
+
console.log(chalk3.green(`MR !${mrIid} \uBA38\uC9C0 \uC644\uB8CC`));
|
|
530
|
+
console.log(`State: ${mr.state}`);
|
|
531
|
+
} catch (e) {
|
|
532
|
+
console.error(chalk3.red(`\uBA38\uC9C0 \uC2E4\uD328: ${e.message}`));
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
mrCmd.command("close <projectId> <mrIid>").description("MR \uB2EB\uAE30").action(async (projectId, mrIid) => {
|
|
536
|
+
const client = initClient();
|
|
537
|
+
const api = new GitlabMergeRequestApi(client);
|
|
538
|
+
try {
|
|
539
|
+
await api.updateMergeRequest(parseInt(projectId), parseInt(mrIid), {
|
|
540
|
+
state_event: "close"
|
|
541
|
+
});
|
|
542
|
+
console.log(chalk3.green(`MR !${mrIid} \uB2EB\uAE30 \uC644\uB8CC`));
|
|
543
|
+
} catch (e) {
|
|
544
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
mrCmd.command("comment <projectId> <mrIid>").requiredOption("-b, --body <text>", "\uCF54\uBA58\uD2B8 \uB0B4\uC6A9").description("MR \uCF54\uBA58\uD2B8 \uCD94\uAC00").action(async (projectId, mrIid, options) => {
|
|
548
|
+
const client = initClient();
|
|
549
|
+
const api = new GitlabMergeRequestApi(client);
|
|
550
|
+
try {
|
|
551
|
+
const note = await api.addMergeRequestNote(
|
|
552
|
+
parseInt(projectId),
|
|
553
|
+
parseInt(mrIid),
|
|
554
|
+
options.body
|
|
555
|
+
);
|
|
556
|
+
console.log(chalk3.green(`\uCF54\uBA58\uD2B8 \uCD94\uAC00 \uC644\uB8CC (ID: ${note.id})`));
|
|
557
|
+
} catch (e) {
|
|
558
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
const pipelineCmd = gitlabCmd.command("pipeline").description("\uD30C\uC774\uD504\uB77C\uC778 \uAD00\uB9AC");
|
|
562
|
+
pipelineCmd.command("list <projectId>").option("-s, --status <status>", "\uC0C1\uD0DC \uD544\uD130").option("-r, --ref <branch>", "\uBE0C\uB79C\uCE58/\uD0DC\uADF8 \uD544\uD130").description("\uD30C\uC774\uD504\uB77C\uC778 \uBAA9\uB85D \uC870\uD68C").action(async (projectId, options) => {
|
|
563
|
+
const client = initClient();
|
|
564
|
+
const api = new GitlabPipelineApi(client);
|
|
565
|
+
try {
|
|
566
|
+
const pipelines = await api.getPipelines(parseInt(projectId), {
|
|
567
|
+
status: options.status,
|
|
568
|
+
ref: options.ref
|
|
569
|
+
});
|
|
570
|
+
const table = new Table3({
|
|
571
|
+
head: ["ID", "Status", "Ref", "SHA", "Created"],
|
|
572
|
+
style: { head: ["cyan"] }
|
|
573
|
+
});
|
|
574
|
+
pipelines.forEach(
|
|
575
|
+
(p) => table.push([
|
|
576
|
+
p.id.toString(),
|
|
577
|
+
p.status,
|
|
578
|
+
p.ref,
|
|
579
|
+
p.sha.substring(0, 8),
|
|
580
|
+
p.created_at?.substring(0, 10) || "N/A"
|
|
581
|
+
])
|
|
582
|
+
);
|
|
583
|
+
console.log(table.toString());
|
|
584
|
+
} catch (e) {
|
|
585
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
pipelineCmd.command("get <projectId> <pipelineId>").option("-j, --jobs", "\uC791\uC5C5 \uBAA9\uB85D \uD3EC\uD568").description("\uD30C\uC774\uD504\uB77C\uC778 \uC0C1\uC138 \uC870\uD68C").action(async (projectId, pipelineId, options) => {
|
|
589
|
+
const client = initClient();
|
|
590
|
+
const api = new GitlabPipelineApi(client);
|
|
591
|
+
try {
|
|
592
|
+
const p = await api.getPipeline(parseInt(projectId), parseInt(pipelineId));
|
|
593
|
+
console.log(chalk3.bold(`Pipeline #${p.id}`));
|
|
594
|
+
console.log(`Status: ${p.status}`);
|
|
595
|
+
console.log(`Ref: ${p.ref}`);
|
|
596
|
+
console.log(`SHA: ${p.sha}`);
|
|
597
|
+
console.log(`Duration: ${p.duration ? p.duration + "s" : "N/A"}`);
|
|
598
|
+
console.log(`URL: ${p.web_url}`);
|
|
599
|
+
if (options.jobs) {
|
|
600
|
+
const jobs = await api.getPipelineJobs(
|
|
601
|
+
parseInt(projectId),
|
|
602
|
+
parseInt(pipelineId)
|
|
603
|
+
);
|
|
604
|
+
console.log(chalk3.dim(`
|
|
605
|
+
--- Jobs (${jobs.length}\uAC1C) ---`));
|
|
606
|
+
const table = new Table3({
|
|
607
|
+
head: ["Stage", "Name", "Status", "Duration"],
|
|
608
|
+
style: { head: ["cyan"] }
|
|
609
|
+
});
|
|
610
|
+
jobs.forEach(
|
|
611
|
+
(j) => table.push([
|
|
612
|
+
j.stage,
|
|
613
|
+
j.name,
|
|
614
|
+
j.status,
|
|
615
|
+
j.duration ? j.duration + "s" : "N/A"
|
|
616
|
+
])
|
|
617
|
+
);
|
|
618
|
+
console.log(table.toString());
|
|
619
|
+
}
|
|
620
|
+
} catch (e) {
|
|
621
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
const branchCmd = gitlabCmd.command("branch").description("\uBE0C\uB79C\uCE58 \uAD00\uB9AC");
|
|
625
|
+
branchCmd.command("list <projectId>").option("-s, --search <query>", "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC").description("\uBE0C\uB79C\uCE58 \uBAA9\uB85D \uC870\uD68C").action(async (projectId, options) => {
|
|
626
|
+
const client = initClient();
|
|
627
|
+
const api = new GitlabBranchApi(client);
|
|
628
|
+
try {
|
|
629
|
+
const branches = await api.getBranches(parseInt(projectId), {
|
|
630
|
+
search: options.search
|
|
631
|
+
});
|
|
632
|
+
const table = new Table3({
|
|
633
|
+
head: ["Name", "Commit", "Message", "Protected", "Default"],
|
|
634
|
+
style: { head: ["cyan"] }
|
|
635
|
+
});
|
|
636
|
+
branches.forEach(
|
|
637
|
+
(b) => table.push([
|
|
638
|
+
b.name,
|
|
639
|
+
b.commit.short_id,
|
|
640
|
+
b.commit.message.split("\n")[0].substring(0, 40),
|
|
641
|
+
b.protected ? "Yes" : "No",
|
|
642
|
+
b.default ? "Yes" : "No"
|
|
643
|
+
])
|
|
644
|
+
);
|
|
645
|
+
console.log(table.toString());
|
|
646
|
+
} catch (e) {
|
|
647
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
branchCmd.command("get <projectId> <branchName>").description("\uBE0C\uB79C\uCE58 \uC0C1\uC138 \uC870\uD68C").action(async (projectId, branchName) => {
|
|
651
|
+
const client = initClient();
|
|
652
|
+
const api = new GitlabBranchApi(client);
|
|
653
|
+
try {
|
|
654
|
+
const b = await api.getBranch(parseInt(projectId), branchName);
|
|
655
|
+
console.log(chalk3.bold(b.name));
|
|
656
|
+
console.log(`Default: ${b.default}`);
|
|
657
|
+
console.log(`Protected: ${b.protected}`);
|
|
658
|
+
console.log(`Merged: ${b.merged}`);
|
|
659
|
+
console.log(`Commit: ${b.commit.id}`);
|
|
660
|
+
console.log(`Message: ${b.commit.message}`);
|
|
661
|
+
console.log(`Author: ${b.commit.author_name}`);
|
|
662
|
+
console.log(`Date: ${b.commit.authored_date}`);
|
|
663
|
+
} catch (e) {
|
|
664
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
branchCmd.command("create <projectId>").requiredOption("-n, --name <branch>", "\uBE0C\uB79C\uCE58 \uC774\uB984").requiredOption("-r, --ref <ref>", "\uAE30\uC900 ref").description("\uBE0C\uB79C\uCE58 \uC0DD\uC131").action(async (projectId, options) => {
|
|
668
|
+
const client = initClient();
|
|
669
|
+
const api = new GitlabBranchApi(client);
|
|
670
|
+
try {
|
|
671
|
+
const b = await api.createBranch(
|
|
672
|
+
parseInt(projectId),
|
|
673
|
+
options.name,
|
|
674
|
+
options.ref
|
|
675
|
+
);
|
|
676
|
+
console.log(chalk3.green(`\uBE0C\uB79C\uCE58 \uC0DD\uC131 \uC644\uB8CC: ${b.name}`));
|
|
677
|
+
} catch (e) {
|
|
678
|
+
console.error(chalk3.red(`\uC0DD\uC131 \uC2E4\uD328: ${e.message}`));
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
branchCmd.command("delete <projectId> <branchName>").description("\uBE0C\uB79C\uCE58 \uC0AD\uC81C").action(async (projectId, branchName) => {
|
|
682
|
+
const client = initClient();
|
|
683
|
+
const api = new GitlabBranchApi(client);
|
|
684
|
+
try {
|
|
685
|
+
await api.deleteBranch(parseInt(projectId), branchName);
|
|
686
|
+
console.log(chalk3.green(`\uBE0C\uB79C\uCE58 \uC0AD\uC81C \uC644\uB8CC: ${branchName}`));
|
|
687
|
+
} catch (e) {
|
|
688
|
+
console.error(chalk3.red(`\uC0AD\uC81C \uC2E4\uD328: ${e.message}`));
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
const fileCmd = gitlabCmd.command("file").description("\uD30C\uC77C \uAD00\uB9AC");
|
|
692
|
+
fileCmd.command("get <projectId> <filePath>").option("-r, --ref <ref>", "\uBE0C\uB79C\uCE58/\uD0DC\uADF8/\uCEE4\uBC0B").description("\uD30C\uC77C \uB0B4\uC6A9 \uC870\uD68C").action(async (projectId, filePath, options) => {
|
|
693
|
+
const client = initClient();
|
|
694
|
+
const api = new GitlabRepositoryApi(client);
|
|
695
|
+
try {
|
|
696
|
+
const file = await api.getFile(parseInt(projectId), filePath, options.ref);
|
|
697
|
+
console.log(chalk3.bold(file.file_path));
|
|
698
|
+
console.log(chalk3.gray(`Size: ${file.size} bytes | Ref: ${file.ref}`));
|
|
699
|
+
console.log(chalk3.dim("---"));
|
|
700
|
+
console.log(file.content);
|
|
701
|
+
} catch (e) {
|
|
702
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
fileCmd.command("tree <projectId>").option("-p, --path <dir>", "\uB514\uB809\uD1A0\uB9AC \uACBD\uB85C").option("-r, --ref <ref>", "\uBE0C\uB79C\uCE58/\uD0DC\uADF8").option("--recursive", "\uC7AC\uADC0 \uC870\uD68C").description("\uB514\uB809\uD1A0\uB9AC \uD2B8\uB9AC \uC870\uD68C").action(async (projectId, options) => {
|
|
706
|
+
const client = initClient();
|
|
707
|
+
const api = new GitlabRepositoryApi(client);
|
|
708
|
+
try {
|
|
709
|
+
const entries = await api.getTree(parseInt(projectId), {
|
|
710
|
+
path: options.path,
|
|
711
|
+
ref: options.ref,
|
|
712
|
+
recursive: options.recursive
|
|
713
|
+
});
|
|
714
|
+
entries.forEach((e) => {
|
|
715
|
+
const icon = e.type === "tree" ? "\u{1F4C1}" : "\u{1F4C4}";
|
|
716
|
+
console.log(`${icon} ${e.path}`);
|
|
717
|
+
});
|
|
718
|
+
} catch (e) {
|
|
719
|
+
console.error(chalk3.red(`Error: ${e.message}`));
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
|
|
134
724
|
// src/cli.ts
|
|
135
725
|
import dotenv from "dotenv";
|
|
136
726
|
dotenv.config();
|
|
137
727
|
var program = new Command();
|
|
138
728
|
program.name("tdecollab").description("TDE Collaboration CLI").version("0.1.0");
|
|
139
729
|
registerConfluenceCommands(program);
|
|
730
|
+
registerJiraCommands(program);
|
|
731
|
+
registerGitlabCommands(program);
|
|
140
732
|
program.command("mcp").description("Run MCP Server").action(async () => {
|
|
141
|
-
const { runServer } = await import("./server-
|
|
733
|
+
const { runServer } = await import("./server-HS774DWY.js");
|
|
142
734
|
await runServer();
|
|
143
735
|
});
|
|
144
736
|
program.parse(process.argv);
|