No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

optionsHelper.js 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getParams = exports.getSecretEnvVars = exports.getNonSecretEnv = exports.getExtensionFunctionInfo = exports.buildOptions = void 0;
  4. const fs = require("fs-extra");
  5. const path = require("path");
  6. const paramHelper = require("../paramHelper");
  7. const specHelper = require("./specHelper");
  8. const localHelper = require("../localHelper");
  9. const triggerHelper = require("./triggerHelper");
  10. const types_1 = require("../types");
  11. const extensionsHelper = require("../extensionsHelper");
  12. const planner = require("../../deploy/extensions/planner");
  13. const config_1 = require("../../config");
  14. const error_1 = require("../../error");
  15. const emulatorLogger_1 = require("../../emulator/emulatorLogger");
  16. const projectUtils_1 = require("../../projectUtils");
  17. const types_2 = require("../../emulator/types");
  18. async function buildOptions(options) {
  19. const extDevDir = localHelper.findExtensionYaml(process.cwd());
  20. options.extDevDir = extDevDir;
  21. const spec = await specHelper.readExtensionYaml(extDevDir);
  22. extensionsHelper.validateSpec(spec);
  23. const params = getParams(options, spec);
  24. extensionsHelper.validateCommandLineParams(params, spec.params);
  25. const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, params);
  26. let testConfig;
  27. if (options.testConfig) {
  28. testConfig = readTestConfigFile(options.testConfig);
  29. checkTestConfig(testConfig, functionResources);
  30. }
  31. options.config = buildConfig(functionResources, testConfig);
  32. options.extDevEnv = params;
  33. const functionEmuTriggerDefs = functionResources.map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r));
  34. options.extDevTriggers = functionEmuTriggerDefs;
  35. options.extDevNodeVersion = specHelper.getNodeVersion(functionResources);
  36. return options;
  37. }
  38. exports.buildOptions = buildOptions;
  39. async function getExtensionFunctionInfo(instance, paramValues) {
  40. const spec = await planner.getExtensionSpec(instance);
  41. const functionResources = specHelper.getFunctionResourcesWithParamSubstitution(spec, paramValues);
  42. const extensionTriggers = functionResources
  43. .map((r) => triggerHelper.functionResourceToEmulatedTriggerDefintion(r))
  44. .map((trigger) => {
  45. trigger.name = `ext-${instance.instanceId}-${trigger.name}`;
  46. return trigger;
  47. });
  48. const nodeMajorVersion = specHelper.getNodeVersion(functionResources);
  49. const nonSecretEnv = getNonSecretEnv(spec.params, paramValues);
  50. const secretEnvVariables = getSecretEnvVars(spec.params, paramValues);
  51. return {
  52. extensionTriggers,
  53. nodeMajorVersion,
  54. nonSecretEnv,
  55. secretEnvVariables,
  56. };
  57. }
  58. exports.getExtensionFunctionInfo = getExtensionFunctionInfo;
  59. const isSecretParam = (p) => p.type === extensionsHelper.SpecParamType.SECRET || p.type === types_1.ParamType.SECRET;
  60. function getNonSecretEnv(params, paramValues) {
  61. const getNonSecretEnv = Object.assign({}, paramValues);
  62. const secretParams = params.filter(isSecretParam);
  63. for (const p of secretParams) {
  64. delete getNonSecretEnv[p.param];
  65. }
  66. return getNonSecretEnv;
  67. }
  68. exports.getNonSecretEnv = getNonSecretEnv;
  69. function getSecretEnvVars(params, paramValues) {
  70. const secretEnvVar = [];
  71. const secretParams = params.filter(isSecretParam);
  72. for (const s of secretParams) {
  73. if (paramValues[s.param]) {
  74. const [, projectId, , secret, , version] = paramValues[s.param].split("/");
  75. secretEnvVar.push({
  76. key: s.param,
  77. secret,
  78. projectId,
  79. version,
  80. });
  81. }
  82. }
  83. return secretEnvVar;
  84. }
  85. exports.getSecretEnvVars = getSecretEnvVars;
  86. function getParams(options, extensionSpec) {
  87. const projectId = (0, projectUtils_1.needProjectId)(options);
  88. const userParams = paramHelper.readEnvFile(options.testParams);
  89. const autoParams = {
  90. PROJECT_ID: projectId,
  91. EXT_INSTANCE_ID: extensionSpec.name,
  92. DATABASE_INSTANCE: projectId,
  93. DATABASE_URL: `https://${projectId}.firebaseio.com`,
  94. STORAGE_BUCKET: `${projectId}.appspot.com`,
  95. };
  96. const unsubbedParamsWithoutDefaults = Object.assign(autoParams, userParams);
  97. const unsubbedParams = extensionsHelper.populateDefaultParams(unsubbedParamsWithoutDefaults, extensionSpec.params);
  98. return extensionsHelper.substituteParams(unsubbedParams, unsubbedParams);
  99. }
  100. exports.getParams = getParams;
  101. function checkTestConfig(testConfig, functionResources) {
  102. const logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_2.Emulators.FUNCTIONS);
  103. if (!testConfig.functions && functionResources.length) {
  104. logger.log("WARN", "This extension uses functions," +
  105. "but 'firebase.json' provided by --test-config is missing a top-level 'functions' object." +
  106. "Functions will not be emulated.");
  107. }
  108. if (!testConfig.firestore && shouldEmulateFirestore(functionResources)) {
  109. logger.log("WARN", "This extension interacts with Cloud Firestore," +
  110. "but 'firebase.json' provided by --test-config is missing a top-level 'firestore' object." +
  111. "Cloud Firestore will not be emulated.");
  112. }
  113. if (!testConfig.database && shouldEmulateDatabase(functionResources)) {
  114. logger.log("WARN", "This extension interacts with Realtime Database," +
  115. "but 'firebase.json' provided by --test-config is missing a top-level 'database' object." +
  116. "Realtime Database will not be emulated.");
  117. }
  118. if (!testConfig.storage && shouldEmulateStorage(functionResources)) {
  119. logger.log("WARN", "This extension interacts with Cloud Storage," +
  120. "but 'firebase.json' provided by --test-config is missing a top-level 'storage' object." +
  121. "Cloud Storage will not be emulated.");
  122. }
  123. }
  124. function readTestConfigFile(testConfigPath) {
  125. try {
  126. const buf = fs.readFileSync(path.resolve(testConfigPath));
  127. return JSON.parse(buf.toString());
  128. }
  129. catch (err) {
  130. throw new error_1.FirebaseError(`Error reading --test-config file: ${err.message}\n`, {
  131. original: err,
  132. });
  133. }
  134. }
  135. function buildConfig(functionResources, testConfig) {
  136. const config = new config_1.Config(testConfig || {}, { projectDir: process.cwd(), cwd: process.cwd() });
  137. const emulateFunctions = shouldEmulateFunctions(functionResources);
  138. if (!testConfig) {
  139. if (emulateFunctions) {
  140. config.set("functions", {});
  141. }
  142. if (shouldEmulateFirestore(functionResources)) {
  143. config.set("firestore", {});
  144. }
  145. if (shouldEmulateDatabase(functionResources)) {
  146. config.set("database", {});
  147. }
  148. if (shouldEmulatePubsub(functionResources)) {
  149. config.set("pubsub", {});
  150. }
  151. if (shouldEmulateStorage(functionResources)) {
  152. config.set("storage", {});
  153. }
  154. }
  155. if (config.src.functions) {
  156. const sourceDirectory = getFunctionSourceDirectory(functionResources);
  157. config.set("functions.source", sourceDirectory);
  158. }
  159. return config;
  160. }
  161. function getFunctionSourceDirectory(functionResources) {
  162. var _a;
  163. let sourceDirectory;
  164. for (const r of functionResources) {
  165. const dir = ((_a = r.properties) === null || _a === void 0 ? void 0 : _a.sourceDirectory) || "functions";
  166. if (!sourceDirectory) {
  167. sourceDirectory = dir;
  168. }
  169. else if (sourceDirectory !== dir) {
  170. throw new error_1.FirebaseError(`Found function resources with different sourceDirectories: '${sourceDirectory}' and '${dir}'. The extensions emulator only supports a single sourceDirectory.`);
  171. }
  172. }
  173. return sourceDirectory || "functions";
  174. }
  175. function shouldEmulateFunctions(resources) {
  176. return resources.length > 0;
  177. }
  178. function shouldEmulate(emulatorName, resources) {
  179. var _a, _b;
  180. for (const r of resources) {
  181. const eventType = ((_b = (_a = r.properties) === null || _a === void 0 ? void 0 : _a.eventTrigger) === null || _b === void 0 ? void 0 : _b.eventType) || "";
  182. if (eventType.includes(emulatorName)) {
  183. return true;
  184. }
  185. }
  186. return false;
  187. }
  188. function shouldEmulateFirestore(resources) {
  189. return shouldEmulate("cloud.firestore", resources);
  190. }
  191. function shouldEmulateDatabase(resources) {
  192. return shouldEmulate("google.firebase.database", resources);
  193. }
  194. function shouldEmulatePubsub(resources) {
  195. return shouldEmulate("google.pubsub", resources);
  196. }
  197. function shouldEmulateStorage(resources) {
  198. return shouldEmulate("google.storage", resources);
  199. }