@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
|
@@ -2,43 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
6
|
-
var
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
415
|
-
|
|
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
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
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
|
|
6
|
-
var
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
415
|
-
|
|
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
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
593
|
+
commander.program.parse();
|
|
599
594
|
}
|
|
600
595
|
|
|
601
596
|
exports.run = run;
|
|
@@ -1,24 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
395
|
-
|
|
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
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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
|
-
|
|
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
|
+
"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
|
-
"
|
|
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.
|
|
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"
|