@griffin-app/griffin-ts 0.1.9 → 0.1.11
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/dist/assertions.d.ts.map +1 -1
- package/dist/assertions.js +18 -6
- package/dist/assertions.js.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +2 -2
- package/dist/builder.js.map +1 -1
- package/dist/builder.test.js +13 -6
- package/dist/builder.test.js.map +1 -1
- package/dist/frequency.test.js +80 -20
- package/dist/frequency.test.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/migrations.d.ts +51 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +92 -0
- package/dist/migrations.js.map +1 -0
- package/dist/migrations.test.d.ts +5 -0
- package/dist/migrations.test.d.ts.map +1 -0
- package/dist/migrations.test.js +127 -0
- package/dist/migrations.test.js.map +1 -0
- package/dist/schema-exports.d.ts +2 -1
- package/dist/schema-exports.d.ts.map +1 -1
- package/dist/schema-exports.js +5 -3
- package/dist/schema-exports.js.map +1 -1
- package/dist/schema.d.ts +439 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +56 -7
- package/dist/schema.js.map +1 -1
- package/dist/secrets.test.js +4 -4
- package/dist/secrets.test.js.map +1 -1
- package/dist/sequential-builder.js +3 -3
- package/dist/sequential-builder.js.map +1 -1
- package/dist/sequential-builder.test.js +7 -11
- package/dist/sequential-builder.test.js.map +1 -1
- package/dist/variable.test.js +11 -11
- package/dist/variable.test.js.map +1 -1
- package/package.json +1 -1
- package/src/builder.test.ts +2 -2
- package/src/builder.ts +2 -2
- package/src/index.ts +36 -0
- package/src/migrations.test.ts +148 -0
- package/src/migrations.ts +120 -0
- package/src/schema-exports.ts +30 -2
- package/src/schema.ts +69 -5
- package/src/sequential-builder.test.ts +2 -2
- package/src/sequential-builder.ts +3 -3
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration framework for test plan versioning.
|
|
3
|
+
* Provides functions to migrate plans between different schema versions.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { CURRENT_PLAN_VERSION, SUPPORTED_PLAN_VERSIONS } from "./schema.js";
|
|
7
|
+
import type { ResolvedPlan, ResolvedPlanV1 } from "./schema.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Type representing a migration function from one version to another
|
|
11
|
+
*/
|
|
12
|
+
type MigrationFn<From = unknown, To = unknown> = (plan: From) => To;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Registry of all available migrations between versions
|
|
16
|
+
* Key format: "fromVersion->toVersion"
|
|
17
|
+
*/
|
|
18
|
+
const migrations: Record<string, MigrationFn<any, any>> = {
|
|
19
|
+
// Future migrations will be added here
|
|
20
|
+
// Example: "1.0->2.0": migrateV1ToV2,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the next version in the supported versions list
|
|
25
|
+
*/
|
|
26
|
+
function getNextVersion(currentVersion: string): string {
|
|
27
|
+
const versions = SUPPORTED_PLAN_VERSIONS as readonly string[];
|
|
28
|
+
const currentIndex = versions.indexOf(currentVersion);
|
|
29
|
+
|
|
30
|
+
if (currentIndex === -1) {
|
|
31
|
+
throw new Error(`Unsupported plan version: ${currentVersion}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (currentIndex === versions.length - 1) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`No migration path available from version ${currentVersion}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return versions[currentIndex + 1];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Migrate a plan from its current version to a target version
|
|
45
|
+
*
|
|
46
|
+
* @param plan - Plan to migrate (must have a version field)
|
|
47
|
+
* @param targetVersion - Target version to migrate to
|
|
48
|
+
* @returns Migrated plan at target version
|
|
49
|
+
* @throws Error if no migration path exists
|
|
50
|
+
*/
|
|
51
|
+
export function migratePlan<T>(
|
|
52
|
+
plan: { version: string },
|
|
53
|
+
targetVersion: string,
|
|
54
|
+
): T {
|
|
55
|
+
let current: any = plan;
|
|
56
|
+
|
|
57
|
+
// Already at target version
|
|
58
|
+
if (current.version === targetVersion) {
|
|
59
|
+
return current as T;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Migrate step by step through versions
|
|
63
|
+
while (current.version !== targetVersion) {
|
|
64
|
+
const nextVersion = getNextVersion(current.version);
|
|
65
|
+
const migrationKey = `${current.version}->${nextVersion}`;
|
|
66
|
+
const migrate = migrations[migrationKey];
|
|
67
|
+
|
|
68
|
+
if (!migrate) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`No migration path from version ${current.version} to ${nextVersion}`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
current = migrate(current);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return current as T;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Migrate a plan to the latest supported version
|
|
82
|
+
*
|
|
83
|
+
* @param plan - Plan to migrate (must have a version field)
|
|
84
|
+
* @returns Plan migrated to latest version
|
|
85
|
+
*/
|
|
86
|
+
export function migrateToLatest(plan: { version: string }): ResolvedPlan {
|
|
87
|
+
return migratePlan<ResolvedPlan>(plan, CURRENT_PLAN_VERSION);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Check if a plan version is supported
|
|
92
|
+
*
|
|
93
|
+
* @param version - Version string to check
|
|
94
|
+
* @returns True if version is supported
|
|
95
|
+
*/
|
|
96
|
+
export function isSupportedVersion(version: string): boolean {
|
|
97
|
+
return SUPPORTED_PLAN_VERSIONS.includes(version as any);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get all supported plan versions
|
|
102
|
+
*/
|
|
103
|
+
export function getSupportedVersions(): readonly string[] {
|
|
104
|
+
return SUPPORTED_PLAN_VERSIONS;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Example migration function template (for future use)
|
|
109
|
+
*
|
|
110
|
+
* Uncomment and modify when creating v2.0:
|
|
111
|
+
*
|
|
112
|
+
* function migrateV1ToV2(plan: ResolvedPlanV1): ResolvedPlanV2 {
|
|
113
|
+
* return {
|
|
114
|
+
* ...plan,
|
|
115
|
+
* version: "2.0",
|
|
116
|
+
* // Add/modify fields as needed for v2.0
|
|
117
|
+
* newField: "default value",
|
|
118
|
+
* };
|
|
119
|
+
* }
|
|
120
|
+
*/
|
package/src/schema-exports.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export {
|
|
7
|
-
// Schema values
|
|
7
|
+
// Schema values - DSL (what users write)
|
|
8
8
|
SecretRefDataSchema,
|
|
9
9
|
SecretRefSchema,
|
|
10
10
|
StringLiteralSchema,
|
|
@@ -19,6 +19,7 @@ export {
|
|
|
19
19
|
XMLPathSchema,
|
|
20
20
|
TextPathSchema,
|
|
21
21
|
UnaryPredicateSchema,
|
|
22
|
+
UnaryPredicateOperatorSchema,
|
|
22
23
|
BinaryPredicateOperatorSchema,
|
|
23
24
|
BinaryPredicateSchema,
|
|
24
25
|
AssertionSchema,
|
|
@@ -26,6 +27,14 @@ export {
|
|
|
26
27
|
NodeDSLSchema,
|
|
27
28
|
EdgeSchema,
|
|
28
29
|
PlanDSLSchema,
|
|
30
|
+
PlanDSLSchemaV1,
|
|
31
|
+
|
|
32
|
+
// Schema values - Resolved (what hub/executor use)
|
|
33
|
+
ResolvedStringSchema,
|
|
34
|
+
HttpRequestResolvedSchema,
|
|
35
|
+
NodeResolvedSchema,
|
|
36
|
+
ResolvedPlanV1Schema,
|
|
37
|
+
ResolvedPlanSchema,
|
|
29
38
|
|
|
30
39
|
// Enums (runtime values)
|
|
31
40
|
FrequencyUnit,
|
|
@@ -36,5 +45,24 @@ export {
|
|
|
36
45
|
BinaryPredicateOperator,
|
|
37
46
|
|
|
38
47
|
// Constants
|
|
39
|
-
|
|
48
|
+
CURRENT_PLAN_VERSION,
|
|
49
|
+
SUPPORTED_PLAN_VERSIONS,
|
|
50
|
+
} from "./schema.js";
|
|
51
|
+
|
|
52
|
+
// Type exports
|
|
53
|
+
export type {
|
|
54
|
+
PlanDSL,
|
|
55
|
+
PlanDSLV1,
|
|
56
|
+
NodeDSL,
|
|
57
|
+
HttpRequestDSL,
|
|
58
|
+
Edge,
|
|
59
|
+
Frequency,
|
|
60
|
+
Assertion,
|
|
61
|
+
Assertions,
|
|
62
|
+
SecretRef,
|
|
63
|
+
VariableRef,
|
|
64
|
+
ResolvedPlan,
|
|
65
|
+
ResolvedPlanV1,
|
|
66
|
+
NodeResolved,
|
|
67
|
+
HttpRequestResolved,
|
|
40
68
|
} from "./schema.js";
|
package/src/schema.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
2
|
import { Ref, StringEnum } from "./shared.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// Version constants
|
|
5
|
+
export const CURRENT_PLAN_VERSION = "1.0";
|
|
6
|
+
export const SUPPORTED_PLAN_VERSIONS = ["1.0"] as const;
|
|
5
7
|
|
|
6
8
|
// Secret reference schema for values that may contain secrets
|
|
7
9
|
export const SecretRefDataSchema = Type.Object({
|
|
@@ -311,21 +313,27 @@ export const EdgeSchema = Type.Object(
|
|
|
311
313
|
{ $id: "Edge" },
|
|
312
314
|
);
|
|
313
315
|
|
|
314
|
-
|
|
316
|
+
// Version-specific DSL schemas
|
|
317
|
+
export const PlanDSLSchemaV1 = Type.Object(
|
|
315
318
|
{
|
|
316
319
|
locations: Type.Optional(Type.Array(Type.String())),
|
|
317
320
|
name: Type.String(),
|
|
318
|
-
version: Type.Literal(
|
|
321
|
+
version: Type.Literal("1.0"),
|
|
319
322
|
frequency: FrequencySchema,
|
|
320
323
|
nodes: Type.Array(NodeDSLSchema),
|
|
321
324
|
edges: Type.Array(EdgeSchema),
|
|
322
325
|
},
|
|
323
326
|
{
|
|
324
|
-
$id: "
|
|
327
|
+
$id: "PlanDSLV1",
|
|
325
328
|
},
|
|
326
329
|
);
|
|
327
330
|
|
|
328
|
-
|
|
331
|
+
// Union schema for validation (accepts any supported version)
|
|
332
|
+
export const PlanDSLSchema = PlanDSLSchemaV1; // Currently only v1.0, will become union when v2.0 is added
|
|
333
|
+
|
|
334
|
+
// Type extraction
|
|
335
|
+
export type PlanDSLV1 = Static<typeof PlanDSLSchemaV1>;
|
|
336
|
+
export type PlanDSL = PlanDSLV1; // Currently only v1.0, will become union when v2.0 is added
|
|
329
337
|
export type VariableRef = Static<typeof VariableRefSchema>;
|
|
330
338
|
export type NodeDSL = Static<typeof NodeDSLSchema>;
|
|
331
339
|
export type Edge = Static<typeof EdgeSchema>;
|
|
@@ -342,3 +350,59 @@ export type SecretRefData = Static<typeof SecretRefDataSchema>;
|
|
|
342
350
|
export type StringLiteral = Static<typeof StringLiteralSchema>;
|
|
343
351
|
export type String = Static<typeof StringSchema>;
|
|
344
352
|
export type Frequency = Static<typeof FrequencySchema>;
|
|
353
|
+
|
|
354
|
+
// ============================================================================
|
|
355
|
+
// Resolved Plan Schemas (after variable resolution, used by hub/executor)
|
|
356
|
+
// ============================================================================
|
|
357
|
+
|
|
358
|
+
// Union type for resolved values (variables are resolved, only secrets/literals remain)
|
|
359
|
+
export const ResolvedStringSchema = Type.Union([
|
|
360
|
+
StringLiteralSchema,
|
|
361
|
+
SecretRefSchema,
|
|
362
|
+
]);
|
|
363
|
+
|
|
364
|
+
export const HttpRequestResolvedSchema = Type.Object(
|
|
365
|
+
{
|
|
366
|
+
id: Type.String(),
|
|
367
|
+
type: Type.Literal(NodeType.HTTP_REQUEST),
|
|
368
|
+
method: HttpMethodSchema,
|
|
369
|
+
path: Type.String(),
|
|
370
|
+
base: Type.String(),
|
|
371
|
+
headers: Type.Optional(Type.Record(Type.String(), ResolvedStringSchema)),
|
|
372
|
+
body: Type.Optional(Type.Any()), // Body can contain nested SecretRefs
|
|
373
|
+
response_format: ResponseFormatSchema,
|
|
374
|
+
},
|
|
375
|
+
{ $id: "HttpRequestResolved" },
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
export const NodeResolvedSchema = Type.Union(
|
|
379
|
+
[HttpRequestResolvedSchema, WaitSchema, AssertionsSchema],
|
|
380
|
+
{ $id: "NodeResolved" },
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
// Version-specific resolved plan schemas
|
|
384
|
+
export const ResolvedPlanV1Schema = Type.Object(
|
|
385
|
+
{
|
|
386
|
+
project: Type.String(),
|
|
387
|
+
locations: Type.Optional(Type.Array(Type.String())),
|
|
388
|
+
id: Type.Readonly(Type.String()),
|
|
389
|
+
name: Type.String(),
|
|
390
|
+
version: Type.Literal("1.0"),
|
|
391
|
+
frequency: FrequencySchema,
|
|
392
|
+
environment: Type.String({ default: "default" }),
|
|
393
|
+
nodes: Type.Array(NodeResolvedSchema),
|
|
394
|
+
edges: Type.Array(EdgeSchema),
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
$id: "ResolvedPlanV1",
|
|
398
|
+
},
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
// Union of all supported resolved plan versions
|
|
402
|
+
export const ResolvedPlanSchema = ResolvedPlanV1Schema;
|
|
403
|
+
|
|
404
|
+
// Type exports for resolved plans
|
|
405
|
+
export type ResolvedPlanV1 = Static<typeof ResolvedPlanV1Schema>;
|
|
406
|
+
export type ResolvedPlan = ResolvedPlanV1;
|
|
407
|
+
export type HttpRequestResolved = Static<typeof HttpRequestResolvedSchema>;
|
|
408
|
+
export type NodeResolved = Static<typeof NodeResolvedSchema>;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
HttpMethod,
|
|
10
10
|
ResponseFormat,
|
|
11
11
|
NodeType,
|
|
12
|
-
|
|
12
|
+
CURRENT_PLAN_VERSION,
|
|
13
13
|
} from "./schema.js";
|
|
14
14
|
|
|
15
15
|
describe("Sequential Test Builder", () => {
|
|
@@ -28,7 +28,7 @@ describe("Sequential Test Builder", () => {
|
|
|
28
28
|
.build();
|
|
29
29
|
|
|
30
30
|
expect(plan.name).toBe("simple-check");
|
|
31
|
-
expect(plan.version).toBe(
|
|
31
|
+
expect(plan.version).toBe(CURRENT_PLAN_VERSION);
|
|
32
32
|
expect(plan.frequency).toEqual({ every: 5, unit: "MINUTE" });
|
|
33
33
|
expect(plan.nodes).toHaveLength(1);
|
|
34
34
|
expect(plan.edges).toEqual([
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./builder.js";
|
|
8
8
|
import { START, END } from "./constants.js";
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
CURRENT_PLAN_VERSION,
|
|
11
11
|
Edge,
|
|
12
12
|
NodeDSL,
|
|
13
13
|
Frequency,
|
|
@@ -177,7 +177,7 @@ class SequentialTestBuilderImpl<
|
|
|
177
177
|
name,
|
|
178
178
|
frequency,
|
|
179
179
|
locations,
|
|
180
|
-
version:
|
|
180
|
+
version: CURRENT_PLAN_VERSION,
|
|
181
181
|
nodes: [],
|
|
182
182
|
edges: [{ from: START, to: END }],
|
|
183
183
|
};
|
|
@@ -199,7 +199,7 @@ class SequentialTestBuilderImpl<
|
|
|
199
199
|
|
|
200
200
|
return {
|
|
201
201
|
name,
|
|
202
|
-
version:
|
|
202
|
+
version: CURRENT_PLAN_VERSION,
|
|
203
203
|
frequency,
|
|
204
204
|
locations,
|
|
205
205
|
nodes: this.nodes,
|