@smartbear/mcp 0.12.0 → 0.13.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/README.md +30 -6
- package/dist/bugsnag/client/api/CurrentUser.js +50 -26
- package/dist/bugsnag/client/api/Error.js +158 -57
- package/dist/bugsnag/client/api/Project.js +398 -243
- package/dist/bugsnag/client/api/api.js +4087 -3837
- package/dist/bugsnag/client/api/base.js +155 -173
- package/dist/bugsnag/client/api/configuration.js +28 -25
- package/dist/bugsnag/client/filters.js +11 -20
- package/dist/bugsnag/client.js +1398 -1277
- package/dist/bugsnag/input-schemas.js +39 -57
- package/dist/collaborator/client.js +335 -371
- package/dist/common/bugsnag.js +5 -3
- package/dist/common/cache.js +50 -57
- package/dist/common/client-registry.js +106 -119
- package/dist/common/info.js +7 -3
- package/dist/common/register-clients.js +0 -16
- package/dist/common/server.js +270 -228
- package/dist/common/tools.js +19 -0
- package/dist/common/transport-http.js +252 -343
- package/dist/common/transport-stdio.js +40 -37
- package/dist/common/zod-utils.js +20 -0
- package/dist/index.js +18 -23
- package/dist/package.json.js +11 -0
- package/dist/pactflow/client/ai.js +142 -169
- package/dist/pactflow/client/base.js +41 -51
- package/dist/pactflow/client/prompt-utils.js +93 -84
- package/dist/pactflow/client/prompts.js +95 -92
- package/dist/pactflow/client/tools.js +94 -83
- package/dist/pactflow/client/utils.js +60 -64
- package/dist/pactflow/client.js +399 -320
- package/dist/qmetry/client/api/client-api.js +43 -41
- package/dist/qmetry/client/api/error-handler.js +264 -310
- package/dist/qmetry/client/auto-resolve.js +78 -99
- package/dist/qmetry/client/automation.js +139 -162
- package/dist/qmetry/client/handlers.js +49 -46
- package/dist/qmetry/client/issues.js +133 -115
- package/dist/qmetry/client/project.js +153 -174
- package/dist/qmetry/client/requirement.js +82 -70
- package/dist/qmetry/client/testcase.js +240 -208
- package/dist/qmetry/client/testsuite.js +332 -293
- package/dist/qmetry/client/tools/automation-tools.js +291 -288
- package/dist/qmetry/client/tools/index.js +16 -13
- package/dist/qmetry/client/tools/issue-tools.js +534 -543
- package/dist/qmetry/client/tools/project-tools.js +635 -656
- package/dist/qmetry/client/tools/requirement-tools.js +525 -528
- package/dist/qmetry/client/tools/testcase-tools.js +773 -786
- package/dist/qmetry/client/tools/testsuite-tools.js +1069 -1083
- package/dist/qmetry/client/utils.js +8 -14
- package/dist/qmetry/client.js +111 -109
- package/dist/qmetry/config/constants.js +48 -44
- package/dist/qmetry/config/rest-endpoints.js +51 -48
- package/dist/qmetry/types/automation.js +7 -7
- package/dist/qmetry/types/common.js +763 -1049
- package/dist/qmetry/types/issues.js +26 -19
- package/dist/qmetry/types/project.js +32 -25
- package/dist/qmetry/types/requirements.js +26 -21
- package/dist/qmetry/types/testcase.js +55 -44
- package/dist/qmetry/types/testsuite.js +66 -52
- package/dist/reflect/client.js +284 -226
- package/dist/swagger/client/api.js +645 -662
- package/dist/swagger/client/configuration.js +31 -33
- package/dist/swagger/client/portal-types.js +204 -244
- package/dist/swagger/client/registry-types.js +62 -96
- package/dist/swagger/client/tools.js +148 -158
- package/dist/swagger/client/user-management-types.js +11 -22
- package/dist/swagger/client.js +143 -135
- package/dist/swagger/config-utils.js +10 -16
- package/dist/zephyr/client.js +43 -42
- package/dist/zephyr/common/api-client.js +35 -30
- package/dist/zephyr/common/auth-service.js +16 -13
- package/dist/zephyr/common/rest-api-schemas.js +3173 -5146
- package/dist/zephyr/tool/environment/get-environments.js +66 -66
- package/dist/zephyr/tool/priority/get-priorities.js +41 -41
- package/dist/zephyr/tool/project/get-project.js +37 -37
- package/dist/zephyr/tool/project/get-projects.js +46 -46
- package/dist/zephyr/tool/status/get-statuses.js +47 -47
- package/dist/zephyr/tool/test-case/get-test-case.js +37 -37
- package/dist/zephyr/tool/test-case/get-test-cases.js +62 -62
- package/dist/zephyr/tool/test-cycle/get-test-cycle.js +37 -37
- package/dist/zephyr/tool/test-cycle/get-test-cycles.js +70 -70
- package/dist/zephyr/tool/test-execution/get-test-execution.js +37 -37
- package/dist/zephyr/tool/test-execution/get-test-executions.js +43 -43
- package/package.json +5 -5
- package/dist/bugsnag/client/api/index.js +0 -6
- package/dist/common/types.js +0 -6
- package/dist/qmetry/client/tools/types.js +0 -1
- package/dist/swagger/client/index.js +0 -6
- package/dist/tests/unit/bugsnag/utils/factories.js +0 -86
- package/dist/zephyr/tool/zephyr-tool.js +0 -1
|
@@ -1,106 +1,85 @@
|
|
|
1
1
|
import { QMetryToolsHandlers } from "../config/constants.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
handler: QMetryToolsHandlers.FETCH_ISSUES,
|
|
53
|
-
viewIdPath: "latestViews.IS.viewId",
|
|
54
|
-
moduleName: "Issues",
|
|
55
|
-
},
|
|
2
|
+
const AUTO_RESOLVE_MODULES = [
|
|
3
|
+
{
|
|
4
|
+
handler: QMetryToolsHandlers.FETCH_TEST_CASES,
|
|
5
|
+
viewIdPath: "latestViews.TC.viewId",
|
|
6
|
+
moduleName: "Test Cases"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
handler: QMetryToolsHandlers.CREATE_TEST_CASE,
|
|
10
|
+
folderIdPath: "rootFolders.TC.id",
|
|
11
|
+
folderIdField: "tcFolderID",
|
|
12
|
+
moduleName: "Test Cases"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
handler: QMetryToolsHandlers.FETCH_REQUIREMENTS,
|
|
16
|
+
viewIdPath: "latestViews.RQ.viewId",
|
|
17
|
+
moduleName: "Requirements"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
handler: QMetryToolsHandlers.FETCH_TEST_SUITES,
|
|
21
|
+
viewIdPath: "latestViews.TS.viewId",
|
|
22
|
+
moduleName: "Test Suites"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
handler: QMetryToolsHandlers.FETCH_TESTCASE_RUNS_BY_TESTSUITE_RUN,
|
|
26
|
+
viewIdPath: "latestViews.TE.viewId",
|
|
27
|
+
moduleName: "Test Case Run By Test Suite Run"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
handler: QMetryToolsHandlers.FETCH_EXECUTIONS_BY_TESTSUITE,
|
|
31
|
+
viewIdPath: "latestViews.TEL.viewId",
|
|
32
|
+
moduleName: "Executions By Test Suites"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
handler: QMetryToolsHandlers.FETCH_TESTSUITES_FOR_TESTCASE,
|
|
36
|
+
viewIdPath: "latestViews.TSFS.viewId",
|
|
37
|
+
folderIdPath: "rootFolders.TS.id",
|
|
38
|
+
folderIdField: "tsFolderID",
|
|
39
|
+
moduleName: "Test Suites"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
handler: QMetryToolsHandlers.CREATE_TEST_SUITE,
|
|
43
|
+
folderIdPath: "rootFolders.TS.id",
|
|
44
|
+
folderIdField: "parentFolderId",
|
|
45
|
+
moduleName: "Test Suites"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
handler: QMetryToolsHandlers.FETCH_ISSUES,
|
|
49
|
+
viewIdPath: "latestViews.IS.viewId",
|
|
50
|
+
moduleName: "Issues"
|
|
51
|
+
}
|
|
56
52
|
];
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* @param obj - Object to traverse
|
|
60
|
-
* @param path - Dot notation path (e.g., 'latestViews.TC.viewId')
|
|
61
|
-
* @returns The value at the path or undefined if not found
|
|
62
|
-
*/
|
|
63
|
-
export function getNestedProperty(obj, path) {
|
|
64
|
-
return path.split(".").reduce((current, key) => current?.[key], obj);
|
|
53
|
+
function getNestedProperty(obj, path) {
|
|
54
|
+
return path.split(".").reduce((current, key) => current?.[key], obj);
|
|
65
55
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const updatedArgs = { ...args };
|
|
75
|
-
let viewId = updatedArgs.viewId;
|
|
76
|
-
const folderPath = updatedArgs.folderPath;
|
|
77
|
-
// Auto-resolve viewId if not provided and config has viewIdPath
|
|
78
|
-
if (!viewId && config.viewIdPath) {
|
|
79
|
-
viewId = getNestedProperty(projectInfo, config.viewIdPath);
|
|
80
|
-
if (viewId) {
|
|
81
|
-
updatedArgs.viewId = viewId;
|
|
82
|
-
}
|
|
56
|
+
function autoResolveViewIdAndFolderPath(args, projectInfo, config) {
|
|
57
|
+
const updatedArgs = { ...args };
|
|
58
|
+
let viewId = updatedArgs.viewId;
|
|
59
|
+
const folderPath = updatedArgs.folderPath;
|
|
60
|
+
if (!viewId && config.viewIdPath) {
|
|
61
|
+
viewId = getNestedProperty(projectInfo, config.viewIdPath);
|
|
62
|
+
if (viewId) {
|
|
63
|
+
updatedArgs.viewId = viewId;
|
|
83
64
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
65
|
+
}
|
|
66
|
+
if (folderPath === void 0) {
|
|
67
|
+
updatedArgs.folderPath = "";
|
|
68
|
+
}
|
|
69
|
+
if (config.folderIdPath && config.folderIdField && !updatedArgs[config.folderIdField]) {
|
|
70
|
+
const folderId = getNestedProperty(projectInfo, config.folderIdPath);
|
|
71
|
+
if (folderId) {
|
|
72
|
+
updatedArgs[config.folderIdField] = folderId;
|
|
87
73
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
config.folderIdField &&
|
|
91
|
-
!updatedArgs[config.folderIdField]) {
|
|
92
|
-
const folderId = getNestedProperty(projectInfo, config.folderIdPath);
|
|
93
|
-
if (folderId) {
|
|
94
|
-
updatedArgs[config.folderIdField] = folderId;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return updatedArgs;
|
|
74
|
+
}
|
|
75
|
+
return updatedArgs;
|
|
98
76
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* @param handler - The handler name to find config for
|
|
102
|
-
* @returns Module configuration or undefined if not found
|
|
103
|
-
*/
|
|
104
|
-
export function findAutoResolveConfig(handler) {
|
|
105
|
-
return AUTO_RESOLVE_MODULES.find((module) => module.handler === handler);
|
|
77
|
+
function findAutoResolveConfig(handler) {
|
|
78
|
+
return AUTO_RESOLVE_MODULES.find((module) => module.handler === handler);
|
|
106
79
|
}
|
|
80
|
+
export {
|
|
81
|
+
AUTO_RESOLVE_MODULES,
|
|
82
|
+
autoResolveViewIdAndFolderPath,
|
|
83
|
+
findAutoResolveConfig,
|
|
84
|
+
getNestedProperty
|
|
85
|
+
};
|
|
@@ -4,168 +4,145 @@ import { QMETRY_PATHS } from "../config/rest-endpoints.js";
|
|
|
4
4
|
import { DEFAULT_IMPORT_AUTOMATION_PAYLOAD } from "../types/automation.js";
|
|
5
5
|
import { qmetryRequest } from "./api/client-api.js";
|
|
6
6
|
import { handleQMetryApiError } from "./api/error-handler.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* @returns Promise resolving to import result with test suite and execution details
|
|
24
|
-
*/
|
|
25
|
-
export async function importAutomationResults(token, baseUrl, project, payload) {
|
|
26
|
-
// Merge with defaults
|
|
27
|
-
const finalPayload = {
|
|
28
|
-
...DEFAULT_IMPORT_AUTOMATION_PAYLOAD,
|
|
29
|
-
...payload,
|
|
30
|
-
};
|
|
31
|
-
// Create FormData for multipart/form-data upload
|
|
32
|
-
const formData = new FormData();
|
|
33
|
-
// Handle file upload
|
|
34
|
-
// The file should be provided as base64 string or file content
|
|
35
|
-
let fileBlob;
|
|
36
|
-
if (finalPayload.file.startsWith("data:")) {
|
|
37
|
-
// Base64 data URI format
|
|
38
|
-
const base64Data = finalPayload.file.split(",")[1];
|
|
39
|
-
const binaryData = atob(base64Data);
|
|
40
|
-
const bytes = new Uint8Array(binaryData.length);
|
|
41
|
-
for (let i = 0; i < binaryData.length; i++) {
|
|
42
|
-
bytes[i] = binaryData.charCodeAt(i);
|
|
43
|
-
}
|
|
44
|
-
fileBlob = new Blob([bytes]);
|
|
45
|
-
}
|
|
46
|
-
else if (finalPayload.file.startsWith("/") ||
|
|
47
|
-
finalPayload.file.includes(":\\")) {
|
|
48
|
-
// File path - read file from filesystem (Node.js only)
|
|
49
|
-
try {
|
|
50
|
-
const fs = await import("node:fs/promises");
|
|
51
|
-
const fileBuffer = await fs.readFile(finalPayload.file);
|
|
52
|
-
fileBlob = new Blob([new Uint8Array(fileBuffer)]);
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
throw new Error(`Failed to read file from path: ${finalPayload.file}. Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
// Assume raw base64 string
|
|
60
|
-
try {
|
|
61
|
-
const binaryData = atob(finalPayload.file);
|
|
62
|
-
const bytes = new Uint8Array(binaryData.length);
|
|
63
|
-
for (let i = 0; i < binaryData.length; i++) {
|
|
64
|
-
bytes[i] = binaryData.charCodeAt(i);
|
|
65
|
-
}
|
|
66
|
-
fileBlob = new Blob([bytes]);
|
|
67
|
-
}
|
|
68
|
-
catch (_error) {
|
|
69
|
-
throw new Error("Invalid file format. Please provide base64 encoded file content or file path.");
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Add file to FormData
|
|
73
|
-
formData.append("file", fileBlob, finalPayload.fileName);
|
|
74
|
-
// Add required entityType
|
|
75
|
-
formData.append("entityType", finalPayload.entityType);
|
|
76
|
-
// Add optional parameters
|
|
77
|
-
if (finalPayload.automationHierarchy) {
|
|
78
|
-
formData.append("automationHierarchy", finalPayload.automationHierarchy);
|
|
79
|
-
}
|
|
80
|
-
if (finalPayload.testsuiteName) {
|
|
81
|
-
formData.append("testsuiteName", finalPayload.testsuiteName);
|
|
82
|
-
}
|
|
83
|
-
if (finalPayload.testsuiteId) {
|
|
84
|
-
formData.append("testsuiteId", finalPayload.testsuiteId);
|
|
85
|
-
}
|
|
86
|
-
if (finalPayload.tsFolderPath) {
|
|
87
|
-
formData.append("tsFolderPath", finalPayload.tsFolderPath);
|
|
88
|
-
}
|
|
89
|
-
if (finalPayload.tcFolderPath) {
|
|
90
|
-
formData.append("tcFolderPath", finalPayload.tcFolderPath);
|
|
91
|
-
}
|
|
92
|
-
if (finalPayload.platformID) {
|
|
93
|
-
formData.append("platformID", finalPayload.platformID);
|
|
94
|
-
}
|
|
95
|
-
if (finalPayload.projectID) {
|
|
96
|
-
formData.append("projectID", finalPayload.projectID);
|
|
97
|
-
}
|
|
98
|
-
if (finalPayload.releaseID) {
|
|
99
|
-
formData.append("releaseID", finalPayload.releaseID);
|
|
100
|
-
}
|
|
101
|
-
if (finalPayload.cycleID) {
|
|
102
|
-
formData.append("cycleID", finalPayload.cycleID);
|
|
103
|
-
}
|
|
104
|
-
if (finalPayload.buildID) {
|
|
105
|
-
formData.append("buildID", finalPayload.buildID);
|
|
106
|
-
}
|
|
107
|
-
if (finalPayload.testcase_fields) {
|
|
108
|
-
formData.append("testcase_fields", finalPayload.testcase_fields);
|
|
109
|
-
}
|
|
110
|
-
if (finalPayload.testsuite_fields) {
|
|
111
|
-
formData.append("testsuite_fields", finalPayload.testsuite_fields);
|
|
112
|
-
}
|
|
113
|
-
if (finalPayload.skipWarning) {
|
|
114
|
-
formData.append("skipWarning", finalPayload.skipWarning);
|
|
115
|
-
}
|
|
116
|
-
if (finalPayload.is_matching_required) {
|
|
117
|
-
formData.append("is_matching_required", finalPayload.is_matching_required);
|
|
118
|
-
}
|
|
119
|
-
// Make API request
|
|
120
|
-
const url = `${baseUrl || QMETRY_DEFAULTS.BASE_URL}${QMETRY_PATHS.AUTOMATION.IMPORT_RESULTS}`;
|
|
121
|
-
const headers = {
|
|
122
|
-
apikey: token,
|
|
123
|
-
project: finalPayload.projectID || project || QMETRY_DEFAULTS.PROJECT_KEY,
|
|
124
|
-
"User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
|
|
125
|
-
// Note: Content-Type will be set automatically by fetch for FormData
|
|
126
|
-
};
|
|
127
|
-
let res;
|
|
7
|
+
async function importAutomationResults(token, baseUrl, project, payload) {
|
|
8
|
+
const finalPayload = {
|
|
9
|
+
...DEFAULT_IMPORT_AUTOMATION_PAYLOAD,
|
|
10
|
+
...payload
|
|
11
|
+
};
|
|
12
|
+
const formData = new FormData();
|
|
13
|
+
let fileBlob;
|
|
14
|
+
if (finalPayload.file.startsWith("data:")) {
|
|
15
|
+
const base64Data = finalPayload.file.split(",")[1];
|
|
16
|
+
const binaryData = atob(base64Data);
|
|
17
|
+
const bytes = new Uint8Array(binaryData.length);
|
|
18
|
+
for (let i = 0; i < binaryData.length; i++) {
|
|
19
|
+
bytes[i] = binaryData.charCodeAt(i);
|
|
20
|
+
}
|
|
21
|
+
fileBlob = new Blob([bytes]);
|
|
22
|
+
} else if (finalPayload.file.startsWith("/") || finalPayload.file.includes(":\\")) {
|
|
128
23
|
try {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
24
|
+
const fs = await import("node:fs/promises");
|
|
25
|
+
const fileBuffer = await fs.readFile(finalPayload.file);
|
|
26
|
+
fileBlob = new Blob([new Uint8Array(fileBuffer)]);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Failed to read file from path: ${finalPayload.file}. Error: ${error instanceof Error ? error.message : String(error)}`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
try {
|
|
34
|
+
const binaryData = atob(finalPayload.file);
|
|
35
|
+
const bytes = new Uint8Array(binaryData.length);
|
|
36
|
+
for (let i = 0; i < binaryData.length; i++) {
|
|
37
|
+
bytes[i] = binaryData.charCodeAt(i);
|
|
38
|
+
}
|
|
39
|
+
fileBlob = new Blob([bytes]);
|
|
40
|
+
} catch (_error) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"Invalid file format. Please provide base64 encoded file content or file path."
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
formData.append("file", fileBlob, finalPayload.fileName);
|
|
47
|
+
formData.append("entityType", finalPayload.entityType);
|
|
48
|
+
if (finalPayload.automationHierarchy) {
|
|
49
|
+
formData.append("automationHierarchy", finalPayload.automationHierarchy);
|
|
50
|
+
}
|
|
51
|
+
if (finalPayload.testsuiteName) {
|
|
52
|
+
formData.append("testsuiteName", finalPayload.testsuiteName);
|
|
53
|
+
}
|
|
54
|
+
if (finalPayload.testsuiteId) {
|
|
55
|
+
formData.append("testsuiteId", finalPayload.testsuiteId);
|
|
56
|
+
}
|
|
57
|
+
if (finalPayload.tsFolderPath) {
|
|
58
|
+
formData.append("tsFolderPath", finalPayload.tsFolderPath);
|
|
59
|
+
}
|
|
60
|
+
if (finalPayload.tcFolderPath) {
|
|
61
|
+
formData.append("tcFolderPath", finalPayload.tcFolderPath);
|
|
62
|
+
}
|
|
63
|
+
if (finalPayload.platformID) {
|
|
64
|
+
formData.append("platformID", finalPayload.platformID);
|
|
65
|
+
}
|
|
66
|
+
if (finalPayload.projectID) {
|
|
67
|
+
formData.append("projectID", finalPayload.projectID);
|
|
68
|
+
}
|
|
69
|
+
if (finalPayload.releaseID) {
|
|
70
|
+
formData.append("releaseID", finalPayload.releaseID);
|
|
71
|
+
}
|
|
72
|
+
if (finalPayload.cycleID) {
|
|
73
|
+
formData.append("cycleID", finalPayload.cycleID);
|
|
74
|
+
}
|
|
75
|
+
if (finalPayload.buildID) {
|
|
76
|
+
formData.append("buildID", finalPayload.buildID);
|
|
77
|
+
}
|
|
78
|
+
if (finalPayload.testcase_fields) {
|
|
79
|
+
formData.append("testcase_fields", finalPayload.testcase_fields);
|
|
80
|
+
}
|
|
81
|
+
if (finalPayload.testsuite_fields) {
|
|
82
|
+
formData.append("testsuite_fields", finalPayload.testsuite_fields);
|
|
83
|
+
}
|
|
84
|
+
if (finalPayload.skipWarning) {
|
|
85
|
+
formData.append("skipWarning", finalPayload.skipWarning);
|
|
86
|
+
}
|
|
87
|
+
if (finalPayload.is_matching_required) {
|
|
88
|
+
formData.append("is_matching_required", finalPayload.is_matching_required);
|
|
89
|
+
}
|
|
90
|
+
const url = `${baseUrl || QMETRY_DEFAULTS.BASE_URL}${QMETRY_PATHS.AUTOMATION.IMPORT_RESULTS}`;
|
|
91
|
+
const headers = {
|
|
92
|
+
apikey: token,
|
|
93
|
+
project: finalPayload.projectID || project || QMETRY_DEFAULTS.PROJECT_KEY,
|
|
94
|
+
"User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`
|
|
95
|
+
// Note: Content-Type will be set automatically by fetch for FormData
|
|
96
|
+
};
|
|
97
|
+
let res;
|
|
98
|
+
try {
|
|
99
|
+
res = await fetch(url, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers,
|
|
102
|
+
body: formData
|
|
170
103
|
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Failed to import automation results. Network error: ${error instanceof Error ? error.message : String(error)}
|
|
107
|
+
|
|
108
|
+
Please check:
|
|
109
|
+
- QMetry server is accessible
|
|
110
|
+
- File size is under 30 MB
|
|
111
|
+
- File format is .json, .xml, or .zip`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
if (!res.ok) {
|
|
115
|
+
await handleQMetryApiError(
|
|
116
|
+
res,
|
|
117
|
+
baseUrl || QMETRY_DEFAULTS.BASE_URL,
|
|
118
|
+
project || QMETRY_DEFAULTS.PROJECT_KEY,
|
|
119
|
+
QMETRY_PATHS.AUTOMATION.IMPORT_RESULTS
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return await res.json();
|
|
123
|
+
}
|
|
124
|
+
async function getAutomationStatus(token, baseUrl, project, requestID) {
|
|
125
|
+
let numericRequestID;
|
|
126
|
+
if (typeof requestID === "object" && requestID !== null && "requestID" in requestID && typeof requestID.requestID !== "undefined") {
|
|
127
|
+
numericRequestID = Number(requestID.requestID);
|
|
128
|
+
} else {
|
|
129
|
+
numericRequestID = Number(requestID);
|
|
130
|
+
}
|
|
131
|
+
if (!numericRequestID || Number.isNaN(numericRequestID)) {
|
|
132
|
+
throw new Error("requestID must be a valid number");
|
|
133
|
+
}
|
|
134
|
+
return qmetryRequest({
|
|
135
|
+
method: "GET",
|
|
136
|
+
path: QMETRY_PATHS.AUTOMATION.GET_STATUS.replace(
|
|
137
|
+
":requestID",
|
|
138
|
+
String(numericRequestID)
|
|
139
|
+
),
|
|
140
|
+
token,
|
|
141
|
+
baseUrl: baseUrl || QMETRY_DEFAULTS.BASE_URL,
|
|
142
|
+
project: project || QMETRY_DEFAULTS.PROJECT_KEY
|
|
143
|
+
});
|
|
171
144
|
}
|
|
145
|
+
export {
|
|
146
|
+
getAutomationStatus,
|
|
147
|
+
importAutomationResults
|
|
148
|
+
};
|
|
@@ -1,49 +1,52 @@
|
|
|
1
1
|
import { QMetryToolsHandlers } from "../config/constants.js";
|
|
2
2
|
import { getAutomationStatus, importAutomationResults } from "./automation.js";
|
|
3
|
-
import {
|
|
4
|
-
import { createCycle, createRelease, getBuilds,
|
|
5
|
-
import { fetchRequirementDetails, fetchRequirements
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
3
|
+
import { linkIssuesToTestcaseRun, fetchIssues, updateIssue, createIssue, fetchIssuesLinkedToTestCase } from "./issues.js";
|
|
4
|
+
import { updateCycle, createCycle, createRelease, getPlatforms, getBuilds, getReleasesCycles, getProjectInfo, getProjects } from "./project.js";
|
|
5
|
+
import { fetchRequirementsLinkedToTestCase, fetchRequirementDetails, fetchRequirements } from "./requirement.js";
|
|
6
|
+
import { fetchTestCasesLinkedToRequirement, linkRequirementToTestCase, fetchTestCaseExecutions, fetchTestCaseSteps, fetchTestCaseVersionDetails, fetchTestCaseDetails, fetchTestCases, updateTestCase, createTestCases } from "./testcase.js";
|
|
7
|
+
import { linkPlatformsToTestSuite, fetchLinkedIssuesByTestCaseRun, fetchTestCaseRunsByTestSuiteRun, bulkUpdateExecutionStatus, fetchExecutionsByTestSuite, fetchTestCasesByTestSuite, reqLinkedTestCasesToTestSuite, linkTestCasesToTestSuite, fetchTestSuitesForTestCase, fetchTestSuites, updateTestSuite, createTestSuites } from "./testsuite.js";
|
|
8
|
+
const QMETRY_HANDLER_MAP = {
|
|
9
|
+
[QMetryToolsHandlers.FETCH_PROJECTS]: getProjects,
|
|
10
|
+
[QMetryToolsHandlers.SET_PROJECT_INFO]: getProjectInfo,
|
|
11
|
+
[QMetryToolsHandlers.FETCH_PROJECT_INFO]: getProjectInfo,
|
|
12
|
+
[QMetryToolsHandlers.FETCH_RELEASES_CYCLES]: getReleasesCycles,
|
|
13
|
+
[QMetryToolsHandlers.FETCH_BUILDS]: getBuilds,
|
|
14
|
+
[QMetryToolsHandlers.FETCH_PLATFORMS]: getPlatforms,
|
|
15
|
+
[QMetryToolsHandlers.CREATE_RELEASE]: createRelease,
|
|
16
|
+
[QMetryToolsHandlers.CREATE_CYCLE]: createCycle,
|
|
17
|
+
[QMetryToolsHandlers.UPDATE_CYCLE]: updateCycle,
|
|
18
|
+
[QMetryToolsHandlers.CREATE_TEST_CASE]: createTestCases,
|
|
19
|
+
[QMetryToolsHandlers.UPDATE_TEST_CASE]: updateTestCase,
|
|
20
|
+
[QMetryToolsHandlers.FETCH_TEST_CASES]: fetchTestCases,
|
|
21
|
+
[QMetryToolsHandlers.FETCH_TEST_CASE_DETAILS]: fetchTestCaseDetails,
|
|
22
|
+
[QMetryToolsHandlers.FETCH_TEST_CASE_VERSION_DETAILS]: fetchTestCaseVersionDetails,
|
|
23
|
+
[QMetryToolsHandlers.FETCH_TEST_CASE_STEPS]: fetchTestCaseSteps,
|
|
24
|
+
[QMetryToolsHandlers.FETCH_TEST_CASE_EXECUTIONS]: fetchTestCaseExecutions,
|
|
25
|
+
[QMetryToolsHandlers.LINK_REQUIREMENT_TO_TESTCASE]: linkRequirementToTestCase,
|
|
26
|
+
[QMetryToolsHandlers.FETCH_REQUIREMENTS]: fetchRequirements,
|
|
27
|
+
[QMetryToolsHandlers.FETCH_REQUIREMENT_DETAILS]: fetchRequirementDetails,
|
|
28
|
+
[QMetryToolsHandlers.FETCH_TESTCASES_LINKED_TO_REQUIREMENT]: fetchTestCasesLinkedToRequirement,
|
|
29
|
+
[QMetryToolsHandlers.FETCH_REQUIREMENTS_LINKED_TO_TESTCASE]: fetchRequirementsLinkedToTestCase,
|
|
30
|
+
[QMetryToolsHandlers.CREATE_TEST_SUITE]: createTestSuites,
|
|
31
|
+
[QMetryToolsHandlers.UPDATE_TEST_SUITE]: updateTestSuite,
|
|
32
|
+
[QMetryToolsHandlers.FETCH_TEST_SUITES]: fetchTestSuites,
|
|
33
|
+
[QMetryToolsHandlers.FETCH_TESTSUITES_FOR_TESTCASE]: fetchTestSuitesForTestCase,
|
|
34
|
+
[QMetryToolsHandlers.LINK_TESTCASES_TO_TESTSUITE]: linkTestCasesToTestSuite,
|
|
35
|
+
[QMetryToolsHandlers.REQUIREMENTS_LINKED_TESTCASES_TO_TESTSUITE]: reqLinkedTestCasesToTestSuite,
|
|
36
|
+
[QMetryToolsHandlers.FETCH_TESTCASES_BY_TESTSUITE]: fetchTestCasesByTestSuite,
|
|
37
|
+
[QMetryToolsHandlers.FETCH_EXECUTIONS_BY_TESTSUITE]: fetchExecutionsByTestSuite,
|
|
38
|
+
[QMetryToolsHandlers.BULK_UPDATE_EXECUTION_STATUS]: bulkUpdateExecutionStatus,
|
|
39
|
+
[QMetryToolsHandlers.FETCH_TESTCASE_RUNS_BY_TESTSUITE_RUN]: fetchTestCaseRunsByTestSuiteRun,
|
|
40
|
+
[QMetryToolsHandlers.FETCH_LINKED_ISSUES_BY_TESTCASE_RUN]: fetchLinkedIssuesByTestCaseRun,
|
|
41
|
+
[QMetryToolsHandlers.FETCH_ISSUES_LINKED_TO_TESTCASE]: fetchIssuesLinkedToTestCase,
|
|
42
|
+
[QMetryToolsHandlers.CREATE_ISSUE]: createIssue,
|
|
43
|
+
[QMetryToolsHandlers.UPDATE_ISSUE]: updateIssue,
|
|
44
|
+
[QMetryToolsHandlers.FETCH_ISSUES]: fetchIssues,
|
|
45
|
+
[QMetryToolsHandlers.LINK_ISSUES_TO_TESTCASE_RUN]: linkIssuesToTestcaseRun,
|
|
46
|
+
[QMetryToolsHandlers.LINK_PLATFORMS_TO_TESTSUITE]: linkPlatformsToTestSuite,
|
|
47
|
+
[QMetryToolsHandlers.IMPORT_AUTOMATION_RESULTS]: importAutomationResults,
|
|
48
|
+
[QMetryToolsHandlers.FETCH_AUTOMATION_STATUS]: getAutomationStatus
|
|
49
|
+
};
|
|
50
|
+
export {
|
|
51
|
+
QMETRY_HANDLER_MAP
|
|
49
52
|
};
|