@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/dist/core/apply.test.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from "vitest";
|
|
2
2
|
import { applyDiff } from "./apply.js";
|
|
3
|
-
// Helper to create a minimal test
|
|
4
|
-
function
|
|
3
|
+
// Helper to create a minimal test monitor
|
|
4
|
+
function createMonitor(name) {
|
|
5
5
|
return {
|
|
6
|
-
id: `
|
|
6
|
+
id: `monitor-${name}`,
|
|
7
7
|
name,
|
|
8
8
|
project: "test-project",
|
|
9
9
|
environment: "test",
|
|
@@ -19,92 +19,92 @@ describe("applyDiff", () => {
|
|
|
19
19
|
actions: [],
|
|
20
20
|
summary: { creates: 0, updates: 0, deletes: 0, noops: 0 },
|
|
21
21
|
};
|
|
22
|
-
const
|
|
23
|
-
const result = await applyDiff(diff,
|
|
22
|
+
const mockMonitorApi = {};
|
|
23
|
+
const result = await applyDiff(diff, mockMonitorApi);
|
|
24
24
|
expect(result.success).toBe(true);
|
|
25
25
|
expect(result.applied).toHaveLength(0);
|
|
26
26
|
expect(result.errors).toHaveLength(0);
|
|
27
27
|
});
|
|
28
28
|
it("should skip noop actions", async () => {
|
|
29
|
-
const
|
|
29
|
+
const monitor = createMonitor("health-check");
|
|
30
30
|
const diff = {
|
|
31
31
|
actions: [
|
|
32
32
|
{
|
|
33
33
|
type: "noop",
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
monitor: monitor,
|
|
35
|
+
remoteMonitor: monitor,
|
|
36
36
|
reason: "unchanged",
|
|
37
37
|
},
|
|
38
38
|
],
|
|
39
39
|
summary: { creates: 0, updates: 0, deletes: 0, noops: 1 },
|
|
40
40
|
};
|
|
41
|
-
const
|
|
42
|
-
const result = await applyDiff(diff,
|
|
41
|
+
const mockMonitorApi = {};
|
|
42
|
+
const result = await applyDiff(diff, mockMonitorApi);
|
|
43
43
|
expect(result.success).toBe(true);
|
|
44
44
|
expect(result.applied).toHaveLength(0);
|
|
45
45
|
});
|
|
46
46
|
it("should apply create action", async () => {
|
|
47
|
-
const
|
|
47
|
+
const monitor = createMonitor("new-monitor");
|
|
48
48
|
const diff = {
|
|
49
49
|
actions: [
|
|
50
50
|
{
|
|
51
51
|
type: "create",
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
monitor: monitor,
|
|
53
|
+
remoteMonitor: null,
|
|
54
54
|
reason: "new",
|
|
55
55
|
},
|
|
56
56
|
],
|
|
57
57
|
summary: { creates: 1, updates: 0, deletes: 0, noops: 0 },
|
|
58
58
|
};
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
data: { data: { ...
|
|
59
|
+
const mockMonitorApi = {
|
|
60
|
+
postMonitor: vi.fn().mockResolvedValue({
|
|
61
|
+
data: { data: { ...monitor, id: "created-id" } },
|
|
62
62
|
}),
|
|
63
63
|
};
|
|
64
|
-
const result = await applyDiff(diff,
|
|
64
|
+
const result = await applyDiff(diff, mockMonitorApi);
|
|
65
65
|
expect(result.success).toBe(true);
|
|
66
66
|
expect(result.applied).toHaveLength(1);
|
|
67
67
|
expect(result.applied[0].type).toBe("create");
|
|
68
|
-
expect(result.applied[0].
|
|
68
|
+
expect(result.applied[0].monitorName).toBe("new-monitor");
|
|
69
69
|
expect(result.applied[0].success).toBe(true);
|
|
70
70
|
// Verify the API was called with injected project and environment
|
|
71
|
-
expect(
|
|
71
|
+
expect(mockMonitorApi.postMonitor).toHaveBeenCalledWith(expect.objectContaining({
|
|
72
72
|
body: expect.objectContaining({
|
|
73
|
-
name: "new-
|
|
73
|
+
name: "new-monitor",
|
|
74
74
|
project: "test-project",
|
|
75
75
|
environment: "test",
|
|
76
76
|
}),
|
|
77
77
|
}));
|
|
78
78
|
});
|
|
79
79
|
it("should apply update action", async () => {
|
|
80
|
-
const
|
|
81
|
-
const
|
|
80
|
+
const localMonitor = createMonitor("existing-monitor");
|
|
81
|
+
const remoteMonitor = { ...localMonitor, id: "remote-id" };
|
|
82
82
|
const diff = {
|
|
83
83
|
actions: [
|
|
84
84
|
{
|
|
85
85
|
type: "update",
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
monitor: localMonitor,
|
|
87
|
+
remoteMonitor: remoteMonitor,
|
|
88
88
|
reason: "changed",
|
|
89
89
|
},
|
|
90
90
|
],
|
|
91
91
|
summary: { creates: 0, updates: 1, deletes: 0, noops: 0 },
|
|
92
92
|
};
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
data: { data:
|
|
93
|
+
const mockMonitorApi = {
|
|
94
|
+
putMonitorById: vi.fn().mockResolvedValue({
|
|
95
|
+
data: { data: remoteMonitor },
|
|
96
96
|
}),
|
|
97
97
|
};
|
|
98
|
-
const result = await applyDiff(diff,
|
|
98
|
+
const result = await applyDiff(diff, mockMonitorApi);
|
|
99
99
|
expect(result.success).toBe(true);
|
|
100
100
|
expect(result.applied).toHaveLength(1);
|
|
101
101
|
expect(result.applied[0].type).toBe("update");
|
|
102
|
-
expect(result.applied[0].
|
|
102
|
+
expect(result.applied[0].monitorName).toBe("existing-monitor");
|
|
103
103
|
expect(result.applied[0].success).toBe(true);
|
|
104
|
-
// Verify the API was called with the remote
|
|
105
|
-
expect(
|
|
104
|
+
// Verify the API was called with the remote monitor's ID
|
|
105
|
+
expect(mockMonitorApi.putMonitorById).toHaveBeenCalledWith(expect.objectContaining({
|
|
106
106
|
body: expect.objectContaining({
|
|
107
|
-
name: "existing-
|
|
107
|
+
name: "existing-monitor",
|
|
108
108
|
project: "test-project",
|
|
109
109
|
environment: "test",
|
|
110
110
|
}),
|
|
@@ -114,44 +114,44 @@ describe("applyDiff", () => {
|
|
|
114
114
|
}));
|
|
115
115
|
});
|
|
116
116
|
it("should apply delete action", async () => {
|
|
117
|
-
const
|
|
117
|
+
const remoteMonitor = createMonitor("old-monitor");
|
|
118
118
|
const diff = {
|
|
119
|
-
actions: [{ type: "delete",
|
|
119
|
+
actions: [{ type: "delete", monitor: null, remoteMonitor, reason: "removed" }],
|
|
120
120
|
summary: { creates: 0, updates: 0, deletes: 1, noops: 0 },
|
|
121
121
|
};
|
|
122
|
-
const
|
|
123
|
-
|
|
122
|
+
const mockMonitorApi = {
|
|
123
|
+
deleteMonitorById: vi.fn().mockResolvedValue({}),
|
|
124
124
|
};
|
|
125
|
-
const result = await applyDiff(diff,
|
|
125
|
+
const result = await applyDiff(diff, mockMonitorApi);
|
|
126
126
|
expect(result.success).toBe(true);
|
|
127
127
|
expect(result.applied).toHaveLength(1);
|
|
128
128
|
expect(result.applied[0].type).toBe("delete");
|
|
129
|
-
expect(result.applied[0].
|
|
129
|
+
expect(result.applied[0].monitorName).toBe("old-monitor");
|
|
130
130
|
expect(result.applied[0].success).toBe(true);
|
|
131
|
-
// Verify the API was called with the remote
|
|
132
|
-
expect(
|
|
131
|
+
// Verify the API was called with the remote monitor's ID
|
|
132
|
+
expect(mockMonitorApi.deleteMonitorById).toHaveBeenCalledWith({
|
|
133
133
|
path: {
|
|
134
|
-
id:
|
|
134
|
+
id: remoteMonitor.id,
|
|
135
135
|
},
|
|
136
136
|
});
|
|
137
137
|
});
|
|
138
138
|
it("should handle errors gracefully", async () => {
|
|
139
|
-
const
|
|
139
|
+
const monitor = createMonitor("failing-monitor");
|
|
140
140
|
const diff = {
|
|
141
141
|
actions: [
|
|
142
142
|
{
|
|
143
143
|
type: "create",
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
monitor: monitor,
|
|
145
|
+
remoteMonitor: null,
|
|
146
146
|
reason: "new",
|
|
147
147
|
},
|
|
148
148
|
],
|
|
149
149
|
summary: { creates: 1, updates: 0, deletes: 0, noops: 0 },
|
|
150
150
|
};
|
|
151
|
-
const
|
|
152
|
-
|
|
151
|
+
const mockMonitorApi = {
|
|
152
|
+
postMonitor: vi.fn().mockRejectedValue(new Error("API Error")),
|
|
153
153
|
};
|
|
154
|
-
const result = await applyDiff(diff,
|
|
154
|
+
const result = await applyDiff(diff, mockMonitorApi);
|
|
155
155
|
expect(result.success).toBe(false);
|
|
156
156
|
expect(result.errors).toHaveLength(1);
|
|
157
157
|
expect(result.applied).toHaveLength(1);
|
|
@@ -159,26 +159,26 @@ describe("applyDiff", () => {
|
|
|
159
159
|
expect(result.applied[0].error).toBe("API Error");
|
|
160
160
|
});
|
|
161
161
|
it("should skip actions in dry-run mode", async () => {
|
|
162
|
-
const
|
|
162
|
+
const monitor = createMonitor("dry-run-monitor");
|
|
163
163
|
const diff = {
|
|
164
164
|
actions: [
|
|
165
165
|
{
|
|
166
166
|
type: "create",
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
monitor: monitor,
|
|
168
|
+
remoteMonitor: null,
|
|
169
169
|
reason: "new",
|
|
170
170
|
},
|
|
171
171
|
],
|
|
172
172
|
summary: { creates: 1, updates: 0, deletes: 0, noops: 0 },
|
|
173
173
|
};
|
|
174
|
-
const
|
|
175
|
-
|
|
174
|
+
const mockMonitorApi = {
|
|
175
|
+
postMonitor: vi.fn(),
|
|
176
176
|
};
|
|
177
|
-
const result = await applyDiff(diff,
|
|
177
|
+
const result = await applyDiff(diff, mockMonitorApi, {
|
|
178
178
|
dryRun: true,
|
|
179
179
|
});
|
|
180
180
|
expect(result.success).toBe(true);
|
|
181
181
|
expect(result.applied).toHaveLength(0);
|
|
182
|
-
expect(
|
|
182
|
+
expect(mockMonitorApi.postMonitor).not.toHaveBeenCalled();
|
|
183
183
|
});
|
|
184
184
|
});
|
package/dist/core/diff.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type
|
|
1
|
+
import type { MonitorV1 } from "@griffin-app/griffin-hub-sdk";
|
|
2
|
+
import { type MonitorChanges } from "./monitor-diff.js";
|
|
3
3
|
export type DiffActionType = "create" | "update" | "delete" | "noop";
|
|
4
|
-
export type
|
|
4
|
+
export type ResolvedMonitor = Omit<MonitorV1, "id">;
|
|
5
5
|
export interface DiffAction {
|
|
6
6
|
type: DiffActionType;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
monitor: ResolvedMonitor | null;
|
|
8
|
+
remoteMonitor: MonitorV1 | null;
|
|
9
9
|
reason: string;
|
|
10
|
-
changes?:
|
|
10
|
+
changes?: MonitorChanges;
|
|
11
11
|
}
|
|
12
12
|
export interface DiffResult {
|
|
13
13
|
actions: DiffAction[];
|
|
@@ -22,17 +22,17 @@ export interface DiffOptions {
|
|
|
22
22
|
includeDeletions: boolean;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
* Compute diff between local
|
|
26
|
-
* Local
|
|
27
|
-
*
|
|
25
|
+
* Compute diff between local monitors and remote monitors (hub is source of truth).
|
|
26
|
+
* Local monitors should be resolved (variables replaced with actual values) before calling this.
|
|
27
|
+
* Monitors are matched by name.
|
|
28
28
|
*
|
|
29
29
|
* Rules:
|
|
30
|
-
* - CREATE:
|
|
31
|
-
* - UPDATE:
|
|
32
|
-
* - DELETE:
|
|
33
|
-
* - NOOP:
|
|
30
|
+
* - CREATE: Monitor exists locally but not on hub
|
|
31
|
+
* - UPDATE: Monitor exists in both, but content differs
|
|
32
|
+
* - DELETE: Monitor exists on hub but not locally (only if includeDeletions is true)
|
|
33
|
+
* - NOOP: Monitor exists in both with same content
|
|
34
34
|
*/
|
|
35
|
-
export declare function computeDiff(
|
|
35
|
+
export declare function computeDiff(localMonitors: ResolvedMonitor[], remoteMonitors: MonitorV1[], options: DiffOptions): DiffResult;
|
|
36
36
|
/**
|
|
37
37
|
* Format diff result as human-readable text with granular changes
|
|
38
38
|
*/
|
package/dist/core/diff.js
CHANGED
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { compareMonitors } from "./monitor-diff.js";
|
|
2
2
|
/**
|
|
3
|
-
* Compute diff between local
|
|
4
|
-
* Local
|
|
5
|
-
*
|
|
3
|
+
* Compute diff between local monitors and remote monitors (hub is source of truth).
|
|
4
|
+
* Local monitors should be resolved (variables replaced with actual values) before calling this.
|
|
5
|
+
* Monitors are matched by name.
|
|
6
6
|
*
|
|
7
7
|
* Rules:
|
|
8
|
-
* - CREATE:
|
|
9
|
-
* - UPDATE:
|
|
10
|
-
* - DELETE:
|
|
11
|
-
* - NOOP:
|
|
8
|
+
* - CREATE: Monitor exists locally but not on hub
|
|
9
|
+
* - UPDATE: Monitor exists in both, but content differs
|
|
10
|
+
* - DELETE: Monitor exists on hub but not locally (only if includeDeletions is true)
|
|
11
|
+
* - NOOP: Monitor exists in both with same content
|
|
12
12
|
*/
|
|
13
|
-
export function computeDiff(
|
|
13
|
+
export function computeDiff(localMonitors, remoteMonitors, options) {
|
|
14
14
|
const actions = [];
|
|
15
|
-
// Build lookup: remote
|
|
15
|
+
// Build lookup: remote monitors by name
|
|
16
16
|
const remoteByName = new Map();
|
|
17
|
-
for (const
|
|
18
|
-
remoteByName.set(
|
|
17
|
+
for (const monitor of remoteMonitors) {
|
|
18
|
+
remoteByName.set(monitor.name, monitor);
|
|
19
19
|
}
|
|
20
20
|
const localNames = new Set();
|
|
21
|
-
for (const
|
|
22
|
-
localNames.add(
|
|
21
|
+
for (const monitor of localMonitors) {
|
|
22
|
+
localNames.add(monitor.name);
|
|
23
23
|
}
|
|
24
|
-
// Check local
|
|
25
|
-
for (const local of
|
|
24
|
+
// Check local monitors against remote
|
|
25
|
+
for (const local of localMonitors) {
|
|
26
26
|
const remote = remoteByName.get(local.name);
|
|
27
27
|
if (!remote) {
|
|
28
|
-
//
|
|
28
|
+
// Monitor not on hub -> CREATE
|
|
29
29
|
actions.push({
|
|
30
30
|
type: "create",
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
reason: `
|
|
31
|
+
monitor: local,
|
|
32
|
+
remoteMonitor: null,
|
|
33
|
+
reason: `Monitor "${local.name}" does not exist on hub`,
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
//
|
|
38
|
-
const changes =
|
|
37
|
+
// Monitor exists in both - compute granular changes
|
|
38
|
+
const changes = compareMonitors(local, remote);
|
|
39
39
|
if (changes.hasChanges) {
|
|
40
|
-
//
|
|
40
|
+
// Monitor on hub but differs -> UPDATE
|
|
41
41
|
actions.push({
|
|
42
42
|
type: "update",
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
reason: `
|
|
43
|
+
monitor: local,
|
|
44
|
+
remoteMonitor: remote,
|
|
45
|
+
reason: `Monitor "${local.name}" has local changes`,
|
|
46
46
|
changes,
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
else {
|
|
50
|
-
//
|
|
50
|
+
// Monitor matches -> NOOP
|
|
51
51
|
actions.push({
|
|
52
52
|
type: "noop",
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
reason: `
|
|
53
|
+
monitor: local,
|
|
54
|
+
remoteMonitor: remote,
|
|
55
|
+
reason: `Monitor "${local.name}" is up to date`,
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
// Check for
|
|
60
|
+
// Check for monitors on hub not present locally -> DELETE (only if --prune)
|
|
61
61
|
if (options.includeDeletions) {
|
|
62
|
-
for (const remote of
|
|
62
|
+
for (const remote of remoteMonitors) {
|
|
63
63
|
if (!localNames.has(remote.name)) {
|
|
64
64
|
actions.push({
|
|
65
65
|
type: "delete",
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
reason: `
|
|
66
|
+
monitor: null,
|
|
67
|
+
remoteMonitor: remote,
|
|
68
|
+
reason: `Monitor "${remote.name}" no longer exists locally`,
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -90,21 +90,21 @@ export function formatDiff(diff) {
|
|
|
90
90
|
lines.push("No changes. Infrastructure is up to date.");
|
|
91
91
|
return lines.join("\n");
|
|
92
92
|
}
|
|
93
|
-
lines.push("
|
|
93
|
+
lines.push("Monitor:");
|
|
94
94
|
lines.push("");
|
|
95
95
|
for (const action of diff.actions) {
|
|
96
96
|
if (action.type === "create") {
|
|
97
|
-
lines.push(` + ${action.
|
|
97
|
+
lines.push(` + ${action.monitor.name} (create)`);
|
|
98
98
|
}
|
|
99
99
|
else if (action.type === "update") {
|
|
100
|
-
lines.push(` ~ ${action.
|
|
100
|
+
lines.push(` ~ ${action.monitor.name} (update)`);
|
|
101
101
|
// Show granular changes for updates
|
|
102
102
|
if (action.changes) {
|
|
103
|
-
|
|
103
|
+
formatMonitorChanges(action.changes, lines);
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
else if (action.type === "delete") {
|
|
107
|
-
lines.push(` - ${action.
|
|
107
|
+
lines.push(` - ${action.remoteMonitor.name} (delete)`);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
lines.push("");
|
|
@@ -115,9 +115,9 @@ export function formatDiff(diff) {
|
|
|
115
115
|
return lines.join("\n");
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
118
|
-
* Format granular
|
|
118
|
+
* Format granular monitor changes in terraform style
|
|
119
119
|
*/
|
|
120
|
-
function
|
|
120
|
+
function formatMonitorChanges(changes, lines) {
|
|
121
121
|
// Nodes section
|
|
122
122
|
if (changes.nodes.length > 0) {
|
|
123
123
|
lines.push(" Nodes:");
|
package/dist/core/diff.test.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import { computeDiff } from "./diff.js";
|
|
3
|
-
// Helper to create a minimal test
|
|
4
|
-
function
|
|
3
|
+
// Helper to create a minimal test monitor
|
|
4
|
+
function createMonitor(name, overrides) {
|
|
5
5
|
return {
|
|
6
|
-
id: `
|
|
6
|
+
id: `monitor-${name}`,
|
|
7
7
|
name,
|
|
8
8
|
project: "test-project",
|
|
9
9
|
environment: "test",
|
|
@@ -14,8 +14,8 @@ function createPlan(name, overrides) {
|
|
|
14
14
|
...overrides,
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
// Helper to create a resolved
|
|
18
|
-
function
|
|
17
|
+
// Helper to create a resolved monitor (without id)
|
|
18
|
+
function createResolvedMonitor(name, overrides) {
|
|
19
19
|
return {
|
|
20
20
|
name,
|
|
21
21
|
project: "test-project",
|
|
@@ -29,30 +29,30 @@ function createResolvedPlan(name, overrides) {
|
|
|
29
29
|
}
|
|
30
30
|
describe("computeDiff", () => {
|
|
31
31
|
describe("CREATE actions", () => {
|
|
32
|
-
it("should create action when
|
|
33
|
-
const local = [
|
|
32
|
+
it("should create action when monitor exists locally but not remotely", () => {
|
|
33
|
+
const local = [createResolvedMonitor("health-check")];
|
|
34
34
|
const remote = [];
|
|
35
35
|
const result = computeDiff(local, remote, {
|
|
36
36
|
includeDeletions: false,
|
|
37
37
|
});
|
|
38
38
|
expect(result.actions).toHaveLength(1);
|
|
39
39
|
expect(result.actions[0].type).toBe("create");
|
|
40
|
-
expect(result.actions[0].
|
|
41
|
-
expect(result.actions[0].
|
|
40
|
+
expect(result.actions[0].monitor?.name).toBe("health-check");
|
|
41
|
+
expect(result.actions[0].remoteMonitor).toBeNull();
|
|
42
42
|
expect(result.summary.creates).toBe(1);
|
|
43
43
|
expect(result.summary.updates).toBe(0);
|
|
44
44
|
expect(result.summary.deletes).toBe(0);
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
describe("UPDATE actions", () => {
|
|
48
|
-
it("should create update action when
|
|
48
|
+
it("should create update action when monitor content differs", () => {
|
|
49
49
|
const local = [
|
|
50
|
-
|
|
50
|
+
createResolvedMonitor("health-check", {
|
|
51
51
|
frequency: { every: 10, unit: "MINUTE" },
|
|
52
52
|
}),
|
|
53
53
|
];
|
|
54
54
|
const remote = [
|
|
55
|
-
|
|
55
|
+
createMonitor("health-check", {
|
|
56
56
|
frequency: { every: 5, unit: "MINUTE" },
|
|
57
57
|
}),
|
|
58
58
|
];
|
|
@@ -61,19 +61,19 @@ describe("computeDiff", () => {
|
|
|
61
61
|
});
|
|
62
62
|
expect(result.actions).toHaveLength(1);
|
|
63
63
|
expect(result.actions[0].type).toBe("update");
|
|
64
|
-
expect(result.actions[0].
|
|
65
|
-
expect(result.actions[0].
|
|
64
|
+
expect(result.actions[0].monitor?.name).toBe("health-check");
|
|
65
|
+
expect(result.actions[0].remoteMonitor?.name).toBe("health-check");
|
|
66
66
|
expect(result.summary.creates).toBe(0);
|
|
67
67
|
expect(result.summary.updates).toBe(1);
|
|
68
68
|
expect(result.summary.deletes).toBe(0);
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
describe("NOOP actions", () => {
|
|
72
|
-
it("should create noop action when
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const local = [
|
|
76
|
-
const remote = [
|
|
72
|
+
it("should create noop action when monitor content matches", () => {
|
|
73
|
+
const resolvedMonitor = createResolvedMonitor("health-check");
|
|
74
|
+
const remoteMonitor = createMonitor("health-check");
|
|
75
|
+
const local = [resolvedMonitor];
|
|
76
|
+
const remote = [remoteMonitor];
|
|
77
77
|
const result = computeDiff(local, remote, {
|
|
78
78
|
includeDeletions: false,
|
|
79
79
|
});
|
|
@@ -88,37 +88,37 @@ describe("computeDiff", () => {
|
|
|
88
88
|
describe("DELETE actions", () => {
|
|
89
89
|
it("should not create delete action when includeDeletions is false", () => {
|
|
90
90
|
const local = [];
|
|
91
|
-
const remote = [
|
|
91
|
+
const remote = [createMonitor("old-monitor")];
|
|
92
92
|
const result = computeDiff(local, remote, { includeDeletions: false });
|
|
93
93
|
expect(result.actions).toHaveLength(0);
|
|
94
94
|
expect(result.summary.deletes).toBe(0);
|
|
95
95
|
});
|
|
96
96
|
it("should create delete action when includeDeletions is true", () => {
|
|
97
97
|
const local = [];
|
|
98
|
-
const remote = [
|
|
98
|
+
const remote = [createMonitor("old-monitor")];
|
|
99
99
|
const result = computeDiff(local, remote, { includeDeletions: true });
|
|
100
100
|
expect(result.actions).toHaveLength(1);
|
|
101
101
|
expect(result.actions[0].type).toBe("delete");
|
|
102
|
-
expect(result.actions[0].
|
|
103
|
-
expect(result.actions[0].
|
|
102
|
+
expect(result.actions[0].monitor).toBeNull();
|
|
103
|
+
expect(result.actions[0].remoteMonitor?.name).toBe("old-monitor");
|
|
104
104
|
expect(result.summary.deletes).toBe(1);
|
|
105
105
|
});
|
|
106
106
|
});
|
|
107
107
|
describe("Mixed scenarios", () => {
|
|
108
|
-
it("should handle multiple
|
|
108
|
+
it("should handle multiple monitors with different actions", () => {
|
|
109
109
|
const local = [
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
createResolvedMonitor("new-monitor"),
|
|
111
|
+
createResolvedMonitor("updated-monitor", {
|
|
112
112
|
frequency: { every: 10, unit: "MINUTE" },
|
|
113
113
|
}),
|
|
114
|
-
|
|
114
|
+
createResolvedMonitor("unchanged-monitor"),
|
|
115
115
|
];
|
|
116
116
|
const remote = [
|
|
117
|
-
|
|
117
|
+
createMonitor("updated-monitor", {
|
|
118
118
|
frequency: { every: 5, unit: "MINUTE" },
|
|
119
119
|
}),
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
createMonitor("unchanged-monitor"),
|
|
121
|
+
createMonitor("deleted-monitor"),
|
|
122
122
|
];
|
|
123
123
|
const result = computeDiff(local, remote, {
|
|
124
124
|
includeDeletions: true,
|
|
@@ -131,10 +131,10 @@ describe("computeDiff", () => {
|
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
133
|
describe("Matching by name", () => {
|
|
134
|
-
it("should match
|
|
135
|
-
// Local
|
|
136
|
-
const local = [
|
|
137
|
-
const remote = [
|
|
134
|
+
it("should match monitors by name, not by ID", () => {
|
|
135
|
+
// Local monitors don't have IDs after resolution
|
|
136
|
+
const local = [createResolvedMonitor("health-check")];
|
|
137
|
+
const remote = [createMonitor("health-check", { id: "remote-id-456" })];
|
|
138
138
|
const result = computeDiff(local, remote, {
|
|
139
139
|
includeDeletions: false,
|
|
140
140
|
});
|
package/dist/core/discovery.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface
|
|
3
|
-
|
|
1
|
+
import type { MonitorDSL } from "@griffin-app/griffin-ts/types";
|
|
2
|
+
export interface DiscoveredMonitor {
|
|
3
|
+
monitor: MonitorDSL;
|
|
4
4
|
filePath: string;
|
|
5
5
|
exportName: string;
|
|
6
6
|
}
|
|
7
7
|
export interface DiscoveryResult {
|
|
8
|
-
|
|
8
|
+
monitors: DiscoveredMonitor[];
|
|
9
9
|
errors: DiscoveryError[];
|
|
10
10
|
}
|
|
11
11
|
export interface DiscoveryError {
|
|
@@ -13,9 +13,9 @@ export interface DiscoveryError {
|
|
|
13
13
|
error: Error;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Discover and load test
|
|
16
|
+
* Discover and load test monitor files from the filesystem
|
|
17
17
|
*/
|
|
18
|
-
export declare function
|
|
18
|
+
export declare function discoverMonitors(pattern: string, ignore: string[]): Promise<DiscoveryResult>;
|
|
19
19
|
/**
|
|
20
20
|
* Format discovery errors for display
|
|
21
21
|
*/
|