jira-pilot 2.1.3 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/src/commands/bulk.js +10 -9
- package/dist/src/commands/bulk.js.map +1 -1
- package/dist/src/commands/dashboard.js +8 -7
- package/dist/src/commands/dashboard.js.map +1 -1
- package/dist/src/commands/issue.js +34 -38
- package/dist/src/commands/issue.js.map +1 -1
- package/dist/src/server/mcp-server.js +209 -27
- package/dist/src/server/mcp-server.js.map +1 -1
- package/dist/src/services/api-service.d.ts +1 -1
- package/dist/src/services/api-service.js +9 -6
- package/dist/src/services/api-service.js.map +1 -1
- package/dist/src/utils/api-paths.d.ts +31 -0
- package/dist/src/utils/api-paths.js +32 -0
- package/dist/src/utils/api-paths.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/bulk.ts +10 -9
- package/src/commands/dashboard.ts +9 -7
- package/src/commands/issue.ts +35 -38
- package/src/server/mcp-server.ts +234 -27
- package/src/services/api-service.ts +11 -6
- package/src/utils/api-paths.ts +32 -0
package/src/server/mcp-server.ts
CHANGED
|
@@ -1,18 +1,54 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CallToolRequestSchema,
|
|
5
|
+
ListToolsRequestSchema,
|
|
6
|
+
ListPromptsRequestSchema,
|
|
7
|
+
GetPromptRequestSchema,
|
|
8
|
+
ListResourceTemplatesRequestSchema,
|
|
9
|
+
ListResourcesRequestSchema,
|
|
10
|
+
ReadResourceRequestSchema,
|
|
11
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
4
12
|
import { api } from "../services/api-service.js";
|
|
5
13
|
import { textToADF } from "../utils/text-to-adf.js";
|
|
14
|
+
import { readFileSync, existsSync } from "fs";
|
|
15
|
+
import { join, dirname } from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
import { API } from "../utils/api-paths.js";
|
|
18
|
+
|
|
19
|
+
// Load package.json for version
|
|
20
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
|
|
22
|
+
function getPackageVersion() {
|
|
23
|
+
const candidates = [
|
|
24
|
+
join(__dirname, "../../package.json"),
|
|
25
|
+
join(__dirname, "../../../package.json"),
|
|
26
|
+
join(process.cwd(), "package.json"),
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
for (const p of candidates) {
|
|
30
|
+
if (!existsSync(p)) continue;
|
|
31
|
+
try {
|
|
32
|
+
const pkg = JSON.parse(readFileSync(p, "utf-8"));
|
|
33
|
+
if (typeof pkg.version === "string" && pkg.version) return pkg.version;
|
|
34
|
+
} catch { /* ignore */ }
|
|
35
|
+
}
|
|
36
|
+
return "0.0.0";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const version = getPackageVersion();
|
|
6
40
|
|
|
7
41
|
// Initialize MCP Server
|
|
8
42
|
const server = new Server(
|
|
9
43
|
{
|
|
10
44
|
name: "jira-pilot",
|
|
11
|
-
version:
|
|
45
|
+
version: version,
|
|
12
46
|
},
|
|
13
47
|
{
|
|
14
48
|
capabilities: {
|
|
15
49
|
tools: {},
|
|
50
|
+
prompts: { listChanged: true },
|
|
51
|
+
resources: { subscribe: false, listChanged: true },
|
|
16
52
|
},
|
|
17
53
|
}
|
|
18
54
|
);
|
|
@@ -200,6 +236,175 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
200
236
|
};
|
|
201
237
|
});
|
|
202
238
|
|
|
239
|
+
// ── Prompt Definitions ────────────────────────────────────────────────
|
|
240
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
241
|
+
return {
|
|
242
|
+
prompts: [
|
|
243
|
+
{
|
|
244
|
+
name: "jira-assist",
|
|
245
|
+
description: "A system prompt to help the LLM understand how to assist with Jira tasks.",
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "jira-summarize-issue",
|
|
249
|
+
description: "Summarize a specific Jira issue.",
|
|
250
|
+
arguments: [
|
|
251
|
+
{
|
|
252
|
+
name: "issueKey",
|
|
253
|
+
description: "The key of the issue to summarize (e.g., PROJ-123)",
|
|
254
|
+
required: true
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
263
|
+
const { name, arguments: args } = request.params;
|
|
264
|
+
|
|
265
|
+
if (name === "jira-assist") {
|
|
266
|
+
return {
|
|
267
|
+
messages: [
|
|
268
|
+
{
|
|
269
|
+
role: "user",
|
|
270
|
+
content: {
|
|
271
|
+
type: "text",
|
|
272
|
+
text: `You are Jira Pilot, an intelligent assistant for Jira.
|
|
273
|
+
Your goal is to help users manage their projects, issues, and workflows efficiently.
|
|
274
|
+
|
|
275
|
+
Available Tools:
|
|
276
|
+
- Use 'jira_list_issues' to find issues.
|
|
277
|
+
- Use 'jira_get_issue' to see details.
|
|
278
|
+
- Use 'jira_create_issue', 'jira_update_issue', 'jira_transition_issue' to modify.
|
|
279
|
+
|
|
280
|
+
Guidelines:
|
|
281
|
+
1. Always be concise and helpful.
|
|
282
|
+
2. If the user asks to "fix" something, look for relevant issues first.
|
|
283
|
+
3. When creating issues, ask for clarification if fields are missing (Project, Type).
|
|
284
|
+
4. Use JQL for powerful searching.`
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
]
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (name === "jira-summarize-issue") {
|
|
292
|
+
const issueKey = args?.issueKey;
|
|
293
|
+
if (!issueKey) {
|
|
294
|
+
throw new Error("Missing required argument: issueKey");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
messages: [
|
|
299
|
+
{
|
|
300
|
+
role: "user",
|
|
301
|
+
content: {
|
|
302
|
+
type: "text",
|
|
303
|
+
text: `Please fetch details for Jira issue ${issueKey} using 'jira_get_issue', and then provide a concise summary of its status, priority, and recent activity.`
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
]
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
throw new Error(`Prompt not found: ${name}. Available: jira-assist, jira-summarize-issue`);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// ── Resource Templates ──────────────────────────────────────────────
|
|
314
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
|
|
315
|
+
return {
|
|
316
|
+
resourceTemplates: []
|
|
317
|
+
};
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ── Resource Definitions ──────────────────────────────────────────────
|
|
321
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
322
|
+
return {
|
|
323
|
+
resources: [
|
|
324
|
+
{
|
|
325
|
+
uri: "jira://myself",
|
|
326
|
+
name: "My Profile",
|
|
327
|
+
description: "Details of the currently authenticated user.",
|
|
328
|
+
mimeType: "application/json"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
uri: "jira://projects",
|
|
332
|
+
name: "All Projects",
|
|
333
|
+
description: "List of all accessible Jira projects.",
|
|
334
|
+
mimeType: "application/json"
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
};
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
341
|
+
const { uri } = request.params;
|
|
342
|
+
|
|
343
|
+
const createEnvelope = (type: string, data: any) => ({
|
|
344
|
+
source: "jira-pilot",
|
|
345
|
+
type,
|
|
346
|
+
data,
|
|
347
|
+
fetchedAt: new Date().toISOString()
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
try {
|
|
351
|
+
if (uri === "jira://myself") {
|
|
352
|
+
const myself = await api.get(API.USER.MYSELF);
|
|
353
|
+
// Mask sensitive data if needed, though 'myself' usually implies permission to see own data.
|
|
354
|
+
// keeping it simple for now, but ensuring consistent shape.
|
|
355
|
+
const safeData = {
|
|
356
|
+
accountId: myself.accountId,
|
|
357
|
+
displayName: myself.displayName,
|
|
358
|
+
active: myself.active,
|
|
359
|
+
timeZone: myself.timeZone,
|
|
360
|
+
// Only include email if present, or maybe mask it? User asked to be careful.
|
|
361
|
+
// We'll exclude email to be safe as per user request "do not include email".
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
contents: [{
|
|
366
|
+
uri,
|
|
367
|
+
mimeType: "application/json",
|
|
368
|
+
text: JSON.stringify(createEnvelope("myself", safeData), null, 2)
|
|
369
|
+
}]
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (uri === "jira://projects") {
|
|
374
|
+
const data = await api.get(`${API.PROJECT.SEARCH}?maxResults=50`);
|
|
375
|
+
const projects = (data.values || []).map((p: any) => ({
|
|
376
|
+
key: p.key,
|
|
377
|
+
name: p.name,
|
|
378
|
+
id: p.id,
|
|
379
|
+
style: p.style
|
|
380
|
+
}));
|
|
381
|
+
|
|
382
|
+
return {
|
|
383
|
+
contents: [{
|
|
384
|
+
uri,
|
|
385
|
+
mimeType: "application/json",
|
|
386
|
+
text: JSON.stringify(createEnvelope("projects", projects), null, 2)
|
|
387
|
+
}]
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
throw new Error(`Resource not found: ${uri}. Available: jira://myself, jira://projects`);
|
|
392
|
+
|
|
393
|
+
} catch (e: any) {
|
|
394
|
+
// Handle Auth/Network errors specifically
|
|
395
|
+
if (e.response?.status === 401 || e.response?.status === 403) {
|
|
396
|
+
throw new Error(`Jira auth is missing or expired. Run 'jira config setup' to authenticate.`);
|
|
397
|
+
}
|
|
398
|
+
if (e.message.includes("Resource not found")) {
|
|
399
|
+
throw e; // Re-throw 404s we generated
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Upstream errors
|
|
403
|
+
const status = e.response?.status || "Unknown";
|
|
404
|
+
throw new Error(`Upstream Jira error (${status}): ${e.message}`);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
|
|
203
408
|
// ── Tool Handlers ────────────────────────────────────────────────────
|
|
204
409
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
205
410
|
const { name, arguments: args } = request.params as { name: string; arguments: any };
|
|
@@ -209,7 +414,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
209
414
|
if (name === "jira_list_issues") {
|
|
210
415
|
const jql = args.jql || "";
|
|
211
416
|
const limit = args.limit || 10;
|
|
212
|
-
const data = await api.post(
|
|
417
|
+
const data = await api.post(API.SEARCH.JQL, {
|
|
213
418
|
jql,
|
|
214
419
|
maxResults: limit,
|
|
215
420
|
fields: ['summary', 'status', 'assignee', 'priority', 'created', 'updated']
|
|
@@ -233,7 +438,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
233
438
|
|
|
234
439
|
// ── jira_get_issue ──────────────────────────────────
|
|
235
440
|
if (name === "jira_get_issue") {
|
|
236
|
-
const data = await api.get(
|
|
441
|
+
const data = await api.get(API.ISSUE.GET(args.issueKey));
|
|
237
442
|
|
|
238
443
|
// Return a cleaner summary for agents
|
|
239
444
|
const result = {
|
|
@@ -284,7 +489,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
284
489
|
body.fields.assignee = { accountId: args.assigneeId };
|
|
285
490
|
}
|
|
286
491
|
|
|
287
|
-
const data = await api.post(
|
|
492
|
+
const data = await api.post(API.ISSUE.BASE, body);
|
|
288
493
|
return {
|
|
289
494
|
content: [{ type: "text", text: JSON.stringify({ key: data.key, self: data.self }, null, 2) }]
|
|
290
495
|
};
|
|
@@ -294,8 +499,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
294
499
|
if (name === "jira_transition_issue") {
|
|
295
500
|
if (!args.transitionId) {
|
|
296
501
|
// List available transitions
|
|
297
|
-
const transData = await api.get(
|
|
298
|
-
const issue = await api.get(
|
|
502
|
+
const transData = await api.get(API.ISSUE.TRANSITIONS(args.issueKey));
|
|
503
|
+
const issue = await api.get(`${API.ISSUE.GET(args.issueKey)}?fields=summary,status`);
|
|
299
504
|
|
|
300
505
|
const result = {
|
|
301
506
|
issueKey: args.issueKey,
|
|
@@ -314,7 +519,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
314
519
|
}
|
|
315
520
|
|
|
316
521
|
// Execute transition
|
|
317
|
-
await api.post(
|
|
522
|
+
await api.post(API.ISSUE.TRANSITIONS(args.issueKey), {
|
|
318
523
|
transition: { id: args.transitionId }
|
|
319
524
|
});
|
|
320
525
|
|
|
@@ -329,11 +534,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
329
534
|
|
|
330
535
|
// Resolve "me" to actual account ID
|
|
331
536
|
if (accountId === 'me') {
|
|
332
|
-
const myself = await api.get(
|
|
537
|
+
const myself = await api.get(API.USER.MYSELF);
|
|
333
538
|
accountId = myself.accountId;
|
|
334
539
|
}
|
|
335
540
|
|
|
336
|
-
await api.put(
|
|
541
|
+
await api.put(API.ISSUE.ASSIGNEE(args.issueKey), {
|
|
337
542
|
accountId: accountId || null
|
|
338
543
|
});
|
|
339
544
|
|
|
@@ -344,7 +549,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
344
549
|
|
|
345
550
|
// ── jira_add_comment ────────────────────────────────
|
|
346
551
|
if (name === "jira_add_comment") {
|
|
347
|
-
const data = await api.post(
|
|
552
|
+
const data = await api.post(API.ISSUE.COMMENT(args.issueKey), {
|
|
348
553
|
body: textToADF(args.body)
|
|
349
554
|
});
|
|
350
555
|
|
|
@@ -364,7 +569,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
364
569
|
if (args.assigneeId) {
|
|
365
570
|
let accId = args.assigneeId;
|
|
366
571
|
if (accId === 'me') {
|
|
367
|
-
const myself = await api.get(
|
|
572
|
+
const myself = await api.get(API.USER.MYSELF);
|
|
368
573
|
accId = myself.accountId;
|
|
369
574
|
} else if (accId === 'none') {
|
|
370
575
|
accId = null;
|
|
@@ -379,7 +584,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
379
584
|
};
|
|
380
585
|
}
|
|
381
586
|
|
|
382
|
-
await api.put(
|
|
587
|
+
await api.put(API.ISSUE.GET(args.issueKey), updateBody);
|
|
383
588
|
|
|
384
589
|
return {
|
|
385
590
|
content: [{ type: "text", text: JSON.stringify({ success: true, issueKey: args.issueKey }) }]
|
|
@@ -388,12 +593,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
388
593
|
|
|
389
594
|
// ── jira_search_users ───────────────────────────────
|
|
390
595
|
if (name === "jira_search_users") {
|
|
391
|
-
const users = await api.get(
|
|
596
|
+
const users = await api.get(`${API.USER.SEARCH}?query=${encodeURIComponent(args.query)}`);
|
|
392
597
|
|
|
393
598
|
const results = (users || []).map((u: any) => ({
|
|
394
599
|
accountId: u.accountId,
|
|
395
600
|
displayName: u.displayName,
|
|
396
|
-
|
|
601
|
+
// Email excluded for safety
|
|
602
|
+
// email: u.emailAddress,
|
|
397
603
|
active: u.active
|
|
398
604
|
}));
|
|
399
605
|
|
|
@@ -404,11 +610,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
404
610
|
|
|
405
611
|
// ── jira_myself ─────────────────────────────────────
|
|
406
612
|
if (name === "jira_myself") {
|
|
407
|
-
const myself = await api.get(
|
|
613
|
+
const myself = await api.get(API.USER.MYSELF);
|
|
408
614
|
const result = {
|
|
409
615
|
accountId: myself.accountId,
|
|
410
616
|
displayName: myself.displayName,
|
|
411
|
-
|
|
617
|
+
// Email excluded for safety
|
|
618
|
+
// email: myself.emailAddress,
|
|
412
619
|
active: myself.active,
|
|
413
620
|
timeZone: myself.timeZone
|
|
414
621
|
};
|
|
@@ -421,7 +628,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
421
628
|
// ── jira_list_projects ──────────────────────────────
|
|
422
629
|
if (name === "jira_list_projects") {
|
|
423
630
|
const limit = args.limit || 50;
|
|
424
|
-
const data = await api.get(
|
|
631
|
+
const data = await api.get(`${API.PROJECT.SEARCH}?maxResults=${limit}`);
|
|
425
632
|
|
|
426
633
|
const projects = (data.values || []).map((p: any) => ({
|
|
427
634
|
key: p.key,
|
|
@@ -464,7 +671,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
464
671
|
body.comment = textToADF(args.comment);
|
|
465
672
|
}
|
|
466
673
|
|
|
467
|
-
await api.post(
|
|
674
|
+
await api.post(API.ISSUE.WORKLOG(args.issueKey), body);
|
|
468
675
|
|
|
469
676
|
return {
|
|
470
677
|
content: [{ type: "text", text: JSON.stringify({ success: true, issueKey: args.issueKey, timeSpent: args.timeSpent }) }]
|
|
@@ -474,7 +681,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
474
681
|
// ── jira_create_subtask ─────────────────────────────
|
|
475
682
|
if (name === "jira_create_subtask") {
|
|
476
683
|
// 1. Fetch parent to get project
|
|
477
|
-
const parent = await api.get(
|
|
684
|
+
const parent = await api.get(`${API.ISSUE.GET(args.parentKey)}?fields=project`);
|
|
478
685
|
const projectKey = parent.fields.project.key;
|
|
479
686
|
|
|
480
687
|
// 2. Find subtask issue type
|
|
@@ -504,13 +711,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
504
711
|
if (args.assigneeId) {
|
|
505
712
|
let accId = args.assigneeId;
|
|
506
713
|
if (accId === 'me') {
|
|
507
|
-
const myself = await api.get(
|
|
714
|
+
const myself = await api.get(API.USER.MYSELF);
|
|
508
715
|
accId = myself.accountId;
|
|
509
716
|
}
|
|
510
717
|
body.fields.assignee = { accountId: accId };
|
|
511
718
|
}
|
|
512
719
|
|
|
513
|
-
const data = await api.post(
|
|
720
|
+
const data = await api.post(API.ISSUE.BASE, body);
|
|
514
721
|
return {
|
|
515
722
|
content: [{ type: "text", text: JSON.stringify({ key: data.key, self: data.self }, null, 2) }]
|
|
516
723
|
};
|
|
@@ -520,15 +727,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
520
727
|
if (name === "jira_add_attachment") {
|
|
521
728
|
try {
|
|
522
729
|
// Dynamically import fs/path to avoid top-level node dependencies if this runs in browser-like env (unlikely but safe)
|
|
523
|
-
const
|
|
524
|
-
const path = await import(
|
|
730
|
+
const fs = await import("node:fs");
|
|
731
|
+
const path = await import("node:path");
|
|
525
732
|
|
|
526
733
|
const filePath = args.filePath;
|
|
527
|
-
const file = await openAsBlob(filePath);
|
|
734
|
+
const file = await fs.openAsBlob(filePath);
|
|
528
735
|
const formData = new FormData();
|
|
529
|
-
formData.append(
|
|
736
|
+
formData.append("file", file, path.basename(filePath));
|
|
530
737
|
|
|
531
|
-
const result = await api.upload(
|
|
738
|
+
const result = await api.upload(API.ISSUE.ATTACHMENTS(args.issueKey), formData);
|
|
532
739
|
|
|
533
740
|
return {
|
|
534
741
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HttpClient } from '../utils/http.js';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { getCredentials } from '../utils/config.js';
|
|
4
|
+
import { API } from '../utils/api-paths.js';
|
|
4
5
|
|
|
5
6
|
export class ApiService {
|
|
6
7
|
private client: any;
|
|
@@ -101,14 +102,18 @@ export class ApiService {
|
|
|
101
102
|
return response.data;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
async search(jql: string, startAt: number = 0, maxResults: number = 50) {
|
|
105
|
-
|
|
105
|
+
async search(jql: string, startAt: number = 0, maxResults: number = 50, nextPageToken?: string) {
|
|
106
|
+
const payload: any = {
|
|
106
107
|
jql,
|
|
107
|
-
startAt,
|
|
108
108
|
maxResults,
|
|
109
|
-
fields: ['summary', 'status', 'assignee', 'priority', 'issuetype', 'created', 'updated', 'project']
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
fields: ['summary', 'status', 'assignee', 'priority', 'issuetype', 'created', 'updated', 'project']
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (nextPageToken) {
|
|
113
|
+
payload.nextPageToken = nextPageToken;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return this.post(API.SEARCH.JQL, payload);
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
async upload(url: string, formData: any) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
export const API = {
|
|
3
|
+
SEARCH: {
|
|
4
|
+
JQL: '/search/jql',
|
|
5
|
+
},
|
|
6
|
+
ISSUE: {
|
|
7
|
+
BASE: '/issue',
|
|
8
|
+
GET: (key: string) => `/issue/${key}`,
|
|
9
|
+
TRANSITIONS: (key: string) => `/issue/${key}/transitions`,
|
|
10
|
+
COMMENT: (key: string) => `/issue/${key}/comment`,
|
|
11
|
+
ASSIGNEE: (key: string) => `/issue/${key}/assignee`,
|
|
12
|
+
WORKLOG: (key: string) => `/issue/${key}/worklog`,
|
|
13
|
+
ATTACHMENTS: (key: string) => `/issue/${key}/attachments`,
|
|
14
|
+
CREATEMETA: (projectKey: string) => `/issue/createmeta/${projectKey}/issuetypes`,
|
|
15
|
+
},
|
|
16
|
+
PROJECT: {
|
|
17
|
+
SEARCH: '/project/search',
|
|
18
|
+
GET: (key: string) => `/project/${key}`,
|
|
19
|
+
COMPONENTS: (key: string) => `/project/${key}/components`,
|
|
20
|
+
VERSIONS: (key: string) => `/project/${key}/versions`,
|
|
21
|
+
},
|
|
22
|
+
USER: {
|
|
23
|
+
MYSELF: '/myself',
|
|
24
|
+
SEARCH: '/user/search',
|
|
25
|
+
},
|
|
26
|
+
PRIORITY: {
|
|
27
|
+
ALL: '/priority',
|
|
28
|
+
},
|
|
29
|
+
SERVER: {
|
|
30
|
+
INFO: '/serverInfo',
|
|
31
|
+
}
|
|
32
|
+
};
|