@commercetools-frontend/deployment-cli 0.1.0 → 0.2.1

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.
@@ -2,8 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var _sliceInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/slice');
6
- var mri = require('mri');
5
+ var cac = require('cac');
7
6
  var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
8
7
  var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
9
8
  var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
@@ -15,6 +14,7 @@ var merge = require('lodash/merge');
15
14
  var prompts = require('prompts');
16
15
  var pRetry = require('p-retry');
17
16
  var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
17
+ var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
18
18
  var _URLSearchParams = require('@babel/runtime-corejs3/core-js-stable/url-search-params');
19
19
  var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
20
20
  var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
@@ -23,8 +23,6 @@ var fetch = require('node-fetch');
23
23
 
24
24
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
25
25
 
26
- var _sliceInstanceProperty__default = /*#__PURE__*/_interopDefault(_sliceInstanceProperty);
27
- var mri__default = /*#__PURE__*/_interopDefault(mri);
28
26
  var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
29
27
  var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
30
28
  var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
@@ -34,12 +32,71 @@ var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsW
34
32
  var merge__default = /*#__PURE__*/_interopDefault(merge);
35
33
  var prompts__default = /*#__PURE__*/_interopDefault(prompts);
36
34
  var pRetry__default = /*#__PURE__*/_interopDefault(pRetry);
35
+ var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
37
36
  var _URLSearchParams__default = /*#__PURE__*/_interopDefault(_URLSearchParams);
38
37
  var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
39
38
  var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
40
39
  var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
41
40
  var fetch__default = /*#__PURE__*/_interopDefault(fetch);
42
41
 
42
+ var pkgJson = {
43
+ name: "@commercetools-frontend/deployment-cli",
44
+ version: "0.2.1",
45
+ description: "CLI to manage Custom Applications deployments in Google Storage.",
46
+ keywords: [
47
+ "commercetools",
48
+ "cli",
49
+ "deployment"
50
+ ],
51
+ license: "MIT",
52
+ main: "dist/commercetools-frontend-deployment-cli.cjs.js",
53
+ module: "dist/commercetools-frontend-deployment-cli.esm.js",
54
+ bin: "bin/cli.js",
55
+ files: [
56
+ "cli",
57
+ "dist",
58
+ "package.json",
59
+ "LICENSE",
60
+ "README.md"
61
+ ],
62
+ scripts: {
63
+ typecheck: "tsc --noEmit"
64
+ },
65
+ dependencies: {
66
+ "@babel/core": "^7.21.3",
67
+ "@babel/runtime": "^7.21.0",
68
+ "@babel/runtime-corejs3": "^7.21.0",
69
+ cac: "^6.7.14",
70
+ cosmiconfig: "8.2.0",
71
+ lodash: "4.17.21",
72
+ "node-fetch": "2.6.11",
73
+ "p-retry": "4.6.2",
74
+ prompts: "2.4.2"
75
+ },
76
+ devDependencies: {
77
+ "@tsconfig/node18": "1.0.3",
78
+ "@types/lodash": "^4.14.191",
79
+ "@types/node": "20.4.0",
80
+ "@types/node-fetch": "2.6.2",
81
+ "@types/prompts": "2.4.4",
82
+ msw: "1.2.2",
83
+ typescript: "4.9.5"
84
+ },
85
+ engines: {
86
+ node: ">=14",
87
+ npm: ">=6"
88
+ },
89
+ publishConfig: {
90
+ access: "public"
91
+ },
92
+ preconstruct: {
93
+ entrypoints: [
94
+ "./cli.ts",
95
+ "./index.ts"
96
+ ]
97
+ }
98
+ };
99
+
43
100
  async function loadConfig() {
44
101
  const deploymentConfigExplorer = cosmiconfig.cosmiconfig('deployment');
45
102
  const defaultConfig = {
@@ -369,7 +426,7 @@ async function approve(cliFlags, config, circleCiApis) {
369
426
 
370
427
  async function processCircleCiResponse(response) {
371
428
  if (!response.ok) {
372
- var _context, _context2;
429
+ var _response$headers$get, _context, _context2;
373
430
  /**
374
431
  * NOTE:
375
432
  * Trying to handle known but undocumented responses of the CircleCI API.
@@ -377,17 +434,20 @@ async function processCircleCiResponse(response) {
377
434
  * 1. Message: Already approved job
378
435
  * Deployment was already triggered manually or by train the day before.
379
436
  */
380
- try {
381
- const errorJson = await response.json();
382
- if (errorJson.message.match(/job already approved/i)) {
437
+
438
+ // Response data is a stream so text OR json can only be read once, so
439
+ // we read it as text first and then try to parse it as json to handle
440
+ // known error responses.
441
+ const error = await response.text();
442
+ if ((_response$headers$get = response.headers.get('content-type')) !== null && _response$headers$get !== void 0 && _includesInstanceProperty__default["default"](_response$headers$get).call(_response$headers$get, 'application/json')) {
443
+ const _JSON$parse = JSON.parse(error),
444
+ message = _JSON$parse.message;
445
+ if (message.match(/job already approved/i)) {
383
446
  console.log('ℹ️ Deployment job is already approved.');
384
447
  process.exit(0);
385
448
  }
386
- } catch (e) {
387
- // ignore
388
449
  }
389
- const errorText = await response.text();
390
- throw new Error(_concatInstanceProperty__default["default"](_context = _concatInstanceProperty__default["default"](_context2 = "".concat(response.status, ": Network response was not ok.\n\n Status text is ")).call(_context2, response.statusText, " and text is ")).call(_context, errorText, "."));
450
+ throw new Error(_concatInstanceProperty__default["default"](_context = _concatInstanceProperty__default["default"](_context2 = "".concat(response.status, ": Network response was not ok.\n\n Status text is ")).call(_context2, response.statusText, " and text is ")).call(_context, error, "."));
391
451
  }
392
452
  return response.json();
393
453
  }
@@ -509,6 +569,7 @@ function createCircleCiClient(_ref) {
509
569
  };
510
570
  }
511
571
 
572
+ const cli = cac.cac('deployment-cli');
512
573
  async function run() {
513
574
  const config = await loadConfig();
514
575
  throwIfConfigurationLacksRequiredValues(config);
@@ -516,53 +577,37 @@ async function run() {
516
577
  projectName: config.CircleCI.projectName,
517
578
  apiBaseUrl: config.CircleCI.apiBaseUrl
518
579
  });
519
- try {
520
- var _context;
521
- const cliFlags = mri__default["default"](_sliceInstanceProperty__default["default"](_context = process.argv).call(_context, 2), {
522
- alias: {
523
- help: ['h']
524
- },
525
- boolean: ['dry-run', 'debug', 'yes'],
526
- default: {
527
- branch: 'main'
528
- }
529
- });
530
- const cliCommands = cliFlags._;
531
- if (cliCommands.length === 0 ||
532
- // @ts-expect-error mri is not typed for the help command.
533
- cliCommands.help && cliCommands.length === 0) {
534
- console.log("\nUsage: deployment-cli [command] [flags]\n\nDisplays help information.\n\nCommand:\n approve 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/).\n\nOptions:\n --approval-job The name of the approval job to approve a deployment with.\n --deployment-job (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.\n --deployment (optional) The name of a deployment configured in the configuration file.\n --build-revision <git-sha> (optional) The git commit SHA that needs to be deployed. If not specified, the last successful pipeline is used.\n --branch (optional) The git branch to deploy from. If not specified, defaults to 'main'.\n --yes (optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.\n\nGeneral options:\n --dry-run (optional) Simulate a deployment.\n --debug (optional) Print additional debug information.\n");
535
- process.exit(0);
536
- }
537
- const cliCommand = cliCommands[0];
538
- if (cliFlags['dry-run']) {
539
- console.log("\n \uD83D\uDE4A Do not worry. This is a dry run!\n ");
540
- }
541
- console.log("\uD83C\uDFC3 Running ".concat(cliCommand, " command"));
542
- switch (cliCommand) {
543
- case 'approve':
544
- {
545
- throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
546
- await approve({
547
- deployment: cliFlags.deployment,
548
- branch: cliFlags.branch,
549
- approvalJob: cliFlags['approval-job'],
550
- deploymentJob: cliFlags['deployment-job'],
551
- buildRevision: cliFlags['build-revision'],
552
- yes: cliFlags.yes,
553
- debug: cliFlags.debug,
554
- dryRun: cliFlags['dry-run']
555
- }, config, circleCiApis);
556
- process.exit(0);
557
- }
558
- // eslint-disable-next-line no-fallthrough
559
- default:
560
- throw new Error("\uD83D\uDC80 Unknown command \"".concat(cliCommand, "\"."));
580
+
581
+ // General CLI options
582
+ cli.option('--dry-run', '(optional) Simulate a deployment.', {
583
+ default: false
584
+ });
585
+ cli.option('--debug', '(optional) Print additional debug information.', {
586
+ default: false
587
+ });
588
+
589
+ // Default command
590
+ cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
591
+
592
+ // Command: Approve
593
+ 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/).';
594
+ cli.command('approve', usageApprove).usage("approve \n\n ".concat(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.', {
595
+ default: 'main'
596
+ }).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
597
+ default: false
598
+ }).action(async options => {
599
+ if (options.dryRun) {
600
+ console.log("\uD83D\uDE4A Do not worry. This is a dry run!");
561
601
  }
562
- } catch (error) {
563
- console.error(error);
564
- process.exit(1);
565
- }
602
+ throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
603
+ await approve(options, config, circleCiApis);
604
+ });
605
+ cli.help();
606
+ cli.version(pkgJson.version);
607
+ cli.parse(process.argv, {
608
+ run: false
609
+ });
610
+ await cli.runMatchedCommand();
566
611
  }
567
612
 
568
613
  exports.run = run;
@@ -2,8 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var _sliceInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/slice');
6
- var mri = require('mri');
5
+ var cac = require('cac');
7
6
  var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
8
7
  var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
9
8
  var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
@@ -15,6 +14,7 @@ var merge = require('lodash/merge');
15
14
  var prompts = require('prompts');
16
15
  var pRetry = require('p-retry');
17
16
  var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
17
+ var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
18
18
  var _URLSearchParams = require('@babel/runtime-corejs3/core-js-stable/url-search-params');
19
19
  var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
20
20
  var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
@@ -23,8 +23,6 @@ var fetch = require('node-fetch');
23
23
 
24
24
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
25
25
 
26
- var _sliceInstanceProperty__default = /*#__PURE__*/_interopDefault(_sliceInstanceProperty);
27
- var mri__default = /*#__PURE__*/_interopDefault(mri);
28
26
  var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
29
27
  var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
30
28
  var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
@@ -34,12 +32,71 @@ var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsW
34
32
  var merge__default = /*#__PURE__*/_interopDefault(merge);
35
33
  var prompts__default = /*#__PURE__*/_interopDefault(prompts);
36
34
  var pRetry__default = /*#__PURE__*/_interopDefault(pRetry);
35
+ var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
37
36
  var _URLSearchParams__default = /*#__PURE__*/_interopDefault(_URLSearchParams);
38
37
  var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
39
38
  var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
40
39
  var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
41
40
  var fetch__default = /*#__PURE__*/_interopDefault(fetch);
42
41
 
42
+ var pkgJson = {
43
+ name: "@commercetools-frontend/deployment-cli",
44
+ version: "0.2.1",
45
+ description: "CLI to manage Custom Applications deployments in Google Storage.",
46
+ keywords: [
47
+ "commercetools",
48
+ "cli",
49
+ "deployment"
50
+ ],
51
+ license: "MIT",
52
+ main: "dist/commercetools-frontend-deployment-cli.cjs.js",
53
+ module: "dist/commercetools-frontend-deployment-cli.esm.js",
54
+ bin: "bin/cli.js",
55
+ files: [
56
+ "cli",
57
+ "dist",
58
+ "package.json",
59
+ "LICENSE",
60
+ "README.md"
61
+ ],
62
+ scripts: {
63
+ typecheck: "tsc --noEmit"
64
+ },
65
+ dependencies: {
66
+ "@babel/core": "^7.21.3",
67
+ "@babel/runtime": "^7.21.0",
68
+ "@babel/runtime-corejs3": "^7.21.0",
69
+ cac: "^6.7.14",
70
+ cosmiconfig: "8.2.0",
71
+ lodash: "4.17.21",
72
+ "node-fetch": "2.6.11",
73
+ "p-retry": "4.6.2",
74
+ prompts: "2.4.2"
75
+ },
76
+ devDependencies: {
77
+ "@tsconfig/node18": "1.0.3",
78
+ "@types/lodash": "^4.14.191",
79
+ "@types/node": "20.4.0",
80
+ "@types/node-fetch": "2.6.2",
81
+ "@types/prompts": "2.4.4",
82
+ msw: "1.2.2",
83
+ typescript: "4.9.5"
84
+ },
85
+ engines: {
86
+ node: ">=14",
87
+ npm: ">=6"
88
+ },
89
+ publishConfig: {
90
+ access: "public"
91
+ },
92
+ preconstruct: {
93
+ entrypoints: [
94
+ "./cli.ts",
95
+ "./index.ts"
96
+ ]
97
+ }
98
+ };
99
+
43
100
  async function loadConfig() {
44
101
  const deploymentConfigExplorer = cosmiconfig.cosmiconfig('deployment');
45
102
  const defaultConfig = {
@@ -369,7 +426,7 @@ async function approve(cliFlags, config, circleCiApis) {
369
426
 
370
427
  async function processCircleCiResponse(response) {
371
428
  if (!response.ok) {
372
- var _context, _context2;
429
+ var _response$headers$get, _context, _context2;
373
430
  /**
374
431
  * NOTE:
375
432
  * Trying to handle known but undocumented responses of the CircleCI API.
@@ -377,17 +434,20 @@ async function processCircleCiResponse(response) {
377
434
  * 1. Message: Already approved job
378
435
  * Deployment was already triggered manually or by train the day before.
379
436
  */
380
- try {
381
- const errorJson = await response.json();
382
- if (errorJson.message.match(/job already approved/i)) {
437
+
438
+ // Response data is a stream so text OR json can only be read once, so
439
+ // we read it as text first and then try to parse it as json to handle
440
+ // known error responses.
441
+ const error = await response.text();
442
+ if ((_response$headers$get = response.headers.get('content-type')) !== null && _response$headers$get !== void 0 && _includesInstanceProperty__default["default"](_response$headers$get).call(_response$headers$get, 'application/json')) {
443
+ const _JSON$parse = JSON.parse(error),
444
+ message = _JSON$parse.message;
445
+ if (message.match(/job already approved/i)) {
383
446
  console.log('ℹ️ Deployment job is already approved.');
384
447
  process.exit(0);
385
448
  }
386
- } catch (e) {
387
- // ignore
388
449
  }
389
- const errorText = await response.text();
390
- throw new Error(_concatInstanceProperty__default["default"](_context = _concatInstanceProperty__default["default"](_context2 = "".concat(response.status, ": Network response was not ok.\n\n Status text is ")).call(_context2, response.statusText, " and text is ")).call(_context, errorText, "."));
450
+ throw new Error(_concatInstanceProperty__default["default"](_context = _concatInstanceProperty__default["default"](_context2 = "".concat(response.status, ": Network response was not ok.\n\n Status text is ")).call(_context2, response.statusText, " and text is ")).call(_context, error, "."));
391
451
  }
392
452
  return response.json();
393
453
  }
@@ -509,6 +569,7 @@ function createCircleCiClient(_ref) {
509
569
  };
510
570
  }
511
571
 
572
+ const cli = cac.cac('deployment-cli');
512
573
  async function run() {
513
574
  const config = await loadConfig();
514
575
  throwIfConfigurationLacksRequiredValues(config);
@@ -516,53 +577,37 @@ async function run() {
516
577
  projectName: config.CircleCI.projectName,
517
578
  apiBaseUrl: config.CircleCI.apiBaseUrl
518
579
  });
519
- try {
520
- var _context;
521
- const cliFlags = mri__default["default"](_sliceInstanceProperty__default["default"](_context = process.argv).call(_context, 2), {
522
- alias: {
523
- help: ['h']
524
- },
525
- boolean: ['dry-run', 'debug', 'yes'],
526
- default: {
527
- branch: 'main'
528
- }
529
- });
530
- const cliCommands = cliFlags._;
531
- if (cliCommands.length === 0 ||
532
- // @ts-expect-error mri is not typed for the help command.
533
- cliCommands.help && cliCommands.length === 0) {
534
- console.log("\nUsage: deployment-cli [command] [flags]\n\nDisplays help information.\n\nCommand:\n approve 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/).\n\nOptions:\n --approval-job The name of the approval job to approve a deployment with.\n --deployment-job (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.\n --deployment (optional) The name of a deployment configured in the configuration file.\n --build-revision <git-sha> (optional) The git commit SHA that needs to be deployed. If not specified, the last successful pipeline is used.\n --branch (optional) The git branch to deploy from. If not specified, defaults to 'main'.\n --yes (optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.\n\nGeneral options:\n --dry-run (optional) Simulate a deployment.\n --debug (optional) Print additional debug information.\n");
535
- process.exit(0);
536
- }
537
- const cliCommand = cliCommands[0];
538
- if (cliFlags['dry-run']) {
539
- console.log("\n \uD83D\uDE4A Do not worry. This is a dry run!\n ");
540
- }
541
- console.log("\uD83C\uDFC3 Running ".concat(cliCommand, " command"));
542
- switch (cliCommand) {
543
- case 'approve':
544
- {
545
- throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
546
- await approve({
547
- deployment: cliFlags.deployment,
548
- branch: cliFlags.branch,
549
- approvalJob: cliFlags['approval-job'],
550
- deploymentJob: cliFlags['deployment-job'],
551
- buildRevision: cliFlags['build-revision'],
552
- yes: cliFlags.yes,
553
- debug: cliFlags.debug,
554
- dryRun: cliFlags['dry-run']
555
- }, config, circleCiApis);
556
- process.exit(0);
557
- }
558
- // eslint-disable-next-line no-fallthrough
559
- default:
560
- throw new Error("\uD83D\uDC80 Unknown command \"".concat(cliCommand, "\"."));
580
+
581
+ // General CLI options
582
+ cli.option('--dry-run', '(optional) Simulate a deployment.', {
583
+ default: false
584
+ });
585
+ cli.option('--debug', '(optional) Print additional debug information.', {
586
+ default: false
587
+ });
588
+
589
+ // Default command
590
+ cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
591
+
592
+ // Command: Approve
593
+ 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/).';
594
+ cli.command('approve', usageApprove).usage("approve \n\n ".concat(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.', {
595
+ default: 'main'
596
+ }).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
597
+ default: false
598
+ }).action(async options => {
599
+ if (options.dryRun) {
600
+ console.log("\uD83D\uDE4A Do not worry. This is a dry run!");
561
601
  }
562
- } catch (error) {
563
- console.error(error);
564
- process.exit(1);
565
- }
602
+ throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
603
+ await approve(options, config, circleCiApis);
604
+ });
605
+ cli.help();
606
+ cli.version(pkgJson.version);
607
+ cli.parse(process.argv, {
608
+ run: false
609
+ });
610
+ await cli.runMatchedCommand();
566
611
  }
567
612
 
568
613
  exports.run = run;
@@ -1,5 +1,4 @@
1
- import _sliceInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/slice';
2
- import mri from 'mri';
1
+ import { cac } from 'cac';
3
2
  import _concatInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/concat';
4
3
  import _findInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/find';
5
4
  import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each';
@@ -11,12 +10,71 @@ import merge from 'lodash/merge';
11
10
  import prompts from 'prompts';
12
11
  import pRetry from 'p-retry';
13
12
  import _slicedToArray from '@babel/runtime-corejs3/helpers/esm/slicedToArray';
13
+ import _includesInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/includes';
14
14
  import _URLSearchParams from '@babel/runtime-corejs3/core-js-stable/url-search-params';
15
15
  import _Object$entries from '@babel/runtime-corejs3/core-js-stable/object/entries';
16
16
  import _Promise from '@babel/runtime-corejs3/core-js-stable/promise';
17
17
  import _JSON$stringify from '@babel/runtime-corejs3/core-js-stable/json/stringify';
18
18
  import fetch from 'node-fetch';
19
19
 
20
+ var pkgJson = {
21
+ name: "@commercetools-frontend/deployment-cli",
22
+ version: "0.2.1",
23
+ description: "CLI to manage Custom Applications deployments in Google Storage.",
24
+ keywords: [
25
+ "commercetools",
26
+ "cli",
27
+ "deployment"
28
+ ],
29
+ license: "MIT",
30
+ main: "dist/commercetools-frontend-deployment-cli.cjs.js",
31
+ module: "dist/commercetools-frontend-deployment-cli.esm.js",
32
+ bin: "bin/cli.js",
33
+ files: [
34
+ "cli",
35
+ "dist",
36
+ "package.json",
37
+ "LICENSE",
38
+ "README.md"
39
+ ],
40
+ scripts: {
41
+ typecheck: "tsc --noEmit"
42
+ },
43
+ dependencies: {
44
+ "@babel/core": "^7.21.3",
45
+ "@babel/runtime": "^7.21.0",
46
+ "@babel/runtime-corejs3": "^7.21.0",
47
+ cac: "^6.7.14",
48
+ cosmiconfig: "8.2.0",
49
+ lodash: "4.17.21",
50
+ "node-fetch": "2.6.11",
51
+ "p-retry": "4.6.2",
52
+ prompts: "2.4.2"
53
+ },
54
+ devDependencies: {
55
+ "@tsconfig/node18": "1.0.3",
56
+ "@types/lodash": "^4.14.191",
57
+ "@types/node": "20.4.0",
58
+ "@types/node-fetch": "2.6.2",
59
+ "@types/prompts": "2.4.4",
60
+ msw: "1.2.2",
61
+ typescript: "4.9.5"
62
+ },
63
+ engines: {
64
+ node: ">=14",
65
+ npm: ">=6"
66
+ },
67
+ publishConfig: {
68
+ access: "public"
69
+ },
70
+ preconstruct: {
71
+ entrypoints: [
72
+ "./cli.ts",
73
+ "./index.ts"
74
+ ]
75
+ }
76
+ };
77
+
20
78
  async function loadConfig() {
21
79
  const deploymentConfigExplorer = cosmiconfig('deployment');
22
80
  const defaultConfig = {
@@ -346,7 +404,7 @@ async function approve(cliFlags, config, circleCiApis) {
346
404
 
347
405
  async function processCircleCiResponse(response) {
348
406
  if (!response.ok) {
349
- var _context, _context2;
407
+ var _response$headers$get, _context, _context2;
350
408
  /**
351
409
  * NOTE:
352
410
  * Trying to handle known but undocumented responses of the CircleCI API.
@@ -354,17 +412,20 @@ async function processCircleCiResponse(response) {
354
412
  * 1. Message: Already approved job
355
413
  * Deployment was already triggered manually or by train the day before.
356
414
  */
357
- try {
358
- const errorJson = await response.json();
359
- if (errorJson.message.match(/job already approved/i)) {
415
+
416
+ // Response data is a stream so text OR json can only be read once, so
417
+ // we read it as text first and then try to parse it as json to handle
418
+ // known error responses.
419
+ const error = await response.text();
420
+ if ((_response$headers$get = response.headers.get('content-type')) !== null && _response$headers$get !== void 0 && _includesInstanceProperty(_response$headers$get).call(_response$headers$get, 'application/json')) {
421
+ const _JSON$parse = JSON.parse(error),
422
+ message = _JSON$parse.message;
423
+ if (message.match(/job already approved/i)) {
360
424
  console.log('ℹ️ Deployment job is already approved.');
361
425
  process.exit(0);
362
426
  }
363
- } catch (e) {
364
- // ignore
365
427
  }
366
- const errorText = await response.text();
367
- throw new Error(_concatInstanceProperty(_context = _concatInstanceProperty(_context2 = "".concat(response.status, ": Network response was not ok.\n\n Status text is ")).call(_context2, response.statusText, " and text is ")).call(_context, errorText, "."));
428
+ throw new Error(_concatInstanceProperty(_context = _concatInstanceProperty(_context2 = "".concat(response.status, ": Network response was not ok.\n\n Status text is ")).call(_context2, response.statusText, " and text is ")).call(_context, error, "."));
368
429
  }
369
430
  return response.json();
370
431
  }
@@ -486,6 +547,7 @@ function createCircleCiClient(_ref) {
486
547
  };
487
548
  }
488
549
 
550
+ const cli = cac('deployment-cli');
489
551
  async function run() {
490
552
  const config = await loadConfig();
491
553
  throwIfConfigurationLacksRequiredValues(config);
@@ -493,53 +555,37 @@ async function run() {
493
555
  projectName: config.CircleCI.projectName,
494
556
  apiBaseUrl: config.CircleCI.apiBaseUrl
495
557
  });
496
- try {
497
- var _context;
498
- const cliFlags = mri(_sliceInstanceProperty(_context = process.argv).call(_context, 2), {
499
- alias: {
500
- help: ['h']
501
- },
502
- boolean: ['dry-run', 'debug', 'yes'],
503
- default: {
504
- branch: 'main'
505
- }
506
- });
507
- const cliCommands = cliFlags._;
508
- if (cliCommands.length === 0 ||
509
- // @ts-expect-error mri is not typed for the help command.
510
- cliCommands.help && cliCommands.length === 0) {
511
- console.log("\nUsage: deployment-cli [command] [flags]\n\nDisplays help information.\n\nCommand:\n approve 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/).\n\nOptions:\n --approval-job The name of the approval job to approve a deployment with.\n --deployment-job (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.\n --deployment (optional) The name of a deployment configured in the configuration file.\n --build-revision <git-sha> (optional) The git commit SHA that needs to be deployed. If not specified, the last successful pipeline is used.\n --branch (optional) The git branch to deploy from. If not specified, defaults to 'main'.\n --yes (optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.\n\nGeneral options:\n --dry-run (optional) Simulate a deployment.\n --debug (optional) Print additional debug information.\n");
512
- process.exit(0);
513
- }
514
- const cliCommand = cliCommands[0];
515
- if (cliFlags['dry-run']) {
516
- console.log("\n \uD83D\uDE4A Do not worry. This is a dry run!\n ");
517
- }
518
- console.log("\uD83C\uDFC3 Running ".concat(cliCommand, " command"));
519
- switch (cliCommand) {
520
- case 'approve':
521
- {
522
- throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
523
- await approve({
524
- deployment: cliFlags.deployment,
525
- branch: cliFlags.branch,
526
- approvalJob: cliFlags['approval-job'],
527
- deploymentJob: cliFlags['deployment-job'],
528
- buildRevision: cliFlags['build-revision'],
529
- yes: cliFlags.yes,
530
- debug: cliFlags.debug,
531
- dryRun: cliFlags['dry-run']
532
- }, config, circleCiApis);
533
- process.exit(0);
534
- }
535
- // eslint-disable-next-line no-fallthrough
536
- default:
537
- throw new Error("\uD83D\uDC80 Unknown command \"".concat(cliCommand, "\"."));
558
+
559
+ // General CLI options
560
+ cli.option('--dry-run', '(optional) Simulate a deployment.', {
561
+ default: false
562
+ });
563
+ cli.option('--debug', '(optional) Print additional debug information.', {
564
+ default: false
565
+ });
566
+
567
+ // Default command
568
+ cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
569
+
570
+ // Command: Approve
571
+ 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/).';
572
+ cli.command('approve', usageApprove).usage("approve \n\n ".concat(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.', {
573
+ default: 'main'
574
+ }).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
575
+ default: false
576
+ }).action(async options => {
577
+ if (options.dryRun) {
578
+ console.log("\uD83D\uDE4A Do not worry. This is a dry run!");
538
579
  }
539
- } catch (error) {
540
- console.error(error);
541
- process.exit(1);
542
- }
580
+ throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
581
+ await approve(options, config, circleCiApis);
582
+ });
583
+ cli.help();
584
+ cli.version(pkgJson.version);
585
+ cli.parse(process.argv, {
586
+ run: false
587
+ });
588
+ await cli.runMatchedCommand();
543
589
  }
544
590
 
545
591
  export { run };
@@ -1,5 +1,5 @@
1
1
  import { TCircleCiClient } from '../apis';
2
2
  import { TDeploymentCLIConfig } from '../helpers';
3
- import type { TApproveCliFlags } from '../types';
4
- declare function approve(cliFlags: TApproveCliFlags, config: TDeploymentCLIConfig, circleCiApis: TCircleCiClient): Promise<void>;
3
+ import type { TAllCliFlags } from '../types';
4
+ declare function approve(cliFlags: TAllCliFlags, config: TDeploymentCLIConfig, circleCiApis: TCircleCiClient): Promise<void>;
5
5
  export default approve;
@@ -28,17 +28,17 @@ declare function throwIfConfigurationLacksRequiredValues(parsedConfiguration: TD
28
28
  declare function throwIfRequiredEnvironmentVariableIsUnset(requiredEnvironmentVariables: string[]): void;
29
29
  type TPaginateToDeploymentPipelineArgs = {
30
30
  circleCiApis: TCircleCiClient;
31
- branch: string;
32
- buildRevision: string;
33
- debug: boolean;
31
+ branch?: string;
32
+ buildRevision?: string;
33
+ debug?: boolean;
34
34
  maxPages: number;
35
35
  };
36
36
  declare function paginateToDeploymentPipeline({ circleCiApis, buildRevision, branch, debug, maxPages, }: TPaginateToDeploymentPipelineArgs): Promise<TDeploymentPipeline | undefined>;
37
37
  type TWaitForDeploymentPipelinePromptArgs = {
38
38
  circleCiApis: TCircleCiClient;
39
- branch: string;
39
+ branch?: string;
40
40
  pagesForPipelineSelection: number;
41
- debug: boolean;
41
+ debug?: boolean;
42
42
  };
43
43
  declare function waitForDeploymentPipelinePrompt({ circleCiApis, branch, pagesForPipelineSelection, debug, }: TWaitForDeploymentPipelinePromptArgs): Promise<TDeploymentPipeline>;
44
44
  type TWaitForConfirmationPromptArgs = {
@@ -59,8 +59,8 @@ type TWaitForDeploymentJobNumberArgs = {
59
59
  circleCiApis: TCircleCiClient;
60
60
  };
61
61
  declare function waitForDeploymentJobNumber({ workflowId, deploymentJob, circleCiApis }: TWaitForDeploymentJobNumberArgs, { debug }: {
62
- debug: boolean;
63
- dryRun: boolean;
64
- yes: boolean;
62
+ debug?: boolean;
63
+ dryRun?: boolean;
64
+ yes?: boolean;
65
65
  }): Promise<number>;
66
66
  export { loadConfig, throwIfRequiredEnvironmentVariableIsUnset, throwIfConfigurationLacksRequiredValues, waitForDeploymentJobNumber, waitForDeploymentPipelinePrompt, waitForConfirmationPrompt, paginateToDeploymentPipeline, getJobUrl, };
@@ -1,23 +1,13 @@
1
1
  type TCliBaseFlags = {
2
- url: string;
3
- application: string;
4
2
  debug: boolean;
5
- yes: boolean;
6
- deployment: string;
7
- branch: string;
8
- };
9
- type TAllParsedCliFlags = TCliBaseFlags & {
10
- buildRevision: string;
11
- approvalJob: string;
12
- deploymentJob: string;
13
3
  dryRun: boolean;
14
4
  };
15
- export type TCliFlags = TCliBaseFlags & {
16
- 'build-revision': string;
17
- 'approval-job': string;
18
- 'deployment-job': string;
19
- 'dry-run': boolean;
5
+ export type TAllCliFlags = TCliBaseFlags & {
6
+ approvalJob: string;
7
+ deploymentJob?: string;
8
+ deployment?: string;
9
+ buildRevision?: string;
10
+ branch: string;
11
+ yes: boolean;
20
12
  };
21
- export type TApproveCliFlags = Pick<TAllParsedCliFlags, 'deployment' | 'approvalJob' | 'deploymentJob' | 'buildRevision' | 'branch' | 'yes' | 'debug' | 'dryRun'>;
22
- export type TCliCommands = 'help' | 'approve';
23
13
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercetools-frontend/deployment-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI to manage Custom Applications deployments in Google Storage.",
5
5
  "keywords": [
6
6
  "commercetools",
@@ -22,21 +22,21 @@
22
22
  "@babel/core": "^7.21.3",
23
23
  "@babel/runtime": "^7.21.0",
24
24
  "@babel/runtime-corejs3": "^7.21.0",
25
- "cosmiconfig": "8.1.3",
25
+ "cac": "^6.7.14",
26
+ "cosmiconfig": "8.2.0",
26
27
  "lodash": "4.17.21",
27
- "mri": "1.2.0",
28
- "node-fetch": "2.6.9",
28
+ "node-fetch": "2.6.11",
29
29
  "p-retry": "4.6.2",
30
30
  "prompts": "2.4.2"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@tsconfig/node18": "1.0.3",
34
34
  "@types/lodash": "^4.14.191",
35
- "@types/node": "18.15.12",
36
- "@types/node-fetch": "2.6.3",
35
+ "@types/node": "20.4.0",
36
+ "@types/node-fetch": "2.6.2",
37
37
  "@types/prompts": "2.4.4",
38
- "msw": "1.2.1",
39
- "typescript": "^4.9.5"
38
+ "msw": "1.2.2",
39
+ "typescript": "4.9.5"
40
40
  },
41
41
  "engines": {
42
42
  "node": ">=14",