backend-manager 5.0.30 → 5.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/bem +1 -1
- package/firebase-debug.log +28 -0
- package/package.json +1 -1
- package/src/cli/cli-refactored.js +0 -21
- package/src/cli/cli.js +41 -204
- package/src/cli/commands/index.js +0 -1
- package/src/cli/commands/install.js +1 -1
- package/src/cli/commands/serve.js +1 -6
- package/src/cli/commands/setup-tests/backend-manager-tests-file.js +23 -0
- package/src/cli/commands/setup-tests/backend-manager.js +79 -0
- package/src/cli/commands/setup-tests/base-test.js +36 -0
- package/src/cli/commands/setup-tests/bem-config-id.js +25 -0
- package/src/cli/commands/setup-tests/bem-config.js +59 -0
- package/src/cli/commands/setup-tests/env-runtime-config.js +68 -0
- package/src/cli/commands/setup-tests/firebase-admin.js +71 -0
- package/src/cli/commands/setup-tests/firebase-cli.js +30 -0
- package/src/cli/commands/setup-tests/firebase-functions.js +71 -0
- package/src/cli/commands/setup-tests/firestore-indexes-file.js +34 -0
- package/src/cli/commands/setup-tests/firestore-indexes-in-json.js +20 -0
- package/src/cli/commands/setup-tests/firestore-indexes-synced.js +69 -0
- package/src/cli/commands/setup-tests/firestore-rules-file.js +52 -0
- package/src/cli/commands/setup-tests/firestore-rules-in-json.js +20 -0
- package/src/cli/commands/setup-tests/functions-package.js +25 -0
- package/src/cli/commands/setup-tests/gitignore.js +40 -0
- package/src/cli/commands/setup-tests/helpers.js +24 -0
- package/src/cli/commands/setup-tests/hosting-folder.js +23 -0
- package/src/cli/commands/setup-tests/hosting-rewrites.js +34 -0
- package/src/cli/commands/setup-tests/index.js +82 -0
- package/src/cli/commands/setup-tests/is-firebase-project.js +21 -0
- package/src/cli/commands/setup-tests/node-version.js +34 -0
- package/src/cli/commands/setup-tests/npm-dist-script.js +20 -0
- package/src/cli/commands/setup-tests/npm-start-script.js +20 -0
- package/src/cli/commands/setup-tests/nvmrc-version.js +30 -0
- package/src/cli/commands/setup-tests/public-html-files.js +33 -0
- package/src/cli/commands/setup-tests/realtime-rules-file.js +52 -0
- package/src/cli/commands/setup-tests/realtime-rules-in-json.js +20 -0
- package/src/cli/commands/setup-tests/remoteconfig-template-file.js +32 -0
- package/src/cli/commands/setup-tests/remoteconfig-template-in-json.js +20 -0
- package/src/cli/commands/setup-tests/service-account.js +39 -0
- package/src/cli/commands/setup-tests/storage-lifecycle-policy.js +46 -0
- package/src/cli/commands/setup-tests/storage-rules-file.js +32 -0
- package/src/cli/commands/setup-tests/storage-rules-in-json.js +20 -0
- package/src/cli/commands/setup.js +46 -69
- package/templates/runtimeconfig.json +3 -6
- package/src/cli/commands/config.js +0 -165
package/bin/bem
CHANGED
package/firebase-debug.log
CHANGED
|
@@ -22,3 +22,31 @@
|
|
|
22
22
|
[debug] [2025-10-20T23:59:40.562Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
23
23
|
[debug] [2025-10-20T23:59:40.563Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
24
24
|
[debug] [2025-10-20T23:59:40.563Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
25
|
+
[debug] [2025-11-18T02:05:23.261Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
26
|
+
[debug] [2025-11-18T02:05:23.267Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
27
|
+
[debug] [2025-11-18T02:05:23.263Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
28
|
+
[debug] [2025-11-18T02:05:23.263Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
29
|
+
[debug] [2025-11-18T02:05:23.263Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
30
|
+
[debug] [2025-11-18T02:05:23.271Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
31
|
+
[debug] [2025-11-18T02:05:23.271Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
32
|
+
[debug] [2025-11-18T02:05:23.269Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
33
|
+
[debug] [2025-11-18T02:05:23.269Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
34
|
+
[debug] [2025-11-18T02:05:23.269Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
35
|
+
[debug] [2025-11-18T02:05:23.277Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
36
|
+
[debug] [2025-11-18T02:05:23.278Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
37
|
+
[debug] [2025-11-18T02:05:23.329Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
38
|
+
[debug] [2025-11-18T02:05:23.331Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
39
|
+
[debug] [2025-11-18T02:05:23.330Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
40
|
+
[debug] [2025-11-18T02:05:23.331Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
41
|
+
[debug] [2025-11-18T02:05:23.331Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
42
|
+
[debug] [2025-11-18T02:05:23.332Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
43
|
+
[debug] [2025-11-18T02:05:23.332Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
44
|
+
[debug] [2025-11-18T02:05:23.333Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
45
|
+
[debug] [2025-11-18T02:05:23.333Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
46
|
+
[debug] [2025-11-18T02:05:23.331Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
47
|
+
[debug] [2025-11-18T02:05:23.332Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
48
|
+
[debug] [2025-11-18T02:05:23.332Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
49
|
+
[debug] [2025-11-18T02:05:23.333Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
50
|
+
[debug] [2025-11-18T02:05:23.333Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
51
|
+
[debug] [2025-11-18T02:05:23.334Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
52
|
+
[debug] [2025-11-18T02:05:23.334Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
package/package.json
CHANGED
|
@@ -12,7 +12,6 @@ const DeployCommand = require('./commands/deploy');
|
|
|
12
12
|
const TestCommand = require('./commands/test');
|
|
13
13
|
const CleanCommand = require('./commands/clean');
|
|
14
14
|
const IndexesCommand = require('./commands/indexes');
|
|
15
|
-
const ConfigCommand = require('./commands/config');
|
|
16
15
|
|
|
17
16
|
function Main() {}
|
|
18
17
|
|
|
@@ -81,26 +80,6 @@ Main.prototype.process = async function (args) {
|
|
|
81
80
|
return await cmd.get(undefined, true);
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
// Get config
|
|
85
|
-
if (self.options['functions:config:get'] || self.options['config:get']) {
|
|
86
|
-
const cmd = new ConfigCommand(self);
|
|
87
|
-
return await cmd.get();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Set config
|
|
91
|
-
if (self.options['functions:config:set'] || self.options['config:set']) {
|
|
92
|
-
const cmd = new ConfigCommand(self);
|
|
93
|
-
await cmd.set();
|
|
94
|
-
return await cmd.get();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Unset config
|
|
98
|
-
if (self.options['functions:config:unset'] || self.options['config:unset'] || self.options['config:delete'] || self.options['config:remove']) {
|
|
99
|
-
const cmd = new ConfigCommand(self);
|
|
100
|
-
await cmd.unset();
|
|
101
|
-
return await cmd.get();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
83
|
// Deploy
|
|
105
84
|
if (self.options.deploy) {
|
|
106
85
|
const cmd = new DeployCommand(self);
|
package/src/cli/cli.js
CHANGED
|
@@ -52,7 +52,7 @@ let bem_allRulesBackupRegex = /({{\s*?backend-manager\s*?}})/sgm;
|
|
|
52
52
|
let MOCHA_PKG_SCRIPT = 'mocha ../test/ --recursive --timeout=10000';
|
|
53
53
|
let NPM_CLEAN_SCRIPT = 'rm -fr node_modules && rm -fr package-lock.json && npm cache clean --force && npm install && npm rb';
|
|
54
54
|
let NOFIX_TEXT = chalk.red(`There is no automatic fix for this check.`);
|
|
55
|
-
let
|
|
55
|
+
let envRuntimeTemplate = loadJSON(`${__dirname}/../../templates/runtimeconfig.json`);
|
|
56
56
|
let bemConfigTemplate = loadJSON(`${__dirname}/../../templates/backend-manager-config.json`);
|
|
57
57
|
|
|
58
58
|
function Main() {
|
|
@@ -98,7 +98,6 @@ Main.prototype.process = async function (args) {
|
|
|
98
98
|
|
|
99
99
|
// Setup command
|
|
100
100
|
if (self.options.setup) {
|
|
101
|
-
await cmd_configGet(self).catch(e => log(chalk.red(`Failed to run config:get`)));
|
|
102
101
|
await self.setup();
|
|
103
102
|
}
|
|
104
103
|
|
|
@@ -118,7 +117,6 @@ Main.prototype.process = async function (args) {
|
|
|
118
117
|
if (self.options.serve) {
|
|
119
118
|
if (!self.options.quick && !self.options.q) {
|
|
120
119
|
}
|
|
121
|
-
await cmd_configGet(self);
|
|
122
120
|
await self.setup();
|
|
123
121
|
|
|
124
122
|
const port = self.argv.port || _.get(self.argv, '_', [])[1] || '5000';
|
|
@@ -133,26 +131,6 @@ Main.prototype.process = async function (args) {
|
|
|
133
131
|
return await cmd.get(undefined, true);
|
|
134
132
|
}
|
|
135
133
|
|
|
136
|
-
// Get config
|
|
137
|
-
if (self.options['functions:config:get'] || self.options['config:get']) {
|
|
138
|
-
const cmd = new commands.ConfigCommand(self);
|
|
139
|
-
return await cmd.get();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Set config
|
|
143
|
-
if (self.options['functions:config:set'] || self.options['config:set']) {
|
|
144
|
-
const cmd = new commands.ConfigCommand(self);
|
|
145
|
-
await cmd.set();
|
|
146
|
-
return await cmd.get();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Unset config
|
|
150
|
-
if (self.options['functions:config:unset'] || self.options['config:unset'] || self.options['config:delete'] || self.options['config:remove']) {
|
|
151
|
-
const cmd = new commands.ConfigCommand(self);
|
|
152
|
-
await cmd.unset();
|
|
153
|
-
return await cmd.get();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
134
|
// Deploy
|
|
157
135
|
if (self.options.deploy) {
|
|
158
136
|
await self.setup();
|
|
@@ -204,11 +182,26 @@ Main.prototype.setup = async function () {
|
|
|
204
182
|
|
|
205
183
|
log(chalk.green(`\n---- RUNNING SETUP v${self.default.version} ----`));
|
|
206
184
|
|
|
185
|
+
// Load environment variables from .env file
|
|
186
|
+
const envPath = `${self.firebaseProjectPath}/functions/.env`;
|
|
187
|
+
if (jetpack.exists(envPath)) {
|
|
188
|
+
require('dotenv').config({ path: envPath });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Parse runtime config from .env
|
|
192
|
+
self.runtimeConfigJSON = {};
|
|
193
|
+
if (process.env.RUNTIME_CONFIG) {
|
|
194
|
+
try {
|
|
195
|
+
self.runtimeConfigJSON = JSON5.parse(process.env.RUNTIME_CONFIG);
|
|
196
|
+
} catch (e) {
|
|
197
|
+
// Will be caught in test
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
207
201
|
// Load files
|
|
208
202
|
self.package = loadJSON(`${self.firebaseProjectPath}/functions/package.json`);
|
|
209
203
|
self.firebaseJSON = loadJSON(`${self.firebaseProjectPath}/firebase.json`);
|
|
210
204
|
self.firebaseRC = loadJSON(`${self.firebaseProjectPath}/.firebaserc`);
|
|
211
|
-
self.runtimeConfigJSON = loadJSON(`${self.firebaseProjectPath}/functions/.runtimeconfig.json`);
|
|
212
205
|
self.remoteconfigJSON = loadJSON(`${self.firebaseProjectPath}/functions/remoteconfig.template.json`);
|
|
213
206
|
self.projectPackage = loadJSON(`${self.firebaseProjectPath}/package.json`);
|
|
214
207
|
self.bemConfigJSON = loadJSON(`${self.firebaseProjectPath}/functions/backend-manager-config.json`);
|
|
@@ -405,13 +398,29 @@ Main.prototype.setup = async function () {
|
|
|
405
398
|
return self.package.scripts.dist
|
|
406
399
|
}, fix_distScript);
|
|
407
400
|
|
|
408
|
-
// Test: Is the project using a proper .
|
|
409
|
-
await self.test('using proper .
|
|
401
|
+
// Test: Is the project using a proper .env with RUNTIME_CONFIG
|
|
402
|
+
await self.test('using proper .env with RUNTIME_CONFIG', async function () {
|
|
403
|
+
// Check if .env file exists
|
|
404
|
+
const envPath = `${self.firebaseProjectPath}/functions/.env`;
|
|
405
|
+
if (!jetpack.exists(envPath)) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Check if RUNTIME_CONFIG exists in process.env
|
|
410
|
+
if (!process.env.RUNTIME_CONFIG) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Check if runtimeConfigJSON was parsed successfully
|
|
415
|
+
if (!hasContent(self.runtimeConfigJSON)) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
|
|
410
419
|
// Set pass
|
|
411
420
|
let pass = true;
|
|
412
421
|
|
|
413
422
|
// Loop through all the keys in the template
|
|
414
|
-
powertools.getKeys(
|
|
423
|
+
powertools.getKeys(envRuntimeTemplate).forEach((key) => {
|
|
415
424
|
const userValue = _.get(self.runtimeConfigJSON, key, undefined);
|
|
416
425
|
|
|
417
426
|
// If the user value is undefined, then we need to set pass to false
|
|
@@ -422,7 +431,7 @@ Main.prototype.setup = async function () {
|
|
|
422
431
|
|
|
423
432
|
// Return result
|
|
424
433
|
return pass;
|
|
425
|
-
},
|
|
434
|
+
}, fix_envRuntimeConfig);
|
|
426
435
|
|
|
427
436
|
// Test: Is the project using a proper backend-manager-config.json
|
|
428
437
|
await self.test('using proper backend-manager-config.json', async function () {
|
|
@@ -754,14 +763,14 @@ function bemPackageVersionWarning(package, current, latest) {
|
|
|
754
763
|
}
|
|
755
764
|
}
|
|
756
765
|
|
|
757
|
-
async function
|
|
766
|
+
async function fix_envRuntimeConfig(self) {
|
|
758
767
|
return new Promise(function(resolve, reject) {
|
|
759
768
|
// Log
|
|
760
769
|
log(NOFIX_TEXT);
|
|
761
|
-
log(chalk.red(`You need to
|
|
770
|
+
log(chalk.red(`You need to manually edit ${chalk.bold(`functions/.env`)} and ensure RUNTIME_CONFIG has these keys:`));
|
|
762
771
|
|
|
763
772
|
// Log what keys are missing
|
|
764
|
-
powertools.getKeys(
|
|
773
|
+
powertools.getKeys(envRuntimeTemplate).forEach((key) => {
|
|
765
774
|
const userValue = _.get(self.runtimeConfigJSON, key, undefined);
|
|
766
775
|
|
|
767
776
|
if (typeof userValue === 'undefined') {
|
|
@@ -1010,7 +1019,7 @@ function fix_hostingRewrites(self) {
|
|
|
1010
1019
|
|
|
1011
1020
|
// Add to top
|
|
1012
1021
|
hosting.rewrites.unshift({
|
|
1013
|
-
source: '
|
|
1022
|
+
source: '/backend-manager',
|
|
1014
1023
|
function: 'bm_api',
|
|
1015
1024
|
});
|
|
1016
1025
|
|
|
@@ -1287,179 +1296,7 @@ async function cmd_indexesGet(self, filePath, log) {
|
|
|
1287
1296
|
});
|
|
1288
1297
|
}
|
|
1289
1298
|
|
|
1290
|
-
async function cmd_configGet(self, filePath) {
|
|
1291
|
-
return new Promise(function(resolve, reject) {
|
|
1292
|
-
const finalPath = `${self.firebaseProjectPath}/${filePath || 'functions/.runtimeconfig.json'}`;
|
|
1293
|
-
|
|
1294
|
-
const max = 10;
|
|
1295
|
-
let retries = 0;
|
|
1296
|
-
|
|
1297
|
-
async function _attempt() {
|
|
1298
|
-
try {
|
|
1299
|
-
const output = await powertools.execute(`firebase functions:config:get > ${finalPath}`, { log: true });
|
|
1300
|
-
|
|
1301
|
-
// Log success message
|
|
1302
|
-
console.log(chalk.green(`Saving config to: ${finalPath}`));
|
|
1303
|
-
|
|
1304
|
-
// Resolve with the required config
|
|
1305
|
-
resolve(require(finalPath));
|
|
1306
|
-
} catch (error) {
|
|
1307
|
-
console.error(chalk.red(`Failed to get config: ${error}`));
|
|
1308
|
-
|
|
1309
|
-
// Check if retries are exhausted
|
|
1310
|
-
if (retries++ >= max) {
|
|
1311
|
-
return reject(error);
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
// Retry logic with delay
|
|
1315
|
-
const delay = 2500 * retries;
|
|
1316
|
-
console.error(chalk.yellow(`Retrying config:get ${retries}/${max} in ${delay}ms...`));
|
|
1317
|
-
setTimeout(_attempt, delay);
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
// Start the attempts
|
|
1322
|
-
_attempt();
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
async function cmd_configSet(self, newPath, newValue) {
|
|
1327
|
-
return new Promise(async function(resolve, reject) {
|
|
1328
|
-
// console.log(self.options);
|
|
1329
|
-
// console.log(self.argv);
|
|
1330
|
-
newPath = newPath || await inquirer.prompt([
|
|
1331
|
-
{
|
|
1332
|
-
type: 'input',
|
|
1333
|
-
name: 'path',
|
|
1334
|
-
default: 'service.key'
|
|
1335
|
-
}
|
|
1336
|
-
]).then(answers => answers.path);
|
|
1337
|
-
|
|
1338
|
-
let object = null;
|
|
1339
|
-
|
|
1340
|
-
try {
|
|
1341
|
-
object = JSON5.parse(newPath);
|
|
1342
|
-
} catch (e) {
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
const isObject = object && typeof object === 'object';
|
|
1346
|
-
|
|
1347
|
-
// If it's a string, ensure some things
|
|
1348
|
-
if (!isObject) {
|
|
1349
|
-
// Validate path
|
|
1350
|
-
if (!newPath.includes('.')) {
|
|
1351
|
-
console.log(chalk.red(`Path needs 2 parts (one.two): ${newPath}`));
|
|
1352
|
-
return reject();
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
// Make sure it's only letters, numbers, periods, and underscores
|
|
1356
|
-
if (newPath.match(/[^a-zA-Z0-9._]/)) {
|
|
1357
|
-
console.log(chalk.red(`Path contains invalid characters: ${newPath}`));
|
|
1358
|
-
return reject();
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
try {
|
|
1363
|
-
if (isObject) {
|
|
1364
|
-
const keyify = (obj, prefix = '') =>
|
|
1365
|
-
Object.keys(obj).reduce((res, el) => {
|
|
1366
|
-
if( Array.isArray(obj[el]) ) {
|
|
1367
|
-
return res;
|
|
1368
|
-
} else if( typeof obj[el] === 'object' && obj[el] !== null ) {
|
|
1369
|
-
return [...res, ...keyify(obj[el], prefix + el + '.')];
|
|
1370
|
-
}
|
|
1371
|
-
return [...res, prefix + el];
|
|
1372
|
-
}, []);
|
|
1373
|
-
const pathArray = keyify(object);
|
|
1374
|
-
for (var i = 0; i < pathArray.length; i++) {
|
|
1375
|
-
const pathName = pathArray[i];
|
|
1376
|
-
const pathValue = _.get(object, pathName);
|
|
1377
|
-
// console.log(chalk.blue(`Setting object: ${chalk.bold(pathName)} = ${chalk.bold(pathValue)}`));
|
|
1378
|
-
console.log(chalk.blue(`Setting object: ${chalk.bold(pathName)}`));
|
|
1379
|
-
await cmd_configSet(self, pathName, pathValue)
|
|
1380
|
-
.catch(e => {
|
|
1381
|
-
log(chalk.red(`Failed to save object path: ${e}`));
|
|
1382
|
-
})
|
|
1383
|
-
}
|
|
1384
|
-
return resolve();
|
|
1385
|
-
}
|
|
1386
|
-
} catch (e) {
|
|
1387
|
-
log(chalk.red(`Failed to save object: ${e}`));
|
|
1388
|
-
return reject(e)
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
newValue = newValue || await inquirer.prompt([
|
|
1392
|
-
{
|
|
1393
|
-
type: 'input',
|
|
1394
|
-
name: 'value',
|
|
1395
|
-
default: '123-abc'
|
|
1396
|
-
}
|
|
1397
|
-
]).then(answers => answers.value)
|
|
1398
|
-
|
|
1399
|
-
let isInvalid = false;
|
|
1400
|
-
if (newPath !== newPath.toLowerCase()) {
|
|
1401
|
-
isInvalid = true;
|
|
1402
|
-
newPath = newPath.replace(/([A-Z])/g, '_$1').trim().toLowerCase();
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
log(chalk.yellow(`Saving to ${chalk.bold(newPath)}...`));
|
|
1406
|
-
|
|
1407
|
-
await powertools.execute(`firebase functions:config:set ${newPath}="${newValue}"`, { log: true })
|
|
1408
|
-
.then((output) => {
|
|
1409
|
-
// Check if it was invalid
|
|
1410
|
-
if (isInvalid) {
|
|
1411
|
-
log(chalk.red(`!!! Your path contained an invalid uppercase character`));
|
|
1412
|
-
log(chalk.red(`!!! It was set to: ${chalk.bold(newPath)}`));
|
|
1413
|
-
} else {
|
|
1414
|
-
log(chalk.green(`Successfully saved to ${chalk.bold(newPath)}`));
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
// Resolve the promise
|
|
1418
|
-
resolve();
|
|
1419
|
-
})
|
|
1420
|
-
.catch((e) => {
|
|
1421
|
-
log(chalk.red(`Failed to save ${chalk.bold(newPath)}: ${e}`));
|
|
1422
|
-
|
|
1423
|
-
// Reject the promise with the error
|
|
1424
|
-
reject(e);
|
|
1425
|
-
});
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
async function cmd_configUnset(self) {
|
|
1430
|
-
return new Promise(async function(resolve, reject) {
|
|
1431
|
-
// console.log(self.options);
|
|
1432
|
-
// console.log(self.argv);
|
|
1433
|
-
await inquirer
|
|
1434
|
-
.prompt([
|
|
1435
|
-
/* Pass your questions in here */
|
|
1436
|
-
{
|
|
1437
|
-
type: 'input',
|
|
1438
|
-
name: 'path',
|
|
1439
|
-
default: 'service.key'
|
|
1440
|
-
}
|
|
1441
|
-
])
|
|
1442
|
-
.then(async (answers) => {
|
|
1443
|
-
// Use user feedback for... whatever!!
|
|
1444
|
-
// console.log('answer', answers);
|
|
1445
|
-
log(chalk.yellow(`Deleting ${chalk.bold(answers.path)}...`));
|
|
1446
|
-
|
|
1447
|
-
await powertools.execute(`firebase functions:config:unset ${answers.path}`, { log: true })
|
|
1448
|
-
.then((output) => {
|
|
1449
|
-
log(chalk.green(`Successfully deleted ${chalk.bold(answers.path)}`));
|
|
1450
1299
|
|
|
1451
|
-
// Resolve the promise
|
|
1452
|
-
resolve();
|
|
1453
|
-
})
|
|
1454
|
-
.catch((e) => {
|
|
1455
|
-
log(chalk.red(`Failed to delete ${chalk.bold(answers.path)}: ${e}`));
|
|
1456
|
-
|
|
1457
|
-
// Reject the promise with the error
|
|
1458
|
-
reject(e);
|
|
1459
|
-
});
|
|
1460
|
-
});
|
|
1461
|
-
});
|
|
1462
|
-
}
|
|
1463
1300
|
|
|
1464
1301
|
async function cmd_iamImportExport(self) {
|
|
1465
1302
|
return new Promise(async function(resolve, reject) {
|
|
@@ -14,7 +14,7 @@ class InstallCommand extends BaseCommand {
|
|
|
14
14
|
|
|
15
15
|
async installLocal() {
|
|
16
16
|
await this.uninstallPkg('backend-manager');
|
|
17
|
-
await this.installPkg(`npm install ${os.homedir()}/Developer/Repositories/ITW-Creative-Works/backend-manager
|
|
17
|
+
await this.installPkg(`npm install ${os.homedir()}/Developer/Repositories/ITW-Creative-Works/backend-manager`);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
async installLive() {
|
|
@@ -5,12 +5,7 @@ const _ = require('lodash');
|
|
|
5
5
|
class ServeCommand extends BaseCommand {
|
|
6
6
|
async execute() {
|
|
7
7
|
const self = this.main;
|
|
8
|
-
|
|
9
|
-
// Get config
|
|
10
|
-
const ConfigCommand = require('./config');
|
|
11
|
-
const configCmd = new ConfigCommand(self);
|
|
12
|
-
await configCmd.get();
|
|
13
|
-
|
|
8
|
+
|
|
14
9
|
// Run setup
|
|
15
10
|
const SetupCommand = require('./setup');
|
|
16
11
|
const setupCmd = new SetupCommand(self);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const BaseTest = require('./base-test');
|
|
2
|
+
const jetpack = require('fs-jetpack');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
class BackendManagerTestsFileTest extends BaseTest {
|
|
6
|
+
getName() {
|
|
7
|
+
return 'update backend-manager-tests.js';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async run() {
|
|
11
|
+
const self = this.self;
|
|
12
|
+
jetpack.write(`${self.firebaseProjectPath}/test/backend-manager-tests.js`,
|
|
13
|
+
(jetpack.read(path.resolve(`${__dirname}/../../../../templates/backend-manager-tests.js`)))
|
|
14
|
+
);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async fix() {
|
|
19
|
+
throw new Error('No automatic fix available for this test');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = BackendManagerTestsFileTest;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const BaseTest = require('./base-test');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const wonderfulVersion = require('wonderful-version');
|
|
4
|
+
const powertools = require('node-powertools');
|
|
5
|
+
const Npm = require('npm-api');
|
|
6
|
+
const helpers = require('./helpers');
|
|
7
|
+
|
|
8
|
+
class BackendManagerTest extends BaseTest {
|
|
9
|
+
getName() {
|
|
10
|
+
return 'using updated backend-manager';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async run() {
|
|
14
|
+
const pkg = 'backend-manager';
|
|
15
|
+
const latest = await this.getPkgVersion(pkg);
|
|
16
|
+
const mine = this.context.package.dependencies[pkg];
|
|
17
|
+
|
|
18
|
+
// Get level difference
|
|
19
|
+
const levelDifference = wonderfulVersion.levelDifference(latest, mine);
|
|
20
|
+
|
|
21
|
+
// Log if major version mismatch
|
|
22
|
+
if (!helpers.isLocal(mine) && levelDifference === 'major') {
|
|
23
|
+
console.log(chalk.red(`Version ${chalk.bold(latest)} of ${chalk.bold(pkg)} available but you must install this manually because it is a major update.`));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Ensure the version is up to date
|
|
27
|
+
return helpers.isLocal(mine) || wonderfulVersion.is(mine, '>=', latest) || levelDifference === 'major';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async fix() {
|
|
31
|
+
await this.installPkg('backend-manager');
|
|
32
|
+
|
|
33
|
+
console.log(chalk.green(`Process has exited since a new version of backend-manager was installed. Run ${chalk.bold('npx bm setup')} again.`));
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async getPkgVersion(packageName) {
|
|
38
|
+
const npm = new Npm();
|
|
39
|
+
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
npm.repo(packageName)
|
|
42
|
+
.package()
|
|
43
|
+
.then(function(pkg) {
|
|
44
|
+
resolve(pkg.version);
|
|
45
|
+
}, function(err) {
|
|
46
|
+
resolve('0.0.0');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async installPkg(name, version, type) {
|
|
52
|
+
let v;
|
|
53
|
+
let t;
|
|
54
|
+
if (name.indexOf('file:') > -1) {
|
|
55
|
+
v = '';
|
|
56
|
+
} else if (!version) {
|
|
57
|
+
v = '@latest';
|
|
58
|
+
} else {
|
|
59
|
+
v = version;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!type) {
|
|
63
|
+
t = '';
|
|
64
|
+
} else if (type === 'dev' || type === '--save-dev') {
|
|
65
|
+
t = ' --save-dev';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Build the command
|
|
69
|
+
const command = `npm i ${name}${v}${t}`;
|
|
70
|
+
|
|
71
|
+
// Log
|
|
72
|
+
console.log('Running ', command);
|
|
73
|
+
|
|
74
|
+
// Execute
|
|
75
|
+
await powertools.execute(command, { log: true });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = BackendManagerTest;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for all setup tests
|
|
3
|
+
* Each test should extend this class and implement the `run()` method
|
|
4
|
+
*/
|
|
5
|
+
class BaseTest {
|
|
6
|
+
constructor(context) {
|
|
7
|
+
this.context = context;
|
|
8
|
+
this.self = context.main;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Override this method in each test
|
|
13
|
+
* @returns {Promise<boolean>} True if test passes, false if it fails
|
|
14
|
+
*/
|
|
15
|
+
async run() {
|
|
16
|
+
throw new Error('Test must implement run() method');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Override this method to provide a fix for failed tests
|
|
21
|
+
* @returns {Promise<void>}
|
|
22
|
+
*/
|
|
23
|
+
async fix() {
|
|
24
|
+
throw new Error('No automatic fix available for this test');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the test name (used for logging)
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
getName() {
|
|
32
|
+
return this.constructor.name.replace(/Test$/, '').replace(/([A-Z])/g, ' $1').trim().toLowerCase();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = BaseTest;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const BaseTest = require('./base-test');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
|
|
4
|
+
class BemConfigIdTest extends BaseTest {
|
|
5
|
+
getName() {
|
|
6
|
+
return 'has correct ID in backend-manager-config.json';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async run() {
|
|
10
|
+
// Check if the project name matches the projectId
|
|
11
|
+
if (this.self.projectId !== this.self.bemConfigJSON?.firebaseConfig?.projectId) {
|
|
12
|
+
console.error(chalk.red('Mismatch between project name and firebaseConfig.projectId in backend-manager-config.json'));
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Return pass
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async fix() {
|
|
21
|
+
throw new Error('No automatic fix available for this test');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = BemConfigIdTest;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const BaseTest = require('./base-test');
|
|
2
|
+
const jetpack = require('fs-jetpack');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const powertools = require('node-powertools');
|
|
5
|
+
const _ = require('lodash');
|
|
6
|
+
const helpers = require('./helpers');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
// Load template
|
|
10
|
+
const bemConfigTemplate = helpers.loadJSON(path.resolve(__dirname, '../../../templates/backend-manager-config.json'));
|
|
11
|
+
|
|
12
|
+
class BemConfigTest extends BaseTest {
|
|
13
|
+
getName() {
|
|
14
|
+
return 'using proper backend-manager-config.json';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async run() {
|
|
18
|
+
// Set pass
|
|
19
|
+
let pass = true;
|
|
20
|
+
|
|
21
|
+
// Loop through all the keys in the template
|
|
22
|
+
powertools.getKeys(bemConfigTemplate).forEach((key) => {
|
|
23
|
+
const userValue = _.get(this.self.bemConfigJSON, key, undefined);
|
|
24
|
+
|
|
25
|
+
// If the user value is undefined, then we need to set pass to false
|
|
26
|
+
if (typeof userValue === 'undefined') {
|
|
27
|
+
pass = false;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Return result
|
|
32
|
+
return pass;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async fix() {
|
|
36
|
+
console.log(chalk.red(`There is no automatic fix for this check.`));
|
|
37
|
+
console.log(chalk.red(`You need to open backend-manager-config.json and set each of these keys:`));
|
|
38
|
+
|
|
39
|
+
// Write if it doesn't exist
|
|
40
|
+
if (!this.context.hasContent(this.self.bemConfigJSON)) {
|
|
41
|
+
jetpack.write(`${this.self.firebaseProjectPath}/functions/backend-manager-config.json`, {});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Log what keys are missing
|
|
45
|
+
powertools.getKeys(bemConfigTemplate).forEach((key) => {
|
|
46
|
+
const userValue = _.get(this.self.bemConfigJSON, key, undefined);
|
|
47
|
+
|
|
48
|
+
if (typeof userValue === 'undefined') {
|
|
49
|
+
console.log(chalk.red.bold(`${key}`));
|
|
50
|
+
} else {
|
|
51
|
+
console.log(chalk.red(`${key} (${userValue})`));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
throw new Error('Missing required backend-manager-config.json keys');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = BemConfigTest;
|