targetprocess-mcp-server 2.6.0 → 2.6.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.
- package/build/handlers/delete_card.js +19 -0
- package/build/handlers/get_team_iterations.js +30 -0
- package/build/index.js +70 -12
- package/build/tp.js +52 -9
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export async function handleDeleteCard(tp, params) {
|
|
2
|
+
const result = await tp.deleteCard(params);
|
|
3
|
+
if (!result.ok) {
|
|
4
|
+
return {
|
|
5
|
+
content: [{
|
|
6
|
+
type: 'text',
|
|
7
|
+
text: `Failed to delete ${params.type} id: ${params.id}\n` +
|
|
8
|
+
`HTTP status: ${result.status}\n` +
|
|
9
|
+
`Response body: ${result.body}`
|
|
10
|
+
}],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
content: [{
|
|
15
|
+
type: 'text',
|
|
16
|
+
text: JSON.stringify({ deleted: true, id: Number(params.id), type: params.type, card: result.data })
|
|
17
|
+
}],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export async function handleGetTeamIterations(tp, params) {
|
|
2
|
+
const response = await tp.getTeamIterations(params);
|
|
3
|
+
if (!response) {
|
|
4
|
+
return {
|
|
5
|
+
content: [{
|
|
6
|
+
type: 'text',
|
|
7
|
+
text: `Failed to get team iterations, JSON: ${JSON.stringify(response, null, 2)}`
|
|
8
|
+
}],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const items = response.Items || [];
|
|
12
|
+
if (items.length === 0) {
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: 'No team iterations found' }],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
content: [{
|
|
19
|
+
type: 'text',
|
|
20
|
+
text: JSON.stringify(items.map((i) => ({
|
|
21
|
+
id: i.Id,
|
|
22
|
+
name: i.Name,
|
|
23
|
+
startDate: i.StartDate,
|
|
24
|
+
endDate: i.EndDate,
|
|
25
|
+
teamId: i.Team?.Id,
|
|
26
|
+
teamName: i.Team?.Name,
|
|
27
|
+
}))),
|
|
28
|
+
}],
|
|
29
|
+
};
|
|
30
|
+
}
|
package/build/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import { handleGetReleaseOpenBugs } from "./handlers/get_release_open_bugs.js";
|
|
|
20
20
|
import { handleGetReleaseOpenUserStories } from "./handlers/get_release_open_user_stories.js";
|
|
21
21
|
import { handleGetUsers } from "./handlers/get_users.js";
|
|
22
22
|
import { handleGetTeams, handleGetTeamsAndTeamAssignments } from "./handlers/get_teams.js";
|
|
23
|
+
import { handleGetTeamIterations } from "./handlers/get_team_iterations.js";
|
|
23
24
|
import { handleAddComment } from "./handlers/add_comment.js";
|
|
24
25
|
import { handleGetUserStoryComments } from "./handlers/get_user_story_comments.js";
|
|
25
26
|
import { handleGetBugComments } from "./handlers/get_bug_comments.js";
|
|
@@ -44,6 +45,7 @@ import { handleUpdateUserStorySubState } from "./handlers/update_user_story_sub_
|
|
|
44
45
|
import { handleGetCardRelations } from "./handlers/get_card_relations.js";
|
|
45
46
|
import { handleCreateCardRelation } from "./handlers/create_card_relation.js";
|
|
46
47
|
import { handleDeleteCardRelation } from "./handlers/delete_card_relation.js";
|
|
48
|
+
import { handleDeleteCard } from "./handlers/delete_card.js";
|
|
47
49
|
import { handleGetTestPlanById } from "./handlers/get_test_plan_by_id.js";
|
|
48
50
|
import { handleGetTestPlanTestCasesById } from "./handlers/get_test_plan_test_cases_by_id.js";
|
|
49
51
|
import { handleGetTestPlanTestCasesWithStepsById } from "./handlers/get_test_plan_test_cases_with_steps_by_id.js";
|
|
@@ -409,7 +411,8 @@ server.registerTool('update_bug', {
|
|
|
409
411
|
CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
|
|
410
412
|
1) IF the user specified a team by name (not ID), call "get_teams" to find the matching team and use its ID as teamId;
|
|
411
413
|
2) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId;
|
|
412
|
-
3) IF the user specified a state by name (not ID), call "get_bug_workflows" to find the matching state and use its ID as entityStateId
|
|
414
|
+
3) IF the user specified a state by name (not ID), call "get_bug_workflows" to find the matching state and use its ID as entityStateId;
|
|
415
|
+
4) IF the user specified a sprint/iteration by name, call "get_team_iterations" to find the matching iteration and use its ID as teamIterationId;`,
|
|
413
416
|
inputSchema: {
|
|
414
417
|
id: z.string()
|
|
415
418
|
.min(5)
|
|
@@ -443,8 +446,14 @@ server.registerTool('update_bug', {
|
|
|
443
446
|
entityStateId: z.string()
|
|
444
447
|
.optional()
|
|
445
448
|
.describe('Optional Entity State ID — if user gave a state name, resolve it via "get_bug_workflows" first; defaults to "Done"'),
|
|
449
|
+
tags: z.string()
|
|
450
|
+
.optional()
|
|
451
|
+
.describe('Optional comma-separated tags to apply, e.g. "regression, mobile"'),
|
|
452
|
+
teamIterationId: z.string()
|
|
453
|
+
.optional()
|
|
454
|
+
.describe('Optional Team Iteration (sprint) ID — resolve it via "get_team_iterations" first'),
|
|
446
455
|
},
|
|
447
|
-
}, async ({ id, title, bugContent, origin, projectId, teamId, entityStateId }) => handleUpdateBug(tp, { id, title, bugContent, origin, projectId, teamId, entityStateId }));
|
|
456
|
+
}, async ({ id, title, bugContent, origin, projectId, teamId, entityStateId, tags, teamIterationId }) => handleUpdateBug(tp, { id, title, bugContent, origin, projectId, teamId, entityStateId, tags, teamIterationId }));
|
|
448
457
|
server.registerTool('update_user_story_state', {
|
|
449
458
|
title: 'Update a user story card sub state',
|
|
450
459
|
description: `Update a user story card sub state with data provided from user input.
|
|
@@ -474,7 +483,8 @@ server.registerTool('update_user_story', {
|
|
|
474
483
|
CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
|
|
475
484
|
1) IF the user specified a team by name (not ID), call "get_teams" to find the matching team and use its ID as teamId;
|
|
476
485
|
2) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId;
|
|
477
|
-
3) IF the user specified a state by name (not ID), call "get_user_story_workflows" to find the matching state and use its ID as entityStateId
|
|
486
|
+
3) IF the user specified a state by name (not ID), call "get_user_story_workflows" to find the matching state and use its ID as entityStateId;
|
|
487
|
+
4) IF the user specified a sprint/iteration by name, call "get_team_iterations" to find the matching iteration and use its ID as teamIterationId;`,
|
|
478
488
|
inputSchema: {
|
|
479
489
|
id: z.string()
|
|
480
490
|
.min(5)
|
|
@@ -498,9 +508,15 @@ server.registerTool('update_user_story', {
|
|
|
498
508
|
featureId: z.string()
|
|
499
509
|
.optional()
|
|
500
510
|
.describe('Optional Feature ID — moves this user story to the specified feature'),
|
|
511
|
+
tags: z.string()
|
|
512
|
+
.optional()
|
|
513
|
+
.describe('Optional comma-separated tags to apply, e.g. "regression, mobile"'),
|
|
514
|
+
teamIterationId: z.string()
|
|
515
|
+
.optional()
|
|
516
|
+
.describe('Optional Team Iteration (sprint) ID — resolve it via "get_team_iterations" first'),
|
|
501
517
|
},
|
|
502
|
-
}, async ({ id, title, description, projectId, teamId, entityStateId, featureId }) => {
|
|
503
|
-
const response = await tp.updateUserStory({ id, title, description, projectId, teamId, entityStateId, featureId });
|
|
518
|
+
}, async ({ id, title, description, projectId, teamId, entityStateId, featureId, tags, teamIterationId }) => {
|
|
519
|
+
const response = await tp.updateUserStory({ id, title, description, projectId, teamId, entityStateId, featureId, tags, teamIterationId });
|
|
504
520
|
if (!response) {
|
|
505
521
|
return {
|
|
506
522
|
content: [{
|
|
@@ -523,7 +539,8 @@ server.registerTool('create_bug', {
|
|
|
523
539
|
CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
|
|
524
540
|
1) format the new bug inside html <div> tags with Environment(describes where bug was found, dev, feature, review or uat Environment), Issue Description, Steps to Reproduce, Expected Behavior, Actual Behavior and Attachments sections (note: section titles should be wrapped in <h3> tags, e.g. <h3>Issue Description</h3>, step to reproduce should be wrapped in <ol>);
|
|
525
541
|
2) IF the user specified a team by name (not ID), call "get_teams" to find the matching team and use its ID as teamId;
|
|
526
|
-
3) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId
|
|
542
|
+
3) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId;
|
|
543
|
+
4) IF the user specified a sprint/iteration by name, call "get_team_iterations" to find the matching iteration and use its ID as teamIterationId;`,
|
|
527
544
|
inputSchema: {
|
|
528
545
|
title: z.string()
|
|
529
546
|
.describe('Bug card title that summarizes the problem in concise, descriptive, and actionable manner, enabling a developer to understand the issue without opening the report'),
|
|
@@ -552,11 +569,18 @@ server.registerTool('create_bug', {
|
|
|
552
569
|
entityStateId: z.string()
|
|
553
570
|
.optional()
|
|
554
571
|
.describe('Optional Entity State ID — if user gave a state name, resolve it via "get_bug_workflows" first; defaults to "Done"'),
|
|
572
|
+
tags: z.string()
|
|
573
|
+
.optional()
|
|
574
|
+
.describe('Optional comma-separated tags to apply, e.g. "regression, mobile"'),
|
|
575
|
+
teamIterationId: z.string()
|
|
576
|
+
.optional()
|
|
577
|
+
.describe('Optional Team Iteration (sprint) ID — resolve it via "get_team_iterations" first'),
|
|
555
578
|
},
|
|
556
|
-
}, async ({ title, bugContent, origin, projectId, teamId, entityStateId }) => handleCreateBug(tp, { title, bugContent, origin, projectId, teamId, entityStateId }));
|
|
579
|
+
}, async ({ title, bugContent, origin, projectId, teamId, entityStateId, tags, teamIterationId }) => handleCreateBug(tp, { title, bugContent, origin, projectId, teamId, entityStateId, tags, teamIterationId }));
|
|
557
580
|
server.registerTool('create_user_story', {
|
|
558
581
|
title: 'Create a new user story',
|
|
559
|
-
description: `Create a new user story in Targetprocess
|
|
582
|
+
description: `Create a new user story in Targetprocess.
|
|
583
|
+
CRITICAL WORKFLOW: Before calling this tool, IF the user specified a sprint/iteration by name, call "get_team_iterations" to find the matching iteration and use its ID as teamIterationId.`,
|
|
560
584
|
inputSchema: {
|
|
561
585
|
title: z.string()
|
|
562
586
|
.describe('User story title'),
|
|
@@ -579,8 +603,14 @@ server.registerTool('create_user_story', {
|
|
|
579
603
|
teamId: z.string()
|
|
580
604
|
.optional()
|
|
581
605
|
.describe('Optional Team ID — defaults to TP_TEAM_ID from config'),
|
|
606
|
+
tags: z.string()
|
|
607
|
+
.optional()
|
|
608
|
+
.describe('Optional comma-separated tags to apply, e.g. "regression, mobile"'),
|
|
609
|
+
teamIterationId: z.string()
|
|
610
|
+
.optional()
|
|
611
|
+
.describe('Optional Team Iteration (sprint) ID — resolve it via "get_team_iterations" first'),
|
|
582
612
|
},
|
|
583
|
-
}, async ({ title, description, featureId, releaseId, projectId, teamId }) => handleCreateUserStory(tp, { title, description, featureId, releaseId, projectId, teamId }));
|
|
613
|
+
}, async ({ title, description, featureId, releaseId, projectId, teamId, tags, teamIterationId }) => handleCreateUserStory(tp, { title, description, featureId, releaseId, projectId, teamId, tags, teamIterationId }));
|
|
584
614
|
server.registerTool('create_formatted_user_story', {
|
|
585
615
|
title: 'Create a formatted user story',
|
|
586
616
|
description: `Create a new user story in Targetprocess with a structured, template-driven description.
|
|
@@ -589,7 +619,8 @@ server.registerTool('create_formatted_user_story', {
|
|
|
589
619
|
1) IF the user specified a feature by name (not ID), call "get_feature_user_stories" or "search_tp_cards" to resolve the feature ID;
|
|
590
620
|
2) IF the user specified a release by name (not ID), call "get_current_releases" to resolve the release ID;
|
|
591
621
|
3) IF the user specified a team by name (not ID), call "get_teams" to find the matching team and use its ID as teamId;
|
|
592
|
-
4) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId
|
|
622
|
+
4) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId;
|
|
623
|
+
5) IF the user specified a sprint/iteration by name, call "get_team_iterations" to find the matching iteration and use its ID as teamIterationId;`,
|
|
593
624
|
inputSchema: {
|
|
594
625
|
title: z.string()
|
|
595
626
|
.describe('User story title'),
|
|
@@ -657,8 +688,14 @@ server.registerTool('create_formatted_user_story', {
|
|
|
657
688
|
teamId: z.string()
|
|
658
689
|
.optional()
|
|
659
690
|
.describe('Optional Team ID — defaults to TP_TEAM_ID from config'),
|
|
691
|
+
tags: z.string()
|
|
692
|
+
.optional()
|
|
693
|
+
.describe('Optional comma-separated tags to apply, e.g. "regression, mobile"'),
|
|
694
|
+
teamIterationId: z.string()
|
|
695
|
+
.optional()
|
|
696
|
+
.describe('Optional Team Iteration (sprint) ID — resolve it via "get_team_iterations" first'),
|
|
660
697
|
},
|
|
661
|
-
}, async ({ title, header, definitions, acceptanceCriteria, scenarios, examplesTable, edgeCases, references, notes, featureId, releaseId, projectId, teamId }) => {
|
|
698
|
+
}, async ({ title, header, definitions, acceptanceCriteria, scenarios, examplesTable, edgeCases, references, notes, featureId, releaseId, projectId, teamId, tags, teamIterationId }) => {
|
|
662
699
|
const gherkinBlock = (items) => items.map((s, indx) => `<div><strong>Scenario ${indx + 1} - ${s.name}:</strong></div><div>${s.steps.map(step => `<div>\t${step}</div>`).join('\n')}</div>`).join('<br>');
|
|
663
700
|
const parts = ['<div>'];
|
|
664
701
|
parts.push('<h3>Header</h3>');
|
|
@@ -699,7 +736,7 @@ server.registerTool('create_formatted_user_story', {
|
|
|
699
736
|
}
|
|
700
737
|
parts.push('</div>');
|
|
701
738
|
const description = parts.join('\n');
|
|
702
|
-
const userStoryResponse = await tp.createUserStory({ title, description, featureId, releaseId, projectId, teamId });
|
|
739
|
+
const userStoryResponse = await tp.createUserStory({ title, description, featureId, releaseId, projectId, teamId, tags, teamIterationId });
|
|
703
740
|
if (!userStoryResponse) {
|
|
704
741
|
return {
|
|
705
742
|
content: [{
|
|
@@ -961,6 +998,16 @@ server.registerTool('get_teams', {
|
|
|
961
998
|
title: 'Get teams',
|
|
962
999
|
description: 'Get all Targetprocess teams',
|
|
963
1000
|
}, async () => handleGetTeams(tp));
|
|
1001
|
+
server.registerTool('get_team_iterations', {
|
|
1002
|
+
title: 'Get team iterations',
|
|
1003
|
+
description: `Get Targetprocess team iterations (sprints), optionally filtered by team. Use this to resolve a sprint/iteration name to an ID before calling create_user_story, create_bug, update_user_story, or update_bug with teamIterationId.
|
|
1004
|
+
CRITICAL WORKFLOW: IF the user specified a team by name (not ID), call "get_teams" first to find the matching team and use its ID as teamId.`,
|
|
1005
|
+
inputSchema: {
|
|
1006
|
+
teamId: z.string()
|
|
1007
|
+
.optional()
|
|
1008
|
+
.describe('Optional Team ID to filter iterations by — resolve it via "get_teams" first'),
|
|
1009
|
+
},
|
|
1010
|
+
}, async ({ teamId }) => handleGetTeamIterations(tp, { teamId }));
|
|
964
1011
|
server.registerTool('get_logged_in_user', {
|
|
965
1012
|
title: 'Get logged in user',
|
|
966
1013
|
description: 'Get logged in user',
|
|
@@ -1235,6 +1282,17 @@ server.registerTool('delete_card_relation', {
|
|
|
1235
1282
|
.describe('The relation ID to delete (the "relationId" field from "get_card_relations", e.g. 20748)'),
|
|
1236
1283
|
},
|
|
1237
1284
|
}, async ({ relationId }) => handleDeleteCardRelation(tp, relationId));
|
|
1285
|
+
server.registerTool('delete_card', {
|
|
1286
|
+
title: 'Delete a card (Bug, User Story, Feature, or Epic)',
|
|
1287
|
+
description: `Delete (remove) a Targetprocess card by its ID. Works on Bugs, User Stories, Features, and Epics.
|
|
1288
|
+
IF the type is uncertain, resolve it first via "search_tp_cards" or by fetching the card.`,
|
|
1289
|
+
inputSchema: {
|
|
1290
|
+
id: z.string()
|
|
1291
|
+
.describe('The card ID to delete (e.g. 148980)'),
|
|
1292
|
+
type: z.enum(["Bug", "UserStory", "Feature", "Epic"])
|
|
1293
|
+
.describe('The entity type of the card being deleted'),
|
|
1294
|
+
},
|
|
1295
|
+
}, async ({ id, type }) => handleDeleteCard(tp, { id, type }));
|
|
1238
1296
|
server.registerTool('get_in_progress_tasks_and_bugs', {
|
|
1239
1297
|
title: 'Get in-progress tasks and bugs for a user',
|
|
1240
1298
|
description: 'Get all Tasks and Bugs currently in "In Progress" state assigned to a given user ID',
|
package/build/tp.js
CHANGED
|
@@ -24,6 +24,11 @@ export class TpClient {
|
|
|
24
24
|
}
|
|
25
25
|
return _url + "/?" + _urlParams.join("&");
|
|
26
26
|
}
|
|
27
|
+
// Strips the access_token value out of a URL before it's logged, so the
|
|
28
|
+
// live TP credential never ends up in stderr/log files.
|
|
29
|
+
redact(url) {
|
|
30
|
+
return url.replace(this.token, "***");
|
|
31
|
+
}
|
|
27
32
|
// @ts-ignore
|
|
28
33
|
async getAll(params) {
|
|
29
34
|
const allItems = [];
|
|
@@ -58,14 +63,14 @@ export class TpClient {
|
|
|
58
63
|
}
|
|
59
64
|
catch (error) {
|
|
60
65
|
console.error("Error making TP request:", error);
|
|
61
|
-
console.error("Request URL:", _url);
|
|
66
|
+
console.error("Request URL:", this.redact(_url));
|
|
62
67
|
return null;
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
async post(params, data) {
|
|
66
71
|
params.param["access_token"] = this.token;
|
|
67
72
|
let _url = this.params(params);
|
|
68
|
-
console.error(JSON.stringify({ "TP_POST_URL": _url }));
|
|
73
|
+
console.error(JSON.stringify({ "TP_POST_URL": this.redact(_url) }));
|
|
69
74
|
console.error(JSON.stringify({ "TP_POST_BODY": data }));
|
|
70
75
|
try {
|
|
71
76
|
const response = await fetch(_url, {
|
|
@@ -88,7 +93,7 @@ export class TpClient {
|
|
|
88
93
|
async postRaw(params, data) {
|
|
89
94
|
params.param["access_token"] = this.token;
|
|
90
95
|
let _url = this.params(params);
|
|
91
|
-
console.error(JSON.stringify({ "TP_POST_URL": _url }));
|
|
96
|
+
console.error(JSON.stringify({ "TP_POST_URL": this.redact(_url) }));
|
|
92
97
|
console.error(JSON.stringify({ "TP_POST_BODY": data }));
|
|
93
98
|
try {
|
|
94
99
|
const response = await fetch(_url, {
|
|
@@ -113,7 +118,7 @@ export class TpClient {
|
|
|
113
118
|
async del(params) {
|
|
114
119
|
params.param["access_token"] = this.token;
|
|
115
120
|
let _url = this.params(params);
|
|
116
|
-
console.error(JSON.stringify({ "TP_DELETE_URL": _url }));
|
|
121
|
+
console.error(JSON.stringify({ "TP_DELETE_URL": this.redact(_url) }));
|
|
117
122
|
try {
|
|
118
123
|
const response = await fetch(_url, {
|
|
119
124
|
method: "DELETE",
|
|
@@ -227,7 +232,7 @@ export class TpClient {
|
|
|
227
232
|
param: { "format": "json" },
|
|
228
233
|
}, userStory);
|
|
229
234
|
}
|
|
230
|
-
async updateUserStory({ id, title, description, projectId, teamId, entityStateId, featureId }) {
|
|
235
|
+
async updateUserStory({ id, title, description, projectId, teamId, entityStateId, featureId, tags, teamIterationId }) {
|
|
231
236
|
const userStory = { "Id": id };
|
|
232
237
|
if (title)
|
|
233
238
|
userStory["Name"] = title;
|
|
@@ -241,12 +246,16 @@ export class TpClient {
|
|
|
241
246
|
userStory["EntityState"] = { "Id": entityStateId };
|
|
242
247
|
if (featureId)
|
|
243
248
|
userStory["Feature"] = { "Id": featureId };
|
|
249
|
+
if (tags)
|
|
250
|
+
userStory["Tags"] = tags;
|
|
251
|
+
if (teamIterationId)
|
|
252
|
+
userStory["TeamIteration"] = { "Id": teamIterationId };
|
|
244
253
|
return this.post({
|
|
245
254
|
pathParam: ["UserStories"],
|
|
246
255
|
param: { "format": "json" },
|
|
247
256
|
}, userStory);
|
|
248
257
|
}
|
|
249
|
-
async updateBug({ id, title, bugContent, origin, projectId, teamId, entityStateId }) {
|
|
258
|
+
async updateBug({ id, title, bugContent, origin, projectId, teamId, entityStateId, tags, teamIterationId }) {
|
|
250
259
|
const bug = { "Id": id };
|
|
251
260
|
if (title)
|
|
252
261
|
bug["Name"] = title;
|
|
@@ -268,12 +277,16 @@ export class TpClient {
|
|
|
268
277
|
}];
|
|
269
278
|
if (entityStateId)
|
|
270
279
|
bug["entityState"] = { "id": entityStateId };
|
|
280
|
+
if (tags)
|
|
281
|
+
bug["Tags"] = tags;
|
|
282
|
+
if (teamIterationId)
|
|
283
|
+
bug["TeamIteration"] = { "Id": teamIterationId };
|
|
271
284
|
return this.post({
|
|
272
285
|
pathParam: ["bugs"],
|
|
273
286
|
param: { "format": "json" },
|
|
274
287
|
}, bug);
|
|
275
288
|
}
|
|
276
|
-
async createBugOnly({ title, bugContent, origin = "Manual QA", projectId, teamId, entityStateId }) {
|
|
289
|
+
async createBugOnly({ title, bugContent, origin = "Manual QA", projectId, teamId, entityStateId, tags, teamIterationId }) {
|
|
277
290
|
const bug = {
|
|
278
291
|
"Name": title,
|
|
279
292
|
"Project": {
|
|
@@ -293,12 +306,16 @@ export class TpClient {
|
|
|
293
306
|
};
|
|
294
307
|
if (entityStateId)
|
|
295
308
|
bug["EntityState"] = { "Id": entityStateId };
|
|
309
|
+
if (tags)
|
|
310
|
+
bug["Tags"] = tags;
|
|
311
|
+
if (teamIterationId)
|
|
312
|
+
bug["TeamIteration"] = { "Id": teamIterationId };
|
|
296
313
|
return this.post({
|
|
297
314
|
pathParam: ["bugs"],
|
|
298
315
|
param: { "format": "json" },
|
|
299
316
|
}, bug);
|
|
300
317
|
}
|
|
301
|
-
async createUserStory({ title, description, featureId, releaseId, projectId, teamId }) {
|
|
318
|
+
async createUserStory({ title, description, featureId, releaseId, projectId, teamId, tags, teamIterationId }) {
|
|
302
319
|
const userStory = {
|
|
303
320
|
"Name": title,
|
|
304
321
|
"Project": { "Id": projectId || config.tp.projectId },
|
|
@@ -310,11 +327,25 @@ export class TpClient {
|
|
|
310
327
|
userStory["Feature"] = { "Id": featureId };
|
|
311
328
|
if (releaseId)
|
|
312
329
|
userStory["Release"] = { "Id": releaseId };
|
|
330
|
+
if (tags)
|
|
331
|
+
userStory["Tags"] = tags;
|
|
332
|
+
if (teamIterationId)
|
|
333
|
+
userStory["TeamIteration"] = { "Id": teamIterationId };
|
|
313
334
|
return this.post({
|
|
314
335
|
pathParam: ["UserStories"],
|
|
315
336
|
param: { "format": "json" },
|
|
316
337
|
}, userStory);
|
|
317
338
|
}
|
|
339
|
+
async getTeamIterations({ teamId } = {}) {
|
|
340
|
+
return this.get({
|
|
341
|
+
pathParam: ["TeamIterations"],
|
|
342
|
+
param: {
|
|
343
|
+
"format": "json",
|
|
344
|
+
...(teamId ? { "where": `Team.Id eq ${teamId}` } : {}),
|
|
345
|
+
"include": "[Id,Name,StartDate,EndDate,Team[Id,Name]]",
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
}
|
|
318
349
|
async getEpic(epicId) {
|
|
319
350
|
return this.get({
|
|
320
351
|
pathParam: ["Epics", epicId],
|
|
@@ -798,6 +829,18 @@ export class TpClient {
|
|
|
798
829
|
param: { "format": "json" },
|
|
799
830
|
});
|
|
800
831
|
}
|
|
832
|
+
async deleteCard({ id, type }) {
|
|
833
|
+
const pathSegment = {
|
|
834
|
+
"Bug": "bugs",
|
|
835
|
+
"UserStory": "userStories",
|
|
836
|
+
"Feature": "features",
|
|
837
|
+
"Epic": "Epics",
|
|
838
|
+
};
|
|
839
|
+
return this.del({
|
|
840
|
+
pathParam: [pathSegment[type], id],
|
|
841
|
+
param: { "format": "json" },
|
|
842
|
+
});
|
|
843
|
+
}
|
|
801
844
|
async getProjects() {
|
|
802
845
|
return this.get({
|
|
803
846
|
pathParam: ["Projects"],
|
|
@@ -1106,7 +1149,7 @@ export class TpClient {
|
|
|
1106
1149
|
formData.append("generalId", generalId);
|
|
1107
1150
|
formData.append("file", blob, fileName);
|
|
1108
1151
|
const url = `${this.baseUrl}/UploadFile.ashx?access_token=${this.token}`;
|
|
1109
|
-
console.error(JSON.stringify({ "UPLOAD_URL":
|
|
1152
|
+
console.error(JSON.stringify({ "UPLOAD_URL": this.redact(url) }, null, 2));
|
|
1110
1153
|
try {
|
|
1111
1154
|
const response = await fetch(url, {
|
|
1112
1155
|
method: "POST",
|