@commercetools-frontend/deployment-cli 0.0.0-FEC-212-react19-20250122084835

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.
@@ -0,0 +1,601 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var cac = require('cac');
6
+ var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
7
+ var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
8
+ var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
9
+ var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
10
+ var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
11
+ var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
12
+ var cosmiconfig = require('cosmiconfig');
13
+ var merge = require('lodash/merge');
14
+ var prompts = require('prompts');
15
+ var pRetry = require('p-retry');
16
+ var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
17
+ var _URLSearchParams = require('@babel/runtime-corejs3/core-js-stable/url-search-params');
18
+ var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
19
+ var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
20
+ var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
21
+ var node_process = require('node:process');
22
+
23
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
24
+
25
+ var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
26
+ var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
27
+ var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
28
+ var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
29
+ var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
30
+ var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
31
+ var merge__default = /*#__PURE__*/_interopDefault(merge);
32
+ var prompts__default = /*#__PURE__*/_interopDefault(prompts);
33
+ var pRetry__default = /*#__PURE__*/_interopDefault(pRetry);
34
+ var _URLSearchParams__default = /*#__PURE__*/_interopDefault(_URLSearchParams);
35
+ var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
36
+ var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
37
+ var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
38
+
39
+ var pkgJson = {
40
+ name: "@commercetools-frontend/deployment-cli",
41
+ version: "2.0.2",
42
+ description: "CLI to manage Custom Applications deployments in Google Storage.",
43
+ keywords: [
44
+ "commercetools",
45
+ "cli",
46
+ "deployment"
47
+ ],
48
+ license: "MIT",
49
+ main: "dist/commercetools-frontend-deployment-cli.cjs.js",
50
+ module: "dist/commercetools-frontend-deployment-cli.esm.js",
51
+ bin: "bin/cli.js",
52
+ files: [
53
+ "bin",
54
+ "cli",
55
+ "dist",
56
+ "package.json",
57
+ "LICENSE",
58
+ "README.md"
59
+ ],
60
+ scripts: {
61
+ typecheck: "tsc --noEmit"
62
+ },
63
+ dependencies: {
64
+ "@babel/core": "^7.22.11",
65
+ "@babel/runtime-corejs3": "^7.21.0",
66
+ cac: "^6.7.14",
67
+ cosmiconfig: "9.0.0",
68
+ lodash: "4.17.21",
69
+ "p-retry": "4.6.2",
70
+ prompts: "2.4.2"
71
+ },
72
+ devDependencies: {
73
+ "@tsconfig/node20": "20.1.4",
74
+ "@types/lodash": "^4.14.198",
75
+ "@types/node": "20.17.13",
76
+ "@types/prompts": "2.4.9",
77
+ msw: "1.3.5",
78
+ typescript: "5.2.2"
79
+ },
80
+ engines: {
81
+ node: ">=21",
82
+ npm: ">=6"
83
+ },
84
+ publishConfig: {
85
+ access: "public"
86
+ },
87
+ preconstruct: {
88
+ entrypoints: [
89
+ "./cli.ts",
90
+ "./index.ts"
91
+ ]
92
+ }
93
+ };
94
+
95
+ async function loadConfig() {
96
+ const deploymentConfigExplorer = cosmiconfig.cosmiconfig('deployment', {
97
+ searchStrategy: 'project'
98
+ });
99
+ const defaultConfig = {
100
+ CircleCI: {
101
+ apiBaseUrl: 'https://circleci.com/api/v2',
102
+ deploymentWorkflowName: 'test_build_and_deploy',
103
+ pagination: {
104
+ maxPages: 42,
105
+ pagesForPipelineSelection: 5
106
+ }
107
+ },
108
+ MerchantCenter: {}
109
+ };
110
+ try {
111
+ const cosmiconfigResult = await deploymentConfigExplorer.search();
112
+ const mergedConfig = merge__default["default"](defaultConfig, cosmiconfigResult?.config);
113
+ return mergedConfig;
114
+ } catch (e) {
115
+ console.warn(e);
116
+ throw new Error('Failed loading a deployment configuration. Create a cosmiconfig for `deployment` for example `deployment.config.cjs`.');
117
+ }
118
+ }
119
+ function throwIfConfigurationLacksRequiredValues(parsedConfiguration) {
120
+ if (!parsedConfiguration.CircleCI.projectName) {
121
+ throw new Error(`Missing 'projectName' in 'CircleCI' on configuration. Make sure it exists!`);
122
+ }
123
+ }
124
+ function throwIfRequiredEnvironmentVariableIsUnset(requiredEnvironmentVariables) {
125
+ _forEachInstanceProperty__default["default"](requiredEnvironmentVariables).call(requiredEnvironmentVariables, nameOfRequiredEnvironmentVariable => {
126
+ const valueOfRequiredEnvironmentVariable = process.env[nameOfRequiredEnvironmentVariable];
127
+ if (!valueOfRequiredEnvironmentVariable) throw new Error(`Missing '${nameOfRequiredEnvironmentVariable}' environment variable`);
128
+ });
129
+ }
130
+ const promptOptions = {
131
+ applicationSelect: _ref => {
132
+ let packages = _ref.packages;
133
+ return {
134
+ type: 'select',
135
+ name: 'applicationName',
136
+ message: 'Select an application',
137
+ choices: _mapInstanceProperty__default["default"](packages).call(packages, _ref2 => {
138
+ let packageJson = _ref2.packageJson;
139
+ const applicationName = packageJson.name.replace('@commercetools-local/application-', '');
140
+ return {
141
+ title: applicationName,
142
+ value: applicationName
143
+ };
144
+ })
145
+ };
146
+ },
147
+ deploymentPipelineSelect: _ref3 => {
148
+ let deploymentPipelines = _ref3.deploymentPipelines;
149
+ return {
150
+ type: 'select',
151
+ name: 'deploymentPipeline',
152
+ message: 'Select the revision you would like to deploy',
153
+ choices: _mapInstanceProperty__default["default"](deploymentPipelines).call(deploymentPipelines, deploymentPipeline => ({
154
+ title: `${deploymentPipeline.vcs.revision.substring(0, 7)} - ${deploymentPipeline.vcs.commit.subject} <${deploymentPipeline.trigger.actor.login}>`,
155
+ value: deploymentPipeline
156
+ }))
157
+ };
158
+ },
159
+ deploymentConfirmation: _ref4 => {
160
+ let approvalJob = _ref4.approvalJob,
161
+ revision = _ref4.revision;
162
+ return {
163
+ type: 'toggle',
164
+ name: 'confirmed',
165
+ message: `Are you sure you want to deploy by approving ${approvalJob} at ${revision}?`,
166
+ initial: false,
167
+ active: 'Yes',
168
+ inactive: 'No'
169
+ };
170
+ }
171
+ };
172
+ async function paginateToDeploymentPipeline(_ref5) {
173
+ let circleCiApis = _ref5.circleCiApis,
174
+ buildRevision = _ref5.buildRevision,
175
+ branch = _ref5.branch,
176
+ debug = _ref5.debug,
177
+ maxPages = _ref5.maxPages;
178
+ let deploymentPipeline;
179
+ let nextPageToken;
180
+ // eslint-disable-next-line no-plusplus
181
+ for (let i = 0; i < maxPages; i++) {
182
+ var _context, _context2;
183
+ // eslint-disable-next-line no-await-in-loop
184
+
185
+ const pipelineRequest = circleCiApis.pipelines({
186
+ pageToken: nextPageToken,
187
+ branch
188
+ });
189
+ const pipelines = await pipelineRequest.execute({
190
+ debug
191
+ });
192
+ nextPageToken = pipelines.next_page_token;
193
+ const nonScheduledPipelines = _filterInstanceProperty__default["default"](_context = _filterInstanceProperty__default["default"](_context2 = pipelines.items).call(_context2, isNonScheduledPipeline)).call(_context, isNonErroredPipeline);
194
+ if (buildRevision) {
195
+ console.log(`🔄 Trying to find pipeline with revision ${buildRevision}. Attempt ${i + 1} out of ${maxPages}.`);
196
+ deploymentPipeline = _findInstanceProperty__default["default"](nonScheduledPipelines).call(nonScheduledPipelines, pipeline => {
197
+ var _context3;
198
+ return _startsWithInstanceProperty__default["default"](_context3 = pipeline.vcs.revision).call(_context3, buildRevision);
199
+ });
200
+ } else {
201
+ deploymentPipeline = nonScheduledPipelines[0];
202
+ }
203
+ if (deploymentPipeline) {
204
+ console.log(`ℹ️ Using pipeline for deployment with revision ${deploymentPipeline.vcs.revision}.`);
205
+ break;
206
+ }
207
+ }
208
+ return deploymentPipeline;
209
+ }
210
+ async function collectDeploymentPipelines(_ref6) {
211
+ let circleCiApis = _ref6.circleCiApis,
212
+ branch = _ref6.branch,
213
+ pagesForPipelineSelection = _ref6.pagesForPipelineSelection,
214
+ debug = _ref6.debug;
215
+ let deploymentPipelines = [];
216
+ let nextPageToken;
217
+ // eslint-disable-next-line no-plusplus
218
+ for (let i = 0; i < pagesForPipelineSelection; i++) {
219
+ var _context4, _context5;
220
+ // eslint-disable-next-line no-await-in-loop
221
+ const pipelinesRequest = circleCiApis.pipelines({
222
+ pageToken: nextPageToken,
223
+ branch
224
+ });
225
+ const pipelines = await pipelinesRequest.execute({
226
+ debug
227
+ });
228
+ const nonScheduledPipelines = _filterInstanceProperty__default["default"](_context4 = _filterInstanceProperty__default["default"](_context5 = pipelines.items).call(_context5, isNonScheduledPipeline)).call(_context4, isNonErroredPipeline);
229
+ deploymentPipelines = _concatInstanceProperty__default["default"](deploymentPipelines).call(deploymentPipelines, nonScheduledPipelines);
230
+ }
231
+ return deploymentPipelines;
232
+ }
233
+ async function waitForDeploymentPipelinePrompt(_ref7) {
234
+ let circleCiApis = _ref7.circleCiApis,
235
+ branch = _ref7.branch,
236
+ pagesForPipelineSelection = _ref7.pagesForPipelineSelection,
237
+ debug = _ref7.debug;
238
+ const deploymentPipelines = await collectDeploymentPipelines({
239
+ branch,
240
+ pagesForPipelineSelection,
241
+ circleCiApis,
242
+ debug
243
+ });
244
+ const deploymentPipelinePrompt = await prompts__default["default"](
245
+ // @ts-expect-error prompts is not typed
246
+ promptOptions.deploymentPipelineSelect({
247
+ deploymentPipelines
248
+ }));
249
+ const revision = deploymentPipelinePrompt.deploymentPipeline.vcs.revision;
250
+ if (!revision) {
251
+ console.log('☝️ Please select a revision or specify it as a CLI argument via `--build-revision`.');
252
+ throw new Error('No revision specified.');
253
+ }
254
+ return deploymentPipelinePrompt.deploymentPipeline;
255
+ }
256
+ async function waitForConfirmationPrompt(_ref8) {
257
+ let approvalJob = _ref8.approvalJob,
258
+ revision = _ref8.revision;
259
+ return prompts__default["default"](
260
+ // @ts-expect-error prompts is not typed
261
+ promptOptions.deploymentConfirmation({
262
+ approvalJob,
263
+ revision
264
+ }));
265
+ }
266
+ function getJobUrl(_ref9) {
267
+ let pipelineNumber = _ref9.pipelineNumber,
268
+ workflowId = _ref9.workflowId,
269
+ jobNumber = _ref9.jobNumber,
270
+ projectName = _ref9.projectName;
271
+ return `https://app.circleci.com/pipelines/github/commercetools/${projectName}/${pipelineNumber}/workflows/${workflowId}/jobs/${jobNumber}`;
272
+ }
273
+ function isNonScheduledPipeline(pipeline) {
274
+ return pipeline.trigger.type !== 'schedule' && pipeline.trigger.type !== 'scheduled_pipeline';
275
+ }
276
+ function isNonErroredPipeline(pipeline) {
277
+ return pipeline.state !== 'errored';
278
+ }
279
+ async function waitForDeploymentJobNumber(_ref10, _ref11) {
280
+ let workflowId = _ref10.workflowId,
281
+ deploymentJob = _ref10.deploymentJob,
282
+ circleCiApis = _ref10.circleCiApis;
283
+ let debug = _ref11.debug;
284
+ const fetchDeploymentJobNumber = async () => {
285
+ var _context6;
286
+ const jobsRequest = circleCiApis.jobs({
287
+ workflowId
288
+ });
289
+ const jobs = await jobsRequest.execute({
290
+ debug
291
+ });
292
+ const applicationDeploymentJob = _findInstanceProperty__default["default"](_context6 = jobs.items).call(_context6, job => job.name === deploymentJob);
293
+ if (!applicationDeploymentJob || applicationDeploymentJob.status === 'blocked') {
294
+ throw new Error('Deployment job not yet running. Retrying.');
295
+ }
296
+ return applicationDeploymentJob.job_number;
297
+ };
298
+ const deploymentJobNumber = await pRetry__default["default"](fetchDeploymentJobNumber, {
299
+ onFailedAttempt: error => {
300
+ console.log(`🔄 Trying to find deployment job. Attempt ${error.attemptNumber} with ${error.retriesLeft} retries left.`);
301
+ },
302
+ retries: 10
303
+ });
304
+ return deploymentJobNumber;
305
+ }
306
+
307
+ async function approve(cliFlags, config, circleCiApis) {
308
+ var _context, _context2;
309
+ let approvalJob;
310
+ let deploymentJob;
311
+ if (cliFlags.deployment) {
312
+ const requestedDeployment = config.deployments?.[cliFlags.deployment];
313
+ if (!requestedDeployment) {
314
+ throw new Error(`⚠️ Deployment ${cliFlags.deployment} not found in configuration. Make sure it exists.`);
315
+ }
316
+ approvalJob = requestedDeployment.jobs.approval;
317
+ deploymentJob = requestedDeployment.jobs.deployment;
318
+ console.log(`ℹ️ Approving requested deployment ${cliFlags.deployment} with approval job ${approvalJob}.`);
319
+ } else {
320
+ approvalJob = cliFlags.approvalJob;
321
+ deploymentJob = cliFlags.deploymentJob;
322
+ console.log(`ℹ️ Approving with approval job ${approvalJob}.`);
323
+ }
324
+ const deploymentPipeline = cliFlags.yes ? await paginateToDeploymentPipeline({
325
+ circleCiApis,
326
+ buildRevision: cliFlags.buildRevision,
327
+ branch: cliFlags.branch,
328
+ debug: cliFlags.debug,
329
+ maxPages: config.CircleCI.pagination?.maxPages ?? 1
330
+ }) : await waitForDeploymentPipelinePrompt({
331
+ branch: cliFlags.branch,
332
+ circleCiApis,
333
+ pagesForPipelineSelection: config.CircleCI.pagination?.pagesForPipelineSelection ?? 1,
334
+ debug: cliFlags.debug
335
+ });
336
+ if (!deploymentPipeline) {
337
+ throw new Error(`⚠️ No workflow called ${config.CircleCI.deploymentWorkflowName} found in any pipeline for deployment.`);
338
+ }
339
+ console.log(`ℹ️ Found pipeline for deployment with revision ${deploymentPipeline.vcs.revision}.`);
340
+ const workflowsRequest = circleCiApis.workflows({
341
+ pipelineId: deploymentPipeline.id
342
+ });
343
+ const workflows = await workflowsRequest.execute({
344
+ debug: cliFlags.debug
345
+ });
346
+ const buildAndDeployWorkflow = _findInstanceProperty__default["default"](_context = workflows.items).call(_context, workflow => workflow.name === config.CircleCI.deploymentWorkflowName);
347
+ if (!buildAndDeployWorkflow) {
348
+ throw new Error(`⚠️ No workflow called ${config.CircleCI.deploymentWorkflowName} found for deployment.`);
349
+ }
350
+ const workflowId = buildAndDeployWorkflow.id;
351
+ console.log(`ℹ️ Found workflow to build and deploy with id ${workflowId}.`);
352
+ const jobsRequest = circleCiApis.jobs({
353
+ workflowId
354
+ });
355
+ const jobs = await jobsRequest.execute({
356
+ debug: cliFlags.debug
357
+ });
358
+ console.log(`ℹ️ Found jobs for workflow.`);
359
+ const applicationApprovalJob = _findInstanceProperty__default["default"](_context2 = jobs.items).call(_context2, job => job.name === approvalJob);
360
+ const applicationApprovalJobId = applicationApprovalJob?.id;
361
+ if (!applicationApprovalJobId) {
362
+ throw new Error(`✌️ Could not find deployment approval job named ${approvalJob} at revision ${deploymentPipeline.vcs.revision}. Maybe try again later.`);
363
+ }
364
+ console.log(`ℹ️ Found deployment approval job named ${approvalJob} with id ${applicationApprovalJobId}.`);
365
+ let confirmationPrompt;
366
+ if (!cliFlags.yes) {
367
+ confirmationPrompt = await waitForConfirmationPrompt({
368
+ approvalJob: approvalJob,
369
+ revision: deploymentPipeline.vcs.revision
370
+ });
371
+ }
372
+ if (cliFlags.yes || confirmationPrompt?.confirmed) {
373
+ if (cliFlags.dryRun) {
374
+ console.log(`🙊 Not approving deployment job due to dry run.`);
375
+ } else {
376
+ console.log(`ℹ️ Approving deployment job.`);
377
+ }
378
+ const approvalRequest = circleCiApis.approve({
379
+ workflowId,
380
+ approvalRequestId: applicationApprovalJobId
381
+ });
382
+ await approvalRequest.execute({
383
+ debug: cliFlags.debug,
384
+ skip: cliFlags.dryRun
385
+ });
386
+ if (cliFlags.yes) {
387
+ console.log(`ℹ️ Skipping determining deployment job approved by ${approvalJob} due to '--yes' flag. Please check CircleCI manually.`);
388
+ } else if (cliFlags.dryRun) {
389
+ console.log(`✌️ Dry running hence could not determine deployment job approved by ${approvalJob}.`);
390
+ } else if (deploymentJob) {
391
+ const deploymentJobNumber = await waitForDeploymentJobNumber({
392
+ workflowId,
393
+ deploymentJob,
394
+ circleCiApis
395
+ }, {
396
+ debug: cliFlags.debug,
397
+ dryRun: cliFlags.dryRun,
398
+ yes: cliFlags.yes
399
+ });
400
+ console.log(`🙌 The deployment via ${approvalJob} at revision ${deploymentPipeline.vcs.revision} is running at: ${getJobUrl({
401
+ projectName: config.CircleCI.projectName,
402
+ pipelineNumber: deploymentPipeline.number,
403
+ workflowId,
404
+ jobNumber: deploymentJobNumber
405
+ })}`);
406
+ } else {
407
+ console.log(`ℹ️ Skipping determining deployment job as no '--deployment-job' name to wait for was passed. Please check CircleCI manually.`);
408
+ }
409
+ } else {
410
+ console.log(`ℹ️ Not approving deployment job. Confirm the prompt or use '--yes' option.`);
411
+ }
412
+ }
413
+
414
+ async function processCircleCiResponse(response) {
415
+ if (!response.ok) {
416
+ /**
417
+ * NOTE:
418
+ * Trying to handle known but undocumented responses of the CircleCI API.
419
+ *
420
+ * 1. Message: Already approved job
421
+ * Deployment was already triggered manually or by train the day before.
422
+ */
423
+
424
+ // Response data is a stream so text OR json can only be read once, so
425
+ // we read it as text first and then try to parse it as json to handle
426
+ // known error responses.
427
+ const error = await response.text();
428
+ try {
429
+ // The CircleCI API always uses content-type text/plain, so we always
430
+ // try parsing JSON to see if the message property is present.
431
+ const _JSON$parse = JSON.parse(error),
432
+ message = _JSON$parse.message;
433
+ if (message.match(/job already approved/i)) {
434
+ console.log('ℹ️ Deployment job is already approved.');
435
+ // TODO: can we return instead of force exiting?
436
+ node_process.exit(0);
437
+ }
438
+ } catch {
439
+ // Ignore JSON parsing errors
440
+ }
441
+ throw new Error(`${response.status}: Network response was not ok.\n
442
+ Status text is ${response.statusText} and text is ${error}.`);
443
+ }
444
+ return response.json();
445
+ }
446
+ function createCircleCiClient(_ref) {
447
+ let projectName = _ref.projectName,
448
+ apiBaseUrl = _ref.apiBaseUrl;
449
+ async function execute(api) {
450
+ let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
451
+ skip = _ref2.skip,
452
+ debug = _ref2.debug;
453
+ let url = `${apiBaseUrl}${api.url}`;
454
+ if (api.params && api.method === 'GET') {
455
+ const urlSearchParams = new _URLSearchParams__default["default"]();
456
+ for (const _ref3 of _Object$entries__default["default"](api.params)) {
457
+ var _ref4 = _slicedToArray(_ref3, 2);
458
+ const key = _ref4[0];
459
+ const value = _ref4[1];
460
+ if (value !== null && value !== undefined) {
461
+ urlSearchParams.append(key, value);
462
+ }
463
+ }
464
+ url += `?${urlSearchParams.toString()}`;
465
+ }
466
+ if (skip) {
467
+ if (debug) {
468
+ console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
469
+ }
470
+
471
+ // @ts-expect-error
472
+ return _Promise__default["default"].resolve();
473
+ }
474
+ if (debug) {
475
+ console.log(`🏭 Calling CircleCI API at: ${url}.`);
476
+ }
477
+ try {
478
+ const response = await fetch(url, {
479
+ headers: api.headers,
480
+ method: api.method,
481
+ body: api.method === 'POST' ? _JSON$stringify__default["default"](api.params) : undefined
482
+ });
483
+ const processedCircleCiResponse = await processCircleCiResponse(response);
484
+ return processedCircleCiResponse;
485
+ } catch (error) {
486
+ console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
487
+ throw error;
488
+ }
489
+ }
490
+ return {
491
+ pipelines: function () {
492
+ let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
493
+ pageToken = _ref5.pageToken,
494
+ _ref5$projectSlug = _ref5.projectSlug,
495
+ projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
496
+ _ref5$branch = _ref5.branch,
497
+ branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
498
+ return {
499
+ execute: options => execute({
500
+ url: `/project/${projectSlug}/pipeline`,
501
+ headers: {
502
+ 'Content-Type': 'application/json',
503
+ // The CLI throws if this is not present on environment
504
+ 'Circle-Token': process.env.CIRCLE_TOKEN
505
+ },
506
+ method: 'GET',
507
+ params: {
508
+ branch,
509
+ 'page-token': pageToken
510
+ }
511
+ }, options)
512
+ };
513
+ },
514
+ workflows: _ref6 => {
515
+ let pipelineId = _ref6.pipelineId;
516
+ return {
517
+ execute: options => execute({
518
+ url: `/pipeline/${pipelineId}/workflow`,
519
+ headers: {
520
+ 'Content-Type': 'application/json',
521
+ // The CLI throws if this is not present on environment
522
+ 'Circle-Token': process.env.CIRCLE_TOKEN
523
+ },
524
+ method: 'GET'
525
+ }, options)
526
+ };
527
+ },
528
+ jobs: _ref7 => {
529
+ let workflowId = _ref7.workflowId;
530
+ return {
531
+ execute: options => execute({
532
+ url: `/workflow/${workflowId}/job`,
533
+ headers: {
534
+ 'Content-Type': 'application/json',
535
+ // The CLI throws if this is not present on environment
536
+ 'Circle-Token': process.env.CIRCLE_TOKEN
537
+ },
538
+ method: 'GET'
539
+ }, options)
540
+ };
541
+ },
542
+ approve: _ref8 => {
543
+ let workflowId = _ref8.workflowId,
544
+ approvalRequestId = _ref8.approvalRequestId;
545
+ return {
546
+ execute: options => execute({
547
+ url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
548
+ headers: {
549
+ 'Content-Type': 'application/json',
550
+ // The CLI throws if this is not present on environment
551
+ 'Circle-Token': process.env.CIRCLE_TOKEN
552
+ },
553
+ method: 'POST'
554
+ }, options)
555
+ };
556
+ }
557
+ };
558
+ }
559
+
560
+ const cli = cac.cac('deployment-cli');
561
+ async function run() {
562
+ const config = await loadConfig();
563
+ throwIfConfigurationLacksRequiredValues(config);
564
+ const circleCiApis = createCircleCiClient({
565
+ projectName: config.CircleCI.projectName,
566
+ apiBaseUrl: config.CircleCI.apiBaseUrl
567
+ });
568
+
569
+ // General CLI options
570
+ cli.option('--dry-run', '(optional) Simulate a deployment.', {
571
+ default: false
572
+ });
573
+ cli.option('--debug', '(optional) Print additional debug information.', {
574
+ default: false
575
+ });
576
+
577
+ // Default command
578
+ cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
579
+
580
+ // Command: Approve
581
+ const usageApprove = 'Approves a job and by this triggers a deployment of a component. It requires a "CIRCLE_TOKEN" environment variable (https://circleci.com/docs/2.0/managing-api-tokens/).';
582
+ cli.command('approve', usageApprove).usage(`approve \n\n ${usageApprove}`).option('--approval-job <string>', 'The name of the approval job to approve a deployment with.').option('--deployment-job [string]', '(optional) The name of the deployment job triggered by the approval job. If passed the CLI will print a URL to the deployment triggered on CircleCI.').option('--deployment [string]', '(optional) The name of a deployment configured in the configuration file.').option('--build-revision [git-sha]', '(optional) The git commit SHA that needs to be deployed. If not specified, the last successful pipeline is used.').option('--branch [string]', '(optional) The git branch to deploy from. If not specified.', {
583
+ default: 'main'
584
+ }).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
585
+ default: false
586
+ }).action(async options => {
587
+ if (options.dryRun) {
588
+ console.log(`🙊 Do not worry. This is a dry run!`);
589
+ }
590
+ throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
591
+ await approve(options, config, circleCiApis);
592
+ });
593
+ cli.help();
594
+ cli.version(pkgJson.version);
595
+ cli.parse(process.argv, {
596
+ run: false
597
+ });
598
+ await cli.runMatchedCommand();
599
+ }
600
+
601
+ exports.run = run;