@griffin-app/griffin-cli 1.0.18 → 1.0.20
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/cli.js +183 -196
- package/dist/commands/env.d.ts +3 -3
- package/dist/commands/env.js +28 -45
- package/dist/commands/hub/apply.d.ts +1 -1
- package/dist/commands/hub/apply.js +54 -95
- package/dist/commands/hub/connect.d.ts +1 -1
- package/dist/commands/hub/connect.js +2 -6
- package/dist/commands/hub/destroy.d.ts +10 -0
- package/dist/commands/hub/destroy.js +141 -0
- package/dist/commands/hub/integrations.d.ts +9 -9
- package/dist/commands/hub/integrations.js +104 -115
- package/dist/commands/hub/login.js +3 -0
- package/dist/commands/hub/metrics.d.ts +2 -2
- package/dist/commands/hub/metrics.js +41 -69
- package/dist/commands/hub/monitor.d.ts +1 -1
- package/dist/commands/hub/monitor.js +30 -70
- package/dist/commands/hub/notifications.d.ts +3 -3
- package/dist/commands/hub/notifications.js +74 -105
- package/dist/commands/hub/run.d.ts +1 -1
- package/dist/commands/hub/run.js +118 -144
- package/dist/commands/hub/runs.d.ts +1 -1
- package/dist/commands/hub/runs.js +60 -81
- package/dist/commands/hub/secrets.d.ts +8 -8
- package/dist/commands/hub/secrets.js +88 -148
- package/dist/commands/hub/status.d.ts +1 -1
- package/dist/commands/hub/status.js +13 -26
- package/dist/commands/init.js +3 -3
- package/dist/commands/local/run.d.ts +2 -2
- package/dist/commands/local/run.js +37 -42
- package/dist/commands/validate.d.ts +1 -1
- package/dist/commands/validate.js +19 -39
- package/dist/commands/variables.d.ts +3 -3
- package/dist/commands/variables.js +51 -69
- package/dist/core/discovery.js +0 -2
- package/dist/core/monitor-helpers.d.ts +19 -0
- package/dist/core/monitor-helpers.js +48 -0
- package/dist/core/sdk.d.ts +5 -0
- package/dist/core/sdk.js +11 -0
- package/dist/core/state.d.ts +1 -1
- package/dist/core/state.js +0 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/schemas/state.js +1 -1
- package/dist/utils/command-wrapper.d.ts +10 -0
- package/dist/utils/command-wrapper.js +27 -0
- package/dist/utils/sdk-error.js +1 -1
- package/dist/utils/terminal.d.ts +4 -0
- package/dist/utils/terminal.js +17 -0
- package/package.json +4 -4
|
@@ -1,97 +1,76 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
1
|
+
import { createSdkFromState } from "../../core/sdk.js";
|
|
3
2
|
import { terminal } from "../../utils/terminal.js";
|
|
4
3
|
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
4
|
+
import { withCommandErrorHandler } from "../../utils/command-wrapper.js";
|
|
5
5
|
/**
|
|
6
6
|
* Show recent runs from the hub
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
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
|
-
if (!runsData || runsData.total === 0) {
|
|
34
|
-
spinner.info("No runs found.");
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (!Array.isArray(runsData.data)) {
|
|
38
|
-
spinner.fail("Invalid response format");
|
|
39
|
-
terminal.error(`Expected data array but got: ${typeof runsData.data}`);
|
|
40
|
-
terminal.exit(1);
|
|
41
|
-
}
|
|
42
|
-
spinner.succeed(`Found ${runsData.total} run(s)`);
|
|
43
|
-
terminal.blank();
|
|
44
|
-
// Create table
|
|
45
|
-
const table = terminal.table({
|
|
46
|
-
head: ["Status", "Monitor", "Duration", "Started"],
|
|
47
|
-
});
|
|
48
|
-
for (const run of runsData.data) {
|
|
49
|
-
try {
|
|
50
|
-
const statusIcon = getStatusIcon(run.status, run.success);
|
|
51
|
-
const duration = run.duration_ms
|
|
52
|
-
? `${(run.duration_ms / 1000).toFixed(2)}s`
|
|
53
|
-
: "-";
|
|
54
|
-
const started = new Date(run.startedAt).toLocaleString();
|
|
55
|
-
table.push([statusIcon, run.monitorId || "-", duration, started]);
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
terminal.error(`Error processing run ${run.id}: ${error.message}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
8
|
+
export const executeRuns = withCommandErrorHandler(async (options) => {
|
|
9
|
+
// Load state
|
|
10
|
+
const sdk = await createSdkFromState();
|
|
11
|
+
// Get recent runs
|
|
12
|
+
const limit = options.limit || 10;
|
|
13
|
+
const spinner = terminal.spinner("Fetching runs...").start();
|
|
14
|
+
const response = await withSDKErrorHandling(() => sdk.getRuns({
|
|
15
|
+
query: {
|
|
16
|
+
monitorId: options.monitor,
|
|
17
|
+
limit: limit,
|
|
18
|
+
offset: 0,
|
|
19
|
+
},
|
|
20
|
+
}), "Failed to fetch runs");
|
|
21
|
+
const runsData = response?.data;
|
|
22
|
+
if (!runsData || runsData.total === 0) {
|
|
23
|
+
spinner.info("No runs found.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
spinner.succeed(`Found ${runsData.total} run(s)`);
|
|
27
|
+
terminal.blank();
|
|
28
|
+
// Create table
|
|
29
|
+
const table = terminal.table({
|
|
30
|
+
head: ["Status", "Monitor", "Duration", "Started"],
|
|
31
|
+
});
|
|
32
|
+
for (const run of runsData.data) {
|
|
61
33
|
try {
|
|
62
|
-
|
|
34
|
+
const statusIcon = getStatusIcon(run.status, run.success);
|
|
35
|
+
const duration = run.duration_ms
|
|
36
|
+
? `${(run.duration_ms / 1000).toFixed(2)}s`
|
|
37
|
+
: "-";
|
|
38
|
+
const started = new Date(run.startedAt).toLocaleString();
|
|
39
|
+
table.push([statusIcon, run.monitorId || "-", duration, started]);
|
|
63
40
|
}
|
|
64
41
|
catch (error) {
|
|
65
|
-
terminal.error(`Error
|
|
66
|
-
terminal.error(error.stack || "");
|
|
67
|
-
terminal.exit(1);
|
|
68
|
-
}
|
|
69
|
-
// Show detailed errors if any
|
|
70
|
-
const runsWithErrors = runsData.data.filter((run) => Array.isArray(run.errors) && run.errors.length > 0);
|
|
71
|
-
if (runsWithErrors.length > 0) {
|
|
72
|
-
terminal.blank();
|
|
73
|
-
terminal.warn("Runs with errors:");
|
|
74
|
-
terminal.blank();
|
|
75
|
-
for (const run of runsWithErrors) {
|
|
76
|
-
terminal.log(`${terminal.colors.red("✗")} ${terminal.colors.cyan(run.monitorId || run.id)}`);
|
|
77
|
-
if (Array.isArray(run.errors) && run.errors.length > 0) {
|
|
78
|
-
const errorsToShow = run.errors.slice(0, 3);
|
|
79
|
-
for (const error of errorsToShow) {
|
|
80
|
-
terminal.dim(` - ${String(error)}`);
|
|
81
|
-
}
|
|
82
|
-
if (run.errors.length > 3) {
|
|
83
|
-
terminal.dim(` ... and ${run.errors.length - 3} more`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
terminal.blank();
|
|
87
|
-
}
|
|
42
|
+
terminal.error(`Error processing run ${run.id}: ${error.message}`);
|
|
88
43
|
}
|
|
89
44
|
}
|
|
45
|
+
try {
|
|
46
|
+
terminal.log(table.toString());
|
|
47
|
+
}
|
|
90
48
|
catch (error) {
|
|
91
|
-
terminal.error(error.message);
|
|
49
|
+
terminal.error(`Error rendering table: ${error.message}`);
|
|
50
|
+
terminal.error(error.stack || "");
|
|
92
51
|
terminal.exit(1);
|
|
93
52
|
}
|
|
94
|
-
|
|
53
|
+
// Show detailed errors if any
|
|
54
|
+
const runsWithErrors = runsData.data.filter((run) => Array.isArray(run.errors) && run.errors.length > 0);
|
|
55
|
+
if (runsWithErrors.length > 0) {
|
|
56
|
+
terminal.blank();
|
|
57
|
+
terminal.warn("Runs with errors:");
|
|
58
|
+
terminal.blank();
|
|
59
|
+
for (const run of runsWithErrors) {
|
|
60
|
+
terminal.log(`${terminal.colors.red("✗")} ${terminal.colors.cyan(run.monitorId || run.id)}`);
|
|
61
|
+
if (Array.isArray(run.errors) && run.errors.length > 0) {
|
|
62
|
+
const errorsToShow = run.errors.slice(0, 3);
|
|
63
|
+
for (const error of errorsToShow) {
|
|
64
|
+
terminal.dim(` - ${String(error)}`);
|
|
65
|
+
}
|
|
66
|
+
if (run.errors.length > 3) {
|
|
67
|
+
terminal.dim(` ... and ${run.errors.length - 3} more`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
terminal.blank();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
95
74
|
function getStatusIcon(status, success) {
|
|
96
75
|
switch (status) {
|
|
97
76
|
case "pending":
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
export interface SecretsListOptions {
|
|
2
|
-
environment
|
|
2
|
+
environment: string;
|
|
3
3
|
json?: boolean;
|
|
4
4
|
}
|
|
5
5
|
export interface SecretsSetOptions {
|
|
6
6
|
name: string;
|
|
7
|
-
environment
|
|
7
|
+
environment: string;
|
|
8
8
|
value?: string;
|
|
9
9
|
}
|
|
10
10
|
export interface SecretsGetOptions {
|
|
11
11
|
name: string;
|
|
12
|
-
environment
|
|
12
|
+
environment: string;
|
|
13
13
|
json?: boolean;
|
|
14
14
|
}
|
|
15
15
|
export interface SecretsDeleteOptions {
|
|
16
16
|
name: string;
|
|
17
|
-
environment
|
|
17
|
+
environment: string;
|
|
18
18
|
force?: boolean;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
@@ -22,16 +22,16 @@ export interface SecretsDeleteOptions {
|
|
|
22
22
|
* Uses the resolved secrets integration for the organization and environment
|
|
23
23
|
* (from hub integrations API or platform default / legacy config).
|
|
24
24
|
*/
|
|
25
|
-
export declare
|
|
25
|
+
export declare const executeSecretsList: (options: SecretsListOptions) => Promise<void>;
|
|
26
26
|
/**
|
|
27
27
|
* Set a secret (prompts for value if not provided)
|
|
28
28
|
*/
|
|
29
|
-
export declare
|
|
29
|
+
export declare const executeSecretsSet: (options: SecretsSetOptions) => Promise<void>;
|
|
30
30
|
/**
|
|
31
31
|
* Get secret metadata only
|
|
32
32
|
*/
|
|
33
|
-
export declare
|
|
33
|
+
export declare const executeSecretsGet: (options: SecretsGetOptions) => Promise<void>;
|
|
34
34
|
/**
|
|
35
35
|
* Delete a secret (with confirmation unless --force)
|
|
36
36
|
*/
|
|
37
|
-
export declare
|
|
37
|
+
export declare const executeSecretsDelete: (options: SecretsDeleteOptions) => Promise<void>;
|
|
@@ -1,98 +1,69 @@
|
|
|
1
1
|
import { createInterface } from "node:readline";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveEnvironment } from "../../core/state.js";
|
|
3
3
|
import { terminal } from "../../utils/terminal.js";
|
|
4
4
|
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createSdkFromState } from "../../core/sdk.js";
|
|
6
|
+
import { withCommandErrorHandler, outputJsonOrContinue, } from "../../utils/command-wrapper.js";
|
|
6
7
|
const SECRET_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7
8
|
/**
|
|
8
9
|
* List secrets (metadata only).
|
|
9
10
|
* Uses the resolved secrets integration for the organization and environment
|
|
10
11
|
* (from hub integrations API or platform default / legacy config).
|
|
11
12
|
*/
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
const baseUrl = state.hub.baseUrl;
|
|
22
|
-
const sdk = await createSdkWithCredentials(baseUrl);
|
|
23
|
-
const env = options.environment ?? "default";
|
|
24
|
-
const response = await withSDKErrorHandling(async () => {
|
|
25
|
-
return sdk.getSecrets({
|
|
26
|
-
query: {
|
|
27
|
-
environment: env,
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
}, "Failed to list secrets");
|
|
31
|
-
const secrets = response?.data?.data ?? [];
|
|
32
|
-
if (options.json) {
|
|
33
|
-
terminal.log(JSON.stringify(secrets, null, 2));
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (secrets.length === 0) {
|
|
37
|
-
terminal.info(`No secrets found for environment "${env}".`);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
terminal.info(`Secrets (environment: ${env})`);
|
|
41
|
-
terminal.blank();
|
|
42
|
-
const table = terminal.table({
|
|
43
|
-
head: ["Name", "Created", "Updated"],
|
|
13
|
+
export const executeSecretsList = withCommandErrorHandler(async (options) => {
|
|
14
|
+
const sdk = await createSdkFromState();
|
|
15
|
+
const env = await resolveEnvironment(options.environment);
|
|
16
|
+
const response = await withSDKErrorHandling(async () => {
|
|
17
|
+
return sdk.getSecrets({
|
|
18
|
+
query: {
|
|
19
|
+
environment: env,
|
|
20
|
+
},
|
|
44
21
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
22
|
+
}, "Failed to list secrets");
|
|
23
|
+
const secrets = response?.data?.data ?? [];
|
|
24
|
+
if (outputJsonOrContinue(secrets, options.json))
|
|
25
|
+
return;
|
|
26
|
+
if (secrets.length === 0) {
|
|
27
|
+
terminal.info(`No secrets found for environment "${env}".`);
|
|
28
|
+
return;
|
|
49
29
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
30
|
+
terminal.info(`Secrets (environment: ${env})`);
|
|
31
|
+
terminal.blank();
|
|
32
|
+
const table = terminal.table({
|
|
33
|
+
head: ["Name", "Created", "Updated"],
|
|
34
|
+
});
|
|
35
|
+
for (const s of secrets) {
|
|
36
|
+
table.push([s.name, s.createdAt ?? "-", s.updatedAt ?? "-"]);
|
|
53
37
|
}
|
|
54
|
-
|
|
38
|
+
terminal.log(table.toString());
|
|
39
|
+
});
|
|
55
40
|
/**
|
|
56
41
|
* Set a secret (prompts for value if not provided)
|
|
57
42
|
*/
|
|
58
|
-
export
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
terminal.
|
|
68
|
-
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
43
|
+
export const executeSecretsSet = withCommandErrorHandler(async (options) => {
|
|
44
|
+
if (!SECRET_NAME_REGEX.test(options.name)) {
|
|
45
|
+
terminal.error("Secret name must start with a letter or underscore and contain only letters, numbers, and underscores.");
|
|
46
|
+
terminal.exit(1);
|
|
47
|
+
}
|
|
48
|
+
let value = options.value;
|
|
49
|
+
if (value === undefined) {
|
|
50
|
+
value = await promptSecret("Enter secret value:");
|
|
51
|
+
if (!value) {
|
|
52
|
+
terminal.error("Secret value cannot be empty.");
|
|
69
53
|
terminal.exit(1);
|
|
70
54
|
}
|
|
71
|
-
let value = options.value;
|
|
72
|
-
if (value === undefined) {
|
|
73
|
-
value = await promptSecret("Enter secret value:");
|
|
74
|
-
if (!value) {
|
|
75
|
-
terminal.error("Secret value cannot be empty.");
|
|
76
|
-
terminal.exit(1);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
const baseUrl = state.hub.baseUrl;
|
|
80
|
-
const env = options.environment ?? "default";
|
|
81
|
-
const sdk = await createSdkWithCredentials(baseUrl);
|
|
82
|
-
const response = await withSDKErrorHandling(async () => {
|
|
83
|
-
return sdk.putSecretsByName({
|
|
84
|
-
path: { name: options.name },
|
|
85
|
-
body: { value, environment: env },
|
|
86
|
-
});
|
|
87
|
-
}, "Failed to set secret");
|
|
88
|
-
const result = response?.data;
|
|
89
|
-
terminal.success(`Secret "${result.data.name}" saved.`);
|
|
90
55
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
56
|
+
const sdk = await createSdkFromState();
|
|
57
|
+
const env = await resolveEnvironment(options.environment);
|
|
58
|
+
const response = await withSDKErrorHandling(async () => {
|
|
59
|
+
return sdk.putSecretsByName({
|
|
60
|
+
path: { name: options.name },
|
|
61
|
+
body: { value, environment: env },
|
|
62
|
+
});
|
|
63
|
+
}, "Failed to set secret");
|
|
64
|
+
const result = response?.data;
|
|
65
|
+
terminal.success(`Secret "${result.data.name}" saved.`);
|
|
66
|
+
});
|
|
96
67
|
function promptSecret(promptText) {
|
|
97
68
|
return new Promise((resolve) => {
|
|
98
69
|
const rl = createInterface({
|
|
@@ -108,80 +79,49 @@ function promptSecret(promptText) {
|
|
|
108
79
|
/**
|
|
109
80
|
* Get secret metadata only
|
|
110
81
|
*/
|
|
111
|
-
export
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
});
|
|
128
|
-
}, "Failed to get secret");
|
|
129
|
-
const secret = response?.data?.data;
|
|
130
|
-
if (options.json) {
|
|
131
|
-
terminal.log(JSON.stringify(secret, null, 2));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
terminal.info(`Secret: ${secret.name}`);
|
|
135
|
-
terminal.dim(`Created: ${secret.createdAt ?? "-"}`);
|
|
136
|
-
terminal.dim(`Updated: ${secret.updatedAt ?? "-"}`);
|
|
137
|
-
}
|
|
138
|
-
catch (error) {
|
|
139
|
-
terminal.error(error.message);
|
|
140
|
-
terminal.exit(1);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
82
|
+
export const executeSecretsGet = withCommandErrorHandler(async (options) => {
|
|
83
|
+
const sdk = await createSdkFromState();
|
|
84
|
+
const env = await resolveEnvironment(options.environment);
|
|
85
|
+
const response = await withSDKErrorHandling(async () => {
|
|
86
|
+
return sdk.getSecretsByName({
|
|
87
|
+
path: { name: options.name },
|
|
88
|
+
query: { environment: env },
|
|
89
|
+
});
|
|
90
|
+
}, "Failed to get secret");
|
|
91
|
+
const secret = response?.data?.data;
|
|
92
|
+
if (outputJsonOrContinue(secret, options.json))
|
|
93
|
+
return;
|
|
94
|
+
terminal.info(`Secret: ${secret.name}`);
|
|
95
|
+
terminal.dim(`Created: ${secret.createdAt ?? "-"}`);
|
|
96
|
+
terminal.dim(`Updated: ${secret.updatedAt ?? "-"}`);
|
|
97
|
+
});
|
|
143
98
|
/**
|
|
144
99
|
* Delete a secret (with confirmation unless --force)
|
|
145
100
|
*/
|
|
146
|
-
export
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (!options.force) {
|
|
159
|
-
const rl = createInterface({
|
|
160
|
-
input: process.stdin,
|
|
161
|
-
output: process.stdout,
|
|
162
|
-
});
|
|
163
|
-
const answer = await new Promise((resolve) => {
|
|
164
|
-
rl.question(`Delete secret "${options.name}" (environment: ${env})? [y/N] `, (a) => {
|
|
165
|
-
rl.close();
|
|
166
|
-
resolve(a.trim().toLowerCase());
|
|
167
|
-
});
|
|
101
|
+
export const executeSecretsDelete = withCommandErrorHandler(async (options) => {
|
|
102
|
+
const sdk = await createSdkFromState();
|
|
103
|
+
const env = await resolveEnvironment(options.environment);
|
|
104
|
+
if (!options.force) {
|
|
105
|
+
const rl = createInterface({
|
|
106
|
+
input: process.stdin,
|
|
107
|
+
output: process.stdout,
|
|
108
|
+
});
|
|
109
|
+
const answer = await new Promise((resolve) => {
|
|
110
|
+
rl.question(`Delete secret "${options.name}" (environment: ${env})? [y/N] `, (a) => {
|
|
111
|
+
rl.close();
|
|
112
|
+
resolve(a.trim().toLowerCase());
|
|
168
113
|
});
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
114
|
+
});
|
|
115
|
+
if (answer !== "y" && answer !== "yes") {
|
|
116
|
+
terminal.info("Aborted.");
|
|
117
|
+
return;
|
|
173
118
|
}
|
|
174
|
-
const response = await withSDKErrorHandling(async () => {
|
|
175
|
-
return sdk.deleteSecretsByName({
|
|
176
|
-
path: { name: options.name },
|
|
177
|
-
query: { environment: env },
|
|
178
|
-
});
|
|
179
|
-
}, "Failed to delete secret");
|
|
180
|
-
const result = response?.data;
|
|
181
|
-
terminal.success(`Secret deleted.`);
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
terminal.error(error.message);
|
|
185
|
-
terminal.exit(1);
|
|
186
119
|
}
|
|
187
|
-
|
|
120
|
+
await withSDKErrorHandling(async () => {
|
|
121
|
+
return sdk.deleteSecretsByName({
|
|
122
|
+
path: { name: options.name },
|
|
123
|
+
query: { environment: env },
|
|
124
|
+
});
|
|
125
|
+
}, "Failed to delete secret");
|
|
126
|
+
terminal.success(`Secret deleted.`);
|
|
127
|
+
});
|
|
@@ -1,34 +1,21 @@
|
|
|
1
1
|
import { loadState } from "../../core/state.js";
|
|
2
2
|
import { getHubCredentials } from "../../core/credentials.js";
|
|
3
3
|
import { terminal } from "../../utils/terminal.js";
|
|
4
|
+
import { withCommandErrorHandler } from "../../utils/command-wrapper.js";
|
|
4
5
|
/**
|
|
5
6
|
* Show hub connection status
|
|
6
7
|
*/
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
// Read credentials from user-level credentials file
|
|
18
|
-
const credentials = await getHubCredentials();
|
|
19
|
-
terminal.info("Hub connection:");
|
|
20
|
-
terminal.log(` URL: ${terminal.colors.cyan(state.hub.baseUrl)}`);
|
|
21
|
-
if (credentials?.token) {
|
|
22
|
-
terminal.log(` API Token: ${terminal.colors.dim(credentials.token.substring(0, 8) + "...")}`);
|
|
23
|
-
terminal.log(` Updated: ${terminal.colors.dim(new Date(credentials.updatedAt).toLocaleString())}`);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
terminal.log(` API Token: ${terminal.colors.dim("(not set)")}`);
|
|
27
|
-
}
|
|
28
|
-
terminal.blank();
|
|
8
|
+
export const executeStatus = withCommandErrorHandler(async () => {
|
|
9
|
+
const state = await loadState();
|
|
10
|
+
const credentials = await getHubCredentials();
|
|
11
|
+
terminal.info("Hub connection:");
|
|
12
|
+
terminal.log(` URL: ${terminal.colors.cyan(state.hub.baseUrl)}`);
|
|
13
|
+
if (credentials?.token) {
|
|
14
|
+
terminal.log(` API Token: ${terminal.colors.dim(credentials.token.substring(0, 8) + "...")}`);
|
|
15
|
+
terminal.log(` Updated: ${terminal.colors.dim(new Date(credentials.updatedAt).toLocaleString())}`);
|
|
29
16
|
}
|
|
30
|
-
|
|
31
|
-
terminal.
|
|
32
|
-
terminal.exit(1);
|
|
17
|
+
else {
|
|
18
|
+
terminal.log(` API Token: ${terminal.colors.dim("(not set)")}`);
|
|
33
19
|
}
|
|
34
|
-
|
|
20
|
+
terminal.blank();
|
|
21
|
+
});
|
package/dist/commands/init.js
CHANGED
|
@@ -29,10 +29,10 @@ export async function executeInit(options) {
|
|
|
29
29
|
terminal.dim(" griffin variables add API_KEY=your-key --env default");
|
|
30
30
|
terminal.dim(" 2. Create test monitors (*.ts files in __griffin__/ directories)");
|
|
31
31
|
terminal.dim(" 3. Run tests locally:");
|
|
32
|
-
terminal.dim(" griffin
|
|
32
|
+
terminal.dim(" griffin test");
|
|
33
33
|
terminal.dim(" 4. Connect to hub (optional):");
|
|
34
|
-
terminal.dim(" griffin
|
|
34
|
+
terminal.dim(" griffin auth connect --url <url> --token <token>");
|
|
35
35
|
terminal.dim(" 5. Deploy to hub:");
|
|
36
|
-
terminal.dim(" griffin
|
|
36
|
+
terminal.dim(" griffin apply");
|
|
37
37
|
terminal.blank();
|
|
38
38
|
}
|
|
@@ -3,54 +3,49 @@ import { runTestFile } from "../../monitor-runner.js";
|
|
|
3
3
|
import { resolveEnvironment } from "../../core/state.js";
|
|
4
4
|
import { terminal } from "../../utils/terminal.js";
|
|
5
5
|
import { basename } from "path";
|
|
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
|
-
else {
|
|
33
|
-
testSpinner.fail(`${terminal.colors.cyan(fileName)} failed`);
|
|
34
|
-
}
|
|
35
|
-
return result;
|
|
36
|
-
}));
|
|
37
|
-
// Print summary
|
|
38
|
-
const successful = results.filter((r) => r.success).length;
|
|
39
|
-
const failed = results.length - successful;
|
|
40
|
-
terminal.blank();
|
|
41
|
-
if (failed === 0) {
|
|
42
|
-
terminal.success(`All tests passed (${terminal.colors.bold(successful.toString())} / ${results.length})`);
|
|
6
|
+
import { withCommandErrorHandler } from "../../utils/command-wrapper.js";
|
|
7
|
+
export const executeRunLocal = withCommandErrorHandler(async (options) => {
|
|
8
|
+
// Resolve environment
|
|
9
|
+
const envName = await resolveEnvironment(options.env);
|
|
10
|
+
terminal.info(`Running tests locally against ${terminal.colors.cyan(envName)} environment`);
|
|
11
|
+
terminal.dim(`Variables will be loaded from variables.yaml for environment: ${envName}`);
|
|
12
|
+
terminal.blank();
|
|
13
|
+
const spinner = terminal.spinner("Discovering test files...").start();
|
|
14
|
+
const testFiles = findTestFiles();
|
|
15
|
+
if (testFiles.length === 0) {
|
|
16
|
+
spinner.fail("No test files found");
|
|
17
|
+
terminal.dim("Looking for .ts files in __griffin__ directories.");
|
|
18
|
+
terminal.exit(1);
|
|
19
|
+
}
|
|
20
|
+
spinner.succeed(`Found ${terminal.colors.bold(testFiles.length.toString())} test file(s)`);
|
|
21
|
+
testFiles.forEach((file) => terminal.dim(` - ${file}`));
|
|
22
|
+
terminal.blank();
|
|
23
|
+
const results = await Promise.all(testFiles.map(async (file) => {
|
|
24
|
+
const fileName = basename(file);
|
|
25
|
+
const testSpinner = terminal
|
|
26
|
+
.spinner(`Running ${terminal.colors.cyan(fileName)}`)
|
|
27
|
+
.start();
|
|
28
|
+
const result = await runTest(file, envName);
|
|
29
|
+
if (result.success) {
|
|
30
|
+
testSpinner.succeed(`${terminal.colors.cyan(fileName)} passed`);
|
|
43
31
|
}
|
|
44
32
|
else {
|
|
45
|
-
|
|
46
|
-
terminal.exit(1);
|
|
33
|
+
testSpinner.fail(`${terminal.colors.cyan(fileName)} failed`);
|
|
47
34
|
}
|
|
35
|
+
return result;
|
|
36
|
+
}));
|
|
37
|
+
// Print summary
|
|
38
|
+
const successful = results.filter((r) => r.success).length;
|
|
39
|
+
const failed = results.length - successful;
|
|
40
|
+
terminal.blank();
|
|
41
|
+
if (failed === 0) {
|
|
42
|
+
terminal.success(`All tests passed (${terminal.colors.bold(successful.toString())} / ${results.length})`);
|
|
48
43
|
}
|
|
49
|
-
|
|
50
|
-
terminal.error(
|
|
44
|
+
else {
|
|
45
|
+
terminal.error(`${terminal.colors.bold(failed.toString())} test(s) failed, ${terminal.colors.bold(successful.toString())} passed`);
|
|
51
46
|
terminal.exit(1);
|
|
52
47
|
}
|
|
53
|
-
}
|
|
48
|
+
});
|
|
54
49
|
async function runTest(file, envName) {
|
|
55
50
|
try {
|
|
56
51
|
const result = await runTestFile(file, envName);
|