@ecubelabs/atlassian-mcp 1.1.0-next.1 → 1.2.0-next.1

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.
@@ -14,59 +14,49 @@ export class JiraService extends BaseApiService {
14
14
  }));
15
15
  }
16
16
  /**
17
- * JQL 검색
18
- * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/#api-rest-api-3-search-jql-get
17
+ * JQL 검색 (Enhanced Search)
18
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/#api-rest-api-3-search-jql-post
19
19
  */
20
20
  async searchIssues(options) {
21
- const allIssues = [];
22
21
  const { jql, nextPageToken, maxResults = 50, fields, expand, properties, fieldsByKeys, failFast, reconcileIssues, } = options;
23
- // Prepare parameters for API request
24
- const params = {
22
+ // Prepare request body for POST request
23
+ const body = {
25
24
  jql,
26
25
  maxResults,
27
26
  };
28
27
  // Add optional parameters if provided
29
28
  if (nextPageToken)
30
- params.nextPageToken = nextPageToken;
29
+ body.nextPageToken = nextPageToken;
31
30
  if (fields)
32
- params.fields = fields.join(",");
31
+ body.fields = fields;
33
32
  if (expand)
34
- params.expand = expand.join(",");
33
+ body.expand = expand;
35
34
  if (properties)
36
- params.properties = properties.join(",");
35
+ body.properties = properties;
37
36
  if (fieldsByKeys !== undefined)
38
- params.fieldsByKeys = fieldsByKeys;
37
+ body.fieldsByKeys = fieldsByKeys;
39
38
  if (failFast !== undefined)
40
- params.failFast = failFast;
39
+ body.failFast = failFast;
41
40
  if (reconcileIssues)
42
- params.reconcileIssues = reconcileIssues.join(",");
43
- // Single page retrieval when nextPageToken is provided
44
- if (nextPageToken) {
45
- const response = await this.makeRequest(() => this.client.get("/search/jql", { params }));
46
- return response.issues || [];
47
- }
48
- // Use pagination for complete result set
49
- let token = null;
50
- do {
51
- if (token)
52
- params.nextPageToken = token;
53
- const response = await this.makeRequest(() => this.client.get("/search/jql", { params }));
54
- if (response.issues) {
55
- allIssues.push(...response.issues);
56
- }
57
- token = response.nextPageToken || null;
58
- } while (token);
59
- return allIssues;
41
+ body.reconcileIssues = reconcileIssues;
42
+ const response = await this.makeRequest(() => this.client.post("/search/jql", body));
43
+ return {
44
+ issues: response.issues || [],
45
+ startAt: response.startAt,
46
+ maxResults: response.maxResults,
47
+ total: response.total,
48
+ nextPageToken: response.nextPageToken,
49
+ };
60
50
  }
61
51
  /**
62
- * 프로젝트 목록 조회
52
+ * 프로젝트 목록 조회 (Paginated)
63
53
  * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-projects/#api-rest-api-3-project-search-get
64
54
  */
65
55
  async getProjects(options) {
66
56
  const params = {};
67
57
  // Add optional parameters if provided
68
58
  if (options) {
69
- const { startAt, maxResults, orderBy, id, keys, query, typeKey, categoryId, action, expand, status, properties, propertyQuery } = options;
59
+ const { startAt, maxResults, orderBy, id, keys, query, typeKey, categoryId, action, expand, status, properties, propertyQuery, } = options;
70
60
  if (startAt !== undefined)
71
61
  params.startAt = startAt;
72
62
  if (maxResults !== undefined)
@@ -74,9 +64,9 @@ export class JiraService extends BaseApiService {
74
64
  if (orderBy)
75
65
  params.orderBy = orderBy;
76
66
  if (id)
77
- params.id = id.join(',');
67
+ params.id = id.join(",");
78
68
  if (keys)
79
- params.keys = keys.join(',');
69
+ params.keys = keys.join(",");
80
70
  if (query)
81
71
  params.query = query;
82
72
  if (typeKey)
@@ -86,13 +76,13 @@ export class JiraService extends BaseApiService {
86
76
  if (action)
87
77
  params.action = action;
88
78
  if (expand)
89
- params.expand = expand.join(',');
79
+ params.expand = expand.join(",");
90
80
  if (status)
91
- params.status = status.join(',');
81
+ params.status = status.join(",");
92
82
  if (properties) {
93
83
  // Handle the nested StringList structure
94
84
  properties.forEach((prop, index) => {
95
- params[`properties[${index}]`] = prop.join(',');
85
+ params[`properties[${index}]`] = prop.join(",");
96
86
  });
97
87
  }
98
88
  if (propertyQuery)
@@ -116,8 +106,656 @@ export class JiraService extends BaseApiService {
116
106
  if (orderBy)
117
107
  params.orderBy = orderBy;
118
108
  if (expand)
119
- params.expand = expand.join(',');
109
+ params.expand = expand.join(",");
120
110
  }
121
111
  return this.makeRequest(() => this.client.get(`/issue/${issueKey}/comment`, { params }));
122
112
  }
113
+ /**
114
+ * 프로젝트의 이슈 타입 목록 조회 (이슈 생성용)
115
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-type/#api-rest-api-3-issue-createmeta-projectidorkey-issuetypes-get
116
+ */
117
+ async getCreateMetadataIssueTypes(projectIdOrKey) {
118
+ return this.makeRequest(() => this.client.get(`/issue/createmeta/${projectIdOrKey}/issuetypes`));
119
+ }
120
+ /**
121
+ * 프로젝트와 이슈 타입에 대한 필드 메타데이터 조회
122
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-createmeta-projectidorkey-issuetypes-issuetypeid-get
123
+ */
124
+ async getCreateFieldMetadata(projectIdOrKey, issueTypeId) {
125
+ return this.makeRequest(() => this.client.get(`/issue/createmeta/${projectIdOrKey}/issuetypes/${issueTypeId}`));
126
+ }
127
+ /**
128
+ * 시스템 필드 목록 조회
129
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-fields/#api-rest-api-3-field-search-get
130
+ */
131
+ async getFields(options) {
132
+ const params = {};
133
+ if (options) {
134
+ const { type, query, orderBy, startAt, maxResults } = options;
135
+ if (type)
136
+ params.type = type;
137
+ if (query)
138
+ params.query = query;
139
+ if (orderBy)
140
+ params.orderBy = orderBy;
141
+ if (startAt !== undefined)
142
+ params.startAt = startAt;
143
+ if (maxResults !== undefined)
144
+ params.maxResults = maxResults;
145
+ }
146
+ return this.makeRequest(() => this.client.get("/field/search", { params }));
147
+ }
148
+ /**
149
+ * JQL 파싱 및 검증
150
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-jql/#api-rest-api-3-jql-parse-post
151
+ */
152
+ async parseJql(query, validation) {
153
+ return this.makeRequest(() => this.client.post("/jql/parse", {
154
+ query,
155
+ validation: validation || "strict",
156
+ }));
157
+ }
158
+ /**
159
+ * 이슈 생성
160
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-post
161
+ */
162
+ async createIssue(options) {
163
+ const fields = {
164
+ project: { key: options.projectKey },
165
+ summary: options.summary,
166
+ };
167
+ // Issue type (ID takes precedence)
168
+ if (options.issueTypeId) {
169
+ fields.issuetype = { id: options.issueTypeId };
170
+ }
171
+ else if (options.issueTypeName) {
172
+ fields.issuetype = { name: options.issueTypeName };
173
+ }
174
+ // Optional fields
175
+ if (options.description) {
176
+ fields.description = {
177
+ type: "doc",
178
+ version: 1,
179
+ content: [
180
+ {
181
+ type: "paragraph",
182
+ content: [
183
+ {
184
+ type: "text",
185
+ text: options.description,
186
+ },
187
+ ],
188
+ },
189
+ ],
190
+ };
191
+ }
192
+ if (options.assigneeAccountId) {
193
+ fields.assignee = { accountId: options.assigneeAccountId };
194
+ }
195
+ if (options.reporterAccountId) {
196
+ fields.reporter = { accountId: options.reporterAccountId };
197
+ }
198
+ if (options.priorityId) {
199
+ fields.priority = { id: options.priorityId };
200
+ }
201
+ if (options.labels) {
202
+ fields.labels = options.labels;
203
+ }
204
+ // Merge additional fields
205
+ if (options.additionalFields) {
206
+ Object.assign(fields, options.additionalFields);
207
+ }
208
+ return this.makeRequest(() => this.client.post("/issue", { fields }));
209
+ }
210
+ /**
211
+ * 이슈 담당자 변경
212
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-assignee-put
213
+ */
214
+ async assignIssue(issueKey, accountId) {
215
+ const body = accountId ? { accountId } : null;
216
+ return this.makeRequest(() => this.client.put(`/issue/${issueKey}/assignee`, body));
217
+ }
218
+ /**
219
+ * 이슈 수정
220
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-put
221
+ */
222
+ async editIssue(issueKey, options) {
223
+ const fields = {};
224
+ if (options.summary) {
225
+ fields.summary = options.summary;
226
+ }
227
+ if (options.description) {
228
+ fields.description = {
229
+ type: "doc",
230
+ version: 1,
231
+ content: [
232
+ {
233
+ type: "paragraph",
234
+ content: [
235
+ {
236
+ type: "text",
237
+ text: options.description,
238
+ },
239
+ ],
240
+ },
241
+ ],
242
+ };
243
+ }
244
+ if (options.unassignAssignee) {
245
+ fields.assignee = null;
246
+ }
247
+ else if (options.assigneeAccountId) {
248
+ fields.assignee = { accountId: options.assigneeAccountId };
249
+ }
250
+ if (options.priorityId) {
251
+ fields.priority = { id: options.priorityId };
252
+ }
253
+ if (options.labels !== undefined) {
254
+ fields.labels = options.labels;
255
+ }
256
+ // Merge additional fields
257
+ if (options.additionalFields) {
258
+ Object.assign(fields, options.additionalFields);
259
+ }
260
+ return this.makeRequest(() => this.client.put(`/issue/${issueKey}`, { fields }));
261
+ }
262
+ /**
263
+ * 사용자 검색
264
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-user-search/#api-rest-api-3-user-search-get
265
+ */
266
+ async searchUsers(options) {
267
+ const params = {};
268
+ if (options) {
269
+ const { query, accountId, startAt, maxResults, property } = options;
270
+ if (query)
271
+ params.query = query;
272
+ if (accountId)
273
+ params.accountId = accountId;
274
+ if (startAt !== undefined)
275
+ params.startAt = startAt;
276
+ if (maxResults !== undefined)
277
+ params.maxResults = maxResults;
278
+ if (property)
279
+ params.property = property;
280
+ }
281
+ return this.makeRequest(() => this.client.get("/user/search", { params }));
282
+ }
283
+ /**
284
+ * 사용자 선택 자동완성
285
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-user-search/#api-rest-api-3-user-picker-get
286
+ */
287
+ async getUserPicker(options) {
288
+ const params = {
289
+ query: options.query,
290
+ };
291
+ if (options.maxResults !== undefined)
292
+ params.maxResults = options.maxResults;
293
+ if (options.showAvatar !== undefined)
294
+ params.showAvatar = options.showAvatar;
295
+ if (options.exclude)
296
+ params.exclude = options.exclude;
297
+ if (options.excludeAccountIds)
298
+ params.excludeAccountIds = options.excludeAccountIds;
299
+ if (options.avatarSize)
300
+ params.avatarSize = options.avatarSize;
301
+ if (options.excludeConnectUsers !== undefined)
302
+ params.excludeConnectUsers = options.excludeConnectUsers;
303
+ return this.makeRequest(() => this.client.get("/user/picker", { params }));
304
+ }
305
+ /**
306
+ * 할당 가능한 사용자 검색
307
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-user-search/#api-rest-api-3-user-assignable-search-get
308
+ */
309
+ async searchAssignableUsers(options) {
310
+ const params = {};
311
+ if (options.projectKeys)
312
+ params.projectKeys = options.projectKeys.join(",");
313
+ if (options.query)
314
+ params.query = options.query;
315
+ if (options.username)
316
+ params.username = options.username;
317
+ if (options.accountId)
318
+ params.accountId = options.accountId;
319
+ if (options.startAt !== undefined)
320
+ params.startAt = options.startAt;
321
+ if (options.maxResults !== undefined)
322
+ params.maxResults = options.maxResults;
323
+ return this.makeRequest(() => this.client.get("/user/assignable/search", { params }));
324
+ }
325
+ /**
326
+ * 권한별 사용자 검색
327
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-user-search/#api-rest-api-3-user-permission-search-get
328
+ */
329
+ async searchUsersByPermission(options) {
330
+ const params = {
331
+ permissions: options.permissions,
332
+ };
333
+ if (options.projectKey)
334
+ params.projectKey = options.projectKey;
335
+ if (options.issueKey)
336
+ params.issueKey = options.issueKey;
337
+ if (options.query)
338
+ params.query = options.query;
339
+ if (options.username)
340
+ params.username = options.username;
341
+ if (options.accountId)
342
+ params.accountId = options.accountId;
343
+ if (options.startAt !== undefined)
344
+ params.startAt = options.startAt;
345
+ if (options.maxResults !== undefined)
346
+ params.maxResults = options.maxResults;
347
+ return this.makeRequest(() => this.client.get("/user/permission/search", { params }));
348
+ }
349
+ /**
350
+ * 현재 사용자 정보 조회
351
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-myself/#api-rest-api-3-myself-get
352
+ */
353
+ async getMyself(expand) {
354
+ const params = {};
355
+ if (expand) {
356
+ params.expand = expand.join(",");
357
+ }
358
+ return this.makeRequest(() => this.client.get("/myself", { params }));
359
+ }
360
+ /**
361
+ * 현재 사용자의 권한 조회
362
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-myself/#api-rest-api-3-mypermissions-get
363
+ */
364
+ async getMyPermissions(options) {
365
+ const params = {};
366
+ if (options) {
367
+ const { projectKey, projectId, issueKey, issueId, permissions, projectUuid, projectConfigurationUuid, commentId, } = options;
368
+ if (projectKey)
369
+ params.projectKey = projectKey;
370
+ if (projectId)
371
+ params.projectId = projectId;
372
+ if (issueKey)
373
+ params.issueKey = issueKey;
374
+ if (issueId)
375
+ params.issueId = issueId;
376
+ if (permissions)
377
+ params.permissions = permissions;
378
+ if (projectUuid)
379
+ params.projectUuid = projectUuid;
380
+ if (projectConfigurationUuid)
381
+ params.projectConfigurationUuid = projectConfigurationUuid;
382
+ if (commentId)
383
+ params.commentId = commentId;
384
+ }
385
+ return this.makeRequest(() => this.client.get("/mypermissions", { params }));
386
+ }
387
+ /**
388
+ * 현재 사용자 설정 업데이트
389
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-myself/#api-rest-api-3-myself-put
390
+ */
391
+ async updateMyself(options) {
392
+ const body = {};
393
+ if (options.emailAddress)
394
+ body.emailAddress = options.emailAddress;
395
+ if (options.displayName)
396
+ body.displayName = options.displayName;
397
+ if (options.timeZone)
398
+ body.timeZone = options.timeZone;
399
+ if (options.locale)
400
+ body.locale = options.locale;
401
+ return this.makeRequest(() => this.client.put("/myself", body));
402
+ }
403
+ /**
404
+ * 현재 사용자의 설정 값 조회
405
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-myself/#api-rest-api-3-mypreferences-get
406
+ */
407
+ async getMyPreferences(key) {
408
+ const params = {};
409
+ if (key) {
410
+ params.key = key;
411
+ }
412
+ return this.makeRequest(() => this.client.get("/mypreferences", { params }));
413
+ }
414
+ /**
415
+ * 현재 사용자의 설정 값 업데이트
416
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-myself/#api-rest-api-3-mypreferences-put
417
+ */
418
+ async updateMyPreferences(key, value) {
419
+ const params = { key };
420
+ return this.makeRequest(() => this.client.put("/mypreferences", value, { params }));
421
+ }
422
+ /**
423
+ * 현재 사용자의 로케일 조회
424
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-myself/#api-rest-api-3-mypreferences-locale-get
425
+ */
426
+ async getMyLocale() {
427
+ return this.makeRequest(() => this.client.get("/mypreferences/locale"));
428
+ }
429
+ /**
430
+ * 현재 사용자의 로케일 업데이트
431
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-myself/#api-rest-api-3-mypreferences-locale-put
432
+ */
433
+ async updateMyLocale(locale) {
434
+ return this.makeRequest(() => this.client.put("/mypreferences/locale", { locale }));
435
+ }
436
+ /**
437
+ * 모든 우선순위 조회
438
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-priorities/#api-rest-api-3-priority-get
439
+ */
440
+ async getPriorities() {
441
+ return this.makeRequest(() => this.client.get("/priority"));
442
+ }
443
+ /**
444
+ * 특정 우선순위 조회
445
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-priorities/#api-rest-api-3-priority-id-get
446
+ */
447
+ async getPriority(id) {
448
+ return this.makeRequest(() => this.client.get(`/priority/${id}`));
449
+ }
450
+ /**
451
+ * 우선순위 검색
452
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-priorities/#api-rest-api-3-priority-search-get
453
+ */
454
+ async searchPriorities(options) {
455
+ const params = {};
456
+ if (options) {
457
+ const { startAt, maxResults, id, projectId, priorityName, onlyDefault } = options;
458
+ if (startAt !== undefined)
459
+ params.startAt = startAt;
460
+ if (maxResults !== undefined)
461
+ params.maxResults = maxResults;
462
+ if (id)
463
+ params.id = id.join(",");
464
+ if (projectId)
465
+ params.projectId = projectId.join(",");
466
+ if (priorityName)
467
+ params.priorityName = priorityName;
468
+ if (onlyDefault !== undefined)
469
+ params.onlyDefault = onlyDefault;
470
+ }
471
+ return this.makeRequest(() => this.client.get("/priority/search", { params }));
472
+ }
473
+ /**
474
+ * 이슈의 가능한 전환 조회
475
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-get
476
+ */
477
+ async getIssueTransitions(issueKey, expand) {
478
+ const params = {};
479
+ if (expand) {
480
+ params.expand = expand.join(",");
481
+ }
482
+ return this.makeRequest(() => this.client.get(`/issue/${issueKey}/transitions`, { params }));
483
+ }
484
+ /**
485
+ * 이슈 상태 전환
486
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-post
487
+ */
488
+ async transitionIssue(issueKey, options) {
489
+ const body = {
490
+ transition: { id: options.transitionId },
491
+ };
492
+ if (options.comment) {
493
+ body.update = body.update || {};
494
+ body.update.comment = [
495
+ {
496
+ add: {
497
+ body: {
498
+ type: "doc",
499
+ version: 1,
500
+ content: [
501
+ {
502
+ type: "paragraph",
503
+ content: [
504
+ {
505
+ type: "text",
506
+ text: options.comment.body,
507
+ },
508
+ ],
509
+ },
510
+ ],
511
+ },
512
+ ...(options.comment.visibility && {
513
+ visibility: options.comment.visibility,
514
+ }),
515
+ },
516
+ },
517
+ ];
518
+ }
519
+ if (options.fields) {
520
+ body.fields = options.fields;
521
+ }
522
+ if (options.update) {
523
+ body.update = { ...body.update, ...options.update };
524
+ }
525
+ if (options.historyMetadata) {
526
+ body.historyMetadata = options.historyMetadata;
527
+ }
528
+ if (options.properties) {
529
+ body.properties = options.properties;
530
+ }
531
+ return this.makeRequest(() => this.client.post(`/issue/${issueKey}/transitions`, body));
532
+ }
533
+ /**
534
+ * 모든 상태 조회
535
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-workflow-statuses/#api-rest-api-3-status-get
536
+ */
537
+ async getStatuses() {
538
+ return this.makeRequest(() => this.client.get("/status"));
539
+ }
540
+ /**
541
+ * 특정 상태 조회
542
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-workflow-statuses/#api-rest-api-3-status-idorname-get
543
+ */
544
+ async getStatus(idOrName) {
545
+ return this.makeRequest(() => this.client.get(`/status/${idOrName}`));
546
+ }
547
+ /**
548
+ * 상태 검색
549
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-workflow-statuses/#api-rest-api-3-statuses-search-get
550
+ */
551
+ async searchStatuses(options) {
552
+ const params = {};
553
+ if (options) {
554
+ const { startAt, maxResults, searchString, projectId, expand } = options;
555
+ if (startAt !== undefined)
556
+ params.startAt = startAt;
557
+ if (maxResults !== undefined)
558
+ params.maxResults = maxResults;
559
+ if (searchString)
560
+ params.searchString = searchString;
561
+ if (projectId)
562
+ params.projectId = projectId;
563
+ if (expand)
564
+ params.expand = expand;
565
+ }
566
+ return this.makeRequest(() => this.client.get("/statuses/search", { params }));
567
+ }
568
+ /**
569
+ * 이슈에 댓글 추가
570
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-comments/#api-rest-api-3-issue-issueidorkey-comment-post
571
+ */
572
+ async createComment(issueKey, options) {
573
+ const body = {
574
+ body: {
575
+ type: "doc",
576
+ version: 1,
577
+ content: [
578
+ {
579
+ type: "paragraph",
580
+ content: [
581
+ {
582
+ type: "text",
583
+ text: options.body,
584
+ },
585
+ ],
586
+ },
587
+ ],
588
+ },
589
+ };
590
+ if (options.visibility) {
591
+ body.visibility = options.visibility;
592
+ }
593
+ if (options.properties) {
594
+ body.properties = options.properties;
595
+ }
596
+ return this.makeRequest(() => this.client.post(`/issue/${issueKey}/comment`, body));
597
+ }
598
+ /**
599
+ * 댓글 수정
600
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-comments/#api-rest-api-3-issue-issueidorkey-comment-id-put
601
+ */
602
+ async updateComment(issueKey, commentId, options) {
603
+ const body = {
604
+ body: {
605
+ type: "doc",
606
+ version: 1,
607
+ content: [
608
+ {
609
+ type: "paragraph",
610
+ content: [
611
+ {
612
+ type: "text",
613
+ text: options.body,
614
+ },
615
+ ],
616
+ },
617
+ ],
618
+ },
619
+ };
620
+ if (options.visibility) {
621
+ body.visibility = options.visibility;
622
+ }
623
+ if (options.properties) {
624
+ body.properties = options.properties;
625
+ }
626
+ return this.makeRequest(() => this.client.put(`/issue/${issueKey}/comment/${commentId}`, body));
627
+ }
628
+ /**
629
+ * 댓글 삭제
630
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-comments/#api-rest-api-3-issue-issueidorkey-comment-id-delete
631
+ */
632
+ async deleteComment(issueKey, commentId) {
633
+ return this.makeRequest(() => this.client.delete(`/issue/${issueKey}/comment/${commentId}`));
634
+ }
635
+ /**
636
+ * 이슈 삭제
637
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-delete
638
+ */
639
+ async deleteIssue(issueKey, deleteSubtasks) {
640
+ const params = {};
641
+ if (deleteSubtasks !== undefined) {
642
+ params.deleteSubtasks = deleteSubtasks;
643
+ }
644
+ return this.makeRequest(() => this.client.delete(`/issue/${issueKey}`, { params }));
645
+ }
646
+ /**
647
+ * 사용 가능한 이슈 링크 타입 조회
648
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-link-types/#api-rest-api-3-issuelinktype-get
649
+ */
650
+ async getIssueLinkTypes() {
651
+ return this.makeRequest(() => this.client.get("/issueLinkType"));
652
+ }
653
+ /**
654
+ * 특정 이슈 링크 타입 조회
655
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-link-types/#api-rest-api-3-issuelinktype-issuelinktypeid-get
656
+ */
657
+ async getIssueLinkType(issueLinkTypeId) {
658
+ return this.makeRequest(() => this.client.get(`/issueLinkType/${issueLinkTypeId}`));
659
+ }
660
+ /**
661
+ * 이슈 링크 생성
662
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-links/#api-rest-api-3-issuelink-post
663
+ */
664
+ async createIssueLink(options) {
665
+ const body = {
666
+ type: options.type,
667
+ inwardIssue: options.inwardIssue,
668
+ outwardIssue: options.outwardIssue,
669
+ };
670
+ if (options.comment) {
671
+ body.comment = {
672
+ body: {
673
+ type: "doc",
674
+ version: 1,
675
+ content: [
676
+ {
677
+ type: "paragraph",
678
+ content: [
679
+ {
680
+ type: "text",
681
+ text: options.comment.body,
682
+ },
683
+ ],
684
+ },
685
+ ],
686
+ },
687
+ ...(options.comment.visibility && {
688
+ visibility: options.comment.visibility,
689
+ }),
690
+ };
691
+ }
692
+ return this.makeRequest(() => this.client.post("/issueLink", body));
693
+ }
694
+ /**
695
+ * 이슈 링크 조회
696
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-links/#api-rest-api-3-issuelink-linkid-get
697
+ */
698
+ async getIssueLink(linkId) {
699
+ return this.makeRequest(() => this.client.get(`/issueLink/${linkId}`));
700
+ }
701
+ /**
702
+ * 이슈 링크 삭제
703
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-links/#api-rest-api-3-issuelink-linkid-delete
704
+ */
705
+ async deleteIssueLink(linkId) {
706
+ return this.makeRequest(() => this.client.delete(`/issueLink/${linkId}`));
707
+ }
708
+ /**
709
+ * 이슈의 모든 링크 조회 (이슈 조회 시 issuelinks 필드 포함)
710
+ */
711
+ async getIssueWithLinks(issueKey) {
712
+ return this.makeRequest(() => this.client.get(`/issue/${issueKey}`, {
713
+ params: { fields: "*all", expand: "issuelinks" },
714
+ }));
715
+ }
716
+ /**
717
+ * 이슈의 감시자 조회
718
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-watchers/#api-rest-api-3-issue-issueidorkey-watchers-get
719
+ */
720
+ async getIssueWatchers(issueKey) {
721
+ return this.makeRequest(() => this.client.get(`/issue/${issueKey}/watchers`));
722
+ }
723
+ /**
724
+ * 이슈에 감시자 추가
725
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-watchers/#api-rest-api-3-issue-issueidorkey-watchers-post
726
+ */
727
+ async addWatcher(issueKey, accountId) {
728
+ return this.makeRequest(() => this.client.post(`/issue/${issueKey}/watchers`, `"${accountId}"`, {
729
+ headers: {
730
+ "Content-Type": "application/json",
731
+ },
732
+ }));
733
+ }
734
+ /**
735
+ * 이슈에서 감시자 제거
736
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-watchers/#api-rest-api-3-issue-issueidorkey-watchers-delete
737
+ */
738
+ async removeWatcher(issueKey, accountId) {
739
+ return this.makeRequest(() => this.client.delete(`/issue/${issueKey}/watchers`, {
740
+ params: { accountId },
741
+ }));
742
+ }
743
+ /**
744
+ * 현재 사용자가 이슈 감시 시작
745
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-watchers/#api-rest-api-3-issue-issueidorkey-watchers-post
746
+ */
747
+ async watchIssue(issueKey) {
748
+ // 현재 사용자 정보 가져오기
749
+ const currentUser = await this.getMyself();
750
+ return this.addWatcher(issueKey, currentUser.accountId);
751
+ }
752
+ /**
753
+ * 현재 사용자가 이슈 감시 중단
754
+ * @see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-watchers/#api-rest-api-3-issue-issueidorkey-watchers-delete
755
+ */
756
+ async unwatchIssue(issueKey) {
757
+ // 현재 사용자 정보 가져오기
758
+ const currentUser = await this.getMyself();
759
+ return this.removeWatcher(issueKey, currentUser.accountId);
760
+ }
123
761
  }