zephyr-scale-mcp-server 0.4.4 → 0.4.5
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/tool-handlers.js +57 -7
- package/package.json +1 -1
- package/src/tool-handlers.ts +59 -10
package/build/tool-handlers.js
CHANGED
|
@@ -212,14 +212,65 @@ export class ZephyrToolHandlers {
|
|
|
212
212
|
const { test_case_key, bdd_content, name } = args;
|
|
213
213
|
const converted = convertToGherkin(bdd_content);
|
|
214
214
|
const finalText = converted && converted.trim().length > 0 ? converted : bdd_content;
|
|
215
|
+
// Fetch the test case first to get the numeric ID.
|
|
216
|
+
// After a DC→Cloud migration, the project key prefix in the test case key (e.g. "CNIDS")
|
|
217
|
+
// may no longer match an active Cloud project, causing key-based write endpoints to return 404.
|
|
218
|
+
// Falling back to the numeric ID bypasses that project-key validation.
|
|
219
|
+
let tc = null;
|
|
215
220
|
try {
|
|
216
|
-
await this.axiosInstance.
|
|
217
|
-
|
|
221
|
+
const getResponse = await this.axiosInstance.get(`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}`);
|
|
222
|
+
tc = getResponse.data;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// GET failed — proceed with key only; write will surface the real error
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
// Primary path: POST to dedicated testscript endpoint using the key
|
|
229
|
+
let scriptUpdateError = null;
|
|
230
|
+
try {
|
|
231
|
+
await this.axiosInstance.post(`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}/testscript`, { type: 'bdd', text: finalText });
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
scriptUpdateError = err;
|
|
235
|
+
}
|
|
236
|
+
// Fallback: if testscript POST failed (e.g. migrated project key), try PUT on the full
|
|
237
|
+
// test case record with the testScript field embedded — some Cloud instances accept this
|
|
238
|
+
// for migrated test cases where the project is deactivated.
|
|
239
|
+
if (scriptUpdateError) {
|
|
240
|
+
if (!tc) {
|
|
241
|
+
throw scriptUpdateError; // no test case data to build PUT payload, surface original error
|
|
242
|
+
}
|
|
243
|
+
const putPayload = {
|
|
244
|
+
id: tc.id,
|
|
245
|
+
key: test_case_key,
|
|
246
|
+
name: (typeof name === 'string' && name.trim().length > 0) ? name : tc.name,
|
|
247
|
+
status: tc.status,
|
|
248
|
+
priority: tc.priority,
|
|
249
|
+
project: tc.project,
|
|
250
|
+
testScript: { type: 'bdd', text: finalText },
|
|
251
|
+
};
|
|
252
|
+
for (const field of ['objective', 'precondition', 'estimatedTime', 'component', 'owner', 'folder']) {
|
|
253
|
+
if (tc[field] !== undefined && tc[field] !== null)
|
|
254
|
+
putPayload[field] = tc[field];
|
|
255
|
+
}
|
|
256
|
+
if (Array.isArray(tc.labels) && tc.labels.length > 0)
|
|
257
|
+
putPayload.labels = tc.labels;
|
|
258
|
+
if (tc.customFields && Object.keys(tc.customFields).length > 0)
|
|
259
|
+
putPayload.customFields = tc.customFields;
|
|
260
|
+
await this.axiosInstance.put(`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}`, putPayload);
|
|
261
|
+
return {
|
|
262
|
+
content: [{
|
|
263
|
+
type: 'text',
|
|
264
|
+
text: `✅ Updated ${test_case_key} with BDD content successfully (Cloud v2, via PUT fallback for migrated project)`,
|
|
265
|
+
}],
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Primary path succeeded — optionally rename
|
|
218
269
|
if (typeof name === 'string' && name.trim().length > 0) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
270
|
+
if (!tc) {
|
|
271
|
+
const getResponse = await this.axiosInstance.get(`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}`);
|
|
272
|
+
tc = getResponse.data;
|
|
273
|
+
}
|
|
223
274
|
const putPayload = {
|
|
224
275
|
id: tc.id,
|
|
225
276
|
key: test_case_key,
|
|
@@ -228,7 +279,6 @@ export class ZephyrToolHandlers {
|
|
|
228
279
|
priority: tc.priority,
|
|
229
280
|
project: tc.project,
|
|
230
281
|
};
|
|
231
|
-
// Preserve all optional fields to avoid the API clearing them
|
|
232
282
|
for (const field of ['objective', 'precondition', 'estimatedTime', 'component', 'owner', 'folder']) {
|
|
233
283
|
if (tc[field] !== undefined && tc[field] !== null)
|
|
234
284
|
putPayload[field] = tc[field];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zephyr-scale-mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for Zephyr Scale test case management with comprehensive STEP_BY_STEP, PLAIN_TEXT, and BDD support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./build/index.js",
|
package/src/tool-handlers.ts
CHANGED
|
@@ -229,18 +229,68 @@ export class ZephyrToolHandlers {
|
|
|
229
229
|
const converted = convertToGherkin(bdd_content);
|
|
230
230
|
const finalText = converted && converted.trim().length > 0 ? converted : bdd_content;
|
|
231
231
|
|
|
232
|
+
// Fetch the test case first to get the numeric ID.
|
|
233
|
+
// After a DC→Cloud migration, the project key prefix in the test case key (e.g. "CNIDS")
|
|
234
|
+
// may no longer match an active Cloud project, causing key-based write endpoints to return 404.
|
|
235
|
+
// Falling back to the numeric ID bypasses that project-key validation.
|
|
236
|
+
let tc: any = null;
|
|
232
237
|
try {
|
|
233
|
-
await this.axiosInstance.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
238
|
+
const getResponse = await this.axiosInstance.get(`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}`);
|
|
239
|
+
tc = getResponse.data;
|
|
240
|
+
} catch {
|
|
241
|
+
// GET failed — proceed with key only; write will surface the real error
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
// Primary path: POST to dedicated testscript endpoint using the key
|
|
246
|
+
let scriptUpdateError: any = null;
|
|
247
|
+
try {
|
|
248
|
+
await this.axiosInstance.post(
|
|
249
|
+
`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}/testscript`,
|
|
250
|
+
{ type: 'bdd', text: finalText }
|
|
251
|
+
);
|
|
252
|
+
} catch (err: any) {
|
|
253
|
+
scriptUpdateError = err;
|
|
254
|
+
}
|
|
237
255
|
|
|
238
|
-
//
|
|
256
|
+
// Fallback: if testscript POST failed (e.g. migrated project key), try PUT on the full
|
|
257
|
+
// test case record with the testScript field embedded — some Cloud instances accept this
|
|
258
|
+
// for migrated test cases where the project is deactivated.
|
|
259
|
+
if (scriptUpdateError) {
|
|
260
|
+
if (!tc) {
|
|
261
|
+
throw scriptUpdateError; // no test case data to build PUT payload, surface original error
|
|
262
|
+
}
|
|
263
|
+
const putPayload: any = {
|
|
264
|
+
id: tc.id,
|
|
265
|
+
key: test_case_key,
|
|
266
|
+
name: (typeof name === 'string' && name.trim().length > 0) ? name : tc.name,
|
|
267
|
+
status: tc.status,
|
|
268
|
+
priority: tc.priority,
|
|
269
|
+
project: tc.project,
|
|
270
|
+
testScript: { type: 'bdd', text: finalText },
|
|
271
|
+
};
|
|
272
|
+
for (const field of ['objective', 'precondition', 'estimatedTime', 'component', 'owner', 'folder']) {
|
|
273
|
+
if (tc[field] !== undefined && tc[field] !== null) putPayload[field] = tc[field];
|
|
274
|
+
}
|
|
275
|
+
if (Array.isArray(tc.labels) && tc.labels.length > 0) putPayload.labels = tc.labels;
|
|
276
|
+
if (tc.customFields && Object.keys(tc.customFields).length > 0) putPayload.customFields = tc.customFields;
|
|
277
|
+
|
|
278
|
+
await this.axiosInstance.put(`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}`, putPayload);
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
content: [{
|
|
282
|
+
type: 'text',
|
|
283
|
+
text: `✅ Updated ${test_case_key} with BDD content successfully (Cloud v2, via PUT fallback for migrated project)`,
|
|
284
|
+
}],
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Primary path succeeded — optionally rename
|
|
239
289
|
if (typeof name === 'string' && name.trim().length > 0) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
290
|
+
if (!tc) {
|
|
291
|
+
const getResponse = await this.axiosInstance.get(`${this.jiraConfig.apiEndpoints.testcase}/${test_case_key}`);
|
|
292
|
+
tc = getResponse.data;
|
|
293
|
+
}
|
|
244
294
|
const putPayload: any = {
|
|
245
295
|
id: tc.id,
|
|
246
296
|
key: test_case_key,
|
|
@@ -249,7 +299,6 @@ export class ZephyrToolHandlers {
|
|
|
249
299
|
priority: tc.priority,
|
|
250
300
|
project: tc.project,
|
|
251
301
|
};
|
|
252
|
-
// Preserve all optional fields to avoid the API clearing them
|
|
253
302
|
for (const field of ['objective', 'precondition', 'estimatedTime', 'component', 'owner', 'folder']) {
|
|
254
303
|
if (tc[field] !== undefined && tc[field] !== null) putPayload[field] = tc[field];
|
|
255
304
|
}
|