@griffin-app/griffin-cli 1.0.18 → 1.0.19
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 +61 -89
- 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/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 +1 -1
|
@@ -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);
|
|
@@ -1,47 +1,27 @@
|
|
|
1
1
|
import { loadState } from "../core/state.js";
|
|
2
|
-
import { discoverMonitors, formatDiscoveryErrors } from "../core/discovery.js";
|
|
3
2
|
import { terminal } from "../utils/terminal.js";
|
|
3
|
+
import { withCommandErrorHandler } from "../utils/command-wrapper.js";
|
|
4
|
+
import { discoverLocalMonitors } from "../core/monitor-helpers.js";
|
|
4
5
|
/**
|
|
5
6
|
* Validate test monitor files without syncing
|
|
6
7
|
*/
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
terminal.blank();
|
|
23
|
-
terminal.error(formatDiscoveryErrors(errors));
|
|
24
|
-
terminal.exit(1);
|
|
8
|
+
export const executeValidate = withCommandErrorHandler(async () => {
|
|
9
|
+
// Load state for discovery settings
|
|
10
|
+
const state = await loadState();
|
|
11
|
+
// Discover monitors
|
|
12
|
+
const { monitors } = await discoverLocalMonitors(state);
|
|
13
|
+
// Report success
|
|
14
|
+
terminal.blank();
|
|
15
|
+
for (const { monitor, filePath, exportName } of monitors) {
|
|
16
|
+
const shortPath = filePath.replace(process.cwd(), ".");
|
|
17
|
+
const exportInfo = exportName === "default" ? "" : terminal.colors.dim(` (${exportName})`);
|
|
18
|
+
terminal.log(` ${terminal.colors.green("●")} ${terminal.colors.cyan(monitor.name)}${exportInfo}`);
|
|
19
|
+
terminal.dim(` ${shortPath}`);
|
|
20
|
+
terminal.dim(` Nodes: ${monitor.nodes.length}, Edges: ${monitor.edges.length}`);
|
|
21
|
+
if (monitor.frequency) {
|
|
22
|
+
terminal.dim(` Schedule: Every ${monitor.frequency.every} ${monitor.frequency.unit}`);
|
|
25
23
|
}
|
|
26
|
-
// Report success
|
|
27
|
-
spinner.succeed(`Found ${terminal.colors.bold(monitors.length.toString())} valid monitor(s)`);
|
|
28
24
|
terminal.blank();
|
|
29
|
-
for (const { monitor, filePath, exportName } of monitors) {
|
|
30
|
-
const shortPath = filePath.replace(process.cwd(), ".");
|
|
31
|
-
const exportInfo = exportName === "default" ? "" : terminal.colors.dim(` (${exportName})`);
|
|
32
|
-
terminal.log(` ${terminal.colors.green("●")} ${terminal.colors.cyan(monitor.name)}${exportInfo}`);
|
|
33
|
-
terminal.dim(` ${shortPath}`);
|
|
34
|
-
terminal.dim(` Nodes: ${monitor.nodes.length}, Edges: ${monitor.edges.length}`);
|
|
35
|
-
if (monitor.frequency) {
|
|
36
|
-
terminal.dim(` Schedule: Every ${monitor.frequency.every} ${monitor.frequency.unit}`);
|
|
37
|
-
}
|
|
38
|
-
terminal.blank();
|
|
39
|
-
}
|
|
40
|
-
terminal.success("All monitors are valid");
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
spinner.fail("Validation failed");
|
|
44
|
-
terminal.error(error.message);
|
|
45
|
-
terminal.exit(1);
|
|
46
25
|
}
|
|
47
|
-
|
|
26
|
+
terminal.success("All monitors are valid");
|
|
27
|
+
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* List all variables for an environment
|
|
3
3
|
*/
|
|
4
|
-
export declare
|
|
4
|
+
export declare const executeVariablesList: (env: string) => Promise<void>;
|
|
5
5
|
/**
|
|
6
6
|
* Add or update a variable for an environment
|
|
7
7
|
*/
|
|
8
|
-
export declare
|
|
8
|
+
export declare const executeVariablesAdd: (keyValue: string, env: string) => Promise<void>;
|
|
9
9
|
/**
|
|
10
10
|
* Remove a variable from an environment
|
|
11
11
|
*/
|
|
12
|
-
export declare
|
|
12
|
+
export declare const executeVariablesRemove: (key: string, env: string) => Promise<void>;
|