@griffin-app/griffin-cli 1.0.25 → 1.0.28
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 +122 -367
- package/dist/cli.js +48 -29
- package/dist/commands/env.d.ts +14 -3
- package/dist/commands/env.js +24 -22
- package/dist/commands/generate-key.d.ts +5 -6
- package/dist/commands/generate-key.js +20 -26
- package/dist/commands/hub/apply.d.ts +1 -0
- package/dist/commands/hub/apply.js +44 -29
- package/dist/commands/hub/connect.d.ts +2 -1
- package/dist/commands/hub/connect.js +18 -22
- package/dist/commands/hub/destroy.d.ts +2 -1
- package/dist/commands/hub/destroy.js +123 -119
- package/dist/commands/hub/integrations.d.ts +4 -1
- package/dist/commands/hub/integrations.js +160 -141
- package/dist/commands/hub/login.d.ts +13 -1
- package/dist/commands/hub/login.js +81 -15
- package/dist/commands/hub/logout.d.ts +2 -1
- package/dist/commands/hub/logout.js +7 -12
- package/dist/commands/hub/metrics.js +29 -27
- package/dist/commands/hub/monitor.js +16 -16
- package/dist/commands/hub/notifications.d.ts +3 -6
- package/dist/commands/hub/notifications.js +52 -38
- package/dist/commands/hub/run.d.ts +1 -0
- package/dist/commands/hub/run.js +114 -87
- package/dist/commands/hub/runs.d.ts +2 -0
- package/dist/commands/hub/runs.js +47 -45
- package/dist/commands/hub/secrets.d.ts +5 -5
- package/dist/commands/hub/secrets.js +80 -72
- package/dist/commands/hub/status.d.ts +4 -1
- package/dist/commands/hub/status.js +15 -9
- package/dist/commands/init.d.ts +2 -1
- package/dist/commands/init.js +31 -25
- package/dist/commands/local/run.d.ts +1 -0
- package/dist/commands/local/run.js +34 -26
- package/dist/commands/validate.d.ts +4 -1
- package/dist/commands/validate.js +23 -14
- package/dist/commands/variables.d.ts +17 -3
- package/dist/commands/variables.js +29 -28
- package/dist/core/credentials.d.ts +15 -0
- package/dist/core/credentials.js +37 -0
- package/dist/core/variables.js +4 -0
- package/dist/monitor-runner.js +0 -12
- package/dist/utils/command-wrapper.d.ts +9 -0
- package/dist/utils/command-wrapper.js +23 -0
- package/dist/utils/output.d.ts +66 -0
- package/dist/utils/output.js +202 -0
- package/dist/utils/sdk-error.d.ts +6 -1
- package/dist/utils/sdk-error.js +107 -77
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -24,33 +24,34 @@ const program = new Command();
|
|
|
24
24
|
program
|
|
25
25
|
.name("griffin")
|
|
26
26
|
.description("Griffin CLI - API Monitoring as Code")
|
|
27
|
-
.version("1.0.0")
|
|
27
|
+
.version("1.0.0")
|
|
28
|
+
.option("--json", "Output as JSON (for scripts and AI agents)");
|
|
28
29
|
// Top-level commands
|
|
29
30
|
program
|
|
30
31
|
.command("init")
|
|
31
32
|
.description("Initialize griffin in the current directory")
|
|
32
33
|
.option("--project <name>", "Project ID (defaults to package.json name or directory name)")
|
|
33
34
|
.action(async (options) => {
|
|
34
|
-
await executeInit(options);
|
|
35
|
+
await executeInit({ ...options, json: program.opts().json });
|
|
35
36
|
});
|
|
36
37
|
program
|
|
37
38
|
.command("validate")
|
|
38
39
|
.description("Check monitor files for errors")
|
|
39
40
|
.action(async () => {
|
|
40
|
-
await executeValidate();
|
|
41
|
+
await executeValidate({ json: program.opts().json });
|
|
41
42
|
});
|
|
42
43
|
program
|
|
43
44
|
.command("status")
|
|
44
45
|
.description("Show project and connection status")
|
|
45
46
|
.action(async () => {
|
|
46
|
-
await executeStatus();
|
|
47
|
+
await executeStatus({ json: program.opts().json });
|
|
47
48
|
});
|
|
48
49
|
program
|
|
49
50
|
.command("test")
|
|
50
51
|
.description("Run monitors locally")
|
|
51
52
|
.option("--env <name>", "Environment name", "default")
|
|
52
53
|
.action(async (options) => {
|
|
53
|
-
await executeRunLocal({ env: options.env });
|
|
54
|
+
await executeRunLocal({ env: options.env, json: program.opts().json });
|
|
54
55
|
});
|
|
55
56
|
program
|
|
56
57
|
.command("plan")
|
|
@@ -58,7 +59,7 @@ program
|
|
|
58
59
|
.option("--env <name>", "Environment name", "default")
|
|
59
60
|
.option("--json", "Output in JSON format")
|
|
60
61
|
.action(async (options) => {
|
|
61
|
-
await executePlan({ ...options, env: options.env });
|
|
62
|
+
await executePlan({ ...options, env: options.env, json: program.opts().json ?? options.json });
|
|
62
63
|
});
|
|
63
64
|
program
|
|
64
65
|
.command("apply")
|
|
@@ -68,7 +69,7 @@ program
|
|
|
68
69
|
.option("--dry-run", "Show what would be done without making changes")
|
|
69
70
|
.option("--prune", "Delete monitors on hub that don't exist locally")
|
|
70
71
|
.action(async (options) => {
|
|
71
|
-
await executeApply({ ...options, env: options.env });
|
|
72
|
+
await executeApply({ ...options, env: options.env, json: program.opts().json });
|
|
72
73
|
});
|
|
73
74
|
program
|
|
74
75
|
.command("runs")
|
|
@@ -81,6 +82,7 @@ program
|
|
|
81
82
|
...options,
|
|
82
83
|
env: options.env,
|
|
83
84
|
limit: parseInt(options.limit, 10),
|
|
85
|
+
json: program.opts().json,
|
|
84
86
|
});
|
|
85
87
|
});
|
|
86
88
|
program
|
|
@@ -91,7 +93,7 @@ program
|
|
|
91
93
|
.option("--wait", "Wait for run to complete")
|
|
92
94
|
.option("--force", "Run even if local monitor differs from hub")
|
|
93
95
|
.action(async (options) => {
|
|
94
|
-
await executeRun({ ...options, env: options.env });
|
|
96
|
+
await executeRun({ ...options, env: options.env, json: program.opts().json });
|
|
95
97
|
});
|
|
96
98
|
program
|
|
97
99
|
.command("metrics")
|
|
@@ -103,7 +105,7 @@ program
|
|
|
103
105
|
await executeMetrics({
|
|
104
106
|
period: options.period,
|
|
105
107
|
environment: options.env,
|
|
106
|
-
json: options.json,
|
|
108
|
+
json: program.opts().json ?? options.json,
|
|
107
109
|
});
|
|
108
110
|
});
|
|
109
111
|
program
|
|
@@ -114,21 +116,27 @@ program
|
|
|
114
116
|
.option("--auto-approve", "Skip confirmation prompt")
|
|
115
117
|
.option("--dry-run", "Show what would be destroyed without making changes")
|
|
116
118
|
.action(async (env, options) => {
|
|
117
|
-
await executeDestroy({ ...options, env });
|
|
119
|
+
await executeDestroy({ ...options, env, json: program.opts().json });
|
|
118
120
|
});
|
|
119
121
|
// Auth command group
|
|
120
122
|
const auth = program.command("auth").description("Manage authentication");
|
|
121
123
|
auth
|
|
122
124
|
.command("login")
|
|
123
125
|
.description("Authenticate with Griffin Cloud")
|
|
124
|
-
.
|
|
125
|
-
|
|
126
|
+
.option("--no-poll", "Only output auth URL and exit; run again with --poll after completing authorization")
|
|
127
|
+
.option("--poll", "Poll for completion after user has authorized in browser (use after --no-poll)")
|
|
128
|
+
.action(async (options) => {
|
|
129
|
+
await executeLogin({
|
|
130
|
+
json: program.opts().json,
|
|
131
|
+
noPoll: options.noPoll,
|
|
132
|
+
poll: options.poll,
|
|
133
|
+
});
|
|
126
134
|
});
|
|
127
135
|
auth
|
|
128
136
|
.command("logout")
|
|
129
137
|
.description("Clear stored credentials")
|
|
130
138
|
.action(async (options) => {
|
|
131
|
-
await executeLogout(options);
|
|
139
|
+
await executeLogout({ ...options, json: program.opts().json });
|
|
132
140
|
});
|
|
133
141
|
auth
|
|
134
142
|
.command("connect")
|
|
@@ -136,13 +144,13 @@ auth
|
|
|
136
144
|
.requiredOption("--url <url>", "Hub URL")
|
|
137
145
|
.requiredOption("--token <token>", "API authentication token")
|
|
138
146
|
.action(async (options) => {
|
|
139
|
-
await executeConnect(options);
|
|
147
|
+
await executeConnect({ ...options, json: program.opts().json });
|
|
140
148
|
});
|
|
141
149
|
auth
|
|
142
150
|
.command("generate-key")
|
|
143
151
|
.description("Generate an API key")
|
|
144
152
|
.action(async () => {
|
|
145
|
-
await executeGenerateKey();
|
|
153
|
+
await executeGenerateKey({ json: program.opts().json });
|
|
146
154
|
});
|
|
147
155
|
// Environment command group
|
|
148
156
|
const env = program.command("env").description("Manage environments");
|
|
@@ -150,19 +158,19 @@ env
|
|
|
150
158
|
.command("list")
|
|
151
159
|
.description("List configured environments")
|
|
152
160
|
.action(async () => {
|
|
153
|
-
await executeEnvList();
|
|
161
|
+
await executeEnvList({ json: program.opts().json });
|
|
154
162
|
});
|
|
155
163
|
env
|
|
156
164
|
.command("add <name>")
|
|
157
165
|
.description("Add an environment")
|
|
158
166
|
.action(async (name) => {
|
|
159
|
-
await executeEnvAdd(name);
|
|
167
|
+
await executeEnvAdd({ name, json: program.opts().json });
|
|
160
168
|
});
|
|
161
169
|
env
|
|
162
170
|
.command("remove <name>")
|
|
163
171
|
.description("Remove an environment")
|
|
164
172
|
.action(async (name) => {
|
|
165
|
-
await executeEnvRemove(name);
|
|
173
|
+
await executeEnvRemove({ name, json: program.opts().json });
|
|
166
174
|
});
|
|
167
175
|
// Variables command group
|
|
168
176
|
const variables = program
|
|
@@ -173,21 +181,29 @@ variables
|
|
|
173
181
|
.description("List variables for an environment")
|
|
174
182
|
.option("--env <name>", "Environment name", "default")
|
|
175
183
|
.action(async (options) => {
|
|
176
|
-
await executeVariablesList(options.env);
|
|
184
|
+
await executeVariablesList({ env: options.env, json: program.opts().json });
|
|
177
185
|
});
|
|
178
186
|
variables
|
|
179
187
|
.command("add <keyValue>")
|
|
180
188
|
.description("Set a variable (KEY=VALUE)")
|
|
181
189
|
.option("--env <name>", "Environment name", "default")
|
|
182
190
|
.action(async (keyValue, options) => {
|
|
183
|
-
await executeVariablesAdd(
|
|
191
|
+
await executeVariablesAdd({
|
|
192
|
+
keyValue,
|
|
193
|
+
env: options.env,
|
|
194
|
+
json: program.opts().json,
|
|
195
|
+
});
|
|
184
196
|
});
|
|
185
197
|
variables
|
|
186
198
|
.command("remove <key>")
|
|
187
199
|
.description("Remove a variable")
|
|
188
200
|
.option("--env <name>", "Environment name", "default")
|
|
189
201
|
.action(async (key, options) => {
|
|
190
|
-
await executeVariablesRemove(
|
|
202
|
+
await executeVariablesRemove({
|
|
203
|
+
key,
|
|
204
|
+
env: options.env,
|
|
205
|
+
json: program.opts().json,
|
|
206
|
+
});
|
|
191
207
|
});
|
|
192
208
|
// Secrets command group
|
|
193
209
|
const secrets = program
|
|
@@ -201,7 +217,7 @@ secrets
|
|
|
201
217
|
.action(async (options) => {
|
|
202
218
|
await executeSecretsList({
|
|
203
219
|
environment: options.env,
|
|
204
|
-
json: options.json,
|
|
220
|
+
json: program.opts().json ?? options.json,
|
|
205
221
|
});
|
|
206
222
|
});
|
|
207
223
|
secrets
|
|
@@ -214,6 +230,7 @@ secrets
|
|
|
214
230
|
name,
|
|
215
231
|
environment: options.env,
|
|
216
232
|
value: options.value,
|
|
233
|
+
json: program.opts().json,
|
|
217
234
|
});
|
|
218
235
|
});
|
|
219
236
|
secrets
|
|
@@ -225,7 +242,7 @@ secrets
|
|
|
225
242
|
await executeSecretsGet({
|
|
226
243
|
name,
|
|
227
244
|
environment: options.env,
|
|
228
|
-
json: options.json,
|
|
245
|
+
json: program.opts().json ?? options.json,
|
|
229
246
|
});
|
|
230
247
|
});
|
|
231
248
|
secrets
|
|
@@ -238,6 +255,7 @@ secrets
|
|
|
238
255
|
name,
|
|
239
256
|
environment: options.env,
|
|
240
257
|
force: options.force,
|
|
258
|
+
json: program.opts().json,
|
|
241
259
|
});
|
|
242
260
|
});
|
|
243
261
|
// Integrations command group
|
|
@@ -258,7 +276,7 @@ integrations
|
|
|
258
276
|
provider: options.provider,
|
|
259
277
|
environment: options.env,
|
|
260
278
|
enabled: options.enabled ? true : undefined,
|
|
261
|
-
json: options.json,
|
|
279
|
+
json: program.opts().json ?? options.json,
|
|
262
280
|
});
|
|
263
281
|
});
|
|
264
282
|
integrations
|
|
@@ -266,7 +284,7 @@ integrations
|
|
|
266
284
|
.description("Show integration details")
|
|
267
285
|
.option("--json", "Output as JSON")
|
|
268
286
|
.action(async (id, options) => {
|
|
269
|
-
await executeIntegrationsShow({ id, json: options.json });
|
|
287
|
+
await executeIntegrationsShow({ id, json: program.opts().json ?? options.json });
|
|
270
288
|
});
|
|
271
289
|
integrations
|
|
272
290
|
.command("connect [type] [provider]")
|
|
@@ -280,7 +298,7 @@ integrations
|
|
|
280
298
|
provider: provider ?? "",
|
|
281
299
|
name: options.name,
|
|
282
300
|
environment: options.env,
|
|
283
|
-
json: options.json,
|
|
301
|
+
json: program.opts().json ?? options.json,
|
|
284
302
|
});
|
|
285
303
|
});
|
|
286
304
|
integrations
|
|
@@ -296,7 +314,7 @@ integrations
|
|
|
296
314
|
name: options.name,
|
|
297
315
|
environment: options.env,
|
|
298
316
|
enabled: options.enabled,
|
|
299
|
-
json: options.json,
|
|
317
|
+
json: program.opts().json ?? options.json,
|
|
300
318
|
});
|
|
301
319
|
});
|
|
302
320
|
integrations
|
|
@@ -304,7 +322,7 @@ integrations
|
|
|
304
322
|
.description("Remove an integration")
|
|
305
323
|
.option("--force", "Skip confirmation")
|
|
306
324
|
.action(async (id, options) => {
|
|
307
|
-
await executeIntegrationsRemove({ id, force: options.force });
|
|
325
|
+
await executeIntegrationsRemove({ id, force: options.force, json: program.opts().json });
|
|
308
326
|
});
|
|
309
327
|
// Notifications command group
|
|
310
328
|
const notifications = program
|
|
@@ -320,7 +338,7 @@ notifications
|
|
|
320
338
|
await executeNotificationsList({
|
|
321
339
|
monitor: options.monitor,
|
|
322
340
|
enabled: options.enabled ? true : undefined,
|
|
323
|
-
json: options.json,
|
|
341
|
+
json: program.opts().json ?? options.json,
|
|
324
342
|
});
|
|
325
343
|
});
|
|
326
344
|
notifications
|
|
@@ -334,6 +352,7 @@ notifications
|
|
|
334
352
|
integration: options.integration,
|
|
335
353
|
channel: options.channel,
|
|
336
354
|
toAddresses: options.toAddresses,
|
|
355
|
+
json: program.opts().json,
|
|
337
356
|
});
|
|
338
357
|
});
|
|
339
358
|
// Parse arguments
|
package/dist/commands/env.d.ts
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
export interface EnvListOptions {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
}
|
|
1
4
|
/**
|
|
2
5
|
* List all available environments
|
|
3
6
|
*/
|
|
4
|
-
export declare const executeEnvList: () => Promise<void>;
|
|
7
|
+
export declare const executeEnvList: (options: EnvListOptions) => Promise<void>;
|
|
8
|
+
export interface EnvAddOptions {
|
|
9
|
+
name: string;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
}
|
|
5
12
|
/**
|
|
6
13
|
* Add a new environment
|
|
7
14
|
*/
|
|
8
|
-
export declare const executeEnvAdd: (
|
|
15
|
+
export declare const executeEnvAdd: (options: EnvAddOptions) => Promise<void>;
|
|
16
|
+
export interface EnvRemoveOptions {
|
|
17
|
+
name: string;
|
|
18
|
+
json?: boolean;
|
|
19
|
+
}
|
|
9
20
|
/**
|
|
10
21
|
* Remove an environment
|
|
11
22
|
*/
|
|
12
|
-
export declare const executeEnvRemove: (
|
|
23
|
+
export declare const executeEnvRemove: (options: EnvRemoveOptions) => Promise<void>;
|
package/dist/commands/env.js
CHANGED
|
@@ -1,42 +1,44 @@
|
|
|
1
1
|
import { loadState, addEnvironment, removeEnvironment } from "../core/state.js";
|
|
2
|
-
import {
|
|
3
|
-
import { withCommandErrorHandler } from "../utils/command-wrapper.js";
|
|
2
|
+
import { createCommandHandler } from "../utils/command-wrapper.js";
|
|
4
3
|
/**
|
|
5
4
|
* List all available environments
|
|
6
5
|
*/
|
|
7
|
-
export const executeEnvList =
|
|
6
|
+
export const executeEnvList = createCommandHandler("env list", async (_options, output) => {
|
|
8
7
|
const state = await loadState();
|
|
9
8
|
const environments = Object.keys(state.environments);
|
|
9
|
+
output.setData({ environments });
|
|
10
10
|
if (environments.length === 0) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
output.warn("No environments configured.");
|
|
12
|
+
output.blank();
|
|
13
|
+
output.dim("Run 'griffin init' to set up your project.");
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
output.info("Available environments:");
|
|
17
|
+
output.blank();
|
|
18
18
|
for (const envName of environments) {
|
|
19
|
-
const marker =
|
|
20
|
-
const envDisplay =
|
|
21
|
-
|
|
19
|
+
const marker = output.colors.green("●");
|
|
20
|
+
const envDisplay = output.colors.cyan(envName);
|
|
21
|
+
output.log(` ${marker} ${envDisplay}`);
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
output.blank();
|
|
24
24
|
});
|
|
25
25
|
/**
|
|
26
26
|
* Add a new environment
|
|
27
27
|
*/
|
|
28
|
-
export const executeEnvAdd =
|
|
29
|
-
await addEnvironment(name, {});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
export const executeEnvAdd = createCommandHandler("env add", async (options, output) => {
|
|
29
|
+
await addEnvironment(options.name, {});
|
|
30
|
+
output.setData({ environment: options.name, added: true });
|
|
31
|
+
output.success(`Environment '${options.name}' added successfully.`);
|
|
32
|
+
output.blank();
|
|
33
|
+
output.dim(`Add variables with: griffin variables add KEY=VALUE --env ${options.name}`);
|
|
34
|
+
output.blank();
|
|
34
35
|
});
|
|
35
36
|
/**
|
|
36
37
|
* Remove an environment
|
|
37
38
|
*/
|
|
38
|
-
export const executeEnvRemove =
|
|
39
|
-
await removeEnvironment(name);
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
export const executeEnvRemove = createCommandHandler("env remove", async (options, output) => {
|
|
40
|
+
await removeEnvironment(options.name);
|
|
41
|
+
output.setData({ environment: options.name, removed: true });
|
|
42
|
+
output.success(`Environment '${options.name}' removed successfully.`);
|
|
43
|
+
output.blank();
|
|
42
44
|
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
export interface GenerateKeyOptions {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
}
|
|
1
4
|
/**
|
|
2
5
|
* Generate a cryptographically secure API key for griffin-runner authentication.
|
|
3
|
-
*
|
|
4
|
-
* The key format is: grfn_sk_<48-character-hex-string>
|
|
5
|
-
* - grfn: Griffin prefix
|
|
6
|
-
* - sk: Secret Key
|
|
7
|
-
* - 48 hex chars: 24 random bytes = 192 bits of entropy
|
|
6
|
+
* Format: grfn_sk_<48-character-hex-string>
|
|
8
7
|
*/
|
|
9
|
-
export declare
|
|
8
|
+
export declare const executeGenerateKey: (options: GenerateKeyOptions) => Promise<void>;
|
|
@@ -1,33 +1,27 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { createCommandHandler } from "../utils/command-wrapper.js";
|
|
3
3
|
/**
|
|
4
4
|
* Generate a cryptographically secure API key for griffin-runner authentication.
|
|
5
|
-
*
|
|
6
|
-
* The key format is: grfn_sk_<48-character-hex-string>
|
|
7
|
-
* - grfn: Griffin prefix
|
|
8
|
-
* - sk: Secret Key
|
|
9
|
-
* - 48 hex chars: 24 random bytes = 192 bits of entropy
|
|
5
|
+
* Format: grfn_sk_<48-character-hex-string>
|
|
10
6
|
*/
|
|
11
|
-
export async
|
|
12
|
-
// Generate 24 random bytes (192 bits of entropy)
|
|
7
|
+
export const executeGenerateKey = createCommandHandler("generate-key", async (_options, output) => {
|
|
13
8
|
const keyBytes = randomBytes(24);
|
|
14
|
-
// Convert to hex string
|
|
15
9
|
const keySecret = keyBytes.toString("hex");
|
|
16
|
-
// Add prefix following the pattern: grfn_sk_<secret>
|
|
17
10
|
const apiKey = `grfn_sk_${keySecret}`;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
11
|
+
output.setData({ apiKey });
|
|
12
|
+
output.blank();
|
|
13
|
+
output.success("Generated API key:");
|
|
14
|
+
output.blank();
|
|
15
|
+
output.log(` ${output.colors.cyan(apiKey)}`);
|
|
16
|
+
output.blank();
|
|
17
|
+
output.warn("Store this key securely - it cannot be retrieved later.");
|
|
18
|
+
output.blank();
|
|
19
|
+
output.info("To use this key:");
|
|
20
|
+
output.dim(" 1. Add it to your runner's AUTH_API_KEYS environment variable:");
|
|
21
|
+
output.dim(` AUTH_API_KEYS=${apiKey}`);
|
|
22
|
+
output.dim(" 2. Or add it to your .griffinrc.json:");
|
|
23
|
+
output.dim(` { "runner": { "apiToken": "${apiKey}" } }`);
|
|
24
|
+
output.dim(" 3. Or pass it via environment variable:");
|
|
25
|
+
output.dim(` GRIFFIN_API_TOKEN=${apiKey}`);
|
|
26
|
+
output.blank();
|
|
27
|
+
});
|
|
@@ -2,53 +2,54 @@ import { resolveEnvironment } from "../../core/state.js";
|
|
|
2
2
|
import { computeDiff, formatDiff } from "../../core/diff.js";
|
|
3
3
|
import { applyDiff, formatApplyResult } from "../../core/apply.js";
|
|
4
4
|
import { createSdkAndState } from "../../core/sdk.js";
|
|
5
|
-
import {
|
|
6
|
-
import { withCommandErrorHandler } from "../../utils/command-wrapper.js";
|
|
5
|
+
import { createCommandHandler } from "../../utils/command-wrapper.js";
|
|
7
6
|
import { discoverLocalMonitors, fetchRemoteMonitors, resolveLocalMonitors, } from "../../core/monitor-helpers.js";
|
|
8
7
|
/**
|
|
9
8
|
* Apply changes to the hub
|
|
10
9
|
*/
|
|
11
|
-
export const executeApply =
|
|
10
|
+
export const executeApply = createCommandHandler("apply", async (options, output) => {
|
|
12
11
|
const { sdk, state } = await createSdkAndState();
|
|
13
|
-
// Resolve environment
|
|
14
12
|
const envName = await resolveEnvironment(options.env);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// Discover local monitors
|
|
13
|
+
output.info(`Applying to ${output.colors.cyan(envName)} environment`);
|
|
14
|
+
output.blank();
|
|
18
15
|
const { monitors } = await discoverLocalMonitors(state);
|
|
19
|
-
// Fetch remote monitors for this project + environment
|
|
20
16
|
const remoteMonitors = await fetchRemoteMonitors(sdk, state.projectId, envName);
|
|
21
|
-
// Load variables and resolve local monitors before computing diff
|
|
22
17
|
const resolvedMonitors = await resolveLocalMonitors(monitors, state.projectId, envName);
|
|
23
|
-
// Compute diff (include deletions if --prune)
|
|
24
18
|
const diff = computeDiff(resolvedMonitors, remoteMonitors, {
|
|
25
19
|
includeDeletions: options.prune || false,
|
|
26
20
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
output.blank();
|
|
22
|
+
output.log(formatDiff(diff));
|
|
23
|
+
output.blank();
|
|
24
|
+
const changeCount = diff.summary.creates + diff.summary.updates + diff.summary.deletes;
|
|
25
|
+
if (changeCount === 0) {
|
|
26
|
+
output.success("No changes to apply.");
|
|
27
|
+
output.setData({
|
|
28
|
+
summary: diff.summary,
|
|
29
|
+
applied: [],
|
|
30
|
+
success: true,
|
|
31
|
+
message: "No changes to apply.",
|
|
32
|
+
});
|
|
35
33
|
return;
|
|
36
34
|
}
|
|
37
|
-
// Show deletions warning if --prune
|
|
38
35
|
if (options.prune && diff.summary.deletes > 0) {
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
output.warn(`--prune will DELETE ${diff.summary.deletes} monitor(s) from the hub`);
|
|
37
|
+
output.blank();
|
|
41
38
|
}
|
|
42
|
-
// Ask for confirmation unless auto-approved
|
|
43
39
|
if (!options.autoApprove && !options.dryRun) {
|
|
44
|
-
const confirmed = await
|
|
40
|
+
const confirmed = await output.confirm("Do you want to perform these actions?");
|
|
45
41
|
if (!confirmed) {
|
|
46
|
-
|
|
42
|
+
output.warn("Apply cancelled.");
|
|
43
|
+
output.setData({
|
|
44
|
+
summary: diff.summary,
|
|
45
|
+
applied: [],
|
|
46
|
+
success: false,
|
|
47
|
+
message: "Apply cancelled.",
|
|
48
|
+
});
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
|
-
|
|
51
|
-
const applySpinner = terminal.spinner("Applying changes...").start();
|
|
52
|
+
const applySpinner = output.spinner("Applying changes...").start();
|
|
52
53
|
const result = await applyDiff(diff, sdk, {
|
|
53
54
|
dryRun: options.dryRun,
|
|
54
55
|
});
|
|
@@ -58,9 +59,23 @@ export const executeApply = withCommandErrorHandler(async (options) => {
|
|
|
58
59
|
else {
|
|
59
60
|
applySpinner.fail("Apply failed");
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
output.setData({
|
|
63
|
+
summary: diff.summary,
|
|
64
|
+
applied: result.applied.map((a) => ({
|
|
65
|
+
type: a.type,
|
|
66
|
+
monitorName: a.monitorName,
|
|
67
|
+
success: a.success,
|
|
68
|
+
error: a.error,
|
|
69
|
+
})),
|
|
70
|
+
errors: result.errors.map((e) => ({
|
|
71
|
+
action: e.action.type,
|
|
72
|
+
error: e.error.message,
|
|
73
|
+
})),
|
|
74
|
+
success: result.success,
|
|
75
|
+
});
|
|
76
|
+
output.blank();
|
|
77
|
+
output.log(formatApplyResult(result));
|
|
63
78
|
if (!result.success) {
|
|
64
|
-
|
|
79
|
+
output.exit(1);
|
|
65
80
|
}
|
|
66
81
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export interface ConnectOptions {
|
|
2
2
|
url: string;
|
|
3
3
|
token: string;
|
|
4
|
+
json?: boolean;
|
|
4
5
|
}
|
|
5
6
|
/**
|
|
6
7
|
* Configure hub connection settings
|
|
7
8
|
*/
|
|
8
|
-
export declare
|
|
9
|
+
export declare const executeConnect: (options: ConnectOptions) => Promise<void>;
|
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
import { randomBytes } from "crypto";
|
|
2
2
|
import { loadState, saveState } from "../../core/state.js";
|
|
3
3
|
import { saveHubCredentials } from "../../core/credentials.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createCommandHandler } from "../../utils/command-wrapper.js";
|
|
5
5
|
/**
|
|
6
6
|
* Configure hub connection settings
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
terminal.error(error.message);
|
|
26
|
-
terminal.exit(1);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
8
|
+
export const executeConnect = createCommandHandler("auth connect", async (options, output) => {
|
|
9
|
+
const state = await loadState();
|
|
10
|
+
await saveHubCredentials(options.token);
|
|
11
|
+
state.hub = {
|
|
12
|
+
baseUrl: options.url,
|
|
13
|
+
clientId: randomBytes(16).toString("hex"),
|
|
14
|
+
};
|
|
15
|
+
await saveState(state);
|
|
16
|
+
output.setData({
|
|
17
|
+
url: options.url,
|
|
18
|
+
configured: true,
|
|
19
|
+
});
|
|
20
|
+
output.success("Hub connection configured");
|
|
21
|
+
output.log(` URL: ${output.colors.cyan(options.url)}`);
|
|
22
|
+
output.log(` API Token: ${output.colors.dim("***")} (saved to user credentials)`);
|
|
23
|
+
output.blank();
|
|
24
|
+
});
|
|
@@ -3,8 +3,9 @@ export interface DestroyOptions {
|
|
|
3
3
|
dryRun?: boolean;
|
|
4
4
|
env: string;
|
|
5
5
|
monitor?: string;
|
|
6
|
+
json?: boolean;
|
|
6
7
|
}
|
|
7
8
|
/**
|
|
8
9
|
* Destroy monitors on the hub
|
|
9
10
|
*/
|
|
10
|
-
export declare
|
|
11
|
+
export declare const executeDestroy: (options: DestroyOptions) => Promise<void>;
|