@commercetools-frontend/application-cli 1.7.3 → 1.8.0

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/README.md CHANGED
@@ -26,6 +26,9 @@ pnpm application-cli compile-deployments \
26
26
  The environments to compile the deployments for must be specified in a `google-storage-buckets` [cosmiconfig](https://github.com/davidtheclark/cosmiconfig) file for example `google-storage-buckets.config.cjs` with the bucket region mapping to multiple environments. For example:
27
27
 
28
28
  ```js
29
+ /**
30
+ * @type {import('@commercetools-frontend/application-cli').TGoogleStorageBucketsConfig}
31
+ */
29
32
  module.exports = {
30
33
  'merchant-center-north-america': ['gcp-production-us'],
31
34
  'merchant-center-asia': ['gcp-production-au'],
@@ -57,6 +60,26 @@ Depending on the environment you are deploying to, you need to:
57
60
 
58
61
  Additionally, when specifying the `--dotenv-folder` option, you can specify a dotenv file for each environment (for example `.env.gcp-production-eu`) and a single `.env.production` dotenv file. These files are then loaded when compiling the application for the respective environment.
59
62
 
63
+ The configuration also supports an expanded version in which each cloud environment can be linked to another bucket environment:
64
+
65
+ ```js
66
+ /**
67
+ * @type {import('@commercetools-frontend/application-cli').TGoogleStorageBucketsConfig}
68
+ */
69
+ module.exports = {
70
+ 'merchant-center-europe': [
71
+ {
72
+ cloudEnvironment: 'ctp_production_aws_eu-central-1_v1',
73
+ bucketEnvironment: 'ctp-aws-production-fra',
74
+ },
75
+ ],
76
+ };
77
+ ```
78
+
79
+ Given the configuration above the cloud environment `ctp_production_aws_eu-central-1_v1` will be uploaded to the `merchant-center-europe` bucket region within the `ctp-aws-production-fra` folder as the bucket environment.
80
+
81
+ This is useful as cloud and bucket environments do not fall in the same lifecycle. A Kubernetes cluster is versioned and may have to change (e.g. be updated) without that needing to be reflected in the respective bucket environment. Also two cloud environments (e.g. in different versions) can be served from one bucket environment if needed.
82
+
60
83
  ### Command: `compile-menu`
61
84
 
62
85
  This command compiles the menu configuration [defined in the application config](https://docs.commercetools.com/custom-applications/api-reference/application-config#mainmenulink) into a `menu.json` file.
@@ -13,9 +13,9 @@ var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/obje
13
13
  var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
14
14
  var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
15
15
  var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
16
- var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
17
16
  var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
18
17
  var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
18
+ var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
19
19
  var fs = require('fs');
20
20
  var path = require('path');
21
21
  var listr2 = require('listr2');
@@ -41,9 +41,9 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
41
41
  var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
42
42
  var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
43
43
  var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
44
- var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
45
44
  var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
46
45
  var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
46
+ var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
47
47
  var fs__default = /*#__PURE__*/_interopDefault(fs);
48
48
  var path__default = /*#__PURE__*/_interopDefault(path);
49
49
  var execa__default = /*#__PURE__*/_interopDefault(execa);
@@ -67,29 +67,104 @@ function isCI() {
67
67
  }
68
68
 
69
69
  function createApplicationIndexUploadScript(_ref) {
70
- var _context, _context2, _context3, _context4, _context5, _context6, _context7, _context8, _context9, _context10;
71
70
  let packageManagerName = _ref.packageManagerName,
72
71
  bucketUrl = _ref.bucketUrl,
73
72
  cdnUrl = _ref.cdnUrl,
74
- cloudEnvironment = _ref.cloudEnvironment,
73
+ bucketEnvironment = _ref.bucketEnvironment,
75
74
  buildRevision = _ref.buildRevision,
76
75
  buildNumber = _ref.buildNumber,
77
76
  applicationIndexOutFile = _ref.applicationIndexOutFile;
78
- const uploadScriptContent = _concatInstanceProperty__default["default"](_context = _concatInstanceProperty__default["default"](_context2 = _concatInstanceProperty__default["default"](_context3 = _concatInstanceProperty__default["default"](_context4 = _concatInstanceProperty__default["default"](_context5 = _concatInstanceProperty__default["default"](_context6 = _concatInstanceProperty__default["default"](_context7 = _concatInstanceProperty__default["default"](_context8 = _concatInstanceProperty__default["default"](_context9 = _concatInstanceProperty__default["default"](_context10 = "#!/usr/bin/env bash\n\nset -e\n\necho \"Uploading compiled ".concat(applicationIndexOutFile, " to bucket ")).call(_context10, bucketUrl, "\"\ngcloud storage cp \\\n \"$(dirname \"$0\")/")).call(_context9, applicationIndexOutFile, "\" \\\n \"")).call(_context8, bucketUrl, "/\" \\\n -z html \\\n --content-type=\"text/html\" \\\n --cache-control=\"public,max-age=0,no-transform\"\n\necho \"Creating version.json and uploading it to bucket ")).call(_context7, bucketUrl, "\"\n\nNODE_ENV=production ")).call(_context6, packageManagerName, " application-cli create-version \\\n --version-url=")).call(_context5, cdnUrl, "/")).call(_context4, cloudEnvironment, "/version.json \\\n --build-revision=")).call(_context3, buildRevision, " \\\n --build-number=")).call(_context2, buildNumber, " \\\n --out-file=$(dirname \"$0\")/version.json\n\ngcloud storage cp \\\n \"$(dirname \"$0\")/version.json\" \\\n \"")).call(_context, bucketUrl, "/\" \\\n -z json \\\n --content-type=\"application/json\" \\\n --cache-control=\"public,max-age=0,no-transform\"\n");
77
+ const uploadScriptContent = `#!/usr/bin/env bash
78
+
79
+ set -e
80
+
81
+ echo "Uploading compiled ${applicationIndexOutFile} to bucket ${bucketUrl}"
82
+ gcloud storage cp \\
83
+ "$(dirname "$0")/${applicationIndexOutFile}" \\
84
+ "${bucketUrl}/" \\
85
+ -z html \\
86
+ --content-type="text/html" \\
87
+ --cache-control="public,max-age=0,no-transform"
88
+
89
+ echo "Creating version.json and uploading it to bucket ${bucketUrl}"
90
+
91
+ NODE_ENV=production ${packageManagerName} application-cli create-version \\
92
+ --version-url=${cdnUrl}/${bucketEnvironment}/version.json \\
93
+ --build-revision=${buildRevision} \\
94
+ --build-number=${buildNumber} \\
95
+ --out-file=$(dirname "$0")/version.json
96
+
97
+ gcloud storage cp \\
98
+ "$(dirname "$0")/version.json" \\
99
+ "${bucketUrl}/" \\
100
+ -z json \\
101
+ --content-type="application/json" \\
102
+ --cache-control="public,max-age=0,no-transform"
103
+ `;
79
104
  return uploadScriptContent;
80
105
  }
81
106
 
82
107
  function createApplicationAssetsUploadScript(_ref) {
83
- var _context, _context2, _context3, _context4, _context5, _context6;
84
108
  let bucketUrl = _ref.bucketUrl,
85
109
  assetsPath = _ref.assetsPath,
86
110
  skipMenu = _ref.skipMenu;
87
- const uploadScriptContent = _concatInstanceProperty__default["default"](_context = _concatInstanceProperty__default["default"](_context2 = _concatInstanceProperty__default["default"](_context3 = _concatInstanceProperty__default["default"](_context4 = _concatInstanceProperty__default["default"](_context5 = _concatInstanceProperty__default["default"](_context6 = "#!/usr/bin/env bash\n\nset -e\n\n# NOTES:\n# https://cloud.google.com/sdk/gcloud/reference/storage/cp\n# 1. The '-z' option triggers compressing the assets before\n# uploading them and sets the 'Content-Encoding' to 'gzip'.\n# 2. The 'Accept-encoding: gzip' is set automatically by the 'gcloud storage'.\n# 3. The 'max-age' is set to 1 year which is considered the maximum\n# \"valid\" lifetime of an asset to be cached.\n# 4. The '-n' will skip uploading existing files and prevents them to\n# be overwritten\necho \"Uploading static assets to bucket ".concat(bucketUrl, "\"\n\ngcloud storage cp \\\n ")).call(_context6, assetsPath, "/public/{*.css,*.js,*.js.map,*.png,*.html,robots.txt} \\\n \"")).call(_context5, bucketUrl, "\" \\\n -n \\\n -z js,css \\\n --cache-control=\"public,max-age=31536000,no-transform\"\n\nif ")).call(_context4, skipMenu, "; then\n echo \"Skipping menu.json upload\"\nelse\n echo \"Uploading menu.json to bucket ")).call(_context3, bucketUrl, "\"\n # NOTE: somehow the 'cache-control:private' doesn't work.\n # I mean, the file is uploaded with the correct metadata but when I fetch\n # the file the response contains the header\n # 'cache-control: public,max-age=31536000,no-transform', even though the\n # documentation clearly states that by marking the header as 'private' will\n # disable the cache (for publicly readable objects).\n # https://cloud.google.com/storage/docs/gsutil/addlhelp/WorkingWithObjectMetadata#cache-control\n # However, I found out that, by requesting the file with any RANDOM\n # query parameter, will instruct the storage to return a 'fresh' object\n # (without any cache control).\n # Unofficial source: https://stackoverflow.com/a/49052895\n # This seems to be the 'easiest' option to 'disable' the cache for public\n # objects. Other alternative approaces are:\n # * make the object private with some simple ACL (private objects are not cached)\n # * suffix the file name with e.g. the git SHA, so we have different files\n # for each upload ('index.html.template-${CIRCLE_SHA1}'). The server knows\n # the git SHA on runtime and can get the correct file when it starts.\n # * find out why the 'private' cache control does not work\n gcloud storage cp \\\n ")).call(_context2, assetsPath, "/menu.json \\\n ")).call(_context, bucketUrl, " \\\n -z json \\\n --content-type=\"application/json\" \\\n --cache-control=\"public,max-age=0,no-transform\"\nfi\n");
111
+ const uploadScriptContent = `#!/usr/bin/env bash
112
+
113
+ set -e
114
+
115
+ # NOTES:
116
+ # https://cloud.google.com/sdk/gcloud/reference/storage/cp
117
+ # 1. The '-z' option triggers compressing the assets before
118
+ # uploading them and sets the 'Content-Encoding' to 'gzip'.
119
+ # 2. The 'Accept-encoding: gzip' is set automatically by the 'gcloud storage'.
120
+ # 3. The 'max-age' is set to 1 year which is considered the maximum
121
+ # "valid" lifetime of an asset to be cached.
122
+ # 4. The '-n' will skip uploading existing files and prevents them to
123
+ # be overwritten
124
+ echo "Uploading static assets to bucket ${bucketUrl}"
125
+
126
+ gcloud storage cp \\
127
+ ${assetsPath}/public/{*.css,*.js,*.js.map,*.png,*.html,robots.txt} \\
128
+ "${bucketUrl}" \\
129
+ -n \\
130
+ -z js,css \\
131
+ --cache-control="public,max-age=31536000,no-transform"
132
+
133
+ if ${skipMenu}; then
134
+ echo "Skipping menu.json upload"
135
+ else
136
+ echo "Uploading menu.json to bucket ${bucketUrl}"
137
+ # NOTE: somehow the 'cache-control:private' doesn't work.
138
+ # I mean, the file is uploaded with the correct metadata but when I fetch
139
+ # the file the response contains the header
140
+ # 'cache-control: public,max-age=31536000,no-transform', even though the
141
+ # documentation clearly states that by marking the header as 'private' will
142
+ # disable the cache (for publicly readable objects).
143
+ # https://cloud.google.com/storage/docs/gsutil/addlhelp/WorkingWithObjectMetadata#cache-control
144
+ # However, I found out that, by requesting the file with any RANDOM
145
+ # query parameter, will instruct the storage to return a 'fresh' object
146
+ # (without any cache control).
147
+ # Unofficial source: https://stackoverflow.com/a/49052895
148
+ # This seems to be the 'easiest' option to 'disable' the cache for public
149
+ # objects. Other alternative approaces are:
150
+ # * make the object private with some simple ACL (private objects are not cached)
151
+ # * suffix the file name with e.g. the git SHA, so we have different files
152
+ # for each upload ('index.html.template-\${CIRCLE_SHA1}'). The server knows
153
+ # the git SHA on runtime and can get the correct file when it starts.
154
+ # * find out why the 'private' cache control does not work
155
+ gcloud storage cp \\
156
+ ${assetsPath}/menu.json \\
157
+ ${bucketUrl} \\
158
+ -z json \\
159
+ --content-type="application/json" \\
160
+ --cache-control="public,max-age=0,no-transform"
161
+ fi
162
+ `;
88
163
  return uploadScriptContent;
89
164
  }
90
165
 
91
166
  function ownKeys$3(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; }
92
- function _objectSpread$3(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context2 = ownKeys$3(Object(t), !0)).call(_context2, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context3 = ownKeys$3(Object(t))).call(_context3, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
167
+ function _objectSpread$3(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$3(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$3(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
93
168
  function loadDotenvFiles(_ref) {
94
169
  let dotenvPath = _ref.dotenvPath,
95
170
  cloudEnvironment = _ref.cloudEnvironment;
@@ -100,12 +175,12 @@ function loadDotenvFiles(_ref) {
100
175
 
101
176
  // Check if the given path exists.
102
177
  if (!fs__default["default"].existsSync(dotenvPath)) {
103
- throw new Error("The dotenv folder path does not exist: \"".concat(dotenvPath, "\"."));
178
+ throw new Error(`The dotenv folder path does not exist: "${dotenvPath}".`);
104
179
  }
105
180
 
106
181
  // Load the environment values
107
182
  const sharedDotenvFile = '.env.production';
108
- const cloudDotenvFile = ".env.".concat(cloudEnvironment);
183
+ const cloudDotenvFile = `.env.${cloudEnvironment}`;
109
184
 
110
185
  // The shared dotenv file across environments is optional
111
186
  const sharedProductionEnvironment = dotenv__default["default"].config({
@@ -117,18 +192,23 @@ function loadDotenvFiles(_ref) {
117
192
  path: path__default["default"].join(dotenvPath, cloudDotenvFile)
118
193
  });
119
194
  if (cloudSpecificProductionEnvironment.error) {
120
- var _context;
121
- throw new Error(_concatInstanceProperty__default["default"](_context = "Failed loading '".concat(cloudDotenvFile, "' in '")).call(_context, dotenvPath, "'. Make sure it exists."));
195
+ throw new Error(`Failed loading '${cloudDotenvFile}' in '${dotenvPath}'. Make sure it exists.`);
122
196
  }
123
197
  if (sharedProductionEnvironment.error) {
124
- throw new Error("Failed loading '".concat(sharedDotenvFile, "' in '").concat(dotenvPath, "'. Make sure it exists."));
198
+ throw new Error(`Failed loading '${sharedDotenvFile}' in '${dotenvPath}'. Make sure it exists.`);
125
199
  }
126
200
  return _objectSpread$3(_objectSpread$3({}, sharedProductionEnvironment.parsed), cloudSpecificProductionEnvironment.parsed);
127
201
  }
128
202
 
129
203
  function ownKeys$2(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; }
130
- function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var _context8, _context9; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context8 = ownKeys$2(Object(t), !0)).call(_context8, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context9 = ownKeys$2(Object(t))).call(_context9, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
204
+ function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var _context5, _context6; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context5 = ownKeys$2(Object(t), !0)).call(_context5, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context6 = ownKeys$2(Object(t))).call(_context6, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
131
205
  const buckedConfigExplorer = cosmiconfig.cosmiconfig('google-storage-buckets');
206
+ function assertCollapsedBucketEnvironmentConfig(bucketEnvironmentConfigOrBucketEnvironment) {
207
+ return typeof bucketEnvironmentConfigOrBucketEnvironment == 'string';
208
+ }
209
+ function assertExpandedBucketEnvironmentConfig(bucketEnvironmentConfigOrBucketEnvironment) {
210
+ return typeof bucketEnvironmentConfigOrBucketEnvironment == 'object' && typeof bucketEnvironmentConfigOrBucketEnvironment.cloudEnvironment == 'string' && typeof bucketEnvironmentConfigOrBucketEnvironment.bucketEnvironment == 'string';
211
+ }
132
212
  function writeUploadScriptFile(_ref) {
133
213
  let fileName = _ref.fileName,
134
214
  fileContent = _ref.fileContent,
@@ -142,7 +222,7 @@ function writeUploadScriptFile(_ref) {
142
222
  function getBucketNamespace(prNumber) {
143
223
  if (!prNumber) return;
144
224
  if (prNumber === 'merchant-center-preview') return prNumber;
145
- return "mc-".concat(prNumber);
225
+ return `mc-${prNumber}`;
146
226
  }
147
227
 
148
228
  /**
@@ -160,32 +240,30 @@ function getApplicationAssetsBucketUrl(_ref2) {
160
240
  let bucketRegion = _ref2.bucketRegion,
161
241
  prNumber = _ref2.prNumber,
162
242
  applicationName = _ref2.applicationName;
163
- const applicationAssetsBucketUrl = _filterInstanceProperty__default["default"](_context = ["gs://".concat(bucketRegion), getBucketNamespace(prNumber), applicationName]).call(_context, Boolean);
243
+ const applicationAssetsBucketUrl = _filterInstanceProperty__default["default"](_context = [`gs://${bucketRegion}`, getBucketNamespace(prNumber), applicationName]).call(_context, Boolean);
164
244
  return applicationAssetsBucketUrl.join('/');
165
245
  }
166
246
  function getApplicationIndexBucketUrl(_ref3) {
167
- var _context2;
168
247
  let bucketRegion = _ref3.bucketRegion,
169
248
  prNumber = _ref3.prNumber,
170
249
  applicationName = _ref3.applicationName,
171
- cloudEnvironment = _ref3.cloudEnvironment;
250
+ bucketEnvironment = _ref3.bucketEnvironment;
172
251
  const applicationAssetsBucketUrl = getApplicationAssetsBucketUrl({
173
252
  bucketRegion,
174
253
  prNumber,
175
254
  applicationName
176
255
  });
177
- const applicationIndexBucketUrl = _concatInstanceProperty__default["default"](_context2 = "".concat(applicationAssetsBucketUrl, "/")).call(_context2, cloudEnvironment);
256
+ const applicationIndexBucketUrl = `${applicationAssetsBucketUrl}/${bucketEnvironment}`;
178
257
  return applicationIndexBucketUrl;
179
258
  }
180
259
  function getCdnUrl(_ref4) {
181
- var _context3;
260
+ var _context2;
182
261
  let bucketRegion = _ref4.bucketRegion,
183
262
  prNumber = _ref4.prNumber,
184
263
  applicationName = _ref4.applicationName;
185
- return _filterInstanceProperty__default["default"](_context3 = ["https://storage.googleapis.com/".concat(bucketRegion), getBucketNamespace(prNumber), applicationName]).call(_context3, Boolean).join('/');
264
+ return _filterInstanceProperty__default["default"](_context2 = [`https://storage.googleapis.com/${bucketRegion}`, getBucketNamespace(prNumber), applicationName]).call(_context2, Boolean).join('/');
186
265
  }
187
266
  async function compileApplicationAssets(_ref5) {
188
- var _context4, _context5;
189
267
  let cliFlags = _ref5.cliFlags,
190
268
  bucketRegion = _ref5.bucketRegion,
191
269
  paths = _ref5.paths;
@@ -199,7 +277,7 @@ async function compileApplicationAssets(_ref5) {
199
277
  skipMenu: cliFlags.skipMenu
200
278
  });
201
279
  const parsedApplicationAssetsUploadScriptFile = path__default["default"].parse(cliFlags.applicationAssetsUploadScriptOutFile);
202
- const applicationAssetsUploadScriptFileName = _concatInstanceProperty__default["default"](_context4 = _concatInstanceProperty__default["default"](_context5 = "".concat(parsedApplicationAssetsUploadScriptFile.name, "-")).call(_context5, bucketRegion)).call(_context4, parsedApplicationAssetsUploadScriptFile.ext);
280
+ const applicationAssetsUploadScriptFileName = `${parsedApplicationAssetsUploadScriptFile.name}-${bucketRegion}${parsedApplicationAssetsUploadScriptFile.ext}`;
203
281
  writeUploadScriptFile({
204
282
  fileName: applicationAssetsUploadScriptFileName,
205
283
  fileContent: applicationAssetsUploadScriptContent,
@@ -210,7 +288,8 @@ async function compileEnvironmentApplicationIndexes(_ref6) {
210
288
  let cliFlags = _ref6.cliFlags,
211
289
  paths = _ref6.paths,
212
290
  bucketRegion = _ref6.bucketRegion,
213
- cloudEnvironment = _ref6.cloudEnvironment;
291
+ cloudEnvironment = _ref6.cloudEnvironment,
292
+ bucketEnvironment = _ref6.bucketEnvironment;
214
293
  const cloudEnvironmentDeploymentPath = path__default["default"].join(paths.deploymentsPath, cloudEnvironment);
215
294
  // Ensure the folder exists
216
295
  const createDeploymentsFolderResult = await execa__default["default"]('mkdir', ['-p', cloudEnvironmentDeploymentPath], {
@@ -232,7 +311,7 @@ async function compileEnvironmentApplicationIndexes(_ref6) {
232
311
  })), {}, {
233
312
  // The trailing slash is important to indicate to the CSP directive that all the resources
234
313
  // under that path should be allowed.
235
- MC_CDN_URL: "".concat(cdnUrl, "/")
314
+ MC_CDN_URL: `${cdnUrl}/`
236
315
  }, cliFlags.mcUrl ? {
237
316
  MC_URL: cliFlags.mcUrl
238
317
  } : {}), cliFlags.mcApiUrl ? {
@@ -270,10 +349,10 @@ async function compileEnvironmentApplicationIndexes(_ref6) {
270
349
  bucketRegion,
271
350
  prNumber: cliFlags.prNumber,
272
351
  applicationName: cliFlags.applicationName,
273
- cloudEnvironment
352
+ bucketEnvironment
274
353
  }),
275
354
  cdnUrl,
276
- cloudEnvironment,
355
+ bucketEnvironment,
277
356
  buildRevision: cliFlags.buildRevision,
278
357
  buildNumber: cliFlags.buildNumber,
279
358
  applicationIndexOutFile: cliFlags.applicationIndexOutFile
@@ -294,7 +373,7 @@ async function compileEnvironmentApplicationIndexes(_ref6) {
294
373
  }
295
374
  }
296
375
  async function command$3(cliFlags, cwd) {
297
- var _context6;
376
+ var _context3;
298
377
  let cloudEnvironmentsGroupedByBucketRegions;
299
378
  try {
300
379
  // This is the list of the supported cloud environments and their related bucket location.
@@ -319,24 +398,36 @@ async function command$3(cliFlags, cwd) {
319
398
  dotenvPath: cliFlags.dotenvFolder && path__default["default"].join(monorepoRoot.rootDir, cliFlags.dotenvFolder),
320
399
  assetsPath
321
400
  };
322
- const taskList = new listr2.Listr(_mapInstanceProperty__default["default"](_context6 = _Object$entries__default["default"](cloudEnvironmentsGroupedByBucketRegions.config)).call(_context6, _ref7 => {
401
+ const taskList = new listr2.Listr(_mapInstanceProperty__default["default"](_context3 = _Object$entries__default["default"](cloudEnvironmentsGroupedByBucketRegions.config)).call(_context3, _ref7 => {
323
402
  let _ref8 = _slicedToArray(_ref7, 2),
324
403
  bucketRegion = _ref8[0],
325
- cloudEnvironments = _ref8[1];
404
+ bucketEnvironmentConfigs = _ref8[1];
326
405
  return {
327
- title: "Compiling application for bucket ".concat(bucketRegion),
406
+ title: `Compiling for bucket region ${bucketRegion}`,
328
407
  task: () => {
329
- var _context7;
330
- return new listr2.Listr(_concatInstanceProperty__default["default"](_context7 = _mapInstanceProperty__default["default"](cloudEnvironments).call(cloudEnvironments, cloudEnvironment => ({
331
- title: "Compiling ".concat(cloudEnvironment, " application index"),
332
- task: () => compileEnvironmentApplicationIndexes({
333
- cliFlags,
334
- paths,
335
- bucketRegion,
336
- cloudEnvironment
337
- })
338
- }))).call(_context7, {
339
- title: "Compiling application assets",
408
+ var _context4;
409
+ return new listr2.Listr(_concatInstanceProperty__default["default"](_context4 = _mapInstanceProperty__default["default"](bucketEnvironmentConfigs).call(bucketEnvironmentConfigs, bucketEnvironmentConfigOrBucketEnvironment => {
410
+ let cloudEnvironment = '';
411
+ let bucketEnvironment = '';
412
+ if (assertExpandedBucketEnvironmentConfig(bucketEnvironmentConfigOrBucketEnvironment)) {
413
+ cloudEnvironment = bucketEnvironmentConfigOrBucketEnvironment.cloudEnvironment;
414
+ bucketEnvironment = bucketEnvironmentConfigOrBucketEnvironment.bucketEnvironment;
415
+ } else if (assertCollapsedBucketEnvironmentConfig(bucketEnvironmentConfigOrBucketEnvironment)) {
416
+ cloudEnvironment = bucketEnvironmentConfigOrBucketEnvironment;
417
+ bucketEnvironment = bucketEnvironmentConfigOrBucketEnvironment;
418
+ }
419
+ return {
420
+ title: `Compiling application index for environment ${cloudEnvironment} and bucket ${bucketEnvironment}`,
421
+ task: () => compileEnvironmentApplicationIndexes({
422
+ cliFlags,
423
+ paths,
424
+ bucketRegion,
425
+ cloudEnvironment,
426
+ bucketEnvironment
427
+ })
428
+ };
429
+ })).call(_context4, {
430
+ title: `Compiling application assets`,
340
431
  task: () => compileApplicationAssets({
341
432
  cliFlags,
342
433
  bucketRegion,
@@ -381,58 +472,52 @@ const mapLabelAllLocalesWithDefaults = (labelAllLocales, defaultLabel) => {
381
472
  */
382
473
 
383
474
  const mapApplicationMenuConfigToGraqhQLMenuJson = config => {
384
- var _ref, _config$env$__DEVELOP, _config$env$__DEVELOP2, _menuLinks$featureTog, _menuLinks$menuVisibi, _menuLinks$actionRigh, _menuLinks$dataFences, _context2, _menuLinks$shouldRend;
475
+ var _context2;
385
476
  const entryPointUriPath = config.env.entryPointUriPath;
386
477
 
387
478
  // @ts-expect-error: the `accountLinks` is not explicitly typed as it's only used by the account app.
388
- const accountLinks = (_ref = (_config$env$__DEVELOP = config.env.__DEVELOPMENT__) === null || _config$env$__DEVELOP === void 0 ? void 0 : _config$env$__DEVELOP.accountLinks) !== null && _ref !== void 0 ? _ref : [];
479
+ const accountLinks = config.env.__DEVELOPMENT__?.accountLinks ?? [];
389
480
  if (accountLinks.length > 0) {
390
- return _mapInstanceProperty__default["default"](accountLinks).call(accountLinks, menuLink => {
391
- var _menuLink$permissions, _menuLink$featureTogg;
392
- return {
393
- key: menuLink.uriPath,
394
- uriPath: menuLink.uriPath,
395
- labelAllLocales: mapLabelAllLocalesWithDefaults(menuLink.labelAllLocales, menuLink.defaultLabel),
396
- permissions: (_menuLink$permissions = menuLink.permissions) !== null && _menuLink$permissions !== void 0 ? _menuLink$permissions : [],
397
- // @ts-ignore: not defined in schema, as it's only used internally.
398
- featureToggle: (_menuLink$featureTogg = menuLink.featureToggle) !== null && _menuLink$featureTogg !== void 0 ? _menuLink$featureTogg : null
399
- };
400
- });
481
+ return _mapInstanceProperty__default["default"](accountLinks).call(accountLinks, menuLink => ({
482
+ key: menuLink.uriPath,
483
+ uriPath: menuLink.uriPath,
484
+ labelAllLocales: mapLabelAllLocalesWithDefaults(menuLink.labelAllLocales, menuLink.defaultLabel),
485
+ permissions: menuLink.permissions ?? [],
486
+ // @ts-ignore: not defined in schema, as it's only used internally.
487
+ featureToggle: menuLink.featureToggle ?? null
488
+ }));
401
489
  }
402
- const menuLinks = (_config$env$__DEVELOP2 = config.env.__DEVELOPMENT__) === null || _config$env$__DEVELOP2 === void 0 ? void 0 : _config$env$__DEVELOP2.menuLinks;
490
+ const menuLinks = config.env.__DEVELOPMENT__?.menuLinks;
403
491
  return {
404
492
  key: entryPointUriPath,
405
493
  uriPath: entryPointUriPath,
406
494
  icon: menuLinks.icon,
407
- labelAllLocales: mapLabelAllLocalesWithDefaults(menuLinks === null || menuLinks === void 0 ? void 0 : menuLinks.labelAllLocales, menuLinks === null || menuLinks === void 0 ? void 0 : menuLinks.defaultLabel),
495
+ labelAllLocales: mapLabelAllLocalesWithDefaults(menuLinks?.labelAllLocales, menuLinks?.defaultLabel),
408
496
  permissions: menuLinks.permissions,
409
497
  // @ts-ignore: not defined in schema, as it's only used internally.
410
- featureToggle: (_menuLinks$featureTog = menuLinks.featureToggle) !== null && _menuLinks$featureTog !== void 0 ? _menuLinks$featureTog : null,
498
+ featureToggle: menuLinks.featureToggle ?? null,
411
499
  // @ts-ignore: not defined in schema, as it's only used internally.
412
- menuVisibility: (_menuLinks$menuVisibi = menuLinks.menuVisibility) !== null && _menuLinks$menuVisibi !== void 0 ? _menuLinks$menuVisibi : null,
500
+ menuVisibility: menuLinks.menuVisibility ?? null,
413
501
  // @ts-ignore: not defined in schema, as it's only used internally.
414
- actionRights: (_menuLinks$actionRigh = menuLinks.actionRights) !== null && _menuLinks$actionRigh !== void 0 ? _menuLinks$actionRigh : null,
502
+ actionRights: menuLinks.actionRights ?? null,
415
503
  // @ts-ignore: not defined in schema, as it's only used internally.
416
- dataFences: (_menuLinks$dataFences = menuLinks.dataFences) !== null && _menuLinks$dataFences !== void 0 ? _menuLinks$dataFences : null,
417
- submenu: _mapInstanceProperty__default["default"](_context2 = menuLinks.submenuLinks).call(_context2, submenuLink => {
418
- var _submenuLink$featureT, _submenuLink$menuVisi, _submenuLink$actionRi, _submenuLink$dataFenc;
419
- return {
420
- key: submenuLink.uriPath.replace('/', '-'),
421
- uriPath: submenuLink.uriPath,
422
- labelAllLocales: mapLabelAllLocalesWithDefaults(submenuLink.labelAllLocales, submenuLink.defaultLabel),
423
- permissions: submenuLink.permissions,
424
- // @ts-ignore: not defined in schema, as it's only used internally.
425
- featureToggle: (_submenuLink$featureT = submenuLink.featureToggle) !== null && _submenuLink$featureT !== void 0 ? _submenuLink$featureT : null,
426
- // @ts-ignore: not defined in schema, as it's only used internally.
427
- menuVisibility: (_submenuLink$menuVisi = submenuLink.menuVisibility) !== null && _submenuLink$menuVisi !== void 0 ? _submenuLink$menuVisi : null,
428
- // @ts-ignore: not defined in schema, as it's only used internally.
429
- actionRights: (_submenuLink$actionRi = submenuLink.actionRights) !== null && _submenuLink$actionRi !== void 0 ? _submenuLink$actionRi : null,
430
- // @ts-ignore: not defined in schema, as it's only used internally.
431
- dataFences: (_submenuLink$dataFenc = submenuLink.dataFences) !== null && _submenuLink$dataFenc !== void 0 ? _submenuLink$dataFenc : null
432
- };
433
- }),
504
+ dataFences: menuLinks.dataFences ?? null,
505
+ submenu: _mapInstanceProperty__default["default"](_context2 = menuLinks.submenuLinks).call(_context2, submenuLink => ({
506
+ key: submenuLink.uriPath.replace('/', '-'),
507
+ uriPath: submenuLink.uriPath,
508
+ labelAllLocales: mapLabelAllLocalesWithDefaults(submenuLink.labelAllLocales, submenuLink.defaultLabel),
509
+ permissions: submenuLink.permissions,
510
+ // @ts-ignore: not defined in schema, as it's only used internally.
511
+ featureToggle: submenuLink.featureToggle ?? null,
512
+ // @ts-ignore: not defined in schema, as it's only used internally.
513
+ menuVisibility: submenuLink.menuVisibility ?? null,
514
+ // @ts-ignore: not defined in schema, as it's only used internally.
515
+ actionRights: submenuLink.actionRights ?? null,
516
+ // @ts-ignore: not defined in schema, as it's only used internally.
517
+ dataFences: submenuLink.dataFences ?? null
518
+ })),
434
519
  // @ts-ignore: not defined in schema, as it's only used internally.
435
- shouldRenderDivider: (_menuLinks$shouldRend = menuLinks.shouldRenderDivider) !== null && _menuLinks$shouldRend !== void 0 ? _menuLinks$shouldRend : false
520
+ shouldRenderDivider: menuLinks.shouldRenderDivider ?? false
436
521
  };
437
522
  };
438
523
  async function command$2(cliFlags, cwd) {
@@ -443,7 +528,7 @@ async function command$2(cliFlags, cwd) {
443
528
  dotenvPath,
444
529
  // The env itself is not important for the menu. However, the application config
445
530
  // uses environment placeholders and therefore we need to provide the variables for it.
446
- cloudEnvironment: 'ctp-gcp-staging'
531
+ cloudEnvironment: 'ctp_staging_gcp_europe-west1_v1'
447
532
  })), {}, {
448
533
  // Again, make sure that the environment is "development", otherwise
449
534
  // the menu config won't be available.
@@ -612,15 +697,15 @@ function validateMenu(menuJson) {
612
697
  async function command(cliFlags) {
613
698
  const menuJsonPath = cliFlags.inputFile;
614
699
  const isAppbarMenu = cliFlags.navigation === 'top';
615
- if (!menuJsonPath) throw new Error("--input-file cannot be empty. please provide the path of compiled menu.json");
616
- if (!fs__default["default"].existsSync(menuJsonPath)) throw new Error("The menu.json file doesn't exist: ".concat(menuJsonPath));
700
+ if (!menuJsonPath) throw new Error(`--input-file cannot be empty. please provide the path of compiled menu.json`);
701
+ if (!fs__default["default"].existsSync(menuJsonPath)) throw new Error(`The menu.json file doesn't exist: ${menuJsonPath}`);
617
702
  const menuJson = fs__default["default"].readFileSync(menuJsonPath, 'utf-8');
618
703
  return validateMenu(JSON.parse(menuJson), isAppbarMenu ? appbarMenuSchema : navbarMenuSchema);
619
704
  }
620
705
 
621
706
  var pkgJson = {
622
707
  name: "@commercetools-frontend/application-cli",
623
- version: "1.7.3",
708
+ version: "1.8.0",
624
709
  description: "Internal CLI to manage Merchant Center application deployments across various environments.",
625
710
  keywords: [
626
711
  "commercetools",
@@ -645,9 +730,9 @@ var pkgJson = {
645
730
  "@babel/core": "^7.22.11",
646
731
  "@babel/runtime": "^7.21.0",
647
732
  "@babel/runtime-corejs3": "^7.21.0",
648
- "@commercetools-frontend/application-config": "22.8.2",
649
- "@commercetools-frontend/constants": "22.8.2",
650
- "@commercetools-frontend/l10n": "22.8.2",
733
+ "@commercetools-frontend/application-config": "22.11.0",
734
+ "@commercetools-frontend/constants": "22.11.0",
735
+ "@commercetools-frontend/l10n": "22.11.0",
651
736
  "@manypkg/find-root": "2.2.1",
652
737
  cac: "^6.7.14",
653
738
  cosmiconfig: "8.3.6",
@@ -672,7 +757,8 @@ var pkgJson = {
672
757
  },
673
758
  preconstruct: {
674
759
  entrypoints: [
675
- "./cli.ts"
760
+ "./cli.ts",
761
+ "./index.ts"
676
762
  ]
677
763
  }
678
764
  };
@@ -691,7 +777,7 @@ const run = async () => {
691
777
  // Default command
692
778
  cli.command('').usage('\n\n Compile deployments and menus and create versions for MC applications').action(cli.outputHelp);
693
779
  const usageCompileDeployment = 'Compile the deployments for an application for all environments.';
694
- cli.command('compile-deployments', usageCompileDeployment).usage("compile-deployments \n\n ".concat(usageCompileDeployment)).option('--application-name <string>', '(required) The name of the application being compiled for example application-products.').option('--dotenv-folder [string]', '(optional) The path to a folder containing a dotenv file ".env.production" and a cloud-environment specific dotenv file (for example ".env.gcp-production-eu"). Those values are parsed and merged together to be used by the `mc-scripts compile-html` command.').option('--pr-number [string]', '(optional) A pull request number determining a scoped storage bucket for the deployment. Please use it carefully.').option('--mc-url [string]', '(optional) The MC URL of the deployment. This is usually inferred from the env file and overwrites the value. Please use it carefully.').option('--mc-api-url [string]', '(optional) The MC API URL of the deployment. This is usually inferred from the env file and overwrites the value. Please use it carefully.').option('--application-index-out-file [path]', '(optional) The name of the application index file.', {
780
+ cli.command('compile-deployments', usageCompileDeployment).usage(`compile-deployments \n\n ${usageCompileDeployment}`).option('--application-name <string>', '(required) The name of the application being compiled for example application-products.').option('--dotenv-folder [string]', '(optional) The path to a folder containing a dotenv file ".env.production" and a cloud-environment specific dotenv file (for example ".env.gcp-production-eu"). Those values are parsed and merged together to be used by the `mc-scripts compile-html` command.').option('--pr-number [string]', '(optional) A pull request number determining a scoped storage bucket for the deployment. Please use it carefully.').option('--mc-url [string]', '(optional) The MC URL of the deployment. This is usually inferred from the env file and overwrites the value. Please use it carefully.').option('--mc-api-url [string]', '(optional) The MC API URL of the deployment. This is usually inferred from the env file and overwrites the value. Please use it carefully.').option('--application-index-out-file [path]', '(optional) The name of the application index file.', {
695
781
  default: 'application.html'
696
782
  }).option('--application-index-upload-script-out-file [path]', '(optional) The name of the the application index upload script file.', {
697
783
  default: 'upload-index.sh'
@@ -703,15 +789,15 @@ const run = async () => {
703
789
  await command$3(options, cwd);
704
790
  });
705
791
  const usageCompileMenu = 'Compile the menu links of an application into a `menu.json`. This is only required for internal applications';
706
- cli.command('compile-menu', usageCompileMenu).usage("compile-menu \n\n ".concat(usageCompileMenu)).option('--dotenv-folder [string]', '(optional) The path to a folder containing a dotenv file `.env.production` and a cloud-environment specific dotenv file (for example `.env.gcp-production-eu`). Those values are parsed and merged together to be used by the application config.').action(async options => {
792
+ cli.command('compile-menu', usageCompileMenu).usage(`compile-menu \n\n ${usageCompileMenu}`).option('--dotenv-folder [string]', '(optional) The path to a folder containing a dotenv file `.env.production` and a cloud-environment specific dotenv file (for example `.env.gcp-production-eu`). Those values are parsed and merged together to be used by the application config.').action(async options => {
707
793
  await command$2(options, cwd);
708
794
  });
709
795
  const usageValidateMenu = 'Validate compiled `menu.json` file';
710
- cli.command('validate-menu', usageValidateMenu).usage("validate-menu \n\n ".concat(usageValidateMenu)).option('--input-file <path>', '(required) The path to the `menu.json` file to be validated.').option('--navigation [string]', '(optional) Location of the menu navigation. Possible values are `top`.').action(async options => {
796
+ cli.command('validate-menu', usageValidateMenu).usage(`validate-menu \n\n ${usageValidateMenu}`).option('--input-file <path>', '(required) The path to the `menu.json` file to be validated.').option('--navigation [string]', '(optional) Location of the menu navigation. Possible values are `top`.').action(async options => {
711
797
  await command(options);
712
798
  });
713
799
  const usageCreateVersion = 'Output a JSON string about the information in the `version.json` for a deployment, including the updated list of rollbacks.';
714
- cli.command('create-version', usageCreateVersion).usage("create-version \n\n ".concat(usageCreateVersion)).option('--version-url <url>', "(required) The path of an application's current `version.json` within the storage bucket.").option('--rollbacks [int]', '(optional) The number of max rollbacks to keep', {
800
+ cli.command('create-version', usageCreateVersion).usage(`create-version \n\n ${usageCreateVersion}`).option('--version-url <url>', "(required) The path of an application's current `version.json` within the storage bucket.").option('--rollbacks [int]', '(optional) The number of max rollbacks to keep', {
715
801
  default: 15
716
802
  }).option('--out-file [path]', '(optional) The path to the file where to write the JSON. If not specified, the JSON is printed to stdout.').action(async options => {
717
803
  await command$1(options);