@commercetools-frontend/application-cli 1.4.0 → 1.6.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.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +9 -0
  3. package/cli/dist/commercetools-frontend-application-cli-cli.cjs.d.ts +2 -0
  4. package/cli/dist/commercetools-frontend-application-cli-cli.cjs.d.ts.map +1 -0
  5. package/cli/dist/commercetools-frontend-application-cli-cli.cjs.dev.js +725 -0
  6. package/cli/dist/commercetools-frontend-application-cli-cli.cjs.js +7 -0
  7. package/cli/dist/commercetools-frontend-application-cli-cli.cjs.prod.js +725 -0
  8. package/cli/dist/commercetools-frontend-application-cli-cli.esm.js +699 -0
  9. package/cli/package.json +4 -0
  10. package/dist/declarations/src/cli.d.ts +2 -0
  11. package/dist/declarations/src/commands/compile-deployments.d.ts +3 -0
  12. package/dist/declarations/src/commands/compile-menu.d.ts +3 -0
  13. package/dist/declarations/src/commands/create-version.d.ts +3 -0
  14. package/dist/declarations/src/commands/validate-menu.d.ts +5 -0
  15. package/dist/declarations/src/schema.d.ts +228 -0
  16. package/dist/declarations/src/types.d.ts +92 -0
  17. package/dist/declarations/src/utils/create-application-assets-upload-script.d.ts +3 -0
  18. package/dist/declarations/src/utils/create-application-index-upload-script.d.ts +3 -0
  19. package/dist/declarations/src/utils/get-application-directory.d.ts +2 -0
  20. package/dist/declarations/src/utils/is-ci.d.ts +2 -0
  21. package/dist/declarations/src/utils/load-dotenv-files.d.ts +5 -0
  22. package/dist/declarations/src/utils/resolve-in-application.d.ts +2 -0
  23. package/package.json +31 -13
  24. package/src/bin/cli.js +0 -100
  25. package/src/commands/compile-deployments.js +0 -283
  26. package/src/commands/compile-menu.js +0 -126
  27. package/src/commands/create-version.js +0 -43
  28. package/src/commands/validate-menu.js +0 -33
  29. package/src/commands/validate-menu.spec.js +0 -43
  30. package/src/schema.js +0 -112
  31. package/src/utils/create-application-assets-upload-script.js +0 -62
  32. package/src/utils/create-application-index-upload-script.js +0 -41
  33. package/src/utils/get-application-directory.js +0 -7
  34. package/src/utils/is-ci.js +0 -5
  35. package/src/utils/load-dotenv-files.js +0 -48
  36. package/src/utils/resolve-in-application.js +0 -8
@@ -1,283 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import Listr from 'listr';
4
- import { execa } from 'execa';
5
- import { cosmiconfig } from 'cosmiconfig';
6
- import { findRootSync } from '@manypkg/find-root';
7
- import ListrVerboseRenderer from 'listr-verbose-renderer';
8
- import resolveInApplication from '../utils/resolve-in-application.js';
9
- import getApplicationDirectory from '../utils/get-application-directory.js';
10
- import isCI from '../utils/is-ci.js';
11
- import createApplicationIndexUploadScript from '../utils/create-application-index-upload-script.js';
12
- import createApplicationAssetsUploadScript from '../utils/create-application-assets-upload-script.js';
13
- import loadDotenvFiles from '../utils/load-dotenv-files.js';
14
-
15
- const buckedConfigExplorer = cosmiconfig('google-storage-buckets');
16
-
17
- function writeUploadScriptFile({ fileName, fileContent, filePath }) {
18
- fs.writeFileSync(path.join(filePath, fileName), fileContent, {
19
- // Make the script executable
20
- mode: 0o755,
21
- encoding: 'utf8',
22
- });
23
- }
24
-
25
- function getBucketNamespace(prNumber) {
26
- if (!prNumber) return;
27
- if (prNumber === 'merchant-center-preview') return prNumber;
28
- return `mc-${prNumber}`;
29
- }
30
-
31
- /**
32
- * Construct the storage bucket URL for the specific application and cloud environment.
33
- *
34
- * 1. Static assets are uploaded to `:bucketRegion/:prNumber?/:applicationName`
35
- * 2. The application index is uploaded to `:bucketRegion/:prNumber?/:applicationName/:cloudEnvironment`
36
- *
37
- * This allows all cloud environments sharing the same static assets while each application's index
38
- * is uploaded with different headers (e.g. CSP rules).
39
- */
40
- function getApplicationAssetsBucketUrl({
41
- bucketRegion,
42
- prNumber,
43
- applicationName,
44
- }) {
45
- const applicationAssetsBucketUrl = [
46
- `gs://${bucketRegion}`,
47
- getBucketNamespace(prNumber),
48
- applicationName,
49
- ].filter(Boolean);
50
-
51
- return applicationAssetsBucketUrl.join('/');
52
- }
53
- function getApplicationIndexBucketUrl({
54
- bucketRegion,
55
- prNumber,
56
- applicationName,
57
- cloudEnvironment,
58
- }) {
59
- const applicationAssetsBucketUrl = getApplicationAssetsBucketUrl({
60
- bucketRegion,
61
- prNumber,
62
- applicationName,
63
- });
64
- const applicationIndexBucketUrl = `${applicationAssetsBucketUrl}/${cloudEnvironment}`;
65
-
66
- return applicationIndexBucketUrl;
67
- }
68
- function getCdnUrl({ bucketRegion, prNumber, applicationName }) {
69
- return [
70
- `https://storage.googleapis.com/${bucketRegion}`,
71
- getBucketNamespace(prNumber),
72
- applicationName,
73
- ]
74
- .filter(Boolean)
75
- .join('/');
76
- }
77
-
78
- async function compileApplicationAssets({ cliFlags, bucketRegion, paths }) {
79
- const applicationAssetsUploadScriptContent =
80
- createApplicationAssetsUploadScript({
81
- bucketUrl: getApplicationAssetsBucketUrl({
82
- bucketRegion,
83
- prNumber: cliFlags['pr-number'],
84
- applicationName: cliFlags['application-name'],
85
- }),
86
- assetsPath: paths.assetsPath,
87
- skipMenu: cliFlags['skip-menu'],
88
- });
89
- const parsedApplicationAssetsUploadScriptFile = path.parse(
90
- cliFlags['application-assets-upload-script-out-file']
91
- );
92
- const applicationAssetsUploadScriptFileName = `${parsedApplicationAssetsUploadScriptFile.name}-${bucketRegion}${parsedApplicationAssetsUploadScriptFile.ext}`;
93
-
94
- writeUploadScriptFile({
95
- fileName: applicationAssetsUploadScriptFileName,
96
- fileContent: applicationAssetsUploadScriptContent,
97
- filePath: paths.deploymentsPath,
98
- });
99
- }
100
-
101
- async function compileEnvironmentApplicationIndexes({
102
- cliFlags,
103
- paths,
104
- bucketRegion,
105
- cloudEnvironment,
106
- }) {
107
- const cloudEnvironmentDeploymentPath = path.join(
108
- paths.deploymentsPath,
109
- cloudEnvironment
110
- );
111
- // Ensure the folder exists
112
- const createDeploymentsFolderResult = await execa(
113
- 'mkdir',
114
- ['-p', cloudEnvironmentDeploymentPath],
115
- { encoding: 'utf8' }
116
- );
117
- if (createDeploymentsFolderResult.failed) {
118
- throw new Error(createDeploymentsFolderResult.stderr);
119
- }
120
-
121
- // Construct the proper CDN URL for the specific application
122
- const cdnUrl = getCdnUrl({
123
- bucketRegion,
124
- prNumber: cliFlags['pr-number'],
125
- applicationName: cliFlags['application-name'],
126
- });
127
-
128
- const environmentVariablesForCompilation = {
129
- ...loadDotenvFiles({
130
- dotenvPath: paths.dotenvPath,
131
- cloudEnvironment,
132
- }),
133
- // The trailing slash is important to indicate to the CSP directive that all the resources
134
- // under that path should be allowed.
135
- MC_CDN_URL: `${cdnUrl}/`,
136
- ...(cliFlags['mc-url']
137
- ? {
138
- MC_URL: cliFlags['mc-url'],
139
- }
140
- : {}),
141
- ...(cliFlags['mc-api-url']
142
- ? {
143
- MC_API_URL: cliFlags['mc-api-url'],
144
- }
145
- : {}),
146
- // Will be used by the Application Kit for Sentry and exposed on `window.app.revision`.
147
- REVISION: cliFlags['build-revision'],
148
- };
149
-
150
- /// Sentry and GTM is disabled on branch deployments
151
- if (cliFlags['pr-number']) {
152
- process.env.TRACKING_SENTRY = null;
153
- process.env.TRACKING_GTM = null;
154
- environmentVariablesForCompilation.TRACKING_SENTRY = null;
155
- environmentVariablesForCompilation.TRACKING_GTM = null;
156
- }
157
-
158
- // Compile the application using the loaded environment values
159
- const compileResult = await execa('mc-scripts', ['compile-html'], {
160
- encoding: 'utf8',
161
- preferLocal: true,
162
- extendEnv: true,
163
- env: environmentVariablesForCompilation,
164
- });
165
-
166
- if (compileResult.failed) {
167
- throw new Error(compileResult.stderr);
168
- }
169
-
170
- const applicationIndexUploadScriptContent =
171
- createApplicationIndexUploadScript({
172
- packageManagerName: cliFlags['package-manager-name'],
173
- bucketUrl: getApplicationIndexBucketUrl({
174
- bucketRegion,
175
- prNumber: cliFlags['pr-number'],
176
- applicationName: cliFlags['application-name'],
177
- cloudEnvironment,
178
- }),
179
- cdnUrl,
180
- cloudEnvironment,
181
- buildRevision: cliFlags['build-revision'],
182
- buildNumber: cliFlags['build-number'],
183
- applicationIndexOutFile: cliFlags['application-index-out-file'],
184
- versionJsonOutFile: cliFlags['version-json-out-file'],
185
- });
186
- // Generate bash scripts to run the `gsutil` upload command.
187
- writeUploadScriptFile({
188
- fileName: cliFlags['application-index-upload-script-out-file'],
189
- fileContent: applicationIndexUploadScriptContent,
190
- filePath: cloudEnvironmentDeploymentPath,
191
- });
192
-
193
- // Move the compiled `index.html` to the deployments folder of the related cloud environment.
194
- const moveResult = await execa('mv', [
195
- path.join(paths.publicAssetsPath, 'index.html'),
196
- path.join(
197
- cloudEnvironmentDeploymentPath,
198
- cliFlags['application-index-out-file']
199
- ),
200
- ]);
201
-
202
- if (moveResult.failed) {
203
- throw new Error(moveResult.stderr);
204
- }
205
- }
206
-
207
- async function command(cliFlags, cwd) {
208
- let cloudEnvironmentsGroupedByBucketRegions;
209
- try {
210
- // This is the list of the supported cloud environments and their related bucket location.
211
- cloudEnvironmentsGroupedByBucketRegions =
212
- await buckedConfigExplorer.search();
213
- } catch (e) {
214
- throw new Error(
215
- 'Failed loading a Google Bucket configuration. Create a cosmiconfig for `google-storage-buckets` for example `google-storage-buckets.config.cjs`.'
216
- );
217
- }
218
- const applicationDirectory = getApplicationDirectory(cwd);
219
- let assetsPath;
220
- if (cliFlags['ci-assets-root-path'] && isCI()) {
221
- assetsPath = applicationDirectory.replace(
222
- '/home/circleci/',
223
- cliFlags['ci-assets-root-path']
224
- );
225
- } else {
226
- assetsPath = applicationDirectory;
227
- }
228
-
229
- const monorepoRoot = findRootSync(cwd);
230
- const paths = {
231
- publicAssetsPath: resolveInApplication('public', cwd),
232
- deploymentsPath: resolveInApplication('deployments', cwd),
233
- dotenvPath:
234
- cliFlags['dotenv-folder'] &&
235
- path.join(monorepoRoot.rootDir, cliFlags['dotenv-folder']),
236
- assetsPath,
237
- };
238
-
239
- async function execute() {
240
- const taskList = new Listr(
241
- Object.entries(cloudEnvironmentsGroupedByBucketRegions.config).map(
242
- ([bucketRegion, cloudEnvironments]) => ({
243
- title: `Compiling application for bucket ${bucketRegion}`,
244
- task: () =>
245
- new Listr(
246
- cloudEnvironments
247
- .map((cloudEnvironment) => ({
248
- title: `Compiling ${cloudEnvironment} application index`,
249
- task: async () => {
250
- await compileEnvironmentApplicationIndexes({
251
- cliFlags,
252
- paths,
253
- bucketRegion,
254
- cloudEnvironment,
255
- });
256
- return 'Done';
257
- },
258
- }))
259
- .concat({
260
- title: `Compiling application assets`,
261
- task: () => {
262
- compileApplicationAssets({
263
- cliFlags,
264
- bucketRegion,
265
- paths,
266
- });
267
- },
268
- })
269
- ),
270
- })
271
- ),
272
- {
273
- renderer: isCI() ? ListrVerboseRenderer : 'default',
274
- nonTTYRenderer: ListrVerboseRenderer,
275
- }
276
- );
277
- await taskList.run();
278
- }
279
-
280
- await execute();
281
- }
282
-
283
- export default command;
@@ -1,126 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { findRootSync } from '@manypkg/find-root';
4
- import { processConfig } from '@commercetools-frontend/application-config';
5
- import getApplicationDirectory from '../utils/get-application-directory.js';
6
- import loadDotenvFiles from '../utils/load-dotenv-files.js';
7
-
8
- // The menu links are only parsed from the config in development mode.
9
- process.env.NODE_ENV = 'development';
10
-
11
- const supportedLocales = ['en', 'de', 'es', 'fr-FR', 'zh-CN', 'ja'];
12
-
13
- const mapLabelAllLocalesWithDefaults = (labelAllLocales, defaultLabel) => {
14
- let mappedLabelAllLocales = labelAllLocales;
15
- if (defaultLabel) {
16
- // Map all supported locales with the given localized labels.
17
- // If a locale is not defined in the config, we use the `default` label as the value.
18
- // This is only needed for development as we're trying to map two different schemas.
19
- mappedLabelAllLocales = supportedLocales.map((supportedLocale) => {
20
- const existingField = labelAllLocales.find(
21
- (field) => field.locale === supportedLocale
22
- );
23
- if (existingField) return existingField;
24
- return {
25
- locale: supportedLocale,
26
- value: defaultLabel,
27
- };
28
- });
29
- }
30
- return mappedLabelAllLocales;
31
- };
32
-
33
- /**
34
- * Transform menu links defined in the `custom-application-config.json` to the format
35
- * used by the HTTP Proxy GraphQL API.
36
- */
37
- const mapApplicationMenuConfigToGraqhQLMenuJson = (config) => {
38
- const entryPointUriPath = config.entryPointUriPath;
39
- const accountLinks = config.__DEVELOPMENT__.accountLinks;
40
-
41
- if (accountLinks) {
42
- return accountLinks.map((menuLink) => ({
43
- key: menuLink.uriPath,
44
- uriPath: menuLink.uriPath,
45
- labelAllLocales: mapLabelAllLocalesWithDefaults(
46
- menuLink.labelAllLocales,
47
- menuLink.defaultLabel
48
- ),
49
- permissions: menuLink.permissions ?? [],
50
- featureToggle: menuLink.featureToggle ?? null,
51
- }));
52
- }
53
-
54
- const menuLinks = config.__DEVELOPMENT__.menuLinks;
55
- return {
56
- key: entryPointUriPath,
57
- uriPath: entryPointUriPath,
58
- icon: menuLinks.icon,
59
- labelAllLocales: mapLabelAllLocalesWithDefaults(
60
- menuLinks.labelAllLocales,
61
- menuLinks.defaultLabel
62
- ),
63
- permissions: menuLinks.permissions,
64
- featureToggle: menuLinks.featureToggle ?? null,
65
- menuVisibility: menuLinks.menuVisibility ?? null,
66
- actionRights: menuLinks.actionRights ?? null,
67
- dataFences: menuLinks.dataFences ?? null,
68
- submenu: menuLinks.submenuLinks.map((submenuLink) => ({
69
- key: submenuLink.uriPath.replace('/', '-'),
70
- uriPath: submenuLink.uriPath,
71
- labelAllLocales: mapLabelAllLocalesWithDefaults(
72
- submenuLink.labelAllLocales,
73
- submenuLink.defaultLabel
74
- ),
75
- permissions: submenuLink.permissions,
76
- featureToggle: submenuLink.featureToggle ?? null,
77
- menuVisibility: submenuLink.menuVisibility ?? null,
78
- actionRights: submenuLink.actionRights ?? null,
79
- dataFences: submenuLink.dataFences ?? null,
80
- })),
81
- shouldRenderDivider: menuLinks.shouldRenderDivider ?? false,
82
- };
83
- };
84
-
85
- async function command(cliFlags, cwd) {
86
- const applicationDirectory = getApplicationDirectory(cwd);
87
- const monorepoRoot = findRootSync(cwd);
88
- const dotenvPath =
89
- cliFlags['dotenv-folder'] &&
90
- path.join(monorepoRoot.rootDir, cliFlags['dotenv-folder']);
91
-
92
- const processEnv = {
93
- ...loadDotenvFiles({
94
- dotenvPath,
95
- // The env itself is not important for the menu. However, the application config
96
- // uses environment placeholders and therefore we need to provide the variables for it.
97
- cloudEnvironment: 'ctp-gcp-staging',
98
- }),
99
- // Again, make sure that the environment is "development", otherwise
100
- // the menu config won't be available.
101
- NODE_ENV: 'development',
102
- MC_APP_ENV: 'development',
103
- // Something random, just to have environment variable defined.
104
- REVISION: '123',
105
- };
106
-
107
- const applicationRuntimeConfig = processConfig({
108
- disableCache: true,
109
- applicationPath: applicationDirectory,
110
- processEnv,
111
- });
112
-
113
- const applicationMenu = mapApplicationMenuConfigToGraqhQLMenuJson(
114
- applicationRuntimeConfig.env
115
- );
116
-
117
- const formattedJson = JSON.stringify(applicationMenu, null, 2);
118
-
119
- fs.writeFileSync(
120
- path.join(applicationDirectory, 'menu.json'),
121
- formattedJson,
122
- { encoding: 'utf8' }
123
- );
124
- }
125
-
126
- export default command;
@@ -1,43 +0,0 @@
1
- import fetch from 'node-fetch';
2
- import fs from 'fs';
3
-
4
- async function command(cliFlags) {
5
- const numberOfRollbacks = cliFlags.rollbacks - 1;
6
-
7
- let nextRollbacks;
8
- try {
9
- // The last build's JSON becomes the first rollback
10
- // while all previous rollbacks remain but are sliced.
11
- const lastVersionResponse = await fetch(cliFlags['version-url']);
12
- const lastVersionJson = await lastVersionResponse.json();
13
-
14
- const previousBuild = lastVersionJson && {
15
- buildNumber: lastVersionJson.buildNumber,
16
- revision: lastVersionJson.revision,
17
- deployedAt: lastVersionJson.deployedAt,
18
- };
19
-
20
- nextRollbacks = [previousBuild, ...lastVersionJson.rollbacks]
21
- .filter(Boolean)
22
- .slice(0, numberOfRollbacks);
23
- } catch (error) {
24
- nextRollbacks = [];
25
- }
26
-
27
- const nextBuild = {
28
- buildNumber: cliFlags['build-number'],
29
- revision: cliFlags['build-revision'],
30
- deployedAt: new Date().toISOString(),
31
- rollbacks: nextRollbacks,
32
- };
33
- const formattedJson = JSON.stringify(nextBuild, null, 2);
34
- // Logging to stdout which is from where it will be picked
35
- // up by the caller (a bash script).
36
- if (cliFlags['out-file']) {
37
- fs.writeFileSync(cliFlags['out-file'], formattedJson, { encoding: 'utf8' });
38
- } else {
39
- console.log(formattedJson);
40
- }
41
- }
42
-
43
- export default command;
@@ -1,33 +0,0 @@
1
- import fs from 'fs';
2
- import { Validator } from 'jsonschema';
3
- import { navbarMenuSchema, appbarMenuSchema } from '../schema.js';
4
-
5
- export function validateMenu(menuJson, schema = navbarMenuSchema) {
6
- const validator = new Validator();
7
- const result = validator.validate(menuJson, schema);
8
- if (result.valid) {
9
- return menuJson;
10
- } else {
11
- throw new Error('menu.json validation failed\n' + result.errors);
12
- }
13
- }
14
-
15
- async function command(cliFlags, cwd) {
16
- const menuJsonPath = cliFlags['input-file'];
17
- const isAppbarMenu = cliFlags['navigation'] === 'top';
18
-
19
- if (!menuJsonPath)
20
- throw new Error(
21
- `--input-file cannot be empty. please provide the path of compiled menu.json`
22
- );
23
- if (!fs.existsSync(menuJsonPath))
24
- throw new Error(`The menu.json file doesn't exist: ${menuJsonPath}`);
25
- const menuJson = fs.readFileSync(menuJsonPath, 'utf-8');
26
-
27
- return validateMenu(
28
- JSON.parse(menuJson),
29
- isAppbarMenu ? appbarMenuSchema : navbarMenuSchema
30
- );
31
- }
32
-
33
- export default command;
@@ -1,43 +0,0 @@
1
- import { validateMenu } from './validate-menu.js';
2
-
3
- describe('validate menu', () => {
4
- test.each([
5
- 123,
6
- '{value:123}',
7
- {},
8
- { uriPath: 'products', icon: 'ProductsIcon', submenu: [] },
9
- {
10
- uriPath: 123,
11
- intlMessage: 123,
12
- icon: 123,
13
- permissions: '',
14
- submenu: {},
15
- key: {},
16
- labelAllLocales: {},
17
- },
18
- ])('should return null for invalid menu configs', (json) => {
19
- try {
20
- expect(validateMenu(json)).toEqual([]);
21
- } catch (error) {
22
- // catch block is required otherwise the test fails
23
- // due to `validateMenu` throwing error for invalid menu
24
- }
25
- });
26
- it('should return menu json for valid menu configs', async () => {
27
- const menuJson = {
28
- uriPath: 'products',
29
- intlMessage: 'Products',
30
- icon: 'ProductsIcon',
31
- permissions: ['ViewProducts'],
32
- submenu: [],
33
- key: 'product',
34
- labelAllLocales: [
35
- {
36
- locale: 'en',
37
- value: 'product',
38
- },
39
- ],
40
- };
41
- expect(validateMenu(menuJson)).toEqual(menuJson);
42
- });
43
- });
package/src/schema.js DELETED
@@ -1,112 +0,0 @@
1
- const baseMenuProperties = {
2
- key: {
3
- type: 'string',
4
- },
5
- uriPath: {
6
- type: 'string',
7
- },
8
- icon: {
9
- type: 'string',
10
- },
11
- featureToggle: {
12
- type: ['string', 'null'],
13
- },
14
- labelAllLocales: {
15
- type: 'array',
16
- items: [
17
- {
18
- type: 'object',
19
- properties: {
20
- locale: { type: 'string' },
21
- value: { type: 'string' },
22
- },
23
- required: ['locale', 'value'],
24
- },
25
- ],
26
- },
27
- menuVisibility: {
28
- type: ['string', 'null'],
29
- },
30
- permissions: {
31
- type: 'array',
32
- items: {
33
- type: 'string',
34
- },
35
- },
36
- dataFences: {
37
- type: ['array', 'null'],
38
- items: [
39
- {
40
- type: ['object'],
41
- properties: {
42
- group: {
43
- type: 'string',
44
- },
45
- name: {
46
- type: 'string',
47
- },
48
- type: {
49
- type: 'string',
50
- },
51
- },
52
- },
53
- ],
54
- },
55
- actionRights: {
56
- type: ['array', 'null'],
57
- items: [
58
- {
59
- type: ['object'],
60
- properties: {
61
- group: {
62
- type: 'string',
63
- },
64
- name: {
65
- type: 'string',
66
- },
67
- },
68
- },
69
- ],
70
- },
71
- };
72
-
73
- export const navbarMenuSchema = {
74
- $schema: 'https://json-schema.org/draft/2020-12/schema',
75
- // "$id":""
76
- title: 'NavbarMenu',
77
- type: 'object',
78
- properties: {
79
- ...baseMenuProperties,
80
- submenu: {
81
- type: 'array',
82
- items: [
83
- {
84
- type: 'object',
85
- properties: baseMenuProperties,
86
- },
87
- ],
88
- },
89
- },
90
- required: [
91
- 'icon',
92
- 'key',
93
- 'labelAllLocales',
94
- 'permissions',
95
- 'submenu',
96
- 'uriPath',
97
- ],
98
- };
99
-
100
- export const appbarMenuSchema = {
101
- $schema: 'https://json-schema.org/draft/2020-12/schema',
102
- // "$id":""
103
- title: 'AppbarMenu',
104
- type: 'array',
105
- items: [
106
- {
107
- type: 'object',
108
- properties: baseMenuProperties,
109
- required: ['key', 'labelAllLocales', 'permissions', 'uriPath'],
110
- },
111
- ],
112
- };
@@ -1,62 +0,0 @@
1
- function createApplicationAssetsUploadScript({
2
- bucketUrl,
3
- assetsPath,
4
- skipMenu,
5
- }) {
6
- const uploadScriptContent = `#!/usr/bin/env bash
7
-
8
- set -e
9
-
10
- # NOTES:
11
- # https://cloud.google.com/storage/docs/gsutil/commands/cp#options
12
- # 1. The '-z' option triggers compressing the assets before
13
- # uploading them and sets the 'Content-Encoding' to 'gzip'.
14
- # 2. The 'Accept-encoding: gzip' is set automatically by the 'gsutils'.
15
- # 3. The 'max-age' is set to 1 year which is considered the maximum
16
- # "valid" lifetime of an asset to be cached.
17
- # 5. The '-n' will skip uploading existing files and prevents them to
18
- # be overwritten
19
- echo "Uploading static assets to bucket ${bucketUrl}"
20
-
21
- gsutil -m \\
22
- -h "Cache-Control: public, max-age=31536000, no-transform" \\
23
- cp -z js,css \\
24
- -n \\
25
- ${assetsPath}/public/{*.css,*.js,*.js.map,*.png,*.html,robots.txt} \\
26
- "${bucketUrl}"
27
-
28
- if ${skipMenu}; then
29
- echo "Skipping menu.json upload"
30
- else
31
- echo "Uploading menu.json to bucket ${bucketUrl}"
32
- # NOTE: somehow the 'cache-control:private' doesn't work.
33
- # I mean, the file is uploaded with the correct metadata but when I fetch
34
- # the file the response contains the header
35
- # 'cache-control: public, max-age=31536000, no-transform', even though the
36
- # documentation clearly states that by marking the header as 'private' will
37
- # disable the cache (for publicly readable objects).
38
- # https://cloud.google.com/storage/docs/gsutil/addlhelp/WorkingWithObjectMetadata#cache-control
39
- # However, I found out that, by requesting the file with any RANDOM
40
- # query parameter, will instruct the storage to return a 'fresh' object
41
- # (without any cache control).
42
- # Unofficial source: https://stackoverflow.com/a/49052895
43
- # This seems to be the 'easiest' option to 'disable' the cache for public
44
- # objects. Other alternative approaces are:
45
- # * make the object private with some simple ACL (private objects are not cached)
46
- # * suffix the file name with e.g. the git SHA, so we have different files
47
- # for each upload ('index.html.template-\${CIRCLE_SHA1}'). The server knows
48
- # the git SHA on runtime and can get the correct file when it starts.
49
- # * find out why the 'private' cache control does not work
50
- gsutil \\
51
- -h "Content-Type: application/json" \\
52
- -h "Cache-Control: private, max-age=0, no-transform" \\
53
- cp -z json \\
54
- ${assetsPath}/menu.json \\
55
- ${bucketUrl}
56
- fi
57
- `;
58
-
59
- return uploadScriptContent;
60
- }
61
-
62
- export default createApplicationAssetsUploadScript;