@madgex/fert 5.0.4 → 5.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/bin/cli.js +9 -30
- package/bin/commands/_service-command-bootstrap.js +6 -13
- package/bin/commands/build-tasks/build-tokens.js +8 -22
- package/bin/commands/build-tasks/bundle-entry.js +1 -4
- package/bin/commands/build.js +1 -0
- package/bin/commands/configs.js +17 -53
- package/bin/commands/dev-server.js +5 -14
- package/bin/commands/init.js +27 -117
- package/bin/commands/publish-tasks/asset-store-uploader.js +2 -5
- package/bin/commands/publish.js +10 -30
- package/bin/utils/configs.js +55 -95
- package/bin/utils/cpid-lookup.js +2 -2
- package/bin/utils/cpid-matches-git-remote.js +5 -10
- package/bin/utils/getSchemaMeta.js +1 -1
- package/bin/utils/index.js +14 -25
- package/bin/utils/lookup-cf-distribution-ids.js +2 -7
- package/bin/utils/resolve-external-assets.js +6 -15
- package/constants.js +3 -17
- package/package.json +17 -26
- package/repo-template/fert.config.js +3 -0
- package/repo-template/package.json +22 -0
- package/{repo-templates/template-basic → repo-template/services/jobseekers-frontend}/brand.json +6 -3
- package/repo-template/services/jobseekers-frontend/fert.service.config.js +7 -0
- package/repo-template/services/jobseekers-frontend/public/icons/user.svg +4 -0
- package/repo-template/services/jobseekers-frontend/public/images/favicon.ico +0 -0
- package/repo-template/services/jobseekers-frontend/public/images/fred.jpeg +0 -0
- package/repo-template/services/jobseekers-frontend/src/css/styles.scss +1152 -0
- package/repo-template/services/jobseekers-frontend/src/index.js +9 -0
- package/repo-template/services/jobseekers-frontend/src/js/recruiter-link.js +25 -0
- package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/context/footer-nav.njk +26 -26
- package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/context/main-nav.njk +40 -31
- package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/context/user-nav.njk +16 -16
- package/repo-template/services/jobseekers-frontend/templates/footer.njk +20 -0
- package/repo-template/services/jobseekers-frontend/templates/header.njk +74 -0
- package/repo-template/services/jobseekers-frontend/templates/includes/footer-nav.njk +15 -0
- package/repo-template/services/jobseekers-frontend/templates/includes/main-nav.njk +19 -0
- package/repo-template/services/jobseekers-frontend/templates/includes/user-nav/authenticated.njk +34 -0
- package/repo-template/services/jobseekers-frontend/templates/includes/user-nav/unauthenticated.njk +9 -0
- package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/en.njk +1 -0
- package/server/index.js +2 -3
- package/server/plugins/hapi-vite.js +4 -2
- package/server/routes/views.js +1 -0
- package/server/view-manager.js +2 -5
- package/.prettierrc.js +0 -8
- package/bin/commands/configs.test.js +0 -182
- package/bin/utils/configs.test.js +0 -53
- package/bin/utils/persistent-cache-with-ttl.test.js +0 -42
- package/bin/utils/resolve-external-assets.test.js +0 -98
- package/eslint.config.mjs +0 -53
- package/repo-templates/globals/fert.config.js +0 -9
- package/repo-templates/template-basic/_gitignore +0 -6
- package/repo-templates/template-basic/package.json +0 -13
- package/repo-templates/template-basic/public/favicon.ico +0 -0
- package/repo-templates/template-basic/src/css/styles.scss +0 -11
- package/repo-templates/template-basic/src/index.js +0 -3
- package/repo-templates/template-basic/templates/footer.njk +0 -14
- package/repo-templates/template-basic/templates/header.njk +0 -14
- package/repo-templates/template-bigworkbag/_gitignore +0 -6
- package/repo-templates/template-bigworkbag/brand.json +0 -21
- package/repo-templates/template-bigworkbag/package.json +0 -13
- package/repo-templates/template-bigworkbag/public/favicon.ico +0 -0
- package/repo-templates/template-bigworkbag/public/fonts/mdgx-icons.eot +0 -0
- package/repo-templates/template-bigworkbag/public/fonts/mdgx-icons.svg +0 -71
- package/repo-templates/template-bigworkbag/public/fonts/mdgx-icons.ttf +0 -0
- package/repo-templates/template-bigworkbag/public/fonts/mdgx-icons.woff +0 -0
- package/repo-templates/template-bigworkbag/public/fonts/my-font.woff +0 -1
- package/repo-templates/template-bigworkbag/public/images/logo.png +0 -0
- package/repo-templates/template-bigworkbag/public/images/user-menu-pointer.svg +0 -4
- package/repo-templates/template-bigworkbag/src/css/breakpoints.scss +0 -17
- package/repo-templates/template-bigworkbag/src/css/clicky-menu.scss +0 -52
- package/repo-templates/template-bigworkbag/src/css/desktop-main-nav.scss +0 -25
- package/repo-templates/template-bigworkbag/src/css/desktop-user-nav.scss +0 -127
- package/repo-templates/template-bigworkbag/src/css/footer.scss +0 -77
- package/repo-templates/template-bigworkbag/src/css/header-top.scss +0 -29
- package/repo-templates/template-bigworkbag/src/css/leaderboard-ad.scss +0 -22
- package/repo-templates/template-bigworkbag/src/css/mobile-main-nav.scss +0 -68
- package/repo-templates/template-bigworkbag/src/css/mobile-user-nav.scss +0 -49
- package/repo-templates/template-bigworkbag/src/css/reset.scss +0 -91
- package/repo-templates/template-bigworkbag/src/css/styles.scss +0 -18
- package/repo-templates/template-bigworkbag/src/css/top-bar.scss +0 -13
- package/repo-templates/template-bigworkbag/src/css/typography.scss +0 -20
- package/repo-templates/template-bigworkbag/src/css/util.scss +0 -28
- package/repo-templates/template-bigworkbag/src/css/variables.scss +0 -9
- package/repo-templates/template-bigworkbag/src/index.js +0 -3
- package/repo-templates/template-bigworkbag/src/js/clicky-menus.js +0 -178
- package/repo-templates/template-bigworkbag/src/js/no-js.js +0 -10
- package/repo-templates/template-bigworkbag/templates/footer.njk +0 -68
- package/repo-templates/template-bigworkbag/templates/header.njk +0 -54
- package/repo-templates/template-bigworkbag/templates/includes/desktop-main-nav-items.njk +0 -18
- package/repo-templates/template-bigworkbag/templates/includes/desktop-user-nav/loggedin-items.njk +0 -28
- package/repo-templates/template-bigworkbag/templates/includes/desktop-user-nav/loggedout-items.njk +0 -9
- package/repo-templates/template-bigworkbag/templates/includes/desktop-user-nav/submenu-items.njk +0 -18
- package/repo-templates/template-bigworkbag/templates/includes/desktop-user-nav/user-nav.njk +0 -24
- package/repo-templates/template-bigworkbag/templates/includes/dev-console-context.njk +0 -7
- package/repo-templates/template-bigworkbag/templates/includes/mobile-main-nav-items.njk +0 -25
- package/repo-templates/template-bigworkbag/templates/includes/mobile-user-nav/loggedin-items.njk +0 -33
- package/repo-templates/template-bigworkbag/templates/includes/mobile-user-nav/loggedout-items.njk +0 -16
- package/repo-templates/template-bigworkbag/templates/includes/mobile-user-nav/user-nav.njk +0 -24
- package/repo-templates/template-bigworkbag/templates/svgs/arrow-down.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/arrow-left.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/arrow-right.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/arrow-up.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/cart.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/facebook.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/linkedin.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/profile.svg +0 -5
- package/repo-templates/template-bigworkbag/templates/svgs/star-filled.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/star-outline.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/twitter.svg +0 -3
- package/repo-templates/template-bigworkbag/templates/svgs/youtube.svg +0 -3
- /package/{repo-templates/globals → repo-template}/jenkinsfile +0 -0
- /package/{repo-templates/template-basic → repo-template/services/jobseekers-frontend}/public/fonts/mdgx-icons.eot +0 -0
- /package/{repo-templates/template-basic → repo-template/services/jobseekers-frontend}/public/fonts/mdgx-icons.svg +0 -0
- /package/{repo-templates/template-basic → repo-template/services/jobseekers-frontend}/public/fonts/mdgx-icons.ttf +0 -0
- /package/{repo-templates/template-basic → repo-template/services/jobseekers-frontend}/public/fonts/mdgx-icons.woff +0 -0
- /package/{repo-templates/template-basic → repo-template/services/jobseekers-frontend}/public/fonts/my-font.woff +0 -0
- /package/{repo-templates/template-basic → repo-template/services/jobseekers-frontend}/public/images/logo.png +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/da.njk +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/de.njk +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/es.njk +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/fr.njk +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/nb.njk +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/nl.njk +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/sv.njk +0 -0
- /package/{repo-templates/template-bigworkbag → repo-template/services/jobseekers-frontend}/templates/translations/zh-cn.njk +0 -0
package/bin/commands/publish.js
CHANGED
|
@@ -5,9 +5,7 @@ const { resolveConfig } = require('../utils');
|
|
|
5
5
|
const { log } = require('../utils/logging');
|
|
6
6
|
const getAwsParam = require('./publish-tasks/get-aws-parameter');
|
|
7
7
|
const AssetStoreUploader = require('./publish-tasks/asset-store-uploader');
|
|
8
|
-
const {
|
|
9
|
-
getCloudFrontDistributionsForDomain,
|
|
10
|
-
} = require('../utils/lookup-cf-distribution-ids');
|
|
8
|
+
const { getCloudFrontDistributionsForDomain } = require('../utils/lookup-cf-distribution-ids');
|
|
11
9
|
const {
|
|
12
10
|
ASSET_STORE_API,
|
|
13
11
|
AWS_PARAM_NAME,
|
|
@@ -23,13 +21,12 @@ module.exports = async (options) => {
|
|
|
23
21
|
|
|
24
22
|
// handle legacy options
|
|
25
23
|
if (options.target === 'prod') {
|
|
24
|
+
// eslint-disable-next-line no-param-reassign
|
|
26
25
|
options.target = 'production';
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
if (!validTargets.includes(options.target)) {
|
|
30
|
-
throw Error(
|
|
31
|
-
`Missing or invalid --target option. Choose from [${validTargets}]`
|
|
32
|
-
);
|
|
29
|
+
throw Error(`Missing or invalid --target option. Choose from [${validTargets}]`);
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
if (options.dryRun) {
|
|
@@ -46,29 +43,18 @@ module.exports = async (options) => {
|
|
|
46
43
|
const apiUrl = Hoek.reachTemplate(templateCtx, ASSET_STORE_API);
|
|
47
44
|
const remoteBasePath = Hoek.reachTemplate(templateCtx, REMOTE_UPLOAD_BASE);
|
|
48
45
|
const apiKeyParamPath = Hoek.reachTemplate(templateCtx, AWS_PARAM_NAME);
|
|
49
|
-
const assetStoreInvPath = Hoek.reachTemplate(
|
|
50
|
-
|
|
51
|
-
ASSET_STORE_INVALIDATION_PATH
|
|
52
|
-
);
|
|
53
|
-
const brandedSiteInvPath = Hoek.reachTemplate(
|
|
54
|
-
templateCtx,
|
|
55
|
-
BRANDED_SITE_INVALIDATION_PATH
|
|
56
|
-
);
|
|
46
|
+
const assetStoreInvPath = Hoek.reachTemplate(templateCtx, ASSET_STORE_INVALIDATION_PATH);
|
|
47
|
+
const brandedSiteInvPath = Hoek.reachTemplate(templateCtx, BRANDED_SITE_INVALIDATION_PATH);
|
|
57
48
|
|
|
58
49
|
const apiKey = await getAwsParam(apiKeyParamPath);
|
|
59
50
|
|
|
60
51
|
const siteUrl = new URL(fertConfig.config.JobseekerSiteWebSitePath);
|
|
61
|
-
const clientCloudFrontDists = await getCloudFrontDistributionsForDomain(
|
|
62
|
-
siteUrl.hostname,
|
|
63
|
-
options
|
|
64
|
-
);
|
|
52
|
+
const clientCloudFrontDists = await getCloudFrontDistributionsForDomain(siteUrl.hostname, options);
|
|
65
53
|
|
|
66
54
|
log.info(
|
|
67
55
|
`\nPublishing ${chalk.cyan(localDir)} to ${chalk.green.bold(
|
|
68
|
-
options.target
|
|
69
|
-
)} for ${chalk.green(fertConfig.client.brandName)} ${chalk.dim(
|
|
70
|
-
`(${fertConfig.clientPropertyId})`
|
|
71
|
-
)}\n`
|
|
56
|
+
options.target,
|
|
57
|
+
)} for ${chalk.green(fertConfig.client.brandName)} ${chalk.dim(`(${fertConfig.clientPropertyId})`)}\n`,
|
|
72
58
|
);
|
|
73
59
|
|
|
74
60
|
try {
|
|
@@ -84,9 +70,7 @@ module.exports = async (options) => {
|
|
|
84
70
|
uploadResult = await assetStore.uploadDir(localDir);
|
|
85
71
|
}
|
|
86
72
|
|
|
87
|
-
log.success(
|
|
88
|
-
`Publish complete in ${((uploadResult?.duration || 1) / 1000).toFixed(0)}s\n`
|
|
89
|
-
);
|
|
73
|
+
log.success(`Publish complete in ${((uploadResult?.duration || 1) / 1000).toFixed(0)}s\n`);
|
|
90
74
|
|
|
91
75
|
// invalidate cloudfront cache
|
|
92
76
|
await assetStore.invalidatePaths([assetStoreInvPath]);
|
|
@@ -95,11 +79,7 @@ module.exports = async (options) => {
|
|
|
95
79
|
await assetStore.invalidatePaths([brandedSiteInvPath], dist.id);
|
|
96
80
|
}
|
|
97
81
|
|
|
98
|
-
log.info(
|
|
99
|
-
`\nNote cloudfront invalidations may take upto ${chalk.yellow(
|
|
100
|
-
'30 seconds'
|
|
101
|
-
)} to complete.\n`
|
|
102
|
-
);
|
|
82
|
+
log.info(`\nNote cloudfront invalidations may take upto ${chalk.yellow('30 seconds')} to complete.\n`);
|
|
103
83
|
} catch (error) {
|
|
104
84
|
log.error('An error occurred during the publish process', error);
|
|
105
85
|
}
|
package/bin/utils/configs.js
CHANGED
|
@@ -16,11 +16,7 @@ const { CONFIG_DIR } = require('../../constants');
|
|
|
16
16
|
* @returns {Promise<void>} - Returns a promise that resolves if all configurations are valid.
|
|
17
17
|
* @throws {Error} - Throws an error if any configuration is invalid.
|
|
18
18
|
*/
|
|
19
|
-
const validateLocalConfigs = async ({
|
|
20
|
-
workingDir,
|
|
21
|
-
clientPropertyId,
|
|
22
|
-
throwable = true,
|
|
23
|
-
}) => {
|
|
19
|
+
const validateLocalConfigs = async ({ workingDir, clientPropertyId, throwable = true }) => {
|
|
24
20
|
Hoek.assert(clientPropertyId, 'clientPropertyId is required');
|
|
25
21
|
Hoek.assert(workingDir, 'workingDir is required');
|
|
26
22
|
|
|
@@ -36,55 +32,44 @@ const validateLocalConfigs = async ({
|
|
|
36
32
|
});
|
|
37
33
|
const localConfigs = loadLocalConfigs(workingDir);
|
|
38
34
|
|
|
39
|
-
const validationPromises = Object.keys(localConfigs).map(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const isSchemaReadOnly = api._isSchemaReadOnly(schema);
|
|
35
|
+
const validationPromises = Object.keys(localConfigs).map(async (configName) => {
|
|
36
|
+
try {
|
|
37
|
+
const schema = api.getSchema(configName);
|
|
38
|
+
const isSchemaReadOnly = api._isSchemaReadOnly(schema);
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
49
|
-
}
|
|
40
|
+
if (isSchemaReadOnly) {
|
|
41
|
+
throw Error(`You're trying to set values on a read-only (usually V5) config schema: ${configName}`);
|
|
42
|
+
}
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
);
|
|
57
|
-
}
|
|
44
|
+
// check the entire config against the config validation
|
|
45
|
+
const { error } = schema.validate(localConfigs[configName].data);
|
|
46
|
+
if (error) {
|
|
47
|
+
throw new Error(`Config invalid: ${chalk.bold(localConfigs[configName].path)} - ${error.message}`);
|
|
48
|
+
}
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
`You're trying to set a read-only key on a config schema: ${configName}/${key}`
|
|
66
|
-
);
|
|
67
|
-
}
|
|
50
|
+
// validate all keys individually against the schema keys to ensure we're not trying to set any read-only keys
|
|
51
|
+
const config = localConfigs[configName].data;
|
|
52
|
+
for (const key in config) {
|
|
53
|
+
const keySchema = schema.extract(key);
|
|
54
|
+
if (api._isSchemaReadOnly(keySchema)) {
|
|
55
|
+
throw new Error(`You're trying to set a read-only key on a config schema: ${configName}/${key}`);
|
|
68
56
|
}
|
|
57
|
+
}
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
59
|
+
log.success(`Config validated:`, chalk.bold(configName));
|
|
60
|
+
} catch (err) {
|
|
61
|
+
log.error(err.message);
|
|
73
62
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
63
|
+
if (throwable) {
|
|
64
|
+
throw err;
|
|
77
65
|
}
|
|
78
66
|
}
|
|
79
|
-
);
|
|
67
|
+
});
|
|
80
68
|
|
|
81
69
|
await Promise.all(validationPromises);
|
|
82
70
|
};
|
|
83
71
|
|
|
84
|
-
const getConfigAPI = async ({
|
|
85
|
-
clientPropertyId,
|
|
86
|
-
environment = 'production',
|
|
87
|
-
} = {}) => {
|
|
72
|
+
const getConfigAPI = async ({ clientPropertyId, environment = 'production' } = {}) => {
|
|
88
73
|
const { ConfigAPI } = await import('@madgex/config-api-sdk');
|
|
89
74
|
|
|
90
75
|
const api = new ConfigAPI({
|
|
@@ -143,11 +128,7 @@ const loadLocalConfigs = (workingDir) => {
|
|
|
143
128
|
*
|
|
144
129
|
* @returns {Promise<boolean>} - Returns a promise that resolves to true if the update is successful.
|
|
145
130
|
*/
|
|
146
|
-
const updateProjectConfigs = async ({
|
|
147
|
-
clientPropertyId,
|
|
148
|
-
workingDir,
|
|
149
|
-
environment = 'production',
|
|
150
|
-
} = {}) => {
|
|
131
|
+
const updateProjectConfigs = async ({ clientPropertyId, workingDir, environment = 'production' } = {}) => {
|
|
151
132
|
Hoek.assert(clientPropertyId, 'clientPropertyId is required');
|
|
152
133
|
Hoek.assert(workingDir, 'workingDir is required');
|
|
153
134
|
|
|
@@ -174,7 +155,7 @@ const updateProjectConfigs = async ({
|
|
|
174
155
|
const { host } = new URL(api.options.apiUrl);
|
|
175
156
|
log.info(``);
|
|
176
157
|
log.info(`Project configs applied to ${chalk.bold(host)}`);
|
|
177
|
-
return
|
|
158
|
+
return;
|
|
178
159
|
} catch (error) {
|
|
179
160
|
log.info(``);
|
|
180
161
|
log.error('Failed to apply project configs', error);
|
|
@@ -186,48 +167,37 @@ const collateConfigs = (api, localConfigs) => {
|
|
|
186
167
|
const toRemove = {};
|
|
187
168
|
const toSet = {};
|
|
188
169
|
|
|
189
|
-
Object.entries(localConfigs).forEach(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const isSchemaReadOnly = api._isSchemaReadOnly(schema);
|
|
170
|
+
Object.entries(localConfigs).forEach(([configName, { data: config = {} } = {}]) => {
|
|
171
|
+
const schema = api.getSchema(configName);
|
|
172
|
+
const isSchemaReadOnly = api._isSchemaReadOnly(schema);
|
|
193
173
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
174
|
+
if (isSchemaReadOnly) {
|
|
175
|
+
log.warn(`Skipping read-only schema: ${configName}`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
198
178
|
|
|
199
|
-
|
|
179
|
+
const configDefault = api._getDefaultConfig(configName);
|
|
200
180
|
|
|
201
|
-
|
|
202
|
-
configDefault,
|
|
203
|
-
config
|
|
204
|
-
);
|
|
181
|
+
const unsetKeysWithDefaults = getUnsetKeysWithDefaults(configDefault, config);
|
|
205
182
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
183
|
+
// remove any keys that are read-only from the unset keys collection
|
|
184
|
+
// we don't want to be deleting those!
|
|
185
|
+
for (const key in unsetKeysWithDefaults) {
|
|
186
|
+
if (api._isSchemaReadOnly(schema.extract(key))) {
|
|
187
|
+
delete unsetKeysWithDefaults[key];
|
|
212
188
|
}
|
|
213
|
-
|
|
214
|
-
toRemove[configName] = Object.keys(unsetKeysWithDefaults);
|
|
215
|
-
toSet[configName] = config;
|
|
216
189
|
}
|
|
217
|
-
|
|
190
|
+
|
|
191
|
+
toRemove[configName] = Object.keys(unsetKeysWithDefaults);
|
|
192
|
+
toSet[configName] = config;
|
|
193
|
+
});
|
|
218
194
|
|
|
219
195
|
return { toRemove, toSet };
|
|
220
196
|
};
|
|
221
197
|
|
|
222
198
|
const getUnsetKeysWithDefaults = (defaults = {}, config = {}) => {
|
|
223
|
-
Hoek.assert(
|
|
224
|
-
|
|
225
|
-
'defaults must be an object'
|
|
226
|
-
);
|
|
227
|
-
Hoek.assert(
|
|
228
|
-
typeof config === 'object' && config !== null,
|
|
229
|
-
'config must be an object'
|
|
230
|
-
);
|
|
199
|
+
Hoek.assert(typeof defaults === 'object' && defaults !== null, 'defaults must be an object');
|
|
200
|
+
Hoek.assert(typeof config === 'object' && config !== null, 'config must be an object');
|
|
231
201
|
|
|
232
202
|
const diff = {};
|
|
233
203
|
for (const key in defaults) {
|
|
@@ -243,17 +213,12 @@ const removeConfigs = async (api, toRemove) => {
|
|
|
243
213
|
keys.map(async (key) => {
|
|
244
214
|
try {
|
|
245
215
|
await api.deleteConfig(configName, key);
|
|
246
|
-
log.success(
|
|
247
|
-
`Successfully removed ${chalk.bold(key)} from ${chalk.bold(configName)}`
|
|
248
|
-
);
|
|
216
|
+
log.success(`Successfully removed ${chalk.bold(key)} from ${chalk.bold(configName)}`);
|
|
249
217
|
} catch (error) {
|
|
250
|
-
log.error(
|
|
251
|
-
`Failed to remove ${chalk.bold(key)} from ${chalk.bold(configName)}:`,
|
|
252
|
-
error
|
|
253
|
-
);
|
|
218
|
+
log.error(`Failed to remove ${chalk.bold(key)} from ${chalk.bold(configName)}:`, error);
|
|
254
219
|
throw error;
|
|
255
220
|
}
|
|
256
|
-
})
|
|
221
|
+
}),
|
|
257
222
|
);
|
|
258
223
|
|
|
259
224
|
return Promise.all(operations);
|
|
@@ -264,17 +229,12 @@ const setConfigs = async (api, toSet) => {
|
|
|
264
229
|
Object.entries(config).map(async ([key, value]) => {
|
|
265
230
|
try {
|
|
266
231
|
await api.setConfig(configName, key, value);
|
|
267
|
-
log.success(
|
|
268
|
-
`Successfully set ${chalk.bold(key)} in ${chalk.bold(configName)}`
|
|
269
|
-
);
|
|
232
|
+
log.success(`Successfully set ${chalk.bold(key)} in ${chalk.bold(configName)}`);
|
|
270
233
|
} catch (error) {
|
|
271
|
-
log.error(
|
|
272
|
-
`Failed to set ${chalk.bold(key)} in ${chalk.bold(configName)}:`,
|
|
273
|
-
error
|
|
274
|
-
);
|
|
234
|
+
log.error(`Failed to set ${chalk.bold(key)} in ${chalk.bold(configName)}:`, error);
|
|
275
235
|
throw error;
|
|
276
236
|
}
|
|
277
|
-
})
|
|
237
|
+
}),
|
|
278
238
|
);
|
|
279
239
|
|
|
280
240
|
return Promise.all(operations);
|
package/bin/utils/cpid-lookup.js
CHANGED
|
@@ -19,8 +19,8 @@ exports.doCpidLookup = async (clientPropertyId) => {
|
|
|
19
19
|
.catch((error) => {
|
|
20
20
|
log.error(
|
|
21
21
|
`Unable to lookup CPID [${chalk.yellow(
|
|
22
|
-
clientPropertyId
|
|
23
|
-
)}] from ${chalk.cyan(API_URL)}: ${chalk.redBright(error.message)}\n
|
|
22
|
+
clientPropertyId,
|
|
23
|
+
)}] from ${chalk.cyan(API_URL)}: ${chalk.redBright(error.message)}\n`,
|
|
24
24
|
);
|
|
25
25
|
|
|
26
26
|
throw Error(error.message);
|
|
@@ -26,10 +26,7 @@ exports.cpIdMatchesGitRemote = async (fertConfig) => {
|
|
|
26
26
|
baseDir: fertConfig.workingDir,
|
|
27
27
|
};
|
|
28
28
|
const git = simpleGit(simpleGitOptions);
|
|
29
|
-
Hoek.assert(
|
|
30
|
-
await git.checkIsRepo(),
|
|
31
|
-
`detected fert config in${fertConfigDir}, but it is not a git repository`
|
|
32
|
-
);
|
|
29
|
+
Hoek.assert(await git.checkIsRepo(), `detected fert config in${fertConfigDir}, but it is not a git repository`);
|
|
33
30
|
|
|
34
31
|
// Validate that the CPID in the fert config matches the CPID in the git remote URL
|
|
35
32
|
try {
|
|
@@ -38,22 +35,20 @@ exports.cpIdMatchesGitRemote = async (fertConfig) => {
|
|
|
38
35
|
const repo = parts[parts.length - 1].trim();
|
|
39
36
|
const remoteUrlCpid = repo.split('madgex-')[1].trim().replace('.git', '');
|
|
40
37
|
|
|
41
|
-
if (remoteUrlCpid
|
|
38
|
+
if (remoteUrlCpid === fertConfig.clientPropertyId) {
|
|
42
39
|
return true;
|
|
43
40
|
}
|
|
44
41
|
|
|
45
42
|
// Big ugly console message for high visibility.
|
|
46
43
|
console.log(
|
|
47
44
|
dedent`
|
|
48
|
-
${chalk.bgRed.bold(
|
|
49
|
-
'💀 💀 💀 Client Property IDs do not match! 💀 💀 💀 '
|
|
50
|
-
)}
|
|
45
|
+
${chalk.bgRed.bold('💀 💀 💀 Client Property IDs do not match! 💀 💀 💀 ')}
|
|
51
46
|
${chalk.red('CPID from fert.config.js:')} ${fertConfig.clientPropertyId}
|
|
52
47
|
${chalk.red('CPID from Git remote URL:')} ${remoteUrlCpid}
|
|
53
48
|
${chalk.bgYellow.bold(
|
|
54
|
-
'🤓 Please ensure that the Client Property Id from the fert.config.js and the git remote match 🧐 '
|
|
49
|
+
'🤓 Please ensure that the Client Property Id from the fert.config.js and the git remote match 🧐 ',
|
|
55
50
|
)}\n
|
|
56
|
-
|
|
51
|
+
`,
|
|
57
52
|
);
|
|
58
53
|
} catch (error) {
|
|
59
54
|
console.log(error);
|
package/bin/utils/index.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
const path = require('node:path');
|
|
2
2
|
const fs = require('node:fs');
|
|
3
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
3
4
|
const { glob } = require('node:fs/promises');
|
|
4
|
-
const {
|
|
5
|
-
VERSION,
|
|
6
|
-
FERT_CONFIG_FILENAME,
|
|
7
|
-
FERT_SERVICE_CONFIG_FILENAME,
|
|
8
|
-
} = require('../../constants');
|
|
5
|
+
const { VERSION, FERT_CONFIG_FILENAME, FERT_SERVICE_CONFIG_FILENAME } = require('../../constants');
|
|
9
6
|
const chalk = require('chalk');
|
|
10
7
|
const uuidValidator = require('uuid-validate');
|
|
11
8
|
const Hoek = require('@hapi/hoek');
|
|
@@ -56,7 +53,7 @@ exports.resolveConfig = async (options = {}) => {
|
|
|
56
53
|
|
|
57
54
|
// workingDir based on service folder
|
|
58
55
|
const { dir: workingDir, serviceConfig } = serviceConfigs.find(
|
|
59
|
-
(item) => item.serviceConfig.serviceName === options.serviceName
|
|
56
|
+
(item) => item.serviceConfig.serviceName === options.serviceName,
|
|
60
57
|
);
|
|
61
58
|
const fertConfig = Hoek.applyToDefaults(
|
|
62
59
|
defaults,
|
|
@@ -64,20 +61,17 @@ exports.resolveConfig = async (options = {}) => {
|
|
|
64
61
|
{
|
|
65
62
|
...this.loadConfigFromFile({ dir: rootDir }),
|
|
66
63
|
...serviceConfig,
|
|
67
|
-
}
|
|
64
|
+
},
|
|
68
65
|
);
|
|
69
66
|
|
|
70
67
|
// Check Fert cpid is valid
|
|
71
68
|
Hoek.assert(
|
|
72
69
|
uuidValidator(fertConfig.clientPropertyId),
|
|
73
|
-
`Invalid clientPropertyId specified in fert.config.js: ${fertConfig.clientPropertyId}
|
|
70
|
+
`Invalid clientPropertyId specified in fert.config.js: ${fertConfig.clientPropertyId}`,
|
|
74
71
|
);
|
|
75
72
|
|
|
76
73
|
// Check Fert serviceName is valid
|
|
77
|
-
Hoek.assert(
|
|
78
|
-
typeof fertConfig.serviceName === 'string',
|
|
79
|
-
`serviceName required: ${fertConfig.serviceName}`
|
|
80
|
-
);
|
|
74
|
+
Hoek.assert(typeof fertConfig.serviceName === 'string', `serviceName required: ${fertConfig.serviceName}`);
|
|
81
75
|
// get & store the current git branch
|
|
82
76
|
fertConfig.currBranch = (await git.branch()).current;
|
|
83
77
|
|
|
@@ -86,7 +80,7 @@ exports.resolveConfig = async (options = {}) => {
|
|
|
86
80
|
|
|
87
81
|
Hoek.assert(
|
|
88
82
|
fertCpidMatchesGitRemote,
|
|
89
|
-
`CPID mismatch, please correct before retrying: ${fertConfig.clientPropertyId}
|
|
83
|
+
`CPID mismatch, please correct before retrying: ${fertConfig.clientPropertyId}`,
|
|
90
84
|
);
|
|
91
85
|
|
|
92
86
|
const client = await cpidLookup(fertConfig.clientPropertyId);
|
|
@@ -145,11 +139,7 @@ exports.loadServiceConfigFiles = async () => {
|
|
|
145
139
|
return serviceConfigs;
|
|
146
140
|
};
|
|
147
141
|
|
|
148
|
-
exports.loadConfigFromFile = ({
|
|
149
|
-
dir = process.cwd(),
|
|
150
|
-
filename = FERT_CONFIG_FILENAME,
|
|
151
|
-
silent = false,
|
|
152
|
-
}) => {
|
|
142
|
+
exports.loadConfigFromFile = ({ dir = process.cwd(), filename = FERT_CONFIG_FILENAME, silent = false }) => {
|
|
153
143
|
const configPath = path.resolve(dir, filename);
|
|
154
144
|
try {
|
|
155
145
|
// always return fresh config
|
|
@@ -162,14 +152,13 @@ exports.loadConfigFromFile = ({
|
|
|
162
152
|
return fertConfig;
|
|
163
153
|
} catch (err) {
|
|
164
154
|
if (!silent) {
|
|
165
|
-
log.error(
|
|
166
|
-
`Failed to load ${filename} - ensure you're running fert on a branding repo & config exists.\n`
|
|
167
|
-
);
|
|
155
|
+
log.error(`Failed to load ${filename} - ensure you're running fert on a branding repo & config exists.\n`);
|
|
168
156
|
|
|
169
157
|
console.error(err);
|
|
170
158
|
throw err;
|
|
171
159
|
}
|
|
172
160
|
}
|
|
161
|
+
return null;
|
|
173
162
|
};
|
|
174
163
|
|
|
175
164
|
exports.ensureTrailingSlash = (str) => {
|
|
@@ -178,17 +167,17 @@ exports.ensureTrailingSlash = (str) => {
|
|
|
178
167
|
return lastChar === '/' ? str : `${str}/`;
|
|
179
168
|
};
|
|
180
169
|
|
|
181
|
-
exports.exists = async (
|
|
170
|
+
exports.exists = async (_path) => {
|
|
182
171
|
try {
|
|
183
|
-
fs.access(
|
|
172
|
+
fs.access(_path);
|
|
184
173
|
return true;
|
|
185
174
|
} catch {
|
|
186
175
|
return false;
|
|
187
176
|
}
|
|
188
177
|
};
|
|
189
178
|
|
|
190
|
-
exports.isEmptyDir = function isEmptyDir(
|
|
191
|
-
const files = fs.readdirSync(
|
|
179
|
+
exports.isEmptyDir = function isEmptyDir(_path) {
|
|
180
|
+
const files = fs.readdirSync(_path);
|
|
192
181
|
return files.length === 0 || (files.length === 1 && files[0] === '.git');
|
|
193
182
|
};
|
|
194
183
|
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
const {
|
|
2
|
-
CloudFrontClient,
|
|
3
|
-
ListDistributionsCommand,
|
|
4
|
-
} = require('@aws-sdk/client-cloudfront');
|
|
1
|
+
const { CloudFrontClient, ListDistributionsCommand } = require('@aws-sdk/client-cloudfront');
|
|
5
2
|
const { persistentCacheWithTtl } = require('./persistent-cache-with-ttl');
|
|
6
3
|
const assert = require('node:assert');
|
|
7
4
|
const { ONE_WEEK, AWS_REGION } = require('../../constants');
|
|
@@ -19,9 +16,7 @@ exports.doGetAllCloudFrontDistributions = async () => {
|
|
|
19
16
|
let isTruncated = false;
|
|
20
17
|
|
|
21
18
|
do {
|
|
22
|
-
const list = await cloudfront.send(
|
|
23
|
-
new ListDistributionsCommand({ Marker })
|
|
24
|
-
);
|
|
19
|
+
const list = await cloudfront.send(new ListDistributionsCommand({ Marker }));
|
|
25
20
|
|
|
26
21
|
Marker = list.DistributionList.NextMarker;
|
|
27
22
|
isTruncated = list.DistributionList.IsTruncated;
|
|
@@ -6,18 +6,14 @@ class LinkAsset {
|
|
|
6
6
|
this.href = arg;
|
|
7
7
|
} else if (typeof arg === 'object') {
|
|
8
8
|
if (!arg.href) {
|
|
9
|
-
throw new Error(
|
|
10
|
-
'External assets - the link is missing the href property'
|
|
11
|
-
);
|
|
9
|
+
throw new Error('External assets - the link is missing the href property');
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
for (const [key, value] of Object.entries(arg)) {
|
|
15
13
|
this[key] = value;
|
|
16
14
|
}
|
|
17
15
|
} else {
|
|
18
|
-
throw new Error(
|
|
19
|
-
'External assets - the value should be a string or an object'
|
|
20
|
-
);
|
|
16
|
+
throw new Error('External assets - the value should be a string or an object');
|
|
21
17
|
}
|
|
22
18
|
}
|
|
23
19
|
}
|
|
@@ -29,13 +25,12 @@ class ScriptAsset {
|
|
|
29
25
|
this.src = arg;
|
|
30
26
|
} else if (typeof arg === 'object') {
|
|
31
27
|
if (!arg.src) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
'External assets - the script is missing the src property'
|
|
34
|
-
);
|
|
28
|
+
throw new Error('External assets - the script is missing the src property');
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
// in case defer has been set to false in the config, we remove it so it's not added to the object
|
|
38
32
|
if (arg.defer === false) {
|
|
33
|
+
// eslint-disable-next-line no-param-reassign
|
|
39
34
|
delete arg.defer;
|
|
40
35
|
}
|
|
41
36
|
|
|
@@ -48,9 +43,7 @@ class ScriptAsset {
|
|
|
48
43
|
delete this.async;
|
|
49
44
|
}
|
|
50
45
|
} else {
|
|
51
|
-
throw new Error(
|
|
52
|
-
'External assets - the value should be a string or an object'
|
|
53
|
-
);
|
|
46
|
+
throw new Error('External assets - the value should be a string or an object');
|
|
54
47
|
}
|
|
55
48
|
}
|
|
56
49
|
}
|
|
@@ -70,9 +63,7 @@ function resolveExternalAssets(assets = {}) {
|
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
if (assets.scripts) {
|
|
73
|
-
const scriptArr = Array.isArray(assets.scripts)
|
|
74
|
-
? assets.scripts
|
|
75
|
-
: [assets.scripts];
|
|
66
|
+
const scriptArr = Array.isArray(assets.scripts) ? assets.scripts : [assets.scripts];
|
|
76
67
|
|
|
77
68
|
scriptArr.forEach((item) => {
|
|
78
69
|
result.scripts.push(new ScriptAsset(item));
|
package/constants.js
CHANGED
|
@@ -2,9 +2,7 @@ const fs = require('node:fs');
|
|
|
2
2
|
const path = require('node:path');
|
|
3
3
|
const os = require('node:os');
|
|
4
4
|
|
|
5
|
-
const { version: VERSION } = JSON.parse(
|
|
6
|
-
fs.readFileSync(path.resolve(__dirname, './package.json')).toString()
|
|
7
|
-
);
|
|
5
|
+
const { version: VERSION } = JSON.parse(fs.readFileSync(path.resolve(__dirname, './package.json')).toString());
|
|
8
6
|
|
|
9
7
|
const ONE_MINUTE = 60000;
|
|
10
8
|
const ONE_HOUR = ONE_MINUTE * 60;
|
|
@@ -16,8 +14,7 @@ module.exports = {
|
|
|
16
14
|
TMP_DIR: fs.realpathSync(os.tmpdir()),
|
|
17
15
|
FERT_PACKAGE_DIR: path.resolve('./'),
|
|
18
16
|
AWS_REGION: 'eu-west-1',
|
|
19
|
-
PROPERTY_ID_API:
|
|
20
|
-
'https://property-identification-api.cs.madgexhosting.net/properties/',
|
|
17
|
+
PROPERTY_ID_API: 'https://property-identification-api.cs.madgexhosting.net/properties/',
|
|
21
18
|
ASSETS_API_URL: 'https://asset-store.job.madgexhosting.net',
|
|
22
19
|
BRAND_JSON_FILENAME: 'brand.json',
|
|
23
20
|
FERT_CONFIG_FILENAME: 'fert.config.js',
|
|
@@ -34,8 +31,7 @@ module.exports = {
|
|
|
34
31
|
/**
|
|
35
32
|
* important to have the correct service name and cpid so assets are uploaded to the correct unique place per-service.
|
|
36
33
|
*/
|
|
37
|
-
REMOTE_UPLOAD_BASE:
|
|
38
|
-
'/api/assets/{fertConfig.serviceName}/{fertConfig.clientPropertyId}',
|
|
34
|
+
REMOTE_UPLOAD_BASE: '/api/assets/{fertConfig.serviceName}/{fertConfig.clientPropertyId}',
|
|
39
35
|
/**
|
|
40
36
|
* invalidates the real asset store key path, which is related to `REMOTE_UPLOAD_BASE`
|
|
41
37
|
* asset-store puts things in `rootClientPropertyId` based on the AWS_PARAM_NAME used, and the rest of the path relates to `REMOTE_UPLOAD_BASE`
|
|
@@ -50,16 +46,6 @@ module.exports = {
|
|
|
50
46
|
*/
|
|
51
47
|
BRANDED_SITE_INVALIDATION_PATH: `/_/{fertConfig.serviceName}/assets/*`,
|
|
52
48
|
ASSET_STORE_USER_GUID: 'a386d4b6-f2df-4b80-ad1f-0349e23f530b',
|
|
53
|
-
TEMPLATES: [
|
|
54
|
-
{
|
|
55
|
-
name: 'basic',
|
|
56
|
-
display: 'Basic - blank canvas',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: 'bigworkbag',
|
|
60
|
-
display: 'BigWorkBag - populated, example project',
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
49
|
ONE_MINUTE,
|
|
64
50
|
ONE_HOUR,
|
|
65
51
|
ONE_DAY,
|