@madgex/fert 4.1.2 → 4.2.1
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/.github/workflows/release.yml +2 -2
- package/README.md +85 -2
- package/bin/cli.js +4 -0
- package/bin/commands/configs.js +146 -44
- package/bin/commands/configs.test.js +162 -0
- package/bin/utils/configs.js +20 -18
- package/bin/utils/getSchemaKeyMeta.js +14 -0
- package/bin/utils/index.js +2 -0
- package/eslint.config.mjs +53 -0
- package/package.json +21 -18
- package/server/templates/page1.njk +1 -1
- package/shared/README.md +1 -1
- package/.eslintignore +0 -8
- package/.eslintrc.js +0 -15
|
@@ -16,10 +16,10 @@ jobs:
|
|
|
16
16
|
- name: Checkout
|
|
17
17
|
uses: actions/checkout@v4
|
|
18
18
|
- name: Setup Node.js
|
|
19
|
-
uses: actions/setup-node@
|
|
19
|
+
uses: actions/setup-node@v4
|
|
20
20
|
with:
|
|
21
21
|
cache: npm
|
|
22
|
-
node-version:
|
|
22
|
+
node-version: 22
|
|
23
23
|
|
|
24
24
|
- name: Setup SSH Keys and known_hosts
|
|
25
25
|
env:
|
package/README.md
CHANGED
|
@@ -190,6 +190,91 @@ Index all the files and their paths in the `dist` directory, and using a recursi
|
|
|
190
190
|
|
|
191
191
|
The Asset Store API uses a multi-part form upload to PUT files in the client directory. Upload paths are respected, directories are created on the fly.
|
|
192
192
|
|
|
193
|
+
## Configs
|
|
194
|
+
|
|
195
|
+
`fert configs`
|
|
196
|
+
|
|
197
|
+
A set of commands to help with publishing, downloading & referencing project configs.
|
|
198
|
+
|
|
199
|
+
**Usage**
|
|
200
|
+
|
|
201
|
+
`fert configs [root] --[query|download|publish] [env]`
|
|
202
|
+
|
|
203
|
+
| Option | Description |
|
|
204
|
+
| -------------------- | --------------------------------------------------------------------------------------- |
|
|
205
|
+
| --query [configName] | Describe known keys for a config, omit to list all known configs |
|
|
206
|
+
| --download <env> | Download known configs from the Configuration API for environment "dev" or "production" |
|
|
207
|
+
| --publish | Publish configs to Configuration API environment "dev" or "production" |
|
|
208
|
+
|
|
209
|
+
### Example usage
|
|
210
|
+
|
|
211
|
+
Its assumed you're running from a branding repo in all examples
|
|
212
|
+
|
|
213
|
+
#### Review all known configs
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# fert configs --query
|
|
217
|
+
|
|
218
|
+
Fert v0.0.0-development
|
|
219
|
+
|
|
220
|
+
Available config schemas...
|
|
221
|
+
* JobSeekerDesignConfig
|
|
222
|
+
* JobSeekerSiteConfig
|
|
223
|
+
* jsfe-config
|
|
224
|
+
* webconfig
|
|
225
|
+
...
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### Review validation schema & default values for a config
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# fert configs --query JobBoardConfig.filesizeDefinitions
|
|
232
|
+
|
|
233
|
+
Fert v0.0.0-development
|
|
234
|
+
|
|
235
|
+
Getting schema description for config: JobBoardConfig.filesizeDefinitions...
|
|
236
|
+
{
|
|
237
|
+
"documents": {
|
|
238
|
+
"type": "number",
|
|
239
|
+
"flags": {
|
|
240
|
+
"description": "The definition in MBs of how large documents can be",
|
|
241
|
+
"default": 1
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
Configs default values:
|
|
247
|
+
{
|
|
248
|
+
"documents": 1
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### Download known configs for the current client (specified in `fert.config.js`) from the Configuration API. This is intended as a one-time command to get the current config values in the repo
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# fert configs --download production
|
|
256
|
+
|
|
257
|
+
Fert v0.0.0-development
|
|
258
|
+
✔ Downloading v6 configs...
|
|
259
|
+
Saving files...
|
|
260
|
+
- JobBoardConfig.applicationForm.json
|
|
261
|
+
- JobBoardConfig.articlesFilterByDate.json
|
|
262
|
+
- JobBoardConfig.careerpathCountryIso.json
|
|
263
|
+
- JobBoardConfig.careerpathGlobalRoleSettings.json
|
|
264
|
+
...
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Publish all known, valid configs found in branding repos `./config/*` for the current client. In this scenario, there is only `./config/jsfe-config.json`
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# fert configs --publish production
|
|
271
|
+
|
|
272
|
+
Fert v0.0.0-development
|
|
273
|
+
✔ Config validated: jsfe-config
|
|
274
|
+
✔ Project configs applied to configuration-api.job.madgexhosting.net
|
|
275
|
+
upload
|
|
276
|
+
```
|
|
277
|
+
|
|
193
278
|
# Global options
|
|
194
279
|
|
|
195
280
|
These options are available no matter the command used.
|
|
@@ -216,5 +301,3 @@ Here are the default npm scripts in a Fert-scaffolded project.
|
|
|
216
301
|
```
|
|
217
302
|
|
|
218
303
|
Its expected that a Jenkins pipeline will run `fert publish` to send all built assets to the Asset Store API.
|
|
219
|
-
|
|
220
|
-
.
|
package/bin/cli.js
CHANGED
|
@@ -44,6 +44,10 @@ const run = () => {
|
|
|
44
44
|
'--publish <env>',
|
|
45
45
|
'Publish configs to Configuration API environment "dev" or "production"'
|
|
46
46
|
)
|
|
47
|
+
.option(
|
|
48
|
+
'--download <env>',
|
|
49
|
+
'Download known configs from the Configuration API for environment "dev" or "production"'
|
|
50
|
+
)
|
|
47
51
|
.option(
|
|
48
52
|
'--query [configName]',
|
|
49
53
|
'Describe known keys for a config, omit to list all known configs'
|
package/bin/commands/configs.js
CHANGED
|
@@ -6,65 +6,167 @@ const {
|
|
|
6
6
|
} = require('../utils/configs.js');
|
|
7
7
|
const chalk = require('chalk');
|
|
8
8
|
const { log } = require('../utils/logging.js');
|
|
9
|
+
const { getSchemaKeyMeta } = require('../utils/getSchemaKeyMeta.js');
|
|
10
|
+
const ora = require('ora');
|
|
11
|
+
const { mkdir, writeFile } = require('node:fs/promises');
|
|
12
|
+
const Path = require('node:path');
|
|
13
|
+
const { CONFIG_DIR } = require('../../constants.js');
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const api = await getConfigAPI(fertConfig);
|
|
15
|
+
const handleDownload = async (fertConfig, api, options) => {
|
|
16
|
+
const validTargets = ['dev', 'production'];
|
|
13
17
|
|
|
14
|
-
if (!
|
|
15
|
-
|
|
18
|
+
if (!validTargets.includes(options.download)) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Missing or invalid --download option. Choose from [${validTargets}]`
|
|
21
|
+
);
|
|
16
22
|
}
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
const spinner = ora('Downloading v6 configs...').start();
|
|
25
|
+
const resultObj = {};
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
);
|
|
25
|
-
}
|
|
27
|
+
try {
|
|
28
|
+
for (const [schemaName, schema] of Object.entries(api.schemas)) {
|
|
29
|
+
const configs = await api.getSchemaKeys(schemaName);
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
log.debug(err);
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
} else if (options.query) {
|
|
35
|
-
try {
|
|
36
|
-
if (options.query !== true) {
|
|
37
|
-
console.log(
|
|
38
|
-
chalk.cyan(`\nGetting ${options.query} schema description...`)
|
|
39
|
-
);
|
|
40
|
-
const schema = api.schemas[options.query];
|
|
41
|
-
if (!schema) {
|
|
42
|
-
console.error(chalk.red(`Schema not found for ${options.query}`));
|
|
43
|
-
return;
|
|
31
|
+
for (const configKey of configs) {
|
|
32
|
+
const meta = getSchemaKeyMeta(schema, configKey);
|
|
33
|
+
if (meta.readOnly) {
|
|
34
|
+
continue;
|
|
44
35
|
}
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
37
|
+
try {
|
|
38
|
+
const data = await api.getConfig(schemaName, configKey, {
|
|
39
|
+
useSchema: false,
|
|
40
|
+
});
|
|
41
|
+
if (!data.isDefault) {
|
|
42
|
+
let result = data.result;
|
|
43
|
+
try {
|
|
44
|
+
result = JSON.parse(result);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
log.debug(
|
|
47
|
+
`Unable to JSON parse ${chalk.cyan(data.response?.url || schemaName + '/' + configKey)} error:`,
|
|
48
|
+
error.message
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
resultObj[schemaName] = {
|
|
53
|
+
...result[schemaName],
|
|
54
|
+
[configKey]: result,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
log.debug(
|
|
59
|
+
`Unable to retrieve ${chalk.cyan(error.url || schemaName + '/' + configKey)}`,
|
|
60
|
+
error.message || error.statusText || error
|
|
61
|
+
);
|
|
62
|
+
}
|
|
51
63
|
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
spinner.succeed();
|
|
67
|
+
} catch (error) {
|
|
68
|
+
spinner.fail(
|
|
69
|
+
`Error ${error.code ? `[${error.code}]` : ''}: ${error.message}`
|
|
70
|
+
);
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(chalk.green('Saving files...'));
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
78
|
+
} catch (error) {
|
|
79
|
+
log.debug(`Unable to create directory ${CONFIG_DIR}`, error);
|
|
80
|
+
// basically ignore error
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const [schemaName, data] of Object.entries(resultObj)) {
|
|
84
|
+
const filePath = Path.join(CONFIG_DIR, `${schemaName}.json`);
|
|
85
|
+
await writeFile(filePath, JSON.stringify(data, null, 2));
|
|
86
|
+
console.log(` - ${schemaName}.json`);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const handlePublish = async (fertConfig, api, options) => {
|
|
91
|
+
const validTargets = ['dev', 'production'];
|
|
52
92
|
|
|
53
|
-
|
|
93
|
+
if (!validTargets.includes(options.publish)) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Missing or invalid --publish option. Choose from [${validTargets}]`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
await validateLocalConfigs(fertConfig, { catch: false });
|
|
101
|
+
await updateProjectConfigs(fertConfig, { environment: options.publish });
|
|
102
|
+
console.log('upload');
|
|
103
|
+
} catch (err) {
|
|
104
|
+
log.debug(err);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const handleQuery = async (fertConfig, api, options) => {
|
|
110
|
+
try {
|
|
111
|
+
if (options.query !== true) {
|
|
54
112
|
console.log(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.join('\n'),
|
|
59
|
-
'\n'
|
|
113
|
+
chalk.cyan(
|
|
114
|
+
`\nGetting schema description for config: ${chalk.bold(options.query)}...`
|
|
115
|
+
)
|
|
60
116
|
);
|
|
117
|
+
const schema = api.schemas[options.query];
|
|
118
|
+
if (!schema) {
|
|
119
|
+
console.error(
|
|
120
|
+
chalk.red(`Schema not found for ${chalk.bold(options.query)}`)
|
|
121
|
+
);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
61
124
|
|
|
125
|
+
console.log(JSON.stringify(schema.describe().keys, null, 2));
|
|
62
126
|
console.log(
|
|
63
|
-
'
|
|
127
|
+
`\n${chalk.cyan('Configs default values')}:\n${JSON.stringify(schema.validate({}).value, null, 2)}`
|
|
64
128
|
);
|
|
65
|
-
|
|
66
|
-
log.debug(err);
|
|
67
|
-
process.exit(1);
|
|
129
|
+
return;
|
|
68
130
|
}
|
|
131
|
+
|
|
132
|
+
console.log(chalk.cyan(`\nAvailable config schemas...`));
|
|
133
|
+
console.log(
|
|
134
|
+
Object.keys(api.schemas)
|
|
135
|
+
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
|
136
|
+
.map((key) => ` * ${key}`)
|
|
137
|
+
.join('\n'),
|
|
138
|
+
'\n'
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
console.log(
|
|
142
|
+
'Use `fert configs <configName>` to get a specific schema description'
|
|
143
|
+
);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
log.debug(err);
|
|
146
|
+
process.exit(1);
|
|
69
147
|
}
|
|
70
148
|
};
|
|
149
|
+
|
|
150
|
+
module.exports = async (root, options) => {
|
|
151
|
+
const fertConfig = await resolveConfig(root, options);
|
|
152
|
+
const api = await getConfigAPI(fertConfig);
|
|
153
|
+
|
|
154
|
+
if (!options.publish && !options.query && !options.download) {
|
|
155
|
+
console.log(
|
|
156
|
+
chalk.red(`Missing required --publish, --query or --download option`)
|
|
157
|
+
);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (options.download) {
|
|
162
|
+
await handleDownload(fertConfig, api, options);
|
|
163
|
+
} else if (options.publish) {
|
|
164
|
+
await handlePublish(fertConfig, api, options);
|
|
165
|
+
} else if (options.query) {
|
|
166
|
+
await handleQuery(fertConfig, api, options);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
module.exports.handleDownload = handleDownload;
|
|
171
|
+
module.exports.handlePublish = handlePublish;
|
|
172
|
+
module.exports.handleQuery = handleQuery;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const assert = require('node:assert');
|
|
2
|
+
const { describe, it, beforeEach } = require('node:test');
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const Path = require('node:path');
|
|
5
|
+
const Joi = require('joi');
|
|
6
|
+
|
|
7
|
+
describe('configs', () => {
|
|
8
|
+
let fertConfig;
|
|
9
|
+
let api;
|
|
10
|
+
let mkdirMock;
|
|
11
|
+
let writeFileMock;
|
|
12
|
+
let handleDownload;
|
|
13
|
+
let handleQuery;
|
|
14
|
+
let handlePublish;
|
|
15
|
+
|
|
16
|
+
beforeEach(async (t) => {
|
|
17
|
+
fertConfig = {
|
|
18
|
+
clientPropertyId: 'ff6102ff-0f4b-43d1-a2c7-83b835b8dee5',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const { ConfigAPI } = await import('@madgex/config-api-sdk');
|
|
22
|
+
|
|
23
|
+
api = new ConfigAPI({
|
|
24
|
+
clientPropertyId: fertConfig.clientPropertyId,
|
|
25
|
+
environment: 'dev',
|
|
26
|
+
schemas: {
|
|
27
|
+
'jsfe-config': Joi.object({
|
|
28
|
+
StrConfig: Joi.string().default('My new JSFE config'),
|
|
29
|
+
}),
|
|
30
|
+
},
|
|
31
|
+
fetch: async () => ({
|
|
32
|
+
ok: true,
|
|
33
|
+
json: async () => ({
|
|
34
|
+
status: 'success',
|
|
35
|
+
data: [
|
|
36
|
+
{
|
|
37
|
+
configName: 'jsfe-config',
|
|
38
|
+
key: 'StrConfig',
|
|
39
|
+
value: '"hello"',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
}),
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Set up mocks before requiring the module that uses them
|
|
47
|
+
mkdirMock = t.mock.method(fs, 'mkdir', async () => {});
|
|
48
|
+
writeFileMock = t.mock.method(fs, 'writeFile', async () => {});
|
|
49
|
+
|
|
50
|
+
// Clear require cache to ensure we get a fresh copy with our mocks
|
|
51
|
+
delete require.cache[require.resolve('./configs')];
|
|
52
|
+
({ handleDownload, handleQuery, handlePublish } = require('./configs'));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('handleDownload', () => {
|
|
56
|
+
let options;
|
|
57
|
+
|
|
58
|
+
beforeEach(async () => {
|
|
59
|
+
options = { download: 'dev' };
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('iterates over known schemas', async () => {
|
|
63
|
+
await handleDownload(fertConfig, api, options);
|
|
64
|
+
|
|
65
|
+
assert.strictEqual(Object.keys(api.schemas).length, 1);
|
|
66
|
+
assert.strictEqual(mkdirMock.mock.calls.length, 1);
|
|
67
|
+
assert.strictEqual(mkdirMock.mock.calls[0].arguments[0], 'config');
|
|
68
|
+
assert.strictEqual(writeFileMock.mock.calls.length, 1); // Only one schema
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('saves to the expected place', async () => {
|
|
72
|
+
await handleDownload(fertConfig, api, options);
|
|
73
|
+
|
|
74
|
+
assert.strictEqual(writeFileMock.mock.calls.length, 1);
|
|
75
|
+
|
|
76
|
+
assert.strictEqual(
|
|
77
|
+
writeFileMock.mock.calls[0].arguments[0],
|
|
78
|
+
Path.join('config', 'jsfe-config.json')
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('writes the expected data', async () => {
|
|
83
|
+
await handleDownload(fertConfig, api, options);
|
|
84
|
+
|
|
85
|
+
assert.strictEqual(writeFileMock.mock.calls.length, 1);
|
|
86
|
+
|
|
87
|
+
const jsfeConfig = JSON.parse(writeFileMock.mock.calls[0].arguments[1]);
|
|
88
|
+
assert.strictEqual(Object.keys(jsfeConfig).length, 1);
|
|
89
|
+
assert.strictEqual(jsfeConfig.StrConfig, 'hello');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('skips read-only keys', async () => {
|
|
93
|
+
// clone api object including prototype
|
|
94
|
+
const tweakedApi = Object.assign(
|
|
95
|
+
Object.create(Object.getPrototypeOf(api)),
|
|
96
|
+
api
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
tweakedApi.schemas = {
|
|
100
|
+
'jsfe-config': Joi.object({
|
|
101
|
+
StrConfig: Joi.string().default('My new JSFE config'),
|
|
102
|
+
ReadOnlyConfig: Joi.string()
|
|
103
|
+
.default('I am read-only')
|
|
104
|
+
.meta({ readOnly: true }),
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
await handleDownload(fertConfig, tweakedApi, options);
|
|
109
|
+
|
|
110
|
+
assert.strictEqual(writeFileMock.mock.calls.length, 1);
|
|
111
|
+
|
|
112
|
+
const jsfeConfig = JSON.parse(writeFileMock.mock.calls[0].arguments[1]);
|
|
113
|
+
assert.strictEqual(Object.keys(jsfeConfig).length, 1);
|
|
114
|
+
assert.strictEqual(jsfeConfig.ReadOnlyConfig, undefined);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe.skip('handlePublish', () => {
|
|
119
|
+
let options;
|
|
120
|
+
|
|
121
|
+
beforeEach(async () => {
|
|
122
|
+
options = { publish: true };
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('publishes the configs', async () => {
|
|
126
|
+
await handlePublish(fertConfig, api, options);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe.skip('handleQuery', () => {
|
|
130
|
+
let options;
|
|
131
|
+
|
|
132
|
+
beforeEach(async () => {
|
|
133
|
+
options = { query: true };
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('logs available schemas if query option is true', async () => {
|
|
137
|
+
await handleQuery(fertConfig, api, options);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it.skip('logs schema description if query option is valid', async (t) => {
|
|
141
|
+
const api = {
|
|
142
|
+
schemas: {
|
|
143
|
+
testSchema: {
|
|
144
|
+
describe: () => ({ keys: {} }),
|
|
145
|
+
validate: () => ({}),
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
const options = { query: 'testSchema' };
|
|
150
|
+
let logMessage = '';
|
|
151
|
+
|
|
152
|
+
t.mock.method(console, 'log', (message) => {
|
|
153
|
+
logMessage += message;
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await handleQuery(api, options);
|
|
157
|
+
|
|
158
|
+
assert(logMessage.includes('Getting testSchema schema description...'));
|
|
159
|
+
assert(logMessage.includes('Defaults'));
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
package/bin/utils/configs.js
CHANGED
|
@@ -77,25 +77,27 @@ const loadLocalConfigs = (fertConfig) => {
|
|
|
77
77
|
const configs = {};
|
|
78
78
|
const files = fs.readdirSync(dir);
|
|
79
79
|
|
|
80
|
-
files
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
80
|
+
files
|
|
81
|
+
.filter((file) => file.endsWith('.json'))
|
|
82
|
+
.forEach((file) => {
|
|
83
|
+
const filePath = path.join(dir, file);
|
|
84
|
+
|
|
85
|
+
if (fs.statSync(filePath).isFile()) {
|
|
86
|
+
const fileName = path.basename(file, path.extname(file));
|
|
87
|
+
|
|
88
|
+
// Purge any existing cache of the file
|
|
89
|
+
delete require.cache[filePath];
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
configs[fileName] = {
|
|
93
|
+
path: filePath,
|
|
94
|
+
data: require(filePath),
|
|
95
|
+
};
|
|
96
|
+
} catch (err) {
|
|
97
|
+
log.error(`Error loading config (${filePath}): ${err.message}`);
|
|
98
|
+
}
|
|
96
99
|
}
|
|
97
|
-
}
|
|
98
|
-
});
|
|
100
|
+
});
|
|
99
101
|
|
|
100
102
|
return configs;
|
|
101
103
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const getSchemaKeyMeta = function (schema, key) {
|
|
2
|
+
if (!schema) throw new Error('Schema is required');
|
|
3
|
+
if (!key) throw new Error('Key is required');
|
|
4
|
+
|
|
5
|
+
const keySchema = schema.extract(key);
|
|
6
|
+
if (!keySchema) {
|
|
7
|
+
throw new Error(`Key "${key}" not found in schema`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const metas = keySchema.describe().metas;
|
|
11
|
+
return Array.isArray(metas) && metas.length > 0 ? metas[0] : {};
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = { getSchemaKeyMeta };
|
package/bin/utils/index.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import prettier from 'eslint-plugin-prettier';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import js from '@eslint/js';
|
|
6
|
+
import { FlatCompat } from '@eslint/eslintrc';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const compat = new FlatCompat({
|
|
11
|
+
baseDirectory: __dirname,
|
|
12
|
+
recommendedConfig: js.configs.recommended,
|
|
13
|
+
allConfig: js.configs.all,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export default [
|
|
17
|
+
{
|
|
18
|
+
ignores: [
|
|
19
|
+
'**/dist',
|
|
20
|
+
'**/temp',
|
|
21
|
+
'**/dist',
|
|
22
|
+
'**/*.json',
|
|
23
|
+
'**/*.json',
|
|
24
|
+
'**/.eslintrc.js',
|
|
25
|
+
'**/node_modules',
|
|
26
|
+
'**/repo-templates',
|
|
27
|
+
'eslint.config.mjs',
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
...compat.extends('eslint:recommended', 'plugin:prettier/recommended'),
|
|
31
|
+
{
|
|
32
|
+
plugins: {
|
|
33
|
+
prettier,
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
languageOptions: {
|
|
37
|
+
globals: {
|
|
38
|
+
...globals.node,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
ecmaVersion: 'latest',
|
|
42
|
+
sourceType: 'commonjs',
|
|
43
|
+
|
|
44
|
+
parserOptions: {
|
|
45
|
+
requireConfigFile: false,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
rules: {
|
|
50
|
+
'prettier/prettier': 'error',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madgex/fert",
|
|
3
|
-
"version": "4.1
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"description": "Tool to help build the V6 branding",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fert": "./bin/cli.js"
|
|
@@ -23,23 +23,23 @@
|
|
|
23
23
|
"author": "Madgex",
|
|
24
24
|
"license": "UNLICENSED",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@aws-sdk/client-cloudfront": "^3.
|
|
27
|
-
"@aws-sdk/client-ssm": "^3.
|
|
28
|
-
"@aws-sdk/credential-providers": "^3.
|
|
29
|
-
"@hapi/hapi": "^21.3.
|
|
30
|
-
"@hapi/hoek": "^11.0.
|
|
26
|
+
"@aws-sdk/client-cloudfront": "^3.716.0",
|
|
27
|
+
"@aws-sdk/client-ssm": "^3.716.0",
|
|
28
|
+
"@aws-sdk/credential-providers": "^3.716.0",
|
|
29
|
+
"@hapi/hapi": "^21.3.12",
|
|
30
|
+
"@hapi/hoek": "^11.0.7",
|
|
31
31
|
"@hapi/inert": "^7.1.0",
|
|
32
32
|
"@hapi/vision": "^7.0.3",
|
|
33
33
|
"@hapipal/toys": "^4.0.0",
|
|
34
|
-
"@madgex/config-api-sdk": "^1.0.
|
|
35
|
-
"@madgex/design-system": "^9.1.
|
|
34
|
+
"@madgex/config-api-sdk": "^1.0.13",
|
|
35
|
+
"@madgex/design-system": "^9.1.9",
|
|
36
36
|
"@private/header-footer-podlet-server": "github:wiley/madgex-header-footer-podlet",
|
|
37
|
-
"axios": "^1.7.
|
|
37
|
+
"axios": "^1.7.9",
|
|
38
38
|
"cac": "^6.7.14",
|
|
39
39
|
"chalk": "4.1.2",
|
|
40
40
|
"chokidar": "^3.5.3",
|
|
41
41
|
"dayjs": "^1.11.13",
|
|
42
|
-
"debug": "^4.
|
|
42
|
+
"debug": "^4.4.0",
|
|
43
43
|
"dedent": "^1.5.3",
|
|
44
44
|
"flat-cache": "^4.0.0",
|
|
45
45
|
"form-data": "^4.0.1",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"ora": "5.4.1",
|
|
50
50
|
"prompts": "^2.4.2",
|
|
51
51
|
"rimraf": "^5.0.5",
|
|
52
|
-
"sass": "^1.
|
|
52
|
+
"sass": "^1.83.0",
|
|
53
53
|
"simple-git": "^3.27.0",
|
|
54
54
|
"simple-update-notifier": "^2.0.0",
|
|
55
55
|
"style-dictionary": "3.9.0",
|
|
@@ -58,17 +58,20 @@
|
|
|
58
58
|
"vite-plugin-static-copy": "^0.17.1"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@commitlint/cli": "^19.6.
|
|
61
|
+
"@commitlint/cli": "^19.6.1",
|
|
62
62
|
"@commitlint/config-conventional": "^19.6.0",
|
|
63
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
64
|
+
"@eslint/js": "^9.17.0",
|
|
63
65
|
"commitizen": "^4.3.1",
|
|
64
66
|
"cz-conventional-changelog": "^3.3.0",
|
|
65
|
-
"eslint": "^
|
|
66
|
-
"eslint-config-prettier": "^9.
|
|
67
|
-
"eslint-plugin-prettier": "^5.
|
|
67
|
+
"eslint": "^9.17.0",
|
|
68
|
+
"eslint-config-prettier": "^9.1.0",
|
|
69
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
70
|
+
"globals": "^15.14.0",
|
|
68
71
|
"husky": "^9.1.7",
|
|
69
|
-
"lint-staged": "^15.
|
|
70
|
-
"prettier": "^3.
|
|
71
|
-
"semantic-release": "^
|
|
72
|
+
"lint-staged": "^15.3.0",
|
|
73
|
+
"prettier": "^3.4.2",
|
|
74
|
+
"semantic-release": "^24.2.0"
|
|
72
75
|
},
|
|
73
76
|
"peerDependencies": {
|
|
74
77
|
"@ctrl/tinycolor": "^3.6.0"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<div class="mds-branded-container mds-branded-container--1 mds-padding-b4 mds-padding-bottom-b5 mds-margin-bottom-b5">
|
|
31
31
|
<h2 class="mds-font-s2">Branded Container</h2>
|
|
32
32
|
<p class="mds-margin-bottom-b4">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
|
|
33
|
-
<a href="#" draggable="false" class="mds-button mds-button--
|
|
33
|
+
<a href="#" draggable="false" class="mds-button mds-button--small">Lorem ipsum</a>
|
|
34
34
|
</div>
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
package/shared/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
The docker file in this folder (`Dockerfile.brandingRepoPublish`) will be used by Jenkins to build and publish the repo assets to S3.
|
|
2
2
|
|
|
3
3
|
When changes are pushed on a project repo, Jenkins will clone this repo, extract the docker file and use it to build and publish the assets to S3.
|
|
4
|
-
If the changes are on a branch other than master, the assets will be sent to the jb-dev S3 bucket. If the changes are pushed to master, they will be sent to the production bucket.
|
|
4
|
+
If the changes are on a branch other than master, the assets will be sent to the jb-dev S3 bucket. If the changes are pushed to master, they will be sent to the production bucket.
|
package/.eslintignore
DELETED
package/.eslintrc.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
env: {
|
|
3
|
-
node: true,
|
|
4
|
-
es6: true,
|
|
5
|
-
},
|
|
6
|
-
plugins: ['prettier'],
|
|
7
|
-
extends: ['eslint:recommended', 'plugin:prettier/recommended'],
|
|
8
|
-
parserOptions: {
|
|
9
|
-
requireConfigFile: false,
|
|
10
|
-
ecmaVersion: 'latest',
|
|
11
|
-
},
|
|
12
|
-
rules: {
|
|
13
|
-
'prettier/prettier': 'error',
|
|
14
|
-
},
|
|
15
|
-
};
|