@skyramp/mcp 0.2.8 → 0.2.150-rc.ldw
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/commands/commandLibrary.d.ts +1 -0
- package/build/commands/commandLibrary.js +20 -14
- package/build/commands/commandLibrary.test.d.ts +1 -0
- package/build/commands/commandLibrary.test.js +59 -0
- package/build/commands/localDevTestChangesCommand.d.ts +15 -0
- package/build/commands/localDevTestChangesCommand.js +188 -0
- package/build/index.js +77 -13
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +9 -8
- package/build/prompts/local-dev/local-dev-plan.d.ts +25 -0
- package/build/prompts/local-dev/local-dev-plan.js +419 -0
- package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
- package/build/prompts/local-dev/local-dev-prompts.js +157 -0
- package/build/prompts/prompt-utils.d.ts +8 -0
- package/build/prompts/prompt-utils.js +33 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +3 -1
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +3 -1
- package/build/prompts/sut-setup/shared.d.ts +20 -0
- package/build/prompts/sut-setup/shared.js +69 -7
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -28
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +16 -1
- package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
- package/build/prompts/testbot/testbot-prompts.js +4 -34
- package/build/resources/testbotResource.js +2 -1
- package/build/services/AnalyticsService.d.ts +1 -1
- package/build/services/TestExecutionService.d.ts +2 -1
- package/build/services/TestExecutionService.js +15 -10
- package/build/services/TestExecutionService.test.js +75 -1
- package/build/services/TestGenerationService.d.ts +2 -2
- package/build/tool-phases.js +4 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.js +47 -18
- package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
- package/build/tools/enrichTestWithMocksTool.js +726 -0
- package/build/tools/enrichTestWithMocksTool.test.d.ts +1 -0
- package/build/tools/enrichTestWithMocksTool.test.js +266 -0
- package/build/tools/executeSkyrampTestTool.d.ts +4 -0
- package/build/tools/executeSkyrampTestTool.js +48 -24
- package/build/tools/executeSkyrampTestTool.test.d.ts +1 -0
- package/build/tools/executeSkyrampTestTool.test.js +16 -0
- package/build/tools/generate-tests/batchMockGenerationTool.d.ts +85 -0
- package/build/tools/generate-tests/batchMockGenerationTool.js +432 -0
- package/build/tools/generate-tests/generateContractRestTool.js +2 -2
- package/build/tools/generate-tests/generateMockRestTool.d.ts +129 -6
- package/build/tools/generate-tests/generateMockRestTool.js +234 -22
- package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
- package/build/tools/generateEnrichedIntegrationTestTool.d.ts +24 -0
- package/build/tools/generateEnrichedIntegrationTestTool.js +225 -0
- package/build/tools/generateEnrichedIntegrationTestTool.test.d.ts +1 -0
- package/build/tools/generateEnrichedIntegrationTestTool.test.js +44 -0
- package/build/tools/localDevWorkflowFixes.test.d.ts +1 -0
- package/build/tools/localDevWorkflowFixes.test.js +255 -0
- package/build/tools/one-click/oneClickTool.d.ts +10 -0
- package/build/tools/one-click/oneClickTool.js +177 -21
- package/build/tools/one-click/oneClickTool.test.d.ts +1 -0
- package/build/tools/one-click/oneClickTool.test.js +172 -0
- package/build/tools/preflightMockCheckTool.d.ts +2 -0
- package/build/tools/preflightMockCheckTool.js +96 -0
- package/build/tools/submitReportTool.d.ts +14 -14
- package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
- package/build/tools/test-management/analyzeChangesTool.js +59 -38
- package/build/tools/trace/startTraceCollectionTool.js +3 -3
- package/build/tools/workspace/initializeWorkspaceTool.js +2 -9
- package/build/tools/workspace/initializeWorkspaceTool.test.js +9 -4
- package/build/types/OneClickCommands.d.ts +1 -1
- package/build/types/RepositoryAnalysis.d.ts +117 -0
- package/build/types/RepositoryAnalysis.js +16 -2
- package/build/types/TestExecution.d.ts +1 -0
- package/build/types/TestTypes.d.ts +20 -8
- package/build/types/TestTypes.js +19 -5
- package/build/utils/analyze-openapi.js +18 -1
- package/build/utils/analyze-openapi.test.d.ts +1 -0
- package/build/utils/analyze-openapi.test.js +19 -0
- package/build/utils/branchDiff.d.ts +17 -1
- package/build/utils/branchDiff.js +96 -14
- package/build/utils/branchDiff.test.d.ts +1 -0
- package/build/utils/branchDiff.test.js +109 -0
- package/build/utils/docker.test.js +1 -1
- package/build/utils/featureFlags.d.ts +20 -1
- package/build/utils/featureFlags.js +26 -2
- package/build/utils/featureFlags.test.js +57 -2
- package/build/utils/grpcMockValidation.d.ts +1 -0
- package/build/utils/grpcMockValidation.js +49 -0
- package/build/utils/grpcMockValidation.test.d.ts +1 -0
- package/build/utils/grpcMockValidation.test.js +41 -0
- package/build/utils/httpMethodValidation.d.ts +4 -0
- package/build/utils/httpMethodValidation.js +13 -0
- package/build/utils/mockCompatibility.d.ts +49 -0
- package/build/utils/mockCompatibility.js +82 -0
- package/build/utils/mockCompatibility.test.d.ts +1 -0
- package/build/utils/mockCompatibility.test.js +79 -0
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/workspace/workspace.d.ts +49 -35
- package/build/workspace/workspace.js +10 -5
- package/build/workspace/workspace.test.js +65 -6
- package/package.json +2 -2
|
@@ -36,7 +36,9 @@ describe("initializeWorkspaceTool", () => {
|
|
|
36
36
|
// Build a mock WorkspaceConfigManager
|
|
37
37
|
mockManager = {
|
|
38
38
|
exists: jest.fn().mockResolvedValue(false),
|
|
39
|
-
getConfigPath: jest
|
|
39
|
+
getConfigPath: jest
|
|
40
|
+
.fn()
|
|
41
|
+
.mockReturnValue(path.join(tmpDir, ".skyramp/workspace.yml")),
|
|
40
42
|
initialize: jest.fn().mockResolvedValue({ workspace: {}, services: [] }),
|
|
41
43
|
updateMetadata: jest.fn().mockImplementation(async (data) => ({
|
|
42
44
|
workspace: {},
|
|
@@ -95,7 +97,6 @@ describe("initializeWorkspaceTool", () => {
|
|
|
95
97
|
expect(result.content[0].text).toContain("Workspace initialized");
|
|
96
98
|
expect(mockManager.initialize).toHaveBeenCalled();
|
|
97
99
|
expect(mockManager.updateMetadata).toHaveBeenCalledWith(expect.objectContaining({
|
|
98
|
-
mcpVersion: expect.any(String),
|
|
99
100
|
executorVersion: expect.any(String),
|
|
100
101
|
}));
|
|
101
102
|
});
|
|
@@ -103,7 +104,9 @@ describe("initializeWorkspaceTool", () => {
|
|
|
103
104
|
mockManager.exists.mockResolvedValue(true);
|
|
104
105
|
const result = await handler({
|
|
105
106
|
workspacePath: tmpDir,
|
|
106
|
-
services: [
|
|
107
|
+
services: [
|
|
108
|
+
{ serviceName: "svc", language: "python", testDirectory: "tests" },
|
|
109
|
+
],
|
|
107
110
|
scanToken: "valid-token",
|
|
108
111
|
force: false,
|
|
109
112
|
});
|
|
@@ -114,7 +117,9 @@ describe("initializeWorkspaceTool", () => {
|
|
|
114
117
|
validateAndConsumeScanToken.mockReturnValue(false);
|
|
115
118
|
const result = await handler({
|
|
116
119
|
workspacePath: tmpDir,
|
|
117
|
-
services: [
|
|
120
|
+
services: [
|
|
121
|
+
{ serviceName: "svc", language: "python", testDirectory: "tests" },
|
|
122
|
+
],
|
|
118
123
|
scanToken: "bad-token",
|
|
119
124
|
force: false,
|
|
120
125
|
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and executed by the coding assistant following the workflow instructions.
|
|
5
5
|
*/
|
|
6
6
|
/** Unique identifier for a one-click command */
|
|
7
|
-
export type OneClickCommandId = "test_given_endpoint_comprehensively" | "full_repo_scan_recommend_generate_and_execute_top_n_tests";
|
|
7
|
+
export type OneClickCommandId = "test_given_endpoint_comprehensively" | "full_repo_scan_recommend_generate_and_execute_top_n_tests" | "local_dev_test_changes";
|
|
8
8
|
/** Metadata for intent recognition by coding assistants */
|
|
9
9
|
export interface CommandIntentMetadata {
|
|
10
10
|
/** Context indicators describing when to use and when NOT to use this workflow */
|
|
@@ -145,6 +145,22 @@ export interface BranchDiffContext {
|
|
|
145
145
|
affectedServices: string[];
|
|
146
146
|
summary?: string;
|
|
147
147
|
}
|
|
148
|
+
export interface RouteDiscoveryInfo {
|
|
149
|
+
/** Files the LLM should inspect to infer endpoint methods and paths from source. */
|
|
150
|
+
candidateFiles: string[];
|
|
151
|
+
/** Static scanner output. Best-effort hints only, not an authoritative catalog. */
|
|
152
|
+
staticHints: Array<{
|
|
153
|
+
path: string;
|
|
154
|
+
methods: string[];
|
|
155
|
+
sourceFile: string;
|
|
156
|
+
}>;
|
|
157
|
+
/** OpenAPI paths from workspace config. Authoritative when specFetchSucceeded is true. */
|
|
158
|
+
openApiPaths: string[];
|
|
159
|
+
/** Router/module entry points that help the LLM reconstruct full mounted paths. */
|
|
160
|
+
routerMountContext: string[];
|
|
161
|
+
/** Full diff file path when available; read this to ground endpoint extraction in changed code. */
|
|
162
|
+
diffFilePath?: string;
|
|
163
|
+
}
|
|
148
164
|
export interface RepositoryAnalysis {
|
|
149
165
|
metadata: AnalysisMetadata;
|
|
150
166
|
projectClassification: ProjectClassification;
|
|
@@ -155,6 +171,7 @@ export interface RepositoryAnalysis {
|
|
|
155
171
|
authentication: AuthenticationInfo;
|
|
156
172
|
infrastructure: InfrastructureInfo;
|
|
157
173
|
existingTests: ExistingTestInfo;
|
|
174
|
+
routeDiscovery?: RouteDiscoveryInfo;
|
|
158
175
|
branchDiffContext?: BranchDiffContext;
|
|
159
176
|
}
|
|
160
177
|
export interface AnalysisMetadata {
|
|
@@ -1423,6 +1440,45 @@ export declare const branchDiffContextSchema: z.ZodObject<{
|
|
|
1423
1440
|
}[] | undefined;
|
|
1424
1441
|
summary?: string | undefined;
|
|
1425
1442
|
}>;
|
|
1443
|
+
export declare const routeDiscoveryInfoSchema: z.ZodObject<{
|
|
1444
|
+
candidateFiles: z.ZodArray<z.ZodString, "many">;
|
|
1445
|
+
staticHints: z.ZodArray<z.ZodObject<{
|
|
1446
|
+
path: z.ZodString;
|
|
1447
|
+
methods: z.ZodArray<z.ZodString, "many">;
|
|
1448
|
+
sourceFile: z.ZodString;
|
|
1449
|
+
}, "strip", z.ZodTypeAny, {
|
|
1450
|
+
path: string;
|
|
1451
|
+
sourceFile: string;
|
|
1452
|
+
methods: string[];
|
|
1453
|
+
}, {
|
|
1454
|
+
path: string;
|
|
1455
|
+
sourceFile: string;
|
|
1456
|
+
methods: string[];
|
|
1457
|
+
}>, "many">;
|
|
1458
|
+
openApiPaths: z.ZodArray<z.ZodString, "many">;
|
|
1459
|
+
routerMountContext: z.ZodArray<z.ZodString, "many">;
|
|
1460
|
+
diffFilePath: z.ZodOptional<z.ZodString>;
|
|
1461
|
+
}, "strip", z.ZodTypeAny, {
|
|
1462
|
+
candidateFiles: string[];
|
|
1463
|
+
staticHints: {
|
|
1464
|
+
path: string;
|
|
1465
|
+
sourceFile: string;
|
|
1466
|
+
methods: string[];
|
|
1467
|
+
}[];
|
|
1468
|
+
openApiPaths: string[];
|
|
1469
|
+
routerMountContext: string[];
|
|
1470
|
+
diffFilePath?: string | undefined;
|
|
1471
|
+
}, {
|
|
1472
|
+
candidateFiles: string[];
|
|
1473
|
+
staticHints: {
|
|
1474
|
+
path: string;
|
|
1475
|
+
sourceFile: string;
|
|
1476
|
+
methods: string[];
|
|
1477
|
+
}[];
|
|
1478
|
+
openApiPaths: string[];
|
|
1479
|
+
routerMountContext: string[];
|
|
1480
|
+
diffFilePath?: string | undefined;
|
|
1481
|
+
}>;
|
|
1426
1482
|
export declare const analysisMetadataSchema: z.ZodObject<{
|
|
1427
1483
|
repositoryName: z.ZodString;
|
|
1428
1484
|
analysisDate: z.ZodString;
|
|
@@ -2440,6 +2496,45 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2440
2496
|
estimatedCoverage?: number | undefined;
|
|
2441
2497
|
relevantExternalTestPaths?: string[] | undefined;
|
|
2442
2498
|
}>;
|
|
2499
|
+
routeDiscovery: z.ZodOptional<z.ZodObject<{
|
|
2500
|
+
candidateFiles: z.ZodArray<z.ZodString, "many">;
|
|
2501
|
+
staticHints: z.ZodArray<z.ZodObject<{
|
|
2502
|
+
path: z.ZodString;
|
|
2503
|
+
methods: z.ZodArray<z.ZodString, "many">;
|
|
2504
|
+
sourceFile: z.ZodString;
|
|
2505
|
+
}, "strip", z.ZodTypeAny, {
|
|
2506
|
+
path: string;
|
|
2507
|
+
sourceFile: string;
|
|
2508
|
+
methods: string[];
|
|
2509
|
+
}, {
|
|
2510
|
+
path: string;
|
|
2511
|
+
sourceFile: string;
|
|
2512
|
+
methods: string[];
|
|
2513
|
+
}>, "many">;
|
|
2514
|
+
openApiPaths: z.ZodArray<z.ZodString, "many">;
|
|
2515
|
+
routerMountContext: z.ZodArray<z.ZodString, "many">;
|
|
2516
|
+
diffFilePath: z.ZodOptional<z.ZodString>;
|
|
2517
|
+
}, "strip", z.ZodTypeAny, {
|
|
2518
|
+
candidateFiles: string[];
|
|
2519
|
+
staticHints: {
|
|
2520
|
+
path: string;
|
|
2521
|
+
sourceFile: string;
|
|
2522
|
+
methods: string[];
|
|
2523
|
+
}[];
|
|
2524
|
+
openApiPaths: string[];
|
|
2525
|
+
routerMountContext: string[];
|
|
2526
|
+
diffFilePath?: string | undefined;
|
|
2527
|
+
}, {
|
|
2528
|
+
candidateFiles: string[];
|
|
2529
|
+
staticHints: {
|
|
2530
|
+
path: string;
|
|
2531
|
+
sourceFile: string;
|
|
2532
|
+
methods: string[];
|
|
2533
|
+
}[];
|
|
2534
|
+
openApiPaths: string[];
|
|
2535
|
+
routerMountContext: string[];
|
|
2536
|
+
diffFilePath?: string | undefined;
|
|
2537
|
+
}>>;
|
|
2443
2538
|
branchDiffContext: z.ZodOptional<z.ZodObject<{
|
|
2444
2539
|
currentBranch: z.ZodString;
|
|
2445
2540
|
baseBranch: z.ZodString;
|
|
@@ -2768,6 +2863,17 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2768
2863
|
estimatedCoverage?: number | undefined;
|
|
2769
2864
|
relevantExternalTestPaths?: string[] | undefined;
|
|
2770
2865
|
};
|
|
2866
|
+
routeDiscovery?: {
|
|
2867
|
+
candidateFiles: string[];
|
|
2868
|
+
staticHints: {
|
|
2869
|
+
path: string;
|
|
2870
|
+
sourceFile: string;
|
|
2871
|
+
methods: string[];
|
|
2872
|
+
}[];
|
|
2873
|
+
openApiPaths: string[];
|
|
2874
|
+
routerMountContext: string[];
|
|
2875
|
+
diffFilePath?: string | undefined;
|
|
2876
|
+
} | undefined;
|
|
2771
2877
|
branchDiffContext?: {
|
|
2772
2878
|
currentBranch: string;
|
|
2773
2879
|
baseBranch: string;
|
|
@@ -2970,6 +3076,17 @@ export declare const repositoryAnalysisSchema: z.ZodObject<{
|
|
|
2970
3076
|
estimatedCoverage?: number | undefined;
|
|
2971
3077
|
relevantExternalTestPaths?: string[] | undefined;
|
|
2972
3078
|
};
|
|
3079
|
+
routeDiscovery?: {
|
|
3080
|
+
candidateFiles: string[];
|
|
3081
|
+
staticHints: {
|
|
3082
|
+
path: string;
|
|
3083
|
+
sourceFile: string;
|
|
3084
|
+
methods: string[];
|
|
3085
|
+
}[];
|
|
3086
|
+
openApiPaths: string[];
|
|
3087
|
+
routerMountContext: string[];
|
|
3088
|
+
diffFilePath?: string | undefined;
|
|
3089
|
+
} | undefined;
|
|
2973
3090
|
branchDiffContext?: {
|
|
2974
3091
|
currentBranch: string;
|
|
2975
3092
|
baseBranch: string;
|
|
@@ -128,17 +128,30 @@ export const branchDiffContextSchema = z.object({
|
|
|
128
128
|
changeType: z.enum(["added", "modified", "removed"]),
|
|
129
129
|
})),
|
|
130
130
|
})),
|
|
131
|
-
removedEndpoints: z
|
|
131
|
+
removedEndpoints: z
|
|
132
|
+
.array(z.object({
|
|
132
133
|
path: z.string(),
|
|
133
134
|
methods: z.array(z.object({
|
|
134
135
|
method: z.string(),
|
|
135
136
|
sourceFile: z.string(),
|
|
136
137
|
changeType: z.literal("removed"),
|
|
137
138
|
})),
|
|
138
|
-
}))
|
|
139
|
+
}))
|
|
140
|
+
.optional(),
|
|
139
141
|
affectedServices: z.array(z.string()),
|
|
140
142
|
summary: z.string().optional(),
|
|
141
143
|
});
|
|
144
|
+
export const routeDiscoveryInfoSchema = z.object({
|
|
145
|
+
candidateFiles: z.array(z.string()),
|
|
146
|
+
staticHints: z.array(z.object({
|
|
147
|
+
path: z.string(),
|
|
148
|
+
methods: z.array(z.string()),
|
|
149
|
+
sourceFile: z.string(),
|
|
150
|
+
})),
|
|
151
|
+
openApiPaths: z.array(z.string()),
|
|
152
|
+
routerMountContext: z.array(z.string()),
|
|
153
|
+
diffFilePath: z.string().optional(),
|
|
154
|
+
});
|
|
142
155
|
export const analysisMetadataSchema = z.object({
|
|
143
156
|
repositoryName: z.string(),
|
|
144
157
|
analysisDate: z.string(),
|
|
@@ -239,5 +252,6 @@ export const repositoryAnalysisSchema = z.object({
|
|
|
239
252
|
estimatedCoverage: z.number().optional(),
|
|
240
253
|
relevantExternalTestPaths: z.array(z.string()).optional(),
|
|
241
254
|
}),
|
|
255
|
+
routeDiscovery: routeDiscoveryInfoSchema.optional(),
|
|
242
256
|
branchDiffContext: branchDiffContextSchema.optional(),
|
|
243
257
|
});
|
|
@@ -14,8 +14,17 @@ export declare enum TestType {
|
|
|
14
14
|
LOAD = "load",
|
|
15
15
|
INTEGRATION = "integration",
|
|
16
16
|
E2E = "e2e",
|
|
17
|
-
UI = "ui"
|
|
18
|
-
|
|
17
|
+
UI = "ui"
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Mock is not a test type — mock files are deployed via apply_mock(),
|
|
21
|
+
* not executed as tests. Kept as a standalone constant for mock generation.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MOCK_TYPE: "mock";
|
|
24
|
+
export declare enum MockProtocol {
|
|
25
|
+
Rest = "rest",
|
|
26
|
+
Grpc = "grpc",
|
|
27
|
+
Kafka = "kafka"
|
|
19
28
|
}
|
|
20
29
|
export declare enum HttpMethod {
|
|
21
30
|
GET = "GET",
|
|
@@ -29,8 +38,11 @@ export declare enum HttpMethod {
|
|
|
29
38
|
export declare enum RuntimeEnvironment {
|
|
30
39
|
LOCAL = "local",
|
|
31
40
|
DOCKER = "docker",
|
|
32
|
-
KUBERNETES = "
|
|
41
|
+
KUBERNETES = "k8s"
|
|
33
42
|
}
|
|
43
|
+
export declare const runtimeEnvironmentSchema: z.ZodNativeEnum<typeof RuntimeEnvironment>;
|
|
44
|
+
export declare const runtimeEnvironmentInputSchema: z.ZodEffects<z.ZodNativeEnum<typeof RuntimeEnvironment>, RuntimeEnvironment, unknown>;
|
|
45
|
+
export declare function normalizeRuntimeEnvironment(value: RuntimeEnvironment | "kubernetes"): RuntimeEnvironment;
|
|
34
46
|
export interface TestConfig {
|
|
35
47
|
testType: TestType;
|
|
36
48
|
toolName: string;
|
|
@@ -49,7 +61,7 @@ export declare const languageSchema: z.ZodObject<{
|
|
|
49
61
|
}>;
|
|
50
62
|
export declare const baseSchema: z.ZodObject<{
|
|
51
63
|
deployDashboard: z.ZodDefault<z.ZodBoolean>;
|
|
52
|
-
runtime: z.ZodDefault<z.ZodNativeEnum<typeof RuntimeEnvironment>>;
|
|
64
|
+
runtime: z.ZodDefault<z.ZodEffects<z.ZodNativeEnum<typeof RuntimeEnvironment>, RuntimeEnvironment, unknown>>;
|
|
53
65
|
dockerNetwork: z.ZodDefault<z.ZodString>;
|
|
54
66
|
dockerWorkerPort: z.ZodDefault<z.ZodNumber>;
|
|
55
67
|
k8sNamespace: z.ZodDefault<z.ZodString>;
|
|
@@ -91,7 +103,7 @@ export declare const baseSchema: z.ZodObject<{
|
|
|
91
103
|
outputDir: string;
|
|
92
104
|
prompt: string;
|
|
93
105
|
deployDashboard?: boolean | undefined;
|
|
94
|
-
runtime?:
|
|
106
|
+
runtime?: unknown;
|
|
95
107
|
dockerNetwork?: string | undefined;
|
|
96
108
|
dockerWorkerPort?: number | undefined;
|
|
97
109
|
k8sNamespace?: string | undefined;
|
|
@@ -129,7 +141,7 @@ export declare const basePlaywrightSchema: z.ZodObject<{
|
|
|
129
141
|
}>;
|
|
130
142
|
export declare const baseTraceSchema: z.ZodObject<{
|
|
131
143
|
deployDashboard: z.ZodDefault<z.ZodBoolean>;
|
|
132
|
-
runtime: z.ZodDefault<z.ZodNativeEnum<typeof RuntimeEnvironment>>;
|
|
144
|
+
runtime: z.ZodDefault<z.ZodEffects<z.ZodNativeEnum<typeof RuntimeEnvironment>, RuntimeEnvironment, unknown>>;
|
|
133
145
|
dockerNetwork: z.ZodDefault<z.ZodString>;
|
|
134
146
|
dockerWorkerPort: z.ZodDefault<z.ZodNumber>;
|
|
135
147
|
k8sNamespace: z.ZodDefault<z.ZodString>;
|
|
@@ -178,7 +190,7 @@ export declare const baseTraceSchema: z.ZodObject<{
|
|
|
178
190
|
prompt: string;
|
|
179
191
|
trace: string;
|
|
180
192
|
deployDashboard?: boolean | undefined;
|
|
181
|
-
runtime?:
|
|
193
|
+
runtime?: unknown;
|
|
182
194
|
dockerNetwork?: string | undefined;
|
|
183
195
|
dockerWorkerPort?: number | undefined;
|
|
184
196
|
k8sNamespace?: string | undefined;
|
|
@@ -196,7 +208,7 @@ export declare const baseTraceSchema: z.ZodObject<{
|
|
|
196
208
|
}>;
|
|
197
209
|
export declare const baseTestSchema: {
|
|
198
210
|
deployDashboard: z.ZodDefault<z.ZodBoolean>;
|
|
199
|
-
runtime: z.ZodDefault<z.ZodNativeEnum<typeof RuntimeEnvironment>>;
|
|
211
|
+
runtime: z.ZodDefault<z.ZodEffects<z.ZodNativeEnum<typeof RuntimeEnvironment>, RuntimeEnvironment, unknown>>;
|
|
200
212
|
dockerNetwork: z.ZodDefault<z.ZodString>;
|
|
201
213
|
dockerWorkerPort: z.ZodDefault<z.ZodNumber>;
|
|
202
214
|
k8sNamespace: z.ZodDefault<z.ZodString>;
|
package/build/types/TestTypes.js
CHANGED
|
@@ -17,8 +17,18 @@ export var TestType;
|
|
|
17
17
|
TestType["INTEGRATION"] = "integration";
|
|
18
18
|
TestType["E2E"] = "e2e";
|
|
19
19
|
TestType["UI"] = "ui";
|
|
20
|
-
TestType["MOCK"] = "mock";
|
|
21
20
|
})(TestType || (TestType = {}));
|
|
21
|
+
/**
|
|
22
|
+
* Mock is not a test type — mock files are deployed via apply_mock(),
|
|
23
|
+
* not executed as tests. Kept as a standalone constant for mock generation.
|
|
24
|
+
*/
|
|
25
|
+
export const MOCK_TYPE = "mock";
|
|
26
|
+
export var MockProtocol;
|
|
27
|
+
(function (MockProtocol) {
|
|
28
|
+
MockProtocol["Rest"] = "rest";
|
|
29
|
+
MockProtocol["Grpc"] = "grpc";
|
|
30
|
+
MockProtocol["Kafka"] = "kafka";
|
|
31
|
+
})(MockProtocol || (MockProtocol = {}));
|
|
22
32
|
export var HttpMethod;
|
|
23
33
|
(function (HttpMethod) {
|
|
24
34
|
HttpMethod["GET"] = "GET";
|
|
@@ -33,8 +43,13 @@ export var RuntimeEnvironment;
|
|
|
33
43
|
(function (RuntimeEnvironment) {
|
|
34
44
|
RuntimeEnvironment["LOCAL"] = "local";
|
|
35
45
|
RuntimeEnvironment["DOCKER"] = "docker";
|
|
36
|
-
RuntimeEnvironment["KUBERNETES"] = "
|
|
46
|
+
RuntimeEnvironment["KUBERNETES"] = "k8s";
|
|
37
47
|
})(RuntimeEnvironment || (RuntimeEnvironment = {}));
|
|
48
|
+
export const runtimeEnvironmentSchema = z.nativeEnum(RuntimeEnvironment);
|
|
49
|
+
export const runtimeEnvironmentInputSchema = z.preprocess((value) => (value === "kubernetes" ? RuntimeEnvironment.KUBERNETES : value), runtimeEnvironmentSchema);
|
|
50
|
+
export function normalizeRuntimeEnvironment(value) {
|
|
51
|
+
return value === "kubernetes" ? RuntimeEnvironment.KUBERNETES : value;
|
|
52
|
+
}
|
|
38
53
|
export const languageSchema = z.object({
|
|
39
54
|
language: z
|
|
40
55
|
.nativeEnum(ProgrammingLanguage)
|
|
@@ -49,10 +64,9 @@ export const baseSchema = z.object({
|
|
|
49
64
|
.boolean()
|
|
50
65
|
.default(false)
|
|
51
66
|
.describe("Whether to deploy the Skyramp dashboard for test monitoring"),
|
|
52
|
-
runtime:
|
|
53
|
-
.nativeEnum(RuntimeEnvironment)
|
|
67
|
+
runtime: runtimeEnvironmentInputSchema
|
|
54
68
|
.default(RuntimeEnvironment.LOCAL)
|
|
55
|
-
.describe("Runtime environment (docker, kubernetes
|
|
69
|
+
.describe("Runtime environment (local, docker, or k8s; accepts kubernetes as an alias)"),
|
|
56
70
|
dockerNetwork: z
|
|
57
71
|
.string()
|
|
58
72
|
.default("")
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { SkyrampClient } from "@skyramp/skyramp";
|
|
2
2
|
import { IsValidKeyValueList } from "./utils.js";
|
|
3
|
+
import { logger } from "./logger.js";
|
|
4
|
+
function isOpenApiRuntimeFailure(error) {
|
|
5
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6
|
+
return /(?:ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|socket hang up|connection refused|unavailable|timed? out)/i.test(message);
|
|
7
|
+
}
|
|
3
8
|
// Analyze OpenAPI to check for required path params
|
|
4
9
|
export async function analyzeOpenAPIWithGivenEndpoint(apiSchemaInput, uriInput, pathParamsInput) {
|
|
5
10
|
const client = new SkyrampClient();
|
|
@@ -7,7 +12,19 @@ export async function analyzeOpenAPIWithGivenEndpoint(apiSchemaInput, uriInput,
|
|
|
7
12
|
apiSchema: apiSchemaInput,
|
|
8
13
|
uri: uriInput,
|
|
9
14
|
};
|
|
10
|
-
|
|
15
|
+
let pathParamRequired;
|
|
16
|
+
try {
|
|
17
|
+
pathParamRequired = await client.analyzeOpenapi(analyzeOpenapiOptions);
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
if (isOpenApiRuntimeFailure(e)) {
|
|
21
|
+
logger.warning("Skipping OpenAPI path-param validation because schema analysis is unavailable", {
|
|
22
|
+
error: e instanceof Error ? e.message : String(e),
|
|
23
|
+
});
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
throw e;
|
|
27
|
+
}
|
|
11
28
|
if (IsValidKeyValueList(pathParamRequired)) {
|
|
12
29
|
const requiredPathParams = pathParamRequired
|
|
13
30
|
? pathParamRequired.split(",").map((p) => p.trim())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jest, describe, it, expect, beforeEach } from "@jest/globals";
|
|
2
|
+
const analyzeOpenapi = jest.fn();
|
|
3
|
+
jest.unstable_mockModule("@skyramp/skyramp", () => ({
|
|
4
|
+
SkyrampClient: jest.fn(() => ({ analyzeOpenapi })),
|
|
5
|
+
}));
|
|
6
|
+
const { analyzeOpenAPIWithGivenEndpoint } = await import("./analyze-openapi.js");
|
|
7
|
+
describe("analyzeOpenAPIWithGivenEndpoint", () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
analyzeOpenapi.mockReset();
|
|
10
|
+
});
|
|
11
|
+
it("skips path-param validation for runtime connectivity failures", async () => {
|
|
12
|
+
analyzeOpenapi.mockRejectedValue(new Error("gRPC unavailable: connection refused"));
|
|
13
|
+
await expect(analyzeOpenAPIWithGivenEndpoint("schema.yaml", "/users/{id}", "")).resolves.toBeNull();
|
|
14
|
+
});
|
|
15
|
+
it("rethrows schema errors instead of silently disabling validation", async () => {
|
|
16
|
+
analyzeOpenapi.mockRejectedValue(new Error("invalid apiSchema path: missing.yaml"));
|
|
17
|
+
await expect(analyzeOpenAPIWithGivenEndpoint("missing.yaml", "/users/{id}", "")).rejects.toThrow("invalid apiSchema path");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -15,4 +15,20 @@ export interface BranchDiffData {
|
|
|
15
15
|
* Always uses the `b/` form so renames return the new path.
|
|
16
16
|
*/
|
|
17
17
|
export declare function parseChangedFilesFromDiff(rawDiff: string): string[];
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Normalize and validate a caller-provided base branch/ref before passing it
|
|
20
|
+
* to git. Reject option-like or ambiguous values so the ref is always treated
|
|
21
|
+
* as a revision name, not as a command-line flag.
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeProvidedBaseRef(providedBaseBranch?: string): string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Compute the diff between a base reference and the current state.
|
|
26
|
+
*
|
|
27
|
+
* @param repositoryPath Absolute path to the git repository.
|
|
28
|
+
* @param providedBaseBranch A branch name, tag, or commit SHA to diff against.
|
|
29
|
+
* When omitted, the remote default branch is auto-detected.
|
|
30
|
+
* @param includeUncommitted When true, diffs against the working tree so
|
|
31
|
+
* uncommitted/unstaged changes are included. Defaults to false (CI mode
|
|
32
|
+
* that only considers committed changes via the three-dot form).
|
|
33
|
+
*/
|
|
34
|
+
export declare function computeBranchDiff(repositoryPath: string, providedBaseBranch?: string, includeUncommitted?: boolean): Promise<BranchDiffData>;
|
|
@@ -14,6 +14,9 @@ export function parseChangedFilesFromDiff(rawDiff) {
|
|
|
14
14
|
return out;
|
|
15
15
|
}
|
|
16
16
|
/** Parse diff headers to find newly created and deleted files. */
|
|
17
|
+
function isShaLikeRef(ref) {
|
|
18
|
+
return /^[0-9a-f]{7,40}$/i.test(ref);
|
|
19
|
+
}
|
|
17
20
|
function parseNewAndDeletedFiles(rawDiff) {
|
|
18
21
|
const newFiles = [];
|
|
19
22
|
const deletedFiles = [];
|
|
@@ -34,24 +37,84 @@ function parseNewAndDeletedFiles(rawDiff) {
|
|
|
34
37
|
}
|
|
35
38
|
return { newFiles, deletedFiles };
|
|
36
39
|
}
|
|
37
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Normalize and validate a caller-provided base branch/ref before passing it
|
|
42
|
+
* to git. Reject option-like or ambiguous values so the ref is always treated
|
|
43
|
+
* as a revision name, not as a command-line flag.
|
|
44
|
+
*/
|
|
45
|
+
export function normalizeProvidedBaseRef(providedBaseBranch) {
|
|
46
|
+
if (providedBaseBranch === undefined)
|
|
47
|
+
return undefined;
|
|
48
|
+
const trimmed = providedBaseBranch.trim();
|
|
49
|
+
if (!trimmed)
|
|
50
|
+
return undefined;
|
|
51
|
+
if (trimmed.startsWith("-")) {
|
|
52
|
+
throw new Error(`Invalid base branch/ref "${providedBaseBranch}": refs must not start with '-'.`);
|
|
53
|
+
}
|
|
54
|
+
if (/\s/.test(trimmed) || trimmed.includes("\0")) {
|
|
55
|
+
throw new Error(`Invalid base branch/ref "${providedBaseBranch}": refs must not contain whitespace or NUL characters.`);
|
|
56
|
+
}
|
|
57
|
+
return trimmed;
|
|
58
|
+
}
|
|
59
|
+
async function tryDiff(git, ref, includeUncommitted = false) {
|
|
38
60
|
try {
|
|
39
|
-
|
|
61
|
+
// When includeUncommitted is true, diff the ref directly against the
|
|
62
|
+
// working tree so uncommitted/unstaged local changes are captured.
|
|
63
|
+
const diffRange = includeUncommitted ? ref : `${ref}...HEAD`;
|
|
64
|
+
const changedFilesRaw = await git.diff([diffRange, "--name-only"]);
|
|
40
65
|
const changedFiles = changedFilesRaw
|
|
41
66
|
.split("\n")
|
|
42
67
|
.map((f) => f.trim())
|
|
43
68
|
.filter((f) => f.length > 0);
|
|
44
|
-
const diffStat = await git.diff([
|
|
45
|
-
const fullDiff = await git.diff([
|
|
69
|
+
const diffStat = await git.diff([diffRange, "--stat"]);
|
|
70
|
+
const fullDiff = await git.diff([diffRange]);
|
|
46
71
|
const { newFiles, deletedFiles } = parseNewAndDeletedFiles(fullDiff);
|
|
47
|
-
|
|
72
|
+
// git diff does not include untracked files. Include them as both changed
|
|
73
|
+
// and new so endpoint classification treats newly created local files as new.
|
|
74
|
+
if (includeUncommitted) {
|
|
75
|
+
const statusResult = await git.status();
|
|
76
|
+
const untrackedFiles = statusResult.not_added ?? [];
|
|
77
|
+
if (untrackedFiles.length > 0) {
|
|
78
|
+
const changedSet = new Set(changedFiles);
|
|
79
|
+
const newSet = new Set(newFiles);
|
|
80
|
+
for (const file of untrackedFiles) {
|
|
81
|
+
if (!changedSet.has(file)) {
|
|
82
|
+
changedFiles.push(file);
|
|
83
|
+
changedSet.add(file);
|
|
84
|
+
}
|
|
85
|
+
if (!newSet.has(file)) {
|
|
86
|
+
newFiles.push(file);
|
|
87
|
+
newSet.add(file);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
changedFiles,
|
|
94
|
+
diffContent: fullDiff,
|
|
95
|
+
diffStat,
|
|
96
|
+
newFiles,
|
|
97
|
+
deletedFiles,
|
|
98
|
+
};
|
|
48
99
|
}
|
|
49
100
|
catch (err) {
|
|
50
|
-
logger.debug(`tryDiff against ${ref} failed`, {
|
|
101
|
+
logger.debug(`tryDiff against ${ref} failed`, {
|
|
102
|
+
error: err instanceof Error ? err.message : String(err),
|
|
103
|
+
});
|
|
51
104
|
return undefined;
|
|
52
105
|
}
|
|
53
106
|
}
|
|
54
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Compute the diff between a base reference and the current state.
|
|
109
|
+
*
|
|
110
|
+
* @param repositoryPath Absolute path to the git repository.
|
|
111
|
+
* @param providedBaseBranch A branch name, tag, or commit SHA to diff against.
|
|
112
|
+
* When omitted, the remote default branch is auto-detected.
|
|
113
|
+
* @param includeUncommitted When true, diffs against the working tree so
|
|
114
|
+
* uncommitted/unstaged changes are included. Defaults to false (CI mode
|
|
115
|
+
* that only considers committed changes via the three-dot form).
|
|
116
|
+
*/
|
|
117
|
+
export async function computeBranchDiff(repositoryPath, providedBaseBranch, includeUncommitted = false) {
|
|
55
118
|
const git = simpleGit(repositoryPath);
|
|
56
119
|
const isRepo = await git.checkIsRepo();
|
|
57
120
|
if (!isRepo) {
|
|
@@ -60,14 +123,32 @@ export async function computeBranchDiff(repositoryPath, providedBaseBranch) {
|
|
|
60
123
|
const branchInfo = await git.branch();
|
|
61
124
|
const currentBranch = branchInfo.current || "HEAD";
|
|
62
125
|
// Build candidate base refs in priority order:
|
|
63
|
-
// 1. Provided
|
|
64
|
-
// 2.
|
|
65
|
-
// 3.
|
|
126
|
+
// 1. Provided value used directly (supports SHAs, local branches, tags)
|
|
127
|
+
// 2. Provided value with origin/ prefix (remote branch)
|
|
128
|
+
// 3. Remote default branch auto-detected from available remotes
|
|
129
|
+
// 4. FETCH_HEAD — present in base_commit repos (git fetch --depth 1 origin <sha>)
|
|
66
130
|
// where no remote tracking branch is created
|
|
67
|
-
//
|
|
131
|
+
// 5. HEAD~1 — last resort for repos with no remote at all
|
|
68
132
|
const candidates = [];
|
|
69
|
-
|
|
70
|
-
|
|
133
|
+
const normalizedBaseBranch = normalizeProvidedBaseRef(providedBaseBranch);
|
|
134
|
+
if (normalizedBaseBranch) {
|
|
135
|
+
const isRemoteQualified = normalizedBaseBranch.startsWith("origin/");
|
|
136
|
+
const looksLikeSimpleBranch = !isRemoteQualified &&
|
|
137
|
+
!isShaLikeRef(normalizedBaseBranch) &&
|
|
138
|
+
!/[~^:@]/.test(normalizedBaseBranch);
|
|
139
|
+
if (includeUncommitted && looksLikeSimpleBranch) {
|
|
140
|
+
// Local-dev diffs should prefer the remote base branch when available;
|
|
141
|
+
// a developer's local main may be ahead of origin/main.
|
|
142
|
+
candidates.push(`origin/${normalizedBaseBranch}`);
|
|
143
|
+
candidates.push(normalizedBaseBranch);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Try the raw value first — handles commit SHAs, tags, and explicit local refs.
|
|
147
|
+
candidates.push(normalizedBaseBranch);
|
|
148
|
+
if (!isRemoteQualified) {
|
|
149
|
+
candidates.push(`origin/${normalizedBaseBranch}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
71
152
|
}
|
|
72
153
|
// Auto-detect remote default branch
|
|
73
154
|
try {
|
|
@@ -89,12 +170,13 @@ export async function computeBranchDiff(repositoryPath, providedBaseBranch) {
|
|
|
89
170
|
// Final fallback
|
|
90
171
|
candidates.push("HEAD~1");
|
|
91
172
|
for (const ref of candidates) {
|
|
92
|
-
const result = await tryDiff(git, ref);
|
|
173
|
+
const result = await tryDiff(git, ref, includeUncommitted);
|
|
93
174
|
if (result) {
|
|
94
175
|
logger.info("Branch diff computed", {
|
|
95
176
|
currentBranch,
|
|
96
177
|
baseBranch: ref,
|
|
97
178
|
changedFiles: result.changedFiles.length,
|
|
179
|
+
includeUncommitted,
|
|
98
180
|
});
|
|
99
181
|
return { currentBranch, baseBranch: ref, ...result };
|
|
100
182
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|