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.

planner.js 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.checkForV2Upgrade = exports.checkForIllegalUpdate = exports.upgradedScheduleFromV1ToV2 = exports.changedV2PubSubTopic = exports.changedTriggerRegion = exports.upgradedToGCFv2WithoutSettingConcurrency = exports.createDeploymentPlan = exports.calculateUpdate = exports.calculateChangesets = void 0;
  4. const clc = require("colorette");
  5. const functionsDeployHelper_1 = require("../functionsDeployHelper");
  6. const deploymentTool_1 = require("../../../deploymentTool");
  7. const error_1 = require("../../../error");
  8. const utils = require("../../../utils");
  9. const backend = require("../backend");
  10. const v2events = require("../../../functions/events/v2");
  11. function calculateChangesets(want, have, keyFn, deleteAll) {
  12. const toCreate = utils.groupBy(Object.keys(want)
  13. .filter((id) => !have[id])
  14. .map((id) => want[id]), keyFn);
  15. const toDelete = utils.groupBy(Object.keys(have)
  16. .filter((id) => !want[id])
  17. .filter((id) => deleteAll || (0, deploymentTool_1.isFirebaseManaged)(have[id].labels || {}))
  18. .map((id) => have[id]), keyFn);
  19. const toSkipPredicate = (id) => !!(!want[id].targetedByOnly &&
  20. have[id].hash &&
  21. want[id].hash &&
  22. want[id].hash === have[id].hash);
  23. const toSkipEndpointsMap = Object.keys(want)
  24. .filter((id) => have[id])
  25. .filter((id) => toSkipPredicate(id))
  26. .reduce((memo, id) => {
  27. memo[id] = want[id];
  28. return memo;
  29. }, {});
  30. const toSkip = utils.groupBy(Object.values(toSkipEndpointsMap), keyFn);
  31. if (Object.keys(toSkip).length) {
  32. utils.logLabeledBullet("functions", `Skipping the deploy of unchanged functions with ${clc.bold("experimental")} support for skipdeployingnoopfunctions`);
  33. }
  34. const toUpdate = utils.groupBy(Object.keys(want)
  35. .filter((id) => have[id])
  36. .filter((id) => !toSkipEndpointsMap[id])
  37. .map((id) => calculateUpdate(want[id], have[id])), (eu) => keyFn(eu.endpoint));
  38. const result = {};
  39. const keys = new Set([
  40. ...Object.keys(toCreate),
  41. ...Object.keys(toDelete),
  42. ...Object.keys(toUpdate),
  43. ...Object.keys(toSkip),
  44. ]);
  45. for (const key of keys) {
  46. result[key] = {
  47. endpointsToCreate: toCreate[key] || [],
  48. endpointsToUpdate: toUpdate[key] || [],
  49. endpointsToDelete: toDelete[key] || [],
  50. endpointsToSkip: toSkip[key] || [],
  51. };
  52. }
  53. return result;
  54. }
  55. exports.calculateChangesets = calculateChangesets;
  56. function calculateUpdate(want, have) {
  57. checkForIllegalUpdate(want, have);
  58. const update = {
  59. endpoint: want,
  60. };
  61. const needsDelete = changedTriggerRegion(want, have) ||
  62. changedV2PubSubTopic(want, have) ||
  63. upgradedScheduleFromV1ToV2(want, have);
  64. if (needsDelete) {
  65. update.deleteAndRecreate = have;
  66. }
  67. return update;
  68. }
  69. exports.calculateUpdate = calculateUpdate;
  70. function createDeploymentPlan(args) {
  71. let { wantBackend, haveBackend, codebase, filters, deleteAll } = args;
  72. let deployment = {};
  73. wantBackend = backend.matchingBackend(wantBackend, (endpoint) => {
  74. return (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, filters);
  75. });
  76. const wantedEndpoint = backend.hasEndpoint(wantBackend);
  77. haveBackend = backend.matchingBackend(haveBackend, (endpoint) => {
  78. return wantedEndpoint(endpoint) || (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, filters);
  79. });
  80. const regions = new Set([
  81. ...Object.keys(wantBackend.endpoints),
  82. ...Object.keys(haveBackend.endpoints),
  83. ]);
  84. for (const region of regions) {
  85. const changesets = calculateChangesets(wantBackend.endpoints[region] || {}, haveBackend.endpoints[region] || {}, (e) => `${codebase}-${e.region}-${e.availableMemoryMb || "default"}`, deleteAll);
  86. deployment = Object.assign(Object.assign({}, deployment), changesets);
  87. }
  88. if (upgradedToGCFv2WithoutSettingConcurrency(wantBackend, haveBackend)) {
  89. utils.logLabeledBullet("functions", "You are updating one or more functions to Google Cloud Functions v2, " +
  90. "which introduces support for concurrent execution. New functions " +
  91. "default to 80 concurrent executions, but existing functions keep the " +
  92. "old default of 1. You can change this with the 'concurrency' option.");
  93. }
  94. return deployment;
  95. }
  96. exports.createDeploymentPlan = createDeploymentPlan;
  97. function upgradedToGCFv2WithoutSettingConcurrency(want, have) {
  98. return backend.someEndpoint(want, (endpoint) => {
  99. var _a, _b;
  100. if (((_b = (_a = have.endpoints[endpoint.region]) === null || _a === void 0 ? void 0 : _a[endpoint.id]) === null || _b === void 0 ? void 0 : _b.platform) !== "gcfv1") {
  101. return false;
  102. }
  103. if (endpoint.platform !== "gcfv2") {
  104. return false;
  105. }
  106. if (endpoint.concurrency) {
  107. return false;
  108. }
  109. return true;
  110. });
  111. }
  112. exports.upgradedToGCFv2WithoutSettingConcurrency = upgradedToGCFv2WithoutSettingConcurrency;
  113. function changedTriggerRegion(want, have) {
  114. if (want.platform !== "gcfv2") {
  115. return false;
  116. }
  117. if (have.platform !== "gcfv2") {
  118. return false;
  119. }
  120. if (!backend.isEventTriggered(want)) {
  121. return false;
  122. }
  123. if (!backend.isEventTriggered(have)) {
  124. return false;
  125. }
  126. return want.eventTrigger.region !== have.eventTrigger.region;
  127. }
  128. exports.changedTriggerRegion = changedTriggerRegion;
  129. function changedV2PubSubTopic(want, have) {
  130. if (want.platform !== "gcfv2") {
  131. return false;
  132. }
  133. if (have.platform !== "gcfv2") {
  134. return false;
  135. }
  136. if (!backend.isEventTriggered(want)) {
  137. return false;
  138. }
  139. if (!backend.isEventTriggered(have)) {
  140. return false;
  141. }
  142. if (want.eventTrigger.eventType !== v2events.PUBSUB_PUBLISH_EVENT) {
  143. return false;
  144. }
  145. if (have.eventTrigger.eventType !== v2events.PUBSUB_PUBLISH_EVENT) {
  146. return false;
  147. }
  148. return have.eventTrigger.eventFilters.topic !== want.eventTrigger.eventFilters.topic;
  149. }
  150. exports.changedV2PubSubTopic = changedV2PubSubTopic;
  151. function upgradedScheduleFromV1ToV2(want, have) {
  152. if (have.platform !== "gcfv1") {
  153. return false;
  154. }
  155. if (want.platform !== "gcfv2") {
  156. return false;
  157. }
  158. if (!backend.isScheduleTriggered(have)) {
  159. return false;
  160. }
  161. if (!backend.isScheduleTriggered(want)) {
  162. return false;
  163. }
  164. return true;
  165. }
  166. exports.upgradedScheduleFromV1ToV2 = upgradedScheduleFromV1ToV2;
  167. function checkForIllegalUpdate(want, have) {
  168. const triggerType = (e) => {
  169. if (backend.isHttpsTriggered(e)) {
  170. return "an HTTPS";
  171. }
  172. else if (backend.isCallableTriggered(e)) {
  173. return "a callable";
  174. }
  175. else if (backend.isEventTriggered(e)) {
  176. return "a background triggered";
  177. }
  178. else if (backend.isScheduleTriggered(e)) {
  179. return "a scheduled";
  180. }
  181. else if (backend.isTaskQueueTriggered(e)) {
  182. return "a task queue";
  183. }
  184. else if (backend.isBlockingTriggered(e)) {
  185. return e.blockingTrigger.eventType;
  186. }
  187. throw Error("Functions release planner is not able to handle an unknown trigger type");
  188. };
  189. const wantType = triggerType(want);
  190. const haveType = triggerType(have);
  191. if (wantType !== haveType) {
  192. throw new error_1.FirebaseError(`[${(0, functionsDeployHelper_1.getFunctionLabel)(want)}] Changing from ${haveType} function to ${wantType} function is not allowed. Please delete your function and create a new one instead.`);
  193. }
  194. if (want.platform === "gcfv1" && have.platform === "gcfv2") {
  195. throw new error_1.FirebaseError(`[${(0, functionsDeployHelper_1.getFunctionLabel)(want)}] Functions cannot be downgraded from GCFv2 to GCFv1`);
  196. }
  197. exports.checkForV2Upgrade(want, have);
  198. }
  199. exports.checkForIllegalUpdate = checkForIllegalUpdate;
  200. function checkForV2Upgrade(want, have) {
  201. if (want.platform === "gcfv2" && have.platform === "gcfv1") {
  202. throw new error_1.FirebaseError(`[${(0, functionsDeployHelper_1.getFunctionLabel)(have)}] Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.`);
  203. }
  204. }
  205. exports.checkForV2Upgrade = checkForV2Upgrade;