@skyramp/mcp 0.0.63-rc.7 → 0.0.63
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/prompts/testbot/testbot-prompts.js +2 -2
- package/build/services/TestExecutionService.js +1 -1
- package/build/tools/generate-tests/generateContractRestTool.js +56 -8
- package/build/tools/generate-tests/generateMockRestTool.js +4 -1
- package/build/tools/submitReportTool.js +1 -1
- package/build/tools/submitReportTool.test.js +2 -2
- package/package.json +2 -2
|
@@ -170,8 +170,8 @@ Call \`skyramp_submit_report\` with \`summaryOutputFile\`: "${summaryOutputFile}
|
|
|
170
170
|
|
|
171
171
|
**nextSteps** — actionable next steps when test failures suggest misconfiguration.
|
|
172
172
|
Each entry must be a single-line string (no embedded newlines).
|
|
173
|
-
If multiple tests fail with 404 NOT_FOUND or connection refused on endpoints that ARE defined in the diff, add: "Some endpoints returned 404 — verify your \`
|
|
174
|
-
If tests fail with 401/403 on endpoints that require auth, add a step about \`
|
|
173
|
+
If multiple tests fail with 404 NOT_FOUND or connection refused on endpoints that ARE defined in the diff, add: "Some endpoints returned 404 — verify your \`targetSetupCommand\` deploys the PR branch and \`targetReadyCheckCommand\` confirms the service is healthy."
|
|
174
|
+
If tests fail with 401/403 on endpoints that require auth, add a step about \`authTokenCommand\`.
|
|
175
175
|
Only add next steps for systemic patterns (3+ tests with the same error class), not individual failures.
|
|
176
176
|
|
|
177
177
|
**businessCaseAnalysis** — 1-2 sentences describing what user-facing interactions this PR
|
|
@@ -8,7 +8,7 @@ import { logger } from "../utils/logger.js";
|
|
|
8
8
|
import { buildContainerEnv } from "./containerEnv.js";
|
|
9
9
|
const DEFAULT_TIMEOUT = 300000; // 5 minutes
|
|
10
10
|
const MAX_CONCURRENT_EXECUTIONS = 5;
|
|
11
|
-
export const EXECUTOR_DOCKER_IMAGE = "skyramp/executor:v1.3.
|
|
11
|
+
export const EXECUTOR_DOCKER_IMAGE = "skyramp/executor:v1.3.15";
|
|
12
12
|
const DOCKER_PLATFORM = "linux/amd64";
|
|
13
13
|
const EXECUTION_PROGRESS_INTERVAL = 10000; // 10 seconds between progress updates during execution
|
|
14
14
|
// Temp file with valid empty JSON — used instead of /dev/null for .json config files
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "path";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
import { baseTestSchema, TestType } from "../../types/TestTypes.js";
|
|
3
4
|
import { TestGenerationService, } from "../../services/TestGenerationService.js";
|
|
@@ -30,11 +31,31 @@ const contractTestSchema = {
|
|
|
30
31
|
providerOutput: z
|
|
31
32
|
.string()
|
|
32
33
|
.optional()
|
|
33
|
-
.
|
|
34
|
+
.refine((val) => {
|
|
35
|
+
if (!val || val === "")
|
|
36
|
+
return true;
|
|
37
|
+
const validExtensions = [".py", ".ts", ".js", ".java"];
|
|
38
|
+
return validExtensions.some((ext) => val.endsWith(ext));
|
|
39
|
+
}, { message: "Output file must have one of these extensions: .py, .ts, .js, .java" })
|
|
40
|
+
.describe("Output file for the generated provider contract test. " +
|
|
41
|
+
"For Playwright framework, the file must match *.spec.ts so Playwright can discover it " +
|
|
42
|
+
"(e.g. contract_provider_orders.spec.ts). " +
|
|
43
|
+
"For other frameworks (pytest, junit), standard extensions are fine (.py, .java). " +
|
|
44
|
+
"Optional — when omitted, Skyramp generates a default name."),
|
|
34
45
|
consumerOutput: z
|
|
35
46
|
.string()
|
|
36
47
|
.optional()
|
|
37
|
-
.
|
|
48
|
+
.refine((val) => {
|
|
49
|
+
if (!val || val === "")
|
|
50
|
+
return true;
|
|
51
|
+
const validExtensions = [".py", ".ts", ".js", ".java"];
|
|
52
|
+
return validExtensions.some((ext) => val.endsWith(ext));
|
|
53
|
+
}, { message: "Output file must have one of these extensions: .py, .ts, .js, .java" })
|
|
54
|
+
.describe("Output file for the generated consumer contract test. " +
|
|
55
|
+
"For Playwright framework, the file must match *.spec.ts so Playwright can discover it " +
|
|
56
|
+
"(e.g. contract_consumer_orders.spec.ts). " +
|
|
57
|
+
"For other frameworks (pytest, junit), standard extensions are fine (.py, .java). " +
|
|
58
|
+
"Optional — when omitted, Skyramp generates a default name."),
|
|
38
59
|
parentRequestData: z
|
|
39
60
|
.record(z.string(), z.string())
|
|
40
61
|
.optional()
|
|
@@ -55,6 +76,13 @@ const contractTestSchema = {
|
|
|
55
76
|
"The value is the expected HTTP status code string for the provisioning call that creates that parent resource. " +
|
|
56
77
|
"For example: {\"product_id\": \"201\"}. " +
|
|
57
78
|
"Requires apiSchema. Not allowed with consumerMode or skipProvisionParents."),
|
|
79
|
+
parentFormParams: z
|
|
80
|
+
.record(z.string(), z.string())
|
|
81
|
+
.optional()
|
|
82
|
+
.describe("Map of form parameters for provisioning parent resources. " +
|
|
83
|
+
"Key is the path param variable name (e.g. 'product_id'); " +
|
|
84
|
+
"value is comma-separated key=value pairs (e.g. 'field1=val1,field2=val2'). " +
|
|
85
|
+
"Requires apiSchema. Not allowed with consumerMode or skipProvisionParents."),
|
|
58
86
|
skipProvisionParents: z
|
|
59
87
|
.boolean()
|
|
60
88
|
.default(false)
|
|
@@ -126,9 +154,9 @@ ${sections.join("\n")}
|
|
|
126
154
|
if (errList.isError)
|
|
127
155
|
return errList;
|
|
128
156
|
const errors = [];
|
|
129
|
-
if ((params.parentRequestData || params.parentStatusCode) &&
|
|
157
|
+
if ((params.parentRequestData || params.parentStatusCode || params.parentFormParams) &&
|
|
130
158
|
!params.apiSchema) {
|
|
131
|
-
errors.push("parentRequestData and
|
|
159
|
+
errors.push("parentRequestData, parentStatusCode, and parentFormParams are only allowed when apiSchema is provided.");
|
|
132
160
|
}
|
|
133
161
|
if (params.providerOutput && !params.providerMode) {
|
|
134
162
|
errors.push("providerOutput is only valid when providerMode is enabled.");
|
|
@@ -136,15 +164,34 @@ ${sections.join("\n")}
|
|
|
136
164
|
if (params.consumerOutput && !params.consumerMode) {
|
|
137
165
|
errors.push("consumerOutput is only valid when consumerMode is enabled.");
|
|
138
166
|
}
|
|
139
|
-
if (params.consumerMode && (params.parentRequestData || params.parentStatusCode)) {
|
|
140
|
-
errors.push("parentRequestData and
|
|
167
|
+
if (params.consumerMode && (params.parentRequestData || params.parentStatusCode || params.parentFormParams)) {
|
|
168
|
+
errors.push("parentRequestData, parentStatusCode, and parentFormParams are not allowed when consumerMode is enabled.");
|
|
169
|
+
}
|
|
170
|
+
const fw = (params.framework ?? "").toLowerCase();
|
|
171
|
+
if (fw === "playwright") {
|
|
172
|
+
const specPattern = /\.(spec|test)\.[tj]s$/;
|
|
173
|
+
for (const [field, value] of [
|
|
174
|
+
["providerOutput", params.providerOutput],
|
|
175
|
+
["consumerOutput", params.consumerOutput],
|
|
176
|
+
]) {
|
|
177
|
+
if (value && value !== "") {
|
|
178
|
+
if (!specPattern.test(value)) {
|
|
179
|
+
const parsed = path.parse(value);
|
|
180
|
+
const suggested = /\.[tj]s$/.test(parsed.ext)
|
|
181
|
+
? value.replace(/\.[tj]s$/, ".spec.ts")
|
|
182
|
+
: value + ".spec.ts";
|
|
183
|
+
errors.push(`Error: Playwright requires test files to match *.{spec}.{ts,js} (got "${value}" for ${field}). ` +
|
|
184
|
+
`Rename to e.g. ${suggested} so Playwright can discover it.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
141
188
|
}
|
|
142
189
|
if (params.skipProvisionParents) {
|
|
143
190
|
if (!params.providerMode) {
|
|
144
191
|
errors.push("skipProvisionParents requires providerMode to be enabled.");
|
|
145
192
|
}
|
|
146
|
-
if (params.parentRequestData || params.parentStatusCode) {
|
|
147
|
-
errors.push("parentRequestData and
|
|
193
|
+
if (params.parentRequestData || params.parentStatusCode || params.parentFormParams) {
|
|
194
|
+
errors.push("parentRequestData, parentStatusCode, and parentFormParams are not allowed when skipProvisionParents is enabled.");
|
|
148
195
|
}
|
|
149
196
|
}
|
|
150
197
|
if (errors.length > 0) {
|
|
@@ -166,6 +213,7 @@ ${sections.join("\n")}
|
|
|
166
213
|
consumerOutput: params.consumerOutput,
|
|
167
214
|
parentRequestData: params.parentRequestData,
|
|
168
215
|
parentStatusCode: params.parentStatusCode,
|
|
216
|
+
parentFormParams: params.parentFormParams,
|
|
169
217
|
skipProvisionParents: params.skipProvisionParents,
|
|
170
218
|
};
|
|
171
219
|
}
|
|
@@ -128,7 +128,10 @@ This file must:
|
|
|
128
128
|
method: params.method,
|
|
129
129
|
apiSchema: params.apiSchema ? [params.apiSchema] : [],
|
|
130
130
|
language: params.language ?? "python",
|
|
131
|
-
framework: params.framework ??
|
|
131
|
+
framework: params.framework ??
|
|
132
|
+
(params.language === "typescript" || params.language === "javascript"
|
|
133
|
+
? "playwright"
|
|
134
|
+
: ""),
|
|
132
135
|
output: params.output,
|
|
133
136
|
outputDir: params.outputDir,
|
|
134
137
|
force: params.force ?? true,
|
|
@@ -88,7 +88,7 @@ export function registerSubmitReportTool(server) {
|
|
|
88
88
|
.optional()
|
|
89
89
|
.default([])
|
|
90
90
|
.describe("Actionable next steps for the user. Populate when test failures suggest misconfiguration " +
|
|
91
|
-
"(e.g. 404s on endpoints that exist in the diff → check
|
|
91
|
+
"(e.g. 404s on endpoints that exist in the diff → check targetSetupCommand)."),
|
|
92
92
|
commitMessage: z
|
|
93
93
|
.string()
|
|
94
94
|
.optional()
|
|
@@ -170,12 +170,12 @@ describe("registerSubmitReportTool", () => {
|
|
|
170
170
|
const outputFile = path.join(tmpDir, "report.json");
|
|
171
171
|
const result = await handler({
|
|
172
172
|
...sampleReportParams(outputFile),
|
|
173
|
-
nextSteps: ["Check your
|
|
173
|
+
nextSteps: ["Check your targetSetupCommand — endpoints returned 404"],
|
|
174
174
|
});
|
|
175
175
|
expect(result.isError).toBeUndefined();
|
|
176
176
|
const written = JSON.parse(await fs.readFile(outputFile, "utf-8"));
|
|
177
177
|
expect(written.nextSteps).toEqual([
|
|
178
|
-
"Check your
|
|
178
|
+
"Check your targetSetupCommand — endpoints returned 404",
|
|
179
179
|
]);
|
|
180
180
|
});
|
|
181
181
|
it("defaults nextSteps to empty array when omitted", async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyramp/mcp",
|
|
3
|
-
"version": "0.0.63
|
|
3
|
+
"version": "0.0.63",
|
|
4
4
|
"main": "build/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
48
48
|
"@playwright/test": "^1.55.0",
|
|
49
|
-
"@skyramp/skyramp": "1.3.
|
|
49
|
+
"@skyramp/skyramp": "1.3.15",
|
|
50
50
|
"dockerode": "^4.0.6",
|
|
51
51
|
"fast-glob": "^3.3.3",
|
|
52
52
|
"simple-git": "^3.30.0",
|