@griffin-app/griffin-cli 1.0.6 → 1.0.7
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 +38 -38
- package/dist/cli.js +11 -11
- package/dist/commands/apply.js +7 -7
- package/dist/commands/deploy.js +1 -1
- package/dist/commands/hub/apply.d.ts +1 -1
- package/dist/commands/hub/apply.js +17 -17
- package/dist/commands/hub/login.js +2 -6
- package/dist/commands/hub/monitor.d.ts +8 -0
- package/dist/commands/hub/monitor.js +75 -0
- package/dist/commands/hub/plan.d.ts +2 -2
- package/dist/commands/hub/plan.js +16 -16
- package/dist/commands/hub/run.d.ts +2 -2
- package/dist/commands/hub/run.js +33 -33
- package/dist/commands/hub/runs.d.ts +1 -1
- package/dist/commands/hub/runs.js +4 -4
- package/dist/commands/init.js +28 -12
- package/dist/commands/local/run.d.ts +2 -2
- package/dist/commands/local/run.js +1 -1
- package/dist/commands/plan.d.ts +2 -2
- package/dist/commands/plan.js +7 -7
- package/dist/commands/run-remote.d.ts +1 -1
- package/dist/commands/run-remote.js +10 -10
- package/dist/commands/validate.d.ts +1 -1
- package/dist/commands/validate.js +12 -12
- package/dist/core/apply.d.ts +2 -2
- package/dist/core/apply.js +25 -25
- package/dist/core/apply.test.js +54 -54
- package/dist/core/diff.d.ts +14 -14
- package/dist/core/diff.js +42 -42
- package/dist/core/diff.test.js +34 -34
- package/dist/core/discovery.d.ts +6 -6
- package/dist/core/discovery.js +20 -20
- package/dist/core/monitor-diff.d.ts +41 -0
- package/dist/core/monitor-diff.js +257 -0
- package/dist/core/plan-diff.d.ts +6 -6
- package/dist/core/plan-diff.js +5 -5
- package/dist/core/state.js +2 -2
- package/dist/core/variables.d.ts +5 -5
- package/dist/core/variables.js +7 -7
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/resolve.d.ts +3 -3
- package/dist/resolve.js +9 -9
- package/dist/schemas/payload.d.ts +3 -3
- package/dist/schemas/payload.js +3 -3
- package/dist/schemas/state.d.ts +1 -1
- package/dist/schemas/state.js +2 -2
- package/dist/test-runner.d.ts +1 -1
- package/dist/test-runner.js +13 -13
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -6,9 +6,9 @@ Command-line interface for managing API monitoring tests as code.
|
|
|
6
6
|
|
|
7
7
|
Griffin CLI enables monitoring-as-code with support for both local test execution and hub-based orchestration. It provides a declarative workflow:
|
|
8
8
|
|
|
9
|
-
1. Write test
|
|
9
|
+
1. Write test monitors in TypeScript/JavaScript
|
|
10
10
|
2. Run tests locally against configured targets
|
|
11
|
-
3. Preview changes with `griffin hub
|
|
11
|
+
3. Preview changes with `griffin hub monitor`
|
|
12
12
|
4. Apply changes to hub with `griffin hub apply`
|
|
13
13
|
5. Monitor execution with `griffin hub runs`
|
|
14
14
|
|
|
@@ -30,7 +30,7 @@ This creates `.griffin/state.json` which tracks:
|
|
|
30
30
|
|
|
31
31
|
- Project ID (auto-detected from package.json or directory name)
|
|
32
32
|
- Environment configurations with their targets
|
|
33
|
-
- Synced
|
|
33
|
+
- Synced monitor state
|
|
34
34
|
- Hub connection settings (optional)
|
|
35
35
|
|
|
36
36
|
Override project ID with `--project <name>`.
|
|
@@ -43,9 +43,9 @@ View configured environments:
|
|
|
43
43
|
griffin env list
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
### 3. Create Test
|
|
46
|
+
### 3. Create Test Monitors
|
|
47
47
|
|
|
48
|
-
Create test files in `__griffin__/` directories. These files export test
|
|
48
|
+
Create test files in `__griffin__/` directories. These files export test monitors that can be run locally or synced to the hub.
|
|
49
49
|
|
|
50
50
|
### 4. Run Tests Locally
|
|
51
51
|
|
|
@@ -64,8 +64,8 @@ griffin hub connect --url https://hub.example.com --token <token>
|
|
|
64
64
|
### 6. Preview Hub Changes
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
griffin hub
|
|
68
|
-
griffin hub
|
|
67
|
+
griffin hub monitor
|
|
68
|
+
griffin hub monitor production
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
Shows what will be created, updated, or deleted on the hub for the specified environment.
|
|
@@ -77,15 +77,15 @@ griffin hub apply
|
|
|
77
77
|
griffin hub apply production
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
Syncs
|
|
80
|
+
Syncs monitors to the hub for the specified environment.
|
|
81
81
|
|
|
82
82
|
### 8. Trigger Hub Run
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
griffin hub run production --
|
|
85
|
+
griffin hub run production --monitor <name>
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
Triggers a
|
|
88
|
+
Triggers a monitor execution on the hub in the specified environment.
|
|
89
89
|
|
|
90
90
|
## Commands
|
|
91
91
|
|
|
@@ -94,7 +94,7 @@ Commands are organized into four groups:
|
|
|
94
94
|
- **Top-level**: Project initialization and utilities
|
|
95
95
|
- **env**: Environment management
|
|
96
96
|
- **local**: Local test execution
|
|
97
|
-
- **hub**: Hub operations (
|
|
97
|
+
- **hub**: Hub operations (monitor sync, remote execution)
|
|
98
98
|
|
|
99
99
|
### Top-Level Commands
|
|
100
100
|
|
|
@@ -115,7 +115,7 @@ griffin init --project my-service
|
|
|
115
115
|
|
|
116
116
|
#### `griffin validate`
|
|
117
117
|
|
|
118
|
-
Validate test
|
|
118
|
+
Validate test monitor files without syncing.
|
|
119
119
|
|
|
120
120
|
**Example:**
|
|
121
121
|
|
|
@@ -222,17 +222,17 @@ Show recent runs from the hub.
|
|
|
222
222
|
|
|
223
223
|
**Options:**
|
|
224
224
|
|
|
225
|
-
- `--
|
|
225
|
+
- `--monitor <name>` - Filter by monitor name
|
|
226
226
|
- `--limit <number>` - Number of runs to show (default: 10)
|
|
227
227
|
|
|
228
228
|
**Example:**
|
|
229
229
|
|
|
230
230
|
```bash
|
|
231
231
|
griffin hub runs
|
|
232
|
-
griffin hub runs --
|
|
232
|
+
griffin hub runs --monitor health-check --limit 5
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
#### `griffin hub
|
|
235
|
+
#### `griffin hub monitor [env]`
|
|
236
236
|
|
|
237
237
|
Show what changes would be applied to the hub. Environment can be specified as a positional argument, or uses the default environment if omitted.
|
|
238
238
|
|
|
@@ -243,9 +243,9 @@ Show what changes would be applied to the hub. Environment can be specified as a
|
|
|
243
243
|
**Example:**
|
|
244
244
|
|
|
245
245
|
```bash
|
|
246
|
-
griffin hub
|
|
247
|
-
griffin hub
|
|
248
|
-
griffin hub
|
|
246
|
+
griffin hub monitor
|
|
247
|
+
griffin hub monitor production
|
|
248
|
+
griffin hub monitor staging --json
|
|
249
249
|
```
|
|
250
250
|
|
|
251
251
|
**Exit codes:**
|
|
@@ -262,7 +262,7 @@ Apply changes to the hub. Environment can be specified as a positional argument,
|
|
|
262
262
|
|
|
263
263
|
- `--auto-approve` - Skip confirmation prompt
|
|
264
264
|
- `--dry-run` - Show what would be done without making changes
|
|
265
|
-
- `--prune` - Delete
|
|
265
|
+
- `--prune` - Delete monitors on hub that don't exist locally
|
|
266
266
|
|
|
267
267
|
**Example:**
|
|
268
268
|
|
|
@@ -275,20 +275,20 @@ griffin hub apply production --prune
|
|
|
275
275
|
|
|
276
276
|
#### `griffin hub run <env>`
|
|
277
277
|
|
|
278
|
-
Trigger a
|
|
278
|
+
Trigger a monitor run on the hub in the specified environment.
|
|
279
279
|
|
|
280
280
|
**Options:**
|
|
281
281
|
|
|
282
|
-
- `--
|
|
282
|
+
- `--monitor <name>` - Monitor name to run (required)
|
|
283
283
|
- `--wait` - Wait for run to complete
|
|
284
|
-
- `--force` - Run even if local
|
|
284
|
+
- `--force` - Run even if local monitor differs from hub
|
|
285
285
|
|
|
286
286
|
**Example:**
|
|
287
287
|
|
|
288
288
|
```bash
|
|
289
|
-
griffin hub run production --
|
|
290
|
-
griffin hub run staging --
|
|
291
|
-
griffin hub run production --
|
|
289
|
+
griffin hub run production --monitor health-check
|
|
290
|
+
griffin hub run staging --monitor health-check --wait
|
|
291
|
+
griffin hub run production --monitor api-check --force
|
|
292
292
|
```
|
|
293
293
|
|
|
294
294
|
## Configuration
|
|
@@ -375,22 +375,22 @@ griffin local run staging
|
|
|
375
375
|
griffin hub apply production
|
|
376
376
|
```
|
|
377
377
|
|
|
378
|
-
## Test
|
|
378
|
+
## Test Monitor Discovery
|
|
379
379
|
|
|
380
|
-
By default, Griffin discovers test
|
|
380
|
+
By default, Griffin discovers test monitors from files in `__griffin__/` directories matching `**/__griffin__/*.{ts,js}`.
|
|
381
381
|
|
|
382
|
-
Test files should be TypeScript or JavaScript files that export test
|
|
382
|
+
Test files should be TypeScript or JavaScript files that export test monitor objects.
|
|
383
383
|
|
|
384
384
|
## Diff Rules
|
|
385
385
|
|
|
386
386
|
Griffin computes changes using:
|
|
387
387
|
|
|
388
|
-
- **CREATE**:
|
|
389
|
-
- **UPDATE**:
|
|
390
|
-
- **DELETE**:
|
|
391
|
-
- **NOOP**:
|
|
388
|
+
- **CREATE**: Monitor exists locally but not in state
|
|
389
|
+
- **UPDATE**: Monitor exists in both, but hash differs
|
|
390
|
+
- **DELETE**: Monitor exists in state but not locally
|
|
391
|
+
- **NOOP**: Monitor exists in both with same hash
|
|
392
392
|
|
|
393
|
-
Change detection uses a SHA-256 hash of the normalized
|
|
393
|
+
Change detection uses a SHA-256 hash of the normalized monitor payload.
|
|
394
394
|
|
|
395
395
|
## Hub API Compatibility
|
|
396
396
|
|
|
@@ -398,11 +398,11 @@ Griffin CLI is compatible with Griffin Hub API v1.
|
|
|
398
398
|
|
|
399
399
|
Required endpoints:
|
|
400
400
|
|
|
401
|
-
- `POST /
|
|
402
|
-
- `GET /
|
|
401
|
+
- `POST /monitor` - Create/update monitor
|
|
402
|
+
- `GET /monitor` - List monitors
|
|
403
403
|
- `GET /runs` - List runs
|
|
404
404
|
- `GET /runs/:id` - Get run details
|
|
405
|
-
- `POST /runs/trigger/:
|
|
405
|
+
- `POST /runs/trigger/:monitorId` - Trigger run
|
|
406
406
|
|
|
407
407
|
## Development
|
|
408
408
|
|
|
@@ -432,7 +432,7 @@ griffin-cli/
|
|
|
432
432
|
│ │ │ ├── connect.ts
|
|
433
433
|
│ │ │ ├── status.ts
|
|
434
434
|
│ │ │ ├── runs.ts
|
|
435
|
-
│ │ │ ├──
|
|
435
|
+
│ │ │ ├── monitor.ts
|
|
436
436
|
│ │ │ ├── apply.ts
|
|
437
437
|
│ │ │ └── run.ts
|
|
438
438
|
│ │ ├── env.ts # Environment commands
|
|
@@ -443,7 +443,7 @@ griffin-cli/
|
|
|
443
443
|
│ │ ├── sdk.ts # Hub SDK client
|
|
444
444
|
│ │ ├── apply.ts # Apply engine
|
|
445
445
|
│ │ ├── diff.ts # Diff computation
|
|
446
|
-
│ │ ├── discovery.ts #
|
|
446
|
+
│ │ ├── discovery.ts # Monitor discovery
|
|
447
447
|
│ │ ├── state.ts # State management
|
|
448
448
|
│ │ ├── variables.ts # Variable resolution
|
|
449
449
|
│ │ └── project.ts # Project detection
|
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import { executeRunLocal } from "./commands/local/run.js";
|
|
|
10
10
|
import { executeConnect } from "./commands/hub/connect.js";
|
|
11
11
|
import { executeStatus } from "./commands/hub/status.js";
|
|
12
12
|
import { executeRuns } from "./commands/hub/runs.js";
|
|
13
|
-
import {
|
|
13
|
+
import { executeMonitor } from "./commands/hub/monitor.js";
|
|
14
14
|
import { executeApply } from "./commands/hub/apply.js";
|
|
15
15
|
import { executeRun } from "./commands/hub/run.js";
|
|
16
16
|
import { executeLogin } from "./commands/hub/login.js";
|
|
@@ -30,7 +30,7 @@ program
|
|
|
30
30
|
});
|
|
31
31
|
program
|
|
32
32
|
.command("validate")
|
|
33
|
-
.description("Validate test
|
|
33
|
+
.description("Validate test monitor files without syncing")
|
|
34
34
|
.action(async () => {
|
|
35
35
|
await executeValidate();
|
|
36
36
|
});
|
|
@@ -51,7 +51,7 @@ env
|
|
|
51
51
|
// Local command group
|
|
52
52
|
const local = program.command("local").description("Local test execution");
|
|
53
53
|
local
|
|
54
|
-
.command("run
|
|
54
|
+
.command("run <env>")
|
|
55
55
|
.description("Run tests locally against an environment")
|
|
56
56
|
.action(async (env, options) => {
|
|
57
57
|
await executeRunLocal({ env });
|
|
@@ -75,7 +75,7 @@ hub
|
|
|
75
75
|
hub
|
|
76
76
|
.command("runs")
|
|
77
77
|
.description("Show recent runs from the hub")
|
|
78
|
-
.option("--
|
|
78
|
+
.option("--monitor <name>", "Filter by monitor name")
|
|
79
79
|
.option("--limit <number>", "Number of runs to show", "10")
|
|
80
80
|
.action(async (options) => {
|
|
81
81
|
await executeRuns({
|
|
@@ -84,27 +84,27 @@ hub
|
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
86
|
hub
|
|
87
|
-
.command("
|
|
87
|
+
.command("monitor <env>")
|
|
88
88
|
.description("Show what changes would be applied")
|
|
89
89
|
.option("--json", "Output in JSON format")
|
|
90
90
|
.action(async (env, options) => {
|
|
91
|
-
await
|
|
91
|
+
await executeMonitor({ ...options, env });
|
|
92
92
|
});
|
|
93
93
|
hub
|
|
94
|
-
.command("apply
|
|
94
|
+
.command("apply <env>")
|
|
95
95
|
.description("Apply changes to the hub")
|
|
96
96
|
.option("--auto-approve", "Skip confirmation prompt")
|
|
97
97
|
.option("--dry-run", "Show what would be done without making changes")
|
|
98
|
-
.option("--prune", "Delete
|
|
98
|
+
.option("--prune", "Delete monitors on hub that don't exist locally")
|
|
99
99
|
.action(async (env, options) => {
|
|
100
100
|
await executeApply({ ...options, env });
|
|
101
101
|
});
|
|
102
102
|
hub
|
|
103
103
|
.command("run <env>")
|
|
104
|
-
.description("Trigger a
|
|
105
|
-
.requiredOption("--
|
|
104
|
+
.description("Trigger a monitor run on the hub")
|
|
105
|
+
.requiredOption("--monitor <name>", "Monitor name to run")
|
|
106
106
|
.option("--wait", "Wait for run to complete")
|
|
107
|
-
.option("--force", "Run even if local
|
|
107
|
+
.option("--force", "Run even if local monitor differs from hub")
|
|
108
108
|
.action(async (env, options) => {
|
|
109
109
|
await executeRun({ ...options, env });
|
|
110
110
|
});
|
package/dist/commands/apply.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadState, resolveEnvironment } from "../core/state.js";
|
|
2
|
-
import {
|
|
2
|
+
import { discoverMonitors, formatDiscoveryErrors } from "../core/discovery.js";
|
|
3
3
|
import { computeDiff, formatDiff } from "../core/diff.js";
|
|
4
4
|
import { applyDiff, formatApplyResult } from "../core/apply.js";
|
|
5
5
|
import { createSdkClients } from "../core/sdk.js";
|
|
@@ -26,23 +26,23 @@ export async function executeApply(options) {
|
|
|
26
26
|
baseUrl: state.runner.baseUrl,
|
|
27
27
|
apiToken: state.runner.apiToken || undefined,
|
|
28
28
|
});
|
|
29
|
-
// Discover local
|
|
29
|
+
// Discover local monitors
|
|
30
30
|
const discoveryPattern = state.discovery?.pattern || "**/__griffin__/*.{ts,js}";
|
|
31
31
|
const discoveryIgnore = state.discovery?.ignore || [
|
|
32
32
|
"node_modules/**",
|
|
33
33
|
"dist/**",
|
|
34
34
|
];
|
|
35
|
-
const {
|
|
35
|
+
const { monitors, errors } = await discoverMonitors(discoveryPattern, discoveryIgnore);
|
|
36
36
|
if (errors.length > 0) {
|
|
37
37
|
console.error(formatDiscoveryErrors(errors));
|
|
38
38
|
process.exit(1);
|
|
39
39
|
}
|
|
40
|
-
// Fetch remote
|
|
40
|
+
// Fetch remote monitors for this project
|
|
41
41
|
const response = await planApi.planGet(state.projectId);
|
|
42
|
-
const
|
|
42
|
+
const remoteMonitors = response.data.data.map((p) => p);
|
|
43
43
|
// Compute diff for this environment
|
|
44
|
-
const diff = computeDiff(
|
|
45
|
-
// Show
|
|
44
|
+
const diff = computeDiff(monitors.map((p) => p.monitor), state, remoteMonitors, envName);
|
|
45
|
+
// Show monitor
|
|
46
46
|
console.log(formatDiff(diff));
|
|
47
47
|
console.log("");
|
|
48
48
|
// Check if there are changes
|
package/dist/commands/deploy.js
CHANGED
|
@@ -17,7 +17,7 @@ export async function executeDeploy() {
|
|
|
17
17
|
}
|
|
18
18
|
// TODO: Implement deployment logic
|
|
19
19
|
// - Read each test file
|
|
20
|
-
// - Execute it to get JSON
|
|
20
|
+
// - Execute it to get JSON monitor
|
|
21
21
|
// - Send to runner API
|
|
22
22
|
// - Handle responses
|
|
23
23
|
console.log("Deployed.");
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { loadState, resolveEnvironment } from "../../core/state.js";
|
|
2
|
-
import {
|
|
2
|
+
import { discoverMonitors, formatDiscoveryErrors } from "../../core/discovery.js";
|
|
3
3
|
import { computeDiff, formatDiff } from "../../core/diff.js";
|
|
4
4
|
import { applyDiff, formatApplyResult } from "../../core/apply.js";
|
|
5
5
|
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
6
6
|
import { terminal } from "../../utils/terminal.js";
|
|
7
7
|
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
8
8
|
import { loadVariables } from "../../core/variables.js";
|
|
9
|
-
import {
|
|
9
|
+
import { resolveMonitor } from "../../resolve.js";
|
|
10
10
|
/**
|
|
11
11
|
* Apply changes to the hub
|
|
12
12
|
*/
|
|
@@ -27,38 +27,38 @@ export async function executeApply(options) {
|
|
|
27
27
|
terminal.blank();
|
|
28
28
|
// Create SDK clients with credentials
|
|
29
29
|
const sdk = await createSdkWithCredentials(state.hub.baseUrl);
|
|
30
|
-
// Discover local
|
|
30
|
+
// Discover local monitors
|
|
31
31
|
const discoveryPattern = state.discovery?.pattern || "**/__griffin__/*.{ts,js}";
|
|
32
32
|
const discoveryIgnore = state.discovery?.ignore || [
|
|
33
33
|
"node_modules/**",
|
|
34
34
|
"dist/**",
|
|
35
35
|
];
|
|
36
|
-
const spinner = terminal.spinner("Discovering local
|
|
37
|
-
const {
|
|
36
|
+
const spinner = terminal.spinner("Discovering local monitors...").start();
|
|
37
|
+
const { monitors, errors } = await discoverMonitors(discoveryPattern, discoveryIgnore);
|
|
38
38
|
if (errors.length > 0) {
|
|
39
39
|
spinner.fail("Discovery failed");
|
|
40
40
|
terminal.error(formatDiscoveryErrors(errors));
|
|
41
41
|
terminal.exit(1);
|
|
42
42
|
}
|
|
43
|
-
spinner.succeed(`Found ${
|
|
44
|
-
// Fetch remote
|
|
45
|
-
const fetchSpinner = terminal.spinner("Fetching remote
|
|
46
|
-
const response = await withSDKErrorHandling(() => sdk.
|
|
43
|
+
spinner.succeed(`Found ${monitors.length} local monitor(s)`);
|
|
44
|
+
// Fetch remote monitors for this project + environment
|
|
45
|
+
const fetchSpinner = terminal.spinner("Fetching remote monitors...").start();
|
|
46
|
+
const response = await withSDKErrorHandling(() => sdk.getMonitor({
|
|
47
47
|
query: {
|
|
48
48
|
projectId: state.projectId,
|
|
49
49
|
environment: envName,
|
|
50
50
|
},
|
|
51
|
-
}), "Failed to fetch remote
|
|
52
|
-
const
|
|
53
|
-
fetchSpinner.succeed(`Found ${
|
|
54
|
-
// Load variables and resolve local
|
|
51
|
+
}), "Failed to fetch remote monitors");
|
|
52
|
+
const remoteMonitors = response?.data?.data;
|
|
53
|
+
fetchSpinner.succeed(`Found ${remoteMonitors.length} remote monitor(s)`);
|
|
54
|
+
// Load variables and resolve local monitors before computing diff
|
|
55
55
|
const variables = await loadVariables(envName);
|
|
56
|
-
const
|
|
56
|
+
const resolvedMonitors = monitors.map((p) => resolveMonitor(p.monitor, state.projectId, envName, variables));
|
|
57
57
|
// Compute diff (include deletions if --prune)
|
|
58
|
-
const diff = computeDiff(
|
|
58
|
+
const diff = computeDiff(resolvedMonitors, remoteMonitors, {
|
|
59
59
|
includeDeletions: options.prune || false,
|
|
60
60
|
});
|
|
61
|
-
// Show
|
|
61
|
+
// Show monitor
|
|
62
62
|
terminal.blank();
|
|
63
63
|
terminal.log(formatDiff(diff));
|
|
64
64
|
terminal.blank();
|
|
@@ -70,7 +70,7 @@ export async function executeApply(options) {
|
|
|
70
70
|
}
|
|
71
71
|
// Show deletions warning if --prune
|
|
72
72
|
if (options.prune && diff.summary.deletes > 0) {
|
|
73
|
-
terminal.warn(`--prune will DELETE ${diff.summary.deletes}
|
|
73
|
+
terminal.warn(`--prune will DELETE ${diff.summary.deletes} monitor(s) from the hub`);
|
|
74
74
|
terminal.blank();
|
|
75
75
|
}
|
|
76
76
|
// Ask for confirmation unless auto-approved
|
|
@@ -12,10 +12,7 @@ const hubBaseUrl = "http://localhost:3000";
|
|
|
12
12
|
const oauthGrant = "urn:ietf:params:oauth:grant-type:device_code";
|
|
13
13
|
const authClient = createAuthClient({
|
|
14
14
|
baseURL: baseURL,
|
|
15
|
-
plugins: [
|
|
16
|
-
deviceAuthorizationClient(),
|
|
17
|
-
jwtClient(),
|
|
18
|
-
],
|
|
15
|
+
plugins: [deviceAuthorizationClient(), jwtClient()],
|
|
19
16
|
});
|
|
20
17
|
async function pollForToken(clientId, deviceCode, interval) {
|
|
21
18
|
const { data, error } = await authClient.device.token({
|
|
@@ -48,8 +45,7 @@ export async function executeLogin() {
|
|
|
48
45
|
state = await loadState();
|
|
49
46
|
clientId = state.hub?.clientId;
|
|
50
47
|
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
}
|
|
48
|
+
catch (error) { }
|
|
53
49
|
if (!clientId) {
|
|
54
50
|
clientId = randomBytes(16).toString("hex");
|
|
55
51
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { loadState, resolveEnvironment } from "../../core/state.js";
|
|
2
|
+
import { discoverMonitors, formatDiscoveryErrors } from "../../core/discovery.js";
|
|
3
|
+
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
4
|
+
import { computeDiff, formatDiff, formatDiffJson } from "../../core/diff.js";
|
|
5
|
+
import { terminal } from "../../utils/terminal.js";
|
|
6
|
+
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
7
|
+
import { loadVariables } from "../../core/variables.js";
|
|
8
|
+
import { resolveMonitor } from "../../resolve.js";
|
|
9
|
+
/**
|
|
10
|
+
* Show what changes would be applied
|
|
11
|
+
*/
|
|
12
|
+
export async function executeMonitor(options) {
|
|
13
|
+
try {
|
|
14
|
+
// Load state
|
|
15
|
+
const state = await loadState();
|
|
16
|
+
// Resolve environment
|
|
17
|
+
const envName = await resolveEnvironment(options.env);
|
|
18
|
+
if (!state.hub?.baseUrl) {
|
|
19
|
+
terminal.error("Hub connection not configured.");
|
|
20
|
+
terminal.dim("Connect with:");
|
|
21
|
+
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
22
|
+
terminal.exit(1);
|
|
23
|
+
}
|
|
24
|
+
// Discover local monitors
|
|
25
|
+
const discoveryPattern = state.discovery?.pattern || "**/__griffin__/*.{ts,js}";
|
|
26
|
+
const discoveryIgnore = state.discovery?.ignore || [
|
|
27
|
+
"node_modules/**",
|
|
28
|
+
"dist/**",
|
|
29
|
+
];
|
|
30
|
+
const spinner = terminal.spinner("Discovering local monitors...").start();
|
|
31
|
+
const { monitors, errors } = await discoverMonitors(discoveryPattern, discoveryIgnore);
|
|
32
|
+
if (errors.length > 0) {
|
|
33
|
+
spinner.fail("Discovery failed");
|
|
34
|
+
terminal.error(formatDiscoveryErrors(errors));
|
|
35
|
+
terminal.exit(1);
|
|
36
|
+
}
|
|
37
|
+
spinner.succeed(`Found ${monitors.length} local monitor(s)`);
|
|
38
|
+
// Create SDK clients with credentials
|
|
39
|
+
const sdk = await createSdkWithCredentials(state.hub.baseUrl);
|
|
40
|
+
// Fetch remote monitors for this project + environment
|
|
41
|
+
const fetchSpinner = terminal.spinner("Fetching remote monitors...").start();
|
|
42
|
+
const response = await withSDKErrorHandling(() => sdk.getMonitor({
|
|
43
|
+
query: {
|
|
44
|
+
projectId: state.projectId,
|
|
45
|
+
environment: envName,
|
|
46
|
+
},
|
|
47
|
+
}), "Failed to fetch remote monitors");
|
|
48
|
+
const remoteMonitors = response?.data?.data;
|
|
49
|
+
fetchSpinner.succeed(`Found ${remoteMonitors.length} remote monitor(s)`);
|
|
50
|
+
// Load variables and resolve local monitors before computing diff
|
|
51
|
+
const variables = await loadVariables(envName);
|
|
52
|
+
const resolvedMonitors = monitors.map((p) => resolveMonitor(p.monitor, state.projectId, envName, variables));
|
|
53
|
+
// Compute diff (no deletions shown by default)
|
|
54
|
+
const diff = computeDiff(resolvedMonitors, remoteMonitors, {
|
|
55
|
+
includeDeletions: false,
|
|
56
|
+
});
|
|
57
|
+
terminal.blank();
|
|
58
|
+
// Output
|
|
59
|
+
if (options.json) {
|
|
60
|
+
terminal.log(formatDiffJson(diff));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
terminal.log(formatDiff(diff));
|
|
64
|
+
}
|
|
65
|
+
// Exit with error code if there are changes
|
|
66
|
+
if (diff.summary.creates + diff.summary.updates + diff.summary.deletes >
|
|
67
|
+
0) {
|
|
68
|
+
terminal.exit(2); // Exit code 2 indicates changes pending
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
terminal.error(error.message);
|
|
73
|
+
terminal.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface MonitorOptions {
|
|
2
2
|
json?: boolean;
|
|
3
3
|
env?: string;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
6
|
* Show what changes would be applied
|
|
7
7
|
*/
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function executeMonitor(options: MonitorOptions): Promise<void>;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { loadState, resolveEnvironment } from "../../core/state.js";
|
|
2
|
-
import {
|
|
2
|
+
import { discoverMonitors, formatDiscoveryErrors } from "../../core/discovery.js";
|
|
3
3
|
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
4
4
|
import { computeDiff, formatDiff, formatDiffJson } from "../../core/diff.js";
|
|
5
5
|
import { terminal } from "../../utils/terminal.js";
|
|
6
6
|
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
7
7
|
import { loadVariables } from "../../core/variables.js";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveMonitor } from "../../resolve.js";
|
|
9
9
|
/**
|
|
10
10
|
* Show what changes would be applied
|
|
11
11
|
*/
|
|
12
|
-
export async function
|
|
12
|
+
export async function executeMonitor(options) {
|
|
13
13
|
try {
|
|
14
14
|
// Load state
|
|
15
15
|
const state = await loadState();
|
|
@@ -21,37 +21,37 @@ export async function executePlan(options) {
|
|
|
21
21
|
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
22
22
|
terminal.exit(1);
|
|
23
23
|
}
|
|
24
|
-
// Discover local
|
|
24
|
+
// Discover local monitors
|
|
25
25
|
const discoveryPattern = state.discovery?.pattern || "**/__griffin__/*.{ts,js}";
|
|
26
26
|
const discoveryIgnore = state.discovery?.ignore || [
|
|
27
27
|
"node_modules/**",
|
|
28
28
|
"dist/**",
|
|
29
29
|
];
|
|
30
|
-
const spinner = terminal.spinner("Discovering local
|
|
31
|
-
const {
|
|
30
|
+
const spinner = terminal.spinner("Discovering local monitors...").start();
|
|
31
|
+
const { monitors, errors } = await discoverMonitors(discoveryPattern, discoveryIgnore);
|
|
32
32
|
if (errors.length > 0) {
|
|
33
33
|
spinner.fail("Discovery failed");
|
|
34
34
|
terminal.error(formatDiscoveryErrors(errors));
|
|
35
35
|
terminal.exit(1);
|
|
36
36
|
}
|
|
37
|
-
spinner.succeed(`Found ${
|
|
37
|
+
spinner.succeed(`Found ${monitors.length} local monitor(s)`);
|
|
38
38
|
// Create SDK clients with credentials
|
|
39
39
|
const sdk = await createSdkWithCredentials(state.hub.baseUrl);
|
|
40
|
-
// Fetch remote
|
|
41
|
-
const fetchSpinner = terminal.spinner("Fetching remote
|
|
42
|
-
const response = await withSDKErrorHandling(() => sdk.
|
|
40
|
+
// Fetch remote monitors for this project + environment
|
|
41
|
+
const fetchSpinner = terminal.spinner("Fetching remote monitors...").start();
|
|
42
|
+
const response = await withSDKErrorHandling(() => sdk.getMonitor({
|
|
43
43
|
query: {
|
|
44
44
|
projectId: state.projectId,
|
|
45
45
|
environment: envName,
|
|
46
46
|
},
|
|
47
|
-
}), "Failed to fetch remote
|
|
48
|
-
const
|
|
49
|
-
fetchSpinner.succeed(`Found ${
|
|
50
|
-
// Load variables and resolve local
|
|
47
|
+
}), "Failed to fetch remote monitors");
|
|
48
|
+
const remoteMonitors = response?.data?.data;
|
|
49
|
+
fetchSpinner.succeed(`Found ${remoteMonitors.length} remote monitor(s)`);
|
|
50
|
+
// Load variables and resolve local monitors before computing diff
|
|
51
51
|
const variables = await loadVariables(envName);
|
|
52
|
-
const
|
|
52
|
+
const resolvedMonitors = monitors.map((p) => resolveMonitor(p.monitor, state.projectId, envName, variables));
|
|
53
53
|
// Compute diff (no deletions shown by default)
|
|
54
|
-
const diff = computeDiff(
|
|
54
|
+
const diff = computeDiff(resolvedMonitors, remoteMonitors, {
|
|
55
55
|
includeDeletions: false,
|
|
56
56
|
});
|
|
57
57
|
terminal.blank();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export interface RunOptions {
|
|
2
|
-
|
|
2
|
+
monitor: string;
|
|
3
3
|
env: string;
|
|
4
4
|
wait?: boolean;
|
|
5
5
|
force?: boolean;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Trigger a
|
|
8
|
+
* Trigger a monitor run on the hub
|
|
9
9
|
*/
|
|
10
10
|
export declare function executeRun(options: RunOptions): Promise<void>;
|