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.

reporter.js 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.triggerTag = exports.printAbortedErrors = exports.printErrors = exports.logAndTrackDeployStats = exports.AbortedDeploymentError = exports.DeploymentError = void 0;
  4. const backend = require("../backend");
  5. const clc = require("colorette");
  6. const logger_1 = require("../../../logger");
  7. const track_1 = require("../../../track");
  8. const utils = require("../../../utils");
  9. const functionsDeployHelper_1 = require("../functionsDeployHelper");
  10. class DeploymentError extends Error {
  11. constructor(endpoint, op, original) {
  12. super(`Failed to ${op} function ${endpoint.id} in region ${endpoint.region}`);
  13. this.endpoint = endpoint;
  14. this.op = op;
  15. this.original = original;
  16. }
  17. }
  18. exports.DeploymentError = DeploymentError;
  19. class AbortedDeploymentError extends DeploymentError {
  20. constructor(endpoint) {
  21. super(endpoint, "delete", new Error("aborted"));
  22. this.endpoint = endpoint;
  23. }
  24. }
  25. exports.AbortedDeploymentError = AbortedDeploymentError;
  26. async function logAndTrackDeployStats(summary) {
  27. let totalTime = 0;
  28. let totalErrors = 0;
  29. let totalSuccesses = 0;
  30. let totalAborts = 0;
  31. const reports = [];
  32. const regions = new Set();
  33. for (const result of summary.results) {
  34. const tag = triggerTag(result.endpoint);
  35. regions.add(result.endpoint.region);
  36. totalTime += result.durationMs;
  37. if (!result.error) {
  38. totalSuccesses++;
  39. reports.push((0, track_1.track)("function_deploy_success", tag, result.durationMs));
  40. }
  41. else if (result.error instanceof AbortedDeploymentError) {
  42. totalAborts++;
  43. reports.push((0, track_1.track)("function_deploy_abort", tag, result.durationMs));
  44. }
  45. else {
  46. totalErrors++;
  47. reports.push((0, track_1.track)("function_deploy_failure", tag, result.durationMs));
  48. }
  49. }
  50. const regionCountTag = regions.size < 5 ? regions.size.toString() : ">=5";
  51. reports.push((0, track_1.track)("functions_region_count", regionCountTag, 1));
  52. const gcfv1 = summary.results.find((r) => r.endpoint.platform === "gcfv1");
  53. const gcfv2 = summary.results.find((r) => r.endpoint.platform === "gcfv2");
  54. const tag = gcfv1 && gcfv2 ? "v1+v2" : gcfv1 ? "v1" : "v2";
  55. reports.push((0, track_1.track)("functions_codebase_deploy", tag, summary.results.length));
  56. const avgTime = totalTime / (totalSuccesses + totalErrors);
  57. logger_1.logger.debug(`Total Function Deployment time: ${summary.totalTime}`);
  58. logger_1.logger.debug(`${totalErrors + totalSuccesses + totalAborts} Functions Deployed`);
  59. logger_1.logger.debug(`${totalErrors} Functions Errored`);
  60. logger_1.logger.debug(`${totalAborts} Function Deployments Aborted`);
  61. logger_1.logger.debug(`Average Function Deployment time: ${avgTime}`);
  62. if (totalErrors + totalSuccesses > 0) {
  63. if (totalErrors === 0) {
  64. reports.push((0, track_1.track)("functions_deploy_result", "success", totalSuccesses));
  65. }
  66. else if (totalSuccesses > 0) {
  67. reports.push((0, track_1.track)("functions_deploy_result", "partial_success", totalSuccesses));
  68. reports.push((0, track_1.track)("functions_deploy_result", "partial_failure", totalErrors));
  69. reports.push((0, track_1.track)("functions_deploy_result", "partial_error_ratio", totalErrors / (totalSuccesses + totalErrors)));
  70. }
  71. else {
  72. reports.push((0, track_1.track)("functions_deploy_result", "failure", totalErrors));
  73. }
  74. }
  75. await utils.allSettled(reports);
  76. }
  77. exports.logAndTrackDeployStats = logAndTrackDeployStats;
  78. function printErrors(summary) {
  79. const errored = summary.results.filter((r) => r.error);
  80. if (errored.length === 0) {
  81. return;
  82. }
  83. errored.sort((left, right) => backend.compareFunctions(left.endpoint, right.endpoint));
  84. logger_1.logger.info("");
  85. logger_1.logger.info("Functions deploy had errors with the following functions:" +
  86. errored
  87. .filter((r) => !(r.error instanceof AbortedDeploymentError))
  88. .map((result) => `\n\t${(0, functionsDeployHelper_1.getFunctionLabel)(result.endpoint)}`)
  89. .join(""));
  90. printIamErrors(errored);
  91. printQuotaErrors(errored);
  92. printAbortedErrors(errored);
  93. }
  94. exports.printErrors = printErrors;
  95. function printIamErrors(results) {
  96. const iamFailures = results.filter((r) => r.error instanceof DeploymentError && r.error.op === "set invoker");
  97. if (!iamFailures.length) {
  98. return;
  99. }
  100. logger_1.logger.info("");
  101. logger_1.logger.info("Unable to set the invoker for the IAM policy on the following functions:" +
  102. iamFailures.map((result) => `\n\t${(0, functionsDeployHelper_1.getFunctionLabel)(result.endpoint)}`).join(""));
  103. logger_1.logger.info("");
  104. logger_1.logger.info("Some common causes of this:");
  105. logger_1.logger.info("");
  106. logger_1.logger.info("- You may not have the roles/functions.admin IAM role. Note that " +
  107. "roles/functions.developer does not allow you to change IAM policies.");
  108. logger_1.logger.info("");
  109. logger_1.logger.info("- An organization policy that restricts Network Access on your project.");
  110. const hadImplicitMakePublic = iamFailures.find((r) => backend.isHttpsTriggered(r.endpoint) && !r.endpoint.httpsTrigger.invoker);
  111. if (!hadImplicitMakePublic) {
  112. return;
  113. }
  114. logger_1.logger.info("");
  115. logger_1.logger.info("One or more functions were being implicitly made publicly available on function create.");
  116. logger_1.logger.info("Functions are not implicitly made public on updates. To try to make " +
  117. "these functions public on next deploy, configure these functions with " +
  118. `${clc.bold("invoker")} set to ${clc.bold(`"public"`)}`);
  119. }
  120. function printQuotaErrors(results) {
  121. const hadQuotaError = results.find((r) => {
  122. var _a, _b, _c, _d, _e, _f;
  123. if (!(r.error instanceof DeploymentError)) {
  124. return false;
  125. }
  126. const original = r.error.original;
  127. const code = (original === null || original === void 0 ? void 0 : original.status) ||
  128. (original === null || original === void 0 ? void 0 : original.code) ||
  129. ((_b = (_a = original === null || original === void 0 ? void 0 : original.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) ||
  130. ((_c = original === null || original === void 0 ? void 0 : original.original) === null || _c === void 0 ? void 0 : _c.code) ||
  131. ((_f = (_e = (_d = original === null || original === void 0 ? void 0 : original.original) === null || _d === void 0 ? void 0 : _d.context) === null || _e === void 0 ? void 0 : _e.response) === null || _f === void 0 ? void 0 : _f.statusCode);
  132. return code === 429 || code === 409;
  133. });
  134. if (!hadQuotaError) {
  135. return;
  136. }
  137. logger_1.logger.info("");
  138. logger_1.logger.info("Exceeded maximum retries while deploying functions. " +
  139. "If you are deploying a large number of functions, " +
  140. "please deploy your functions in batches by using the --only flag, " +
  141. "and wait a few minutes before deploying again. " +
  142. "Go to https://firebase.google.com/docs/cli/#partial_deploys to learn more.");
  143. }
  144. function printAbortedErrors(results) {
  145. const aborted = results.filter((r) => r.error instanceof AbortedDeploymentError);
  146. if (!aborted.length) {
  147. return;
  148. }
  149. logger_1.logger.info("");
  150. logger_1.logger.info("Because there were errors creating or updating functions, the following " +
  151. "functions were not deleted" +
  152. aborted.map((result) => `\n\t${(0, functionsDeployHelper_1.getFunctionLabel)(result.endpoint)}`).join(""));
  153. logger_1.logger.info(`To delete these, use ${clc.bold("firebase functions:delete")}`);
  154. }
  155. exports.printAbortedErrors = printAbortedErrors;
  156. function triggerTag(endpoint) {
  157. var _a;
  158. const prefix = endpoint.platform === "gcfv1" ? "v1" : "v2";
  159. if (backend.isScheduleTriggered(endpoint)) {
  160. return `${prefix}.scheduled`;
  161. }
  162. if (backend.isTaskQueueTriggered(endpoint)) {
  163. return `${prefix}.taskQueue`;
  164. }
  165. if (backend.isCallableTriggered(endpoint)) {
  166. return `${prefix}.callable`;
  167. }
  168. if (backend.isHttpsTriggered(endpoint)) {
  169. if ((_a = endpoint.labels) === null || _a === void 0 ? void 0 : _a["deployment-callable"]) {
  170. return `${prefix}.callable`;
  171. }
  172. return `${prefix}.https`;
  173. }
  174. if (backend.isBlockingTriggered(endpoint)) {
  175. return `${prefix}.blocking`;
  176. }
  177. return endpoint.eventTrigger.eventType;
  178. }
  179. exports.triggerTag = triggerTag;