@griffin-app/griffin-cli 1.0.10 → 1.0.11
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
CHANGED
|
@@ -197,7 +197,7 @@ integrations
|
|
|
197
197
|
.requiredOption("--provider-type <type>", "Provider type (e.g. slack_webhook, datadog)")
|
|
198
198
|
.requiredOption("--name <name>", "Display name")
|
|
199
199
|
.option("--environment <env>", "Environment scope (omit for org-wide)")
|
|
200
|
-
.option("--enabled
|
|
200
|
+
.option("--enabled", "Enabled")
|
|
201
201
|
.option("--json", "Output as JSON")
|
|
202
202
|
.action(async (options) => {
|
|
203
203
|
await executeIntegrationsAdd({
|
|
@@ -214,7 +214,7 @@ integrations
|
|
|
214
214
|
.description("Update an integration")
|
|
215
215
|
.option("--name <name>", "Display name")
|
|
216
216
|
.option("--environment <env>", "Environment scope")
|
|
217
|
-
.option("--enabled
|
|
217
|
+
.option("--enabled", "Enabled")
|
|
218
218
|
.option("--json", "Output as JSON")
|
|
219
219
|
.action(async (id, options) => {
|
|
220
220
|
await executeIntegrationsUpdate({
|
|
@@ -232,6 +232,23 @@ integrations
|
|
|
232
232
|
.action(async (id) => {
|
|
233
233
|
await executeIntegrationsRemove({ id });
|
|
234
234
|
});
|
|
235
|
+
integrations
|
|
236
|
+
.command("connect <provider>")
|
|
237
|
+
.description("Connect an OAuth integration (opens browser)")
|
|
238
|
+
.option("--name <name>", "Display name for the integration")
|
|
239
|
+
.option("--environment <env>", "Environment scope")
|
|
240
|
+
.option("--category <cat>", "Category (default: notifications)")
|
|
241
|
+
.option("--json", "Output integration ID as JSON")
|
|
242
|
+
.action(async (provider, options) => {
|
|
243
|
+
const { executeIntegrationsConnect } = await import("./commands/hub/integrations.js");
|
|
244
|
+
await executeIntegrationsConnect({
|
|
245
|
+
providerType: provider,
|
|
246
|
+
name: options.name,
|
|
247
|
+
environment: options.environment,
|
|
248
|
+
category: options.category,
|
|
249
|
+
json: options.json,
|
|
250
|
+
});
|
|
251
|
+
});
|
|
235
252
|
// Secrets command group
|
|
236
253
|
const secrets = hub
|
|
237
254
|
.command("secrets")
|
|
@@ -35,3 +35,11 @@ export interface IntegrationsRemoveOptions {
|
|
|
35
35
|
force?: boolean;
|
|
36
36
|
}
|
|
37
37
|
export declare function executeIntegrationsRemove(options: IntegrationsRemoveOptions): Promise<void>;
|
|
38
|
+
export interface IntegrationsConnectOptions {
|
|
39
|
+
providerType: string;
|
|
40
|
+
name?: string;
|
|
41
|
+
environment?: string;
|
|
42
|
+
category?: string;
|
|
43
|
+
json?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function executeIntegrationsConnect(options: IntegrationsConnectOptions): Promise<void>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { platform } from "node:os";
|
|
1
3
|
import { loadState } from "../../core/state.js";
|
|
2
4
|
import { getHubCredentials } from "../../core/credentials.js";
|
|
3
5
|
import { terminal } from "../../utils/terminal.js";
|
|
@@ -165,3 +167,89 @@ export async function executeIntegrationsRemove(options) {
|
|
|
165
167
|
}
|
|
166
168
|
terminal.info("Integration removed.");
|
|
167
169
|
}
|
|
170
|
+
function openBrowser(url) {
|
|
171
|
+
const cmd = platform() === "darwin"
|
|
172
|
+
? "open"
|
|
173
|
+
: platform() === "win32"
|
|
174
|
+
? "start"
|
|
175
|
+
: "xdg-open";
|
|
176
|
+
exec(`${cmd} "${url.replace(/"/g, '\\"')}"`, (err) => {
|
|
177
|
+
if (err) {
|
|
178
|
+
terminal.dim(`Could not open browser: ${err.message}`);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const POLL_INITIAL_MS = 2000;
|
|
183
|
+
const POLL_MAX_MS = 10000;
|
|
184
|
+
const POLL_TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes
|
|
185
|
+
export async function executeIntegrationsConnect(options) {
|
|
186
|
+
const category = options.category ?? "notifications";
|
|
187
|
+
const body = {
|
|
188
|
+
category,
|
|
189
|
+
providerType: options.providerType,
|
|
190
|
+
name: options.name ?? undefined,
|
|
191
|
+
environment: options.environment ?? undefined,
|
|
192
|
+
};
|
|
193
|
+
const result = await hubFetch("/integrations/oauth/initiate", { method: "POST", body });
|
|
194
|
+
if (result.error) {
|
|
195
|
+
terminal.error(result.error);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
const data = result.data;
|
|
199
|
+
if (!data) {
|
|
200
|
+
terminal.error("Initiate failed.");
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
terminal.info("Open this URL in your browser to authorize:");
|
|
204
|
+
terminal.log(data.authUrl);
|
|
205
|
+
terminal.blank();
|
|
206
|
+
openBrowser(data.authUrl);
|
|
207
|
+
terminal.info("Waiting for authorization… (polling)");
|
|
208
|
+
const start = Date.now();
|
|
209
|
+
let interval = POLL_INITIAL_MS;
|
|
210
|
+
const poll = async () => {
|
|
211
|
+
const statusResult = await hubFetch(`/integrations/oauth/status/${encodeURIComponent(data.transactionId)}`);
|
|
212
|
+
if (statusResult.error) {
|
|
213
|
+
throw new Error(statusResult.error);
|
|
214
|
+
}
|
|
215
|
+
const status = statusResult.data;
|
|
216
|
+
if (!status) {
|
|
217
|
+
throw new Error("Invalid status response");
|
|
218
|
+
}
|
|
219
|
+
if (status.status !== "pending") {
|
|
220
|
+
return status;
|
|
221
|
+
}
|
|
222
|
+
if (Date.now() - start >= POLL_TIMEOUT_MS) {
|
|
223
|
+
return { status: "expired", errorMessage: "Polling timed out" };
|
|
224
|
+
}
|
|
225
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
226
|
+
interval = Math.min(interval + 1000, POLL_MAX_MS);
|
|
227
|
+
return poll();
|
|
228
|
+
};
|
|
229
|
+
try {
|
|
230
|
+
const status = await poll();
|
|
231
|
+
if (status.status === "completed" && status.integrationId) {
|
|
232
|
+
if (options.json) {
|
|
233
|
+
terminal.log(JSON.stringify({ integrationId: status.integrationId }, null, 2));
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
terminal.success(`Integration connected: ${status.integrationId}`);
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (status.status === "failed") {
|
|
241
|
+
terminal.error(status.errorMessage ?? "Authorization failed");
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
if (status.status === "expired") {
|
|
245
|
+
terminal.error(status.errorMessage ?? "Transaction expired");
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
terminal.error("Unexpected status");
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
terminal.error(err instanceof Error ? err.message : "Polling failed");
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { findTestFiles } from "../../
|
|
2
|
-
import { runTestFile } from "../../
|
|
1
|
+
import { findTestFiles } from "../../monitor-discovery.js";
|
|
2
|
+
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";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griffin-app/griffin-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "CLI tool for running and managing griffin API tests",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"author": "",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@griffin-app/griffin-hub-sdk": "1.0.
|
|
27
|
+
"@griffin-app/griffin-hub-sdk": "1.0.14",
|
|
28
28
|
"@griffin-app/griffin-plan-executor": "0.1.18",
|
|
29
29
|
"@griffin-app/griffin-ts": "0.1.16",
|
|
30
30
|
"better-auth": "^1.4.17",
|