@griffin-app/griffin-cli 1.0.3 → 1.0.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/README.md +111 -161
- package/dist/cli.js +34 -15
- package/dist/commands/env.d.ts +1 -22
- package/dist/commands/env.js +22 -109
- package/dist/commands/generate-key.js +16 -10
- package/dist/commands/hub/apply.js +58 -34
- package/dist/commands/hub/connect.js +16 -9
- package/dist/commands/hub/login.d.ts +1 -0
- package/dist/commands/hub/login.js +79 -0
- package/dist/commands/hub/logout.d.ts +6 -0
- package/dist/commands/hub/logout.js +16 -0
- package/dist/commands/hub/plan.js +38 -21
- package/dist/commands/hub/run.js +93 -57
- package/dist/commands/hub/runs.js +75 -42
- package/dist/commands/hub/status.js +18 -13
- package/dist/commands/init.js +32 -24
- package/dist/commands/local/run.js +30 -16
- package/dist/commands/validate.js +18 -17
- package/dist/core/apply.d.ts +2 -2
- package/dist/core/apply.js +36 -38
- package/dist/core/apply.test.js +71 -27
- package/dist/core/credentials.d.ts +36 -0
- package/dist/core/credentials.js +98 -0
- package/dist/core/credentials.test.d.ts +1 -0
- package/dist/core/credentials.test.js +137 -0
- package/dist/core/diff.d.ts +7 -6
- package/dist/core/diff.js +2 -1
- package/dist/core/diff.test.js +44 -20
- package/dist/core/discovery.d.ts +2 -3
- package/dist/core/discovery.js +3 -10
- package/dist/core/plan-diff.d.ts +5 -6
- package/dist/core/plan-diff.js +6 -6
- package/dist/core/sdk.d.ts +5 -9
- package/dist/core/sdk.js +23 -15
- package/dist/core/variables.js +13 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +6 -2
- package/dist/resolve.d.ts +3 -0
- package/dist/resolve.js +9 -0
- package/dist/schemas/credentials.d.ts +24 -0
- package/dist/schemas/credentials.js +23 -0
- package/dist/schemas/state.d.ts +5 -5
- package/dist/schemas/state.js +5 -7
- package/dist/test-runner.js +18 -22
- package/dist/utils/console.d.ts +5 -0
- package/dist/utils/console.js +5 -0
- package/dist/utils/sdk-error.d.ts +8 -0
- package/dist/utils/sdk-error.js +114 -0
- package/dist/utils/terminal.d.ts +100 -0
- package/dist/utils/terminal.js +148 -0
- package/package.json +9 -4
package/dist/core/diff.test.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import { computeDiff } from "./diff.js";
|
|
3
|
-
import { FrequencyUnit } from "@griffin-app/griffin-ts/schema";
|
|
4
3
|
// Helper to create a minimal test plan
|
|
5
4
|
function createPlan(name, overrides) {
|
|
6
5
|
return {
|
|
@@ -9,7 +8,20 @@ function createPlan(name, overrides) {
|
|
|
9
8
|
project: "test-project",
|
|
10
9
|
environment: "test",
|
|
11
10
|
version: "1.0",
|
|
12
|
-
frequency: { every: 5, unit:
|
|
11
|
+
frequency: { every: 5, unit: "MINUTE" },
|
|
12
|
+
nodes: [],
|
|
13
|
+
edges: [],
|
|
14
|
+
...overrides,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
// Helper to create a resolved plan (without id)
|
|
18
|
+
function createResolvedPlan(name, overrides) {
|
|
19
|
+
return {
|
|
20
|
+
name,
|
|
21
|
+
project: "test-project",
|
|
22
|
+
environment: "test",
|
|
23
|
+
version: "1.0",
|
|
24
|
+
frequency: { every: 5, unit: "MINUTE" },
|
|
13
25
|
nodes: [],
|
|
14
26
|
edges: [],
|
|
15
27
|
...overrides,
|
|
@@ -18,9 +30,11 @@ function createPlan(name, overrides) {
|
|
|
18
30
|
describe("computeDiff", () => {
|
|
19
31
|
describe("CREATE actions", () => {
|
|
20
32
|
it("should create action when plan exists locally but not remotely", () => {
|
|
21
|
-
const local = [
|
|
33
|
+
const local = [createResolvedPlan("health-check")];
|
|
22
34
|
const remote = [];
|
|
23
|
-
const result = computeDiff(local, remote, {
|
|
35
|
+
const result = computeDiff(local, remote, {
|
|
36
|
+
includeDeletions: false,
|
|
37
|
+
});
|
|
24
38
|
expect(result.actions).toHaveLength(1);
|
|
25
39
|
expect(result.actions[0].type).toBe("create");
|
|
26
40
|
expect(result.actions[0].plan?.name).toBe("health-check");
|
|
@@ -33,16 +47,18 @@ describe("computeDiff", () => {
|
|
|
33
47
|
describe("UPDATE actions", () => {
|
|
34
48
|
it("should create update action when plan content differs", () => {
|
|
35
49
|
const local = [
|
|
36
|
-
|
|
37
|
-
frequency: { every: 10, unit:
|
|
50
|
+
createResolvedPlan("health-check", {
|
|
51
|
+
frequency: { every: 10, unit: "MINUTE" },
|
|
38
52
|
}),
|
|
39
53
|
];
|
|
40
54
|
const remote = [
|
|
41
55
|
createPlan("health-check", {
|
|
42
|
-
frequency: { every: 5, unit:
|
|
56
|
+
frequency: { every: 5, unit: "MINUTE" },
|
|
43
57
|
}),
|
|
44
58
|
];
|
|
45
|
-
const result = computeDiff(local, remote, {
|
|
59
|
+
const result = computeDiff(local, remote, {
|
|
60
|
+
includeDeletions: false,
|
|
61
|
+
});
|
|
46
62
|
expect(result.actions).toHaveLength(1);
|
|
47
63
|
expect(result.actions[0].type).toBe("update");
|
|
48
64
|
expect(result.actions[0].plan?.name).toBe("health-check");
|
|
@@ -54,10 +70,13 @@ describe("computeDiff", () => {
|
|
|
54
70
|
});
|
|
55
71
|
describe("NOOP actions", () => {
|
|
56
72
|
it("should create noop action when plan content matches", () => {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
73
|
+
const resolvedPlan = createResolvedPlan("health-check");
|
|
74
|
+
const remotePlan = createPlan("health-check");
|
|
75
|
+
const local = [resolvedPlan];
|
|
76
|
+
const remote = [remotePlan];
|
|
77
|
+
const result = computeDiff(local, remote, {
|
|
78
|
+
includeDeletions: false,
|
|
79
|
+
});
|
|
61
80
|
expect(result.actions).toHaveLength(1);
|
|
62
81
|
expect(result.actions[0].type).toBe("noop");
|
|
63
82
|
expect(result.summary.creates).toBe(0);
|
|
@@ -88,20 +107,22 @@ describe("computeDiff", () => {
|
|
|
88
107
|
describe("Mixed scenarios", () => {
|
|
89
108
|
it("should handle multiple plans with different actions", () => {
|
|
90
109
|
const local = [
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
frequency: { every: 10, unit:
|
|
110
|
+
createResolvedPlan("new-plan"),
|
|
111
|
+
createResolvedPlan("updated-plan", {
|
|
112
|
+
frequency: { every: 10, unit: "MINUTE" },
|
|
94
113
|
}),
|
|
95
|
-
|
|
114
|
+
createResolvedPlan("unchanged-plan"),
|
|
96
115
|
];
|
|
97
116
|
const remote = [
|
|
98
117
|
createPlan("updated-plan", {
|
|
99
|
-
frequency: { every: 5, unit:
|
|
118
|
+
frequency: { every: 5, unit: "MINUTE" },
|
|
100
119
|
}),
|
|
101
120
|
createPlan("unchanged-plan"),
|
|
102
121
|
createPlan("deleted-plan"),
|
|
103
122
|
];
|
|
104
|
-
const result = computeDiff(local, remote, {
|
|
123
|
+
const result = computeDiff(local, remote, {
|
|
124
|
+
includeDeletions: true,
|
|
125
|
+
});
|
|
105
126
|
expect(result.actions).toHaveLength(4);
|
|
106
127
|
expect(result.summary.creates).toBe(1);
|
|
107
128
|
expect(result.summary.updates).toBe(1);
|
|
@@ -111,9 +132,12 @@ describe("computeDiff", () => {
|
|
|
111
132
|
});
|
|
112
133
|
describe("Matching by name", () => {
|
|
113
134
|
it("should match plans by name, not by ID", () => {
|
|
114
|
-
|
|
135
|
+
// Local plans don't have IDs after resolution
|
|
136
|
+
const local = [createResolvedPlan("health-check")];
|
|
115
137
|
const remote = [createPlan("health-check", { id: "remote-id-456" })];
|
|
116
|
-
const result = computeDiff(local, remote, {
|
|
138
|
+
const result = computeDiff(local, remote, {
|
|
139
|
+
includeDeletions: false,
|
|
140
|
+
});
|
|
117
141
|
// Should be NOOP because names match (IDs are ignored)
|
|
118
142
|
expect(result.actions).toHaveLength(1);
|
|
119
143
|
expect(result.actions[0].type).toBe("noop");
|
package/dist/core/discovery.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type RawTestPlan = Omit<TestPlanV1, "id" | "environment" | "project">;
|
|
1
|
+
import type { PlanDSL } from "@griffin-app/griffin-ts/types";
|
|
3
2
|
export interface DiscoveredPlan {
|
|
4
|
-
plan:
|
|
3
|
+
plan: PlanDSL;
|
|
5
4
|
filePath: string;
|
|
6
5
|
exportName: string;
|
|
7
6
|
}
|
package/dist/core/discovery.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { glob } from "glob";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
import {
|
|
4
|
+
import { PlanDSLSchema } from "@griffin-app/griffin-ts/schema";
|
|
5
5
|
import { Value } from "typebox/value";
|
|
6
|
-
import { Type } from "typebox";
|
|
7
|
-
const RawTestPlanSchema = Type.Omit(TestPlanV1Schema, [
|
|
8
|
-
"id",
|
|
9
|
-
"environment",
|
|
10
|
-
"project",
|
|
11
|
-
]);
|
|
12
6
|
/**
|
|
13
7
|
* Discover and load test plan files from the filesystem
|
|
14
8
|
*/
|
|
@@ -21,7 +15,6 @@ export async function discoverPlans(pattern, ignore) {
|
|
|
21
15
|
absolute: true,
|
|
22
16
|
cwd: process.cwd(),
|
|
23
17
|
});
|
|
24
|
-
console.log(`Found ${files.length} test file(s)`);
|
|
25
18
|
// Load each file
|
|
26
19
|
for (const filePath of files) {
|
|
27
20
|
try {
|
|
@@ -38,7 +31,7 @@ export async function discoverPlans(pattern, ignore) {
|
|
|
38
31
|
return { plans, errors };
|
|
39
32
|
}
|
|
40
33
|
function isPlan(value) {
|
|
41
|
-
return Value.Check(
|
|
34
|
+
return Value.Check(PlanDSLSchema, value);
|
|
42
35
|
}
|
|
43
36
|
/**
|
|
44
37
|
* Load plans from a single file
|
|
@@ -60,7 +53,7 @@ async function loadPlansFromFile(filePath) {
|
|
|
60
53
|
});
|
|
61
54
|
}
|
|
62
55
|
else {
|
|
63
|
-
const errors = Value.Errors(
|
|
56
|
+
const errors = Value.Errors(PlanDSLSchema, module.default);
|
|
64
57
|
throw new Error(`Default export is not a valid TestPlan. Got: ${JSON.stringify(errors, null, 2)}`);
|
|
65
58
|
}
|
|
66
59
|
}
|
package/dist/core/plan-diff.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { TestPlanV1 } from "@griffin-app/griffin-ts/types";
|
|
3
|
-
import { NodeType } from "@griffin-app/griffin-ts/schema";
|
|
1
|
+
import { PlanV1 } from "@griffin-app/griffin-hub-sdk";
|
|
4
2
|
/**
|
|
5
3
|
* Represents a change to a single field
|
|
6
4
|
*/
|
|
@@ -15,7 +13,7 @@ export interface FieldChange {
|
|
|
15
13
|
export interface NodeChange {
|
|
16
14
|
type: "add" | "remove" | "modify";
|
|
17
15
|
nodeId: string;
|
|
18
|
-
nodeType:
|
|
16
|
+
nodeType: "ASSERTION" | "ENDPOINT" | "WAIT";
|
|
19
17
|
summary: string;
|
|
20
18
|
fieldChanges: FieldChange[];
|
|
21
19
|
}
|
|
@@ -37,6 +35,7 @@ export interface PlanChanges {
|
|
|
37
35
|
topLevel: FieldChange[];
|
|
38
36
|
}
|
|
39
37
|
/**
|
|
40
|
-
* Compare two test plans and return granular changes
|
|
38
|
+
* Compare two test plans and return granular changes.
|
|
39
|
+
* Local plan should be resolved (variables replaced with actual values).
|
|
41
40
|
*/
|
|
42
|
-
export declare function comparePlans(local:
|
|
41
|
+
export declare function comparePlans(local: PlanV1, remote: PlanV1): PlanChanges;
|
package/dist/core/plan-diff.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import objectHash from "object-hash";
|
|
2
|
+
import { NodeType } from "@griffin-app/griffin-ts/schema";
|
|
2
3
|
/**
|
|
3
|
-
* Compare two test plans and return granular changes
|
|
4
|
+
* Compare two test plans and return granular changes.
|
|
5
|
+
* Local plan should be resolved (variables replaced with actual values).
|
|
4
6
|
*/
|
|
5
7
|
export function comparePlans(local, remote) {
|
|
6
8
|
const nodeChanges = compareNodes(local.nodes, remote.nodes);
|
|
@@ -82,8 +84,6 @@ function getNodeSummary(node) {
|
|
|
82
84
|
return `wait ${node.duration_ms}ms`;
|
|
83
85
|
case "ASSERTION":
|
|
84
86
|
return `${node.assertions.length} assertion(s)`;
|
|
85
|
-
default:
|
|
86
|
-
return node.type;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
@@ -116,13 +116,13 @@ function compareNodeFields(local, remote) {
|
|
|
116
116
|
return changes;
|
|
117
117
|
}
|
|
118
118
|
switch (local.type) {
|
|
119
|
-
case
|
|
119
|
+
case NodeType.ENDPOINT:
|
|
120
120
|
compareEndpointFields(local, remote, changes);
|
|
121
121
|
break;
|
|
122
|
-
case
|
|
122
|
+
case NodeType.WAIT:
|
|
123
123
|
compareWaitFields(local, remote, changes);
|
|
124
124
|
break;
|
|
125
|
-
case
|
|
125
|
+
case NodeType.ASSERTION:
|
|
126
126
|
compareAssertionFields(local, remote, changes);
|
|
127
127
|
break;
|
|
128
128
|
}
|
package/dist/core/sdk.d.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { TestPlanV1 } from "@griffin-app/griffin-ts/types";
|
|
1
|
+
import { GriffinHubSdk } from "@griffin-app/griffin-hub-sdk";
|
|
3
2
|
/**
|
|
4
3
|
* Create configured SDK API instances
|
|
5
4
|
*/
|
|
6
|
-
export declare function
|
|
5
|
+
export declare function createSdk(config: {
|
|
7
6
|
baseUrl: string;
|
|
8
7
|
apiToken?: string;
|
|
9
|
-
}):
|
|
10
|
-
planApi: PlanApi;
|
|
11
|
-
runsApi: RunsApi;
|
|
12
|
-
};
|
|
8
|
+
}): GriffinHubSdk;
|
|
13
9
|
/**
|
|
14
|
-
*
|
|
10
|
+
* Create SDK with credentials from user-level credentials file
|
|
15
11
|
*/
|
|
16
|
-
export declare function
|
|
12
|
+
export declare function createSdkWithCredentials(baseUrl: string): Promise<GriffinHubSdk>;
|
package/dist/core/sdk.js
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GriffinHubSdk } from "@griffin-app/griffin-hub-sdk";
|
|
2
|
+
import { createClient } from "@griffin-app/griffin-hub-sdk/client";
|
|
3
|
+
import { getHubCredentials } from "./credentials.js";
|
|
2
4
|
/**
|
|
3
5
|
* Create configured SDK API instances
|
|
4
6
|
*/
|
|
5
|
-
export function
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
export function createSdk(config) {
|
|
8
|
+
const client = createClient({
|
|
9
|
+
throwOnError: true,
|
|
10
|
+
baseURL: config.baseUrl,
|
|
9
11
|
});
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
client.setConfig({
|
|
13
|
+
auth() {
|
|
14
|
+
return config.apiToken;
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
const sdk = new GriffinHubSdk({
|
|
18
|
+
client: client,
|
|
19
|
+
});
|
|
20
|
+
return sdk;
|
|
14
21
|
}
|
|
15
22
|
/**
|
|
16
|
-
*
|
|
23
|
+
* Create SDK with credentials from user-level credentials file
|
|
17
24
|
*/
|
|
18
|
-
export function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
export async function createSdkWithCredentials(baseUrl) {
|
|
26
|
+
const credentials = await getHubCredentials();
|
|
27
|
+
return createSdk({
|
|
28
|
+
baseUrl: baseUrl,
|
|
29
|
+
apiToken: credentials?.token,
|
|
30
|
+
});
|
|
23
31
|
}
|
package/dist/core/variables.js
CHANGED
|
@@ -46,6 +46,16 @@ function isVariableRef(value) {
|
|
|
46
46
|
return (typeof varData.key === "string" &&
|
|
47
47
|
(varData.template === undefined || typeof varData.template === "string"));
|
|
48
48
|
}
|
|
49
|
+
function isStringLiteral(value) {
|
|
50
|
+
if (typeof value !== "object" || value === null) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const obj = value;
|
|
54
|
+
if (!("$literal" in obj) || typeof obj.$literal !== "string") {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
49
59
|
/**
|
|
50
60
|
* Resolve a single variable reference to its string value.
|
|
51
61
|
*
|
|
@@ -83,6 +93,9 @@ export function resolveVariablesInPlan(obj, variables) {
|
|
|
83
93
|
if (isVariableRef(obj)) {
|
|
84
94
|
return resolveVariable(obj, variables);
|
|
85
95
|
}
|
|
96
|
+
if (isStringLiteral(obj)) {
|
|
97
|
+
return obj.$literal;
|
|
98
|
+
}
|
|
86
99
|
// Recursively process arrays
|
|
87
100
|
if (Array.isArray(obj)) {
|
|
88
101
|
return obj.map((item) => resolveVariablesInPlan(item, variables));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
export type { StateFile,
|
|
1
|
+
export type { StateFile, HubConfig } from "./schemas/state.js";
|
|
2
|
+
export type { CredentialsFile, HubCredentials } from "./schemas/credentials.js";
|
|
2
3
|
export type { DiscoveredPlan, DiscoveryResult, DiscoveryError, } from "./core/discovery.js";
|
|
3
4
|
export type { DiffAction, DiffResult } from "./core/diff.js";
|
|
4
5
|
export type { ApplyResult, ApplyAction, ApplyError } from "./core/apply.js";
|
|
5
|
-
export { createEmptyState, StateFileSchema,
|
|
6
|
+
export { createEmptyState, StateFileSchema, HubConfigSchema, } from "./schemas/state.js";
|
|
7
|
+
export { createEmptyCredentials, CredentialsFileSchema, HubCredentialsSchema, } from "./schemas/credentials.js";
|
|
6
8
|
export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, initState, addEnvironment, removeEnvironment, setDefaultEnvironment, resolveEnvironment, getEnvironment, } from "./core/state.js";
|
|
9
|
+
export { getCredentialsDirPath, getCredentialsFilePath, credentialsExist, loadCredentials, saveCredentials, saveHubCredentials, getHubCredentials, removeHubCredentials, } from "./core/credentials.js";
|
|
7
10
|
export { discoverPlans, formatDiscoveryErrors } from "./core/discovery.js";
|
|
8
11
|
export { computeDiff, formatDiff, formatDiffJson } from "./core/diff.js";
|
|
9
12
|
export { applyDiff, formatApplyResult } from "./core/apply.js";
|
|
10
|
-
export {
|
|
13
|
+
export { createSdk, createSdkWithCredentials } from "./core/sdk.js";
|
|
11
14
|
export { detectProjectId } from "./core/project.js";
|
|
12
15
|
export { executeInit } from "./commands/init.js";
|
|
13
16
|
export { executeValidate } from "./commands/validate.js";
|
|
@@ -19,3 +22,5 @@ export { executeRuns } from "./commands/hub/runs.js";
|
|
|
19
22
|
export { executePlan } from "./commands/hub/plan.js";
|
|
20
23
|
export { executeApply } from "./commands/hub/apply.js";
|
|
21
24
|
export { executeRun } from "./commands/hub/run.js";
|
|
25
|
+
export { executeLogin } from "./commands/hub/login.js";
|
|
26
|
+
export { executeLogout } from "./commands/hub/logout.js";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// Export core functions
|
|
2
|
-
export { createEmptyState, StateFileSchema,
|
|
2
|
+
export { createEmptyState, StateFileSchema, HubConfigSchema, } from "./schemas/state.js";
|
|
3
|
+
export { createEmptyCredentials, CredentialsFileSchema, HubCredentialsSchema, } from "./schemas/credentials.js";
|
|
3
4
|
export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, initState, addEnvironment, removeEnvironment, setDefaultEnvironment, resolveEnvironment, getEnvironment, } from "./core/state.js";
|
|
5
|
+
export { getCredentialsDirPath, getCredentialsFilePath, credentialsExist, loadCredentials, saveCredentials, saveHubCredentials, getHubCredentials, removeHubCredentials, } from "./core/credentials.js";
|
|
4
6
|
export { discoverPlans, formatDiscoveryErrors } from "./core/discovery.js";
|
|
5
7
|
export { computeDiff, formatDiff, formatDiffJson } from "./core/diff.js";
|
|
6
8
|
export { applyDiff, formatApplyResult } from "./core/apply.js";
|
|
7
|
-
export {
|
|
9
|
+
export { createSdk, createSdkWithCredentials } from "./core/sdk.js";
|
|
8
10
|
export { detectProjectId } from "./core/project.js";
|
|
9
11
|
// Export command executors (for programmatic use)
|
|
10
12
|
export { executeInit } from "./commands/init.js";
|
|
@@ -19,3 +21,5 @@ export { executeRuns } from "./commands/hub/runs.js";
|
|
|
19
21
|
export { executePlan } from "./commands/hub/plan.js";
|
|
20
22
|
export { executeApply } from "./commands/hub/apply.js";
|
|
21
23
|
export { executeRun } from "./commands/hub/run.js";
|
|
24
|
+
export { executeLogin } from "./commands/hub/login.js";
|
|
25
|
+
export { executeLogout } from "./commands/hub/logout.js";
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { resolveVariablesInPlan } from "./core/variables.js";
|
|
2
|
+
export function resolvePlan(plan, projectId, envName, variables) {
|
|
3
|
+
const resolvedPlan = resolveVariablesInPlan(plan, variables);
|
|
4
|
+
return {
|
|
5
|
+
...resolvedPlan,
|
|
6
|
+
project: projectId,
|
|
7
|
+
environment: envName,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Type, type Static } from "typebox";
|
|
2
|
+
/**
|
|
3
|
+
* Credentials file schema for storing user-level authentication
|
|
4
|
+
* Stored in ~/.griffin/credentials.json
|
|
5
|
+
*
|
|
6
|
+
* This file stores tokens and API keys scoped to the user across all projects.
|
|
7
|
+
*/
|
|
8
|
+
export declare const HubCredentialsSchema: Type.TObject<{
|
|
9
|
+
token: Type.TString;
|
|
10
|
+
updatedAt: Type.TString;
|
|
11
|
+
}>;
|
|
12
|
+
export type HubCredentials = Static<typeof HubCredentialsSchema>;
|
|
13
|
+
export declare const CredentialsFileSchema: Type.TObject<{
|
|
14
|
+
version: Type.TLiteral<1>;
|
|
15
|
+
hub: Type.TOptional<Type.TObject<{
|
|
16
|
+
token: Type.TString;
|
|
17
|
+
updatedAt: Type.TString;
|
|
18
|
+
}>>;
|
|
19
|
+
}>;
|
|
20
|
+
export type CredentialsFile = Static<typeof CredentialsFileSchema>;
|
|
21
|
+
/**
|
|
22
|
+
* Create an empty credentials file
|
|
23
|
+
*/
|
|
24
|
+
export declare function createEmptyCredentials(): CredentialsFile;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
/**
|
|
3
|
+
* Credentials file schema for storing user-level authentication
|
|
4
|
+
* Stored in ~/.griffin/credentials.json
|
|
5
|
+
*
|
|
6
|
+
* This file stores tokens and API keys scoped to the user across all projects.
|
|
7
|
+
*/
|
|
8
|
+
export const HubCredentialsSchema = Type.Object({
|
|
9
|
+
token: Type.String(),
|
|
10
|
+
updatedAt: Type.String(), // ISO timestamp
|
|
11
|
+
});
|
|
12
|
+
export const CredentialsFileSchema = Type.Object({
|
|
13
|
+
version: Type.Literal(1),
|
|
14
|
+
hub: Type.Optional(HubCredentialsSchema),
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Create an empty credentials file
|
|
18
|
+
*/
|
|
19
|
+
export function createEmptyCredentials() {
|
|
20
|
+
return {
|
|
21
|
+
version: 1,
|
|
22
|
+
};
|
|
23
|
+
}
|
package/dist/schemas/state.d.ts
CHANGED
|
@@ -8,11 +8,11 @@ import { Type, type Static } from "typebox";
|
|
|
8
8
|
*/
|
|
9
9
|
export declare const EnvironmentConfigSchema: Type.TObject<{}>;
|
|
10
10
|
export type EnvironmentConfig = Static<typeof EnvironmentConfigSchema>;
|
|
11
|
-
export declare const
|
|
11
|
+
export declare const HubConfigSchema: Type.TObject<{
|
|
12
12
|
baseUrl: Type.TString;
|
|
13
|
-
|
|
13
|
+
clientId: Type.TString;
|
|
14
14
|
}>;
|
|
15
|
-
export type
|
|
15
|
+
export type HubConfig = Static<typeof HubConfigSchema>;
|
|
16
16
|
export declare const DiscoveryConfigSchema: Type.TObject<{
|
|
17
17
|
pattern: Type.TOptional<Type.TString>;
|
|
18
18
|
ignore: Type.TOptional<Type.TArray<Type.TString>>;
|
|
@@ -23,9 +23,9 @@ export declare const StateFileSchema: Type.TObject<{
|
|
|
23
23
|
projectId: Type.TString;
|
|
24
24
|
environments: Type.TRecord<"^.*$", Type.TObject<{}>>;
|
|
25
25
|
defaultEnvironment: Type.TOptional<Type.TString>;
|
|
26
|
-
|
|
26
|
+
hub: Type.TOptional<Type.TObject<{
|
|
27
27
|
baseUrl: Type.TString;
|
|
28
|
-
|
|
28
|
+
clientId: Type.TString;
|
|
29
29
|
}>>;
|
|
30
30
|
discovery: Type.TOptional<Type.TObject<{
|
|
31
31
|
pattern: Type.TOptional<Type.TString>;
|
package/dist/schemas/state.js
CHANGED
|
@@ -6,12 +6,10 @@ import { Type } from "typebox";
|
|
|
6
6
|
* Note: The hub is now the source of truth for plans.
|
|
7
7
|
* This file only stores configuration (project, environments, runner connection).
|
|
8
8
|
*/
|
|
9
|
-
export const EnvironmentConfigSchema = Type.Object({
|
|
10
|
-
|
|
11
|
-
});
|
|
12
|
-
export const RunnerConfigSchema = Type.Object({
|
|
9
|
+
export const EnvironmentConfigSchema = Type.Object({});
|
|
10
|
+
export const HubConfigSchema = Type.Object({
|
|
13
11
|
baseUrl: Type.String(),
|
|
14
|
-
|
|
12
|
+
clientId: Type.String(),
|
|
15
13
|
});
|
|
16
14
|
export const DiscoveryConfigSchema = Type.Object({
|
|
17
15
|
pattern: Type.Optional(Type.String()),
|
|
@@ -24,8 +22,8 @@ export const StateFileSchema = Type.Object({
|
|
|
24
22
|
// Environment configuration
|
|
25
23
|
environments: Type.Record(Type.String(), EnvironmentConfigSchema),
|
|
26
24
|
defaultEnvironment: Type.Optional(Type.String()),
|
|
27
|
-
//
|
|
28
|
-
|
|
25
|
+
// Hub connection (for remote execution)
|
|
26
|
+
hub: Type.Optional(HubConfigSchema),
|
|
29
27
|
// Discovery settings
|
|
30
28
|
discovery: Type.Optional(DiscoveryConfigSchema),
|
|
31
29
|
});
|
package/dist/test-runner.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import "tsx";
|
|
2
2
|
import { Value } from "typebox/value";
|
|
3
3
|
import { executePlanV1, AxiosAdapter, EnvSecretProvider, SecretProviderRegistry, } from "@griffin-app/griffin-plan-executor";
|
|
4
|
-
import {
|
|
5
|
-
import { Type } from "typebox";
|
|
4
|
+
import { PlanDSLSchema } from "@griffin-app/griffin-ts/schema";
|
|
6
5
|
import { randomUUID } from "crypto";
|
|
7
|
-
import { loadVariables
|
|
6
|
+
import { loadVariables } from "./core/variables.js";
|
|
8
7
|
import { getProjectId } from "./core/state.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
import { resolvePlan } from "./resolve.js";
|
|
9
|
+
import { terminal } from "./utils/terminal.js";
|
|
10
|
+
function validateDsl(plan) {
|
|
11
|
+
const errors = Value.Errors(PlanDSLSchema, plan);
|
|
12
|
+
if (errors.length > 0) {
|
|
13
|
+
throw new Error(`Invalid plan: ${JSON.stringify([...errors], null, 2)}`);
|
|
14
|
+
}
|
|
15
|
+
return plan;
|
|
16
|
+
}
|
|
14
17
|
/**
|
|
15
18
|
* Runs a TypeScript test file and executes the resulting JSON plan.
|
|
16
19
|
*/
|
|
@@ -18,31 +21,24 @@ export async function runTestFile(filePath, envName) {
|
|
|
18
21
|
const variables = await loadVariables(envName);
|
|
19
22
|
const projectId = await getProjectId();
|
|
20
23
|
const defaultExport = await import(filePath);
|
|
21
|
-
const rawPlan = defaultExport.default;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const resolvedPlan = resolveVariablesInPlan(rawPlan, variables);
|
|
24
|
+
const rawPlan = validateDsl(defaultExport.default);
|
|
25
|
+
terminal.dim(`Project ID: ${projectId}`);
|
|
26
|
+
const resolvedPlan = resolvePlan(rawPlan, projectId, envName, variables);
|
|
25
27
|
const secretRegistry = new SecretProviderRegistry();
|
|
26
28
|
secretRegistry.register(new EnvSecretProvider());
|
|
27
29
|
try {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
...parsedPlan,
|
|
30
|
+
const result = await executePlanV1({
|
|
31
|
+
...resolvedPlan,
|
|
31
32
|
id: randomUUID(),
|
|
32
|
-
|
|
33
|
-
environment: envName,
|
|
34
|
-
};
|
|
35
|
-
const result = await executePlanV1(syntheticPlan, "default-org", {
|
|
33
|
+
}, "default-org", {
|
|
36
34
|
mode: "local",
|
|
37
35
|
httpClient: new AxiosAdapter(),
|
|
38
36
|
secretRegistry: secretRegistry,
|
|
39
37
|
});
|
|
40
|
-
console.log(JSON.stringify(result, null, 2));
|
|
41
38
|
return result;
|
|
42
39
|
}
|
|
43
40
|
catch (error) {
|
|
44
|
-
|
|
45
|
-
throw new Error(`Invalid plan: ${JSON.stringify([...errors], null, 2)}: ${error}`);
|
|
41
|
+
throw new Error(`Error executing plan: ${error instanceof Error ? error.message : String(error)}`);
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
44
|
//function findWorkspaceRoot(): string {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handle SDK errors with user-friendly messaging
|
|
3
|
+
*/
|
|
4
|
+
export declare function handleSDKError(error: unknown, context?: string): never;
|
|
5
|
+
/**
|
|
6
|
+
* Wrap an SDK call with error handling
|
|
7
|
+
*/
|
|
8
|
+
export declare function withSDKErrorHandling<T>(fn: () => Promise<T>, context?: string): Promise<T>;
|