duoops 0.2.6 → 0.2.8
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/commands/init.js +73 -34
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BigQuery } from '@google-cloud/bigquery';
|
|
2
|
-
import { confirm, input, password, select } from '@inquirer/prompts';
|
|
2
|
+
import { checkbox, confirm, input, password, select } from '@inquirer/prompts';
|
|
3
3
|
import { Command } from '@oclif/core';
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
import { bold, gray, green, yellow } from 'kleur/colors';
|
|
@@ -46,6 +46,21 @@ const detectGitRemotePath = () => {
|
|
|
46
46
|
}
|
|
47
47
|
catch { /* ignore */ }
|
|
48
48
|
};
|
|
49
|
+
const resolveProjectId = async (auth, pathOrId) => {
|
|
50
|
+
const base = normalizeGitLabUrl(auth.baseUrl);
|
|
51
|
+
const encoded = encodeURIComponent(normalizeProjectPath(pathOrId));
|
|
52
|
+
try {
|
|
53
|
+
const res = await axios.get(`${base}/api/v4/projects/${encoded}`, {
|
|
54
|
+
headers: gitlabAuthHeaders(auth.token),
|
|
55
|
+
timeout: 5000,
|
|
56
|
+
validateStatus: () => true,
|
|
57
|
+
});
|
|
58
|
+
if (res.status === 200 && res.data?.id) {
|
|
59
|
+
return { id: res.data.id, name: res.data.name_with_namespace, path: res.data.path_with_namespace };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch { /* ignore */ }
|
|
63
|
+
};
|
|
49
64
|
const normalizeProjectPath = (project) => project.replace(/^\/+/, '');
|
|
50
65
|
const normalizeGitLabUrl = (url) => url.replace(/\/+$/, '');
|
|
51
66
|
const setGitlabVariable = async (auth, projectPath, variable) => {
|
|
@@ -295,9 +310,16 @@ export default class Init extends Command {
|
|
|
295
310
|
message: 'GitLab Personal Access Token',
|
|
296
311
|
});
|
|
297
312
|
}
|
|
298
|
-
const
|
|
299
|
-
|
|
313
|
+
const features = await checkbox({
|
|
314
|
+
choices: [
|
|
315
|
+
{ checked: true, name: 'Carbon measurement (BigQuery)', value: 'measure' },
|
|
316
|
+
{ checked: true, name: 'Duo agents and flows', value: 'agents' },
|
|
317
|
+
{ checked: true, name: 'MCP server (Cloud Run)', value: 'mcp' },
|
|
318
|
+
{ checked: true, name: 'CI project wiring (variables + runner)', value: 'ci' },
|
|
319
|
+
],
|
|
320
|
+
message: 'What would you like to set up?',
|
|
300
321
|
});
|
|
322
|
+
const enableMeasure = features.includes('measure');
|
|
301
323
|
let bigqueryDataset;
|
|
302
324
|
let bigqueryTable;
|
|
303
325
|
let googleProjectId;
|
|
@@ -369,11 +391,7 @@ export default class Init extends Command {
|
|
|
369
391
|
};
|
|
370
392
|
configManager.set(config);
|
|
371
393
|
this.log(green('Configuration saved.'));
|
|
372
|
-
|
|
373
|
-
default: true,
|
|
374
|
-
message: 'Set up DuoOps agents and flows in this project?',
|
|
375
|
-
});
|
|
376
|
-
if (setupAgents) {
|
|
394
|
+
if (features.includes('agents')) {
|
|
377
395
|
const { scaffoldProject } = await import('../lib/scaffold.js');
|
|
378
396
|
const result = scaffoldProject(process.cwd());
|
|
379
397
|
for (const f of result.created) {
|
|
@@ -384,30 +402,20 @@ export default class Init extends Command {
|
|
|
384
402
|
}
|
|
385
403
|
}
|
|
386
404
|
this.log(`\nTry '${this.config.bin} pipelines:list <project>' to verify GitLab access.\n`);
|
|
387
|
-
if (
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
'--gitlab-url', gitlabUrl,
|
|
399
|
-
]);
|
|
400
|
-
}
|
|
401
|
-
catch (error) {
|
|
402
|
-
this.warn(`MCP Deployment failed: ${error}`);
|
|
403
|
-
}
|
|
405
|
+
if (features.includes('mcp') && googleProjectId && bigqueryDataset && bigqueryTable) {
|
|
406
|
+
try {
|
|
407
|
+
await McpDeploy.run([
|
|
408
|
+
'--gcp-project', googleProjectId,
|
|
409
|
+
'--bq-dataset', bigqueryDataset,
|
|
410
|
+
'--bq-table', bigqueryTable,
|
|
411
|
+
'--gitlab-url', gitlabUrl,
|
|
412
|
+
]);
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
this.warn(`MCP Deployment failed: ${error}`);
|
|
404
416
|
}
|
|
405
417
|
}
|
|
406
|
-
|
|
407
|
-
default: true,
|
|
408
|
-
message: 'Configure a GitLab project (CI variables + optional GCP runner) now?',
|
|
409
|
-
});
|
|
410
|
-
if (!configureProject) {
|
|
418
|
+
if (!features.includes('ci')) {
|
|
411
419
|
return;
|
|
412
420
|
}
|
|
413
421
|
const updatedDefaultProject = await this.configureGitLabProject({ baseUrl: gitlabUrl, token: gitlabToken }, config.defaultProjectId);
|
|
@@ -447,13 +455,44 @@ export default class Init extends Command {
|
|
|
447
455
|
this.warn('GitLab credentials missing, skipping project configuration.');
|
|
448
456
|
return;
|
|
449
457
|
}
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
458
|
+
const detectedPath = detectGitRemotePath();
|
|
459
|
+
let projectPath;
|
|
460
|
+
let resolvedProject;
|
|
461
|
+
if (detectedPath) {
|
|
462
|
+
resolvedProject = await resolveProjectId(auth, detectedPath);
|
|
463
|
+
}
|
|
464
|
+
if (resolvedProject) {
|
|
465
|
+
const useDetected = await confirm({
|
|
466
|
+
default: true,
|
|
467
|
+
message: `Detected project: ${resolvedProject.name} (ID: ${resolvedProject.id}). Use it?`,
|
|
468
|
+
});
|
|
469
|
+
if (useDetected) {
|
|
470
|
+
projectPath = resolvedProject.path;
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
projectPath = await input({
|
|
474
|
+
default: currentDefault,
|
|
475
|
+
message: 'GitLab project path or URL',
|
|
476
|
+
});
|
|
477
|
+
resolvedProject = await resolveProjectId(auth, projectPath);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
projectPath = await input({
|
|
482
|
+
default: currentDefault ?? detectedPath,
|
|
483
|
+
message: 'GitLab project path or URL',
|
|
484
|
+
});
|
|
485
|
+
resolvedProject = await resolveProjectId(auth, projectPath);
|
|
486
|
+
}
|
|
454
487
|
if (!projectPath) {
|
|
455
488
|
this.warn('Project path is required to configure CI variables.');
|
|
456
489
|
}
|
|
490
|
+
if (resolvedProject) {
|
|
491
|
+
this.log(gray(` Project: ${resolvedProject.name} (ID: ${resolvedProject.id})`));
|
|
492
|
+
}
|
|
493
|
+
else if (projectPath) {
|
|
494
|
+
this.warn(`Could not resolve project "${projectPath}". Continuing with path as-is.`);
|
|
495
|
+
}
|
|
457
496
|
const setAsDefault = await confirm({
|
|
458
497
|
default: !currentDefault,
|
|
459
498
|
message: 'Use this project as the default for DuoOps commands?',
|
package/oclif.manifest.json
CHANGED