@commercetools-frontend/deployment-cli 2.0.3 → 2.0.5

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/bin/cli.js CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ process.env.NODE_ENV = 'production';
4
+
3
5
  const { exit } = require('node:process');
4
6
  const { run } = require('@commercetools-frontend/deployment-cli/cli');
5
7
 
@@ -2,43 +2,56 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var cac = require('cac');
6
- var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
5
+ var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
6
+ var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
7
+ var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
8
+ var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
7
9
  var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
10
+ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
11
+ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
12
+ var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
13
+ var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
14
+ var commander = require('commander');
15
+ var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
16
+ var _URLSearchParams = require('@babel/runtime-corejs3/core-js-stable/url-search-params');
17
+ var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
18
+ var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
19
+ var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
20
+ var node_process = require('node:process');
21
+ var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
8
22
  var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
9
- var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
10
23
  var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
11
24
  var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
12
25
  var cosmiconfig = require('cosmiconfig');
13
26
  var merge = require('lodash/merge');
14
27
  var prompts = require('prompts');
15
28
  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
29
 
23
30
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
24
31
 
25
- var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
32
+ var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
33
+ var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
34
+ var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
35
+ var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
26
36
  var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
37
+ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
38
+ var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
39
+ var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
40
+ var _URLSearchParams__default = /*#__PURE__*/_interopDefault(_URLSearchParams);
41
+ var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
42
+ var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
43
+ var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
44
+ var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
27
45
  var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
28
- var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
29
46
  var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
30
47
  var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
31
48
  var merge__default = /*#__PURE__*/_interopDefault(merge);
32
49
  var prompts__default = /*#__PURE__*/_interopDefault(prompts);
33
50
  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
51
 
39
52
  var pkgJson = {
40
53
  name: "@commercetools-frontend/deployment-cli",
41
- version: "2.0.3",
54
+ version: "2.0.5",
42
55
  description: "CLI to manage Custom Applications deployments in Google Storage.",
43
56
  keywords: [
44
57
  "commercetools",
@@ -63,7 +76,7 @@ var pkgJson = {
63
76
  dependencies: {
64
77
  "@babel/core": "^7.22.11",
65
78
  "@babel/runtime-corejs3": "^7.21.0",
66
- cac: "^6.7.14",
79
+ commander: "^13.1.0",
67
80
  cosmiconfig: "9.0.0",
68
81
  lodash: "4.17.21",
69
82
  "p-retry": "4.6.2",
@@ -72,7 +85,7 @@ var pkgJson = {
72
85
  devDependencies: {
73
86
  "@tsconfig/node20": "20.1.4",
74
87
  "@types/lodash": "^4.14.198",
75
- "@types/node": "22.10.10",
88
+ "@types/node": "22.13.9",
76
89
  "@types/prompts": "2.4.9",
77
90
  msw: "1.3.5",
78
91
  typescript: "5.2.2"
@@ -92,6 +105,152 @@ var pkgJson = {
92
105
  }
93
106
  };
94
107
 
108
+ async function processCircleCiResponse(response) {
109
+ if (!response.ok) {
110
+ /**
111
+ * NOTE:
112
+ * Trying to handle known but undocumented responses of the CircleCI API.
113
+ *
114
+ * 1. Message: Already approved job
115
+ * Deployment was already triggered manually or by train the day before.
116
+ */
117
+
118
+ // Response data is a stream so text OR json can only be read once, so
119
+ // we read it as text first and then try to parse it as json to handle
120
+ // known error responses.
121
+ const error = await response.text();
122
+ try {
123
+ // The CircleCI API always uses content-type text/plain, so we always
124
+ // try parsing JSON to see if the message property is present.
125
+ const _JSON$parse = JSON.parse(error),
126
+ message = _JSON$parse.message;
127
+ if (message.match(/job already approved/i)) {
128
+ console.log('ℹ️ Deployment job is already approved.');
129
+ // TODO: can we return instead of force exiting?
130
+ node_process.exit(0);
131
+ }
132
+ } catch {
133
+ // Ignore JSON parsing errors
134
+ }
135
+ throw new Error(`${response.status}: Network response was not ok.\n
136
+ Status text is ${response.statusText} and text is ${error}.`);
137
+ }
138
+ return response.json();
139
+ }
140
+ function createCircleCiClient(_ref) {
141
+ let projectName = _ref.projectName,
142
+ apiBaseUrl = _ref.apiBaseUrl;
143
+ async function execute(api) {
144
+ let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
145
+ skip = _ref2.skip,
146
+ debug = _ref2.debug;
147
+ let url = `${apiBaseUrl}${api.url}`;
148
+ if (api.params && api.method === 'GET') {
149
+ const urlSearchParams = new _URLSearchParams__default["default"]();
150
+ for (const _ref3 of _Object$entries__default["default"](api.params)) {
151
+ var _ref4 = _slicedToArray(_ref3, 2);
152
+ const key = _ref4[0];
153
+ const value = _ref4[1];
154
+ if (value !== null && value !== undefined) {
155
+ urlSearchParams.append(key, value);
156
+ }
157
+ }
158
+ url += `?${urlSearchParams.toString()}`;
159
+ }
160
+ if (skip) {
161
+ if (debug) {
162
+ console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
163
+ }
164
+
165
+ // @ts-expect-error
166
+ return _Promise__default["default"].resolve();
167
+ }
168
+ if (debug) {
169
+ console.log(`🏭 Calling CircleCI API at: ${url}.`);
170
+ }
171
+ try {
172
+ const response = await fetch(url, {
173
+ headers: api.headers,
174
+ method: api.method,
175
+ body: api.method === 'POST' ? _JSON$stringify__default["default"](api.params) : undefined
176
+ });
177
+ const processedCircleCiResponse = await processCircleCiResponse(response);
178
+ return processedCircleCiResponse;
179
+ } catch (error) {
180
+ console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
181
+ throw error;
182
+ }
183
+ }
184
+ return {
185
+ pipelines: function () {
186
+ let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
187
+ pageToken = _ref5.pageToken,
188
+ _ref5$projectSlug = _ref5.projectSlug,
189
+ projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
190
+ _ref5$branch = _ref5.branch,
191
+ branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
192
+ return {
193
+ execute: options => execute({
194
+ url: `/project/${projectSlug}/pipeline`,
195
+ headers: {
196
+ 'Content-Type': 'application/json',
197
+ // The CLI throws if this is not present on environment
198
+ 'Circle-Token': process.env.CIRCLE_TOKEN
199
+ },
200
+ method: 'GET',
201
+ params: {
202
+ branch,
203
+ 'page-token': pageToken
204
+ }
205
+ }, options)
206
+ };
207
+ },
208
+ workflows: _ref6 => {
209
+ let pipelineId = _ref6.pipelineId;
210
+ return {
211
+ execute: options => execute({
212
+ url: `/pipeline/${pipelineId}/workflow`,
213
+ headers: {
214
+ 'Content-Type': 'application/json',
215
+ // The CLI throws if this is not present on environment
216
+ 'Circle-Token': process.env.CIRCLE_TOKEN
217
+ },
218
+ method: 'GET'
219
+ }, options)
220
+ };
221
+ },
222
+ jobs: _ref7 => {
223
+ let workflowId = _ref7.workflowId;
224
+ return {
225
+ execute: options => execute({
226
+ url: `/workflow/${workflowId}/job`,
227
+ headers: {
228
+ 'Content-Type': 'application/json',
229
+ // The CLI throws if this is not present on environment
230
+ 'Circle-Token': process.env.CIRCLE_TOKEN
231
+ },
232
+ method: 'GET'
233
+ }, options)
234
+ };
235
+ },
236
+ approve: _ref8 => {
237
+ let workflowId = _ref8.workflowId,
238
+ approvalRequestId = _ref8.approvalRequestId;
239
+ return {
240
+ execute: options => execute({
241
+ url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
242
+ headers: {
243
+ 'Content-Type': 'application/json',
244
+ // The CLI throws if this is not present on environment
245
+ 'Circle-Token': process.env.CIRCLE_TOKEN
246
+ },
247
+ method: 'POST'
248
+ }, options)
249
+ };
250
+ }
251
+ };
252
+ }
253
+
95
254
  async function loadConfig() {
96
255
  const deploymentConfigExplorer = cosmiconfig.cosmiconfig('deployment', {
97
256
  searchStrategy: 'project'
@@ -411,153 +570,9 @@ async function approve(cliFlags, config, circleCiApis) {
411
570
  }
412
571
  }
413
572
 
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');
573
+ function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
574
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
575
+ commander.program.name('deployment-cli').description('CLI to help manage deployment pipelines').version(pkgJson.version).option('--dry-run', '(optional) Simulate a deployment.', false).option('--debug', '(optional) Print additional debug information.', false);
561
576
  async function run() {
562
577
  const config = await loadConfig();
563
578
  throwIfConfigurationLacksRequiredValues(config);
@@ -566,36 +581,16 @@ async function run() {
566
581
  apiBaseUrl: config.CircleCI.apiBaseUrl
567
582
  });
568
583
 
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
584
  // 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) {
585
+ commander.program.command('approve').description('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/).').option('--approval-job [string]', '(optional) 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.', 'main').option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', false).action(async options => {
586
+ const globalOptions = commander.program.opts();
587
+ if (globalOptions.dryRun) {
588
588
  console.log(`🙊 Do not worry. This is a dry run!`);
589
589
  }
590
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
591
+ await approve(_objectSpread(_objectSpread({}, globalOptions), options), config, circleCiApis);
597
592
  });
598
- await cli.runMatchedCommand();
593
+ commander.program.parse();
599
594
  }
600
595
 
601
596
  exports.run = run;
@@ -2,43 +2,56 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var cac = require('cac');
6
- var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
5
+ var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
6
+ var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
7
+ var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
8
+ var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
7
9
  var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
10
+ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
11
+ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
12
+ var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
13
+ var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
14
+ var commander = require('commander');
15
+ var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
16
+ var _URLSearchParams = require('@babel/runtime-corejs3/core-js-stable/url-search-params');
17
+ var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
18
+ var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
19
+ var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
20
+ var node_process = require('node:process');
21
+ var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
8
22
  var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
9
- var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
10
23
  var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
11
24
  var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
12
25
  var cosmiconfig = require('cosmiconfig');
13
26
  var merge = require('lodash/merge');
14
27
  var prompts = require('prompts');
15
28
  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
29
 
23
30
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
24
31
 
25
- var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
32
+ var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
33
+ var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
34
+ var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
35
+ var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
26
36
  var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
37
+ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
38
+ var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
39
+ var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
40
+ var _URLSearchParams__default = /*#__PURE__*/_interopDefault(_URLSearchParams);
41
+ var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
42
+ var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
43
+ var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
44
+ var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
27
45
  var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
28
- var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
29
46
  var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
30
47
  var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
31
48
  var merge__default = /*#__PURE__*/_interopDefault(merge);
32
49
  var prompts__default = /*#__PURE__*/_interopDefault(prompts);
33
50
  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
51
 
39
52
  var pkgJson = {
40
53
  name: "@commercetools-frontend/deployment-cli",
41
- version: "2.0.3",
54
+ version: "2.0.5",
42
55
  description: "CLI to manage Custom Applications deployments in Google Storage.",
43
56
  keywords: [
44
57
  "commercetools",
@@ -63,7 +76,7 @@ var pkgJson = {
63
76
  dependencies: {
64
77
  "@babel/core": "^7.22.11",
65
78
  "@babel/runtime-corejs3": "^7.21.0",
66
- cac: "^6.7.14",
79
+ commander: "^13.1.0",
67
80
  cosmiconfig: "9.0.0",
68
81
  lodash: "4.17.21",
69
82
  "p-retry": "4.6.2",
@@ -72,7 +85,7 @@ var pkgJson = {
72
85
  devDependencies: {
73
86
  "@tsconfig/node20": "20.1.4",
74
87
  "@types/lodash": "^4.14.198",
75
- "@types/node": "22.10.10",
88
+ "@types/node": "22.13.9",
76
89
  "@types/prompts": "2.4.9",
77
90
  msw: "1.3.5",
78
91
  typescript: "5.2.2"
@@ -92,6 +105,152 @@ var pkgJson = {
92
105
  }
93
106
  };
94
107
 
108
+ async function processCircleCiResponse(response) {
109
+ if (!response.ok) {
110
+ /**
111
+ * NOTE:
112
+ * Trying to handle known but undocumented responses of the CircleCI API.
113
+ *
114
+ * 1. Message: Already approved job
115
+ * Deployment was already triggered manually or by train the day before.
116
+ */
117
+
118
+ // Response data is a stream so text OR json can only be read once, so
119
+ // we read it as text first and then try to parse it as json to handle
120
+ // known error responses.
121
+ const error = await response.text();
122
+ try {
123
+ // The CircleCI API always uses content-type text/plain, so we always
124
+ // try parsing JSON to see if the message property is present.
125
+ const _JSON$parse = JSON.parse(error),
126
+ message = _JSON$parse.message;
127
+ if (message.match(/job already approved/i)) {
128
+ console.log('ℹ️ Deployment job is already approved.');
129
+ // TODO: can we return instead of force exiting?
130
+ node_process.exit(0);
131
+ }
132
+ } catch {
133
+ // Ignore JSON parsing errors
134
+ }
135
+ throw new Error(`${response.status}: Network response was not ok.\n
136
+ Status text is ${response.statusText} and text is ${error}.`);
137
+ }
138
+ return response.json();
139
+ }
140
+ function createCircleCiClient(_ref) {
141
+ let projectName = _ref.projectName,
142
+ apiBaseUrl = _ref.apiBaseUrl;
143
+ async function execute(api) {
144
+ let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
145
+ skip = _ref2.skip,
146
+ debug = _ref2.debug;
147
+ let url = `${apiBaseUrl}${api.url}`;
148
+ if (api.params && api.method === 'GET') {
149
+ const urlSearchParams = new _URLSearchParams__default["default"]();
150
+ for (const _ref3 of _Object$entries__default["default"](api.params)) {
151
+ var _ref4 = _slicedToArray(_ref3, 2);
152
+ const key = _ref4[0];
153
+ const value = _ref4[1];
154
+ if (value !== null && value !== undefined) {
155
+ urlSearchParams.append(key, value);
156
+ }
157
+ }
158
+ url += `?${urlSearchParams.toString()}`;
159
+ }
160
+ if (skip) {
161
+ if (debug) {
162
+ console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
163
+ }
164
+
165
+ // @ts-expect-error
166
+ return _Promise__default["default"].resolve();
167
+ }
168
+ if (debug) {
169
+ console.log(`🏭 Calling CircleCI API at: ${url}.`);
170
+ }
171
+ try {
172
+ const response = await fetch(url, {
173
+ headers: api.headers,
174
+ method: api.method,
175
+ body: api.method === 'POST' ? _JSON$stringify__default["default"](api.params) : undefined
176
+ });
177
+ const processedCircleCiResponse = await processCircleCiResponse(response);
178
+ return processedCircleCiResponse;
179
+ } catch (error) {
180
+ console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
181
+ throw error;
182
+ }
183
+ }
184
+ return {
185
+ pipelines: function () {
186
+ let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
187
+ pageToken = _ref5.pageToken,
188
+ _ref5$projectSlug = _ref5.projectSlug,
189
+ projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
190
+ _ref5$branch = _ref5.branch,
191
+ branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
192
+ return {
193
+ execute: options => execute({
194
+ url: `/project/${projectSlug}/pipeline`,
195
+ headers: {
196
+ 'Content-Type': 'application/json',
197
+ // The CLI throws if this is not present on environment
198
+ 'Circle-Token': process.env.CIRCLE_TOKEN
199
+ },
200
+ method: 'GET',
201
+ params: {
202
+ branch,
203
+ 'page-token': pageToken
204
+ }
205
+ }, options)
206
+ };
207
+ },
208
+ workflows: _ref6 => {
209
+ let pipelineId = _ref6.pipelineId;
210
+ return {
211
+ execute: options => execute({
212
+ url: `/pipeline/${pipelineId}/workflow`,
213
+ headers: {
214
+ 'Content-Type': 'application/json',
215
+ // The CLI throws if this is not present on environment
216
+ 'Circle-Token': process.env.CIRCLE_TOKEN
217
+ },
218
+ method: 'GET'
219
+ }, options)
220
+ };
221
+ },
222
+ jobs: _ref7 => {
223
+ let workflowId = _ref7.workflowId;
224
+ return {
225
+ execute: options => execute({
226
+ url: `/workflow/${workflowId}/job`,
227
+ headers: {
228
+ 'Content-Type': 'application/json',
229
+ // The CLI throws if this is not present on environment
230
+ 'Circle-Token': process.env.CIRCLE_TOKEN
231
+ },
232
+ method: 'GET'
233
+ }, options)
234
+ };
235
+ },
236
+ approve: _ref8 => {
237
+ let workflowId = _ref8.workflowId,
238
+ approvalRequestId = _ref8.approvalRequestId;
239
+ return {
240
+ execute: options => execute({
241
+ url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
242
+ headers: {
243
+ 'Content-Type': 'application/json',
244
+ // The CLI throws if this is not present on environment
245
+ 'Circle-Token': process.env.CIRCLE_TOKEN
246
+ },
247
+ method: 'POST'
248
+ }, options)
249
+ };
250
+ }
251
+ };
252
+ }
253
+
95
254
  async function loadConfig() {
96
255
  const deploymentConfigExplorer = cosmiconfig.cosmiconfig('deployment', {
97
256
  searchStrategy: 'project'
@@ -411,153 +570,9 @@ async function approve(cliFlags, config, circleCiApis) {
411
570
  }
412
571
  }
413
572
 
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');
573
+ function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
574
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
575
+ commander.program.name('deployment-cli').description('CLI to help manage deployment pipelines').version(pkgJson.version).option('--dry-run', '(optional) Simulate a deployment.', false).option('--debug', '(optional) Print additional debug information.', false);
561
576
  async function run() {
562
577
  const config = await loadConfig();
563
578
  throwIfConfigurationLacksRequiredValues(config);
@@ -566,36 +581,16 @@ async function run() {
566
581
  apiBaseUrl: config.CircleCI.apiBaseUrl
567
582
  });
568
583
 
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
584
  // 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) {
585
+ commander.program.command('approve').description('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/).').option('--approval-job [string]', '(optional) 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.', 'main').option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', false).action(async options => {
586
+ const globalOptions = commander.program.opts();
587
+ if (globalOptions.dryRun) {
588
588
  console.log(`🙊 Do not worry. This is a dry run!`);
589
589
  }
590
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
591
+ await approve(_objectSpread(_objectSpread({}, globalOptions), options), config, circleCiApis);
597
592
  });
598
- await cli.runMatchedCommand();
593
+ commander.program.parse();
599
594
  }
600
595
 
601
596
  exports.run = run;
@@ -1,24 +1,31 @@
1
- import { cac } from 'cac';
2
- import _findInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/find';
1
+ import _Object$keys from '@babel/runtime-corejs3/core-js-stable/object/keys';
2
+ import _Object$getOwnPropertySymbols from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols';
3
+ import _filterInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/filter';
4
+ import _Object$getOwnPropertyDescriptor from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor';
3
5
  import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each';
6
+ import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors';
7
+ import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties';
8
+ import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
9
+ import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty';
10
+ import { program } from 'commander';
11
+ import _slicedToArray from '@babel/runtime-corejs3/helpers/esm/slicedToArray';
12
+ import _URLSearchParams from '@babel/runtime-corejs3/core-js-stable/url-search-params';
13
+ import _Object$entries from '@babel/runtime-corejs3/core-js-stable/object/entries';
14
+ import _Promise from '@babel/runtime-corejs3/core-js-stable/promise';
15
+ import _JSON$stringify from '@babel/runtime-corejs3/core-js-stable/json/stringify';
16
+ import { exit } from 'node:process';
17
+ import _findInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/find';
4
18
  import _mapInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/map';
5
- import _filterInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/filter';
6
19
  import _startsWithInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/starts-with';
7
20
  import _concatInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/concat';
8
21
  import { cosmiconfig } from 'cosmiconfig';
9
22
  import merge from 'lodash/merge';
10
23
  import prompts from 'prompts';
11
24
  import pRetry from 'p-retry';
12
- import _slicedToArray from '@babel/runtime-corejs3/helpers/esm/slicedToArray';
13
- import _URLSearchParams from '@babel/runtime-corejs3/core-js-stable/url-search-params';
14
- import _Object$entries from '@babel/runtime-corejs3/core-js-stable/object/entries';
15
- import _Promise from '@babel/runtime-corejs3/core-js-stable/promise';
16
- import _JSON$stringify from '@babel/runtime-corejs3/core-js-stable/json/stringify';
17
- import { exit } from 'node:process';
18
25
 
19
26
  var pkgJson = {
20
27
  name: "@commercetools-frontend/deployment-cli",
21
- version: "2.0.3",
28
+ version: "2.0.5",
22
29
  description: "CLI to manage Custom Applications deployments in Google Storage.",
23
30
  keywords: [
24
31
  "commercetools",
@@ -43,7 +50,7 @@ var pkgJson = {
43
50
  dependencies: {
44
51
  "@babel/core": "^7.22.11",
45
52
  "@babel/runtime-corejs3": "^7.21.0",
46
- cac: "^6.7.14",
53
+ commander: "^13.1.0",
47
54
  cosmiconfig: "9.0.0",
48
55
  lodash: "4.17.21",
49
56
  "p-retry": "4.6.2",
@@ -52,7 +59,7 @@ var pkgJson = {
52
59
  devDependencies: {
53
60
  "@tsconfig/node20": "20.1.4",
54
61
  "@types/lodash": "^4.14.198",
55
- "@types/node": "22.10.10",
62
+ "@types/node": "22.13.9",
56
63
  "@types/prompts": "2.4.9",
57
64
  msw: "1.3.5",
58
65
  typescript: "5.2.2"
@@ -72,6 +79,152 @@ var pkgJson = {
72
79
  }
73
80
  };
74
81
 
82
+ async function processCircleCiResponse(response) {
83
+ if (!response.ok) {
84
+ /**
85
+ * NOTE:
86
+ * Trying to handle known but undocumented responses of the CircleCI API.
87
+ *
88
+ * 1. Message: Already approved job
89
+ * Deployment was already triggered manually or by train the day before.
90
+ */
91
+
92
+ // Response data is a stream so text OR json can only be read once, so
93
+ // we read it as text first and then try to parse it as json to handle
94
+ // known error responses.
95
+ const error = await response.text();
96
+ try {
97
+ // The CircleCI API always uses content-type text/plain, so we always
98
+ // try parsing JSON to see if the message property is present.
99
+ const _JSON$parse = JSON.parse(error),
100
+ message = _JSON$parse.message;
101
+ if (message.match(/job already approved/i)) {
102
+ console.log('ℹ️ Deployment job is already approved.');
103
+ // TODO: can we return instead of force exiting?
104
+ exit(0);
105
+ }
106
+ } catch {
107
+ // Ignore JSON parsing errors
108
+ }
109
+ throw new Error(`${response.status}: Network response was not ok.\n
110
+ Status text is ${response.statusText} and text is ${error}.`);
111
+ }
112
+ return response.json();
113
+ }
114
+ function createCircleCiClient(_ref) {
115
+ let projectName = _ref.projectName,
116
+ apiBaseUrl = _ref.apiBaseUrl;
117
+ async function execute(api) {
118
+ let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
119
+ skip = _ref2.skip,
120
+ debug = _ref2.debug;
121
+ let url = `${apiBaseUrl}${api.url}`;
122
+ if (api.params && api.method === 'GET') {
123
+ const urlSearchParams = new _URLSearchParams();
124
+ for (const _ref3 of _Object$entries(api.params)) {
125
+ var _ref4 = _slicedToArray(_ref3, 2);
126
+ const key = _ref4[0];
127
+ const value = _ref4[1];
128
+ if (value !== null && value !== undefined) {
129
+ urlSearchParams.append(key, value);
130
+ }
131
+ }
132
+ url += `?${urlSearchParams.toString()}`;
133
+ }
134
+ if (skip) {
135
+ if (debug) {
136
+ console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
137
+ }
138
+
139
+ // @ts-expect-error
140
+ return _Promise.resolve();
141
+ }
142
+ if (debug) {
143
+ console.log(`🏭 Calling CircleCI API at: ${url}.`);
144
+ }
145
+ try {
146
+ const response = await fetch(url, {
147
+ headers: api.headers,
148
+ method: api.method,
149
+ body: api.method === 'POST' ? _JSON$stringify(api.params) : undefined
150
+ });
151
+ const processedCircleCiResponse = await processCircleCiResponse(response);
152
+ return processedCircleCiResponse;
153
+ } catch (error) {
154
+ console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
155
+ throw error;
156
+ }
157
+ }
158
+ return {
159
+ pipelines: function () {
160
+ let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
161
+ pageToken = _ref5.pageToken,
162
+ _ref5$projectSlug = _ref5.projectSlug,
163
+ projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
164
+ _ref5$branch = _ref5.branch,
165
+ branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
166
+ return {
167
+ execute: options => execute({
168
+ url: `/project/${projectSlug}/pipeline`,
169
+ headers: {
170
+ 'Content-Type': 'application/json',
171
+ // The CLI throws if this is not present on environment
172
+ 'Circle-Token': process.env.CIRCLE_TOKEN
173
+ },
174
+ method: 'GET',
175
+ params: {
176
+ branch,
177
+ 'page-token': pageToken
178
+ }
179
+ }, options)
180
+ };
181
+ },
182
+ workflows: _ref6 => {
183
+ let pipelineId = _ref6.pipelineId;
184
+ return {
185
+ execute: options => execute({
186
+ url: `/pipeline/${pipelineId}/workflow`,
187
+ headers: {
188
+ 'Content-Type': 'application/json',
189
+ // The CLI throws if this is not present on environment
190
+ 'Circle-Token': process.env.CIRCLE_TOKEN
191
+ },
192
+ method: 'GET'
193
+ }, options)
194
+ };
195
+ },
196
+ jobs: _ref7 => {
197
+ let workflowId = _ref7.workflowId;
198
+ return {
199
+ execute: options => execute({
200
+ url: `/workflow/${workflowId}/job`,
201
+ headers: {
202
+ 'Content-Type': 'application/json',
203
+ // The CLI throws if this is not present on environment
204
+ 'Circle-Token': process.env.CIRCLE_TOKEN
205
+ },
206
+ method: 'GET'
207
+ }, options)
208
+ };
209
+ },
210
+ approve: _ref8 => {
211
+ let workflowId = _ref8.workflowId,
212
+ approvalRequestId = _ref8.approvalRequestId;
213
+ return {
214
+ execute: options => execute({
215
+ url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
216
+ headers: {
217
+ 'Content-Type': 'application/json',
218
+ // The CLI throws if this is not present on environment
219
+ 'Circle-Token': process.env.CIRCLE_TOKEN
220
+ },
221
+ method: 'POST'
222
+ }, options)
223
+ };
224
+ }
225
+ };
226
+ }
227
+
75
228
  async function loadConfig() {
76
229
  const deploymentConfigExplorer = cosmiconfig('deployment', {
77
230
  searchStrategy: 'project'
@@ -391,153 +544,9 @@ async function approve(cliFlags, config, circleCiApis) {
391
544
  }
392
545
  }
393
546
 
394
- async function processCircleCiResponse(response) {
395
- if (!response.ok) {
396
- /**
397
- * NOTE:
398
- * Trying to handle known but undocumented responses of the CircleCI API.
399
- *
400
- * 1. Message: Already approved job
401
- * Deployment was already triggered manually or by train the day before.
402
- */
403
-
404
- // Response data is a stream so text OR json can only be read once, so
405
- // we read it as text first and then try to parse it as json to handle
406
- // known error responses.
407
- const error = await response.text();
408
- try {
409
- // The CircleCI API always uses content-type text/plain, so we always
410
- // try parsing JSON to see if the message property is present.
411
- const _JSON$parse = JSON.parse(error),
412
- message = _JSON$parse.message;
413
- if (message.match(/job already approved/i)) {
414
- console.log('ℹ️ Deployment job is already approved.');
415
- // TODO: can we return instead of force exiting?
416
- exit(0);
417
- }
418
- } catch {
419
- // Ignore JSON parsing errors
420
- }
421
- throw new Error(`${response.status}: Network response was not ok.\n
422
- Status text is ${response.statusText} and text is ${error}.`);
423
- }
424
- return response.json();
425
- }
426
- function createCircleCiClient(_ref) {
427
- let projectName = _ref.projectName,
428
- apiBaseUrl = _ref.apiBaseUrl;
429
- async function execute(api) {
430
- let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
431
- skip = _ref2.skip,
432
- debug = _ref2.debug;
433
- let url = `${apiBaseUrl}${api.url}`;
434
- if (api.params && api.method === 'GET') {
435
- const urlSearchParams = new _URLSearchParams();
436
- for (const _ref3 of _Object$entries(api.params)) {
437
- var _ref4 = _slicedToArray(_ref3, 2);
438
- const key = _ref4[0];
439
- const value = _ref4[1];
440
- if (value !== null && value !== undefined) {
441
- urlSearchParams.append(key, value);
442
- }
443
- }
444
- url += `?${urlSearchParams.toString()}`;
445
- }
446
- if (skip) {
447
- if (debug) {
448
- console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
449
- }
450
-
451
- // @ts-expect-error
452
- return _Promise.resolve();
453
- }
454
- if (debug) {
455
- console.log(`🏭 Calling CircleCI API at: ${url}.`);
456
- }
457
- try {
458
- const response = await fetch(url, {
459
- headers: api.headers,
460
- method: api.method,
461
- body: api.method === 'POST' ? _JSON$stringify(api.params) : undefined
462
- });
463
- const processedCircleCiResponse = await processCircleCiResponse(response);
464
- return processedCircleCiResponse;
465
- } catch (error) {
466
- console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
467
- throw error;
468
- }
469
- }
470
- return {
471
- pipelines: function () {
472
- let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
473
- pageToken = _ref5.pageToken,
474
- _ref5$projectSlug = _ref5.projectSlug,
475
- projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
476
- _ref5$branch = _ref5.branch,
477
- branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
478
- return {
479
- execute: options => execute({
480
- url: `/project/${projectSlug}/pipeline`,
481
- headers: {
482
- 'Content-Type': 'application/json',
483
- // The CLI throws if this is not present on environment
484
- 'Circle-Token': process.env.CIRCLE_TOKEN
485
- },
486
- method: 'GET',
487
- params: {
488
- branch,
489
- 'page-token': pageToken
490
- }
491
- }, options)
492
- };
493
- },
494
- workflows: _ref6 => {
495
- let pipelineId = _ref6.pipelineId;
496
- return {
497
- execute: options => execute({
498
- url: `/pipeline/${pipelineId}/workflow`,
499
- headers: {
500
- 'Content-Type': 'application/json',
501
- // The CLI throws if this is not present on environment
502
- 'Circle-Token': process.env.CIRCLE_TOKEN
503
- },
504
- method: 'GET'
505
- }, options)
506
- };
507
- },
508
- jobs: _ref7 => {
509
- let workflowId = _ref7.workflowId;
510
- return {
511
- execute: options => execute({
512
- url: `/workflow/${workflowId}/job`,
513
- headers: {
514
- 'Content-Type': 'application/json',
515
- // The CLI throws if this is not present on environment
516
- 'Circle-Token': process.env.CIRCLE_TOKEN
517
- },
518
- method: 'GET'
519
- }, options)
520
- };
521
- },
522
- approve: _ref8 => {
523
- let workflowId = _ref8.workflowId,
524
- approvalRequestId = _ref8.approvalRequestId;
525
- return {
526
- execute: options => execute({
527
- url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
528
- headers: {
529
- 'Content-Type': 'application/json',
530
- // The CLI throws if this is not present on environment
531
- 'Circle-Token': process.env.CIRCLE_TOKEN
532
- },
533
- method: 'POST'
534
- }, options)
535
- };
536
- }
537
- };
538
- }
539
-
540
- const cli = cac('deployment-cli');
547
+ function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
548
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
549
+ program.name('deployment-cli').description('CLI to help manage deployment pipelines').version(pkgJson.version).option('--dry-run', '(optional) Simulate a deployment.', false).option('--debug', '(optional) Print additional debug information.', false);
541
550
  async function run() {
542
551
  const config = await loadConfig();
543
552
  throwIfConfigurationLacksRequiredValues(config);
@@ -546,36 +555,16 @@ async function run() {
546
555
  apiBaseUrl: config.CircleCI.apiBaseUrl
547
556
  });
548
557
 
549
- // General CLI options
550
- cli.option('--dry-run', '(optional) Simulate a deployment.', {
551
- default: false
552
- });
553
- cli.option('--debug', '(optional) Print additional debug information.', {
554
- default: false
555
- });
556
-
557
- // Default command
558
- cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
559
-
560
558
  // Command: Approve
561
- 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/).';
562
- 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.', {
563
- default: 'main'
564
- }).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
565
- default: false
566
- }).action(async options => {
567
- if (options.dryRun) {
559
+ program.command('approve').description('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/).').option('--approval-job [string]', '(optional) 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.', 'main').option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', false).action(async options => {
560
+ const globalOptions = program.opts();
561
+ if (globalOptions.dryRun) {
568
562
  console.log(`🙊 Do not worry. This is a dry run!`);
569
563
  }
570
564
  throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
571
- await approve(options, config, circleCiApis);
572
- });
573
- cli.help();
574
- cli.version(pkgJson.version);
575
- cli.parse(process.argv, {
576
- run: false
565
+ await approve(_objectSpread(_objectSpread({}, globalOptions), options), config, circleCiApis);
577
566
  });
578
- await cli.runMatchedCommand();
567
+ program.parse();
579
568
  }
580
569
 
581
570
  export { run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercetools-frontend/deployment-cli",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "CLI to manage Custom Applications deployments in Google Storage.",
5
5
  "keywords": [
6
6
  "commercetools",
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "@babel/core": "^7.22.11",
24
24
  "@babel/runtime-corejs3": "^7.21.0",
25
- "cac": "^6.7.14",
25
+ "commander": "^13.1.0",
26
26
  "cosmiconfig": "9.0.0",
27
27
  "lodash": "4.17.21",
28
28
  "p-retry": "4.6.2",
@@ -31,7 +31,7 @@
31
31
  "devDependencies": {
32
32
  "@tsconfig/node20": "20.1.4",
33
33
  "@types/lodash": "^4.14.198",
34
- "@types/node": "22.10.10",
34
+ "@types/node": "22.13.9",
35
35
  "@types/prompts": "2.4.9",
36
36
  "msw": "1.3.5",
37
37
  "typescript": "5.2.2"