duoops 0.1.0 → 0.1.3
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 +24 -0
- package/bin/dev.js +0 -0
- package/dist/commands/init.js +11 -4
- package/oclif.manifest.json +91 -91
- package/package.json +12 -7
package/README.md
CHANGED
|
@@ -158,6 +158,23 @@ duoops runner:logs --lines 300
|
|
|
158
158
|
duoops runner:reinstall-duoops --version 0.1.0
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
### 7. Use the GitLab CI Component
|
|
162
|
+
|
|
163
|
+
Instead of copying `.duoops/measure-component.yml` into every project, you can reference the published component directly:
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
include:
|
|
167
|
+
- component: gitlab.com/youneslaaroussi/duoops/templates/duoops-measure-component@v0.1.0
|
|
168
|
+
inputs:
|
|
169
|
+
gcp_project_id: "my-project"
|
|
170
|
+
gcp_instance_id: "1234567890123456789"
|
|
171
|
+
gcp_zone: "us-central1-a"
|
|
172
|
+
machine_type: "e2-standard-4"
|
|
173
|
+
tags: ["gcp"]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Make sure your runner already has DuoOps installed (the provisioning flow handles this) and that `GCP_SA_KEY_BASE64` plus any optional BigQuery variables are set in the project’s CI/CD settings. Pin to a version tag (`@v0.1.0`) and update when you’re ready to adopt new behavior.
|
|
177
|
+
|
|
161
178
|
## 🛠️ Development
|
|
162
179
|
|
|
163
180
|
### Project Structure
|
|
@@ -188,6 +205,13 @@ This compiles the TypeScript CLI and builds the React frontend, copying assets t
|
|
|
188
205
|
3. Inspect the publish payload locally with `pnpm pack` (this runs the `prepack` script, which now builds the CLI, portal, and Oclif manifest automatically). Untar the generated `.tgz` if you want to double-check the contents.
|
|
189
206
|
4. When you're satisfied, publish the package: `pnpm publish --access public`.
|
|
190
207
|
|
|
208
|
+
## 📦 Publishing the CI Component
|
|
209
|
+
|
|
210
|
+
1. Update `templates/duoops-measure-component.yml` and commit the changes.
|
|
211
|
+
2. Let the `.gitlab-ci.yml` validation job pass (runs automatically on MRs, default branch, and tags).
|
|
212
|
+
3. Tag the repository (e.g., `git tag v0.1.0 && git push origin v0.1.0`). Consumers reference the component with the tag via the snippet above.
|
|
213
|
+
4. Update release notes/README with the new component version so teams know what changed.
|
|
214
|
+
|
|
191
215
|
## 📄 License
|
|
192
216
|
|
|
193
217
|
MIT
|
package/bin/dev.js
CHANGED
|
File without changes
|
package/dist/commands/init.js
CHANGED
|
@@ -78,17 +78,23 @@ const createServiceAccountKey = (projectId, serviceAccount) => {
|
|
|
78
78
|
fs.unlinkSync(tmpPath);
|
|
79
79
|
return contents.toString('base64');
|
|
80
80
|
};
|
|
81
|
-
const
|
|
81
|
+
const ensureServiceEnabled = (projectId, service, label, log) => {
|
|
82
82
|
try {
|
|
83
|
-
log?.(gray(
|
|
84
|
-
execSync(`gcloud services enable
|
|
83
|
+
log?.(gray(`Ensuring ${label} API is enabled...`));
|
|
84
|
+
execSync(`gcloud services enable ${service} --project=${projectId} --quiet`, {
|
|
85
85
|
stdio: 'ignore',
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
catch {
|
|
89
|
-
log?.(gray(
|
|
89
|
+
log?.(gray(`${label} API enablement skipped (it may already be enabled).`));
|
|
90
90
|
}
|
|
91
91
|
};
|
|
92
|
+
const ensureComputeApiEnabled = (projectId, log) => {
|
|
93
|
+
ensureServiceEnabled(projectId, 'compute.googleapis.com', 'Compute Engine', log);
|
|
94
|
+
};
|
|
95
|
+
const ensureMonitoringApiEnabled = (projectId, log) => {
|
|
96
|
+
ensureServiceEnabled(projectId, 'monitoring.googleapis.com', 'Cloud Monitoring', log);
|
|
97
|
+
};
|
|
92
98
|
const sleep = (ms) => new Promise((resolve) => {
|
|
93
99
|
setTimeout(resolve, ms);
|
|
94
100
|
});
|
|
@@ -440,6 +446,7 @@ export default class Init extends Command {
|
|
|
440
446
|
message: 'Runner tag (GitLab jobs will use this)',
|
|
441
447
|
});
|
|
442
448
|
ensureComputeApiEnabled(gcpProjectId, (message) => this.log(message));
|
|
449
|
+
ensureMonitoringApiEnabled(gcpProjectId, (message) => this.log(message));
|
|
443
450
|
let runnerToken = tryCreateRunnerToken(projectPath, vmName, runnerTag);
|
|
444
451
|
if (!runnerToken) {
|
|
445
452
|
this.log(gray('Unable to create a runner token automatically. Generate one in your GitLab project (Settings → CI/CD → Runners) and paste it below.'));
|
package/oclif.manifest.json
CHANGED
|
@@ -171,96 +171,6 @@
|
|
|
171
171
|
"logs.js"
|
|
172
172
|
]
|
|
173
173
|
},
|
|
174
|
-
"pipelines:list": {
|
|
175
|
-
"aliases": [],
|
|
176
|
-
"args": {
|
|
177
|
-
"project": {
|
|
178
|
-
"description": "Project ID or path (e.g. group/project)",
|
|
179
|
-
"name": "project",
|
|
180
|
-
"required": false
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
"description": "List GitLab CI pipelines for a project",
|
|
184
|
-
"examples": [
|
|
185
|
-
"<%= config.bin %> <%= command.id %> group/my-project",
|
|
186
|
-
"<%= config.bin %> <%= command.id %> 123 --limit 20 --ref main"
|
|
187
|
-
],
|
|
188
|
-
"flags": {
|
|
189
|
-
"limit": {
|
|
190
|
-
"char": "n",
|
|
191
|
-
"description": "Maximum number of pipelines to return",
|
|
192
|
-
"name": "limit",
|
|
193
|
-
"default": 10,
|
|
194
|
-
"hasDynamicHelp": false,
|
|
195
|
-
"multiple": false,
|
|
196
|
-
"type": "option"
|
|
197
|
-
},
|
|
198
|
-
"ref": {
|
|
199
|
-
"description": "Filter by branch or tag",
|
|
200
|
-
"name": "ref",
|
|
201
|
-
"hasDynamicHelp": false,
|
|
202
|
-
"multiple": false,
|
|
203
|
-
"type": "option"
|
|
204
|
-
},
|
|
205
|
-
"status": {
|
|
206
|
-
"description": "Filter by status (created, pending, running, success, failed, canceled, skipped, manual, scheduled)",
|
|
207
|
-
"name": "status",
|
|
208
|
-
"hasDynamicHelp": false,
|
|
209
|
-
"multiple": false,
|
|
210
|
-
"type": "option"
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
"hasDynamicHelp": false,
|
|
214
|
-
"hiddenAliases": [],
|
|
215
|
-
"id": "pipelines:list",
|
|
216
|
-
"pluginAlias": "duoops",
|
|
217
|
-
"pluginName": "duoops",
|
|
218
|
-
"pluginType": "core",
|
|
219
|
-
"strict": true,
|
|
220
|
-
"enableJsonFlag": false,
|
|
221
|
-
"isESM": true,
|
|
222
|
-
"relativePath": [
|
|
223
|
-
"dist",
|
|
224
|
-
"commands",
|
|
225
|
-
"pipelines",
|
|
226
|
-
"list.js"
|
|
227
|
-
]
|
|
228
|
-
},
|
|
229
|
-
"pipelines:show": {
|
|
230
|
-
"aliases": [],
|
|
231
|
-
"args": {
|
|
232
|
-
"project": {
|
|
233
|
-
"description": "Project ID (e.g. 123456)",
|
|
234
|
-
"name": "project",
|
|
235
|
-
"required": true
|
|
236
|
-
},
|
|
237
|
-
"pipeline_id": {
|
|
238
|
-
"description": "Pipeline ID",
|
|
239
|
-
"name": "pipeline_id",
|
|
240
|
-
"required": true
|
|
241
|
-
}
|
|
242
|
-
},
|
|
243
|
-
"description": "Show pipeline details and jobs",
|
|
244
|
-
"examples": [
|
|
245
|
-
"<%= config.bin %> <%= command.id %> 12345 67890"
|
|
246
|
-
],
|
|
247
|
-
"flags": {},
|
|
248
|
-
"hasDynamicHelp": false,
|
|
249
|
-
"hiddenAliases": [],
|
|
250
|
-
"id": "pipelines:show",
|
|
251
|
-
"pluginAlias": "duoops",
|
|
252
|
-
"pluginName": "duoops",
|
|
253
|
-
"pluginType": "core",
|
|
254
|
-
"strict": true,
|
|
255
|
-
"enableJsonFlag": false,
|
|
256
|
-
"isESM": true,
|
|
257
|
-
"relativePath": [
|
|
258
|
-
"dist",
|
|
259
|
-
"commands",
|
|
260
|
-
"pipelines",
|
|
261
|
-
"show.js"
|
|
262
|
-
]
|
|
263
|
-
},
|
|
264
174
|
"measure:calculate": {
|
|
265
175
|
"aliases": [],
|
|
266
176
|
"args": {},
|
|
@@ -410,6 +320,96 @@
|
|
|
410
320
|
"seed.js"
|
|
411
321
|
]
|
|
412
322
|
},
|
|
323
|
+
"pipelines:list": {
|
|
324
|
+
"aliases": [],
|
|
325
|
+
"args": {
|
|
326
|
+
"project": {
|
|
327
|
+
"description": "Project ID or path (e.g. group/project)",
|
|
328
|
+
"name": "project",
|
|
329
|
+
"required": false
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
"description": "List GitLab CI pipelines for a project",
|
|
333
|
+
"examples": [
|
|
334
|
+
"<%= config.bin %> <%= command.id %> group/my-project",
|
|
335
|
+
"<%= config.bin %> <%= command.id %> 123 --limit 20 --ref main"
|
|
336
|
+
],
|
|
337
|
+
"flags": {
|
|
338
|
+
"limit": {
|
|
339
|
+
"char": "n",
|
|
340
|
+
"description": "Maximum number of pipelines to return",
|
|
341
|
+
"name": "limit",
|
|
342
|
+
"default": 10,
|
|
343
|
+
"hasDynamicHelp": false,
|
|
344
|
+
"multiple": false,
|
|
345
|
+
"type": "option"
|
|
346
|
+
},
|
|
347
|
+
"ref": {
|
|
348
|
+
"description": "Filter by branch or tag",
|
|
349
|
+
"name": "ref",
|
|
350
|
+
"hasDynamicHelp": false,
|
|
351
|
+
"multiple": false,
|
|
352
|
+
"type": "option"
|
|
353
|
+
},
|
|
354
|
+
"status": {
|
|
355
|
+
"description": "Filter by status (created, pending, running, success, failed, canceled, skipped, manual, scheduled)",
|
|
356
|
+
"name": "status",
|
|
357
|
+
"hasDynamicHelp": false,
|
|
358
|
+
"multiple": false,
|
|
359
|
+
"type": "option"
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
"hasDynamicHelp": false,
|
|
363
|
+
"hiddenAliases": [],
|
|
364
|
+
"id": "pipelines:list",
|
|
365
|
+
"pluginAlias": "duoops",
|
|
366
|
+
"pluginName": "duoops",
|
|
367
|
+
"pluginType": "core",
|
|
368
|
+
"strict": true,
|
|
369
|
+
"enableJsonFlag": false,
|
|
370
|
+
"isESM": true,
|
|
371
|
+
"relativePath": [
|
|
372
|
+
"dist",
|
|
373
|
+
"commands",
|
|
374
|
+
"pipelines",
|
|
375
|
+
"list.js"
|
|
376
|
+
]
|
|
377
|
+
},
|
|
378
|
+
"pipelines:show": {
|
|
379
|
+
"aliases": [],
|
|
380
|
+
"args": {
|
|
381
|
+
"project": {
|
|
382
|
+
"description": "Project ID (e.g. 123456)",
|
|
383
|
+
"name": "project",
|
|
384
|
+
"required": true
|
|
385
|
+
},
|
|
386
|
+
"pipeline_id": {
|
|
387
|
+
"description": "Pipeline ID",
|
|
388
|
+
"name": "pipeline_id",
|
|
389
|
+
"required": true
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
"description": "Show pipeline details and jobs",
|
|
393
|
+
"examples": [
|
|
394
|
+
"<%= config.bin %> <%= command.id %> 12345 67890"
|
|
395
|
+
],
|
|
396
|
+
"flags": {},
|
|
397
|
+
"hasDynamicHelp": false,
|
|
398
|
+
"hiddenAliases": [],
|
|
399
|
+
"id": "pipelines:show",
|
|
400
|
+
"pluginAlias": "duoops",
|
|
401
|
+
"pluginName": "duoops",
|
|
402
|
+
"pluginType": "core",
|
|
403
|
+
"strict": true,
|
|
404
|
+
"enableJsonFlag": false,
|
|
405
|
+
"isESM": true,
|
|
406
|
+
"relativePath": [
|
|
407
|
+
"dist",
|
|
408
|
+
"commands",
|
|
409
|
+
"pipelines",
|
|
410
|
+
"show.js"
|
|
411
|
+
]
|
|
412
|
+
},
|
|
413
413
|
"runner:logs": {
|
|
414
414
|
"aliases": [],
|
|
415
415
|
"args": {},
|
|
@@ -480,5 +480,5 @@
|
|
|
480
480
|
]
|
|
481
481
|
}
|
|
482
482
|
},
|
|
483
|
-
"version": "0.1.
|
|
483
|
+
"version": "0.1.3"
|
|
484
484
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "duoops",
|
|
3
3
|
"description": "Toolset for Explainable and Sustainable CI on Gitlab.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"author": "Younes Laaroussi",
|
|
6
6
|
"bin": {
|
|
7
7
|
"duoops": "./bin/run.js"
|
|
@@ -88,16 +88,21 @@
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
|
-
"repository":
|
|
92
|
-
|
|
93
|
-
"
|
|
91
|
+
"repository": {
|
|
92
|
+
"type": "git",
|
|
93
|
+
"url": "https://gitlab.com/youneslaaroussi/duoops.git"
|
|
94
94
|
},
|
|
95
|
-
"types": "dist/index.d.ts",
|
|
96
95
|
"scripts": {
|
|
97
96
|
"build": "shx rm -rf dist && tsc -b && pnpm --filter portal run build && shx cp -r portal/dist dist/portal",
|
|
98
97
|
"lint": "eslint --ignore-pattern \"portal/**\"",
|
|
98
|
+
"postpack": "shx rm -f oclif.manifest.json",
|
|
99
99
|
"posttest": "pnpm run lint",
|
|
100
|
+
"prepack": "pnpm run build && oclif manifest && oclif readme",
|
|
100
101
|
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
|
101
102
|
"version": "oclif readme && git add README.md"
|
|
102
|
-
}
|
|
103
|
-
|
|
103
|
+
},
|
|
104
|
+
"publishConfig": {
|
|
105
|
+
"access": "public"
|
|
106
|
+
},
|
|
107
|
+
"types": "dist/index.d.ts"
|
|
108
|
+
}
|