@bifos/dooray-cli 0.1.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/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/index.js +1606 -0
- package/package.json +50 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1606 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_commander23 = require("commander");
|
|
28
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
29
|
+
|
|
30
|
+
// src/commands/config.ts
|
|
31
|
+
var import_commander = require("commander");
|
|
32
|
+
var import_chalk = __toESM(require("chalk"));
|
|
33
|
+
|
|
34
|
+
// src/config/store.ts
|
|
35
|
+
var import_promises = require("fs/promises");
|
|
36
|
+
var import_node_path = require("path");
|
|
37
|
+
var import_node_os = require("os");
|
|
38
|
+
|
|
39
|
+
// src/utils/errors.ts
|
|
40
|
+
var DoorayCliError = class extends Error {
|
|
41
|
+
constructor(message, exitCode) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.exitCode = exitCode;
|
|
44
|
+
this.name = "DoorayCliError";
|
|
45
|
+
}
|
|
46
|
+
exitCode;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/utils/exit-codes.ts
|
|
50
|
+
var EXIT_API_ERROR = 1;
|
|
51
|
+
var EXIT_AUTH_ERROR = 2;
|
|
52
|
+
var EXIT_PARAM_ERROR = 3;
|
|
53
|
+
var EXIT_CONFIG_ERROR = 4;
|
|
54
|
+
|
|
55
|
+
// src/config/store.ts
|
|
56
|
+
var DOORAY_DIR = (0, import_node_path.join)((0, import_node_os.homedir)(), ".dooray");
|
|
57
|
+
var CONFIG_PATH = (0, import_node_path.join)(DOORAY_DIR, "config.json");
|
|
58
|
+
async function ensureDir() {
|
|
59
|
+
await (0, import_promises.mkdir)(DOORAY_DIR, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
async function getConfig() {
|
|
62
|
+
try {
|
|
63
|
+
const raw = await (0, import_promises.readFile)(CONFIG_PATH, "utf-8");
|
|
64
|
+
return JSON.parse(raw);
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function getConfigOrThrow() {
|
|
70
|
+
const config = await getConfig();
|
|
71
|
+
if (!config || !config.apiKey || !config.baseUrl) {
|
|
72
|
+
throw new DoorayCliError(
|
|
73
|
+
"\uC124\uC815\uC774 \uC644\uB8CC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 \uC124\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694:\n dooray config set api-key <YOUR_API_KEY>\n dooray config set base-url <YOUR_BASE_URL>",
|
|
74
|
+
EXIT_CONFIG_ERROR
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return config;
|
|
78
|
+
}
|
|
79
|
+
async function setConfigValue(key, value) {
|
|
80
|
+
await ensureDir();
|
|
81
|
+
const config = await getConfig() ?? {
|
|
82
|
+
version: 1,
|
|
83
|
+
apiKey: "",
|
|
84
|
+
baseUrl: ""
|
|
85
|
+
};
|
|
86
|
+
switch (key) {
|
|
87
|
+
case "api-key":
|
|
88
|
+
config.apiKey = value;
|
|
89
|
+
break;
|
|
90
|
+
case "base-url":
|
|
91
|
+
config.baseUrl = value;
|
|
92
|
+
break;
|
|
93
|
+
default:
|
|
94
|
+
throw new DoorayCliError(
|
|
95
|
+
`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${key}
|
|
96
|
+
\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uD0A4: api-key, base-url`,
|
|
97
|
+
EXIT_CONFIG_ERROR
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
await (0, import_promises.writeFile)(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/commands/config.ts
|
|
104
|
+
function maskApiKey(key) {
|
|
105
|
+
if (key.length <= 8) return "****";
|
|
106
|
+
return key.slice(0, 4) + "****" + key.slice(-4);
|
|
107
|
+
}
|
|
108
|
+
var configCommand = new import_commander.Command("config").description("CLI \uC124\uC815 \uAD00\uB9AC");
|
|
109
|
+
configCommand.command("set").description("\uC124\uC815 \uAC12 \uC800\uC7A5").argument("<key>", "\uC124\uC815 \uD0A4 (api-key, base-url)").argument("<value>", "\uC124\uC815 \uAC12").action(async (key, value) => {
|
|
110
|
+
try {
|
|
111
|
+
await setConfigValue(key, value);
|
|
112
|
+
console.log(import_chalk.default.green(`\u2713 ${key} \uC124\uC815 \uC644\uB8CC`));
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (err instanceof DoorayCliError) {
|
|
115
|
+
console.error(import_chalk.default.red(err.message));
|
|
116
|
+
process.exit(err.exitCode);
|
|
117
|
+
}
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
configCommand.command("get").description("\uC124\uC815 \uAC12 \uC870\uD68C").argument("[key]", "\uC124\uC815 \uD0A4 (\uC0DD\uB7B5 \uC2DC \uC804\uCCB4 \uCD9C\uB825)").action(async (key) => {
|
|
122
|
+
const config = await getConfig();
|
|
123
|
+
if (!config) {
|
|
124
|
+
console.error(import_chalk.default.red("\uC124\uC815 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. dooray config set \uC73C\uB85C \uC124\uC815\uD558\uC138\uC694."));
|
|
125
|
+
process.exit(EXIT_CONFIG_ERROR);
|
|
126
|
+
}
|
|
127
|
+
const display = {
|
|
128
|
+
"api-key": config.apiKey ? maskApiKey(config.apiKey) : "(\uBBF8\uC124\uC815)",
|
|
129
|
+
"base-url": config.baseUrl || "(\uBBF8\uC124\uC815)"
|
|
130
|
+
};
|
|
131
|
+
if (key) {
|
|
132
|
+
const val = display[key];
|
|
133
|
+
if (val === void 0) {
|
|
134
|
+
console.error(import_chalk.default.red(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${key}
|
|
135
|
+
\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uD0A4: api-key, base-url`));
|
|
136
|
+
process.exit(EXIT_CONFIG_ERROR);
|
|
137
|
+
}
|
|
138
|
+
console.log(`${key}: ${val}`);
|
|
139
|
+
} else {
|
|
140
|
+
for (const [k, v] of Object.entries(display)) {
|
|
141
|
+
console.log(`${k}: ${v}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// src/commands/cache.ts
|
|
147
|
+
var import_commander2 = require("commander");
|
|
148
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
149
|
+
|
|
150
|
+
// src/cache/store.ts
|
|
151
|
+
var import_promises2 = require("fs/promises");
|
|
152
|
+
var import_node_path2 = require("path");
|
|
153
|
+
var import_node_os2 = require("os");
|
|
154
|
+
var CACHE_DIR = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".dooray", "cache");
|
|
155
|
+
var ME_PATH = (0, import_node_path2.join)(CACHE_DIR, "me.json");
|
|
156
|
+
var PROJECTS_PATH = (0, import_node_path2.join)(CACHE_DIR, "projects.json");
|
|
157
|
+
var MEMBERS_DIR = (0, import_node_path2.join)(CACHE_DIR, "members");
|
|
158
|
+
var WORKFLOWS_DIR = (0, import_node_path2.join)(CACHE_DIR, "workflows");
|
|
159
|
+
async function ensureDir2(dir) {
|
|
160
|
+
await (0, import_promises2.mkdir)(dir, { recursive: true });
|
|
161
|
+
}
|
|
162
|
+
async function readJson(path) {
|
|
163
|
+
try {
|
|
164
|
+
const raw = await (0, import_promises2.readFile)(path, "utf-8");
|
|
165
|
+
return JSON.parse(raw);
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async function writeJson(path, data) {
|
|
171
|
+
const dir = path.substring(0, path.lastIndexOf("/"));
|
|
172
|
+
await ensureDir2(dir);
|
|
173
|
+
await (0, import_promises2.writeFile)(path, JSON.stringify(data, null, 2) + "\n");
|
|
174
|
+
}
|
|
175
|
+
function isExpired(updatedAt, ttlMs) {
|
|
176
|
+
if (!updatedAt) return true;
|
|
177
|
+
return Date.now() - new Date(updatedAt).getTime() > ttlMs;
|
|
178
|
+
}
|
|
179
|
+
function now() {
|
|
180
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
181
|
+
}
|
|
182
|
+
async function getMe() {
|
|
183
|
+
return readJson(ME_PATH);
|
|
184
|
+
}
|
|
185
|
+
async function setMe(data) {
|
|
186
|
+
await writeJson(ME_PATH, { updatedAt: now(), data });
|
|
187
|
+
}
|
|
188
|
+
async function getProjects() {
|
|
189
|
+
return readJson(PROJECTS_PATH);
|
|
190
|
+
}
|
|
191
|
+
async function setProjects(items) {
|
|
192
|
+
await writeJson(PROJECTS_PATH, { updatedAt: now(), data: items });
|
|
193
|
+
}
|
|
194
|
+
function membersPath(projectId) {
|
|
195
|
+
return (0, import_node_path2.join)(MEMBERS_DIR, `${projectId}.json`);
|
|
196
|
+
}
|
|
197
|
+
async function getMembers(projectId) {
|
|
198
|
+
return readJson(membersPath(projectId));
|
|
199
|
+
}
|
|
200
|
+
async function setMembers(projectId, items) {
|
|
201
|
+
await writeJson(membersPath(projectId), { updatedAt: now(), data: items });
|
|
202
|
+
}
|
|
203
|
+
function workflowsPath(projectId) {
|
|
204
|
+
return (0, import_node_path2.join)(WORKFLOWS_DIR, `${projectId}.json`);
|
|
205
|
+
}
|
|
206
|
+
async function getWorkflows(projectId) {
|
|
207
|
+
return readJson(workflowsPath(projectId));
|
|
208
|
+
}
|
|
209
|
+
async function setWorkflows(projectId, items) {
|
|
210
|
+
await writeJson(workflowsPath(projectId), { updatedAt: now(), data: items });
|
|
211
|
+
}
|
|
212
|
+
async function clearCache() {
|
|
213
|
+
try {
|
|
214
|
+
await (0, import_promises2.rm)(CACHE_DIR, { recursive: true, force: true });
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function getCacheStats() {
|
|
219
|
+
const projects = await getProjects();
|
|
220
|
+
const projectCount = projects?.data.length ?? 0;
|
|
221
|
+
let memberProjectCount = 0;
|
|
222
|
+
try {
|
|
223
|
+
const files = await (0, import_promises2.readdir)(MEMBERS_DIR);
|
|
224
|
+
memberProjectCount = files.filter((f) => f.endsWith(".json")).length;
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
let workflowProjectCount = 0;
|
|
228
|
+
try {
|
|
229
|
+
const files = await (0, import_promises2.readdir)(WORKFLOWS_DIR);
|
|
230
|
+
workflowProjectCount = files.filter((f) => f.endsWith(".json")).length;
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
const me = await getMe();
|
|
234
|
+
return { projectCount, memberProjectCount, workflowProjectCount, me: me?.data ?? null };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/commands/cache.ts
|
|
238
|
+
var cacheCommand = new import_commander2.Command("cache").description("\uCE90\uC2DC \uAD00\uB9AC");
|
|
239
|
+
cacheCommand.command("clear").description("\uCE90\uC2DC \uC804\uCCB4 \uC0AD\uC81C").action(async () => {
|
|
240
|
+
await clearCache();
|
|
241
|
+
console.log(import_chalk2.default.green("\u2713 \uCE90\uC2DC\uAC00 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
242
|
+
});
|
|
243
|
+
cacheCommand.command("refresh").description("\uCE90\uC2DC \uAC31\uC2E0 (API \uD074\uB77C\uC774\uC5B8\uD2B8 \uC5F0\uB3D9 \uD6C4 \uC9C0\uC6D0 \uC608\uC815)").action(async () => {
|
|
244
|
+
await clearCache();
|
|
245
|
+
console.log(import_chalk2.default.yellow("\uCE90\uC2DC\uB97C \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4. API \uD074\uB77C\uC774\uC5B8\uD2B8 \uC5F0\uB3D9 \uD6C4 \uC790\uB3D9 \uAC31\uC2E0\uC774 \uC9C0\uC6D0\uB429\uB2C8\uB2E4."));
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// src/commands/doctor.ts
|
|
249
|
+
var import_commander3 = require("commander");
|
|
250
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
251
|
+
|
|
252
|
+
// src/api/client.ts
|
|
253
|
+
var import_ky = __toESM(require("ky"));
|
|
254
|
+
function joinIds(ids) {
|
|
255
|
+
return ids && ids.length > 0 ? ids.join(",") : void 0;
|
|
256
|
+
}
|
|
257
|
+
async function toDoorayCliError(error) {
|
|
258
|
+
if (error instanceof import_ky.HTTPError) {
|
|
259
|
+
const status = error.response.status;
|
|
260
|
+
const exitCode = status === 401 || status === 403 ? EXIT_AUTH_ERROR : EXIT_API_ERROR;
|
|
261
|
+
try {
|
|
262
|
+
const body = await error.response.json();
|
|
263
|
+
throw new DoorayCliError(
|
|
264
|
+
`API \uD638\uCD9C \uC2E4\uD328: ${body.header.resultMessage}`,
|
|
265
|
+
exitCode
|
|
266
|
+
);
|
|
267
|
+
} catch (e) {
|
|
268
|
+
if (e instanceof DoorayCliError) throw e;
|
|
269
|
+
throw new DoorayCliError(
|
|
270
|
+
`API \uD638\uCD9C \uC2E4\uD328 (${status}): ${error.message}`,
|
|
271
|
+
exitCode
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
var DoorayApiClient = class {
|
|
278
|
+
api;
|
|
279
|
+
constructor(apiKey, baseUrl) {
|
|
280
|
+
this.api = import_ky.default.create({
|
|
281
|
+
prefixUrl: baseUrl,
|
|
282
|
+
headers: {
|
|
283
|
+
Authorization: `dooray-api ${apiKey}`
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
// ─── Me ─────────────────────────────────────────────
|
|
288
|
+
async getMe() {
|
|
289
|
+
try {
|
|
290
|
+
return await this.api.get("common/v1/members/me").json();
|
|
291
|
+
} catch (e) {
|
|
292
|
+
return toDoorayCliError(e);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// ─── Projects ───────────────────────────────────────
|
|
296
|
+
async getProjects(params) {
|
|
297
|
+
try {
|
|
298
|
+
return await this.api.get("project/v1/projects", {
|
|
299
|
+
searchParams: {
|
|
300
|
+
member: "me",
|
|
301
|
+
...params?.page != null && { page: params.page },
|
|
302
|
+
...params?.size != null && { size: params.size },
|
|
303
|
+
...params?.type && { type: params.type },
|
|
304
|
+
...params?.scope && { scope: params.scope },
|
|
305
|
+
...params?.state && { state: params.state }
|
|
306
|
+
}
|
|
307
|
+
}).json();
|
|
308
|
+
} catch (e) {
|
|
309
|
+
return toDoorayCliError(e);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// ─── Posts ──────────────────────────────────────────
|
|
313
|
+
async getPosts(projectId, params) {
|
|
314
|
+
try {
|
|
315
|
+
return await this.api.get(`project/v1/projects/${projectId}/posts`, {
|
|
316
|
+
searchParams: {
|
|
317
|
+
...params?.page != null && { page: params.page },
|
|
318
|
+
...params?.size != null && { size: params.size },
|
|
319
|
+
...joinIds(params?.fromMemberIds) && { fromMemberIds: joinIds(params?.fromMemberIds) },
|
|
320
|
+
...joinIds(params?.toMemberIds) && { toMemberIds: joinIds(params?.toMemberIds) },
|
|
321
|
+
...joinIds(params?.ccMemberIds) && { ccMemberIds: joinIds(params?.ccMemberIds) },
|
|
322
|
+
...joinIds(params?.tagIds) && { tagIds: joinIds(params?.tagIds) },
|
|
323
|
+
...params?.parentPostId && { parentPostId: params.parentPostId },
|
|
324
|
+
...params?.postNumber && { postNumber: params.postNumber },
|
|
325
|
+
...joinIds(params?.postWorkflowClasses) && { postWorkflowClasses: joinIds(params?.postWorkflowClasses) },
|
|
326
|
+
...joinIds(params?.postWorkflowIds) && { postWorkflowIds: joinIds(params?.postWorkflowIds) },
|
|
327
|
+
...joinIds(params?.milestoneIds) && { milestoneIds: joinIds(params?.milestoneIds) },
|
|
328
|
+
...params?.subjects && { subjects: params.subjects },
|
|
329
|
+
...params?.createdAt && { createdAt: params.createdAt },
|
|
330
|
+
...params?.updatedAt && { updatedAt: params.updatedAt },
|
|
331
|
+
...params?.dueAt && { dueAt: params.dueAt },
|
|
332
|
+
...params?.order && { order: params.order }
|
|
333
|
+
}
|
|
334
|
+
}).json();
|
|
335
|
+
} catch (e) {
|
|
336
|
+
return toDoorayCliError(e);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
async getPost(projectId, postId) {
|
|
340
|
+
try {
|
|
341
|
+
return await this.api.get(`project/v1/projects/${projectId}/posts/${postId}`).json();
|
|
342
|
+
} catch (e) {
|
|
343
|
+
return toDoorayCliError(e);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
async createPost(projectId, body) {
|
|
347
|
+
try {
|
|
348
|
+
return await this.api.post(`project/v1/projects/${projectId}/posts`, { json: body }).json();
|
|
349
|
+
} catch (e) {
|
|
350
|
+
return toDoorayCliError(e);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
async updatePost(projectId, postId, body) {
|
|
354
|
+
try {
|
|
355
|
+
return await this.api.put(`project/v1/projects/${projectId}/posts/${postId}`, { json: body }).json();
|
|
356
|
+
} catch (e) {
|
|
357
|
+
return toDoorayCliError(e);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async setPostDone(projectId, postId) {
|
|
361
|
+
try {
|
|
362
|
+
return await this.api.post(`project/v1/projects/${projectId}/posts/${postId}/set-done`).json();
|
|
363
|
+
} catch (e) {
|
|
364
|
+
return toDoorayCliError(e);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async setPostWorkflow(projectId, postId, workflowId) {
|
|
368
|
+
try {
|
|
369
|
+
return await this.api.post(`project/v1/projects/${projectId}/posts/${postId}/set-workflow`, {
|
|
370
|
+
json: { workflowId }
|
|
371
|
+
}).json();
|
|
372
|
+
} catch (e) {
|
|
373
|
+
return toDoorayCliError(e);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async setPostParent(projectId, postId, parentPostId) {
|
|
377
|
+
try {
|
|
378
|
+
return await this.api.post(`project/v1/projects/${projectId}/posts/${postId}/set-parent-post`, {
|
|
379
|
+
json: { parentPostId }
|
|
380
|
+
}).json();
|
|
381
|
+
} catch (e) {
|
|
382
|
+
return toDoorayCliError(e);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// ─── Post Comments ──────────────────────────────────
|
|
386
|
+
async getPostComments(projectId, postId, params) {
|
|
387
|
+
try {
|
|
388
|
+
return await this.api.get(`project/v1/projects/${projectId}/posts/${postId}/logs`, {
|
|
389
|
+
searchParams: {
|
|
390
|
+
...params?.page != null && { page: params.page },
|
|
391
|
+
...params?.size != null && { size: params.size },
|
|
392
|
+
...params?.order && { order: params.order }
|
|
393
|
+
}
|
|
394
|
+
}).json();
|
|
395
|
+
} catch (e) {
|
|
396
|
+
return toDoorayCliError(e);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async createPostComment(projectId, postId, body) {
|
|
400
|
+
try {
|
|
401
|
+
return await this.api.post(`project/v1/projects/${projectId}/posts/${postId}/logs`, { json: body }).json();
|
|
402
|
+
} catch (e) {
|
|
403
|
+
return toDoorayCliError(e);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async updatePostComment(projectId, postId, logId, body) {
|
|
407
|
+
try {
|
|
408
|
+
return await this.api.put(`project/v1/projects/${projectId}/posts/${postId}/logs/${logId}`, { json: body }).json();
|
|
409
|
+
} catch (e) {
|
|
410
|
+
return toDoorayCliError(e);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
async deletePostComment(projectId, postId, logId) {
|
|
414
|
+
try {
|
|
415
|
+
return await this.api.delete(`project/v1/projects/${projectId}/posts/${postId}/logs/${logId}`).json();
|
|
416
|
+
} catch (e) {
|
|
417
|
+
return toDoorayCliError(e);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
// ─── Members ────────────────────────────────────────
|
|
421
|
+
async getProjectMembers(projectId, params) {
|
|
422
|
+
try {
|
|
423
|
+
return await this.api.get(`project/v1/projects/${projectId}/members`, {
|
|
424
|
+
searchParams: {
|
|
425
|
+
member: "me",
|
|
426
|
+
...params?.page != null && { page: params.page },
|
|
427
|
+
...params?.size != null && { size: params.size }
|
|
428
|
+
}
|
|
429
|
+
}).json();
|
|
430
|
+
} catch (e) {
|
|
431
|
+
return toDoorayCliError(e);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
async getMemberDetail(memberId) {
|
|
435
|
+
try {
|
|
436
|
+
return await this.api.get(`common/v1/members/${memberId}`).json();
|
|
437
|
+
} catch (e) {
|
|
438
|
+
return toDoorayCliError(e);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// ─── Workflows ──────────────────────────────────────
|
|
442
|
+
async getProjectWorkflows(projectId) {
|
|
443
|
+
try {
|
|
444
|
+
return await this.api.get(`project/v1/projects/${projectId}/workflows`).json();
|
|
445
|
+
} catch (e) {
|
|
446
|
+
return toDoorayCliError(e);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
// ─── Wiki ───────────────────────────────────────────
|
|
450
|
+
async getWikis(params) {
|
|
451
|
+
try {
|
|
452
|
+
return await this.api.get("wiki/v1/wikis", {
|
|
453
|
+
searchParams: {
|
|
454
|
+
...params?.page != null && { page: params.page },
|
|
455
|
+
...params?.size != null && { size: params.size }
|
|
456
|
+
}
|
|
457
|
+
}).json();
|
|
458
|
+
} catch (e) {
|
|
459
|
+
return toDoorayCliError(e);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
async getWikiPages(wikiId, parentPageId) {
|
|
463
|
+
try {
|
|
464
|
+
return await this.api.get(`wiki/v1/wikis/${wikiId}/pages`, {
|
|
465
|
+
searchParams: {
|
|
466
|
+
...parentPageId && { parentPageId }
|
|
467
|
+
}
|
|
468
|
+
}).json();
|
|
469
|
+
} catch (e) {
|
|
470
|
+
return toDoorayCliError(e);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
async getWikiPage(wikiId, pageId) {
|
|
474
|
+
try {
|
|
475
|
+
return await this.api.get(`wiki/v1/wikis/${wikiId}/pages/${pageId}`).json();
|
|
476
|
+
} catch (e) {
|
|
477
|
+
return toDoorayCliError(e);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async createWikiPage(wikiId, body) {
|
|
481
|
+
try {
|
|
482
|
+
return await this.api.post(`wiki/v1/wikis/${wikiId}/pages`, { json: body }).json();
|
|
483
|
+
} catch (e) {
|
|
484
|
+
return toDoorayCliError(e);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
async updateWikiPage(wikiId, pageId, body) {
|
|
488
|
+
try {
|
|
489
|
+
return await this.api.put(`wiki/v1/wikis/${wikiId}/pages/${pageId}`, { json: body }).json();
|
|
490
|
+
} catch (e) {
|
|
491
|
+
return toDoorayCliError(e);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
// src/cache/types.ts
|
|
497
|
+
var PROJECTS_TTL_MS = 36e5;
|
|
498
|
+
var MEMBERS_TTL_MS = 36e5;
|
|
499
|
+
var WORKFLOWS_TTL_MS = 864e5;
|
|
500
|
+
var ME_TTL_MS = 864e5;
|
|
501
|
+
|
|
502
|
+
// src/resolvers/me.ts
|
|
503
|
+
async function ensureMe(client) {
|
|
504
|
+
const entry = await getMe();
|
|
505
|
+
if (entry && !isExpired(entry.updatedAt, ME_TTL_MS)) {
|
|
506
|
+
return entry.data;
|
|
507
|
+
}
|
|
508
|
+
const res = await client.getMe();
|
|
509
|
+
const me = { id: res.result.id, name: res.result.name };
|
|
510
|
+
await setMe(me);
|
|
511
|
+
return me;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/commands/doctor.ts
|
|
515
|
+
var doctorCommand = new import_commander3.Command("doctor").description("\uC124\uC815 \uBC0F \uD658\uACBD \uC9C4\uB2E8").action(async () => {
|
|
516
|
+
console.log(import_chalk3.default.bold("\n\u{1F50D} Dooray CLI \uC9C4\uB2E8\n"));
|
|
517
|
+
const config = await getConfig();
|
|
518
|
+
const apiKeyOk = !!config?.apiKey;
|
|
519
|
+
const baseUrlOk = !!config?.baseUrl;
|
|
520
|
+
console.log(` API Key: ${apiKeyOk ? import_chalk3.default.green("\u2705 \uC124\uC815\uB428") : import_chalk3.default.red("\u274C \uBBF8\uC124\uC815")}`);
|
|
521
|
+
console.log(` Base URL: ${baseUrlOk ? import_chalk3.default.green(`\u2705 ${config.baseUrl}`) : import_chalk3.default.red("\u274C \uBBF8\uC124\uC815")}`);
|
|
522
|
+
if (apiKeyOk && baseUrlOk) {
|
|
523
|
+
console.log(import_chalk3.default.bold("\n\u{1F310} API \uC5F0\uACB0 \uD14C\uC2A4\uD2B8\n"));
|
|
524
|
+
try {
|
|
525
|
+
const validConfig = await getConfigOrThrow();
|
|
526
|
+
const client = new DoorayApiClient(validConfig.apiKey, validConfig.baseUrl);
|
|
527
|
+
await client.getProjects({ page: 0, size: 1 });
|
|
528
|
+
const me = await ensureMe(client);
|
|
529
|
+
console.log(` \uC5F0\uACB0: ${import_chalk3.default.green("\u2705 \uC131\uACF5")} (${me.name})`);
|
|
530
|
+
} catch {
|
|
531
|
+
console.log(` \uC5F0\uACB0: ${import_chalk3.default.red("\u274C \uC2E4\uD328 \u2014 API \uD0A4 \uB610\uB294 URL\uC744 \uD655\uC778\uD558\uC138\uC694")}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const stats = await getCacheStats();
|
|
535
|
+
console.log(import_chalk3.default.bold("\n\u{1F4E6} \uCE90\uC2DC \uC0C1\uD0DC\n"));
|
|
536
|
+
console.log(` \uB0B4 \uC815\uBCF4: ${stats.me ? import_chalk3.default.green(`${stats.me.name} (${stats.me.id})`) : import_chalk3.default.gray("\uC5C6\uC74C")}`);
|
|
537
|
+
console.log(` \uD504\uB85C\uC81D\uD2B8: ${stats.projectCount}\uAC1C`);
|
|
538
|
+
console.log(` \uBA64\uBC84: ${stats.memberProjectCount}\uAC1C \uD504\uB85C\uC81D\uD2B8`);
|
|
539
|
+
console.log(` \uC6CC\uD06C\uD50C\uB85C\uC6B0: ${stats.workflowProjectCount}\uAC1C \uD504\uB85C\uC81D\uD2B8`);
|
|
540
|
+
console.log();
|
|
541
|
+
if (apiKeyOk && baseUrlOk) {
|
|
542
|
+
console.log(import_chalk3.default.green("\u2713 \uAE30\uBCF8 \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
543
|
+
} else {
|
|
544
|
+
console.log(import_chalk3.default.yellow("\u26A0 \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4:"));
|
|
545
|
+
if (!apiKeyOk) console.log(import_chalk3.default.yellow(" dooray config set api-key <YOUR_API_KEY>"));
|
|
546
|
+
if (!baseUrlOk) console.log(import_chalk3.default.yellow(" dooray config set base-url <YOUR_BASE_URL>"));
|
|
547
|
+
}
|
|
548
|
+
console.log();
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// src/commands/project/list.ts
|
|
552
|
+
var import_commander4 = require("commander");
|
|
553
|
+
|
|
554
|
+
// src/resolvers/project.ts
|
|
555
|
+
async function fetchAllProjects(client) {
|
|
556
|
+
const all = [];
|
|
557
|
+
let page = 0;
|
|
558
|
+
const size = 100;
|
|
559
|
+
while (true) {
|
|
560
|
+
const res = await client.getProjects({ page, size });
|
|
561
|
+
for (const p of res.result) {
|
|
562
|
+
all.push({
|
|
563
|
+
id: p.id,
|
|
564
|
+
code: p.code,
|
|
565
|
+
wikiId: p.wiki?.id ?? void 0
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
if (all.length >= res.totalCount) break;
|
|
569
|
+
page++;
|
|
570
|
+
}
|
|
571
|
+
return all;
|
|
572
|
+
}
|
|
573
|
+
async function ensureProjects(client) {
|
|
574
|
+
const entry = await getProjects();
|
|
575
|
+
if (entry && !isExpired(entry.updatedAt, PROJECTS_TTL_MS)) {
|
|
576
|
+
return entry.data;
|
|
577
|
+
}
|
|
578
|
+
const items = await fetchAllProjects(client);
|
|
579
|
+
await setProjects(items);
|
|
580
|
+
return items;
|
|
581
|
+
}
|
|
582
|
+
async function resolveProject(client, input) {
|
|
583
|
+
const projects = await ensureProjects(client);
|
|
584
|
+
const match = projects.find((p) => p.code === input || p.id === input);
|
|
585
|
+
if (match) return match.id;
|
|
586
|
+
throw new DoorayCliError(
|
|
587
|
+
`\uD504\uB85C\uC81D\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}`,
|
|
588
|
+
EXIT_PARAM_ERROR
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// src/formatters/table.ts
|
|
593
|
+
var import_cli_table3 = __toESM(require("cli-table3"));
|
|
594
|
+
function printTable(headers, rows) {
|
|
595
|
+
const table = new import_cli_table3.default({ head: headers });
|
|
596
|
+
for (const row of rows) {
|
|
597
|
+
table.push(row);
|
|
598
|
+
}
|
|
599
|
+
process.stdout.write(table.toString() + "\n");
|
|
600
|
+
}
|
|
601
|
+
function printJson(data) {
|
|
602
|
+
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
603
|
+
}
|
|
604
|
+
function printQuiet(ids) {
|
|
605
|
+
process.stdout.write(ids.join("\n") + "\n");
|
|
606
|
+
}
|
|
607
|
+
function output(opts, data) {
|
|
608
|
+
if (opts.json) {
|
|
609
|
+
printJson(data.raw);
|
|
610
|
+
} else if (opts.quiet) {
|
|
611
|
+
printQuiet(data.ids);
|
|
612
|
+
} else {
|
|
613
|
+
printTable(data.headers, data.rows);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/utils/spinner.ts
|
|
618
|
+
var import_ora = __toESM(require("ora"));
|
|
619
|
+
var current = null;
|
|
620
|
+
function startSpinner(text) {
|
|
621
|
+
current = (0, import_ora.default)({ text, stream: process.stderr }).start();
|
|
622
|
+
return current;
|
|
623
|
+
}
|
|
624
|
+
function stopSpinner(success, text) {
|
|
625
|
+
if (!current) return;
|
|
626
|
+
if (success === false) {
|
|
627
|
+
current.fail(text);
|
|
628
|
+
} else {
|
|
629
|
+
current.succeed(text);
|
|
630
|
+
}
|
|
631
|
+
current = null;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/commands/project/list.ts
|
|
635
|
+
var projectListCommand = new import_commander4.Command("list").description("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C").option("-s, --search <keyword>", "code \uD544\uD130\uB9C1").action(async (opts) => {
|
|
636
|
+
const globalOpts = projectListCommand.optsWithGlobals();
|
|
637
|
+
const config = await getConfigOrThrow();
|
|
638
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
639
|
+
startSpinner("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
640
|
+
const projects = await ensureProjects(client);
|
|
641
|
+
stopSpinner(true, "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
642
|
+
let filtered = projects;
|
|
643
|
+
if (opts.search) {
|
|
644
|
+
const keyword = opts.search.toLowerCase();
|
|
645
|
+
filtered = projects.filter((p) => p.code.toLowerCase().includes(keyword));
|
|
646
|
+
}
|
|
647
|
+
output(globalOpts, {
|
|
648
|
+
headers: ["ID", "Code"],
|
|
649
|
+
rows: filtered.map((p) => [p.id, p.code]),
|
|
650
|
+
raw: filtered,
|
|
651
|
+
ids: filtered.map((p) => p.id)
|
|
652
|
+
});
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// src/commands/project/members.ts
|
|
656
|
+
var import_commander5 = require("commander");
|
|
657
|
+
|
|
658
|
+
// src/resolvers/member.ts
|
|
659
|
+
async function fetchAllMembers(client, projectId) {
|
|
660
|
+
const memberIds = [];
|
|
661
|
+
let page = 0;
|
|
662
|
+
const size = 100;
|
|
663
|
+
while (true) {
|
|
664
|
+
const res = await client.getProjectMembers(projectId, { page, size });
|
|
665
|
+
for (const m of res.result) {
|
|
666
|
+
memberIds.push(m.organizationMemberId);
|
|
667
|
+
}
|
|
668
|
+
const total = res.totalCount ?? memberIds.length;
|
|
669
|
+
if (memberIds.length >= total) break;
|
|
670
|
+
page++;
|
|
671
|
+
}
|
|
672
|
+
const all = await Promise.all(
|
|
673
|
+
memberIds.map(async (id) => {
|
|
674
|
+
try {
|
|
675
|
+
const detail = await client.getMemberDetail(id);
|
|
676
|
+
return {
|
|
677
|
+
organizationMemberId: id,
|
|
678
|
+
name: detail.result.name
|
|
679
|
+
};
|
|
680
|
+
} catch {
|
|
681
|
+
return {
|
|
682
|
+
organizationMemberId: id,
|
|
683
|
+
name: ""
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
})
|
|
687
|
+
);
|
|
688
|
+
return all;
|
|
689
|
+
}
|
|
690
|
+
async function ensureMembers(client, projectId) {
|
|
691
|
+
const entry = await getMembers(projectId);
|
|
692
|
+
if (entry && !isExpired(entry.updatedAt, MEMBERS_TTL_MS)) {
|
|
693
|
+
return entry.data;
|
|
694
|
+
}
|
|
695
|
+
const items = await fetchAllMembers(client, projectId);
|
|
696
|
+
await setMembers(projectId, items);
|
|
697
|
+
return items;
|
|
698
|
+
}
|
|
699
|
+
async function resolveMember(client, projectId, input) {
|
|
700
|
+
const members = await ensureMembers(client, projectId);
|
|
701
|
+
const byName = members.filter((m) => m.name.includes(input));
|
|
702
|
+
if (byName.length === 1) return byName[0].organizationMemberId;
|
|
703
|
+
if (byName.length > 1) {
|
|
704
|
+
const candidates = byName.map((m) => ` - ${m.name} (${m.organizationMemberId})`).join("\n");
|
|
705
|
+
throw new DoorayCliError(
|
|
706
|
+
`\uBCF5\uC218\uC758 \uBA64\uBC84\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4: "${input}"
|
|
707
|
+
${candidates}`,
|
|
708
|
+
EXIT_PARAM_ERROR
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
throw new DoorayCliError(
|
|
712
|
+
`\uBA64\uBC84\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}`,
|
|
713
|
+
EXIT_PARAM_ERROR
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// src/commands/project/members.ts
|
|
718
|
+
var projectMembersCommand = new import_commander5.Command("members").description("\uD504\uB85C\uC81D\uD2B8 \uBA64\uBC84 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").action(async (project) => {
|
|
719
|
+
const globalOpts = projectMembersCommand.optsWithGlobals();
|
|
720
|
+
const config = await getConfigOrThrow();
|
|
721
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
722
|
+
startSpinner("\uBA64\uBC84 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
723
|
+
const projectId = await resolveProject(client, project);
|
|
724
|
+
const members = await ensureMembers(client, projectId);
|
|
725
|
+
stopSpinner(true, "\uBA64\uBC84 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
726
|
+
output(globalOpts, {
|
|
727
|
+
headers: ["ID", "Name"],
|
|
728
|
+
rows: members.map((m) => [
|
|
729
|
+
m.organizationMemberId,
|
|
730
|
+
m.name
|
|
731
|
+
]),
|
|
732
|
+
raw: members,
|
|
733
|
+
ids: members.map((m) => m.organizationMemberId)
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
// src/commands/project/workflows.ts
|
|
738
|
+
var import_commander6 = require("commander");
|
|
739
|
+
|
|
740
|
+
// src/resolvers/workflow.ts
|
|
741
|
+
async function ensureWorkflows(client, projectId) {
|
|
742
|
+
const entry = await getWorkflows(projectId);
|
|
743
|
+
if (entry && !isExpired(entry.updatedAt, WORKFLOWS_TTL_MS)) {
|
|
744
|
+
return entry.data;
|
|
745
|
+
}
|
|
746
|
+
const res = await client.getProjectWorkflows(projectId);
|
|
747
|
+
const items = res.result.map((w) => ({
|
|
748
|
+
id: w.id,
|
|
749
|
+
name: w.name,
|
|
750
|
+
class: w.class,
|
|
751
|
+
order: w.order
|
|
752
|
+
}));
|
|
753
|
+
await setWorkflows(projectId, items);
|
|
754
|
+
return items;
|
|
755
|
+
}
|
|
756
|
+
async function resolveWorkflow(client, projectId, input) {
|
|
757
|
+
const workflows = await ensureWorkflows(client, projectId);
|
|
758
|
+
const match = workflows.find((w) => w.name === input || w.class === input);
|
|
759
|
+
if (match) return match.id;
|
|
760
|
+
throw new DoorayCliError(
|
|
761
|
+
`\uC6CC\uD06C\uD50C\uB85C\uC6B0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}`,
|
|
762
|
+
EXIT_PARAM_ERROR
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// src/commands/project/workflows.ts
|
|
767
|
+
var projectWorkflowsCommand = new import_commander6.Command("workflows").description("\uD504\uB85C\uC81D\uD2B8 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").action(async (project) => {
|
|
768
|
+
const globalOpts = projectWorkflowsCommand.optsWithGlobals();
|
|
769
|
+
const config = await getConfigOrThrow();
|
|
770
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
771
|
+
startSpinner("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
772
|
+
const projectId = await resolveProject(client, project);
|
|
773
|
+
const workflows = await ensureWorkflows(client, projectId);
|
|
774
|
+
stopSpinner(true, "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
775
|
+
output(globalOpts, {
|
|
776
|
+
headers: ["ID", "Name", "Class", "Order"],
|
|
777
|
+
rows: workflows.map((w) => [
|
|
778
|
+
w.id,
|
|
779
|
+
w.name,
|
|
780
|
+
w.class,
|
|
781
|
+
String(w.order ?? "")
|
|
782
|
+
]),
|
|
783
|
+
raw: workflows,
|
|
784
|
+
ids: workflows.map((w) => w.id)
|
|
785
|
+
});
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
// src/commands/post/list.ts
|
|
789
|
+
var import_commander7 = require("commander");
|
|
790
|
+
|
|
791
|
+
// src/formatters/post.ts
|
|
792
|
+
function formatPostList(posts, opts) {
|
|
793
|
+
output(opts, {
|
|
794
|
+
headers: ["Number", "Subject", "Workflow", "Priority", "Assignee"],
|
|
795
|
+
rows: posts.map((p) => [
|
|
796
|
+
String(p.number),
|
|
797
|
+
p.subject,
|
|
798
|
+
p.workflow.name,
|
|
799
|
+
p.priority,
|
|
800
|
+
p.users.to.map((u) => u.member?.name ?? u.emailUser?.name ?? "").filter(Boolean).join(", ")
|
|
801
|
+
]),
|
|
802
|
+
raw: posts,
|
|
803
|
+
ids: posts.map((p) => String(p.number))
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
function formatPostDetail(post, opts) {
|
|
807
|
+
if (opts.json) {
|
|
808
|
+
printJson(post);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
const lines = [
|
|
812
|
+
`#${post.number} ${post.subject}`,
|
|
813
|
+
`\uD504\uB85C\uC81D\uD2B8: ${post.project.code}`,
|
|
814
|
+
`\uC0C1\uD0DC: ${post.workflow.name} (${post.workflowClass})`,
|
|
815
|
+
`\uC6B0\uC120\uC21C\uC704: ${post.priority}`,
|
|
816
|
+
`\uC791\uC131\uC790: ${post.users.from.member?.name ?? ""}`,
|
|
817
|
+
`\uB2F4\uB2F9\uC790: ${post.users.to.map((u) => u.member?.name ?? "").filter(Boolean).join(", ")}`,
|
|
818
|
+
`\uC0DD\uC131: ${post.createdAt}`,
|
|
819
|
+
`\uC218\uC815: ${post.updatedAt}`,
|
|
820
|
+
"",
|
|
821
|
+
post.body.content
|
|
822
|
+
];
|
|
823
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
824
|
+
}
|
|
825
|
+
function formatCommentList(comments, opts) {
|
|
826
|
+
output(opts, {
|
|
827
|
+
headers: ["ID", "Creator", "Body", "Created"],
|
|
828
|
+
rows: comments.map((c) => [
|
|
829
|
+
c.id,
|
|
830
|
+
c.creator.member?.name ?? "",
|
|
831
|
+
c.body.content.length > 60 ? c.body.content.slice(0, 57) + "..." : c.body.content,
|
|
832
|
+
c.createdAt
|
|
833
|
+
]),
|
|
834
|
+
raw: comments,
|
|
835
|
+
ids: comments.map((c) => c.id)
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// src/commands/post/list.ts
|
|
840
|
+
var postListCommand = new import_commander7.Command("list").description("\uC5C5\uBB34 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--subject <keyword>", "\uC81C\uBAA9 \uD0A4\uC6CC\uB4DC \uD544\uD130\uB9C1").option("--all", "\uC804\uCCB4 \uD398\uC774\uC9C0\uB124\uC774\uC158 (\uBAA8\uB4E0 \uACB0\uACFC \uC870\uD68C)").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (project, opts) => {
|
|
841
|
+
const globalOpts = postListCommand.optsWithGlobals();
|
|
842
|
+
const config = await getConfigOrThrow();
|
|
843
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
844
|
+
startSpinner("\uC5C5\uBB34 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
845
|
+
const projectId = await resolveProject(client, project);
|
|
846
|
+
const params = {
|
|
847
|
+
order: "-createdAt"
|
|
848
|
+
};
|
|
849
|
+
if (opts.subject) params.subjects = opts.subject;
|
|
850
|
+
let posts;
|
|
851
|
+
if (opts.all) {
|
|
852
|
+
posts = [];
|
|
853
|
+
let page = 0;
|
|
854
|
+
const size = 100;
|
|
855
|
+
while (true) {
|
|
856
|
+
const res = await client.getPosts(projectId, { ...params, page, size });
|
|
857
|
+
posts.push(...res.result);
|
|
858
|
+
if (posts.length >= res.totalCount) break;
|
|
859
|
+
page++;
|
|
860
|
+
}
|
|
861
|
+
} else {
|
|
862
|
+
const res = await client.getPosts(projectId, {
|
|
863
|
+
...params,
|
|
864
|
+
page: Number(opts.page),
|
|
865
|
+
size: Number(opts.size)
|
|
866
|
+
});
|
|
867
|
+
posts = res.result;
|
|
868
|
+
}
|
|
869
|
+
stopSpinner(true, "\uC5C5\uBB34 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
870
|
+
formatPostList(posts, globalOpts);
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
// src/commands/post/search.ts
|
|
874
|
+
var import_commander8 = require("commander");
|
|
875
|
+
var postSearchCommand = new import_commander8.Command("search").description("\uC5C5\uBB34 \uAC80\uC0C9 (\uC81C\uBAA9 \uD0A4\uC6CC\uB4DC)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<keyword>", "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC").action(async (project, keyword) => {
|
|
876
|
+
const globalOpts = postSearchCommand.optsWithGlobals();
|
|
877
|
+
const config = await getConfigOrThrow();
|
|
878
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
879
|
+
startSpinner("\uC5C5\uBB34 \uAC80\uC0C9 \uC911...");
|
|
880
|
+
const projectId = await resolveProject(client, project);
|
|
881
|
+
const res = await client.getPosts(projectId, { subjects: keyword, order: "-createdAt" });
|
|
882
|
+
stopSpinner(true, "\uC5C5\uBB34 \uAC80\uC0C9 \uC644\uB8CC");
|
|
883
|
+
formatPostList(res.result, globalOpts);
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
// src/commands/post/get.ts
|
|
887
|
+
var import_commander9 = require("commander");
|
|
888
|
+
|
|
889
|
+
// src/resolvers/post.ts
|
|
890
|
+
async function resolvePost(client, projectId, postNumber) {
|
|
891
|
+
const res = await client.getPosts(projectId, {
|
|
892
|
+
postNumber: String(postNumber)
|
|
893
|
+
});
|
|
894
|
+
if (res.result.length === 0) {
|
|
895
|
+
throw new DoorayCliError(
|
|
896
|
+
`\uC5C5\uBB34\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: #${postNumber}`,
|
|
897
|
+
EXIT_PARAM_ERROR
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
return res.result[0].id;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// src/commands/post/get.ts
|
|
904
|
+
var postGetCommand = new import_commander9.Command("get").description("\uC5C5\uBB34 \uC0C1\uC138 \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").action(async (project, postNumberStr) => {
|
|
905
|
+
const globalOpts = postGetCommand.optsWithGlobals();
|
|
906
|
+
const config = await getConfigOrThrow();
|
|
907
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
908
|
+
startSpinner("\uC5C5\uBB34 \uC870\uD68C \uC911...");
|
|
909
|
+
const projectId = await resolveProject(client, project);
|
|
910
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
911
|
+
const res = await client.getPost(projectId, postId);
|
|
912
|
+
stopSpinner(true, "\uC5C5\uBB34 \uC870\uD68C \uC644\uB8CC");
|
|
913
|
+
formatPostDetail(res.result, globalOpts);
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
// src/commands/post/edit.ts
|
|
917
|
+
var import_commander10 = require("commander");
|
|
918
|
+
var import_promises4 = __toESM(require("fs/promises"));
|
|
919
|
+
|
|
920
|
+
// src/editor/index.ts
|
|
921
|
+
var import_node_child_process = require("child_process");
|
|
922
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
923
|
+
var import_tmp = __toESM(require("tmp"));
|
|
924
|
+
var import_js_yaml = __toESM(require("js-yaml"));
|
|
925
|
+
function openInEditor(content) {
|
|
926
|
+
const editor = process.env.EDITOR;
|
|
927
|
+
if (!editor) {
|
|
928
|
+
throw new DoorayCliError(
|
|
929
|
+
"$EDITOR \uD658\uACBD\uBCC0\uC218\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. export EDITOR=vim \uB4F1\uC73C\uB85C \uC124\uC815\uD574\uC8FC\uC138\uC694.",
|
|
930
|
+
EXIT_PARAM_ERROR
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
const tmpFile = import_tmp.default.fileSync({ prefix: "dooray-", postfix: ".md" });
|
|
934
|
+
return new Promise(async (resolve, reject) => {
|
|
935
|
+
try {
|
|
936
|
+
await import_promises3.default.writeFile(tmpFile.name, content, "utf-8");
|
|
937
|
+
const child = (0, import_node_child_process.spawn)(editor, [tmpFile.name], {
|
|
938
|
+
stdio: "inherit"
|
|
939
|
+
});
|
|
940
|
+
child.on("error", (err) => {
|
|
941
|
+
tmpFile.removeCallback();
|
|
942
|
+
reject(err);
|
|
943
|
+
});
|
|
944
|
+
child.on("exit", async (code) => {
|
|
945
|
+
try {
|
|
946
|
+
if (code !== 0) {
|
|
947
|
+
throw new DoorayCliError(
|
|
948
|
+
`\uC5D0\uB514\uD130\uAC00 \uBE44\uC815\uC0C1 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (exit code: ${code})`,
|
|
949
|
+
EXIT_PARAM_ERROR
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
const result = await import_promises3.default.readFile(tmpFile.name, "utf-8");
|
|
953
|
+
resolve(result);
|
|
954
|
+
} catch (e) {
|
|
955
|
+
reject(e);
|
|
956
|
+
} finally {
|
|
957
|
+
tmpFile.removeCallback();
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
} catch (e) {
|
|
961
|
+
tmpFile.removeCallback();
|
|
962
|
+
reject(e);
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
function memberIdToEmail(memberId, members) {
|
|
967
|
+
const member = members.find(
|
|
968
|
+
(m) => m.organizationMemberId === memberId
|
|
969
|
+
);
|
|
970
|
+
return member?.emailAddress ?? memberId;
|
|
971
|
+
}
|
|
972
|
+
function serializePostFrontmatter(post, members) {
|
|
973
|
+
const frontmatter = {
|
|
974
|
+
subject: post.subject,
|
|
975
|
+
priority: post.priority,
|
|
976
|
+
due_date: post.dueDate ?? null,
|
|
977
|
+
to: post.users.to.map((u) => {
|
|
978
|
+
if (u.member) return memberIdToEmail(u.member.organizationMemberId, members);
|
|
979
|
+
if (u.emailUser) return u.emailUser.emailAddress;
|
|
980
|
+
return "";
|
|
981
|
+
}).filter(Boolean),
|
|
982
|
+
cc: post.users.cc.map((u) => {
|
|
983
|
+
if (u.member) return memberIdToEmail(u.member.organizationMemberId, members);
|
|
984
|
+
if (u.emailUser) return u.emailUser.emailAddress;
|
|
985
|
+
return "";
|
|
986
|
+
}).filter(Boolean)
|
|
987
|
+
};
|
|
988
|
+
const yamlStr = import_js_yaml.default.dump(frontmatter, {
|
|
989
|
+
quotingType: '"',
|
|
990
|
+
forceQuotes: false,
|
|
991
|
+
lineWidth: -1
|
|
992
|
+
});
|
|
993
|
+
return `---
|
|
994
|
+
${yamlStr}---
|
|
995
|
+
${post.body.content}`;
|
|
996
|
+
}
|
|
997
|
+
function parsePostFrontmatter(content) {
|
|
998
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
999
|
+
if (!match) {
|
|
1000
|
+
throw new DoorayCliError(
|
|
1001
|
+
"frontmatter \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --- \uAD6C\uBD84\uC790\uB97C \uD655\uC778\uD574\uC8FC\uC138\uC694.",
|
|
1002
|
+
EXIT_PARAM_ERROR
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
const frontmatter = import_js_yaml.default.load(match[1]);
|
|
1006
|
+
const body = match[2];
|
|
1007
|
+
return {
|
|
1008
|
+
subject: frontmatter.subject ?? "",
|
|
1009
|
+
priority: frontmatter.priority ?? "normal",
|
|
1010
|
+
due_date: frontmatter.due_date ?? null,
|
|
1011
|
+
to: frontmatter.to ?? [],
|
|
1012
|
+
cc: frontmatter.cc ?? [],
|
|
1013
|
+
body
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
function serializeWikiFrontmatter(page) {
|
|
1017
|
+
const frontmatter = {
|
|
1018
|
+
title: page.subject
|
|
1019
|
+
};
|
|
1020
|
+
const yamlStr = import_js_yaml.default.dump(frontmatter, {
|
|
1021
|
+
quotingType: '"',
|
|
1022
|
+
forceQuotes: false,
|
|
1023
|
+
lineWidth: -1
|
|
1024
|
+
});
|
|
1025
|
+
return `---
|
|
1026
|
+
${yamlStr}---
|
|
1027
|
+
${page.body?.content ?? ""}`;
|
|
1028
|
+
}
|
|
1029
|
+
function parseWikiFrontmatter(content) {
|
|
1030
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
1031
|
+
if (!match) {
|
|
1032
|
+
throw new DoorayCliError(
|
|
1033
|
+
"frontmatter \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --- \uAD6C\uBD84\uC790\uB97C \uD655\uC778\uD574\uC8FC\uC138\uC694.",
|
|
1034
|
+
EXIT_PARAM_ERROR
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
const frontmatter = import_js_yaml.default.load(match[1]);
|
|
1038
|
+
const body = match[2];
|
|
1039
|
+
return {
|
|
1040
|
+
title: frontmatter.title ?? "",
|
|
1041
|
+
body
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// src/commands/post/edit.ts
|
|
1046
|
+
async function resolveUsers(client, projectId, emails) {
|
|
1047
|
+
const users = [];
|
|
1048
|
+
for (const email of emails) {
|
|
1049
|
+
const memberId = await resolveMember(client, projectId, email);
|
|
1050
|
+
users.push({ type: "member", member: { organizationMemberId: memberId } });
|
|
1051
|
+
}
|
|
1052
|
+
return users;
|
|
1053
|
+
}
|
|
1054
|
+
async function readStdin() {
|
|
1055
|
+
if (process.stdin.isTTY) {
|
|
1056
|
+
throw new DoorayCliError(
|
|
1057
|
+
"stdin\uC5D0\uC11C \uC77D\uC73C\uB824\uBA74 \uD30C\uC774\uD504\uB85C \uB370\uC774\uD130\uB97C \uC804\uB2EC\uD574\uC8FC\uC138\uC694.",
|
|
1058
|
+
EXIT_PARAM_ERROR
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
const chunks = [];
|
|
1062
|
+
for await (const chunk of process.stdin) {
|
|
1063
|
+
chunks.push(chunk);
|
|
1064
|
+
}
|
|
1065
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
1066
|
+
}
|
|
1067
|
+
async function resolveBody(opts) {
|
|
1068
|
+
if (opts.body) {
|
|
1069
|
+
if (opts.body === "-") return readStdin();
|
|
1070
|
+
return opts.body;
|
|
1071
|
+
}
|
|
1072
|
+
if (opts.bodyFile) {
|
|
1073
|
+
if (opts.bodyFile === "-") return readStdin();
|
|
1074
|
+
return import_promises4.default.readFile(opts.bodyFile, "utf-8");
|
|
1075
|
+
}
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
var postEditCommand = new import_commander10.Command("edit").description("\uC5C5\uBB34 \uC218\uC815 ($EDITOR \uB610\uB294 --subject/--body \uC635\uC158)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").option("--subject <title>", "\uC81C\uBAA9 \uBCC0\uACBD (non-interactive)").option("--body <text>", "\uBCF8\uBB38 \uBCC0\uACBD (- \uC785\uB825 \uC2DC stdin, non-interactive)").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C (- \uC785\uB825 \uC2DC stdin, non-interactive)").action(async (project, postNumberStr, opts) => {
|
|
1079
|
+
const config = await getConfigOrThrow();
|
|
1080
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1081
|
+
startSpinner("\uC5C5\uBB34 \uC870\uD68C \uC911...");
|
|
1082
|
+
const projectId = await resolveProject(client, project);
|
|
1083
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
1084
|
+
const res = await client.getPost(projectId, postId);
|
|
1085
|
+
const post = res.result;
|
|
1086
|
+
const members = await ensureMembers(client, projectId);
|
|
1087
|
+
stopSpinner(true, "\uC5C5\uBB34 \uC870\uD68C \uC644\uB8CC");
|
|
1088
|
+
const nonInteractive = opts.subject || opts.body || opts.bodyFile;
|
|
1089
|
+
if (nonInteractive) {
|
|
1090
|
+
const newBody = await resolveBody(opts);
|
|
1091
|
+
startSpinner("\uC5C5\uBB34 \uC218\uC815 \uC911...");
|
|
1092
|
+
const toUsers = post.users.to.map((u) => ({
|
|
1093
|
+
type: u.type,
|
|
1094
|
+
member: u.member,
|
|
1095
|
+
emailUser: u.emailUser,
|
|
1096
|
+
group: u.group
|
|
1097
|
+
}));
|
|
1098
|
+
const ccUsers = post.users.cc.map((u) => ({
|
|
1099
|
+
type: u.type,
|
|
1100
|
+
member: u.member,
|
|
1101
|
+
emailUser: u.emailUser,
|
|
1102
|
+
group: u.group
|
|
1103
|
+
}));
|
|
1104
|
+
await client.updatePost(projectId, postId, {
|
|
1105
|
+
subject: opts.subject ?? post.subject,
|
|
1106
|
+
body: {
|
|
1107
|
+
mimeType: "text/x-markdown",
|
|
1108
|
+
content: newBody ?? post.body.content
|
|
1109
|
+
},
|
|
1110
|
+
priority: post.priority,
|
|
1111
|
+
dueDate: post.dueDate,
|
|
1112
|
+
dueDateFlag: post.dueDateFlag,
|
|
1113
|
+
users: { to: toUsers, cc: ccUsers }
|
|
1114
|
+
});
|
|
1115
|
+
stopSpinner(true, "\uC5C5\uBB34 \uC218\uC815 \uC644\uB8CC");
|
|
1116
|
+
} else {
|
|
1117
|
+
const original = serializePostFrontmatter(post, members);
|
|
1118
|
+
const edited = await openInEditor(original);
|
|
1119
|
+
if (original === edited) {
|
|
1120
|
+
process.stdout.write("\uBCC0\uACBD\uC0AC\uD56D \uC5C6\uC74C\n");
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
const parsed = parsePostFrontmatter(edited);
|
|
1124
|
+
startSpinner("\uC5C5\uBB34 \uC218\uC815 \uC911...");
|
|
1125
|
+
const toUsers = await resolveUsers(client, projectId, parsed.to);
|
|
1126
|
+
const ccUsers = await resolveUsers(client, projectId, parsed.cc);
|
|
1127
|
+
await client.updatePost(projectId, postId, {
|
|
1128
|
+
subject: parsed.subject,
|
|
1129
|
+
body: { mimeType: "text/x-markdown", content: parsed.body },
|
|
1130
|
+
priority: parsed.priority,
|
|
1131
|
+
dueDate: parsed.due_date ?? void 0,
|
|
1132
|
+
dueDateFlag: parsed.due_date != null,
|
|
1133
|
+
users: { to: toUsers, cc: ccUsers }
|
|
1134
|
+
});
|
|
1135
|
+
stopSpinner(true, "\uC5C5\uBB34 \uC218\uC815 \uC644\uB8CC");
|
|
1136
|
+
}
|
|
1137
|
+
process.stdout.write(`#${postNumberStr} \uC5C5\uBB34\uAC00 \uC218\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
1138
|
+
`);
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
// src/commands/post/create.ts
|
|
1142
|
+
var import_commander11 = require("commander");
|
|
1143
|
+
var import_promises5 = __toESM(require("fs/promises"));
|
|
1144
|
+
async function readBody(opts) {
|
|
1145
|
+
if (opts.bodyFile) {
|
|
1146
|
+
if (opts.bodyFile === "-") {
|
|
1147
|
+
return readStdin2();
|
|
1148
|
+
}
|
|
1149
|
+
return import_promises5.default.readFile(opts.bodyFile, "utf-8");
|
|
1150
|
+
}
|
|
1151
|
+
if (opts.body === "-") {
|
|
1152
|
+
return readStdin2();
|
|
1153
|
+
}
|
|
1154
|
+
return "";
|
|
1155
|
+
}
|
|
1156
|
+
async function readStdin2() {
|
|
1157
|
+
if (process.stdin.isTTY) {
|
|
1158
|
+
throw new DoorayCliError(
|
|
1159
|
+
"stdin\uC5D0\uC11C \uC77D\uC73C\uB824\uBA74 \uD30C\uC774\uD504\uB85C \uB370\uC774\uD130\uB97C \uC804\uB2EC\uD574\uC8FC\uC138\uC694.",
|
|
1160
|
+
EXIT_PARAM_ERROR
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
const chunks = [];
|
|
1164
|
+
for await (const chunk of process.stdin) {
|
|
1165
|
+
chunks.push(chunk);
|
|
1166
|
+
}
|
|
1167
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
1168
|
+
}
|
|
1169
|
+
async function resolveUsers2(client, projectId, inputs) {
|
|
1170
|
+
const users = [];
|
|
1171
|
+
for (const input of inputs) {
|
|
1172
|
+
const memberId = await resolveMember(client, projectId, input);
|
|
1173
|
+
users.push({ type: "member", member: { organizationMemberId: memberId } });
|
|
1174
|
+
}
|
|
1175
|
+
return users;
|
|
1176
|
+
}
|
|
1177
|
+
var postCreateCommand = new import_commander11.Command("create").description("\uC5C5\uBB34 \uC0DD\uC131").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").requiredOption("--subject <title>", "\uC5C5\uBB34 \uC81C\uBAA9").option("--to <members...>", "\uB2F4\uB2F9\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").option("--cc <members...>", "\uCC38\uC870\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").option("--priority <level>", "\uC6B0\uC120\uC21C\uC704 (highest, high, normal, low, lowest)", "normal").option("--due-date <date>", "\uB9C8\uAC10\uC77C (ISO 8601 \uD615\uC2DD)").action(async (project, opts) => {
|
|
1178
|
+
const globalOpts = postCreateCommand.optsWithGlobals();
|
|
1179
|
+
const config = await getConfigOrThrow();
|
|
1180
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1181
|
+
const bodyContent = await readBody(opts);
|
|
1182
|
+
startSpinner("\uC5C5\uBB34 \uC0DD\uC131 \uC911...");
|
|
1183
|
+
const projectId = await resolveProject(client, project);
|
|
1184
|
+
const toUsers = opts.to ? await resolveUsers2(client, projectId, opts.to) : [];
|
|
1185
|
+
const ccUsers = opts.cc ? await resolveUsers2(client, projectId, opts.cc) : [];
|
|
1186
|
+
const res = await client.createPost(projectId, {
|
|
1187
|
+
subject: opts.subject,
|
|
1188
|
+
body: { mimeType: "text/x-markdown", content: bodyContent },
|
|
1189
|
+
users: { to: toUsers, cc: ccUsers },
|
|
1190
|
+
priority: opts.priority,
|
|
1191
|
+
...opts.dueDate && { dueDate: opts.dueDate, dueDateFlag: true }
|
|
1192
|
+
});
|
|
1193
|
+
stopSpinner(true, "\uC5C5\uBB34 \uC0DD\uC131 \uC644\uB8CC");
|
|
1194
|
+
if (globalOpts.json) {
|
|
1195
|
+
printJson(res.result);
|
|
1196
|
+
} else if (globalOpts.quiet) {
|
|
1197
|
+
process.stdout.write(res.result.id + "\n");
|
|
1198
|
+
} else {
|
|
1199
|
+
process.stdout.write(`\uC5C5\uBB34\uAC00 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${res.result.id}
|
|
1200
|
+
`);
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
// src/commands/post/done.ts
|
|
1205
|
+
var import_commander12 = require("commander");
|
|
1206
|
+
var postDoneCommand = new import_commander12.Command("done").description("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").action(async (project, postNumberStr) => {
|
|
1207
|
+
const config = await getConfigOrThrow();
|
|
1208
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1209
|
+
startSpinner("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC \uC911...");
|
|
1210
|
+
const projectId = await resolveProject(client, project);
|
|
1211
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
1212
|
+
await client.setPostDone(projectId, postId);
|
|
1213
|
+
stopSpinner(true, "\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC \uC644\uB8CC");
|
|
1214
|
+
process.stdout.write(`#${postNumberStr} \uC5C5\uBB34\uAC00 \uC644\uB8CC \uCC98\uB9AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
1215
|
+
`);
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1218
|
+
// src/commands/post/workflow.ts
|
|
1219
|
+
var import_commander13 = require("commander");
|
|
1220
|
+
var postWorkflowCommand = new import_commander13.Command("workflow").description("\uC5C5\uBB34 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").argument("<workflow>", "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984 \uB610\uB294 \uD074\uB798\uC2A4").action(async (project, postNumberStr, workflow) => {
|
|
1221
|
+
const config = await getConfigOrThrow();
|
|
1222
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1223
|
+
startSpinner("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD \uC911...");
|
|
1224
|
+
const projectId = await resolveProject(client, project);
|
|
1225
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
1226
|
+
const workflowId = await resolveWorkflow(client, projectId, workflow);
|
|
1227
|
+
await client.setPostWorkflow(projectId, postId, workflowId);
|
|
1228
|
+
stopSpinner(true, "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD \uC644\uB8CC");
|
|
1229
|
+
process.stdout.write(`#${postNumberStr} \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 "${workflow}"(\uC73C)\uB85C \uBCC0\uACBD\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
1230
|
+
`);
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
// src/commands/post/comment/list.ts
|
|
1234
|
+
var import_commander14 = require("commander");
|
|
1235
|
+
var commentListCommand = new import_commander14.Command("list").description("\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (project, postNumberStr, opts) => {
|
|
1236
|
+
const globalOpts = commentListCommand.optsWithGlobals();
|
|
1237
|
+
const config = await getConfigOrThrow();
|
|
1238
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1239
|
+
startSpinner("\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
1240
|
+
const projectId = await resolveProject(client, project);
|
|
1241
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
1242
|
+
const res = await client.getPostComments(projectId, postId, {
|
|
1243
|
+
page: Number(opts.page),
|
|
1244
|
+
size: Number(opts.size)
|
|
1245
|
+
});
|
|
1246
|
+
stopSpinner(true, "\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
1247
|
+
formatCommentList(res.result, globalOpts);
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
// src/commands/post/comment/add.ts
|
|
1251
|
+
var import_commander15 = require("commander");
|
|
1252
|
+
var import_promises6 = __toESM(require("fs/promises"));
|
|
1253
|
+
async function readStdin3() {
|
|
1254
|
+
if (process.stdin.isTTY) {
|
|
1255
|
+
throw new DoorayCliError(
|
|
1256
|
+
"stdin\uC5D0\uC11C \uC77D\uC73C\uB824\uBA74 \uD30C\uC774\uD504\uB85C \uB370\uC774\uD130\uB97C \uC804\uB2EC\uD574\uC8FC\uC138\uC694.",
|
|
1257
|
+
EXIT_PARAM_ERROR
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
const chunks = [];
|
|
1261
|
+
for await (const chunk of process.stdin) {
|
|
1262
|
+
chunks.push(chunk);
|
|
1263
|
+
}
|
|
1264
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
1265
|
+
}
|
|
1266
|
+
async function resolveBody2(opts) {
|
|
1267
|
+
if (opts.body) {
|
|
1268
|
+
if (opts.body === "-") return readStdin3();
|
|
1269
|
+
return opts.body;
|
|
1270
|
+
}
|
|
1271
|
+
if (opts.bodyFile) {
|
|
1272
|
+
if (opts.bodyFile === "-") return readStdin3();
|
|
1273
|
+
return import_promises6.default.readFile(opts.bodyFile, "utf-8");
|
|
1274
|
+
}
|
|
1275
|
+
return null;
|
|
1276
|
+
}
|
|
1277
|
+
var commentAddCommand = new import_commander15.Command("add").description("\uB313\uAE00 \uCD94\uAC00").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").option("--body <text>", "\uB313\uAE00 \uBCF8\uBB38 (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").action(async (project, postNumberStr, opts) => {
|
|
1278
|
+
const globalOpts = commentAddCommand.optsWithGlobals();
|
|
1279
|
+
const config = await getConfigOrThrow();
|
|
1280
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1281
|
+
let bodyContent = await resolveBody2(opts);
|
|
1282
|
+
if (bodyContent == null) {
|
|
1283
|
+
bodyContent = await openInEditor("");
|
|
1284
|
+
if (!bodyContent.trim()) {
|
|
1285
|
+
process.stdout.write("\uBE48 \uB313\uAE00\uC740 \uC791\uC131\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\n");
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
startSpinner("\uB313\uAE00 \uCD94\uAC00 \uC911...");
|
|
1290
|
+
const projectId = await resolveProject(client, project);
|
|
1291
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
1292
|
+
const res = await client.createPostComment(projectId, postId, {
|
|
1293
|
+
body: { mimeType: "text/x-markdown", content: bodyContent }
|
|
1294
|
+
});
|
|
1295
|
+
stopSpinner(true, "\uB313\uAE00 \uCD94\uAC00 \uC644\uB8CC");
|
|
1296
|
+
if (globalOpts.json) {
|
|
1297
|
+
printJson(res.result);
|
|
1298
|
+
} else if (globalOpts.quiet) {
|
|
1299
|
+
process.stdout.write(res.result.id + "\n");
|
|
1300
|
+
} else {
|
|
1301
|
+
process.stdout.write(`\uB313\uAE00\uC774 \uCD94\uAC00\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${res.result.id}
|
|
1302
|
+
`);
|
|
1303
|
+
}
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
// src/commands/post/comment/edit.ts
|
|
1307
|
+
var import_commander16 = require("commander");
|
|
1308
|
+
var import_promises7 = __toESM(require("fs/promises"));
|
|
1309
|
+
async function readStdin4() {
|
|
1310
|
+
if (process.stdin.isTTY) {
|
|
1311
|
+
throw new DoorayCliError(
|
|
1312
|
+
"stdin\uC5D0\uC11C \uC77D\uC73C\uB824\uBA74 \uD30C\uC774\uD504\uB85C \uB370\uC774\uD130\uB97C \uC804\uB2EC\uD574\uC8FC\uC138\uC694.",
|
|
1313
|
+
EXIT_PARAM_ERROR
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
const chunks = [];
|
|
1317
|
+
for await (const chunk of process.stdin) {
|
|
1318
|
+
chunks.push(chunk);
|
|
1319
|
+
}
|
|
1320
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
1321
|
+
}
|
|
1322
|
+
async function resolveBody3(opts) {
|
|
1323
|
+
if (opts.body) {
|
|
1324
|
+
if (opts.body === "-") return readStdin4();
|
|
1325
|
+
return opts.body;
|
|
1326
|
+
}
|
|
1327
|
+
if (opts.bodyFile) {
|
|
1328
|
+
if (opts.bodyFile === "-") return readStdin4();
|
|
1329
|
+
return import_promises7.default.readFile(opts.bodyFile, "utf-8");
|
|
1330
|
+
}
|
|
1331
|
+
return null;
|
|
1332
|
+
}
|
|
1333
|
+
var commentEditCommand = new import_commander16.Command("edit").description("\uB313\uAE00 \uC218\uC815 ($EDITOR \uB610\uB294 --body \uC635\uC158)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").argument("<comment-id>", "\uB313\uAE00 ID").option("--body <text>", "\uB313\uAE00 \uBCF8\uBB38 \uBCC0\uACBD (- \uC785\uB825 \uC2DC stdin, non-interactive)").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C (- \uC785\uB825 \uC2DC stdin, non-interactive)").action(async (project, postNumberStr, commentId, opts) => {
|
|
1334
|
+
const config = await getConfigOrThrow();
|
|
1335
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1336
|
+
startSpinner("\uB313\uAE00 \uC870\uD68C \uC911...");
|
|
1337
|
+
const projectId = await resolveProject(client, project);
|
|
1338
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
1339
|
+
const comments = await client.getPostComments(projectId, postId);
|
|
1340
|
+
const comment = comments.result.find((c) => c.id === commentId);
|
|
1341
|
+
stopSpinner(true, "\uB313\uAE00 \uC870\uD68C \uC644\uB8CC");
|
|
1342
|
+
if (!comment) {
|
|
1343
|
+
process.stderr.write(`\uB313\uAE00\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${commentId}
|
|
1344
|
+
`);
|
|
1345
|
+
process.exit(1);
|
|
1346
|
+
}
|
|
1347
|
+
let edited = await resolveBody3(opts);
|
|
1348
|
+
if (edited == null) {
|
|
1349
|
+
const original = comment.body.content;
|
|
1350
|
+
edited = await openInEditor(original);
|
|
1351
|
+
if (original === edited) {
|
|
1352
|
+
process.stdout.write("\uBCC0\uACBD\uC0AC\uD56D \uC5C6\uC74C\n");
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
startSpinner("\uB313\uAE00 \uC218\uC815 \uC911...");
|
|
1357
|
+
await client.updatePostComment(projectId, postId, commentId, {
|
|
1358
|
+
body: { mimeType: "text/x-markdown", content: edited }
|
|
1359
|
+
});
|
|
1360
|
+
stopSpinner(true, "\uB313\uAE00 \uC218\uC815 \uC644\uB8CC");
|
|
1361
|
+
process.stdout.write(`\uB313\uAE00\uC774 \uC218\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${commentId}
|
|
1362
|
+
`);
|
|
1363
|
+
});
|
|
1364
|
+
|
|
1365
|
+
// src/commands/post/comment/delete.ts
|
|
1366
|
+
var import_commander17 = require("commander");
|
|
1367
|
+
var commentDeleteCommand = new import_commander17.Command("delete").description("\uB313\uAE00 \uC0AD\uC81C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").argument("<comment-id>", "\uB313\uAE00 ID").action(async (project, postNumberStr, commentId) => {
|
|
1368
|
+
const config = await getConfigOrThrow();
|
|
1369
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1370
|
+
startSpinner("\uB313\uAE00 \uC0AD\uC81C \uC911...");
|
|
1371
|
+
const projectId = await resolveProject(client, project);
|
|
1372
|
+
const postId = await resolvePost(client, projectId, Number(postNumberStr));
|
|
1373
|
+
await client.deletePostComment(projectId, postId, commentId);
|
|
1374
|
+
stopSpinner(true, "\uB313\uAE00 \uC0AD\uC81C \uC644\uB8CC");
|
|
1375
|
+
process.stdout.write(`\uB313\uAE00\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${commentId}
|
|
1376
|
+
`);
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
// src/commands/wiki/list.ts
|
|
1380
|
+
var import_commander18 = require("commander");
|
|
1381
|
+
|
|
1382
|
+
// src/formatters/wiki.ts
|
|
1383
|
+
function formatWikiList(wikis, opts) {
|
|
1384
|
+
output(opts, {
|
|
1385
|
+
headers: ["ID", "Name", "Type"],
|
|
1386
|
+
rows: wikis.map((w) => [w.id, w.name, w.type]),
|
|
1387
|
+
raw: wikis,
|
|
1388
|
+
ids: wikis.map((w) => w.id)
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
function formatWikiPages(pages, opts) {
|
|
1392
|
+
output(opts, {
|
|
1393
|
+
headers: ["ID", "Subject", "Creator"],
|
|
1394
|
+
rows: pages.map((p) => [
|
|
1395
|
+
p.id,
|
|
1396
|
+
p.subject,
|
|
1397
|
+
p.creator?.member?.name ?? ""
|
|
1398
|
+
]),
|
|
1399
|
+
raw: pages,
|
|
1400
|
+
ids: pages.map((p) => p.id)
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
function formatWikiPageDetail(page, opts) {
|
|
1404
|
+
if (opts.json) {
|
|
1405
|
+
printJson(page);
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
const lines = [
|
|
1409
|
+
`${page.subject}`,
|
|
1410
|
+
`ID: ${page.id}`,
|
|
1411
|
+
`Wiki: ${page.wikiId}`,
|
|
1412
|
+
`\uBC84\uC804: ${page.version}`,
|
|
1413
|
+
`\uC791\uC131\uC790: ${page.creator?.member?.name ?? ""}`,
|
|
1414
|
+
...page.createdAt ? [`\uC0DD\uC131: ${page.createdAt}`] : [],
|
|
1415
|
+
...page.updatedAt ? [`\uC218\uC815: ${page.updatedAt}`] : [],
|
|
1416
|
+
"",
|
|
1417
|
+
page.body?.content ?? ""
|
|
1418
|
+
];
|
|
1419
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// src/commands/wiki/list.ts
|
|
1423
|
+
var wikiListCommand = new import_commander18.Command("list").description("\uC704\uD0A4 \uBAA9\uB85D \uC870\uD68C").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (opts) => {
|
|
1424
|
+
const globalOpts = wikiListCommand.optsWithGlobals();
|
|
1425
|
+
const config = await getConfigOrThrow();
|
|
1426
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1427
|
+
startSpinner("\uC704\uD0A4 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
1428
|
+
const res = await client.getWikis({
|
|
1429
|
+
page: Number(opts.page),
|
|
1430
|
+
size: Number(opts.size)
|
|
1431
|
+
});
|
|
1432
|
+
stopSpinner(true, "\uC704\uD0A4 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
1433
|
+
formatWikiList(res.result, globalOpts);
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
// src/commands/wiki/pages.ts
|
|
1437
|
+
var import_commander19 = require("commander");
|
|
1438
|
+
|
|
1439
|
+
// src/resolvers/wiki.ts
|
|
1440
|
+
async function resolveWiki(client, projectCode) {
|
|
1441
|
+
await resolveProject(client, projectCode);
|
|
1442
|
+
const entry = await getProjects();
|
|
1443
|
+
const project = entry?.data.find(
|
|
1444
|
+
(p) => p.code === projectCode || p.id === projectCode
|
|
1445
|
+
);
|
|
1446
|
+
if (!project?.wikiId) {
|
|
1447
|
+
throw new DoorayCliError(
|
|
1448
|
+
`\uD504\uB85C\uC81D\uD2B8\uC5D0 \uC704\uD0A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: ${projectCode}`,
|
|
1449
|
+
EXIT_PARAM_ERROR
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
return project.wikiId;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// src/commands/wiki/pages.ts
|
|
1456
|
+
var wikiPagesCommand = new import_commander19.Command("pages").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--parent <page-id>", "\uBD80\uBAA8 \uD398\uC774\uC9C0 ID").action(async (project, opts) => {
|
|
1457
|
+
const globalOpts = wikiPagesCommand.optsWithGlobals();
|
|
1458
|
+
const config = await getConfigOrThrow();
|
|
1459
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1460
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
1461
|
+
const wikiId = await resolveWiki(client, project);
|
|
1462
|
+
const res = await client.getWikiPages(wikiId, opts.parent);
|
|
1463
|
+
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
1464
|
+
formatWikiPages(res.result, globalOpts);
|
|
1465
|
+
});
|
|
1466
|
+
|
|
1467
|
+
// src/commands/wiki/page-get.ts
|
|
1468
|
+
var import_commander20 = require("commander");
|
|
1469
|
+
var wikiPageGetCommand = new import_commander20.Command("get").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0C1\uC138 \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").action(async (project, pageId) => {
|
|
1470
|
+
const globalOpts = wikiPageGetCommand.optsWithGlobals();
|
|
1471
|
+
const config = await getConfigOrThrow();
|
|
1472
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1473
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC870\uD68C \uC911...");
|
|
1474
|
+
const wikiId = await resolveWiki(client, project);
|
|
1475
|
+
const res = await client.getWikiPage(wikiId, pageId);
|
|
1476
|
+
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC870\uD68C \uC644\uB8CC");
|
|
1477
|
+
formatWikiPageDetail(res.result, globalOpts);
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1480
|
+
// src/commands/wiki/page-create.ts
|
|
1481
|
+
var import_commander21 = require("commander");
|
|
1482
|
+
var import_promises8 = __toESM(require("fs/promises"));
|
|
1483
|
+
async function readBody2(opts) {
|
|
1484
|
+
if (opts.bodyFile) {
|
|
1485
|
+
if (opts.bodyFile === "-") {
|
|
1486
|
+
return readStdin5();
|
|
1487
|
+
}
|
|
1488
|
+
return import_promises8.default.readFile(opts.bodyFile, "utf-8");
|
|
1489
|
+
}
|
|
1490
|
+
if (opts.body === "-") {
|
|
1491
|
+
return readStdin5();
|
|
1492
|
+
}
|
|
1493
|
+
return "";
|
|
1494
|
+
}
|
|
1495
|
+
async function readStdin5() {
|
|
1496
|
+
if (process.stdin.isTTY) {
|
|
1497
|
+
throw new DoorayCliError(
|
|
1498
|
+
"stdin\uC5D0\uC11C \uC77D\uC73C\uB824\uBA74 \uD30C\uC774\uD504\uB85C \uB370\uC774\uD130\uB97C \uC804\uB2EC\uD574\uC8FC\uC138\uC694.",
|
|
1499
|
+
EXIT_PARAM_ERROR
|
|
1500
|
+
);
|
|
1501
|
+
}
|
|
1502
|
+
const chunks = [];
|
|
1503
|
+
for await (const chunk of process.stdin) {
|
|
1504
|
+
chunks.push(chunk);
|
|
1505
|
+
}
|
|
1506
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
1507
|
+
}
|
|
1508
|
+
var wikiPageCreateCommand = new import_commander21.Command("create").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0DD\uC131").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").requiredOption("--title <title>", "\uD398\uC774\uC9C0 \uC81C\uBAA9").option("--parent <page-id>", "\uBD80\uBAA8 \uD398\uC774\uC9C0 ID").option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").action(async (project, opts) => {
|
|
1509
|
+
const globalOpts = wikiPageCreateCommand.optsWithGlobals();
|
|
1510
|
+
const config = await getConfigOrThrow();
|
|
1511
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1512
|
+
const bodyContent = await readBody2(opts);
|
|
1513
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC911...");
|
|
1514
|
+
const wikiId = await resolveWiki(client, project);
|
|
1515
|
+
const res = await client.createWikiPage(wikiId, {
|
|
1516
|
+
subject: opts.title,
|
|
1517
|
+
body: { mimeType: "text/x-markdown", content: bodyContent },
|
|
1518
|
+
parentPageId: opts.parent ?? ""
|
|
1519
|
+
});
|
|
1520
|
+
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC644\uB8CC");
|
|
1521
|
+
if (globalOpts.json) {
|
|
1522
|
+
printJson(res.result);
|
|
1523
|
+
} else if (globalOpts.quiet) {
|
|
1524
|
+
process.stdout.write(res.result.id + "\n");
|
|
1525
|
+
} else {
|
|
1526
|
+
process.stdout.write(`\uC704\uD0A4 \uD398\uC774\uC9C0\uAC00 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${res.result.id}
|
|
1527
|
+
`);
|
|
1528
|
+
}
|
|
1529
|
+
});
|
|
1530
|
+
|
|
1531
|
+
// src/commands/wiki/page-edit.ts
|
|
1532
|
+
var import_commander22 = require("commander");
|
|
1533
|
+
var wikiPageEditCommand = new import_commander22.Command("edit").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 ($EDITOR)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").action(async (project, pageId) => {
|
|
1534
|
+
const config = await getConfigOrThrow();
|
|
1535
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1536
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC870\uD68C \uC911...");
|
|
1537
|
+
const wikiId = await resolveWiki(client, project);
|
|
1538
|
+
const res = await client.getWikiPage(wikiId, pageId);
|
|
1539
|
+
const page = res.result;
|
|
1540
|
+
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC870\uD68C \uC644\uB8CC");
|
|
1541
|
+
const original = serializeWikiFrontmatter(page);
|
|
1542
|
+
const edited = await openInEditor(original);
|
|
1543
|
+
if (original === edited) {
|
|
1544
|
+
process.stdout.write("\uBCC0\uACBD\uC0AC\uD56D \uC5C6\uC74C\n");
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
const parsed = parseWikiFrontmatter(edited);
|
|
1548
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 \uC911...");
|
|
1549
|
+
await client.updateWikiPage(wikiId, pageId, {
|
|
1550
|
+
subject: parsed.title,
|
|
1551
|
+
body: { mimeType: "text/x-markdown", content: parsed.body }
|
|
1552
|
+
});
|
|
1553
|
+
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 \uC644\uB8CC");
|
|
1554
|
+
process.stdout.write(`\uC704\uD0A4 \uD398\uC774\uC9C0\uAC00 \uC218\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${pageId}
|
|
1555
|
+
`);
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
// src/index.ts
|
|
1559
|
+
var program = new import_commander23.Command();
|
|
1560
|
+
program.name("dooray").description("Dooray REST API CLI").version("0.1.0").option("--json", "JSON \uD615\uC2DD\uC73C\uB85C \uCD9C\uB825").option("--quiet", "ID\uB9CC \uCD9C\uB825").option("--no-color", "\uC0C9\uC0C1 \uBE44\uD65C\uC131\uD654");
|
|
1561
|
+
program.hook("preAction", () => {
|
|
1562
|
+
const opts = program.opts();
|
|
1563
|
+
if (opts.color === false || process.env.NO_COLOR) {
|
|
1564
|
+
import_chalk4.default.level = 0;
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
var projectCommand = new import_commander23.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
|
|
1568
|
+
projectCommand.addCommand(projectListCommand);
|
|
1569
|
+
projectCommand.addCommand(projectMembersCommand);
|
|
1570
|
+
projectCommand.addCommand(projectWorkflowsCommand);
|
|
1571
|
+
var postCommand = new import_commander23.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
|
|
1572
|
+
postCommand.addCommand(postListCommand);
|
|
1573
|
+
postCommand.addCommand(postSearchCommand);
|
|
1574
|
+
postCommand.addCommand(postGetCommand);
|
|
1575
|
+
postCommand.addCommand(postEditCommand);
|
|
1576
|
+
postCommand.addCommand(postCreateCommand);
|
|
1577
|
+
postCommand.addCommand(postDoneCommand);
|
|
1578
|
+
postCommand.addCommand(postWorkflowCommand);
|
|
1579
|
+
var commentCommand = new import_commander23.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
|
|
1580
|
+
commentCommand.addCommand(commentListCommand);
|
|
1581
|
+
commentCommand.addCommand(commentAddCommand);
|
|
1582
|
+
commentCommand.addCommand(commentEditCommand);
|
|
1583
|
+
commentCommand.addCommand(commentDeleteCommand);
|
|
1584
|
+
postCommand.addCommand(commentCommand);
|
|
1585
|
+
var wikiCommand = new import_commander23.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
|
|
1586
|
+
wikiCommand.addCommand(wikiListCommand);
|
|
1587
|
+
wikiCommand.addCommand(wikiPagesCommand);
|
|
1588
|
+
var wikiPageCommand = new import_commander23.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
|
|
1589
|
+
wikiPageCommand.addCommand(wikiPageGetCommand);
|
|
1590
|
+
wikiPageCommand.addCommand(wikiPageCreateCommand);
|
|
1591
|
+
wikiPageCommand.addCommand(wikiPageEditCommand);
|
|
1592
|
+
wikiCommand.addCommand(wikiPageCommand);
|
|
1593
|
+
program.addCommand(configCommand);
|
|
1594
|
+
program.addCommand(cacheCommand);
|
|
1595
|
+
program.addCommand(doctorCommand);
|
|
1596
|
+
program.addCommand(projectCommand);
|
|
1597
|
+
program.addCommand(postCommand);
|
|
1598
|
+
program.addCommand(wikiCommand);
|
|
1599
|
+
program.parseAsync().catch((err) => {
|
|
1600
|
+
if (err instanceof DoorayCliError) {
|
|
1601
|
+
process.stderr.write(import_chalk4.default.red(`\uC624\uB958: ${err.message}`) + "\n");
|
|
1602
|
+
process.exit(err.exitCode);
|
|
1603
|
+
}
|
|
1604
|
+
process.stderr.write(import_chalk4.default.red(`\uC624\uB958: ${err.message}`) + "\n");
|
|
1605
|
+
process.exit(1);
|
|
1606
|
+
});
|