From 83143e5b8bc87ca457ca33d04f2b37666049b973 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 19 May 2020 14:43:30 -0700
Subject: [PATCH 01/25] enable changeset

---
 .changeset/README.md   |   8 +
 .changeset/config.json |   9 +
 package.json           |   4 +-
 yarn.lock              | 461 ++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 473 insertions(+), 9 deletions(-)
 create mode 100644 .changeset/README.md
 create mode 100644 .changeset/config.json

diff --git a/.changeset/README.md b/.changeset/README.md
new file mode 100644
index 00000000000..4f3b76b096b
--- /dev/null
+++ b/.changeset/README.md
@@ -0,0 +1,8 @@
+# Changesets
+
+Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
+with multi-package repos, or single-package repos to help you version and publish your code. You can
+find the full documentation for it [in our repository](https://github.com/changesets/changesets)
+
+We have a quick list of common questions to get you started engaging with this project in
+[our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md)
diff --git a/.changeset/config.json b/.changeset/config.json
new file mode 100644
index 00000000000..f71b8a100c3
--- /dev/null
+++ b/.changeset/config.json
@@ -0,0 +1,9 @@
+{
+  "$schema": "https://unpkg.com/@changesets/config@1.1.0/schema.json",
+  "changelog": ["@changesets/changelog-github", { "repo": "firebase/firebase-js-sdk"}],
+  "commit": false,
+  "linked": [],
+  "access": "restricted",
+  "baseBranch": "master",
+  "updateInternalDependencies": "patch"
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index e1a098eac23..4aa75eee7b7 100644
--- a/package.json
+++ b/package.json
@@ -138,7 +138,9 @@
     "typescript": "3.8.3",
     "watch": "1.0.2",
     "webpack": "4.43.0",
-    "yargs": "15.3.1"
+    "yargs": "15.3.1",
+    "@changesets/cli": "2.6.5",
+    "@changesets/changelog-github": "0.2.5"
   },
   "husky": {
     "hooks": {
diff --git a/yarn.lock b/yarn.lock
index 1591ae97d02..f133cd515db 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -763,6 +763,13 @@
     "@babel/types" "^7.4.4"
     esutils "^2.0.2"
 
+"@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5":
+  version "7.9.6"
+  resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f"
+  integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
 "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
   version "7.9.2"
   resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
@@ -836,6 +843,207 @@
     lodash "^4.17.13"
     to-fast-properties "^2.0.0"
 
+"@changesets/apply-release-plan@^2.0.1":
+  version "2.0.2"
+  resolved "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-2.0.2.tgz#d411e7384c764c9500b41ce7e77ebd42a92a8e14"
+  integrity sha512-CmGiGa4sMRyztkPoxUy/EBzdXZrkLpTIzUpS5SXyzdU0jWxSSA+oB9/o1IQ4hwKMM2g8DGbOMAg9NwavK86nPQ==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/config" "^1.0.3"
+    "@changesets/get-version-range-type" "^0.3.2"
+    "@changesets/git" "^1.0.3"
+    "@changesets/types" "^2.0.1"
+    "@manypkg/get-packages" "^1.0.1"
+    fs-extra "^7.0.1"
+    lodash.startcase "^4.4.0"
+    outdent "^0.5.0"
+    prettier "^1.18.2"
+    resolve-from "^5.0.0"
+    semver "^5.4.1"
+
+"@changesets/assemble-release-plan@^2.0.2", "@changesets/assemble-release-plan@^2.0.4":
+  version "2.0.4"
+  resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-2.0.4.tgz#4c138fa306340f851c04e70434dd0a8e2e62a8ad"
+  integrity sha512-v7Z6/7PliGZY62Pod5GzBW4bJ5nBNTMRuCNMIQ/n3BUZkEH6wQrCI/jzEs0tGp8s88HITpdDF3ZMHIBfGsH3eQ==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/errors" "^0.1.4"
+    "@changesets/get-dependents-graph" "^1.1.3"
+    "@changesets/types" "^3.0.0"
+    "@manypkg/get-packages" "^1.0.1"
+    semver "^5.4.1"
+
+"@changesets/changelog-github@0.2.5":
+  version "0.2.5"
+  resolved "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.2.5.tgz#e0c3e8d55c7e2988fa9f8d23e036058aeb597fdd"
+  integrity sha512-p2jwWCVQIRXcdFE0k+JwIMuyd6bQBgECVExk1bvoUdM0ckynuUX935vu8IAYGFO4MNi4kuhJJ6zEooAAxhVCcQ==
+  dependencies:
+    "@changesets/get-github-info" "^0.4.3"
+    "@changesets/types" "^2.0.1"
+    dotenv "^8.1.0"
+
+"@changesets/cli@2.6.5":
+  version "2.6.5"
+  resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.6.5.tgz#1da87511306c997735e76a1e216b504730d2ac96"
+  integrity sha512-vy6FET6o0Y29uGxnYfOjj6Sclx6FYDLtmfI2aL3s6JV+FAQSZVfecENtJtFiwvBO6VL5h3hVP5SensjFVXiDRA==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/apply-release-plan" "^2.0.1"
+    "@changesets/assemble-release-plan" "^2.0.2"
+    "@changesets/config" "^1.0.3"
+    "@changesets/errors" "^0.1.4"
+    "@changesets/get-release-plan" "^1.0.3"
+    "@changesets/git" "^1.0.3"
+    "@changesets/logger" "^0.0.5"
+    "@changesets/pre" "^1.0.3"
+    "@changesets/read" "^0.4.5"
+    "@changesets/types" "^2.0.1"
+    "@changesets/write" "^0.1.2"
+    "@manypkg/get-packages" "^1.0.1"
+    "@types/semver" "^6.0.0"
+    boxen "^1.3.0"
+    chalk "^2.1.0"
+    enquirer "^2.3.0"
+    fs-extra "^7.0.1"
+    human-id "^1.0.2"
+    is-ci "^2.0.0"
+    meow "^5.0.0"
+    outdent "^0.5.0"
+    p-limit "^2.2.0"
+    preferred-pm "^3.0.0"
+    semver "^5.4.1"
+    spawndamnit "^2.0.0"
+    term-size "^2.1.0"
+    tty-table "^2.7.0"
+
+"@changesets/config@^1.0.3", "@changesets/config@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/@changesets/config/-/config-1.1.0.tgz#35d96d12b27df905cc6d706eecf1cc378bf6cffe"
+  integrity sha512-KXZ67QLRd/kMv+CK45r2Edl4O6oOMxKI7B0Sf4qVmwwoonGM5oxHNyNAxeGL31YhE+6z4hIh57+rD7PppF+KFw==
+  dependencies:
+    "@changesets/errors" "^0.1.4"
+    "@changesets/logger" "^0.0.5"
+    "@changesets/types" "^3.0.0"
+    "@manypkg/get-packages" "^1.0.1"
+    fs-extra "^7.0.1"
+
+"@changesets/errors@^0.1.4":
+  version "0.1.4"
+  resolved "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz#f79851746c43679a66b383fdff4c012f480f480d"
+  integrity sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==
+  dependencies:
+    extendable-error "^0.1.5"
+
+"@changesets/get-dependents-graph@^1.1.3":
+  version "1.1.3"
+  resolved "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.1.3.tgz#da959c43ce98f3a990a6b8d9c1f894bcc1b629c7"
+  integrity sha512-cTbySXwSv9yWp4Pp5R/b5Qv23wJgFaFCqUbsI3IJ2pyPl0vMaODAZS8NI1nNK2XSxGIg1tw+dWNSR4PlrKBSVQ==
+  dependencies:
+    "@changesets/types" "^3.0.0"
+    "@manypkg/get-packages" "^1.0.1"
+    chalk "^2.1.0"
+    fs-extra "^7.0.1"
+    semver "^5.4.1"
+
+"@changesets/get-github-info@^0.4.3":
+  version "0.4.3"
+  resolved "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.4.3.tgz#ed3c3ca76dcbaf4c98aa950a20fc5438da1a2f2c"
+  integrity sha512-hMtNDn4Kp2wDUohYipBIH3qGMxONZ3wEoaGtrflXHCSu57iulBcOSQ1oHRYSCJ9pO87dYQHA2XRUfrZUnqRfKA==
+  dependencies:
+    dataloader "^1.4.0"
+    node-fetch "^2.5.0"
+
+"@changesets/get-release-plan@^1.0.3":
+  version "1.0.4"
+  resolved "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-1.0.4.tgz#9c0b830d8ef4aa0988379e7405d2d2ece29d604e"
+  integrity sha512-yxym5rS0seFaAtGI+arUdm3dCz7trb/lvsqsfNpH1Yf0cN90QKMEZSOmWKo8ZEMuifnnl8AFqnH9wRS2+bWVCg==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/assemble-release-plan" "^2.0.4"
+    "@changesets/config" "^1.1.0"
+    "@changesets/pre" "^1.0.4"
+    "@changesets/read" "^0.4.6"
+    "@changesets/types" "^3.0.0"
+    "@manypkg/get-packages" "^1.0.1"
+
+"@changesets/get-version-range-type@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz#8131a99035edd11aa7a44c341cbb05e668618c67"
+  integrity sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==
+
+"@changesets/git@^1.0.3", "@changesets/git@^1.0.5":
+  version "1.0.5"
+  resolved "https://registry.npmjs.org/@changesets/git/-/git-1.0.5.tgz#e392128a13b210c482324d0d329029a3f7613b10"
+  integrity sha512-MgacjTRCrfFCffvoipqbtHSENydaO+HDR6z+gDQ49Gl2kHIat0iIazL1TBfEuW8H4eGCay+Naz/x6412ucUOTw==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/errors" "^0.1.4"
+    "@changesets/types" "^3.0.0"
+    "@manypkg/get-packages" "^1.0.1"
+    is-subdir "^1.1.1"
+    spawndamnit "^2.0.0"
+
+"@changesets/logger@^0.0.5":
+  version "0.0.5"
+  resolved "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz#68305dd5a643e336be16a2369cb17cdd8ed37d4c"
+  integrity sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==
+  dependencies:
+    chalk "^2.1.0"
+
+"@changesets/parse@^0.3.6":
+  version "0.3.6"
+  resolved "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.6.tgz#8c2c8480fc07d2db2c37469d4a8df10906a989c6"
+  integrity sha512-0XPd/es9CfogI7XIqDr7I2mWzm++xX2s9GZsij3GajPYd7ouEsgJyNatPooxNtqj6ZepkiD6uqlqbeBUyj/A0Q==
+  dependencies:
+    "@changesets/types" "^3.0.0"
+    js-yaml "^3.13.1"
+
+"@changesets/pre@^1.0.3", "@changesets/pre@^1.0.4":
+  version "1.0.4"
+  resolved "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.4.tgz#32aa9040f3798e8a46adc6c30cc4c02a617d1889"
+  integrity sha512-PGD3uSCZIs6Fd+HsPziLh0BjJ2ypyTEFZSY8qkwINvAvWYpDK805svV0x9usp54kn6PWI9RZ4tVD2A41dqJ0jw==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/errors" "^0.1.4"
+    "@changesets/types" "^3.0.0"
+    "@manypkg/get-packages" "^1.0.1"
+    fs-extra "^7.0.1"
+
+"@changesets/read@^0.4.5", "@changesets/read@^0.4.6":
+  version "0.4.6"
+  resolved "https://registry.npmjs.org/@changesets/read/-/read-0.4.6.tgz#1c03e709a870a070fc95490ffa696297d23458f7"
+  integrity sha512-rOd8dsF/Lgyy2SYlDalb3Ts/meDI2AcKPXYhSXIW3k6+ZLlj6Pt+nmgV5Ut8euyH7loibklNTDemfvMffF4xig==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/git" "^1.0.5"
+    "@changesets/logger" "^0.0.5"
+    "@changesets/parse" "^0.3.6"
+    "@changesets/types" "^3.0.0"
+    chalk "^2.1.0"
+    fs-extra "^7.0.1"
+    p-filter "^2.1.0"
+
+"@changesets/types@^2.0.1":
+  version "2.0.1"
+  resolved "https://registry.npmjs.org/@changesets/types/-/types-2.0.1.tgz#26db6c4b63b73b7c9aa08b203e185529d7a86a70"
+  integrity sha512-jOBXRpNvgR+V8tv3EL/RI6ugjWiBgal7Tzqkhk+BI1QACavc62tK9kiYVXldsVDv8e0lPRiYBl/OADhOS//NlA==
+
+"@changesets/types@^3.0.0":
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/@changesets/types/-/types-3.0.0.tgz#3804662aa455c1622282ec3253cf6ddd309eee65"
+  integrity sha512-9Mh/JqkX3nkjfu53ESM3UjFmR2meOo4Zw+Tp4vnon0XYtMurk7KjZG5L+J0fD3+Qx0A2FFTZrgydPwiHR4GrXQ==
+
+"@changesets/write@^0.1.2":
+  version "0.1.3"
+  resolved "https://registry.npmjs.org/@changesets/write/-/write-0.1.3.tgz#00ae575af50274773d7493e77fb96838a08ad8ad"
+  integrity sha512-q79rbwlVmTNKP9O6XxcMDj81CEOn/kQHbTFdRleW0tFUv98S1EyEAE9vLPPzO6WnQipHnaozxB1zMhHy0aQn8Q==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+    "@changesets/types" "^3.0.0"
+    fs-extra "^7.0.1"
+    human-id "^1.0.2"
+    prettier "^1.18.2"
+
 "@evocateur/libnpmaccess@^3.1.2":
   version "3.1.2"
   resolved "https://registry.npmjs.org/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz#ecf7f6ce6b004e9f942b098d92200be4a4b1c845"
@@ -1702,6 +1910,27 @@
     npmlog "^4.1.2"
     write-file-atomic "^2.3.0"
 
+"@manypkg/find-root@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.0.0.tgz#b8e96d7c24678b1b65c2057ae47df750669197d7"
+  integrity sha512-c2J5B6MgkCqPVN49/FggigF2a5WThPnjd2RxknDPZjQM/QfSTHpU1r3NOXjQOzKSNRTnFFMHuOYJAVZ66LZNCQ==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+    "@types/node" "^12.7.1"
+    find-up "^4.1.0"
+    fs-extra "^8.1.0"
+
+"@manypkg/get-packages@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.0.1.tgz#0b46907555626ae773abb828e6c1cb313aa44777"
+  integrity sha512-paGfOt9yW+4/kkK9pM5DlnZDfrP7pp75TDimA8VJQlfxxD7/yHpRsBQZh+soqArr9uqwnCw2XkDggG7BlPdQ3Q==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+    "@manypkg/find-root" "^1.0.0"
+    fs-extra "^8.1.0"
+    globby "^11.0.0"
+    read-yaml-file "^1.1.0"
+
 "@microsoft/api-documenter@7.7.20":
   version "7.7.20"
   resolved "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.7.20.tgz#034fe4df720d62ebcc6af311168fdb0faf89da9c"
@@ -2180,6 +2409,11 @@
   resolved "https://registry.npmjs.org/@types/node/-/node-10.17.18.tgz#ae364d97382aacdebf583fa4e7132af2dfe56a0c"
   integrity sha512-DQ2hl/Jl3g33KuAUOcMrcAOtsbzb+y/ufakzAdeK9z/H/xsvkpbETZZbPNMIiQuk24f5ZRMCcZIViAwyFIiKmg==
 
+"@types/node@^12.7.1":
+  version "12.12.40"
+  resolved "https://registry.npmjs.org/@types/node/-/node-12.12.40.tgz#f6fdf7d6675ee9eb7b8931d3fff8c1f163464ea9"
+  integrity sha512-DGOupyZgr0TnemMORnkgR4G3ow5PV61uVW3w51pcnPIo6NV5hc36l59jxZJ/immrBpV5d7h6tn8/YgSgiA9oTw==
+
 "@types/node@^13.7.0":
   version "13.13.4"
   resolved "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz#1581d6c16e3d4803eb079c87d4ac893ee7501c2c"
@@ -2227,6 +2461,11 @@
   resolved "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz#50bea0c3c2acc31c959c5b1e747798b3b3d06d4b"
   integrity sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw==
 
+"@types/semver@^6.0.0":
+  version "6.2.1"
+  resolved "https://registry.npmjs.org/@types/semver/-/semver-6.2.1.tgz#a236185670a7860f1597cf73bea2e16d001461ba"
+  integrity sha512-+beqKQOh9PYxuHvijhVl+tIHvT6tuwOrE9m14zd+MT2A38KoKZhh7pYJ0SNleLtwDsiIxHDsIk9bv01oOxvSvA==
+
 "@types/serve-static@*":
   version "1.13.3"
   resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1"
@@ -2661,7 +2900,7 @@ ansi-colors@^1.0.1:
   dependencies:
     ansi-wrap "^0.1.0"
 
-ansi-colors@^3.0.0:
+ansi-colors@^3.0.0, ansi-colors@^3.2.1:
   version "3.2.4"
   resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
   integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
@@ -3390,6 +3629,13 @@ better-assert@~1.0.0:
   dependencies:
     callsite "1.0.0"
 
+better-path-resolve@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz#13a35a1104cdd48a7b74bf8758f96a1ee613f99d"
+  integrity sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==
+  dependencies:
+    is-windows "^1.0.0"
+
 big-integer@^1.6.17:
   version "1.6.48"
   resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e"
@@ -3492,7 +3738,7 @@ body-parser@1.19.0, body-parser@^1.16.1, body-parser@^1.19.0:
     raw-body "2.4.0"
     type-is "~1.6.17"
 
-boxen@^1.2.1:
+boxen@^1.2.1, boxen@^1.3.0:
   version "1.3.0"
   resolved "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
   integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
@@ -3536,6 +3782,13 @@ braces@^3.0.1, braces@^3.0.2, braces@~3.0.2:
   dependencies:
     fill-range "^7.0.1"
 
+breakword@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.npmjs.org/breakword/-/breakword-1.0.5.tgz#fd420a417f55016736b5b615161cae1c8f819810"
+  integrity sha512-ex5W9DoOQ/LUEU3PMdLs9ua/CYZl1678NUkKOdUSi8Aw5F1idieaiRURCBFJCwVcrD1J8Iy3vfWSloaMwO2qFg==
+  dependencies:
+    wcwidth "^1.0.1"
+
 brorand@^1.0.1:
   version "1.1.0"
   resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -4879,7 +5132,7 @@ cross-spawn@^4.0.0, cross-spawn@^4.0.2:
     lru-cache "^4.0.1"
     which "^1.2.9"
 
-cross-spawn@^5.0.1:
+cross-spawn@^5.0.1, cross-spawn@^5.1.0:
   version "5.1.0"
   resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
   integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
@@ -4934,6 +5187,16 @@ css@2.X, css@^2.2.1:
     source-map-resolve "^0.5.2"
     urix "^0.1.0"
 
+csv-generate@^3.2.4:
+  version "3.2.4"
+  resolved "https://registry.npmjs.org/csv-generate/-/csv-generate-3.2.4.tgz#440dab9177339ee0676c9e5c16f50e2b3463c019"
+  integrity sha512-qNM9eqlxd53TWJeGtY1IQPj90b563Zx49eZs8e0uMyEvPgvNVmX1uZDtdzAcflB3PniuH9creAzcFOdyJ9YGvA==
+
+csv-parse@^4.8.8:
+  version "4.9.1"
+  resolved "https://registry.npmjs.org/csv-parse/-/csv-parse-4.9.1.tgz#96e645520a1c95cbec1ffecb7513ebba61766269"
+  integrity sha512-DSoBx9V5PpAVWZbqqYKaoxYsf6yQdltTlUmZ1gPjvoTeRI5wPDlwa6ovrmeUP/1y4MjUkAPXx17aPlu0E6xBvg==
+
 csv-streamify@^3.0.4:
   version "3.0.4"
   resolved "https://registry.npmjs.org/csv-streamify/-/csv-streamify-3.0.4.tgz#4cb614c57e3f299cca17b63fdcb4ad167777f47a"
@@ -4941,6 +5204,21 @@ csv-streamify@^3.0.4:
   dependencies:
     through2 "2.0.1"
 
+csv-stringify@^5.3.6:
+  version "5.5.0"
+  resolved "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.5.0.tgz#0bdeaaf60d6e15b89c752a0eceb4b4c2c8af5a8a"
+  integrity sha512-G05575DSO/9vFzQxZN+Srh30cNyHk0SM0ePyiTChMD5WVt7GMTVPBQf4rtgMF6mqhNCJUPw4pN8LDe8MF9EYOA==
+
+csv@^5.3.1:
+  version "5.3.2"
+  resolved "https://registry.npmjs.org/csv/-/csv-5.3.2.tgz#50b344e25dfbb8c62684a1bcec18c22468b2161e"
+  integrity sha512-odDyucr9OgJTdGM2wrMbJXbOkJx3nnUX3Pt8SFOwlAMOpsUQlz1dywvLMXJWX/4Ib0rjfOsaawuuwfI5ucqBGQ==
+  dependencies:
+    csv-generate "^3.2.4"
+    csv-parse "^4.8.8"
+    csv-stringify "^5.3.6"
+    stream-transform "^2.0.1"
+
 currently-unhandled@^0.4.1:
   version "0.4.1"
   resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -4990,6 +5268,11 @@ dashdash@^1.12.0:
   dependencies:
     assert-plus "^1.0.0"
 
+dataloader@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8"
+  integrity sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==
+
 date-fns@^1.27.2:
   version "1.30.1"
   resolved "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
@@ -5404,6 +5687,11 @@ dotenv@^6.1.0:
   resolved "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
   integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
 
+dotenv@^8.1.0:
+  version "8.2.0"
+  resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
+  integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
+
 duplexer2@^0.1.2, duplexer2@^0.1.4, duplexer2@~0.1.0, duplexer2@~0.1.2, duplexer2@~0.1.4:
   version "0.1.4"
   resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
@@ -5599,6 +5887,13 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0:
     memory-fs "^0.5.0"
     tapable "^1.0.0"
 
+enquirer@^2.3.0:
+  version "2.3.5"
+  resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz#3ab2b838df0a9d8ab9e7dff235b0e8712ef92381"
+  integrity sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==
+  dependencies:
+    ansi-colors "^3.2.1"
+
 ent@~2.2.0:
   version "2.2.0"
   resolved "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
@@ -6076,6 +6371,11 @@ extend@^3.0.0, extend@^3.0.1, extend@^3.0.2, extend@~3.0.2:
   resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
   integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
 
+extendable-error@^0.1.5:
+  version "0.1.5"
+  resolved "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.5.tgz#122308a7097bc89a263b2c4fbf089c78140e3b6d"
+  integrity sha1-EiMIpwl7yJomOyxPvwiceBQOO20=
+
 external-editor@^3.0.3:
   version "3.1.0"
   resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@@ -6157,7 +6457,7 @@ fast-glob@^2.2.6:
     merge2 "^1.2.3"
     micromatch "^3.1.10"
 
-fast-glob@^3.0.3:
+fast-glob@^3.0.3, fast-glob@^3.1.1:
   version "3.2.2"
   resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d"
   integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==
@@ -6359,6 +6659,14 @@ find-versions@^3.2.0:
   dependencies:
     semver-regex "^2.0.0"
 
+find-yarn-workspace-root2@^1.2.11:
+  version "1.2.12"
+  resolved "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.12.tgz#ff52e0dc646006901c74490229bdd3150c811842"
+  integrity sha512-He5v7hEIXxjr90ro5yq24FUJu0n871/fgIgWzvavpxnJLAqQ8Ks34nKK1acBiK90C/LJdtpmpzmdn9yHIoVZgw==
+  dependencies:
+    micromatch "^4.0.2"
+    pkg-dir "^4.2.0"
+
 findup-sync@3.0.0, findup-sync@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1"
@@ -7064,6 +7372,18 @@ globby@^10.0.1:
     merge2 "^1.2.3"
     slash "^3.0.0"
 
+globby@^11.0.0:
+  version "11.0.0"
+  resolved "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154"
+  integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==
+  dependencies:
+    array-union "^2.1.0"
+    dir-glob "^3.0.1"
+    fast-glob "^3.1.1"
+    ignore "^5.1.4"
+    merge2 "^1.3.0"
+    slash "^3.0.0"
+
 globby@^5.0.0:
   version "5.0.0"
   resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
@@ -7332,6 +7652,16 @@ graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, g
   resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
   integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
 
+graceful-fs@^4.1.5:
+  version "4.2.4"
+  resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
+  integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
+
+grapheme-splitter@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
+  integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
+
 growl@1.10.5:
   version "1.10.5"
   resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
@@ -7731,6 +8061,11 @@ https-proxy-agent@^5.0.0:
     agent-base "6"
     debug "4"
 
+human-id@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz#e654d4b2b0d8b07e45da9f6020d8af17ec0a5df3"
+  integrity sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==
+
 humanize-ms@^1.2.1:
   version "1.2.1"
   resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
@@ -7788,7 +8123,7 @@ ignore@^4.0.3, ignore@^4.0.6:
   resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
   integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
 
-ignore@^5.1.1:
+ignore@^5.1.1, ignore@^5.1.4:
   version "5.1.4"
   resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
   integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==
@@ -8390,6 +8725,13 @@ is-string@^1.0.5:
   resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
   integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
 
+is-subdir@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmjs.org/is-subdir/-/is-subdir-1.1.1.tgz#423e66902f9c5f159b9cc4826c820df083059538"
+  integrity sha512-VYpq0S7gPBVkkmfwkvGnx1EL9UVIo87NQyNcgMiNUdQCws3CJm5wj2nB+XPL7zigvjxhuZgp3bl2yBcKkSIj1w==
+  dependencies:
+    better-path-resolve "1.0.0"
+
 is-symbol@^1.0.2:
   version "1.0.3"
   resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
@@ -8740,7 +9082,7 @@ js-tokens@^3.0.2:
   resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
   integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
 
-js-yaml@3.13.1, js-yaml@^3.13.1, js-yaml@~3.13.1:
+js-yaml@3.13.1, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.6.1, js-yaml@~3.13.1:
   version "3.13.1"
   resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
   integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@@ -9381,6 +9723,16 @@ load-json-file@^5.3.0:
     strip-bom "^3.0.0"
     type-fest "^0.3.0"
 
+load-yaml-file@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz#af854edaf2bea89346c07549122753c07372f64d"
+  integrity sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==
+  dependencies:
+    graceful-fs "^4.1.5"
+    js-yaml "^3.13.0"
+    pify "^4.0.1"
+    strip-bom "^3.0.0"
+
 loader-runner@^2.4.0:
   version "2.4.0"
   resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
@@ -9600,6 +9952,11 @@ lodash.sortby@^4.7.0:
   resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
   integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
 
+lodash.startcase@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8"
+  integrity sha1-lDbjTtJgk+1/+uGTYUQ1CRXZrdg=
+
 lodash.template@^4.0.2, lodash.template@^4.5.0:
   version "4.5.0"
   resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
@@ -10160,6 +10517,11 @@ mixin-deep@^1.2.0:
     for-in "^1.0.2"
     is-extendable "^1.0.1"
 
+mixme@^0.3.1:
+  version "0.3.5"
+  resolved "https://registry.npmjs.org/mixme/-/mixme-0.3.5.tgz#304652cdaf24a3df0487205e61ac6162c6906ddd"
+  integrity sha512-SyV9uPETRig5ZmYev0ANfiGeB+g6N2EnqqEfBbCGmmJ6MgZ3E4qv5aPbnHVdZ60KAHHXV+T3sXopdrnIXQdmjQ==
+
 mkdirp-classic@^0.5.2:
   version "0.5.2"
   resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz#54c441ce4c96cd7790e10b41a87aa51068ecab2b"
@@ -10993,6 +11355,11 @@ osenv@^0.1.4, osenv@^0.1.5:
     os-homedir "^1.0.0"
     os-tmpdir "^1.0.0"
 
+outdent@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz#9e10982fdc41492bb473ad13840d22f9655be2ff"
+  integrity sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==
+
 p-defer@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
@@ -11003,6 +11370,13 @@ p-defer@^3.0.0:
   resolved "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83"
   integrity sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==
 
+p-filter@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c"
+  integrity sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==
+  dependencies:
+    p-map "^2.0.0"
+
 p-finally@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
@@ -11529,6 +11903,16 @@ posix-character-classes@^0.1.0:
   resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
   integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
 
+preferred-pm@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.0.tgz#26cc7fbbfc1815e4cb8272d5fdde15dc96220fb8"
+  integrity sha512-NbN+2UuqjakJpyHamsuIWyeFdQcFUQHF9nkw16hpFE++z3px+/KDsj+AF1h0BlnsBJi1Z5U4EKBW7XnHriny8g==
+  dependencies:
+    find-up "^4.1.0"
+    find-yarn-workspace-root2 "^1.2.11"
+    path-exists "^4.0.0"
+    which-pm "2.0.0"
+
 prelude-ls@~1.1.2:
   version "1.1.2"
   resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -11539,7 +11923,7 @@ prepend-http@^1.0.1:
   resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
   integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
 
-prettier@1.19.1:
+prettier@1.19.1, prettier@^1.18.2:
   version "1.19.1"
   resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
   integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
@@ -11946,6 +12330,16 @@ read-pkg@^3.0.0:
     normalize-package-data "^2.3.2"
     path-type "^3.0.0"
 
+read-yaml-file@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz#9362bbcbdc77007cc8ea4519fe1c0b821a7ce0d8"
+  integrity sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==
+  dependencies:
+    graceful-fs "^4.1.5"
+    js-yaml "^3.6.1"
+    pify "^4.0.1"
+    strip-bom "^3.0.0"
+
 read@1, read@~1.0.1:
   version "1.0.7"
   resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
@@ -12956,6 +13350,17 @@ smart-buffer@^4.1.0:
   resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba"
   integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==
 
+smartwrap@^1.2.3:
+  version "1.2.5"
+  resolved "https://registry.npmjs.org/smartwrap/-/smartwrap-1.2.5.tgz#45ee3e09ac234e5f7f17c16e916f511834f3cd23"
+  integrity sha512-bzWRwHwu0RnWjwU7dFy7tF68pDAx/zMSu3g7xr9Nx5J0iSImYInglwEVExyHLxXljy6PWMjkSAbwF7t2mPnRmg==
+  dependencies:
+    breakword "^1.0.5"
+    grapheme-splitter "^1.0.4"
+    strip-ansi "^6.0.0"
+    wcwidth "^1.0.1"
+    yargs "^15.1.0"
+
 snapdragon-node@^2.0.1:
   version "2.1.1"
   resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -13152,6 +13557,14 @@ spawn-wrap@^2.0.0:
     signal-exit "^3.0.2"
     which "^2.0.1"
 
+spawndamnit@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz#9f762ac5c3476abb994b42ad592b5ad22bb4b0ad"
+  integrity sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==
+  dependencies:
+    cross-spawn "^5.1.0"
+    signal-exit "^3.0.2"
+
 spdx-compare@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz#2c55f117362078d7409e6d7b08ce70a857cd3ed7"
@@ -13346,6 +13759,13 @@ stream-splicer@^2.0.0:
     inherits "^2.0.1"
     readable-stream "^2.0.2"
 
+stream-transform@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.npmjs.org/stream-transform/-/stream-transform-2.0.2.tgz#3cb7a14c802eb39bc40caaab0535e584f3a65caf"
+  integrity sha512-J+D5jWPF/1oX+r9ZaZvEXFbu7znjxSkbNAHJ9L44bt/tCVuOEWZlDqU9qJk7N2xBU1S+K2DPpSKeR/MucmCA1Q==
+  dependencies:
+    mixme "^0.3.1"
+
 streamfilter@^1.0.5:
   version "1.0.7"
   resolved "https://registry.npmjs.org/streamfilter/-/streamfilter-1.0.7.tgz#ae3e64522aa5a35c061fd17f67620c7653c643c9"
@@ -13754,6 +14174,11 @@ term-size@^1.2.0:
   dependencies:
     execa "^0.7.0"
 
+term-size@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753"
+  integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==
+
 terser-webpack-plugin@^1.4.3:
   version "1.4.3"
   resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
@@ -14136,6 +14561,18 @@ tty-browserify@0.0.1, tty-browserify@^0.0.1:
   resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"
   integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==
 
+tty-table@^2.7.0:
+  version "2.8.13"
+  resolved "https://registry.npmjs.org/tty-table/-/tty-table-2.8.13.tgz#d484a416381973eaebbdf19c79136b390e5c6d70"
+  integrity sha512-eVV/+kB6fIIdx+iUImhXrO22gl7f6VmmYh0Zbu6C196fe1elcHXd7U6LcLXu0YoVPc2kNesWiukYcdK8ZmJ6aQ==
+  dependencies:
+    chalk "^3.0.0"
+    csv "^5.3.1"
+    smartwrap "^1.2.3"
+    strip-ansi "^6.0.0"
+    wcwidth "^1.0.1"
+    yargs "^15.1.0"
+
 tunnel-agent@^0.6.0:
   version "0.6.0"
   resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
@@ -14970,6 +15407,14 @@ which-pm-runs@^1.0.0:
   resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
   integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
 
+which-pm@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz#8245609ecfe64bf751d0eef2f376d83bf1ddb7ae"
+  integrity sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==
+  dependencies:
+    load-yaml-file "^0.2.0"
+    path-exists "^4.0.0"
+
 which@1.3.1, which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
   version "1.3.1"
   resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
@@ -15310,7 +15755,7 @@ yargs@13.3.2, yargs@^13.3.0:
     y18n "^4.0.0"
     yargs-parser "^13.1.2"
 
-yargs@15.3.1, yargs@^15.0.2:
+yargs@15.3.1, yargs@^15.0.2, yargs@^15.1.0:
   version "15.3.1"
   resolved "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b"
   integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==

From 4a514e29a95b9be5e7d25315d047e9b40c67a116 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 19 May 2020 15:38:00 -0700
Subject: [PATCH 02/25] Create release pull request

---
 .github/workflows/release.yml | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 .github/workflows/release.yml

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000000..d6781d88c7a
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,30 @@
+name: Release
+
+on:
+  push:
+    branches:
+      - release
+
+jobs:
+  release:
+    name: Release
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@master
+        with:
+          # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
+          fetch-depth: 0
+
+      - name: Setup Node.js 12.x
+        uses: actions/setup-node@master
+        with:
+          node-version: 12.x
+
+      - name: Install Dependencies
+        run: yarn
+
+      - name: Create Release Pull Request
+        uses: changesets/action@master
+        env:
+          GITHUB_TOKEN: ${{ secrets.FEI_GITHUB_TOKEN }}
\ No newline at end of file

From ee7c9c6108b189d78c548a7b608486806a32b136 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 19 May 2020 15:48:21 -0700
Subject: [PATCH 03/25] change env variable name

---
 .github/workflows/release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d6781d88c7a..9c45ccf5dc8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,7 +3,7 @@ name: Release
 on:
   push:
     branches:
-      - release
+      - fei-release
 
 jobs:
   release:

From 4b396ff04ac8f4d557572da13646f3cac8b294e7 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 20 May 2020 14:42:27 -0700
Subject: [PATCH 04/25] use the correct secret in GHA

---
 .github/workflows/release.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9c45ccf5dc8..9620aaab3e2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,7 +3,7 @@ name: Release
 on:
   push:
     branches:
-      - fei-release
+      - release
 
 jobs:
   release:
@@ -27,4 +27,4 @@ jobs:
       - name: Create Release Pull Request
         uses: changesets/action@master
         env:
-          GITHUB_TOKEN: ${{ secrets.FEI_GITHUB_TOKEN }}
\ No newline at end of file
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file

From d94b6272eea9c53a1d604761fb5091162518439b Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 20 May 2020 14:44:05 -0700
Subject: [PATCH 05/25] make firebase a devDependency in integration test
 projects

---
 integration/browserify/package.json       | 4 +---
 integration/firebase-typings/package.json | 4 +---
 integration/messaging/package.json        | 4 +---
 integration/typescript/package.json       | 4 +---
 integration/webpack/package.json          | 4 +---
 5 files changed, 5 insertions(+), 15 deletions(-)

diff --git a/integration/browserify/package.json b/integration/browserify/package.json
index fef0c1d076c..2d6932a44ab 100644
--- a/integration/browserify/package.json
+++ b/integration/browserify/package.json
@@ -7,10 +7,8 @@
     "test": "karma start --single-run",
     "test:ci": "node ../../scripts/run_tests_in_ci.js"
   },
-  "dependencies": {
-    "firebase": "7.14.4"
-  },
   "devDependencies": {
+    "firebase": "7.14.4",
     "@babel/core": "7.9.6",
     "@babel/preset-env": "7.9.6",
     "browserify": "16.5.1",
diff --git a/integration/firebase-typings/package.json b/integration/firebase-typings/package.json
index 3e1e7a7d751..c30dfa20d73 100644
--- a/integration/firebase-typings/package.json
+++ b/integration/firebase-typings/package.json
@@ -6,10 +6,8 @@
     "test": "tsc",
     "test:ci": "node ../../scripts/run_tests_in_ci.js"
   },
-  "dependencies": {
-    "firebase": "7.14.4"
-  },
   "devDependencies": {
+    "firebase": "7.14.4",
     "typescript": "3.8.3"
   }
 }
diff --git a/integration/messaging/package.json b/integration/messaging/package.json
index 2e67bbcb5a1..2aa3639b5ee 100644
--- a/integration/messaging/package.json
+++ b/integration/messaging/package.json
@@ -7,10 +7,8 @@
     "test": "echo 'Tests disabled due to flakiness'",
     "test:manual": "mocha --exit"
   },
-  "dependencies": {
-    "firebase": "7.14.4"
-  },
   "devDependencies": {
+    "firebase": "7.14.4",
     "chai": "4.2.0",
     "chromedriver": "80.0.2",
     "express": "4.17.1",
diff --git a/integration/typescript/package.json b/integration/typescript/package.json
index c0d03ad0a8b..55e4d7923c3 100644
--- a/integration/typescript/package.json
+++ b/integration/typescript/package.json
@@ -6,10 +6,8 @@
     "test": "karma start --single-run",
     "test:ci": "node ../../scripts/run_tests_in_ci.js"
   },
-  "dependencies": {
-    "firebase": "7.14.4"
-  },
   "devDependencies": {
+    "firebase": "7.14.4",
     "@babel/core": "7.9.6",
     "@babel/preset-env": "7.9.6",
     "@types/chai": "4.2.11",
diff --git a/integration/webpack/package.json b/integration/webpack/package.json
index 247d544aab9..ccab4dfea52 100644
--- a/integration/webpack/package.json
+++ b/integration/webpack/package.json
@@ -7,10 +7,8 @@
     "test": "karma start --single-run",
     "test:ci": "node ../../scripts/run_tests_in_ci.js"
   },
-  "dependencies": {
-    "firebase": "7.14.4"
-  },
   "devDependencies": {
+    "firebase": "7.14.4",
     "@babel/core": "7.9.6",
     "@babel/preset-env": "7.9.6",
     "chai": "4.2.0",

From 928329812b3ad0e5b2e7f2705189cb5ff9745b0e Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 20 May 2020 17:28:44 -0700
Subject: [PATCH 06/25] initial changeset release rewrite

---
 package.json                                 |   7 +-
 scripts/release/canary.ts                    |  53 ++++
 scripts/release/cli.js                       | 248 -------------------
 scripts/release/cli.ts                       | 154 ++++++++++++
 scripts/release/utils/enums.ts               |  22 ++
 scripts/release/utils/git.js                 |  15 ++
 scripts/release/utils/inquirer.js            | 150 -----------
 scripts/release/utils/inquirer.ts            |  26 ++
 scripts/release/utils/publish.ts             |  25 ++
 scripts/release/utils/{tests.js => tests.ts} |  25 +-
 scripts/release/utils/{yarn.js => yarn.ts}   |  46 ++--
 scripts/tsconfig.json                        |  16 ++
 scripts/{utils.js => utils.ts}               |  23 +-
 yarn.lock                                    |   7 +
 14 files changed, 362 insertions(+), 455 deletions(-)
 create mode 100644 scripts/release/canary.ts
 delete mode 100644 scripts/release/cli.js
 create mode 100644 scripts/release/cli.ts
 create mode 100644 scripts/release/utils/enums.ts
 delete mode 100644 scripts/release/utils/inquirer.js
 create mode 100644 scripts/release/utils/inquirer.ts
 create mode 100644 scripts/release/utils/publish.ts
 rename scripts/release/utils/{tests.js => tests.ts} (66%)
 rename scripts/release/utils/{yarn.js => yarn.ts} (54%)
 create mode 100644 scripts/tsconfig.json
 rename scripts/{utils.js => utils.ts} (74%)

diff --git a/package.json b/package.json
index 4aa75eee7b7..8294c963970 100644
--- a/package.json
+++ b/package.json
@@ -60,6 +60,8 @@
     "integration/*"
   ],
   "devDependencies": {
+    "@changesets/changelog-github": "0.2.5",
+    "@changesets/cli": "2.6.5",
     "@microsoft/api-documenter": "7.7.20",
     "@microsoft/api-extractor": "7.7.13",
     "@types/chai": "4.2.11",
@@ -71,6 +73,7 @@
     "@types/sinon-chai": "3.2.4",
     "@types/tmp": "0.2.0",
     "@types/yargs": "15.0.4",
+    "@types/child-process-promise": "2.2.1",
     "@typescript-eslint/eslint-plugin": "2.30.0",
     "@typescript-eslint/eslint-plugin-tslint": "2.30.0",
     "@typescript-eslint/parser": "2.30.0",
@@ -138,9 +141,7 @@
     "typescript": "3.8.3",
     "watch": "1.0.2",
     "webpack": "4.43.0",
-    "yargs": "15.3.1",
-    "@changesets/cli": "2.6.5",
-    "@changesets/changelog-github": "0.2.5"
+    "yargs": "15.3.1"
   },
   "husky": {
     "hooks": {
diff --git a/scripts/release/canary.ts b/scripts/release/canary.ts
new file mode 100644
index 00000000000..e719db2cd8e
--- /dev/null
+++ b/scripts/release/canary.ts
@@ -0,0 +1,53 @@
+/**
+ * @license
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Don't do the following for canary releases:
+ * - Rerun tests (this is supposed to be a representation of the sha)
+ * - Commit/Tag the release (we aren't creating new tags, just exposing the
+ *   current version)
+ * - Push updates to github (no updates to push)
+ */
+export async function runCanaryRelease(): Promise<void> {
+  let versions;
+
+  /**
+   * Set the canary version following the pattern below:
+   *
+   * Version: <version>-canary.<git sha>
+   *
+   * A user would be able to install a package canary as follows:
+   *
+   * $ npm install @firebase/app@0.0.0-canary.0000000
+   */
+  let updates;
+  const sha = await getCurrentSha();
+  updates = await getAllPackages();
+  const pkgJsons = await Promise.all(
+    updates.map(pkg => mapPkgNameToPkgJson(pkg))
+  );
+  versions = updates.reduce((map, pkg, idx) => {
+    const { version } = pkgJsons[idx];
+    map[pkg] = `${version}-canary.${sha}`;
+    return map;
+  }, {});
+
+  /**
+   * Update the package.json dependencies throughout the SDK
+   */
+  await updateWorkspaceVersions(versions, argv.canary);
+}
diff --git a/scripts/release/cli.js b/scripts/release/cli.js
deleted file mode 100644
index 22da90df3f6..00000000000
--- a/scripts/release/cli.js
+++ /dev/null
@@ -1,248 +0,0 @@
-/**
- * @license
- * Copyright 2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const { exec } = require('child-process-promise');
-const { createPromptModule } = require('inquirer');
-const prompt = createPromptModule();
-const { hasUpdatedPackages } = require('./utils/lerna');
-const {
-  getAllPackages,
-  getOrderedUpdates,
-  mapPkgNameToPkgJson,
-  updateWorkspaceVersions
-} = require('./utils/workspace');
-const {
-  cleanTree,
-  commitAndTag,
-  getCurrentSha,
-  hasDiff,
-  pushUpdatesToGithub,
-  resetWorkingTree
-} = require('./utils/git');
-const {
-  packageVersionUpdate,
-  releaseType: releaseTypePrompt,
-  validateReadyToPush,
-  validateVersions
-} = require('./utils/inquirer');
-const { reinstallDeps, buildPackages } = require('./utils/yarn');
-const { runTests, setupTestDeps } = require('./utils/tests');
-const { publishToNpm } = require('./utils/npm');
-const { bannerText } = require('./utils/banner');
-const { argv } = require('yargs');
-
-(async () => {
-  try {
-    /**
-     * Welcome to the firebase release CLI!
-     */
-    await bannerText();
-
-    /**
-     * If there are unstaged changes, error
-     */
-    if (await hasDiff()) {
-      throw new Error(
-        'You have unstaged changes, stash your changes before attempting to publish'
-      );
-    }
-
-    /**
-     * If there are no packages that have been updated
-     * skip the release cycle
-     */
-    if (!(await hasUpdatedPackages())) {
-      console.log('No packages need to be updated. Exiting...');
-      return;
-    }
-
-    /**
-     * TODO: Add a check that the current sha exists on Github somewhere
-     *
-     * This should validate that the local branch isn't local-only
-     */
-
-    /**
-     * Log the user who will be publishing the packages
-     */
-    if (!process.env.CI) {
-      const { stdout: whoami } = await exec('npm whoami');
-      console.log(`Publishing as ${whoami}`);
-    }
-
-    /**
-     * Determine if the current release is a staging or production release
-     */
-    const releaseType = await (async () => {
-      if (argv.canary) return 'Canary';
-      /**
-       * Capture the release type if it was passed to the CLI via args
-       */
-      if (
-        argv.releaseType &&
-        (argv.releaseType === 'Staging' || argv.releaseType === 'Production')
-      ) {
-        return argv.releaseType;
-      }
-
-      /**
-       * Prompt for the release type (i.e. staging/prod)
-       */
-      const responses = await prompt([releaseTypePrompt]);
-      return responses.releaseType;
-    })();
-
-    let versions;
-
-    /**
-     * Set the canary version following the pattern below:
-     *
-     * Version: <version>-canary.<git sha>
-     *
-     * A user would be able to install a package canary as follows:
-     *
-     * $ npm install @firebase/app@0.0.0-canary.0000000
-     */
-    let updates;
-    if (argv.canary) {
-      const sha = await getCurrentSha();
-      updates = await getAllPackages();
-      const pkgJsons = await Promise.all(
-        updates.map(pkg => mapPkgNameToPkgJson(pkg))
-      );
-      versions = updates.reduce((map, pkg, idx) => {
-        const { version } = pkgJsons[idx];
-        map[pkg] = `${version}-canary.${sha}`;
-        return map;
-      }, {});
-    } else {
-      /**
-       * Prompt user for the new versions
-       */
-      updates = await getOrderedUpdates();
-      const versionUpdates = await Promise.all(
-        updates.map(pkg => packageVersionUpdate(pkg, releaseType))
-      );
-      versions = await prompt(versionUpdates);
-
-      /**
-       * Verify that the versions selected are correct
-       */
-      const { versionCheck } = await prompt(validateVersions(versions));
-
-      /**
-       * If the versions where incorrect, bail.
-       */
-      if (!versionCheck) throw new Error('Version Check Failed');
-    }
-
-    /**
-     * Update the package.json dependencies throughout the SDK
-     */
-    await updateWorkspaceVersions(versions, argv.canary);
-
-    /**
-     * Users can pass --skipReinstall to skip the installation step
-     */
-    if (!argv.skipReinstall) {
-      /**
-       * Clean install dependencies
-       */
-      console.log('\r\nVerifying Build');
-      await cleanTree();
-      await reinstallDeps();
-    }
-
-    /**
-     * build packages
-     */
-    await buildPackages();
-
-    /**
-     * Don't do the following for canary releases:
-     * - Rerun tests (this is supposed to be a representation of the sha)
-     * - Commit/Tag the release (we aren't creating new tags, just exposing the
-     *   current version)
-     * - Push updates to github (no updates to push)
-     */
-    if (!argv.canary) {
-      /**
-       * Ensure all tests are passing
-       */
-
-      /**
-       * Users can pass --skipTests to skip the testing step
-       */
-      if (!argv.skipTests) {
-        await setupTestDeps();
-        await runTests();
-      }
-
-      const { readyToPush } = await prompt(validateReadyToPush);
-      if (!readyToPush) throw new Error('Push Check Failed');
-
-      /**
-       * Only do the following on a production build
-       */
-      if (releaseType === 'Production') {
-        /**
-         * Commit the version changes and tag the associated versions
-         */
-        const tags = await commitAndTag(versions, releaseType);
-
-        /**
-         * Push new version to Github
-         */
-        await pushUpdatesToGithub(tags);
-      }
-    }
-
-    /**
-     * Release new versions to NPM
-     */
-    await publishToNpm(
-      updates,
-      releaseType,
-      argv.canary ? 'canary' : 'default'
-    );
-
-    /**
-     * If this wasn't a production release there
-     * are now, unstaged chages. Drop them as this
-     * was a prerelease/canary release.
-     */
-    if (releaseType !== 'Production') {
-      await resetWorkingTree();
-    }
-  } catch (err) {
-    /**
-     * Log any errors that happened during the process
-     */
-    console.error(err);
-
-    /**
-     * Reset the working tree (will remove unneeded changes if they weren't
-     * committed already)
-     */
-    await resetWorkingTree();
-
-    /**
-     * Exit with an error code
-     */
-    process.exit(1);
-  }
-})();
diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
new file mode 100644
index 00000000000..1c29a9d9c6b
--- /dev/null
+++ b/scripts/release/cli.ts
@@ -0,0 +1,154 @@
+/**
+ * @license
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { runCanaryRelease } from './canary';
+import { ReleaseType } from './utils/enums';
+import { publish } from './utils/publish';
+import { pushReleaseTagsToGithub } from './utils/git';
+
+const { exec } = require('child-process-promise');
+const { createPromptModule } = require('inquirer');
+const prompt = createPromptModule();
+const { hasUpdatedPackages } = require('./utils/lerna');
+const {
+  getAllPackages,
+  getOrderedUpdates,
+  mapPkgNameToPkgJson,
+  updateWorkspaceVersions
+} = require('./utils/workspace');
+const {
+  cleanTree,
+  commitAndTag,
+  getCurrentSha,
+  hasDiff,
+  pushUpdatesToGithub,
+  resetWorkingTree
+} = require('./utils/git');
+const {
+  packageVersionUpdate,
+  releaseType: releaseTypePrompt,
+  validateVersions
+} = require('./utils/inquirer');
+const { reinstallDeps, buildPackages } = require('./utils/yarn');
+const { runTests, setupTestDeps } = require('./utils/tests');
+const { publishToNpm } = require('./utils/npm');
+const { bannerText } = require('./utils/banner');
+const { argv } = require('yargs');
+
+(async () => {
+  try {
+    /**
+     * Welcome to the firebase release CLI!
+     */
+    await bannerText();
+
+    /**
+     * If there are unstaged changes, error
+     */
+    if (await hasDiff()) {
+      throw new Error(
+        'You have unstaged changes, stash your changes before attempting to publish'
+      );
+    }
+
+    /**
+     * Log the user who will be publishing the packages
+     */
+    if (!process.env.CI) {
+      const { stdout: whoami } = await exec('npm whoami');
+      console.log(`Publishing as ${whoami}`);
+    }
+
+    /**
+     * Determine if the current release is a staging or production release
+     */
+    const releaseType = await (async () => {
+      if (argv.canary) return ReleaseType.Canary;
+      /**
+       * Capture the release type if it was passed to the CLI via args
+       */
+      if (
+        argv.releaseType &&
+        (argv.releaseType === ReleaseType.Staging ||
+          argv.releaseType === ReleaseType.Production)
+      ) {
+        return argv.releaseType;
+      }
+
+      /**
+       * Prompt for the release type (i.e. staging/prod)
+       */
+      const responses = await prompt([releaseTypePrompt]);
+      return responses.releaseType;
+    })();
+
+    if (releaseType === ReleaseType.Canary) {
+      await runCanaryRelease();
+    } else if (releaseType === ReleaseType.Staging) {
+      // TODO: check if changeset is in the pre mode. Throw, if not.
+    }
+
+    /**
+     * Users can pass --skipReinstall to skip the installation step
+     */
+    if (!argv.skipReinstall) {
+      /**
+       * Clean install dependencies
+       */
+      console.log('\r\nVerifying Build');
+      await cleanTree();
+      await reinstallDeps();
+    }
+
+    /**
+     * build packages
+     */
+    await buildPackages();
+
+    /**
+     * Ensure all tests are passing
+     */
+
+    /**
+     * Users can pass --skipTests to skip the testing step
+     */
+    if (!argv.skipTests) {
+      await setupTestDeps();
+      await runTests();
+    }
+
+    /**
+     * Release new versions to NPM using changeset
+     * It will also create tags
+     */
+    await publish();
+
+    /**
+     * Push release tags created by changeset in publish() to Github
+     */
+    await pushReleaseTagsToGithub();
+  } catch (err) {
+    /**
+     * Log any errors that happened during the process
+     */
+    console.error(err);
+    /**
+     * Exit with an error code
+     */
+    process.exit(1);
+  }
+})();
diff --git a/scripts/release/utils/enums.ts b/scripts/release/utils/enums.ts
new file mode 100644
index 00000000000..2243dfc0777
--- /dev/null
+++ b/scripts/release/utils/enums.ts
@@ -0,0 +1,22 @@
+/**
+ * @license
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export enum ReleaseType {
+  Canary = 'Canary',
+  Staging = 'Staging',
+  Production = 'Production'
+}
diff --git a/scripts/release/utils/git.js b/scripts/release/utils/git.js
index b75d5266b59..9f615699b20 100644
--- a/scripts/release/utils/git.js
+++ b/scripts/release/utils/git.js
@@ -80,3 +80,18 @@ exports.hasDiff = async () => {
   console.log(diff);
   return !!diff;
 };
+
+export async function pushReleaseTagsToGithub() {
+  // Get tags pointing to HEAD
+  // When running the release script, these tags should be release tags created by changeset
+  const { stdout: rawTags, stderr } = await exec(`git tag --points-at HEAD`);
+
+  const tags = rawTags.split('\r\n');
+
+  let { stdout: currentBranch, stderr } = await exec(
+    `git rev-parse --abbrev-ref HEAD`
+  );
+  currentBranch = currentBranch.trim();
+
+  await exec(`git push origin ${tags.join(' ')} --no-verify`, { cwd: root });
+}
diff --git a/scripts/release/utils/inquirer.js b/scripts/release/utils/inquirer.js
deleted file mode 100644
index 22569005835..00000000000
--- a/scripts/release/utils/inquirer.js
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * @license
- * Copyright 2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const { exec } = require('child-process-promise');
-const { gt } = require('semver');
-const chalk = require('chalk');
-const { inc, prerelease } = require('semver');
-const { mapPkgNameToPkgJson } = require('./workspace');
-
-function capitalize(string) {
-  return string.charAt(0).toUpperCase() + string.slice(1);
-}
-
-exports.packageVersionUpdate = async (package, releaseType) => {
-  /**
-   * Get the current package version
-   */
-  let { version, private } = await mapPkgNameToPkgJson(package);
-
-  /**
-   * Check and see if we are trying to publish a prerelease
-   */
-  let isPublished = await (async isStaging => {
-    if (isStaging) {
-      let { stdout } = await exec(`npm info ${package}@next version`);
-      return !!stdout.trim();
-    } else {
-      let { stdout } = await exec(`npm info ${package} version`);
-      return !stdout.includes('canary');
-    }
-  })(releaseType === 'Staging');
-
-  if (releaseType === 'Staging' && !private) {
-    let { stdout: nextVersion } = await exec(
-      `npm info ${package}@next version`
-    );
-    /**
-     * Trim this stdout string as the whitespace returned from this function
-     * will break the `semver` module parsing
-     */
-    nextVersion = nextVersion.trim();
-    /**
-     * If we are currently in a prerelease cycle, fast-forward the version
-     * to the prereleased version instead of the current version
-     */
-    if (isPublished && gt(nextVersion, version)) {
-      version = nextVersion;
-    }
-  }
-
-  /**
-   * If the current version is a prerelease allow the developer to
-   * bump the prerelease version
-   */
-  let prereleaseVersions = ['prepatch', 'preminor', 'premajor'];
-  if (prerelease(version)) {
-    prereleaseVersions = ['prerelease', ...prereleaseVersions];
-  }
-
-  /**
-   * Determine which set of increments we will be using
-   */
-  const increments =
-    releaseType === 'Staging'
-      ? prereleaseVersions
-      : ['patch', 'minor', 'major'];
-
-  let choices;
-
-  if (isPublished) {
-    /**
-     * Will hit this codepath if we are publishing a module that has already been
-     * published once
-     */
-    choices = increments.map(increment => {
-      const newVersion = inc(version, increment);
-      return {
-        name: chalk`${capitalize(increment)} {gray ${newVersion}}`,
-        value: newVersion
-      };
-    });
-  } else {
-    version = releaseType === 'Staging' ? inc(version, 'pre') : version;
-    /**
-     * Will hit this codepath if this is the first prerelease of the component
-     */
-    choices = [
-      {
-        name: chalk`Initial Release {gray ${version}}`,
-        value: version
-      }
-    ];
-  }
-
-  /**
-   * Create prompts
-   */
-  return {
-    type: 'list',
-    name: `${package}`,
-    message: `Select semver increment for ${package}`,
-    choices
-  };
-};
-
-exports.releaseType = {
-  type: 'list',
-  name: 'releaseType',
-  message: 'Is this a staging, or a production release?',
-  choices: ['Staging', 'Production'],
-  default: 'Staging'
-};
-
-exports.validateVersions = versionMap => {
-  let message =
-    '\r\nAre you sure these are the versions you want to publish?\r\n';
-  Object.keys(versionMap)
-    .map(name => ({ name, version: versionMap[name] }))
-    .forEach(({ name, version }) => {
-      message += `${name}@${version}\n`;
-    });
-
-  return {
-    type: 'confirm',
-    name: 'versionCheck',
-    message,
-    default: false
-  };
-};
-
-exports.validateReadyToPush = {
-  type: 'confirm',
-  name: 'readyToPush',
-  message: '\r\nAre you sure you are ready to push to Github/NPM?\r\n',
-  default: false
-};
diff --git a/scripts/release/utils/inquirer.ts b/scripts/release/utils/inquirer.ts
new file mode 100644
index 00000000000..03f0cf353a3
--- /dev/null
+++ b/scripts/release/utils/inquirer.ts
@@ -0,0 +1,26 @@
+/**
+ * @license
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ReleaseType } from './enums';
+
+export const releaseType = {
+  type: 'list',
+  name: 'releaseType',
+  message: 'Is this a staging, or a production release?',
+  choices: [ReleaseType.Staging, ReleaseType.Production],
+  default: ReleaseType.Staging
+};
diff --git a/scripts/release/utils/publish.ts b/scripts/release/utils/publish.ts
new file mode 100644
index 00000000000..b46ccfa5d5c
--- /dev/null
+++ b/scripts/release/utils/publish.ts
@@ -0,0 +1,25 @@
+/**
+ * @license
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { spawn } from 'child-process-promise';
+const { projectRoot: root } = require('../../utils');
+
+export async function publish() {
+  await spawn('yarn', ['changeset', 'publish'], {
+    cwd: root
+  });
+}
diff --git a/scripts/release/utils/tests.js b/scripts/release/utils/tests.ts
similarity index 66%
rename from scripts/release/utils/tests.js
rename to scripts/release/utils/tests.ts
index 48fbf6b7c74..ac647299992 100644
--- a/scripts/release/utils/tests.js
+++ b/scripts/release/utils/tests.ts
@@ -15,21 +15,16 @@
  * limitations under the License.
  */
 
-const { spawn } = require('child-process-promise');
-const { projectRoot: root } = require('../../utils');
-const ora = require('ora');
+import { spawn } from 'child-process-promise';
+import { projectRoot as root } from '../../utils';
 
-exports.runTests = async () => {
-  try {
-    await spawn('yarn', ['test'], {
-      cwd: root,
-      stdio: 'inherit'
-    });
-  } catch (err) {
-    throw err;
-  }
-};
+export async function runTests(): Promise<void> {
+  await spawn('yarn', ['test'], {
+    cwd: root,
+    stdio: 'inherit'
+  });
+}
 
-exports.setupTestDeps = async () => {
+export async function setupTestDeps(): Promise<void> {
   await spawn('yarn', ['test:setup'], { stdio: 'inherit' });
-};
+}
diff --git a/scripts/release/utils/yarn.js b/scripts/release/utils/yarn.ts
similarity index 54%
rename from scripts/release/utils/yarn.js
rename to scripts/release/utils/yarn.ts
index 7f66debd11b..a8ce5b488c7 100644
--- a/scripts/release/utils/yarn.js
+++ b/scripts/release/utils/yarn.ts
@@ -15,34 +15,26 @@
  * limitations under the License.
  */
 
-const { spawn } = require('child-process-promise');
+import { spawn } from 'child-process-promise';
 const { projectRoot: root } = require('../../utils');
 const ora = require('ora');
 
-exports.reinstallDeps = async () => {
-  try {
-    const spinner = ora(' Reinstalling Dependencies').start();
-    await spawn('yarn', {
-      cwd: root
-    });
-    spinner.stopAndPersist({
-      symbol: '✅'
-    });
-  } catch (err) {
-    throw err;
-  }
-};
+export async function reinstallDeps() {
+  const spinner = ora(' Reinstalling Dependencies').start();
+  await spawn('yarn', null, {
+    cwd: root
+  });
+  spinner.stopAndPersist({
+    symbol: '✅'
+  });
+}
 
-exports.buildPackages = async () => {
-  try {
-    const spinner = ora(' Building Packages').start();
-    await spawn('yarn', ['build:release'], {
-      cwd: root
-    });
-    spinner.stopAndPersist({
-      symbol: '✅'
-    });
-  } catch (err) {
-    throw err;
-  }
-};
+export async function buildPackages() {
+  const spinner = ora(' Building Packages').start();
+  await spawn('yarn', ['build:release'], {
+    cwd: root
+  });
+  spinner.stopAndPersist({
+    symbol: '✅'
+  });
+}
diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json
new file mode 100644
index 00000000000..336f3ec429b
--- /dev/null
+++ b/scripts/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "strict": true,
+    "lib": [
+      "ESNext"
+    ],
+    "module": "CommonJS",
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+    "target": "es5",
+    "typeRoots": [
+      "../node_modules/@types"
+    ],
+    "allowJs": true
+  }
+}
\ No newline at end of file
diff --git a/scripts/utils.js b/scripts/utils.ts
similarity index 74%
rename from scripts/utils.js
rename to scripts/utils.ts
index 9d873fa9cd1..500a650c365 100644
--- a/scripts/utils.js
+++ b/scripts/utils.ts
@@ -15,14 +15,13 @@
  * limitations under the License.
  */
 
-const { dirname, resolve } = require('path');
-const simpleGit = require('simple-git/promise');
-const { exec } = require('child-process-promise');
+import { dirname, resolve } from 'path';
+import * as simpleGit from 'simple-git/promise';
+import { exec } from 'child-process-promise';
 
-const projectRoot = dirname(resolve(__dirname, '../package.json'));
-exports.projectRoot = projectRoot;
+export const projectRoot = dirname(resolve(__dirname, '../package.json'));
 
-async function getChangedFiles() {
+export async function getChangedFiles(): Promise<string[]> {
   console.log(projectRoot);
   const git = simpleGit(projectRoot);
   const diff = await git.diff(['--name-only', 'origin/master...HEAD']);
@@ -30,10 +29,11 @@ async function getChangedFiles() {
 
   return changedFiles;
 }
-exports.getChangedFiles = getChangedFiles;
 
-async function getChangedPackages(changedFiles) {
-  const changedPackages = new Set();
+export async function getChangedPackages(
+  changedFiles: string[]
+): Promise<string[]> {
+  const changedPackages = new Set<string>();
   const files = changedFiles || (await getChangedFiles());
   for (const filename of files) {
     // Check for changed files inside package dirs.
@@ -49,9 +49,8 @@ async function getChangedPackages(changedFiles) {
   }
   return Array.from(changedPackages.values());
 }
-exports.getChangedPackages = getChangedPackages;
 
-exports.getPackageInfo = async function(
+export async function getPackageInfo(
   { includePrivate } = { includePrivate: true }
 ) {
   const packageInfo = JSON.parse(
@@ -59,4 +58,4 @@ exports.getPackageInfo = async function(
   );
 
   return packageInfo;
-};
+}
diff --git a/yarn.lock b/yarn.lock
index f133cd515db..b236cddf850 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2286,6 +2286,13 @@
   resolved "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50"
   integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==
 
+"@types/child-process-promise@2.2.1":
+  version "2.2.1"
+  resolved "https://registry.npmjs.org/@types/child-process-promise/-/child-process-promise-2.2.1.tgz#049033bef102f77a1719b38672cc86a2c4710ab1"
+  integrity sha512-xZ4kkF82YkmqPCERqV9Tj0bVQj3Tk36BqGlNgxv5XhifgDRhwAqp+of+sccksdpZRbbPsNwMOkmUqOnLgxKtGw==
+  dependencies:
+    "@types/node" "*"
+
 "@types/color-name@^1.1.1":
   version "1.1.1"
   resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"

From 65d6be2c597f8440c22d9ec27b11b8e5136737b1 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 20 May 2020 18:16:41 -0700
Subject: [PATCH 07/25] clean up imports in cli.ts

---
 package.json                             |  3 +-
 scripts/release/cli.ts                   | 36 ++++++------------------
 scripts/release/utils/{git.js => git.ts} | 34 +++++++++++-----------
 yarn.lock                                | 15 ++++++++++
 4 files changed, 43 insertions(+), 45 deletions(-)
 rename scripts/release/utils/{git.js => git.ts} (82%)

diff --git a/package.json b/package.json
index 8294c963970..75aa9dcfa6a 100644
--- a/package.json
+++ b/package.json
@@ -66,6 +66,8 @@
     "@microsoft/api-extractor": "7.7.13",
     "@types/chai": "4.2.11",
     "@types/chai-as-promised": "7.1.2",
+    "@types/child-process-promise": "2.2.1",
+    "@types/inquirer": "6.5.0",
     "@types/long": "4.0.1",
     "@types/mocha": "7.0.2",
     "@types/node": "12.12.37",
@@ -73,7 +75,6 @@
     "@types/sinon-chai": "3.2.4",
     "@types/tmp": "0.2.0",
     "@types/yargs": "15.0.4",
-    "@types/child-process-promise": "2.2.1",
     "@typescript-eslint/eslint-plugin": "2.30.0",
     "@typescript-eslint/eslint-plugin-tslint": "2.30.0",
     "@typescript-eslint/parser": "2.30.0",
diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
index 1c29a9d9c6b..3c14a7ee751 100644
--- a/scripts/release/cli.ts
+++ b/scripts/release/cli.ts
@@ -18,36 +18,18 @@
 import { runCanaryRelease } from './canary';
 import { ReleaseType } from './utils/enums';
 import { publish } from './utils/publish';
-import { pushReleaseTagsToGithub } from './utils/git';
+import { pushReleaseTagsToGithub, cleanTree, hasDiff } from './utils/git';
 
-const { exec } = require('child-process-promise');
-const { createPromptModule } = require('inquirer');
+import { exec } from 'child-process-promise';
+import { createPromptModule } from 'inquirer';
 const prompt = createPromptModule();
-const { hasUpdatedPackages } = require('./utils/lerna');
-const {
-  getAllPackages,
-  getOrderedUpdates,
-  mapPkgNameToPkgJson,
-  updateWorkspaceVersions
-} = require('./utils/workspace');
-const {
-  cleanTree,
-  commitAndTag,
-  getCurrentSha,
-  hasDiff,
-  pushUpdatesToGithub,
-  resetWorkingTree
-} = require('./utils/git');
-const {
-  packageVersionUpdate,
-  releaseType: releaseTypePrompt,
-  validateVersions
-} = require('./utils/inquirer');
-const { reinstallDeps, buildPackages } = require('./utils/yarn');
-const { runTests, setupTestDeps } = require('./utils/tests');
-const { publishToNpm } = require('./utils/npm');
+
+import { releaseType as releaseTypePrompt } from './utils/inquirer';
+import { reinstallDeps, buildPackages } from './utils/yarn';
+import { runTests, setupTestDeps } from './utils/tests';
+import { argv } from 'yargs';
+
 const { bannerText } = require('./utils/banner');
-const { argv } = require('yargs');
 
 (async () => {
   try {
diff --git a/scripts/release/utils/git.js b/scripts/release/utils/git.ts
similarity index 82%
rename from scripts/release/utils/git.js
rename to scripts/release/utils/git.ts
index 9f615699b20..4183e0978e4 100644
--- a/scripts/release/utils/git.js
+++ b/scripts/release/utils/git.ts
@@ -21,7 +21,7 @@ const git = simpleGit(root);
 const { exec } = require('child-process-promise');
 const ora = require('ora');
 
-exports.cleanTree = async () => {
+export async function cleanTree() {
   const spinner = ora(' Cleaning git tree').start();
   await exec('git clean -xdf', {
     cwd: root
@@ -29,7 +29,7 @@ exports.cleanTree = async () => {
   spinner.stopAndPersist({
     symbol: '✅'
   });
-};
+}
 
 /**
  * Commits the current state of the repository and tags it with the appropriate
@@ -37,14 +37,16 @@ exports.cleanTree = async () => {
  *
  * Returns the tagged commits
  */
-exports.commitAndTag = async updatedVersions => {
+export async function commitAndTag(updatedVersions: {
+  [packageName: string]: string;
+}) {
   await exec('git add */package.json yarn.lock');
 
   let result = await exec(
     `git commit -m "Publish firebase@${updatedVersions.firebase}"`
   );
 
-  const tags = [];
+  const tags: string[] = [];
   await Promise.all(
     Object.keys(updatedVersions)
       .map(name => ({ name, version: updatedVersions[name] }))
@@ -55,9 +57,9 @@ exports.commitAndTag = async updatedVersions => {
       })
   );
   return tags;
-};
+}
 
-exports.pushUpdatesToGithub = async tags => {
+export async function pushUpdatesToGithub(tags: string[]) {
   let { stdout: currentBranch, stderr } = await exec(
     `git rev-parse --abbrev-ref HEAD`
   );
@@ -65,32 +67,30 @@ exports.pushUpdatesToGithub = async tags => {
 
   await exec(`git push origin ${currentBranch} --no-verify -u`, { cwd: root });
   await exec(`git push origin ${tags.join(' ')} --no-verify`, { cwd: root });
-};
+}
 
-exports.resetWorkingTree = async () => {
+export async function resetWorkingTree() {
   await git.checkout('.');
-};
+}
 
-exports.getCurrentSha = async () => {
+export async function getCurrentSha() {
   return (await git.revparse(['--short', 'HEAD'])).trim();
-};
+}
 
-exports.hasDiff = async () => {
+export async function hasDiff() {
   const diff = await git.diff();
   console.log(diff);
   return !!diff;
-};
+}
 
 export async function pushReleaseTagsToGithub() {
   // Get tags pointing to HEAD
   // When running the release script, these tags should be release tags created by changeset
-  const { stdout: rawTags, stderr } = await exec(`git tag --points-at HEAD`);
+  const { stdout: rawTags } = await exec(`git tag --points-at HEAD`);
 
   const tags = rawTags.split('\r\n');
 
-  let { stdout: currentBranch, stderr } = await exec(
-    `git rev-parse --abbrev-ref HEAD`
-  );
+  let { stdout: currentBranch } = await exec(`git rev-parse --abbrev-ref HEAD`);
   currentBranch = currentBranch.trim();
 
   await exec(`git push origin ${tags.join(' ')} --no-verify`, { cwd: root });
diff --git a/yarn.lock b/yarn.lock
index b236cddf850..28fd9599d34 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2366,6 +2366,14 @@
     "@types/minimatch" "*"
     "@types/node" "*"
 
+"@types/inquirer@6.5.0":
+  version "6.5.0"
+  resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be"
+  integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==
+  dependencies:
+    "@types/through" "*"
+    rxjs "^6.4.0"
+
 "@types/json-schema@^7.0.3":
   version "7.0.4"
   resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
@@ -2501,6 +2509,13 @@
   resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e"
   integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==
 
+"@types/through@*":
+  version "0.0.30"
+  resolved "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
+  integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
+  dependencies:
+    "@types/node" "*"
+
 "@types/tmp@0.2.0":
   version "0.2.0"
   resolved "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.0.tgz#e3f52b4d7397eaa9193592ef3fdd44dc0af4298c"

From 53b1b94fcc99d34fe6b3e2cae10a276d9459a52a Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 20 May 2020 18:54:30 -0700
Subject: [PATCH 08/25] save progress

---
 package.json                                  |  1 +
 scripts/release/canary.ts                     | 27 +++++---
 scripts/release/cli.ts                        |  7 ++-
 scripts/release/utils/publish.ts              |  2 +-
 .../utils/{workspace.js => workspace.ts}      | 61 +++++++++++--------
 scripts/tsconfig.json                         |  1 +
 yarn.lock                                     |  5 ++
 7 files changed, 63 insertions(+), 41 deletions(-)
 mode change 100644 => 100755 scripts/release/cli.ts
 rename scripts/release/utils/{workspace.js => workspace.ts} (78%)

diff --git a/package.json b/package.json
index 75aa9dcfa6a..affaf4919f4 100644
--- a/package.json
+++ b/package.json
@@ -67,6 +67,7 @@
     "@types/chai": "4.2.11",
     "@types/chai-as-promised": "7.1.2",
     "@types/child-process-promise": "2.2.1",
+    "@types/clone": "0.1.30",
     "@types/inquirer": "6.5.0",
     "@types/long": "4.0.1",
     "@types/mocha": "7.0.2",
diff --git a/scripts/release/canary.ts b/scripts/release/canary.ts
index e719db2cd8e..03790bc09fd 100644
--- a/scripts/release/canary.ts
+++ b/scripts/release/canary.ts
@@ -15,6 +15,13 @@
  * limitations under the License.
  */
 
+import { getCurrentSha } from './utils/git';
+import {
+  getAllPackages,
+  mapPkgNameToPkgJson,
+  updateWorkspaceVersions
+} from './utils/workspace';
+
 /**
  * Don't do the following for canary releases:
  * - Rerun tests (this is supposed to be a representation of the sha)
@@ -23,8 +30,6 @@
  * - Push updates to github (no updates to push)
  */
 export async function runCanaryRelease(): Promise<void> {
-  let versions;
-
   /**
    * Set the canary version following the pattern below:
    *
@@ -34,20 +39,22 @@ export async function runCanaryRelease(): Promise<void> {
    *
    * $ npm install @firebase/app@0.0.0-canary.0000000
    */
-  let updates;
   const sha = await getCurrentSha();
-  updates = await getAllPackages();
+  const updates = await getAllPackages();
   const pkgJsons = await Promise.all(
     updates.map(pkg => mapPkgNameToPkgJson(pkg))
   );
-  versions = updates.reduce((map, pkg, idx) => {
-    const { version } = pkgJsons[idx];
-    map[pkg] = `${version}-canary.${sha}`;
-    return map;
-  }, {});
+  const versions = pkgJsons.reduce<{ [key: string]: string }>(
+    (map, pkgJson) => {
+      const { version, name } = pkgJson;
+      map[name] = `${version}-canary.${sha}`;
+      return map;
+    },
+    {}
+  );
 
   /**
    * Update the package.json dependencies throughout the SDK
    */
-  await updateWorkspaceVersions(versions, argv.canary);
+  await updateWorkspaceVersions(versions, true);
 }
diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
old mode 100644
new mode 100755
index 3c14a7ee751..5a2771c6ae0
--- a/scripts/release/cli.ts
+++ b/scripts/release/cli.ts
@@ -1,3 +1,4 @@
+#!/usr/bin/env ts-node-script
 /**
  * @license
  * Copyright 2018 Google LLC
@@ -79,7 +80,7 @@ const { bannerText } = require('./utils/banner');
     })();
 
     if (releaseType === ReleaseType.Canary) {
-      await runCanaryRelease();
+      // await runCanaryRelease();
     } else if (releaseType === ReleaseType.Staging) {
       // TODO: check if changeset is in the pre mode. Throw, if not.
     }
@@ -117,12 +118,12 @@ const { bannerText } = require('./utils/banner');
      * Release new versions to NPM using changeset
      * It will also create tags
      */
-    await publish();
+    //  await publish();
 
     /**
      * Push release tags created by changeset in publish() to Github
      */
-    await pushReleaseTagsToGithub();
+    //  await pushReleaseTagsToGithub();
   } catch (err) {
     /**
      * Log any errors that happened during the process
diff --git a/scripts/release/utils/publish.ts b/scripts/release/utils/publish.ts
index b46ccfa5d5c..4f1e46c90f7 100644
--- a/scripts/release/utils/publish.ts
+++ b/scripts/release/utils/publish.ts
@@ -16,7 +16,7 @@
  */
 
 import { spawn } from 'child-process-promise';
-const { projectRoot: root } = require('../../utils');
+import { projectRoot as root } from '../../utils';
 
 export async function publish() {
   await spawn('yarn', ['changeset', 'publish'], {
diff --git a/scripts/release/utils/workspace.js b/scripts/release/utils/workspace.ts
similarity index 78%
rename from scripts/release/utils/workspace.js
rename to scripts/release/utils/workspace.ts
index 92574ca2c3f..006ded1832b 100644
--- a/scripts/release/utils/workspace.js
+++ b/scripts/release/utils/workspace.ts
@@ -15,19 +15,26 @@
  * limitations under the License.
  */
 
-const glob = require('glob');
-const { projectRoot: root } = require('../../utils');
-const { workspaces: rawWorkspaces } = require(`${root}/package.json`);
-const workspaces = rawWorkspaces.map(workspace => `${root}/${workspace}`);
-const { DepGraph } = require('dependency-graph');
-const { getUpdatedPackages } = require('./lerna');
-const { promisify } = require('util');
-const { writeFile: _writeFile, existsSync } = require('fs');
+import glob from 'glob';
+import { projectRoot as root } from '../../utils';
+
+import { DepGraph } from 'dependency-graph';
+import { getUpdatedPackages } from './lerna';
+import { promisify } from 'util';
+import { writeFile as _writeFile, existsSync } from 'fs';
+import clone from 'clone';
+
 const writeFile = promisify(_writeFile);
-const clone = require('clone');
 
-function mapWorkspaceToPackages(workspaces) {
-  return Promise.all(
+const {
+  workspaces: rawWorkspaces
+}: { workspaces: string[] } = require(`${root}/package.json`);
+const workspaces = rawWorkspaces.map(workspace => `${root}/${workspace}`);
+
+export function mapWorkspaceToPackages(
+  workspaces: string[]
+): Promise<string[]> {
+  return Promise.all<string[]>(
     workspaces.map(
       workspace =>
         new Promise(resolve => {
@@ -39,9 +46,8 @@ function mapWorkspaceToPackages(workspaces) {
     )
   ).then(paths => paths.reduce((arr, val) => arr.concat(val), []));
 }
-exports.mapWorkspaceToPackages = mapWorkspaceToPackages;
 
-function mapPackagestoPkgJson(packagePaths) {
+function mapPackagestoPkgJson(packagePaths: string[]) {
   return packagePaths
     .map(path => {
       try {
@@ -53,7 +59,7 @@ function mapPackagestoPkgJson(packagePaths) {
     .filter(Boolean);
 }
 
-function mapPackagesToDepGraph(packagePaths) {
+function mapPackagesToDepGraph(packagePaths: string[]) {
   const graph = new DepGraph();
   const packages = mapPackagestoPkgJson(packagePaths);
 
@@ -67,7 +73,7 @@ function mapPackagesToDepGraph(packagePaths) {
   return graph;
 }
 
-exports.mapPkgNameToPkgPath = async pkgName => {
+export async function mapPkgNameToPkgPath(pkgName: string) {
   const packages = await mapWorkspaceToPackages(workspaces);
   return packages
     .filter(path => {
@@ -79,36 +85,37 @@ exports.mapPkgNameToPkgPath = async pkgName => {
       }
     })
     .reduce(val => val);
-};
+}
 
-exports.getAllPackages = async () => {
+export async function getAllPackages() {
   const packages = await mapWorkspaceToPackages(workspaces);
   const dependencies = mapPackagesToDepGraph(packages);
   return dependencies.overallOrder();
-};
+}
 
-exports.getOrderedUpdates = async () => {
+export async function getOrderedUpdates() {
   const packages = await mapWorkspaceToPackages(workspaces);
   const dependencies = mapPackagesToDepGraph(packages);
   const processingOrder = dependencies.overallOrder();
   const updated = await getUpdatedPackages();
 
   return processingOrder.filter(pkg => updated.includes(pkg));
-};
+}
 
-exports.mapPkgNameToPkgJson = async packageName => {
+export async function mapPkgNameToPkgJson(packageName: string) {
   const packages = await mapWorkspaceToPackages(workspaces);
   return mapPackagestoPkgJson(packages)
     .filter(pkg => pkg.name === packageName)
     .reduce(val => val);
-};
+}
 
-exports.updateWorkspaceVersions = async (newVersionObj, includePeerDeps) => {
+export async function updateWorkspaceVersions(
+  newVersionObj: { [pkgName: string]: string },
+  includePeerDeps: boolean
+) {
   try {
     let packages = await mapWorkspaceToPackages(workspaces);
-    packages = packages.filter(package =>
-      existsSync(`${package}/package.json`)
-    );
+    packages = packages.filter(pkg => existsSync(`${pkg}/package.json`));
 
     const pkgJsons = mapPackagestoPkgJson(packages);
 
@@ -153,4 +160,4 @@ exports.updateWorkspaceVersions = async (newVersionObj, includePeerDeps) => {
   } catch (err) {
     console.log(err);
   }
-};
+}
diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json
index 336f3ec429b..2e504fb1601 100644
--- a/scripts/tsconfig.json
+++ b/scripts/tsconfig.json
@@ -6,6 +6,7 @@
     ],
     "module": "CommonJS",
     "moduleResolution": "node",
+    "esModuleInterop": true,
     "resolveJsonModule": true,
     "target": "es5",
     "typeRoots": [
diff --git a/yarn.lock b/yarn.lock
index 28fd9599d34..21470578eed 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2293,6 +2293,11 @@
   dependencies:
     "@types/node" "*"
 
+"@types/clone@0.1.30":
+  version "0.1.30"
+  resolved "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
+  integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
+
 "@types/color-name@^1.1.1":
   version "1.1.1"
   resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"

From f3c0ba2bb2547b37d42aa58f965b5a4f17160c20 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Fri, 29 May 2020 16:49:17 -0700
Subject: [PATCH 09/25] implement canary release

---
 scripts/release/canary.ts          |  93 ++++++++++++++++++++++++-
 scripts/release/cli.ts             |  46 ++++++++----
 scripts/release/utils/lerna.js     |  54 ---------------
 scripts/release/utils/npm.js       | 108 -----------------------------
 scripts/release/utils/workspace.ts |  10 ---
 scripts/utils.ts                   |   2 +-
 6 files changed, 122 insertions(+), 191 deletions(-)
 delete mode 100644 scripts/release/utils/lerna.js
 delete mode 100644 scripts/release/utils/npm.js

diff --git a/scripts/release/canary.ts b/scripts/release/canary.ts
index 03790bc09fd..457701e1f89 100644
--- a/scripts/release/canary.ts
+++ b/scripts/release/canary.ts
@@ -19,12 +19,20 @@ import { getCurrentSha } from './utils/git';
 import {
   getAllPackages,
   mapPkgNameToPkgJson,
-  updateWorkspaceVersions
+  updateWorkspaceVersions,
+  mapPkgNameToPkgPath
 } from './utils/workspace';
+import Listr from 'listr';
+import { readFile as _readFile } from 'fs';
+import { promisify } from 'util';
+import { exec, spawn } from 'child-process-promise';
+
+const readFile = promisify(_readFile);
 
 /**
- * Don't do the following for canary releases:
- * - Rerun tests (this is supposed to be a representation of the sha)
+ *
+ * NOTE: Canary releases are performed in CI.
+ * Canary release does NOT do the following compared to a regular release:
  * - Commit/Tag the release (we aren't creating new tags, just exposing the
  *   current version)
  * - Push updates to github (no updates to push)
@@ -57,4 +65,83 @@ export async function runCanaryRelease(): Promise<void> {
    * Update the package.json dependencies throughout the SDK
    */
   await updateWorkspaceVersions(versions, true);
+
+  await publishToNpm(updates);
+}
+
+/**
+ * Given NPM package name, get env variable name for its publish token.
+ * @param {string} packageName NPM package name
+ */
+function getEnvTokenKey(packageName: string) {
+  let result = packageName.replace('@firebase/', '');
+  result = result.replace(/-/g, '_');
+  result = result.toUpperCase();
+  return `NPM_TOKEN_${result}`;
+}
+
+async function publishPackage(pkg: string) {
+  try {
+    const path = await mapPkgNameToPkgPath(pkg);
+
+    const { private: isPrivate } = JSON.parse(
+      await readFile(`${path}/package.json`, 'utf8')
+    );
+
+    /**
+     * Skip private packages
+     */
+    if (isPrivate) return;
+
+    /**
+     * publish args
+     */
+    const args = [
+      'publish',
+      '--access',
+      'public',
+      '--tag',
+      'canary',
+      '--registry',
+      'https://wombat-dressing-room.appspot.com'
+    ];
+
+    // Write proxy registry token for this package to .npmrc.
+    await exec(
+      `echo "//wombat-dressing-room.appspot.com/:_authToken=${
+        process.env[getEnvTokenKey(pkg)]
+      }" >> ~/.npmrc`
+    );
+
+    return spawn('npm', args, { cwd: path });
+  } catch (err) {
+    throw err;
+  }
+}
+
+async function publishToNpm(updatedPkgs: string[]) {
+  const taskArray = await Promise.all(
+    updatedPkgs.map(async pkg => {
+      const path = await mapPkgNameToPkgPath(pkg);
+
+      /**
+       * Can't require here because we have a cached version of the required JSON
+       * in memory and it doesn't contain the updates
+       */
+      const { version } = JSON.parse(
+        await readFile(`${path}/package.json`, 'utf8')
+      );
+      return {
+        title: `📦  ${pkg}@${version}`,
+        task: () => publishPackage(pkg)
+      };
+    })
+  );
+  const tasks = new Listr(taskArray, {
+    concurrent: false,
+    exitOnError: false
+  });
+
+  console.log('\r\nPublishing Packages to NPM:');
+  return tasks.run();
 }
diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
index 5a2771c6ae0..27d36840dad 100755
--- a/scripts/release/cli.ts
+++ b/scripts/release/cli.ts
@@ -15,22 +15,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import { readFile as _readFile, existsSync } from 'fs';
+import { promisify } from 'util';
+import { exec } from 'child-process-promise';
+import { createPromptModule } from 'inquirer';
+import { argv } from 'yargs';
 
 import { runCanaryRelease } from './canary';
 import { ReleaseType } from './utils/enums';
 import { publish } from './utils/publish';
 import { pushReleaseTagsToGithub, cleanTree, hasDiff } from './utils/git';
-
-import { exec } from 'child-process-promise';
-import { createPromptModule } from 'inquirer';
-const prompt = createPromptModule();
-
 import { releaseType as releaseTypePrompt } from './utils/inquirer';
 import { reinstallDeps, buildPackages } from './utils/yarn';
 import { runTests, setupTestDeps } from './utils/tests';
-import { argv } from 'yargs';
+import { projectRoot } from '../utils';
 
 const { bannerText } = require('./utils/banner');
+const prompt = createPromptModule();
+const readFile = promisify(_readFile);
 
 (async () => {
   try {
@@ -42,11 +44,11 @@ const { bannerText } = require('./utils/banner');
     /**
      * If there are unstaged changes, error
      */
-    if (await hasDiff()) {
-      throw new Error(
-        'You have unstaged changes, stash your changes before attempting to publish'
-      );
-    }
+    // if (await hasDiff()) {
+    //   throw new Error(
+    //     'You have unstaged changes, stash your changes before attempting to publish'
+    //   );
+    // }
 
     /**
      * Log the user who will be publishing the packages
@@ -80,9 +82,23 @@ const { bannerText } = require('./utils/banner');
     })();
 
     if (releaseType === ReleaseType.Canary) {
-      // await runCanaryRelease();
+      await runCanaryRelease();
     } else if (releaseType === ReleaseType.Staging) {
-      // TODO: check if changeset is in the pre mode. Throw, if not.
+      const message = `
+        It looks like you are trying to do a staging release while the repo is not in the pre mode.
+        Do you mean to make a regular release?
+        To enter the pre mode, please run \`yarn changeset pre enter next\`.
+      `;
+      // Check if changeset is in the pre mode. Throw, if not.
+      const preFilePath = `${projectRoot}/.changeset/pre.json`;
+      if (!existsSync(preFilePath)) {
+        throw new Error(message);
+      } else {
+        const preState = JSON.parse(await readFile(preFilePath, 'utf8'));
+        if (preState.mode !== 'pre') {
+          throw new Error(message);
+        }
+      }
     }
 
     /**
@@ -118,12 +134,12 @@ const { bannerText } = require('./utils/banner');
      * Release new versions to NPM using changeset
      * It will also create tags
      */
-    //  await publish();
+    await publish();
 
     /**
      * Push release tags created by changeset in publish() to Github
      */
-    //  await pushReleaseTagsToGithub();
+    await pushReleaseTagsToGithub();
   } catch (err) {
     /**
      * Log any errors that happened during the process
diff --git a/scripts/release/utils/lerna.js b/scripts/release/utils/lerna.js
deleted file mode 100644
index af7dce2f68e..00000000000
--- a/scripts/release/utils/lerna.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * @license
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const { exec } = require('child-process-promise');
-const npmRunPath = require('npm-run-path');
-const { projectRoot: root } = require('../../utils');
-
-function getLernaUpdateJson() {
-  let cache;
-
-  return (async () => {
-    try {
-      if (cache) return cache;
-
-      let { stdout: lastTag } = await exec('git describe --tags --abbrev=0');
-      lastTag = lastTag.trim();
-
-      const result = await exec(`lerna ls --since ${lastTag} --json`, {
-        env: npmRunPath.env(),
-        cwd: root
-      });
-
-      cache = JSON.parse(result.stdout).filter(pkg => !pkg.private);
-
-      return cache;
-    } catch (err) {
-      return [];
-    }
-  })();
-}
-
-exports.hasUpdatedPackages = async () => {
-  const updatedPkgs = await getLernaUpdateJson();
-  return !!updatedPkgs.length;
-};
-
-exports.getUpdatedPackages = async () => {
-  const pkgs = await getLernaUpdateJson();
-  return pkgs.map(result => result.name);
-};
diff --git a/scripts/release/utils/npm.js b/scripts/release/utils/npm.js
deleted file mode 100644
index 1749accf2f2..00000000000
--- a/scripts/release/utils/npm.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * @license
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const { projectRoot: root } = require('../../utils');
-const { spawn, exec } = require('child-process-promise');
-const { mapPkgNameToPkgPath } = require('./workspace');
-const { readFile: _readFile } = require('fs');
-const { promisify } = require('util');
-const Listr = require('listr');
-const readFile = promisify(_readFile);
-
-/**
- * Given NPM package name, get env variable name for its publish token.
- * @param {string} packageName NPM package name
- */
-function getEnvTokenKey(packageName) {
-  let result = packageName.replace('@firebase/', '');
-  result = result.replace(/-/g, '_');
-  result = result.toUpperCase();
-  return `NPM_TOKEN_${result}`;
-}
-
-async function publishPackage(pkg, releaseType) {
-  try {
-    const path = await mapPkgNameToPkgPath(pkg);
-
-    const { private } = JSON.parse(
-      await readFile(`${path}/package.json`, 'utf8')
-    );
-
-    /**
-     * Skip private packages
-     */
-    if (private) return;
-
-    /**
-     * Default publish args
-     */
-
-    let args = ['publish', '--access', 'public'];
-
-    /**
-     * Ensure prereleases are tagged with the `next` tag
-     */
-    if (releaseType === 'Staging') {
-      args = [...args, '--tag', 'next'];
-    } else if (releaseType === 'Canary') {
-      // Write proxy registry token for this package to .npmrc.
-      await exec(
-        `echo "//wombat-dressing-room.appspot.com/:_authToken=${
-          process.env[getEnvTokenKey(pkg)]
-        }" >> ~/.npmrc`
-      );
-      args = [
-        ...args,
-        '--tag',
-        'canary',
-        '--registry',
-        `https://wombat-dressing-room.appspot.com`
-      ];
-    }
-    return spawn('npm', args, { cwd: path });
-  } catch (err) {
-    throw err;
-  }
-}
-
-exports.publishToNpm = async (updatedPkgs, releaseType, renderer) => {
-  const taskArray = await Promise.all(
-    updatedPkgs.map(async pkg => {
-      const path = await mapPkgNameToPkgPath(pkg);
-
-      /**
-       * Can't require here because we have a cached version of the required JSON
-       * in memory and it doesn't contain the updates
-       */
-      const { version } = JSON.parse(
-        await readFile(`${path}/package.json`, 'utf8')
-      );
-      return {
-        title: `📦  ${pkg}@${version}`,
-        task: () => publishPackage(pkg, releaseType)
-      };
-    })
-  );
-  const tasks = new Listr(taskArray, {
-    concurrent: false,
-    exitOnError: false,
-    renderer
-  });
-
-  console.log('\r\nPublishing Packages to NPM:');
-  return tasks.run();
-};
diff --git a/scripts/release/utils/workspace.ts b/scripts/release/utils/workspace.ts
index 006ded1832b..56378f83114 100644
--- a/scripts/release/utils/workspace.ts
+++ b/scripts/release/utils/workspace.ts
@@ -19,7 +19,6 @@ import glob from 'glob';
 import { projectRoot as root } from '../../utils';
 
 import { DepGraph } from 'dependency-graph';
-import { getUpdatedPackages } from './lerna';
 import { promisify } from 'util';
 import { writeFile as _writeFile, existsSync } from 'fs';
 import clone from 'clone';
@@ -93,15 +92,6 @@ export async function getAllPackages() {
   return dependencies.overallOrder();
 }
 
-export async function getOrderedUpdates() {
-  const packages = await mapWorkspaceToPackages(workspaces);
-  const dependencies = mapPackagesToDepGraph(packages);
-  const processingOrder = dependencies.overallOrder();
-  const updated = await getUpdatedPackages();
-
-  return processingOrder.filter(pkg => updated.includes(pkg));
-}
-
 export async function mapPkgNameToPkgJson(packageName: string) {
   const packages = await mapWorkspaceToPackages(workspaces);
   return mapPackagestoPkgJson(packages)
diff --git a/scripts/utils.ts b/scripts/utils.ts
index 500a650c365..6c5b6610525 100644
--- a/scripts/utils.ts
+++ b/scripts/utils.ts
@@ -16,7 +16,7 @@
  */
 
 import { dirname, resolve } from 'path';
-import * as simpleGit from 'simple-git/promise';
+import simpleGit from 'simple-git/promise';
 import { exec } from 'child-process-promise';
 
 export const projectRoot = dirname(resolve(__dirname, '../package.json'));

From c03cbff7ec1446205e014173bcc98d9ace308269 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Fri, 19 Jun 2020 17:04:33 -0700
Subject: [PATCH 10/25] update changesets to the latest

---
 .changeset/config.json | 11 +++++-
 package.json           |  2 +-
 yarn.lock              | 89 +++++++++++++++++++++++-------------------
 3 files changed, 59 insertions(+), 43 deletions(-)

diff --git a/.changeset/config.json b/.changeset/config.json
index f71b8a100c3..bfa24913221 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -5,5 +5,14 @@
   "linked": [],
   "access": "restricted",
   "baseBranch": "master",
-  "updateInternalDependencies": "patch"
+  "updateInternalDependencies": "patch",
+  "ignore": [
+    "@firebase/app-exp",
+    "@firebase/app-types-exp",
+    "firebase-exp"
+  ],
+  "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
+    "onlyUpdatePeerDependentsWhenOutOfRange": true,
+    "useCalculatedVersionForSnapshots": true
+  }
 }
\ No newline at end of file
diff --git a/package.json b/package.json
index affaf4919f4..54107031799 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,7 @@
   ],
   "devDependencies": {
     "@changesets/changelog-github": "0.2.5",
-    "@changesets/cli": "2.6.5",
+    "@changesets/cli": "2.9.1",
     "@microsoft/api-documenter": "7.7.20",
     "@microsoft/api-extractor": "7.7.13",
     "@types/chai": "4.2.11",
diff --git a/yarn.lock b/yarn.lock
index 21470578eed..46af642ead9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -843,16 +843,16 @@
     lodash "^4.17.13"
     to-fast-properties "^2.0.0"
 
-"@changesets/apply-release-plan@^2.0.1":
-  version "2.0.2"
-  resolved "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-2.0.2.tgz#d411e7384c764c9500b41ce7e77ebd42a92a8e14"
-  integrity sha512-CmGiGa4sMRyztkPoxUy/EBzdXZrkLpTIzUpS5SXyzdU0jWxSSA+oB9/o1IQ4hwKMM2g8DGbOMAg9NwavK86nPQ==
+"@changesets/apply-release-plan@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-4.0.0.tgz#e78efb56a4e459a8dab814ba43045f2ace0f27c9"
+  integrity sha512-MrcUd8wIlQ4S/PznzqJVsmnEpUGfPEkCGF54iqt8G05GEqi/zuxpoTfebcScpj5zeiDyxFIcA9RbeZ3pvJJxoA==
   dependencies:
     "@babel/runtime" "^7.4.4"
-    "@changesets/config" "^1.0.3"
+    "@changesets/config" "^1.2.0"
     "@changesets/get-version-range-type" "^0.3.2"
-    "@changesets/git" "^1.0.3"
-    "@changesets/types" "^2.0.1"
+    "@changesets/git" "^1.0.5"
+    "@changesets/types" "^3.1.0"
     "@manypkg/get-packages" "^1.0.1"
     fs-extra "^7.0.1"
     lodash.startcase "^4.4.0"
@@ -861,15 +861,15 @@
     resolve-from "^5.0.0"
     semver "^5.4.1"
 
-"@changesets/assemble-release-plan@^2.0.2", "@changesets/assemble-release-plan@^2.0.4":
-  version "2.0.4"
-  resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-2.0.4.tgz#4c138fa306340f851c04e70434dd0a8e2e62a8ad"
-  integrity sha512-v7Z6/7PliGZY62Pod5GzBW4bJ5nBNTMRuCNMIQ/n3BUZkEH6wQrCI/jzEs0tGp8s88HITpdDF3ZMHIBfGsH3eQ==
+"@changesets/assemble-release-plan@^3.0.0":
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-3.0.0.tgz#23c280b0ea352003302b0c262b8dadb8bda517ed"
+  integrity sha512-TvcqUhNhKoqwE+L8dFtcwwAmos4+fqwmSkOWP3TSjw7K/inz2wjC46bA7IFtbx2hrwEq1iG0RCweQZTS2vrx1w==
   dependencies:
     "@babel/runtime" "^7.4.4"
     "@changesets/errors" "^0.1.4"
     "@changesets/get-dependents-graph" "^1.1.3"
-    "@changesets/types" "^3.0.0"
+    "@changesets/types" "^3.1.0"
     "@manypkg/get-packages" "^1.0.1"
     semver "^5.4.1"
 
@@ -882,23 +882,24 @@
     "@changesets/types" "^2.0.1"
     dotenv "^8.1.0"
 
-"@changesets/cli@2.6.5":
-  version "2.6.5"
-  resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.6.5.tgz#1da87511306c997735e76a1e216b504730d2ac96"
-  integrity sha512-vy6FET6o0Y29uGxnYfOjj6Sclx6FYDLtmfI2aL3s6JV+FAQSZVfecENtJtFiwvBO6VL5h3hVP5SensjFVXiDRA==
+"@changesets/cli@2.9.1":
+  version "2.9.1"
+  resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.9.1.tgz#d678066cffac63df8fca04798c2b358b6eb5ea35"
+  integrity sha512-xWJP0duGF72Rb/0KB99TQrdBz4VnbCxqj9/B4hPT8VFYGt/2gAeS5Y3NQLpjCv+/hNxfHjDI+svzZy6q796t6A==
   dependencies:
     "@babel/runtime" "^7.4.4"
-    "@changesets/apply-release-plan" "^2.0.1"
-    "@changesets/assemble-release-plan" "^2.0.2"
-    "@changesets/config" "^1.0.3"
+    "@changesets/apply-release-plan" "^4.0.0"
+    "@changesets/assemble-release-plan" "^3.0.0"
+    "@changesets/config" "^1.3.0"
     "@changesets/errors" "^0.1.4"
-    "@changesets/get-release-plan" "^1.0.3"
-    "@changesets/git" "^1.0.3"
+    "@changesets/get-dependents-graph" "^1.1.3"
+    "@changesets/get-release-plan" "^2.0.0"
+    "@changesets/git" "^1.0.5"
     "@changesets/logger" "^0.0.5"
-    "@changesets/pre" "^1.0.3"
-    "@changesets/read" "^0.4.5"
-    "@changesets/types" "^2.0.1"
-    "@changesets/write" "^0.1.2"
+    "@changesets/pre" "^1.0.4"
+    "@changesets/read" "^0.4.6"
+    "@changesets/types" "^3.1.0"
+    "@changesets/write" "^0.1.3"
     "@manypkg/get-packages" "^1.0.1"
     "@types/semver" "^6.0.0"
     boxen "^1.3.0"
@@ -916,14 +917,15 @@
     term-size "^2.1.0"
     tty-table "^2.7.0"
 
-"@changesets/config@^1.0.3", "@changesets/config@^1.1.0":
-  version "1.1.0"
-  resolved "https://registry.npmjs.org/@changesets/config/-/config-1.1.0.tgz#35d96d12b27df905cc6d706eecf1cc378bf6cffe"
-  integrity sha512-KXZ67QLRd/kMv+CK45r2Edl4O6oOMxKI7B0Sf4qVmwwoonGM5oxHNyNAxeGL31YhE+6z4hIh57+rD7PppF+KFw==
+"@changesets/config@^1.2.0", "@changesets/config@^1.3.0":
+  version "1.3.0"
+  resolved "https://registry.npmjs.org/@changesets/config/-/config-1.3.0.tgz#82fcbf572b00ba16636be9ea45167983f1fc203b"
+  integrity sha512-IeAHmN5kI7OywBUNJXsk/v4vcXDDscwgTe/K5D3FSng5QTvzbgiMAe5K1iwBxBvuT4u/33n89kxSJdg4TTTFfA==
   dependencies:
     "@changesets/errors" "^0.1.4"
+    "@changesets/get-dependents-graph" "^1.1.3"
     "@changesets/logger" "^0.0.5"
-    "@changesets/types" "^3.0.0"
+    "@changesets/types" "^3.1.0"
     "@manypkg/get-packages" "^1.0.1"
     fs-extra "^7.0.1"
 
@@ -953,17 +955,17 @@
     dataloader "^1.4.0"
     node-fetch "^2.5.0"
 
-"@changesets/get-release-plan@^1.0.3":
-  version "1.0.4"
-  resolved "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-1.0.4.tgz#9c0b830d8ef4aa0988379e7405d2d2ece29d604e"
-  integrity sha512-yxym5rS0seFaAtGI+arUdm3dCz7trb/lvsqsfNpH1Yf0cN90QKMEZSOmWKo8ZEMuifnnl8AFqnH9wRS2+bWVCg==
+"@changesets/get-release-plan@^2.0.0":
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-2.0.0.tgz#570dbd0abcdd4169a73e8332ec139a01130f3b72"
+  integrity sha512-MHbgXMhkfWhXH1zUefrdtQ8IR+H46lAcKthKjptV28k0qGEcDk7KriYLukJ6BNkWiZkkZ/aycaivbNDclF9zaw==
   dependencies:
     "@babel/runtime" "^7.4.4"
-    "@changesets/assemble-release-plan" "^2.0.4"
-    "@changesets/config" "^1.1.0"
+    "@changesets/assemble-release-plan" "^3.0.0"
+    "@changesets/config" "^1.2.0"
     "@changesets/pre" "^1.0.4"
     "@changesets/read" "^0.4.6"
-    "@changesets/types" "^3.0.0"
+    "@changesets/types" "^3.1.0"
     "@manypkg/get-packages" "^1.0.1"
 
 "@changesets/get-version-range-type@^0.3.2":
@@ -971,7 +973,7 @@
   resolved "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz#8131a99035edd11aa7a44c341cbb05e668618c67"
   integrity sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==
 
-"@changesets/git@^1.0.3", "@changesets/git@^1.0.5":
+"@changesets/git@^1.0.5":
   version "1.0.5"
   resolved "https://registry.npmjs.org/@changesets/git/-/git-1.0.5.tgz#e392128a13b210c482324d0d329029a3f7613b10"
   integrity sha512-MgacjTRCrfFCffvoipqbtHSENydaO+HDR6z+gDQ49Gl2kHIat0iIazL1TBfEuW8H4eGCay+Naz/x6412ucUOTw==
@@ -998,7 +1000,7 @@
     "@changesets/types" "^3.0.0"
     js-yaml "^3.13.1"
 
-"@changesets/pre@^1.0.3", "@changesets/pre@^1.0.4":
+"@changesets/pre@^1.0.4":
   version "1.0.4"
   resolved "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.4.tgz#32aa9040f3798e8a46adc6c30cc4c02a617d1889"
   integrity sha512-PGD3uSCZIs6Fd+HsPziLh0BjJ2ypyTEFZSY8qkwINvAvWYpDK805svV0x9usp54kn6PWI9RZ4tVD2A41dqJ0jw==
@@ -1009,7 +1011,7 @@
     "@manypkg/get-packages" "^1.0.1"
     fs-extra "^7.0.1"
 
-"@changesets/read@^0.4.5", "@changesets/read@^0.4.6":
+"@changesets/read@^0.4.6":
   version "0.4.6"
   resolved "https://registry.npmjs.org/@changesets/read/-/read-0.4.6.tgz#1c03e709a870a070fc95490ffa696297d23458f7"
   integrity sha512-rOd8dsF/Lgyy2SYlDalb3Ts/meDI2AcKPXYhSXIW3k6+ZLlj6Pt+nmgV5Ut8euyH7loibklNTDemfvMffF4xig==
@@ -1033,7 +1035,12 @@
   resolved "https://registry.npmjs.org/@changesets/types/-/types-3.0.0.tgz#3804662aa455c1622282ec3253cf6ddd309eee65"
   integrity sha512-9Mh/JqkX3nkjfu53ESM3UjFmR2meOo4Zw+Tp4vnon0XYtMurk7KjZG5L+J0fD3+Qx0A2FFTZrgydPwiHR4GrXQ==
 
-"@changesets/write@^0.1.2":
+"@changesets/types@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.npmjs.org/@changesets/types/-/types-3.1.0.tgz#68957af45a0be29f0908e20a990ecf382282e1f1"
+  integrity sha512-czOfaaxr5aGnNwVRgWr3n2CKoc3iRTfrHM4wUHQ+rBlLKKk9NzGwZ2EPsXkp4CUw4hWHGEOi8hdeIfDTWKrWgg==
+
+"@changesets/write@^0.1.3":
   version "0.1.3"
   resolved "https://registry.npmjs.org/@changesets/write/-/write-0.1.3.tgz#00ae575af50274773d7493e77fb96838a08ad8ad"
   integrity sha512-q79rbwlVmTNKP9O6XxcMDj81CEOn/kQHbTFdRleW0tFUv98S1EyEAE9vLPPzO6WnQipHnaozxB1zMhHy0aQn8Q==

From ecaa9db80554fb64550034ac99f361c328dd5094 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Fri, 19 Jun 2020 17:26:37 -0700
Subject: [PATCH 11/25] ignore integration test projects

---
 .changeset/config.json | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/.changeset/config.json b/.changeset/config.json
index bfa24913221..d08abcb5b41 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -7,6 +7,12 @@
   "baseBranch": "master",
   "updateInternalDependencies": "patch",
   "ignore": [
+    "firebase-browserify-test",
+    "firebase-package-typings-test",
+    "firebase-firestore-integration-test",
+    "firebase-messaging-selenium-test",
+    "firebase-typescript-test",
+    "firebase-webpack-test",
     "@firebase/app-exp",
     "@firebase/app-types-exp",
     "firebase-exp"

From d873223fb9b9ce397e9f86def7aba3696a842be5 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 11:44:28 -0700
Subject: [PATCH 12/25] save updates

---
 package.json               |  1 +
 scripts/release/canary.ts  |  8 +++-
 scripts/release/cli.ts     | 96 ++++++++++++++++++--------------------
 scripts/release/staging.ts | 25 ++++++++++
 4 files changed, 79 insertions(+), 51 deletions(-)
 create mode 100644 scripts/release/staging.ts

diff --git a/package.json b/package.json
index f1838d6e5d0..b293bcaff3a 100644
--- a/package.json
+++ b/package.json
@@ -75,6 +75,7 @@
     "@types/sinon-chai": "3.2.4",
     "@types/tmp": "0.2.0",
     "@types/yargs": "15.0.4",
+    "@types/listr": "0.14.2",
     "@typescript-eslint/eslint-plugin": "2.30.0",
     "@typescript-eslint/eslint-plugin-tslint": "2.30.0",
     "@typescript-eslint/parser": "2.30.0",
diff --git a/scripts/release/canary.ts b/scripts/release/canary.ts
index 457701e1f89..764d38201b6 100644
--- a/scripts/release/canary.ts
+++ b/scripts/release/canary.ts
@@ -26,6 +26,7 @@ import Listr from 'listr';
 import { readFile as _readFile } from 'fs';
 import { promisify } from 'util';
 import { exec, spawn } from 'child-process-promise';
+import { buildPackages } from './utils/yarn';
 
 const readFile = promisify(_readFile);
 
@@ -45,7 +46,7 @@ export async function runCanaryRelease(): Promise<void> {
    *
    * A user would be able to install a package canary as follows:
    *
-   * $ npm install @firebase/app@0.0.0-canary.0000000
+   * $ npm install @firebase/app@canary
    */
   const sha = await getCurrentSha();
   const updates = await getAllPackages();
@@ -66,6 +67,11 @@ export async function runCanaryRelease(): Promise<void> {
    */
   await updateWorkspaceVersions(versions, true);
 
+  /**
+   * build packages
+   */
+  await buildPackages();
+
   await publishToNpm(updates);
 }
 
diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
index 27d36840dad..ed659e82c53 100755
--- a/scripts/release/cli.ts
+++ b/scripts/release/cli.ts
@@ -28,7 +28,7 @@ import { pushReleaseTagsToGithub, cleanTree, hasDiff } from './utils/git';
 import { releaseType as releaseTypePrompt } from './utils/inquirer';
 import { reinstallDeps, buildPackages } from './utils/yarn';
 import { runTests, setupTestDeps } from './utils/tests';
-import { projectRoot } from '../utils';
+import { bumpVersionForStaging } from './staging';
 
 const { bannerText } = require('./utils/banner');
 const prompt = createPromptModule();
@@ -83,63 +83,59 @@ const readFile = promisify(_readFile);
 
     if (releaseType === ReleaseType.Canary) {
       await runCanaryRelease();
-    } else if (releaseType === ReleaseType.Staging) {
-      const message = `
-        It looks like you are trying to do a staging release while the repo is not in the pre mode.
-        Do you mean to make a regular release?
-        To enter the pre mode, please run \`yarn changeset pre enter next\`.
-      `;
-      // Check if changeset is in the pre mode. Throw, if not.
-      const preFilePath = `${projectRoot}/.changeset/pre.json`;
-      if (!existsSync(preFilePath)) {
-        throw new Error(message);
-      } else {
-        const preState = JSON.parse(await readFile(preFilePath, 'utf8'));
-        if (preState.mode !== 'pre') {
-          throw new Error(message);
-        }
-      }
-    }
+    } else {
+      // Staging or Prod release
 
-    /**
-     * Users can pass --skipReinstall to skip the installation step
-     */
-    if (!argv.skipReinstall) {
       /**
-       * Clean install dependencies
+       * Bump versions for staging release
+       * NOTE: For prod, versions are bumped in a PR which should be merged before running this script
        */
-      console.log('\r\nVerifying Build');
-      await cleanTree();
-      await reinstallDeps();
-    }
+      if (releaseType === ReleaseType.Staging) {
+        await bumpVersionForStaging();
+      }
 
-    /**
-     * build packages
-     */
-    await buildPackages();
+      /**
+       * Users can pass --skipReinstall to skip the installation step
+       */
+      if (!argv.skipReinstall) {
+        /**
+         * Clean install dependencies
+         */
+        console.log('\r\nVerifying Build');
+        await cleanTree();
+        await reinstallDeps();
+      }
 
-    /**
-     * Ensure all tests are passing
-     */
+      /**
+       * build packages
+       */
+      await buildPackages();
 
-    /**
-     * Users can pass --skipTests to skip the testing step
-     */
-    if (!argv.skipTests) {
-      await setupTestDeps();
-      await runTests();
-    }
+      /**
+       * Users can pass --skipTests to skip the testing step
+       */
+      if (!argv.skipTests) {
+        await setupTestDeps();
+        await runTests();
+      }
 
-    /**
-     * Release new versions to NPM using changeset
-     * It will also create tags
-     */
-    await publish();
+      /**
+       * Release new versions to NPM using changeset
+       * It will also create tags
+       */
+      await publish();
 
-    /**
-     * Push release tags created by changeset in publish() to Github
-     */
-    await pushReleaseTagsToGithub();
+      /**
+       * Changeset creats tags for staging releases as well,
+       * but we should only push tags to Github for prod releases
+       */
+      if (releaseType === ReleaseType.Production) {
+        /**
+         * Push release tags created by changeset in publish() to Github
+         */
+        await pushReleaseTagsToGithub();
+      }
+    }
   } catch (err) {
     /**
      * Log any errors that happened during the process
diff --git a/scripts/release/staging.ts b/scripts/release/staging.ts
new file mode 100644
index 00000000000..ea5d04282c5
--- /dev/null
+++ b/scripts/release/staging.ts
@@ -0,0 +1,25 @@
+/**
+ * @license
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { spawn } from 'child-process-promise';
+import { projectRoot as root } from '../utils';
+
+export async function bumpVersionForStaging() {
+  await spawn('yarn', ['changeset', 'version', '--snapshot'], {
+    cwd: root
+  });
+}

From 4221ffaf65296d43bf530b1263d715bb03f8b06e Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 11:59:28 -0700
Subject: [PATCH 13/25] update ignore list

---
 .changeset/config.json          |  2 ++
 packages/firestore/package.json |  2 --
 yarn.lock                       | 17 +++++++++--------
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/.changeset/config.json b/.changeset/config.json
index d08abcb5b41..b4ed23bd849 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -15,6 +15,8 @@
     "firebase-webpack-test",
     "@firebase/app-exp",
     "@firebase/app-types-exp",
+    "@firebase/functions-exp",
+    "@firebase/functions-types-exp",
     "firebase-exp"
   ],
   "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
diff --git a/packages/firestore/package.json b/packages/firestore/package.json
index 07cdcfe2ab9..8165709d3ee 100644
--- a/packages/firestore/package.json
+++ b/packages/firestore/package.json
@@ -67,8 +67,6 @@
     "@firebase/app-types": "0.x"
   },
   "devDependencies": {
-    "@firebase/app-exp": "0.x",
-    "@firebase/app-types-exp": "0.x",
     "@rollup/plugin-alias": "3.1.1",
     "@types/json-stable-stringify": "1.0.32",
     "json-stable-stringify": "1.0.1",
diff --git a/yarn.lock b/yarn.lock
index d7fe1db7aa3..c515cc2c038 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1211,13 +1211,6 @@
   dependencies:
     semver "^6.2.0"
 
-"@grpc/grpc-js@^1.0.0":
-  version "1.0.5"
-  resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.0.5.tgz#09948c0810e62828fdd61455b2eb13d7879888b0"
-  integrity sha512-Hm+xOiqAhcpT9RYM8lc15dbQD7aQurM7ZU8ulmulepiPlN7iwBXXwP3vSBUimoFoApRqz7pSIisXU8pZaCB4og==
-  dependencies:
-    semver "^6.2.0"
-
 "@grpc/proto-loader@^0.5.0", "@grpc/proto-loader@^0.5.1":
   version "0.5.4"
   resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.4.tgz#038a3820540f621eeb1b05d81fbedfb045e14de0"
@@ -2431,6 +2424,14 @@
   resolved "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz#121f6917c4389db3923640b2e68de5fa64dda88e"
   integrity sha512-q9Q6+eUEGwQkv4Sbst3J4PNgDOvpuVuKj79Hl/qnmBMEIPzB5QoFRUtjcgcg2xNUZyYUGXBk5wYIBKHt0A+Mxw==
 
+"@types/listr@0.14.2":
+  version "0.14.2"
+  resolved "https://registry.npmjs.org/@types/listr/-/listr-0.14.2.tgz#2e5f80fbc3ca8dceb9940ce9bf8e3113ab452545"
+  integrity sha512-wCipMbQr3t2UHTm90LldVp+oTBj1TX6zvpkCJcWS4o8nn6kS8SN93oUvKJAgueIRZ5M36yOlFmScqBxYH8Ajig==
+  dependencies:
+    "@types/node" "*"
+    rxjs "^6.5.1"
+
 "@types/long@4.0.1", "@types/long@^4.0.0", "@types/long@^4.0.1":
   version "4.0.1"
   resolved "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
@@ -13186,7 +13187,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
   dependencies:
     aproba "^1.1.1"
 
-rxjs@6.5.5, rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.5.3:
+rxjs@6.5.5, rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.5.1, rxjs@^6.5.3:
   version "6.5.5"
   resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec"
   integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==

From e613277866c0d6c979dca4b89b416a007e3b6c92 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 15:01:00 -0700
Subject: [PATCH 14/25] stream changeset output

---
 scripts/release/cli.ts           | 5 +----
 scripts/release/staging.ts       | 3 ++-
 scripts/release/utils/publish.ts | 3 ++-
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
index ed659e82c53..987e6a21932 100755
--- a/scripts/release/cli.ts
+++ b/scripts/release/cli.ts
@@ -15,8 +15,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { readFile as _readFile, existsSync } from 'fs';
-import { promisify } from 'util';
 import { exec } from 'child-process-promise';
 import { createPromptModule } from 'inquirer';
 import { argv } from 'yargs';
@@ -24,7 +22,7 @@ import { argv } from 'yargs';
 import { runCanaryRelease } from './canary';
 import { ReleaseType } from './utils/enums';
 import { publish } from './utils/publish';
-import { pushReleaseTagsToGithub, cleanTree, hasDiff } from './utils/git';
+import { pushReleaseTagsToGithub, cleanTree } from './utils/git';
 import { releaseType as releaseTypePrompt } from './utils/inquirer';
 import { reinstallDeps, buildPackages } from './utils/yarn';
 import { runTests, setupTestDeps } from './utils/tests';
@@ -32,7 +30,6 @@ import { bumpVersionForStaging } from './staging';
 
 const { bannerText } = require('./utils/banner');
 const prompt = createPromptModule();
-const readFile = promisify(_readFile);
 
 (async () => {
   try {
diff --git a/scripts/release/staging.ts b/scripts/release/staging.ts
index ea5d04282c5..acdfd187ec0 100644
--- a/scripts/release/staging.ts
+++ b/scripts/release/staging.ts
@@ -20,6 +20,7 @@ import { projectRoot as root } from '../utils';
 
 export async function bumpVersionForStaging() {
   await spawn('yarn', ['changeset', 'version', '--snapshot'], {
-    cwd: root
+    cwd: root,
+    stdio: 'inherit'
   });
 }
diff --git a/scripts/release/utils/publish.ts b/scripts/release/utils/publish.ts
index 4f1e46c90f7..d71d43719c2 100644
--- a/scripts/release/utils/publish.ts
+++ b/scripts/release/utils/publish.ts
@@ -20,6 +20,7 @@ import { projectRoot as root } from '../../utils';
 
 export async function publish() {
   await spawn('yarn', ['changeset', 'publish'], {
-    cwd: root
+    cwd: root,
+    stdio: 'inherit'
   });
 }

From 3164a1c3670f6ccfa6700437003b530e75daa907 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 16:33:03 -0700
Subject: [PATCH 15/25] validate version for staging releases

---
 scripts/release/cli.ts             | 17 +++++++++++++++--
 scripts/release/staging.ts         | 30 +++++++++++++++++++++++++++++-
 scripts/release/utils/inquirer.ts  | 15 +++++++++++++++
 scripts/release/utils/workspace.ts |  4 ++--
 4 files changed, 61 insertions(+), 5 deletions(-)

diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
index 987e6a21932..216707a4db3 100755
--- a/scripts/release/cli.ts
+++ b/scripts/release/cli.ts
@@ -23,7 +23,10 @@ import { runCanaryRelease } from './canary';
 import { ReleaseType } from './utils/enums';
 import { publish } from './utils/publish';
 import { pushReleaseTagsToGithub, cleanTree } from './utils/git';
-import { releaseType as releaseTypePrompt } from './utils/inquirer';
+import {
+  releaseType as releaseTypePrompt,
+  validateVersions
+} from './utils/inquirer';
 import { reinstallDeps, buildPackages } from './utils/yarn';
 import { runTests, setupTestDeps } from './utils/tests';
 import { bumpVersionForStaging } from './staging';
@@ -88,7 +91,17 @@ const prompt = createPromptModule();
        * NOTE: For prod, versions are bumped in a PR which should be merged before running this script
        */
       if (releaseType === ReleaseType.Staging) {
-        await bumpVersionForStaging();
+        const updatedPackages = await bumpVersionForStaging();
+
+        // We don't need to validate versions for prod releases because prod releases
+        // are validated in the version bump PR which should be merged before running this script
+        const { versionCheck } = await prompt([
+          validateVersions(updatedPackages)
+        ]);
+
+        if (!versionCheck) {
+          throw new Error('Version check failed');
+        }
       }
 
       /**
diff --git a/scripts/release/staging.ts b/scripts/release/staging.ts
index acdfd187ec0..8dee3abbebf 100644
--- a/scripts/release/staging.ts
+++ b/scripts/release/staging.ts
@@ -17,10 +17,38 @@
 
 import { spawn } from 'child-process-promise';
 import { projectRoot as root } from '../utils';
+import { getAllPackages, mapPkgNameToPkgJson } from './utils/workspace';
+
+export async function bumpVersionForStaging(): Promise<
+  Map<string, [string, string]>
+> {
+  const packages = await getAllPackages();
+  const originalVersions = new Map<string, string>();
+
+  const pkgJsons = await Promise.all(
+    packages.map(pkg => mapPkgNameToPkgJson(pkg))
+  );
+  for (const { name, version } of pkgJsons) {
+    originalVersions.set(name, version);
+  }
 
-export async function bumpVersionForStaging() {
   await spawn('yarn', ['changeset', 'version', '--snapshot'], {
     cwd: root,
     stdio: 'inherit'
   });
+
+  const updatedPkgJsons: {
+    name: string;
+    updatedVersion: string;
+  }[] = await Promise.all(packages.map(pkg => mapPkgNameToPkgJson(pkg)));
+  const updatedVersions = new Map<string, [string, string]>();
+
+  for (const { name, updatedVersion } of updatedPkgJsons) {
+    const originalVersion = originalVersions.get(name)!;
+    if (originalVersion !== updatedVersion) {
+      updatedVersions.set(name, [originalVersion, updatedVersion]);
+    }
+  }
+
+  return updatedVersions;
 }
diff --git a/scripts/release/utils/inquirer.ts b/scripts/release/utils/inquirer.ts
index 03f0cf353a3..360501ba9f6 100644
--- a/scripts/release/utils/inquirer.ts
+++ b/scripts/release/utils/inquirer.ts
@@ -24,3 +24,18 @@ export const releaseType = {
   choices: [ReleaseType.Staging, ReleaseType.Production],
   default: ReleaseType.Staging
 };
+
+export function validateVersions(versionMap: Map<string, [string, string]>) {
+  let message =
+    '\r\nAre you sure these are the versions you want to publish?\r\n';
+  for (const [pkgName, [originalVersion, updatedVersion]] of versionMap) {
+    message += `${pkgName} ${originalVersion} -> ${updatedVersion}\n`;
+  }
+
+  return {
+    type: 'confirm',
+    name: 'versionCheck',
+    message,
+    default: false
+  };
+}
diff --git a/scripts/release/utils/workspace.ts b/scripts/release/utils/workspace.ts
index 56378f83114..357b320d894 100644
--- a/scripts/release/utils/workspace.ts
+++ b/scripts/release/utils/workspace.ts
@@ -20,7 +20,7 @@ import { projectRoot as root } from '../../utils';
 
 import { DepGraph } from 'dependency-graph';
 import { promisify } from 'util';
-import { writeFile as _writeFile, existsSync } from 'fs';
+import { writeFile as _writeFile, existsSync, readFileSync } from 'fs';
 import clone from 'clone';
 
 const writeFile = promisify(_writeFile);
@@ -50,7 +50,7 @@ function mapPackagestoPkgJson(packagePaths: string[]) {
   return packagePaths
     .map(path => {
       try {
-        return require(`${path}/package.json`);
+        return JSON.parse(readFileSync(`${path}/package.json`, 'utf8'));
       } catch (err) {
         return null;
       }

From 3ab3d599624b8b8cd50e25b5350f0e3859063cfe Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 16:56:05 -0700
Subject: [PATCH 16/25] fix bug

---
 scripts/release/staging.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/scripts/release/staging.ts b/scripts/release/staging.ts
index 8dee3abbebf..7a45a5df840 100644
--- a/scripts/release/staging.ts
+++ b/scripts/release/staging.ts
@@ -39,13 +39,13 @@ export async function bumpVersionForStaging(): Promise<
 
   const updatedPkgJsons: {
     name: string;
-    updatedVersion: string;
+    version: string;
   }[] = await Promise.all(packages.map(pkg => mapPkgNameToPkgJson(pkg)));
   const updatedVersions = new Map<string, [string, string]>();
 
-  for (const { name, updatedVersion } of updatedPkgJsons) {
+  for (const { name, version: updatedVersion } of updatedPkgJsons) {
     const originalVersion = originalVersions.get(name)!;
-    if (originalVersion !== updatedVersion) {
+    if (updatedVersion && originalVersion !== updatedVersion) {
       updatedVersions.set(name, [originalVersion, updatedVersion]);
     }
   }

From 23e8e6275db93a6713b39620018a1679216bbeba Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 16:56:56 -0700
Subject: [PATCH 17/25] add option

---
 scripts/tsconfig.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json
index 2e504fb1601..826691796fc 100644
--- a/scripts/tsconfig.json
+++ b/scripts/tsconfig.json
@@ -12,6 +12,7 @@
     "typeRoots": [
       "../node_modules/@types"
     ],
-    "allowJs": true
+    "allowJs": true,
+    "downlevelIteration": true
   }
 }
\ No newline at end of file

From 1ded802d4a3c0cb2b6c39a7c5635839700f17e67 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 17:01:10 -0700
Subject: [PATCH 18/25] skip private packages

---
 scripts/release/staging.ts | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/scripts/release/staging.ts b/scripts/release/staging.ts
index 7a45a5df840..66c94bcaef5 100644
--- a/scripts/release/staging.ts
+++ b/scripts/release/staging.ts
@@ -40,10 +40,19 @@ export async function bumpVersionForStaging(): Promise<
   const updatedPkgJsons: {
     name: string;
     version: string;
+    private: boolean;
   }[] = await Promise.all(packages.map(pkg => mapPkgNameToPkgJson(pkg)));
   const updatedVersions = new Map<string, [string, string]>();
 
-  for (const { name, version: updatedVersion } of updatedPkgJsons) {
+  for (const {
+    name,
+    version: updatedVersion,
+    private: isPrivate
+  } of updatedPkgJsons) {
+    if (isPrivate) {
+      continue;
+    }
+
     const originalVersion = originalVersions.get(name)!;
     if (updatedVersion && originalVersion !== updatedVersion) {
       updatedVersions.set(name, [originalVersion, updatedVersion]);

From 059d5c20d0d8c779c81d4c1bfcc73e8500e11e4f Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 17:37:31 -0700
Subject: [PATCH 19/25] remove unused things

---
 scripts/release/cli.ts       | 12 +++++-----
 scripts/release/utils/git.ts | 46 ++++--------------------------------
 2 files changed, 10 insertions(+), 48 deletions(-)

diff --git a/scripts/release/cli.ts b/scripts/release/cli.ts
index 216707a4db3..6510c6695c2 100755
--- a/scripts/release/cli.ts
+++ b/scripts/release/cli.ts
@@ -22,7 +22,7 @@ import { argv } from 'yargs';
 import { runCanaryRelease } from './canary';
 import { ReleaseType } from './utils/enums';
 import { publish } from './utils/publish';
-import { pushReleaseTagsToGithub, cleanTree } from './utils/git';
+import { pushReleaseTagsToGithub, cleanTree, hasDiff } from './utils/git';
 import {
   releaseType as releaseTypePrompt,
   validateVersions
@@ -44,11 +44,11 @@ const prompt = createPromptModule();
     /**
      * If there are unstaged changes, error
      */
-    // if (await hasDiff()) {
-    //   throw new Error(
-    //     'You have unstaged changes, stash your changes before attempting to publish'
-    //   );
-    // }
+    if (await hasDiff()) {
+      throw new Error(
+        'You have unstaged changes, stash your changes before attempting to publish'
+      );
+    }
 
     /**
      * Log the user who will be publishing the packages
diff --git a/scripts/release/utils/git.ts b/scripts/release/utils/git.ts
index 4183e0978e4..1229f56fd26 100644
--- a/scripts/release/utils/git.ts
+++ b/scripts/release/utils/git.ts
@@ -15,11 +15,11 @@
  * limitations under the License.
  */
 
-const simpleGit = require('simple-git/promise');
-const { projectRoot: root } = require('../../utils');
+import simpleGit from 'simple-git/promise';
+import { projectRoot as root } from '../../utils';
+import { exec } from 'child-process-promise';
+import ora from 'ora';
 const git = simpleGit(root);
-const { exec } = require('child-process-promise');
-const ora = require('ora');
 
 export async function cleanTree() {
   const spinner = ora(' Cleaning git tree').start();
@@ -31,44 +31,6 @@ export async function cleanTree() {
   });
 }
 
-/**
- * Commits the current state of the repository and tags it with the appropriate
- * version changes.
- *
- * Returns the tagged commits
- */
-export async function commitAndTag(updatedVersions: {
-  [packageName: string]: string;
-}) {
-  await exec('git add */package.json yarn.lock');
-
-  let result = await exec(
-    `git commit -m "Publish firebase@${updatedVersions.firebase}"`
-  );
-
-  const tags: string[] = [];
-  await Promise.all(
-    Object.keys(updatedVersions)
-      .map(name => ({ name, version: updatedVersions[name] }))
-      .map(async ({ name, version }) => {
-        const tag = `${name}@${version}`;
-        const result = await exec(`git tag ${tag}`);
-        tags.push(tag);
-      })
-  );
-  return tags;
-}
-
-export async function pushUpdatesToGithub(tags: string[]) {
-  let { stdout: currentBranch, stderr } = await exec(
-    `git rev-parse --abbrev-ref HEAD`
-  );
-  currentBranch = currentBranch.trim();
-
-  await exec(`git push origin ${currentBranch} --no-verify -u`, { cwd: root });
-  await exec(`git push origin ${tags.join(' ')} --no-verify`, { cwd: root });
-}
-
 export async function resetWorkingTree() {
   await git.checkout('.');
 }

From 72c53f7275dff872f210c86a22013db9055f0e9f Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Tue, 23 Jun 2020 17:43:24 -0700
Subject: [PATCH 20/25] update release script

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index b293bcaff3a..9f5431ef17e 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
     "link:packages": "lerna exec --scope @firebase/* --scope firebase --scope rxfire -- yarn link",
     "stage:packages": "./scripts/prepublish.sh",
     "repl": "node tools/repl.js",
-    "release": "node scripts/release/cli.js",
+    "release": "ts-node-script scripts/release/cli.ts",
     "pretest": "node tools/pretest.js",
     "test": "lerna run --concurrency 4 --stream test",
     "test:ci": "lerna run --concurrency 4 --stream test:ci",

From b167bba07109b6b96f66727d12527760d5bee234 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 24 Jun 2020 16:37:26 -0700
Subject: [PATCH 21/25] fix type errors

---
 scripts/emulator-testing/database-test-runner.ts |  5 ++---
 scripts/emulator-testing/emulators/emulator.ts   | 15 ++++++++++-----
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/scripts/emulator-testing/database-test-runner.ts b/scripts/emulator-testing/database-test-runner.ts
index 58e2168f844..ac6675924d1 100644
--- a/scripts/emulator-testing/database-test-runner.ts
+++ b/scripts/emulator-testing/database-test-runner.ts
@@ -19,16 +19,15 @@ import { spawn } from 'child-process-promise';
 import * as path from 'path';
 
 import { DatabaseEmulator } from './emulators/database-emulator';
-import { ChildProcessPromise } from './emulators/emulator';
 
-function runTest(port: number, namespace: string): ChildProcessPromise {
+function runTest(port: number, namespace: string) {
   const options = {
     cwd: path.resolve(__dirname, '../../packages/database'),
     env: Object.assign({}, process.env, {
       RTDB_EMULATOR_PORT: port,
       RTDB_EMULATOR_NAMESPACE: namespace
     }),
-    stdio: 'inherit'
+    stdio: 'inherit' as const
   };
   return spawn('yarn', ['test:all'], options);
 }
diff --git a/scripts/emulator-testing/emulators/emulator.ts b/scripts/emulator-testing/emulators/emulator.ts
index b57b266fba3..e7abee703eb 100644
--- a/scripts/emulator-testing/emulators/emulator.ts
+++ b/scripts/emulator-testing/emulators/emulator.ts
@@ -24,9 +24,9 @@ import * as request from 'request';
 // @ts-ignore
 import * as tmp from 'tmp';
 
-export interface ChildProcessPromise extends Promise<void> {
-  childProcess: ChildProcess;
-}
+// export interface ChildProcessPromise extends Promise<void> {
+//   childProcess: ChildProcess;
+// }
 
 export abstract class Emulator {
   binaryPath: string | null = null;
@@ -72,9 +72,14 @@ export abstract class Emulator {
       if (!this.binaryPath) {
         throw new Error('You must call download() before setUp()');
       }
-      const promise: ChildProcessPromise = spawn(
+      const promise = spawn(
         'java',
-        ['-jar', path.basename(this.binaryPath), '--port', this.port],
+        [
+          '-jar',
+          path.basename(this.binaryPath),
+          '--port',
+          this.port.toString()
+        ],
         {
           cwd: path.dirname(this.binaryPath),
           stdio: 'inherit'

From 74cb4c44d09da4713558eb77b173c4900fbdfb7f Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 24 Jun 2020 16:49:22 -0700
Subject: [PATCH 22/25] remove commented code

---
 scripts/emulator-testing/emulators/emulator.ts | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/scripts/emulator-testing/emulators/emulator.ts b/scripts/emulator-testing/emulators/emulator.ts
index e7abee703eb..c39081604d0 100644
--- a/scripts/emulator-testing/emulators/emulator.ts
+++ b/scripts/emulator-testing/emulators/emulator.ts
@@ -24,10 +24,6 @@ import * as request from 'request';
 // @ts-ignore
 import * as tmp from 'tmp';
 
-// export interface ChildProcessPromise extends Promise<void> {
-//   childProcess: ChildProcess;
-// }
-
 export abstract class Emulator {
   binaryPath: string | null = null;
   emulator: ChildProcess | null = null;

From f088bf5183abe39f8ea0f8b6ec7468561261497b Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 24 Jun 2020 17:26:02 -0700
Subject: [PATCH 23/25] fix types

---
 scripts/emulator-testing/firestore-test-runner.ts | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/scripts/emulator-testing/firestore-test-runner.ts b/scripts/emulator-testing/firestore-test-runner.ts
index 69584f11006..e10cad75f69 100644
--- a/scripts/emulator-testing/firestore-test-runner.ts
+++ b/scripts/emulator-testing/firestore-test-runner.ts
@@ -21,21 +21,16 @@ import * as path from 'path';
 // @ts-ignore
 import * as freePortFinder from 'find-free-port';
 
-import { ChildProcessPromise } from './emulators/emulator';
 import { FirestoreEmulator } from './emulators/firestore-emulator';
 
-function runTest(
-  port: number,
-  projectId: string,
-  withPersistence: boolean
-): ChildProcessPromise {
+function runTest(port: number, projectId: string, withPersistence: boolean) {
   const options = {
     cwd: path.resolve(__dirname, '../../packages/firestore'),
     env: Object.assign({}, process.env, {
       FIRESTORE_EMULATOR_PORT: port,
       FIRESTORE_EMULATOR_PROJECT_ID: projectId
     }),
-    stdio: 'inherit'
+    stdio: 'inherit' as const
   };
   // TODO(b/113267261): Include browser test once WebChannel support is
   // ready in Firestore emulator.

From 96949e5c308b6f608c774b5c0098e3fa57ca0779 Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 24 Jun 2020 17:53:56 -0700
Subject: [PATCH 24/25] add Changeset check

---
 .github/workflows/changesets.yml | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 .github/workflows/changesets.yml

diff --git a/.github/workflows/changesets.yml b/.github/workflows/changesets.yml
new file mode 100644
index 00000000000..43b682d56ab
--- /dev/null
+++ b/.github/workflows/changesets.yml
@@ -0,0 +1,25 @@
+name: Changeset Check
+
+on:
+  pull_request:
+    branches:
+      - master
+
+jobs:
+  release:
+    name: Changeset Check
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@master
+
+      - name: Setup Node.js 12.x
+        uses: actions/setup-node@master
+        with:
+          node-version: 12.x
+
+      - name: Install Dependencies
+        run: yarn
+
+      - name: Check if any Changeset file exists
+        run: yarn changeset status
\ No newline at end of file

From f4a1c55c07aaee0c680f097ac20ff6a7f3bb3abe Mon Sep 17 00:00:00 2001
From: Feiyang1 <plane1113@gmail.com>
Date: Wed, 24 Jun 2020 17:59:31 -0700
Subject: [PATCH 25/25] compare to master

---
 .github/workflows/changesets.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/changesets.yml b/.github/workflows/changesets.yml
index 43b682d56ab..0aebbedbeda 100644
--- a/.github/workflows/changesets.yml
+++ b/.github/workflows/changesets.yml
@@ -22,4 +22,4 @@ jobs:
         run: yarn
 
       - name: Check if any Changeset file exists
-        run: yarn changeset status
\ No newline at end of file
+        run: yarn changeset status --since=master
\ No newline at end of file