@commercetools-frontend/deployment-cli 2.0.2 → 2.0.4
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.4",
|
|
42
55
|
description: "CLI to manage Custom Applications deployments in Google Storage.",
|
|
43
56
|
keywords: [
|
|
44
57
|
"commercetools",
|
|
@@ -62,9 +75,8 @@ var pkgJson = {
|
|
|
62
75
|
},
|
|
63
76
|
dependencies: {
|
|
64
77
|
"@babel/core": "^7.22.11",
|
|
65
|
-
"@babel/runtime": "^7.21.0",
|
|
66
78
|
"@babel/runtime-corejs3": "^7.21.0",
|
|
67
|
-
|
|
79
|
+
commander: "^13.1.0",
|
|
68
80
|
cosmiconfig: "9.0.0",
|
|
69
81
|
lodash: "4.17.21",
|
|
70
82
|
"p-retry": "4.6.2",
|
|
@@ -73,7 +85,7 @@ var pkgJson = {
|
|
|
73
85
|
devDependencies: {
|
|
74
86
|
"@tsconfig/node20": "20.1.4",
|
|
75
87
|
"@types/lodash": "^4.14.198",
|
|
76
|
-
"@types/node": "
|
|
88
|
+
"@types/node": "22.13.9",
|
|
77
89
|
"@types/prompts": "2.4.9",
|
|
78
90
|
msw: "1.3.5",
|
|
79
91
|
typescript: "5.2.2"
|
|
@@ -93,6 +105,152 @@ var pkgJson = {
|
|
|
93
105
|
}
|
|
94
106
|
};
|
|
95
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
|
+
|
|
96
254
|
async function loadConfig() {
|
|
97
255
|
const deploymentConfigExplorer = cosmiconfig.cosmiconfig('deployment', {
|
|
98
256
|
searchStrategy: 'project'
|
|
@@ -412,153 +570,9 @@ async function approve(cliFlags, config, circleCiApis) {
|
|
|
412
570
|
}
|
|
413
571
|
}
|
|
414
572
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
* NOTE:
|
|
419
|
-
* Trying to handle known but undocumented responses of the CircleCI API.
|
|
420
|
-
*
|
|
421
|
-
* 1. Message: Already approved job
|
|
422
|
-
* Deployment was already triggered manually or by train the day before.
|
|
423
|
-
*/
|
|
424
|
-
|
|
425
|
-
// Response data is a stream so text OR json can only be read once, so
|
|
426
|
-
// we read it as text first and then try to parse it as json to handle
|
|
427
|
-
// known error responses.
|
|
428
|
-
const error = await response.text();
|
|
429
|
-
try {
|
|
430
|
-
// The CircleCI API always uses content-type text/plain, so we always
|
|
431
|
-
// try parsing JSON to see if the message property is present.
|
|
432
|
-
const _JSON$parse = JSON.parse(error),
|
|
433
|
-
message = _JSON$parse.message;
|
|
434
|
-
if (message.match(/job already approved/i)) {
|
|
435
|
-
console.log('ℹ️ Deployment job is already approved.');
|
|
436
|
-
// TODO: can we return instead of force exiting?
|
|
437
|
-
node_process.exit(0);
|
|
438
|
-
}
|
|
439
|
-
} catch {
|
|
440
|
-
// Ignore JSON parsing errors
|
|
441
|
-
}
|
|
442
|
-
throw new Error(`${response.status}: Network response was not ok.\n
|
|
443
|
-
Status text is ${response.statusText} and text is ${error}.`);
|
|
444
|
-
}
|
|
445
|
-
return response.json();
|
|
446
|
-
}
|
|
447
|
-
function createCircleCiClient(_ref) {
|
|
448
|
-
let projectName = _ref.projectName,
|
|
449
|
-
apiBaseUrl = _ref.apiBaseUrl;
|
|
450
|
-
async function execute(api) {
|
|
451
|
-
let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
|
|
452
|
-
skip = _ref2.skip,
|
|
453
|
-
debug = _ref2.debug;
|
|
454
|
-
let url = `${apiBaseUrl}${api.url}`;
|
|
455
|
-
if (api.params && api.method === 'GET') {
|
|
456
|
-
const urlSearchParams = new _URLSearchParams__default["default"]();
|
|
457
|
-
for (const _ref3 of _Object$entries__default["default"](api.params)) {
|
|
458
|
-
var _ref4 = _slicedToArray(_ref3, 2);
|
|
459
|
-
const key = _ref4[0];
|
|
460
|
-
const value = _ref4[1];
|
|
461
|
-
if (value !== null && value !== undefined) {
|
|
462
|
-
urlSearchParams.append(key, value);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
url += `?${urlSearchParams.toString()}`;
|
|
466
|
-
}
|
|
467
|
-
if (skip) {
|
|
468
|
-
if (debug) {
|
|
469
|
-
console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// @ts-expect-error
|
|
473
|
-
return _Promise__default["default"].resolve();
|
|
474
|
-
}
|
|
475
|
-
if (debug) {
|
|
476
|
-
console.log(`🏭 Calling CircleCI API at: ${url}.`);
|
|
477
|
-
}
|
|
478
|
-
try {
|
|
479
|
-
const response = await fetch(url, {
|
|
480
|
-
headers: api.headers,
|
|
481
|
-
method: api.method,
|
|
482
|
-
body: api.method === 'POST' ? _JSON$stringify__default["default"](api.params) : undefined
|
|
483
|
-
});
|
|
484
|
-
const processedCircleCiResponse = await processCircleCiResponse(response);
|
|
485
|
-
return processedCircleCiResponse;
|
|
486
|
-
} catch (error) {
|
|
487
|
-
console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
|
|
488
|
-
throw error;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
return {
|
|
492
|
-
pipelines: function () {
|
|
493
|
-
let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
494
|
-
pageToken = _ref5.pageToken,
|
|
495
|
-
_ref5$projectSlug = _ref5.projectSlug,
|
|
496
|
-
projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
|
|
497
|
-
_ref5$branch = _ref5.branch,
|
|
498
|
-
branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
|
|
499
|
-
return {
|
|
500
|
-
execute: options => execute({
|
|
501
|
-
url: `/project/${projectSlug}/pipeline`,
|
|
502
|
-
headers: {
|
|
503
|
-
'Content-Type': 'application/json',
|
|
504
|
-
// The CLI throws if this is not present on environment
|
|
505
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
506
|
-
},
|
|
507
|
-
method: 'GET',
|
|
508
|
-
params: {
|
|
509
|
-
branch,
|
|
510
|
-
'page-token': pageToken
|
|
511
|
-
}
|
|
512
|
-
}, options)
|
|
513
|
-
};
|
|
514
|
-
},
|
|
515
|
-
workflows: _ref6 => {
|
|
516
|
-
let pipelineId = _ref6.pipelineId;
|
|
517
|
-
return {
|
|
518
|
-
execute: options => execute({
|
|
519
|
-
url: `/pipeline/${pipelineId}/workflow`,
|
|
520
|
-
headers: {
|
|
521
|
-
'Content-Type': 'application/json',
|
|
522
|
-
// The CLI throws if this is not present on environment
|
|
523
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
524
|
-
},
|
|
525
|
-
method: 'GET'
|
|
526
|
-
}, options)
|
|
527
|
-
};
|
|
528
|
-
},
|
|
529
|
-
jobs: _ref7 => {
|
|
530
|
-
let workflowId = _ref7.workflowId;
|
|
531
|
-
return {
|
|
532
|
-
execute: options => execute({
|
|
533
|
-
url: `/workflow/${workflowId}/job`,
|
|
534
|
-
headers: {
|
|
535
|
-
'Content-Type': 'application/json',
|
|
536
|
-
// The CLI throws if this is not present on environment
|
|
537
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
538
|
-
},
|
|
539
|
-
method: 'GET'
|
|
540
|
-
}, options)
|
|
541
|
-
};
|
|
542
|
-
},
|
|
543
|
-
approve: _ref8 => {
|
|
544
|
-
let workflowId = _ref8.workflowId,
|
|
545
|
-
approvalRequestId = _ref8.approvalRequestId;
|
|
546
|
-
return {
|
|
547
|
-
execute: options => execute({
|
|
548
|
-
url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
|
|
549
|
-
headers: {
|
|
550
|
-
'Content-Type': 'application/json',
|
|
551
|
-
// The CLI throws if this is not present on environment
|
|
552
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
553
|
-
},
|
|
554
|
-
method: 'POST'
|
|
555
|
-
}, options)
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
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);
|
|
562
576
|
async function run() {
|
|
563
577
|
const config = await loadConfig();
|
|
564
578
|
throwIfConfigurationLacksRequiredValues(config);
|
|
@@ -567,36 +581,16 @@ async function run() {
|
|
|
567
581
|
apiBaseUrl: config.CircleCI.apiBaseUrl
|
|
568
582
|
});
|
|
569
583
|
|
|
570
|
-
// General CLI options
|
|
571
|
-
cli.option('--dry-run', '(optional) Simulate a deployment.', {
|
|
572
|
-
default: false
|
|
573
|
-
});
|
|
574
|
-
cli.option('--debug', '(optional) Print additional debug information.', {
|
|
575
|
-
default: false
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
// Default command
|
|
579
|
-
cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
|
|
580
|
-
|
|
581
584
|
// Command: Approve
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
|
|
586
|
-
default: false
|
|
587
|
-
}).action(async options => {
|
|
588
|
-
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/).').requiredOption('--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.', '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) {
|
|
589
588
|
console.log(`🙊 Do not worry. This is a dry run!`);
|
|
590
589
|
}
|
|
591
590
|
throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
|
|
592
|
-
await approve(options, config, circleCiApis);
|
|
593
|
-
});
|
|
594
|
-
cli.help();
|
|
595
|
-
cli.version(pkgJson.version);
|
|
596
|
-
cli.parse(process.argv, {
|
|
597
|
-
run: false
|
|
591
|
+
await approve(_objectSpread(_objectSpread({}, globalOptions), options), config, circleCiApis);
|
|
598
592
|
});
|
|
599
|
-
|
|
593
|
+
commander.program.parse();
|
|
600
594
|
}
|
|
601
595
|
|
|
602
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.4",
|
|
42
55
|
description: "CLI to manage Custom Applications deployments in Google Storage.",
|
|
43
56
|
keywords: [
|
|
44
57
|
"commercetools",
|
|
@@ -62,9 +75,8 @@ var pkgJson = {
|
|
|
62
75
|
},
|
|
63
76
|
dependencies: {
|
|
64
77
|
"@babel/core": "^7.22.11",
|
|
65
|
-
"@babel/runtime": "^7.21.0",
|
|
66
78
|
"@babel/runtime-corejs3": "^7.21.0",
|
|
67
|
-
|
|
79
|
+
commander: "^13.1.0",
|
|
68
80
|
cosmiconfig: "9.0.0",
|
|
69
81
|
lodash: "4.17.21",
|
|
70
82
|
"p-retry": "4.6.2",
|
|
@@ -73,7 +85,7 @@ var pkgJson = {
|
|
|
73
85
|
devDependencies: {
|
|
74
86
|
"@tsconfig/node20": "20.1.4",
|
|
75
87
|
"@types/lodash": "^4.14.198",
|
|
76
|
-
"@types/node": "
|
|
88
|
+
"@types/node": "22.13.9",
|
|
77
89
|
"@types/prompts": "2.4.9",
|
|
78
90
|
msw: "1.3.5",
|
|
79
91
|
typescript: "5.2.2"
|
|
@@ -93,6 +105,152 @@ var pkgJson = {
|
|
|
93
105
|
}
|
|
94
106
|
};
|
|
95
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
|
+
|
|
96
254
|
async function loadConfig() {
|
|
97
255
|
const deploymentConfigExplorer = cosmiconfig.cosmiconfig('deployment', {
|
|
98
256
|
searchStrategy: 'project'
|
|
@@ -412,153 +570,9 @@ async function approve(cliFlags, config, circleCiApis) {
|
|
|
412
570
|
}
|
|
413
571
|
}
|
|
414
572
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
* NOTE:
|
|
419
|
-
* Trying to handle known but undocumented responses of the CircleCI API.
|
|
420
|
-
*
|
|
421
|
-
* 1. Message: Already approved job
|
|
422
|
-
* Deployment was already triggered manually or by train the day before.
|
|
423
|
-
*/
|
|
424
|
-
|
|
425
|
-
// Response data is a stream so text OR json can only be read once, so
|
|
426
|
-
// we read it as text first and then try to parse it as json to handle
|
|
427
|
-
// known error responses.
|
|
428
|
-
const error = await response.text();
|
|
429
|
-
try {
|
|
430
|
-
// The CircleCI API always uses content-type text/plain, so we always
|
|
431
|
-
// try parsing JSON to see if the message property is present.
|
|
432
|
-
const _JSON$parse = JSON.parse(error),
|
|
433
|
-
message = _JSON$parse.message;
|
|
434
|
-
if (message.match(/job already approved/i)) {
|
|
435
|
-
console.log('ℹ️ Deployment job is already approved.');
|
|
436
|
-
// TODO: can we return instead of force exiting?
|
|
437
|
-
node_process.exit(0);
|
|
438
|
-
}
|
|
439
|
-
} catch {
|
|
440
|
-
// Ignore JSON parsing errors
|
|
441
|
-
}
|
|
442
|
-
throw new Error(`${response.status}: Network response was not ok.\n
|
|
443
|
-
Status text is ${response.statusText} and text is ${error}.`);
|
|
444
|
-
}
|
|
445
|
-
return response.json();
|
|
446
|
-
}
|
|
447
|
-
function createCircleCiClient(_ref) {
|
|
448
|
-
let projectName = _ref.projectName,
|
|
449
|
-
apiBaseUrl = _ref.apiBaseUrl;
|
|
450
|
-
async function execute(api) {
|
|
451
|
-
let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
|
|
452
|
-
skip = _ref2.skip,
|
|
453
|
-
debug = _ref2.debug;
|
|
454
|
-
let url = `${apiBaseUrl}${api.url}`;
|
|
455
|
-
if (api.params && api.method === 'GET') {
|
|
456
|
-
const urlSearchParams = new _URLSearchParams__default["default"]();
|
|
457
|
-
for (const _ref3 of _Object$entries__default["default"](api.params)) {
|
|
458
|
-
var _ref4 = _slicedToArray(_ref3, 2);
|
|
459
|
-
const key = _ref4[0];
|
|
460
|
-
const value = _ref4[1];
|
|
461
|
-
if (value !== null && value !== undefined) {
|
|
462
|
-
urlSearchParams.append(key, value);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
url += `?${urlSearchParams.toString()}`;
|
|
466
|
-
}
|
|
467
|
-
if (skip) {
|
|
468
|
-
if (debug) {
|
|
469
|
-
console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// @ts-expect-error
|
|
473
|
-
return _Promise__default["default"].resolve();
|
|
474
|
-
}
|
|
475
|
-
if (debug) {
|
|
476
|
-
console.log(`🏭 Calling CircleCI API at: ${url}.`);
|
|
477
|
-
}
|
|
478
|
-
try {
|
|
479
|
-
const response = await fetch(url, {
|
|
480
|
-
headers: api.headers,
|
|
481
|
-
method: api.method,
|
|
482
|
-
body: api.method === 'POST' ? _JSON$stringify__default["default"](api.params) : undefined
|
|
483
|
-
});
|
|
484
|
-
const processedCircleCiResponse = await processCircleCiResponse(response);
|
|
485
|
-
return processedCircleCiResponse;
|
|
486
|
-
} catch (error) {
|
|
487
|
-
console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
|
|
488
|
-
throw error;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
return {
|
|
492
|
-
pipelines: function () {
|
|
493
|
-
let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
494
|
-
pageToken = _ref5.pageToken,
|
|
495
|
-
_ref5$projectSlug = _ref5.projectSlug,
|
|
496
|
-
projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
|
|
497
|
-
_ref5$branch = _ref5.branch,
|
|
498
|
-
branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
|
|
499
|
-
return {
|
|
500
|
-
execute: options => execute({
|
|
501
|
-
url: `/project/${projectSlug}/pipeline`,
|
|
502
|
-
headers: {
|
|
503
|
-
'Content-Type': 'application/json',
|
|
504
|
-
// The CLI throws if this is not present on environment
|
|
505
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
506
|
-
},
|
|
507
|
-
method: 'GET',
|
|
508
|
-
params: {
|
|
509
|
-
branch,
|
|
510
|
-
'page-token': pageToken
|
|
511
|
-
}
|
|
512
|
-
}, options)
|
|
513
|
-
};
|
|
514
|
-
},
|
|
515
|
-
workflows: _ref6 => {
|
|
516
|
-
let pipelineId = _ref6.pipelineId;
|
|
517
|
-
return {
|
|
518
|
-
execute: options => execute({
|
|
519
|
-
url: `/pipeline/${pipelineId}/workflow`,
|
|
520
|
-
headers: {
|
|
521
|
-
'Content-Type': 'application/json',
|
|
522
|
-
// The CLI throws if this is not present on environment
|
|
523
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
524
|
-
},
|
|
525
|
-
method: 'GET'
|
|
526
|
-
}, options)
|
|
527
|
-
};
|
|
528
|
-
},
|
|
529
|
-
jobs: _ref7 => {
|
|
530
|
-
let workflowId = _ref7.workflowId;
|
|
531
|
-
return {
|
|
532
|
-
execute: options => execute({
|
|
533
|
-
url: `/workflow/${workflowId}/job`,
|
|
534
|
-
headers: {
|
|
535
|
-
'Content-Type': 'application/json',
|
|
536
|
-
// The CLI throws if this is not present on environment
|
|
537
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
538
|
-
},
|
|
539
|
-
method: 'GET'
|
|
540
|
-
}, options)
|
|
541
|
-
};
|
|
542
|
-
},
|
|
543
|
-
approve: _ref8 => {
|
|
544
|
-
let workflowId = _ref8.workflowId,
|
|
545
|
-
approvalRequestId = _ref8.approvalRequestId;
|
|
546
|
-
return {
|
|
547
|
-
execute: options => execute({
|
|
548
|
-
url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
|
|
549
|
-
headers: {
|
|
550
|
-
'Content-Type': 'application/json',
|
|
551
|
-
// The CLI throws if this is not present on environment
|
|
552
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
553
|
-
},
|
|
554
|
-
method: 'POST'
|
|
555
|
-
}, options)
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
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);
|
|
562
576
|
async function run() {
|
|
563
577
|
const config = await loadConfig();
|
|
564
578
|
throwIfConfigurationLacksRequiredValues(config);
|
|
@@ -567,36 +581,16 @@ async function run() {
|
|
|
567
581
|
apiBaseUrl: config.CircleCI.apiBaseUrl
|
|
568
582
|
});
|
|
569
583
|
|
|
570
|
-
// General CLI options
|
|
571
|
-
cli.option('--dry-run', '(optional) Simulate a deployment.', {
|
|
572
|
-
default: false
|
|
573
|
-
});
|
|
574
|
-
cli.option('--debug', '(optional) Print additional debug information.', {
|
|
575
|
-
default: false
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
// Default command
|
|
579
|
-
cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
|
|
580
|
-
|
|
581
584
|
// Command: Approve
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
|
|
586
|
-
default: false
|
|
587
|
-
}).action(async options => {
|
|
588
|
-
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/).').requiredOption('--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.', '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) {
|
|
589
588
|
console.log(`🙊 Do not worry. This is a dry run!`);
|
|
590
589
|
}
|
|
591
590
|
throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
|
|
592
|
-
await approve(options, config, circleCiApis);
|
|
593
|
-
});
|
|
594
|
-
cli.help();
|
|
595
|
-
cli.version(pkgJson.version);
|
|
596
|
-
cli.parse(process.argv, {
|
|
597
|
-
run: false
|
|
591
|
+
await approve(_objectSpread(_objectSpread({}, globalOptions), options), config, circleCiApis);
|
|
598
592
|
});
|
|
599
|
-
|
|
593
|
+
commander.program.parse();
|
|
600
594
|
}
|
|
601
595
|
|
|
602
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.4",
|
|
22
29
|
description: "CLI to manage Custom Applications deployments in Google Storage.",
|
|
23
30
|
keywords: [
|
|
24
31
|
"commercetools",
|
|
@@ -42,9 +49,8 @@ var pkgJson = {
|
|
|
42
49
|
},
|
|
43
50
|
dependencies: {
|
|
44
51
|
"@babel/core": "^7.22.11",
|
|
45
|
-
"@babel/runtime": "^7.21.0",
|
|
46
52
|
"@babel/runtime-corejs3": "^7.21.0",
|
|
47
|
-
|
|
53
|
+
commander: "^13.1.0",
|
|
48
54
|
cosmiconfig: "9.0.0",
|
|
49
55
|
lodash: "4.17.21",
|
|
50
56
|
"p-retry": "4.6.2",
|
|
@@ -53,7 +59,7 @@ var pkgJson = {
|
|
|
53
59
|
devDependencies: {
|
|
54
60
|
"@tsconfig/node20": "20.1.4",
|
|
55
61
|
"@types/lodash": "^4.14.198",
|
|
56
|
-
"@types/node": "
|
|
62
|
+
"@types/node": "22.13.9",
|
|
57
63
|
"@types/prompts": "2.4.9",
|
|
58
64
|
msw: "1.3.5",
|
|
59
65
|
typescript: "5.2.2"
|
|
@@ -73,6 +79,152 @@ var pkgJson = {
|
|
|
73
79
|
}
|
|
74
80
|
};
|
|
75
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
|
+
|
|
76
228
|
async function loadConfig() {
|
|
77
229
|
const deploymentConfigExplorer = cosmiconfig('deployment', {
|
|
78
230
|
searchStrategy: 'project'
|
|
@@ -392,153 +544,9 @@ async function approve(cliFlags, config, circleCiApis) {
|
|
|
392
544
|
}
|
|
393
545
|
}
|
|
394
546
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
* NOTE:
|
|
399
|
-
* Trying to handle known but undocumented responses of the CircleCI API.
|
|
400
|
-
*
|
|
401
|
-
* 1. Message: Already approved job
|
|
402
|
-
* Deployment was already triggered manually or by train the day before.
|
|
403
|
-
*/
|
|
404
|
-
|
|
405
|
-
// Response data is a stream so text OR json can only be read once, so
|
|
406
|
-
// we read it as text first and then try to parse it as json to handle
|
|
407
|
-
// known error responses.
|
|
408
|
-
const error = await response.text();
|
|
409
|
-
try {
|
|
410
|
-
// The CircleCI API always uses content-type text/plain, so we always
|
|
411
|
-
// try parsing JSON to see if the message property is present.
|
|
412
|
-
const _JSON$parse = JSON.parse(error),
|
|
413
|
-
message = _JSON$parse.message;
|
|
414
|
-
if (message.match(/job already approved/i)) {
|
|
415
|
-
console.log('ℹ️ Deployment job is already approved.');
|
|
416
|
-
// TODO: can we return instead of force exiting?
|
|
417
|
-
exit(0);
|
|
418
|
-
}
|
|
419
|
-
} catch {
|
|
420
|
-
// Ignore JSON parsing errors
|
|
421
|
-
}
|
|
422
|
-
throw new Error(`${response.status}: Network response was not ok.\n
|
|
423
|
-
Status text is ${response.statusText} and text is ${error}.`);
|
|
424
|
-
}
|
|
425
|
-
return response.json();
|
|
426
|
-
}
|
|
427
|
-
function createCircleCiClient(_ref) {
|
|
428
|
-
let projectName = _ref.projectName,
|
|
429
|
-
apiBaseUrl = _ref.apiBaseUrl;
|
|
430
|
-
async function execute(api) {
|
|
431
|
-
let _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
|
|
432
|
-
skip = _ref2.skip,
|
|
433
|
-
debug = _ref2.debug;
|
|
434
|
-
let url = `${apiBaseUrl}${api.url}`;
|
|
435
|
-
if (api.params && api.method === 'GET') {
|
|
436
|
-
const urlSearchParams = new _URLSearchParams();
|
|
437
|
-
for (const _ref3 of _Object$entries(api.params)) {
|
|
438
|
-
var _ref4 = _slicedToArray(_ref3, 2);
|
|
439
|
-
const key = _ref4[0];
|
|
440
|
-
const value = _ref4[1];
|
|
441
|
-
if (value !== null && value !== undefined) {
|
|
442
|
-
urlSearchParams.append(key, value);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
url += `?${urlSearchParams.toString()}`;
|
|
446
|
-
}
|
|
447
|
-
if (skip) {
|
|
448
|
-
if (debug) {
|
|
449
|
-
console.log(`🏭 Skipping CircleCI call API at: ${url}.`);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// @ts-expect-error
|
|
453
|
-
return _Promise.resolve();
|
|
454
|
-
}
|
|
455
|
-
if (debug) {
|
|
456
|
-
console.log(`🏭 Calling CircleCI API at: ${url}.`);
|
|
457
|
-
}
|
|
458
|
-
try {
|
|
459
|
-
const response = await fetch(url, {
|
|
460
|
-
headers: api.headers,
|
|
461
|
-
method: api.method,
|
|
462
|
-
body: api.method === 'POST' ? _JSON$stringify(api.params) : undefined
|
|
463
|
-
});
|
|
464
|
-
const processedCircleCiResponse = await processCircleCiResponse(response);
|
|
465
|
-
return processedCircleCiResponse;
|
|
466
|
-
} catch (error) {
|
|
467
|
-
console.log(`⚠️ Calling CircleCI API at: ${url} failed.`);
|
|
468
|
-
throw error;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
return {
|
|
472
|
-
pipelines: function () {
|
|
473
|
-
let _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
474
|
-
pageToken = _ref5.pageToken,
|
|
475
|
-
_ref5$projectSlug = _ref5.projectSlug,
|
|
476
|
-
projectSlug = _ref5$projectSlug === void 0 ? `gh/commercetools/${projectName}` : _ref5$projectSlug,
|
|
477
|
-
_ref5$branch = _ref5.branch,
|
|
478
|
-
branch = _ref5$branch === void 0 ? 'main' : _ref5$branch;
|
|
479
|
-
return {
|
|
480
|
-
execute: options => execute({
|
|
481
|
-
url: `/project/${projectSlug}/pipeline`,
|
|
482
|
-
headers: {
|
|
483
|
-
'Content-Type': 'application/json',
|
|
484
|
-
// The CLI throws if this is not present on environment
|
|
485
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
486
|
-
},
|
|
487
|
-
method: 'GET',
|
|
488
|
-
params: {
|
|
489
|
-
branch,
|
|
490
|
-
'page-token': pageToken
|
|
491
|
-
}
|
|
492
|
-
}, options)
|
|
493
|
-
};
|
|
494
|
-
},
|
|
495
|
-
workflows: _ref6 => {
|
|
496
|
-
let pipelineId = _ref6.pipelineId;
|
|
497
|
-
return {
|
|
498
|
-
execute: options => execute({
|
|
499
|
-
url: `/pipeline/${pipelineId}/workflow`,
|
|
500
|
-
headers: {
|
|
501
|
-
'Content-Type': 'application/json',
|
|
502
|
-
// The CLI throws if this is not present on environment
|
|
503
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
504
|
-
},
|
|
505
|
-
method: 'GET'
|
|
506
|
-
}, options)
|
|
507
|
-
};
|
|
508
|
-
},
|
|
509
|
-
jobs: _ref7 => {
|
|
510
|
-
let workflowId = _ref7.workflowId;
|
|
511
|
-
return {
|
|
512
|
-
execute: options => execute({
|
|
513
|
-
url: `/workflow/${workflowId}/job`,
|
|
514
|
-
headers: {
|
|
515
|
-
'Content-Type': 'application/json',
|
|
516
|
-
// The CLI throws if this is not present on environment
|
|
517
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
518
|
-
},
|
|
519
|
-
method: 'GET'
|
|
520
|
-
}, options)
|
|
521
|
-
};
|
|
522
|
-
},
|
|
523
|
-
approve: _ref8 => {
|
|
524
|
-
let workflowId = _ref8.workflowId,
|
|
525
|
-
approvalRequestId = _ref8.approvalRequestId;
|
|
526
|
-
return {
|
|
527
|
-
execute: options => execute({
|
|
528
|
-
url: `/workflow/${workflowId}/approve/${approvalRequestId} `,
|
|
529
|
-
headers: {
|
|
530
|
-
'Content-Type': 'application/json',
|
|
531
|
-
// The CLI throws if this is not present on environment
|
|
532
|
-
'Circle-Token': process.env.CIRCLE_TOKEN
|
|
533
|
-
},
|
|
534
|
-
method: 'POST'
|
|
535
|
-
}, options)
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
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);
|
|
542
550
|
async function run() {
|
|
543
551
|
const config = await loadConfig();
|
|
544
552
|
throwIfConfigurationLacksRequiredValues(config);
|
|
@@ -547,36 +555,16 @@ async function run() {
|
|
|
547
555
|
apiBaseUrl: config.CircleCI.apiBaseUrl
|
|
548
556
|
});
|
|
549
557
|
|
|
550
|
-
// General CLI options
|
|
551
|
-
cli.option('--dry-run', '(optional) Simulate a deployment.', {
|
|
552
|
-
default: false
|
|
553
|
-
});
|
|
554
|
-
cli.option('--debug', '(optional) Print additional debug information.', {
|
|
555
|
-
default: false
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
// Default command
|
|
559
|
-
cli.command('').usage('\n\n Approve deployment jobs on CI for different components related to MC.').action(cli.outputHelp);
|
|
560
|
-
|
|
561
558
|
// Command: Approve
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}).option('--yes', '(optional) Skip all confirmation prompts. Useful in Continuous integration (CI) to automatically answer confirmation questions.', {
|
|
566
|
-
default: false
|
|
567
|
-
}).action(async options => {
|
|
568
|
-
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/).').requiredOption('--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.', '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) {
|
|
569
562
|
console.log(`🙊 Do not worry. This is a dry run!`);
|
|
570
563
|
}
|
|
571
564
|
throwIfRequiredEnvironmentVariableIsUnset(['CIRCLE_TOKEN']);
|
|
572
|
-
await approve(options, config, circleCiApis);
|
|
573
|
-
});
|
|
574
|
-
cli.help();
|
|
575
|
-
cli.version(pkgJson.version);
|
|
576
|
-
cli.parse(process.argv, {
|
|
577
|
-
run: false
|
|
565
|
+
await approve(_objectSpread(_objectSpread({}, globalOptions), options), config, circleCiApis);
|
|
578
566
|
});
|
|
579
|
-
|
|
567
|
+
program.parse();
|
|
580
568
|
}
|
|
581
569
|
|
|
582
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.4",
|
|
4
4
|
"description": "CLI to manage Custom Applications deployments in Google Storage.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"commercetools",
|
|
@@ -21,9 +21,8 @@
|
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@babel/core": "^7.22.11",
|
|
24
|
-
"@babel/runtime": "^7.21.0",
|
|
25
24
|
"@babel/runtime-corejs3": "^7.21.0",
|
|
26
|
-
"
|
|
25
|
+
"commander": "^13.1.0",
|
|
27
26
|
"cosmiconfig": "9.0.0",
|
|
28
27
|
"lodash": "4.17.21",
|
|
29
28
|
"p-retry": "4.6.2",
|
|
@@ -32,7 +31,7 @@
|
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"@tsconfig/node20": "20.1.4",
|
|
34
33
|
"@types/lodash": "^4.14.198",
|
|
35
|
-
"@types/node": "
|
|
34
|
+
"@types/node": "22.13.9",
|
|
36
35
|
"@types/prompts": "2.4.9",
|
|
37
36
|
"msw": "1.3.5",
|
|
38
37
|
"typescript": "5.2.2"
|