From 0fcb548c054248924190fa27caf7372cfded2ba0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 06:47:17 +0000 Subject: [PATCH 001/288] build(deps-dev): bump swr from 0.4.2 to 0.5.3 (#3230) --- package.json | 2 +- yarn.lock | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 202710fb386d..4de04de8c710 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "stylelint-config-sass-guidelines": "^8.0.0", "stylelint-prettier": "^1.2.0", "stylelint-scss": "^3.19.0", - "swr": "^0.4.2", + "swr": "^0.5.3", "ts-loader": "^8.0.18", "typescript": "^4.2.3", "use-debounce": "^5.2.1", diff --git a/yarn.lock b/yarn.lock index e8f356732376..3dcb9ad75d09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6641,11 +6641,6 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -dequal@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" - integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== - des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -16906,12 +16901,10 @@ svgo@^2.1.0: csso "^4.2.0" stable "^0.1.8" -swr@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/swr/-/swr-0.4.2.tgz#4a9ed5e9948088af145c79d716d294cb99712a29" - integrity sha512-SKGxcAfyijj/lE5ja5zVMDqJNudASH3WZPRUakDVOePTM18FnsXgugndjl9BSRwj+jokFCulMDe7F2pQL+VhEw== - dependencies: - dequal "2.0.2" +swr@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/swr/-/swr-0.5.3.tgz#7290a9a61329d930583ef365317e636b8dbaa8bb" + integrity sha512-RUE3RWn3jt9e4qLPat2A9vbHG/5N6konsc27xKjE65jFSiGv0P7HLD8IGvwAv6DRKktL7Od2UcayX0plKb2awg== symbol-tree@^3.2.4: version "3.2.4" From 8af61551630879fb8b36da53d6effe22d85692b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 06:49:01 +0000 Subject: [PATCH 002/288] build(deps): bump fast-xml-parser from 3.18.0 to 3.19.0 (#3231) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4de04de8c710..371c0f12f070 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "dotenv": "8.2.0", "ejs": "3.1.6", "express": "4.17.1", - "fast-xml-parser": "3.18.0", + "fast-xml-parser": "3.19.0", "file-type": "16.3.0", "front-matter": "4.0.2", "fs-extra": "9.1.0", diff --git a/yarn.lock b/yarn.lock index 3dcb9ad75d09..1230d39890d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7954,10 +7954,10 @@ fast-safe-stringify@^2.0.4: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== -fast-xml-parser@3.18.0: - version "3.18.0" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.18.0.tgz#b77f4a494cd64e6f44aadfa68fbde30cd922b2df" - integrity sha512-tRrwShhppv0K5GKEtuVs92W0VGDaVltZAwtHbpjNF+JOT7cjIFySBGTEOmdBslXYyWYaZwEX/g4Su8ZeKg0LKQ== +fast-xml-parser@3.19.0: + version "3.19.0" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01" + integrity sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg== fastest-levenshtein@^1.0.12: version "1.0.12" From ba908cbba15eace5869bf6d4a0dec0531f7514dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 06:49:29 +0000 Subject: [PATCH 003/288] build(deps-dev): bump html-validate from 4.6.1 to 4.7.0 (#3233) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 371c0f12f070..c680ed8f120f 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "fuzzyjs": "4.0.4", "fuzzysearch": "1.0.3", "history": "5.0.0", - "html-validate": "4.6.1", + "html-validate": "4.7.0", "husky": "4.3.8", "ignore-loader": "^0.1.2", "jest-environment-jsdom-sixteen": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index 1230d39890d0..6085315c423e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9327,10 +9327,10 @@ html-tags@^3.1.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== -html-validate@4.6.1: - version "4.6.1" - resolved "https://registry.yarnpkg.com/html-validate/-/html-validate-4.6.1.tgz#9fc01072d36e518f75b8dc51157fc2e1d45ccb9f" - integrity sha512-vFmvy70+UUySVbekufawocXyfIUDRex6cwX5JMPpHZ3FzTmWnarUTGttXHk1l6/v67c/DDnsdZiJHaLMZWcOUg== +html-validate@4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/html-validate/-/html-validate-4.7.0.tgz#98df8689a2021f069962294d824697412a2c820d" + integrity sha512-tu6xLlHQY4RkfXtR5d8WjJ8+w2BbZZGtAdgtL3C7tRjepFtVluu3vLpGPEfi3NP9wZf9Xk2/Dgm9RK48StqVpA== dependencies: "@babel/code-frame" "^7.10.4" "@html-validate/stylish" "1.0.0" From db0131eadf82c0ed7f3f71df53becfce0383b82c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 06:50:31 +0000 Subject: [PATCH 004/288] build(deps-dev): bump eslint-plugin-jest from 24.2.1 to 24.3.1 (#3234) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c680ed8f120f..c8a960e742ee 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "downshift": "^6.1.0", "eslint": "^7.18.0", "eslint-gitignore": "^0.1.0", - "eslint-plugin-jest": "24.2.1", + "eslint-plugin-jest": "24.3.1", "eslint-plugin-node": "11.1.0", "extend": "^3.0.2", "flexsearch": "0.6.32", diff --git a/yarn.lock b/yarn.lock index 6085315c423e..d6d170c8087b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7412,10 +7412,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@24.2.1, eslint-plugin-jest@^24.1.0: - version "24.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.2.1.tgz#7e84f16a3ca6589b86be9732a93d71367a4ed627" - integrity sha512-s24ve8WUu3DLVidvlSzaqlOpTZre9lTkZTAO+a7X0WMtj8HraWTiTEkW3pbDT1xVxqEHMWSv+Kx7MyqR50nhBw== +eslint-plugin-jest@24.3.1, eslint-plugin-jest@^24.1.0: + version "24.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.1.tgz#c8df037847b83397940bef7fbc2cc168ab466bcc" + integrity sha512-RQt59rfMSHyvedImT72iaf8JcvCcR4P7Uq499dALtjY8mrCjbwWrFi1UceG4sid2wVIeDi+0tjxXZ8CZEVO7Zw== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" From 78b226e1ae5af7b281b9e1cca52b77cffe90b2f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 08:23:02 +0000 Subject: [PATCH 005/288] build(deps-dev): bump flake8 from 3.8.4 to 3.9.0 in /deployer (#3235) --- deployer/poetry.lock | 26 +++++++++++++------------- deployer/pyproject.toml | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index 7fdedf7b741a..239c4c55ee5b 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -174,17 +174,17 @@ develop = ["mock", "pytest (>=3.0.0)", "pytest-cov", "pytest-mock (<3.0.0)", "py [[package]] name = "flake8" -version = "3.8.4" +version = "3.9.0" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.6.0a1,<2.7.0" -pyflakes = ">=2.2.0,<2.3.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "idna" @@ -285,7 +285,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pycodestyle" -version = "2.6.0" +version = "2.7.0" description = "Python style guide checker" category = "dev" optional = false @@ -301,7 +301,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pyflakes" -version = "2.2.0" +version = "2.3.0" description = "passive checker of Python programs" category = "dev" optional = false @@ -479,7 +479,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "08e36bb5279b9dcbabe1f87c8488d3722dacafc4d846711bb68d1734ceedc643" +content-hash = "9c23cadee62150680d858c7c4ea9c46d43bc1d77d410f766872a3c47a64723c7" [metadata.files] appdirs = [ @@ -585,8 +585,8 @@ elasticsearch-dsl = [ {file = "elasticsearch_dsl-7.3.0-py2.py3-none-any.whl", hash = "sha256:9390d8e5cf82ebad3505e7f656e407259cf703f5a4035f211cef454127672572"}, ] flake8 = [ - {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, - {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, + {file = "flake8-3.9.0-py2.py3-none-any.whl", hash = "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff"}, + {file = "flake8-3.9.0.tar.gz", hash = "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, @@ -629,16 +629,16 @@ py = [ {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, ] pycparser = [ {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, ] pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, + {file = "pyflakes-2.3.0-py2.py3-none-any.whl", hash = "sha256:910208209dcea632721cb58363d0f72913d9e8cf64dc6f8ae2e02a3609aba40d"}, + {file = "pyflakes-2.3.0.tar.gz", hash = "sha256:e59fd8e750e588358f1b8885e5a4751203a0516e0ee6d34811089ac294c8806f"}, ] pyopenssl = [ {file = "pyOpenSSL-20.0.1-py2.py3-none-any.whl", hash = "sha256:818ae18e06922c066f777a33f1fca45786d85edfe71cd043de6379337a7f274b"}, diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index c204850e8dc2..b607840d70cd 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -18,7 +18,7 @@ selectolax = "^0.2.10" [tool.poetry.dev-dependencies] black = "^20.8b1" -flake8 = "^3.8.2" +flake8 = "^3.9.0" pytest = "^6.2.2" [tool.poetry.scripts] From 2d115e8a76fe8094280a4614b29149ebef3ebbae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 09:46:35 +0000 Subject: [PATCH 006/288] build(deps-dev): bump flake8 from 3.8.4 to 3.9.0 in /testing/integration (#3237) --- testing/integration/poetry.lock | 26 +++++++++++++------------- testing/integration/pyproject.toml | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/testing/integration/poetry.lock b/testing/integration/poetry.lock index eca0453dc136..ff9354416bfc 100644 --- a/testing/integration/poetry.lock +++ b/testing/integration/poetry.lock @@ -100,17 +100,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "flake8" -version = "3.8.4" +version = "3.9.0" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.6.0a1,<2.7.0" -pyflakes = ">=2.2.0,<2.3.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "idna" @@ -217,7 +217,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pycodestyle" -version = "2.6.0" +version = "2.7.0" description = "Python style guide checker" category = "dev" optional = false @@ -225,7 +225,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pyflakes" -version = "2.2.0" +version = "2.3.0" description = "passive checker of Python programs" category = "dev" optional = false @@ -382,7 +382,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "0bc6df00c02f80c21dac088cf197f3caabf1ec0e98cec4d1f9a8a062ff711e7f" +content-hash = "e2d74c3b25e579b95fe9d6b91d707062cbf3de2994d7553c8a1571b33712eb66" [metadata.files] appdirs = [ @@ -425,8 +425,8 @@ cssselect = [ {file = "cssselect-1.1.0.tar.gz", hash = "sha256:f95f8dedd925fd8f54edb3d2dfb44c190d9d18512377d3c1e2388d16126879bc"}, ] flake8 = [ - {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, - {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, + {file = "flake8-3.9.0-py2.py3-none-any.whl", hash = "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff"}, + {file = "flake8-3.9.0.tar.gz", hash = "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, @@ -504,12 +504,12 @@ py = [ {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, ] pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, ] pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, + {file = "pyflakes-2.3.0-py2.py3-none-any.whl", hash = "sha256:910208209dcea632721cb58363d0f72913d9e8cf64dc6f8ae2e02a3609aba40d"}, + {file = "pyflakes-2.3.0.tar.gz", hash = "sha256:e59fd8e750e588358f1b8885e5a4751203a0516e0ee6d34811089ac294c8806f"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, diff --git a/testing/integration/pyproject.toml b/testing/integration/pyproject.toml index ea61e274ce86..2308fe0d45c1 100644 --- a/testing/integration/pyproject.toml +++ b/testing/integration/pyproject.toml @@ -18,7 +18,7 @@ braceexpand = "^0.1.6" [tool.poetry.dev-dependencies] black = "^20.8b1" -flake8 = "^3.8.2" +flake8 = "^3.9.0" [build-system] requires = ["poetry>=0.12"] From a7a5bc1d40e389a138fa6e118872d6a02cabaa8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 09:57:43 +0000 Subject: [PATCH 007/288] build(deps-dev): bump jsdom from 16.5.0 to 16.5.1 (#3232) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c8a960e742ee..925e4c083ae1 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "jest-environment-jsdom-sixteen": "^1.0.3", "jest-junit-reporter": "^1.1.0", "jest-puppeteer": "4.4.0", - "jsdom": "^16.5.0", + "jsdom": "^16.5.1", "jsesc": "^3.0.2", "nodemon": "2.0.7", "pegjs": "^0.10.0", diff --git a/yarn.lock b/yarn.lock index d6d170c8087b..e535e1d69278 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11148,10 +11148,10 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsdom@^16.2.1, jsdom@^16.4.0, jsdom@^16.5.0: - version "16.5.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.0.tgz#9e453505600cc5a70b385750d35256f380730cc4" - integrity sha512-QxZH0nmDTnTTVI0YDm4RUlaUPl5dcyn62G5TMDNfMmTW+J1u1v9gCR8WR+WZ6UghAa7nKJjDOFaI00eMMWvJFQ== +jsdom@^16.2.1, jsdom@^16.4.0, jsdom@^16.5.1: + version "16.5.1" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.1.tgz#4ced6bbd7b77d67fb980e64d9e3e6fb900f97dd6" + integrity sha512-pF73EOsJgwZekbDHEY5VO/yKXUkab/DuvrQB/ANVizbr6UAHJsDdHXuotZYwkJSGQl1JM+ivXaqY+XBDDL4TiA== dependencies: abab "^2.0.5" acorn "^8.0.5" From a41d5f24794bb7029b893544bf3f299ae3baa5bb Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 15 Mar 2021 07:15:19 -0400 Subject: [PATCH 008/288] sitemap tool (#3158) * _sitemap * more features * fixes * small fixes * misc improvements * open in your editor * eslint * add a basic headless test * more feedbacked --- client/src/app.tsx | 10 + client/src/sitemap/index.scss | 39 ++ client/src/sitemap/index.tsx | 514 ++++++++++++++++++++++++++ client/src/writers-homepage/index.tsx | 3 + server/index.js | 26 +- testing/tests/developing.test.js | 10 + 6 files changed, 592 insertions(+), 10 deletions(-) create mode 100644 client/src/sitemap/index.scss create mode 100644 client/src/sitemap/index.tsx diff --git a/client/src/app.tsx b/client/src/app.tsx index 7aa5065c723a..883319bc758a 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -22,6 +22,7 @@ const DocumentEdit = React.lazy(() => import("./document/forms/edit")); const DocumentCreate = React.lazy(() => import("./document/forms/create")); const DocumentManage = React.lazy(() => import("./document/forms/manage")); const WritersHomepage = React.lazy(() => import("./writers-homepage")); +const Sitemap = React.lazy(() => import("./sitemap")); const isServer = typeof window === "undefined"; @@ -183,6 +184,15 @@ export function App(appProps) { } /> + + + + + } + /> )} { + document.title = "Sitemap"; + }, []); + + const { data, error } = useSWR( + `/${locale}/search-index.json`, + async (url) => { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`${response.status} on ${response.url}`); + } + return (await response.json()) as SearchIndexDoc[]; + }, + { + revalidateOnFocus: false, + } + ); + + const [docs, setDocs] = React.useState(null); + React.useEffect(() => { + if (data) { + const theseDocs = [...data].sort((a, b) => a.url.localeCompare(b.url)); + setDocs(theseDocs); + } + }, [data]); + + const [childCounts, setChildCounts] = React.useState>( + new Map() + ); + React.useEffect(() => { + const counts = new Map(); + if (docs) { + for (const { url } of docs) { + const split = url.split("/"); + const root = split.slice(0, 3); + split.slice(3).forEach((portion, i) => { + root.push(portion); + const key = root.join("/"); + counts.set(key, (counts.get(key) || 0) + 1); + }); + } + setChildCounts(counts); + } + }, [docs]); + + const [thisDoc, setThisDoc] = React.useState(null); + React.useEffect(() => { + if (docs) { + const newThisDoc = docs.find((doc) => { + return doc.url.toLowerCase() === searchPathname; + }); + setThisDoc(newThisDoc || null); + } + }, [searchPathname, docs]); + + const [searchFilter, setSearchFilter] = React.useState(""); + React.useEffect(() => { + setSearchFilter(""); + }, [pathname]); + const [searchSubmitted, setSearchSubmitted] = React.useState(false); + + const [filtered, setFiltered] = React.useState(null); + React.useEffect(() => { + if (docs) { + const depth = searchPathname.split("/").length; + const newFiltered = docs.filter((doc) => { + if ( + doc.url.toLowerCase().startsWith(searchPathname) && + depth + 1 === doc.url.split("/").length + ) { + const baseName = doc.url.split("/").slice(-1)[0].toLowerCase(); + if (!baseName.startsWith(searchFilter.toLowerCase())) { + return false; + } + return true; + } + return false; + }); + setFiltered(newFiltered); + } + }, [searchPathname, docs, searchFilter]); + + const [highlightIndex, setHighlightIndex] = React.useState(0); + React.useEffect(() => { + setHighlightIndex(0); + }, [searchFilter]); + + React.useEffect(() => { + if (searchSubmitted) { + if (filtered && filtered.length >= 1) { + const slug = filtered[highlightIndex].url.split("/").slice(3); + setSearchFilter(""); + setSearchSubmitted(false); + navigate(`/${locale}/_sitemap/${slug.join("/")}`); + } + } + }, [locale, filtered, searchSubmitted, navigate, highlightIndex]); + + function changeHighlight(direction: "up" | "down") { + if (direction === "up") { + let nextNumber = highlightIndex - 1; + if (filtered) { + nextNumber = + ((nextNumber % filtered.length) + filtered.length) % filtered.length; + } + setHighlightIndex(nextNumber); + } else { + let nextNumber = highlightIndex + 1; + if (filtered) { + nextNumber = nextNumber % filtered.length; + } + setHighlightIndex(nextNumber); + } + } + + const [opening, setOpening] = React.useState(null); + const [ + editorOpeningError, + setEditorOpeningError, + ] = React.useState(null); + React.useEffect(() => { + let unsetOpeningTimer: ReturnType; + if (opening) { + unsetOpeningTimer = setTimeout(() => { + setOpening(null); + }, 3000); + } + return () => { + if (unsetOpeningTimer) { + clearTimeout(unsetOpeningTimer); + } + }; + }, [opening]); + + async function openInYourEditor(url: string) { + console.log(`Going to try to open ${url} in your editor`); + setOpening(url); + const sp = new URLSearchParams(); + sp.set("url", url); + try { + const response = await fetch(`/_open?${sp.toString()}`); + if (!response.ok) { + if (response.status >= 500) { + setEditorOpeningError( + new Error(`${response.status}: ${response.statusText}`) + ); + } else { + const body = await response.text(); + setEditorOpeningError(new Error(`${response.status}: ${body}`)); + } + } + } catch (err) { + setEditorOpeningError(err); + } + } + + return ( + +
+ {error && ( +
+

Error

+

+ {error.toString()} +

+
+ )} + + {editorOpeningError && ( +
+

Error opening in your editor

+

+ {editorOpeningError.toString()} +

+
+ )} + + {!data && !error &&

Loading loading loading...

} +
+ {opening && ( + <> + Opening{" "} + {opening.slice(opening.length - 50, opening.length)}{" "} + in your editor... + + )} +
+ {filtered && ( + + )} + {filtered && ( + { + setSearchFilter(text); + setSearchSubmitted(submitted); + }} + onGoUp={() => { + // Navigate to the parent! ...if possible + const split = pathname.split("/"); + if (split.length >= 4) { + const parentPathname = split.slice(0, -1); + navigate(parentPathname.join("/")); + } + }} + onChangeHighlight={changeHighlight} + /> + )} + {filtered && + filtered.length === 0 && + (searchFilter ? ( + nothing found + ) : ( + has no further sub-documents + ))} + {filtered && !searchFilter && } + {filtered && filtered.length > 0 && ( + + )} +

+ Note, this sitemap only shows documents. Not any other applications. +

+
+
+ ); +} + +function GoBackUp({ pathname }: { pathname: string }) { + const parentPath = pathname.split("/").slice(0, -1); + if (parentPath.length <= 2) { + return null; + } + const parentBasename = parentPath[parentPath.length - 1]; + + return ( +

+ + ↖️ Back up to{" "} + {parentPath.length <= 3 ? root : {parentBasename}} + +

+ ); +} + +function FilterForm({ + pathname, + searchFilter, + onUpdate, + onGoUp, + onChangeHighlight, +}: { + pathname: string; + searchFilter: string; + onUpdate: (text: string, submitted: boolean) => void; + onGoUp: () => void; + onChangeHighlight: (s: "up" | "down") => void; +}) { + const [hideTip, setHideTip] = React.useState(false); + + const [countBackspaces, setCountBackspaces] = React.useState(0); + React.useEffect(() => { + if (countBackspaces >= 2) { + setCountBackspaces(0); + onGoUp(); + } + }, [countBackspaces, onGoUp]); + + const inputRef = React.useRef(null); + + const focusSearch = React.useCallback( + (event: KeyboardEvent) => { + if (inputRef.current && event.target) { + const target = event.target as HTMLElement; + + if (target === inputRef.current) { + if (event.key === "ArrowDown") { + onChangeHighlight("down"); + } else if (event.key === "ArrowUp") { + onChangeHighlight("up"); + } + } + + if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") { + if (event.key === "Backspace" && event.target === inputRef.current) { + if (!searchFilter.trim()) { + setCountBackspaces((s) => s + 1); + } + } else { + setCountBackspaces(0); + } + + if (event.key === "Escape") { + inputRef.current.blur(); + } + } else { + if (event.key === "T" || event.key === "t") { + inputRef.current.focus(); + setCountBackspaces(0); + } + } + } + }, + [onChangeHighlight, searchFilter] + ); + + React.useEffect(() => { + window.document.addEventListener("keyup", focusSearch); + return () => { + window.document.removeEventListener("keyup", focusSearch); + }; + }, [focusSearch]); + const prefixPathname = pathname.replace(`/_sitemap`, "/docs"); + + return ( +
{ + event.preventDefault(); + onUpdate(searchFilter.trim(), true); + }} + > + {prefixPathname}/ + { + onUpdate(event.target.value, false); + }} + onFocus={() => { + setHideTip(true); + }} + onBlur={() => { + setHideTip(false); + }} + />{" "} + {!hideTip && ( + + Tip! press t on your keyboard to focus on search filter + + )} +
+ ); +} + +function Breadcrumb({ + pathname, + thisDoc, + openInYourEditor, +}: { + pathname: string; + thisDoc: SearchIndexDoc | null; + openInYourEditor: (url: string) => void; +}) { + const locale = useLocale(); + const split = pathname.split("/").slice(3); + const root = pathname.split("/").slice(0, 2); + root.push("_sitemap"); + + return ( + <> + + + ); +} + +function ShowTree({ + filtered, + childCounts, + highlightIndex, + openInYourEditor, +}: { + filtered: SearchIndexDoc[]; + childCounts: Map; + highlightIndex: number; + openInYourEditor: (url: string) => void; +}) { + const locale = useLocale(); + return ( +
+
    + {filtered.map((doc, i) => { + const countChild = childCounts.get(doc.url) || 0; + return ( +
  • + + {doc.url.replace(`/${locale}/docs`, "")} + {" "} + + ( + {countChild === 1 + ? "1 document" + : `${countChild.toLocaleString()} documents`} + {" | "} + + View + + {" | "} + { + event.preventDefault(); + openInYourEditor(doc.url); + }} + > + Edit + + ) + +
  • + ); + })} +
+
+ ); +} diff --git a/client/src/writers-homepage/index.tsx b/client/src/writers-homepage/index.tsx index 8895645b4a46..487ebc84996a 100644 --- a/client/src/writers-homepage/index.tsx +++ b/client/src/writers-homepage/index.tsx @@ -81,6 +81,9 @@ export default function WritersHomepage() {

Tools

    +
  • + Sitemap +
  • Flaws Dashboard
  • diff --git a/server/index.js b/server/index.js index 4a4cf7f416ba..21d6b1147948 100644 --- a/server/index.js +++ b/server/index.js @@ -93,11 +93,7 @@ app.use(express.urlencoded({ extended: true })); app.use("/_document", documentRouter); app.get("/_open", (req, res) => { - const { line, column, filepath } = req.query; - if (!filepath) { - throw new Error("No .filepath in the request query"); - } - + const { line, column, filepath, url } = req.query; // Sometimes that 'filepath' query string parameter is a full absolute // filepath (e.g. /Users/peterbe/yari/content.../index.html), which usually // happens when you this is used from the displayed flaws on a preview @@ -105,12 +101,22 @@ app.get("/_open", (req, res) => { // But sometimes, it's a relative path and if so, it's always relative // to the main builder source. let absoluteFilepath; - if (fs.existsSync(filepath)) { - absoluteFilepath = filepath; + if (filepath) { + if (fs.existsSync(filepath)) { + absoluteFilepath = filepath; + } else { + const [locale] = filepath.split(path.sep); + const root = getRoot(locale); + absoluteFilepath = path.join(root, filepath); + } + } else if (url) { + const document = Document.findByURL(url); + if (!document) { + res.status(410).send(`No known document by the URL '${url}'\n`); + } + absoluteFilepath = document.fileInfo.path; } else { - const [locale] = filepath.split(path.sep); - const root = getRoot(locale); - absoluteFilepath = path.join(root, filepath); + throw new Error("No .filepath or .url in the request query"); } // Double-check that the file can be found. diff --git a/testing/tests/developing.test.js b/testing/tests/developing.test.js index 26935174ef98..66585fcd10e6 100644 --- a/testing/tests/developing.test.js +++ b/testing/tests/developing.test.js @@ -187,4 +187,14 @@ describe("Testing the CRUD apps", () => { await expect(page).toClick("a", { text: "Flaws Dashboard" }); await expect(page).toMatch("Documents with flaws found (0)"); }); + + withCrud("open the sitemap app", async () => { + await page.goto(devURL("/")); + await expect(page).toMatch("Writer's home page"); + await expect(page).toClick("a", { text: "Sitemap" }); + await expect(page).toMatchElement("a", { text: "Web" }); + await expect(page).toMatchElement("a", { text: "Learn" }); + await expect(page).toClick("a", { text: "Glossary" }); + await expect(page).toMatchElement("a", { text: "Glossary/PNG" }); + }); }); From 1c79f9a24a110680ec30d800ebef5b4ca803c948 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 15 Mar 2021 08:48:10 -0400 Subject: [PATCH 009/288] calm down gather-git-history (#3243) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 925e4c083ae1..dd779ebd6cf8 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "filecheck": "cd filecheck && node cli.js", "fiori:build": "cd client && build-storybook", "fiori:start": "cd client && start-storybook -p 6006", - "prepare-build": "yarn build:client && yarn build:ssr && yarn tool google-analytics-code && yarn tool spas && yarn tool gather-git-history --verbose", + "prepare-build": "yarn build:client && yarn build:ssr && yarn tool google-analytics-code && yarn tool spas && yarn tool gather-git-history", "prettier-check": "prettier --check .", "prettier-format": "prettier --write .", "start": "(test -f client/build/index.html || yarn build:client) && (test -f ssr/dist/main.js || yarn build:ssr) && (test -d client/build/en-us/_spas || yarn tool spas) && nf -j Procfile.start start", From 0a194ed4a5ea7e37d39db44a0604694129709f49 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 15 Mar 2021 08:49:45 -0400 Subject: [PATCH 010/288] make keys for MacroPagesErrors more unique (#3185) * make keys for MacroPagesErrors more unique Fixes #3184 * make keys for MacroPagesErrors more unique Fixes #3184 * Revert "make keys for MacroPagesErrors more unique" This reverts commit abd4918c45edeed1eb66ae71f394e5ff0c1c80a1. * feedbacked --- client/src/document/toolbar/flaws.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/client/src/document/toolbar/flaws.tsx b/client/src/document/toolbar/flaws.tsx index fe2696286e07..076428db36e9 100644 --- a/client/src/document/toolbar/flaws.tsx +++ b/client/src/document/toolbar/flaws.tsx @@ -625,7 +625,7 @@ function Macros({ }; }, [opening]); - function openInEditor(msg: MacroErrorMessage, key: string) { + function openInEditor(msg: MacroErrorMessage, id: string) { const sp = new URLSearchParams(); sp.set("filepath", msg.filepath); sp.set("line", `${msg.line}`); @@ -633,7 +633,7 @@ function Macros({ console.log( `Going to try to open ${msg.filepath}:${msg.line}:${msg.column} in your editor` ); - setOpening(key); + setOpening(id); fetch(`/_open?${sp.toString()}`); } @@ -644,11 +644,9 @@ function Macros({ const inPrerequisiteMacro = !flaw.filepath.includes( `${sourceFolder}/index.html` ); - const key = `${flaw.filepath}:${flaw.line}:${flaw.column}`; - return (
    { event.preventDefault(); - openInEditor(flaw, key); + openInEditor(flaw, flaw.id); }} > {flaw.name} from {flaw.macroName} in line {flaw.line}:{flaw.column} {" "} - {opening && opening === key && Opening...}{" "} + {opening && opening === flaw.id && Opening...}{" "} {inPrerequisiteMacro && ( Date: Mon, 15 Mar 2021 14:17:05 +0100 Subject: [PATCH 011/288] make ru locale active (#3242) --- libs/constants/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/constants/index.js b/libs/constants/index.js index 242785e30e95..5e792969be50 100644 --- a/libs/constants/index.js +++ b/libs/constants/index.js @@ -51,7 +51,7 @@ const LOCALE_ALIASES = new Map([ // This must match what we do in `language-menu/index.tsx` where the cookie // gets set in the client! const PREFERRED_LOCALE_COOKIE_NAME = "preferredlocale"; -const ACTIVE_LOCALES = new Set(["en-us", "fr", "ja", "zh-cn", "zh-tw"]); +const ACTIVE_LOCALES = new Set(["en-us", "fr", "ja", "ru", "zh-cn", "zh-tw"]); module.exports = { ACTIVE_LOCALES, From 65f1627b4f07baa9014366e786134460df93a016 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 13:41:29 +0000 Subject: [PATCH 012/288] build(deps): bump image-size from 0.9.5 to 0.9.7 (#3246) --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index dd779ebd6cf8..327b689018de 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "glob": "^7.1.6", "got": "11.8.2", "http-proxy-middleware": "1.0.6", - "image-size": "0.9.5", + "image-size": "0.9.7", "image-type": "4.1.0", "imagemin": "7.0.1", "imagemin-gifsicle": "7.0.0", diff --git a/yarn.lock b/yarn.lock index e535e1d69278..a520c561ceb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9576,12 +9576,12 @@ ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== -image-size@0.9.5: - version "0.9.5" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.9.5.tgz#03a4224c5b643d2a0a7d21ee561cf7edf8985421" - integrity sha512-HvnQBt6+u5PjmZvaFpJOB1VfrDdwxu8p456HAfYXPzEKl6GJKrNJZKDaN0A/0b1kJ7JpDUU6eBT7hmiREwzqWA== +image-size@0.9.7: + version "0.9.7" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.9.7.tgz#43b4ead4b1310d5ae310a559d52935a347e47c09" + integrity sha512-KRVgLNZkr00YGN0qn9MlIrmlxbRhsCcEb1Byq3WKGnIV4M48iD185cprRtaoK4t5iC+ym2Q5qlArxZ/V1yzDgA== dependencies: - queue "6.0.1" + queue "6.0.2" image-type@4.1.0: version "4.1.0" @@ -14560,10 +14560,10 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== -queue@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.1.tgz#abd5a5b0376912f070a25729e0b6a7d565683791" - integrity sha512-AJBQabRCCNr9ANq8v77RJEv73DPbn55cdTb+Giq4X0AVnNVZvMHlYp7XlQiN+1npCZj1DuSmaA2hYVUUDgxFDg== +queue@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65" + integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA== dependencies: inherits "~2.0.3" From 817860ebe713d270f4d9e6fedf32b152efe7c25a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 11:24:58 -0400 Subject: [PATCH 013/288] build(deps-dev): bump @mdn/minimalist from 0.7.3 to 0.7.4 (#3247) Bumps [@mdn/minimalist](https://github.com/mdn/mdn-minimalist) from 0.7.3 to 0.7.4. - [Release notes](https://github.com/mdn/mdn-minimalist/releases) - [Changelog](https://github.com/mdn/mdn-minimalist/blob/main/CHANGELOG.md) - [Commits](https://github.com/mdn/mdn-minimalist/compare/v0.7.3...v0.7.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 327b689018de..dd94da3c06ae 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "devDependencies": { "@babel/core": "^7.13.10", "@mdn/dinocons": "^0.3.0", - "@mdn/minimalist": "^0.7.3", + "@mdn/minimalist": "^0.7.4", "@storybook/addon-a11y": "^6.1.21", "@storybook/addon-actions": "^6.1.21", "@storybook/addon-essentials": "^6.1.21", diff --git a/yarn.lock b/yarn.lock index a520c561ceb9..74ec9deb093c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1894,10 +1894,10 @@ resolved "https://registry.yarnpkg.com/@mdn/dinocons/-/dinocons-0.3.0.tgz#2162eb6c12b36dd9bfc69f344d9150b4b5a3c9ad" integrity sha512-++oqKEzbWtc4DHELnS9R6HoGt+7AGRe2zlxTyk5YCSwouIIiI4DEGuoMCdtBCrZOoHtp2WHZ1mZ6BqEmQh8hLA== -"@mdn/minimalist@^0.7.3": - version "0.7.3" - resolved "https://registry.yarnpkg.com/@mdn/minimalist/-/minimalist-0.7.3.tgz#e3f0773f94d1ea0578a4b16c19e604ebb4ef294b" - integrity sha512-4cYfO5SrRSyRY4RUusUK4alMsFZlUD0801Z3t2hQqdXE28QDFLRUNKa/B0Fk6hBs0Y3b3z4rhql+dYmyOE1dBA== +"@mdn/minimalist@^0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@mdn/minimalist/-/minimalist-0.7.4.tgz#83e6bfba5d0ded8d05e0b72f92123ea1d77ec1fb" + integrity sha512-5n0cB1HCdRe6Mw78+SFG3UZkXx2xcuv33SfnPTU9dQAFQ13JOjwACJrNBvQZdqtjo2+hjXi6Xu50eyf5tP30Sg== "@mdx-js/loader@^1.6.19": version "1.6.21" From 51dcc558437d6d4502b456fb65fccc39b566813b Mon Sep 17 00:00:00 2001 From: Florian Dieminger Date: Mon, 15 Mar 2021 18:55:49 +0100 Subject: [PATCH 014/288] generate pre in CSSSyntax (#3244) --- kumascript/macros/CSSSyntax.ejs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kumascript/macros/CSSSyntax.ejs b/kumascript/macros/CSSSyntax.ejs index 7af7ca7d2b59..ae52914abe0b 100644 --- a/kumascript/macros/CSSSyntax.ejs +++ b/kumascript/macros/CSSSyntax.ejs @@ -433,4 +433,8 @@ if (!formattedSyntax) { throw new Error(`No syntax found in DB for '${name}'`); } -%><%- formattedSyntax %> +const rtlLocales = ['ar', 'he', 'fa']; +const rtl = rtlLocales.includes(env.locale); +const out = `${formattedSyntax}` + +%><%- out %> From 8556a9e4479276bf5d5f4b9ce8d38c0d59e42301 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 15 Mar 2021 19:10:19 -0400 Subject: [PATCH 015/288] Check of unsafe HTML in SVG files (#3250) * Check of unsafe HTML in SVG files Fixes #3249 * mention in index.html file * feedbacked --- filecheck/checker.js | 17 ++++++++++++++--- testing/tests/filecheck.test.js | 25 +++++++++++++++++++++++++ testing/tests/samplefiles/index.html | 3 +++ testing/tests/samplefiles/onhandler.svg | 3 +++ testing/tests/samplefiles/script.svg | 3 +++ 5 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 testing/tests/filecheck.test.js create mode 100644 testing/tests/samplefiles/index.html create mode 100644 testing/tests/samplefiles/onhandler.svg create mode 100644 testing/tests/samplefiles/script.svg diff --git a/filecheck/checker.js b/filecheck/checker.js index 4b9049656d82..bc892949fb87 100644 --- a/filecheck/checker.js +++ b/filecheck/checker.js @@ -62,9 +62,20 @@ async function checkFile(filePath, options) { throw new Error(`${filePath} does not appear to be an SVG`); } const $ = cheerio.load(content); - if ($("script").length) { - throw new Error(`${filePath} contains a From 9fb7ce0a72c140ec1166e6b3d1399bfeaf882491 Mon Sep 17 00:00:00 2001 From: Sebastian Zartner Date: Tue, 16 Mar 2021 00:15:20 +0100 Subject: [PATCH 016/288] Added CSS Cascade Level 5 spec. to SpecData macro (#3227) --- kumascript/macros/SpecData.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kumascript/macros/SpecData.json b/kumascript/macros/SpecData.json index 2f2e216ccc5d..01908ad3cf74 100644 --- a/kumascript/macros/SpecData.json +++ b/kumascript/macros/SpecData.json @@ -484,6 +484,11 @@ "url": "https://drafts.csswg.org/css-writing-modes-4/", "status": "CR" }, + "CSS5 Cascade": { + "name": "CSS Cascading and Inheritance Level 5", + "url": "https://drafts.csswg.org/css-cascade-5/", + "status": "WD" + }, "CSS5 Media Queries": { "name": "Media Queries Level 5", "url": "https://drafts.csswg.org/mediaqueries-5/", From e5e65c4be334ce20b7c3c3dd066ab1b8e22e5d27 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 15 Mar 2021 19:24:39 -0400 Subject: [PATCH 017/288] only run scheduled workflows on mdn/yari (#3245) Part of #3229 --- .github/workflows/prod-build.yml | 3 +++ .github/workflows/stage-build.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/prod-build.yml b/.github/workflows/prod-build.yml index faf02fdee7b6..c69e4e379b7a 100644 --- a/.github/workflows/prod-build.yml +++ b/.github/workflows/prod-build.yml @@ -51,6 +51,9 @@ jobs: build: runs-on: ubuntu-latest + # Only run the scheduled workflows on the main repo. + if: github.repository == 'mdn/yari' + steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/stage-build.yml b/.github/workflows/stage-build.yml index 527987bd1184..29b5790b82f8 100644 --- a/.github/workflows/stage-build.yml +++ b/.github/workflows/stage-build.yml @@ -51,6 +51,9 @@ jobs: build: runs-on: ubuntu-latest + # Only run the scheduled workflows on the main repo. + if: github.repository == 'mdn/yari' + steps: - uses: actions/checkout@v2 From 5e6d3b74956b40340c2e6e0e65562a67a9314c68 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 15 Mar 2021 20:18:55 -0400 Subject: [PATCH 018/288] doing some more filecheck tests (#3251) --- testing/tests/filecheck.test.js | 23 +++++++++++++++++++++++ testing/tests/samplefiles/orphan.png | Bin 0 -> 592 bytes testing/tests/samplefiles/png.jpeg | Bin 0 -> 592 bytes testing/tests/samplefiles/zero.gif | 0 4 files changed, 23 insertions(+) create mode 100644 testing/tests/samplefiles/orphan.png create mode 100644 testing/tests/samplefiles/png.jpeg create mode 100644 testing/tests/samplefiles/zero.gif diff --git a/testing/tests/filecheck.test.js b/testing/tests/filecheck.test.js index 8dcc89ead234..5871fe713f1a 100644 --- a/testing/tests/filecheck.test.js +++ b/testing/tests/filecheck.test.js @@ -22,4 +22,27 @@ describe("checking files", () => { " contains an unsafe attribute: 'onload'" ); }); + + it("should spot files that are not mentioned in source", async () => { + const filePath = path.join(SAMPLES_DIRECTORY, "orphan.png"); + // Sanity check the test itself + console.assert(fs.existsSync(filePath), `${filePath} does not exist`); + await expect(checkFile(filePath)).rejects.toThrow("is not mentioned in"); + }); + + it("should spot files that are completely empty", async () => { + const filePath = path.join(SAMPLES_DIRECTORY, "zero.gif"); + // Sanity check the test itself + console.assert(fs.existsSync(filePath), `${filePath} does not exist`); + await expect(checkFile(filePath)).rejects.toThrow("is 0 bytes"); + }); + + it("should spot mismatch between file-type and file extension", async () => { + const filePath = path.join(SAMPLES_DIRECTORY, "png.jpeg"); + // Sanity check the test itself + console.assert(fs.existsSync(filePath), `${filePath} does not exist`); + await expect(checkFile(filePath)).rejects.toThrow( + "is type 'image/png' but named extension is '.jpeg'" + ); + }); }); diff --git a/testing/tests/samplefiles/orphan.png b/testing/tests/samplefiles/orphan.png new file mode 100644 index 0000000000000000000000000000000000000000..791501245adad69de482b0346060771ccd008719 GIT binary patch literal 592 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L9kgfz_MvJW-LO=$4iKnkC`(rj~em?#{n~4*ELc2X(978nDC#U>4-ym*aXb`ZX zf%RaI&FufZ{kh-YYp+p1qNlBNu5bI_^IuQF z`#%tT{yJ~X=b*W`YD|7g$lqlWinOK`h^=$~r#@B_cR-(Fms{Nj^4{{c~hKjPK5 z%Q(``uKJslzgI8no|0(7F`~Uv`|6H=mWD`@{|1|S_ z`QJ6N{Xizq|JM5pKS^r#`7%7b{CKnD_AFtbH&jbpBT7;dOH!?pi&B9UgOP!urLKXQ zu910&p{bRjiIt(Lwtt)x7$D3zhS zyj(9cFS|H7u^?41zbJk7I~ysWqVTGah?1bha)pAT{ItxRRE3htf>edff|6tghKf0l zKk;xBhG}S=@;`mX^Jx$Rvog0{GPkg@u=ivUW?==F29v`n%*vZX6i(l`a^lFDBQi(W fPd9ih@X}*=B`#R<$;oso&4-ym*aXb`ZX zf%RaI&FufZ{kh-YYp+p1qNlBNu5bI_^IuQF z`#%tT{yJ~X=b*W`YD|7g$lqlWinOK`h^=$~r#@B_cR-(Fms{Nj^4{{c~hKjPK5 z%Q(``uKJslzgI8no|0(7F`~Uv`|6H=mWD`@{|1|S_ z`QJ6N{Xizq|JM5pKS^r#`7%7b{CKnD_AFtbH&jbpBT7;dOH!?pi&B9UgOP!urLKXQ zu910&p{bRjiIt(Lwtt)x7$D3zhS zyj(9cFS|H7u^?41zbJk7I~ysWqVTGah?1bha)pAT{ItxRRE3htf>edff|6tghKf0l zKk;xBhG}S=@;`mX^Jx$Rvog0{GPkg@u=ivUW?==F29v`n%*vZX6i(l`a^lFDBQi(W fPd9ih@X}*=B`#R<$;oso& Date: Tue, 16 Mar 2021 07:01:39 +0000 Subject: [PATCH 019/288] build(deps): bump boto3 from 1.17.26 to 1.17.28 in /deployer (#3252) --- deployer/poetry.lock | 16 ++++++++-------- deployer/pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index 239c4c55ee5b..8f56f326bbf6 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -52,20 +52,20 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "boto3" -version = "1.17.26" +version = "1.17.28" description = "The AWS SDK for Python" category = "main" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] -botocore = ">=1.20.26,<1.21.0" +botocore = ">=1.20.28,<1.21.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] name = "botocore" -version = "1.20.26" +version = "1.20.28" description = "Low-level, data-driven core of boto 3." category = "main" optional = false @@ -479,7 +479,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "9c23cadee62150680d858c7c4ea9c46d43bc1d77d410f766872a3c47a64723c7" +content-hash = "a66c51cb8338c0f22b775dd06bcc4c468e8f97277006e1953cbb2440f210bc84" [metadata.files] appdirs = [ @@ -498,12 +498,12 @@ black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] boto3 = [ - {file = "boto3-1.17.26-py2.py3-none-any.whl", hash = "sha256:8e9ff8006c41889ed8a11831dee62adf922e071f14d54c52946d1f7855ae7a8e"}, - {file = "boto3-1.17.26.tar.gz", hash = "sha256:64a8900b3a110e2d6ff4d87f4d8cd56f0c8527361d9fc9385fcb50efe7a4975a"}, + {file = "boto3-1.17.28-py2.py3-none-any.whl", hash = "sha256:442c8579541661ab1dbbd2013d646506633bd1435368c217bd38acc01696992d"}, + {file = "boto3-1.17.28.tar.gz", hash = "sha256:ba13bda83ca1a26469fdf5130bb7a8f671dd807d0551e3242cafc8c44caab057"}, ] botocore = [ - {file = "botocore-1.20.26-py2.py3-none-any.whl", hash = "sha256:d27cbe115a25bfa82b851861b62d71fc771c2883bf5645bf37a7c0114789407c"}, - {file = "botocore-1.20.26.tar.gz", hash = "sha256:4a785847a351e59f2329627fc9a19cf50f07644ea68996a1595d5a20487a423f"}, + {file = "botocore-1.20.28-py2.py3-none-any.whl", hash = "sha256:75e6cfa246ec14863742c79ab8ddd887bd1b48c3d44268d53d69a5c6f472dee0"}, + {file = "botocore-1.20.28.tar.gz", hash = "sha256:6dde07154c37b552f52cbf8041541c5460a29d916f527b2098a36d44496c7126"}, ] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index b607840d70cd..00f0a2cdb4ef 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.7" click = "^7.1.2" -boto3 = "^1.17.26" +boto3 = "^1.17.28" python-decouple = "^3.4" requests = {extras = ["security"], version = "^2.25.0"} elasticsearch-dsl = "^7.3.0" From 98788b878f90c6a8ec051d0170b32c4e012d8642 Mon Sep 17 00:00:00 2001 From: Florian Dieminger Date: Tue, 16 Mar 2021 16:42:04 +0100 Subject: [PATCH 020/288] convert *_ROOT env to absolute paths (#3255) fixes #3220 --- content/constants.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/content/constants.js b/content/constants.js index 0088595db15d..74e8afaee1ba 100644 --- a/content/constants.js +++ b/content/constants.js @@ -10,6 +10,7 @@ let CONTENT_ROOT = process.env.CONTENT_ROOT; if (!CONTENT_ROOT) { throw new Error("Env var CONTENT_ROOT must be set"); } +CONTENT_ROOT = fs.realpathSync(CONTENT_ROOT); if ( path.basename(CONTENT_ROOT) !== "files" && fs.existsSync(path.join(CONTENT_ROOT, "files")) @@ -23,8 +24,8 @@ if ( throw new Error(`${path.resolve(CONTENT_ROOT)} does not exist`); } -const CONTENT_ARCHIVED_ROOT = process.env.CONTENT_ARCHIVED_ROOT; -const CONTENT_TRANSLATED_ROOT = process.env.CONTENT_TRANSLATED_ROOT; +let CONTENT_ARCHIVED_ROOT = process.env.CONTENT_ARCHIVED_ROOT; +let CONTENT_TRANSLATED_ROOT = process.env.CONTENT_TRANSLATED_ROOT; // This makes it possible to know, give a root folder, what is the name of // the repository on GitHub. @@ -41,6 +42,7 @@ if (CONTENT_ARCHIVED_ROOT) { if (!fs.existsSync(CONTENT_ARCHIVED_ROOT)) { throw new Error(`${path.resolve(CONTENT_ARCHIVED_ROOT)} does not exist`); } + CONTENT_ARCHIVED_ROOT = fs.realpathSync(CONTENT_ARCHIVED_ROOT); ROOTS.push(CONTENT_ARCHIVED_ROOT); REPOSITORY_URLS[CONTENT_ARCHIVED_ROOT] = "mdn/archived-content"; } @@ -48,6 +50,7 @@ if (CONTENT_TRANSLATED_ROOT) { if (!fs.existsSync(CONTENT_TRANSLATED_ROOT)) { throw new Error(`${path.resolve(CONTENT_TRANSLATED_ROOT)} does not exist`); } + CONTENT_TRANSLATED_ROOT = fs.realpathSync(CONTENT_TRANSLATED_ROOT); ROOTS.push(CONTENT_TRANSLATED_ROOT); REPOSITORY_URLS[CONTENT_TRANSLATED_ROOT] = "mdn/translated-content"; } From f72618bf577da36979face46b5c4f7786873b2f1 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 16 Mar 2021 13:17:06 -0400 Subject: [PATCH 021/288] Broken link checkers should fallback to en-US if possible (#3254) * Broken link checkers should fallback nicely to English if need be Fixes #3104 * remove debugging * adding tests --- build/flaws.js | 73 ++++++++++++++++--- kumascript/src/api/web.js | 2 +- testing/tests/index.test.js | 26 +++++++ .../files/fr/web/foo/index.html | 12 +++ 4 files changed, 103 insertions(+), 10 deletions(-) diff --git a/build/flaws.js b/build/flaws.js index 3f916527c532..6426a47daa74 100644 --- a/build/flaws.js +++ b/build/flaws.js @@ -25,6 +25,7 @@ const { } = require("./matches-in-text"); const { humanFileSize } = require("./utils"); const { VALID_MIME_TYPES } = require("../filecheck/constants"); +const { DEFAULT_LOCALE } = require("../libs/constants"); function injectFlaws(doc, $, options, document) { if (doc.isArchive) return; @@ -204,21 +205,37 @@ function injectBrokenLinksFlaws(doc, $, { rawContent }, level) { // us from calling `findMatchesInText()` more than once. const matches = new Map(); + function mutateLink($element, suggestion, enUSFallback) { + if (suggestion) { + $element.attr("href", suggestion); + } else if (enUSFallback) { + $element.attr("href", enUSFallback); + // This functionality here should match what we do inside + // the `web.smartLink()` function in kumascript rendering. + $element.text(`${$element.text()} (${DEFAULT_LOCALE})`); + $element.addClass("only-in-en-us"); + $element.attr("title", "Currently only available in English (US)"); + } else { + throw new Error("Don't use this function if neither is true"); + } + } + // A closure function to help making it easier to append flaws function addBrokenLink( $element, index, href, suggestion = null, - explanation + explanation = null, + enUSFallback = null ) { if (level === FLAW_LEVELS.IGNORE) { // Note, even if not interested in flaws, we still need to apply the // suggestion. For example, in production builds, we don't care about // logging flaws, but because not all `broken_links` flaws have been // manually fixed at the source. - if (suggestion) { - $element.attr("href", suggestion); + if (suggestion || enUSFallback) { + mutateLink($element, suggestion, enUSFallback); } return; } @@ -245,10 +262,9 @@ function injectBrokenLinksFlaws(doc, $, { rawContent }, level) { doc.flaws.broken_links = []; } const id = `link${doc.flaws.broken_links.length + 1}`; - let fixable = false; - if (suggestion) { - $element.attr("href", suggestion); - fixable = true; + const fixable = !!suggestion; + if (suggestion || enUSFallback) { + mutateLink($element, suggestion, enUSFallback); } $element.attr("data-flaw", id); doc.flaws.broken_links.push( @@ -297,7 +313,8 @@ function injectBrokenLinksFlaws(doc, $, { rawContent }, level) { !Image.findByURL(hrefNormalized) && !Archive.isArchivedURL(hrefNormalized) ) { - // Before we give up, check if it's a redirect. + // Even if it's a redirect, it's still a flaw, but it'll be nice to + // know what it *should* be. const resolved = Redirect.resolve(hrefNormalized); if (resolved !== hrefNormalized) { addBrokenLink( @@ -307,7 +324,45 @@ function injectBrokenLinksFlaws(doc, $, { rawContent }, level) { resolved + absoluteURL.search + absoluteURL.hash.toLowerCase() ); } else { - addBrokenLink(a, checked.get(href), href); + let enUSFallbackURL = null; + // Test if the document is a translated document and the link isn't + // to an en-US URL. We know the link is broken (in this locale!) + // but it might be "salvageable" if we link the en-US equivalent. + // This is, by the way, the same trick the `web.smartLink()` utility + // function does in kumascript rendering. + if ( + doc.locale !== DEFAULT_LOCALE && + href.startsWith(`/${doc.locale}/`) + ) { + // What if you swich to the English link; would th link work + // better then? + const enUSHrefNormalized = hrefNormalized.replace( + `/${doc.locale}/`, + `/${DEFAULT_LOCALE}/` + ); + let enUSFound = Document.findByURL(enUSHrefNormalized); + if (enUSFound) { + enUSFallbackURL = enUSFound.url; + } else { + const enUSResolved = Redirect.resolve(enUSHrefNormalized); + if (enUSResolved !== enUSHrefNormalized) { + enUSFallbackURL = + enUSResolved + + absoluteURL.search + + absoluteURL.hash.toLowerCase(); + } + } + } + addBrokenLink( + a, + checked.get(href), + href, + null, + enUSFallbackURL + ? "Can use the English (en-US) link as a fallback" + : null, + enUSFallbackURL + ); } } // But does it have the correct case?! diff --git a/kumascript/src/api/web.js b/kumascript/src/api/web.js index 71e3c86c9e9a..f682e191e6f0 100644 --- a/kumascript/src/api/web.js +++ b/kumascript/src/api/web.js @@ -99,7 +99,7 @@ module.exports = { flawAttribute = ` data-flaw-src="${util.htmlEscape(flaw.macroSource)}"`; return ( '${content} (en-US)` ); } diff --git a/testing/tests/index.test.js b/testing/tests/index.test.js index 9ee58b5ebc2e..dcd76fe36236 100644 --- a/testing/tests/index.test.js +++ b/testing/tests/index.test.js @@ -1299,3 +1299,29 @@ test("unsafe HTML gets flagged as flaws and replace with its raw HTML", () => { const $ = cheerio.load(html); expect($("code.unsafe-html").length).toBe(6); }); + +test("translated content broken links can fall back to en-us", () => { + const builtFolder = path.join(buildRoot, "fr", "docs", "web", "foo"); + const jsonFile = path.join(builtFolder, "index.json"); + + // We should be able to read it and expect certain values + const { doc } = JSON.parse(fs.readFileSync(jsonFile)); + const map = new Map(doc.flaws.broken_links.map((x) => [x.href, x])); + expect(map.get("/fr/docs/Web/CSS/dumber").explanation).toBe( + "Can use the English (en-US) link as a fallback" + ); + expect(map.get("/fr/docs/Web/CSS/number").explanation).toBe( + "Can use the English (en-US) link as a fallback" + ); + + const htmlFile = path.join(builtFolder, "index.html"); + const html = fs.readFileSync(htmlFile, "utf-8"); + const $ = cheerio.load(html); + expect($('article a[href="/fr/docs/Web/CSS/dumber"]').length).toBe(0); + expect($('article a[href="/fr/docs/Web/CSS/number"]').length).toBe(0); + expect($('article a[href="/en-US/docs/Web/CSS/number"]').length).toBe(2); + expect($("article a.only-in-en-us").length).toBe(2); + expect($("article a.only-in-en-us").attr("title")).toBe( + "Currently only available in English (US)" + ); +}); diff --git a/testing/translated-content/files/fr/web/foo/index.html b/testing/translated-content/files/fr/web/foo/index.html index 2940c8b5458e..67a34f931c1f 100644 --- a/testing/translated-content/files/fr/web/foo/index.html +++ b/testing/translated-content/files/fr/web/foo/index.html @@ -10,3 +10,15 @@ Capture d'écran des couleurs
    Une image parfaitement normale
    + +

    + This here demonstrates what happens when translated links exist but they're + actually broken. And in this case, what should happen is that it can fall back + on the en-US equivalent of those URLs. +

    + From 2072d119109b2d293273ef79488d00b2fe4fa875 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Tue, 16 Mar 2021 16:10:20 -0700 Subject: [PATCH 022/288] fix integration tests to reflect latest changes (#3259) --- testing/integration/headless/map_301.py | 2 +- testing/integration/headless/test_cdn.py | 6 +++--- testing/integration/headless/test_endpoints.py | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/testing/integration/headless/map_301.py b/testing/integration/headless/map_301.py index 6771a6754167..1c5abf7ee3d9 100644 --- a/testing/integration/headless/map_301.py +++ b/testing/integration/headless/map_301.py @@ -1039,7 +1039,7 @@ url_test("/en-US/Security/", "/en-US/docs/Security"), url_test("/en-US/Security/CSP/", "/en-US/docs/Security/CSP"), # Add trailing slash for the home page. - url_test("/en-US", "/en-US/"), + url_test("/en-US", "/en-US/", status_code=302), # Some special cases for "/docs". url_test("/docs", "/docs/Web"), url_test("/docs/", "/docs/Web"), diff --git a/testing/integration/headless/test_cdn.py b/testing/integration/headless/test_cdn.py index 06bbbe764ff4..06bee9beec29 100644 --- a/testing/integration/headless/test_cdn.py +++ b/testing/integration/headless/test_cdn.py @@ -139,7 +139,6 @@ def assert_cached( ("/healthz", 204, None), ("/readiness", 204, None), ("/api/v1/whoami", 200, None), - ("/api/v1/search/en-US?q=css", 200, None), ("/csp-violation-capture", 405, None), ("/en-US/profile", 302, "/en-US/users/signin?next=/en-US/profile"), ("/en-US/profile/edit", 302, "/en-US/users/signin?next=/en-US/profile/edit"), @@ -207,8 +206,9 @@ def test_not_cached(base_url, is_behind_cdn, slug, status, expected_location): ("/en-US/search/xml", 200, None), ("/en-US/search.json?q=yada", 301, "/api/v1/search?q=yada"), ("/en-US/search?q=css", 200, None), - ("/en-US/search/?q=css", 301, "/en-US/search?q=css"), - ("/en-US/search/?q=html", 301, "/en-US/search?q=html"), + ("/en-US/search/?q=css", 302, "/en-US/search?q=css"), + ("/en-US/search/?q=html", 302, "/en-US/search?q=html"), + ("/api/v1/search?q=css", 200, None), ("/en-US/Firefox", 302, "/en-US/docs/Mozilla/Firefox"), ("/en-US/docs/Web/HTML", 200, None), ], diff --git a/testing/integration/headless/test_endpoints.py b/testing/integration/headless/test_endpoints.py index 8f2269f557c6..1df4031a898e 100644 --- a/testing/integration/headless/test_endpoints.py +++ b/testing/integration/headless/test_endpoints.py @@ -136,7 +136,6 @@ def test_api_basic(base_url, uri, expected_keys): "/profile", "/profiles/sheppy", "/users/signin", - "/promote", "/account", ], ) From 49409d3aa64a2a46c8099eced487a658af3adb38 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 16 Mar 2021 20:44:21 -0400 Subject: [PATCH 023/288] Stop saying "Building roots:" twice (#3256) Fixes #3253 --- build/cli.js | 16 +++++++++++++++- content/document.js | 12 +----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/build/cli.js b/build/cli.js index 49b462d1da3c..bb55b76a41d0 100644 --- a/build/cli.js +++ b/build/cli.js @@ -2,6 +2,7 @@ const fs = require("fs"); const path = require("path"); const zlib = require("zlib"); +const chalk = require("chalk"); const cliProgress = require("cli-progress"); const program = require("@caporal/core").default; const { prompt } = require("inquirer"); @@ -10,7 +11,9 @@ const { Document, slugToFolder, translationsOf, + CONTENT_ROOT, CONTENT_TRANSLATED_ROOT, + CONTENT_ARCHIVED_ROOT, } = require("../content"); // eslint-disable-next-line node/no-missing-require @@ -279,7 +282,18 @@ program .action(async ({ args, options }) => { try { if (!options.quiet) { - console.log("\nBuilding Documents..."); + const roots = [ + ["CONTENT_ROOT", CONTENT_ROOT], + ["CONTENT_TRANSLATED_ROOT", CONTENT_TRANSLATED_ROOT], + ["CONTENT_ARCHIVED_ROOT", CONTENT_ARCHIVED_ROOT], + ]; + for (const [key, value] of roots) { + console.log( + `${chalk.grey((key + ":").padEnd(25, " "))}${ + value ? chalk.white(value) : chalk.grey("not set") + }` + ); + } } const { files } = args; const t0 = new Date(); diff --git a/content/document.js b/content/document.js index 1c2f266c9613..02044ffa3f8a 100644 --- a/content/document.js +++ b/content/document.js @@ -358,30 +358,20 @@ function findByURL(url, ...args) { return doc; } -function findAll({ - files = new Set(), - folderSearch = null, - quiet = false, -} = {}) { +function findAll({ files = new Set(), folderSearch = null } = {}) { if (!(files instanceof Set)) throw new TypeError("'files' not a Set"); if (folderSearch && typeof folderSearch !== "string") throw new TypeError("'folderSearch' not a string"); - // TODO: doesn't support archive content yet - // console.warn("Currently hardcoded to only build 'en-us'"); const filePaths = []; const roots = []; if (CONTENT_ARCHIVED_ROOT) { - // roots.push({ path: CONTENT_ARCHIVED_ROOT, isArchive: true }); roots.push(CONTENT_ARCHIVED_ROOT); } if (CONTENT_TRANSLATED_ROOT) { roots.push(CONTENT_TRANSLATED_ROOT); } roots.push(CONTENT_ROOT); - if (!quiet) { - console.log("Building roots:", roots); - } for (const root of roots) { filePaths.push( ...glob From 6aaa7b1e1408979032119fa67e7e11a758bd75b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Mar 2021 05:59:17 +0000 Subject: [PATCH 024/288] build(deps-dev): bump eslint-plugin-jest from 24.3.1 to 24.3.2 (#3262) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index dd94da3c06ae..50b8cf003ee7 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "downshift": "^6.1.0", "eslint": "^7.18.0", "eslint-gitignore": "^0.1.0", - "eslint-plugin-jest": "24.3.1", + "eslint-plugin-jest": "24.3.2", "eslint-plugin-node": "11.1.0", "extend": "^3.0.2", "flexsearch": "0.6.32", diff --git a/yarn.lock b/yarn.lock index 74ec9deb093c..3d3b1ad2441b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7412,10 +7412,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@24.3.1, eslint-plugin-jest@^24.1.0: - version "24.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.1.tgz#c8df037847b83397940bef7fbc2cc168ab466bcc" - integrity sha512-RQt59rfMSHyvedImT72iaf8JcvCcR4P7Uq499dALtjY8mrCjbwWrFi1UceG4sid2wVIeDi+0tjxXZ8CZEVO7Zw== +eslint-plugin-jest@24.3.2, eslint-plugin-jest@^24.1.0: + version "24.3.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.2.tgz#30a8b2dea6278d0da1d6fb9d6cd530aaf58050a1" + integrity sha512-cicWDr+RvTAOKS3Q/k03+Z3odt3VCiWamNUHWd6QWbVQWcYJyYgUTu8x0mx9GfeDEimawU5kQC+nQ3MFxIM6bw== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" From 7131a053ffebcb10d09145c1e08b3f1e1cfbb472 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Mar 2021 06:52:45 +0000 Subject: [PATCH 025/288] build(deps): bump boto3 from 1.17.28 to 1.17.29 in /deployer (#3263) --- deployer/poetry.lock | 19 +++++++++++-------- deployer/pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index 8f56f326bbf6..f2f0f6323c53 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -52,20 +52,20 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "boto3" -version = "1.17.28" +version = "1.17.29" description = "The AWS SDK for Python" category = "main" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] -botocore = ">=1.20.28,<1.21.0" +botocore = ">=1.20.29,<1.21.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] name = "botocore" -version = "1.20.28" +version = "1.20.29" description = "Low-level, data-driven core of boto 3." category = "main" optional = false @@ -76,6 +76,9 @@ jmespath = ">=0.7.1,<1.0.0" python-dateutil = ">=2.1,<3.0.0" urllib3 = ">=1.25.4,<1.27" +[package.extras] +crt = ["awscrt (==0.10.8)"] + [[package]] name = "certifi" version = "2020.12.5" @@ -479,7 +482,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "a66c51cb8338c0f22b775dd06bcc4c468e8f97277006e1953cbb2440f210bc84" +content-hash = "b3e37a230ca3371648e326bde0eb3f7856b9364ae310832e30873b19962f5004" [metadata.files] appdirs = [ @@ -498,12 +501,12 @@ black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] boto3 = [ - {file = "boto3-1.17.28-py2.py3-none-any.whl", hash = "sha256:442c8579541661ab1dbbd2013d646506633bd1435368c217bd38acc01696992d"}, - {file = "boto3-1.17.28.tar.gz", hash = "sha256:ba13bda83ca1a26469fdf5130bb7a8f671dd807d0551e3242cafc8c44caab057"}, + {file = "boto3-1.17.29-py2.py3-none-any.whl", hash = "sha256:bf8ced7760f9ef36964ccdba719f334a2ae6ec8a7719c259b198fec56fabad87"}, + {file = "boto3-1.17.29.tar.gz", hash = "sha256:31396fcaffdfc0f465b4de76e1ecae53894eb869b000ffa54aa1693a98db3a3c"}, ] botocore = [ - {file = "botocore-1.20.28-py2.py3-none-any.whl", hash = "sha256:75e6cfa246ec14863742c79ab8ddd887bd1b48c3d44268d53d69a5c6f472dee0"}, - {file = "botocore-1.20.28.tar.gz", hash = "sha256:6dde07154c37b552f52cbf8041541c5460a29d916f527b2098a36d44496c7126"}, + {file = "botocore-1.20.29-py2.py3-none-any.whl", hash = "sha256:5a26ad20662f8e15685889a17c62a2f8804bf02fcdea59f45ad993b261f9caa2"}, + {file = "botocore-1.20.29.tar.gz", hash = "sha256:184b7d26b0669fd65ac8193662376d1267d800e005b69412b57cc82c5ffbe935"}, ] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index 00f0a2cdb4ef..a1a764877947 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.7" click = "^7.1.2" -boto3 = "^1.17.28" +boto3 = "^1.17.29" python-decouple = "^3.4" requests = {extras = ["security"], version = "^2.25.0"} elasticsearch-dsl = "^7.3.0" From 25408d9970c29a57698a1e97195786c67908067c Mon Sep 17 00:00:00 2001 From: Rachel Andrew Date: Wed, 17 Mar 2021 10:21:10 +0000 Subject: [PATCH 026/288] adds Level 5 Color Spec (#3265) --- kumascript/macros/SpecData.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kumascript/macros/SpecData.json b/kumascript/macros/SpecData.json index 01908ad3cf74..f85523f3afb2 100644 --- a/kumascript/macros/SpecData.json +++ b/kumascript/macros/SpecData.json @@ -489,6 +489,11 @@ "url": "https://drafts.csswg.org/css-cascade-5/", "status": "WD" }, + "CSS5 Colors": { + "name": "CSS Color Module Level 5", + "url": "https://drafts.csswg.org/css-color-5/", + "status": "WD" + }, "CSS5 Media Queries": { "name": "Media Queries Level 5", "url": "https://drafts.csswg.org/mediaqueries-5/", From d75d6075e01ca9a0ba838cc97ce20ff128bd8e42 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Wed, 17 Mar 2021 16:13:48 -0400 Subject: [PATCH 027/288] CompatibilityTable.ejs injects HTML that's considered unsafe (#3270) Fixes #3269 --- kumascript/macros/CompatibilityTable.ejs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kumascript/macros/CompatibilityTable.ejs b/kumascript/macros/CompatibilityTable.ejs index 3ecfc2b2736c..cc9afb5b3d58 100644 --- a/kumascript/macros/CompatibilityTable.ejs +++ b/kumascript/macros/CompatibilityTable.ejs @@ -42,7 +42,7 @@ var cta = mdn.localString({ From aaec11ebf336b58ec92eff065b99dd867d5daa2f Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Wed, 17 Mar 2021 16:20:10 -0400 Subject: [PATCH 028/288] Don't choke on iframes without a src (#3272) Fixes #3271 --- build/flaws.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/flaws.js b/build/flaws.js index 6426a47daa74..b64d624d1589 100644 --- a/build/flaws.js +++ b/build/flaws.js @@ -75,7 +75,7 @@ function injectFlaws(doc, $, options, document) { } } -function injectUnsafeHTMLFlaws(doc, $, { rawContent }) { +function injectUnsafeHTMLFlaws(doc, $, { rawContent, fileInfo }) { function addFlaw(element, explanation) { if (!("unsafe_html" in doc.flaws)) { doc.flaws.unsafe_html = []; @@ -131,6 +131,12 @@ function injectUnsafeHTMLFlaws(doc, $, { rawContent }) { if (tagName === "iframe") { // For iframes we only check the 'src' value const src = $(element).attr("src"); + if (!src) { + console.warn( + `${fileInfo.path} has an iframe without a 'src' attribute` + ); + return; + } // Local URLs are always safe. if (!(src.startsWith("//") || src.includes("://"))) { return; From 24f5df309d5b1961c56d2c13ae9cd33be2db15f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Mar 2021 05:59:50 +0000 Subject: [PATCH 029/288] build(deps-dev): bump @types/jest from 26.0.20 to 26.0.21 (#3275) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 50b8cf003ee7..dbcf633a787d 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@storybook/preset-create-react-app": "^3.1.6", "@storybook/react": "^6.1.21", "@testing-library/react": "^11.2.5", - "@types/jest": "^26.0.20", + "@types/jest": "^26.0.21", "@types/react": "^17.0.3", "@types/react-dom": "^17.0.2", "braces": "^3.0.2", diff --git a/yarn.lock b/yarn.lock index 3d3b1ad2441b..d29083635865 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2997,10 +2997,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.20": - version "26.0.20" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307" - integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA== +"@types/jest@^26.0.21": + version "26.0.21" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.21.tgz#3a73c2731e7e4f0fbaea56ce7ff8c79cf812bd24" + integrity sha512-ab9TyM/69yg7eew9eOwKMUmvIZAKEGZYlq/dhe5/0IMUd/QLJv5ldRMdddSn+u22N13FP3s5jYyktxuBwY0kDA== dependencies: jest-diff "^26.0.0" pretty-format "^26.0.0" From 7884a08738a6a2bbd6fa9f24e754392af8e62a42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Mar 2021 06:01:30 +0000 Subject: [PATCH 030/288] build(deps): bump tempy from 1.0.0 to 1.0.1 (#3276) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index dbcf633a787d..af2d37d40648 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "sanitize-filename": "^1.6.3", "send": "0.17.1", "source-map-support": "0.5.19", - "tempy": "1.0.0" + "tempy": "1.0.1" }, "devDependencies": { "@babel/core": "^7.13.10", diff --git a/yarn.lock b/yarn.lock index d29083635865..d1c44f9fda37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17013,10 +17013,10 @@ tempfile@^2.0.0: temp-dir "^1.0.0" uuid "^3.0.1" -tempy@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/tempy/-/tempy-1.0.0.tgz#4f192b3ee3328a2684d0e3fc5c491425395aab65" - integrity sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w== +tempy@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tempy/-/tempy-1.0.1.tgz#30fe901fd869cfb36ee2bd999805aa72fbb035de" + integrity sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w== dependencies: del "^6.0.0" is-stream "^2.0.0" From 1950c5535678225c6b964746e48653290ba9afac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Mar 2021 07:02:16 +0000 Subject: [PATCH 031/288] build(deps): bump boto3 from 1.17.29 to 1.17.30 in /deployer (#3277) --- deployer/poetry.lock | 16 ++++++++-------- deployer/pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index f2f0f6323c53..4395de5c1f06 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -52,20 +52,20 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "boto3" -version = "1.17.29" +version = "1.17.30" description = "The AWS SDK for Python" category = "main" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] -botocore = ">=1.20.29,<1.21.0" +botocore = ">=1.20.30,<1.21.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] name = "botocore" -version = "1.20.29" +version = "1.20.30" description = "Low-level, data-driven core of boto 3." category = "main" optional = false @@ -482,7 +482,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "b3e37a230ca3371648e326bde0eb3f7856b9364ae310832e30873b19962f5004" +content-hash = "fece341f13f2a5cc7d43fc902fbbec6318d921445d32969a5215c8bcae13adb2" [metadata.files] appdirs = [ @@ -501,12 +501,12 @@ black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] boto3 = [ - {file = "boto3-1.17.29-py2.py3-none-any.whl", hash = "sha256:bf8ced7760f9ef36964ccdba719f334a2ae6ec8a7719c259b198fec56fabad87"}, - {file = "boto3-1.17.29.tar.gz", hash = "sha256:31396fcaffdfc0f465b4de76e1ecae53894eb869b000ffa54aa1693a98db3a3c"}, + {file = "boto3-1.17.30-py2.py3-none-any.whl", hash = "sha256:fe1898c5b10035528207995c9931b78f2f50bb70cf93bac353152aea47c04780"}, + {file = "boto3-1.17.30.tar.gz", hash = "sha256:d39c04b51e60197f5503f8489f043bc904981567cc8431d389367767dc3fd5ae"}, ] botocore = [ - {file = "botocore-1.20.29-py2.py3-none-any.whl", hash = "sha256:5a26ad20662f8e15685889a17c62a2f8804bf02fcdea59f45ad993b261f9caa2"}, - {file = "botocore-1.20.29.tar.gz", hash = "sha256:184b7d26b0669fd65ac8193662376d1267d800e005b69412b57cc82c5ffbe935"}, + {file = "botocore-1.20.30-py2.py3-none-any.whl", hash = "sha256:63951595a736dfc9759f57e33bec6eaea4f09c4800626ef5309437060b263e48"}, + {file = "botocore-1.20.30.tar.gz", hash = "sha256:98ff1eb210d394a1ffe736b33c8a7be68f30f0a03550b559c5bb6fdf0c29328d"}, ] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index a1a764877947..e197857897b6 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.7" click = "^7.1.2" -boto3 = "^1.17.29" +boto3 = "^1.17.30" python-decouple = "^3.4" requests = {extras = ["security"], version = "^2.25.0"} elasticsearch-dsl = "^7.3.0" From 9857a0ebc57cf3b57ccb6fa9ad1a8b45228d2c78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Mar 2021 08:17:51 +0000 Subject: [PATCH 032/288] build(deps-dev): bump @storybook/preset-create-react-app (#3178) --- package.json | 2 +- yarn.lock | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index af2d37d40648..9547951774fd 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "@storybook/addon-essentials": "^6.1.21", "@storybook/addon-links": "^6.1.21", "@storybook/node-logger": "^6.1.19", - "@storybook/preset-create-react-app": "^3.1.6", + "@storybook/preset-create-react-app": "^3.1.7", "@storybook/react": "^6.1.21", "@testing-library/react": "^11.2.5", "@types/jest": "^26.0.21", diff --git a/yarn.lock b/yarn.lock index d1c44f9fda37..7edd6204053b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1984,7 +1984,7 @@ dependencies: mkdirp "^1.0.4" -"@pmmmwh/react-refresh-webpack-plugin@0.4.3", "@pmmmwh/react-refresh-webpack-plugin@^0.4.2": +"@pmmmwh/react-refresh-webpack-plugin@0.4.3", "@pmmmwh/react-refresh-webpack-plugin@^0.4.2", "@pmmmwh/react-refresh-webpack-plugin@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz#1eec460596d200c0236bf195b078a5d1df89b766" integrity sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ== @@ -2526,11 +2526,12 @@ dependencies: core-js "^3.0.1" -"@storybook/preset-create-react-app@^3.1.6": - version "3.1.6" - resolved "https://registry.yarnpkg.com/@storybook/preset-create-react-app/-/preset-create-react-app-3.1.6.tgz#fdcc332343085d26fe50891be484c830921f2688" - integrity sha512-hH8g5bBqNVU1zl2K19fXazncaWX2eiOX+ZHN3RtfQioAgHtXH/S1TS92xJj7uxoU40GYjldRmv7+fhzJCyRxNg== +"@storybook/preset-create-react-app@^3.1.7": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@storybook/preset-create-react-app/-/preset-create-react-app-3.1.7.tgz#e48df77768bdcc4863e3918c11965c45e4110ac8" + integrity sha512-SR+HGSWCrhHA5sszuIHJYdh2tWNi/zu858WB5RM74OBW4ogo8Bv4/7td4p53eWbdm0zBDbnKcrBmwRrAYqwL9Q== dependencies: + "@pmmmwh/react-refresh-webpack-plugin" "^0.4.3" "@types/babel__core" "^7.1.7" "@types/webpack" "^4.41.13" babel-plugin-react-docgen "^4.1.0" From f93f197bd93c1d89e745f18bf2c64d80d5c0dd30 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Thu, 18 Mar 2021 08:22:46 -0400 Subject: [PATCH 033/288] account settings app (#3130) --- build/languages.json | 518 +++++++++++++++++++++++++++++++++ build/spas.js | 35 ++- client/src/app.tsx | 9 + client/src/index.tsx | 2 + client/src/settings/app.tsx | 385 ++++++++++++++++++++++++ client/src/settings/index.tsx | 31 ++ server/static.js | 45 ++- ssr/render.js | 8 + testing/tests/headless.test.js | 26 ++ testing/tests/index.test.js | 18 ++ 10 files changed, 1074 insertions(+), 3 deletions(-) create mode 100644 build/languages.json create mode 100644 client/src/settings/app.tsx create mode 100644 client/src/settings/index.tsx diff --git a/build/languages.json b/build/languages.json new file mode 100644 index 000000000000..f1a53eb0e021 --- /dev/null +++ b/build/languages.json @@ -0,0 +1,518 @@ +{ + "ach": { + "English": "Acholi", + "native": "Acholi" + }, + "ak": { + "English": "Akan", + "native": "Akan" + }, + "am-et": { + "English": "Amharic", + "native": "\u12a0\u121b\u122d\u129b" + }, + "an": { + "English": "Aragonese", + "native": "aragon\u00e9s" + }, + "ar": { + "English": "Arabic", + "native": "\u0639\u0631\u0628\u064a" + }, + "as": { + "English": "Assamese", + "native": "\u0985\u09b8\u09ae\u09c0\u09af\u09bc\u09be" + }, + "ast": { + "English": "Asturian", + "native": "Asturianu" + }, + "azz": { + "English": "Highland Puebla Nahuatl", + "native": "nahuatl sierra norte Puebla" + }, + "be": { + "English": "Belarusian", + "native": "\u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f" + }, + "bg": { + "English": "Bulgarian", + "native": "\u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438" + }, + "bm": { + "English": "Bambara", + "native": "Bamanankan" + }, + "bn": { + "English": "Bengali", + "native": "\u09ac\u09be\u0982\u09b2\u09be" + }, + "br": { + "English": "Breton", + "native": "Brezhoneg" + }, + "brx": { + "English": "Bodo", + "native": "\u092c\u0930'" + }, + "bs": { + "English": "Bosnian", + "native": "Bosanski" + }, + "ca": { + "English": "Catalan", + "native": "Catal\u00e0" + }, + "ca-valencia": { + "English": "Catalan (Valencian)", + "native": "catal\u00e0 (valenci\u00e0)" + }, + "cak": { + "English": "Kaqchikel", + "native": "Maya Kaqchikel" + }, + "csb": { + "English": "Kashubian", + "native": "Kasz\u00ebbsczi" + }, + "cy": { + "English": "Welsh", + "native": "Cymraeg" + }, + "da": { + "English": "Danish", + "native": "Dansk" + }, + "dbg": { + "English": "Debug Robot", + "native": "\u1e12\u1e17\u0180\u016d\u0260 \u0158\u01ff\u0180\u01ff\u0167" + }, + "de": { + "English": "German", + "native": "Deutsch" + }, + "de-AT": { + "English": "German (Austria)", + "native": "Deutsch (\u00d6sterreich)" + }, + "de-CH": { + "English": "German (Switzerland)", + "native": "Deutsch (Schweiz)" + }, + "de-DE": { + "English": "German (Germany)", + "native": "Deutsch (Deutschland)" + }, + "dsb": { + "English": "Lower Sorbian", + "native": "Dolnoserb\u0161\u0107ina" + }, + "el": { + "English": "Greek", + "native": "\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac" + }, + "en-AU": { + "English": "English (Australian)", + "native": "English (Australian)" + }, + "en-CA": { + "English": "English (Canadian)", + "native": "English (Canadian)" + }, + "en-GB": { + "English": "English (British)", + "native": "English (British)" + }, + "en-NZ": { + "English": "English (New Zealand)", + "native": "English (New Zealand)" + }, + "en-US": { + "English": "English (US)", + "native": "English (US)" + }, + "en-ZA": { + "English": "English (South African)", + "native": "English (South African)" + }, + "eo": { + "English": "Esperanto", + "native": "Esperanto" + }, + "es": { + "English": "Spanish", + "native": "Espa\u00f1ol" + }, + "es-AR": { + "English": "Spanish (Argentina)", + "native": "Espa\u00f1ol (de Argentina)" + }, + "es-CL": { + "English": "Spanish (Chile)", + "native": "Espa\u00f1ol (de Chile)" + }, + "es-ES": { + "English": "Spanish (Spain)", + "native": "Espa\u00f1ol (de Espa\u00f1a)" + }, + "es-MX": { + "English": "Spanish (Mexico)", + "native": "Espa\u00f1ol (de M\u00e9xico)" + }, + "et": { + "English": "Estonian", + "native": "Eesti keel" + }, + "eu": { + "English": "Basque", + "native": "Euskara" + }, + "fa": { + "English": "Persian", + "native": "\u0641\u0627\u0631\u0633\u06cc" + }, + "fi": { + "English": "Finnish", + "native": "suomi" + }, + "fj-FJ": { + "English": "Fijian", + "native": "Vosa vaka-Viti" + }, + "fr": { + "English": "French", + "native": "Fran\u00e7ais" + }, + "fur-IT": { + "English": "Friulian", + "native": "Furlan" + }, + "ga": { + "English": "Irish", + "native": "Gaeilge" + }, + "gd": { + "English": "Gaelic (Scotland)", + "native": "G\u00e0idhlig" + }, + "gl": { + "English": "Galician", + "native": "Galego" + }, + "gn": { + "English": "Guarani", + "native": "Ava\u00f1e'\u1ebd" + }, + "gu": { + "English": "Gujarati", + "native": "\u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0" + }, + "gu-IN": { + "English": "Gujarati (India)", + "native": "\u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0 (\u0aad\u0abe\u0ab0\u0aa4)" + }, + "he": { + "English": "Hebrew", + "native": "\u05e2\u05d1\u05e8\u05d9\u05ea" + }, + "hi": { + "English": "Hindi", + "native": "\u0939\u093f\u0928\u094d\u0926\u0940" + }, + "hi-IN": { + "English": "Hindi (India)", + "native": "\u0939\u093f\u0928\u094d\u0926\u0940 (\u092d\u093e\u0930\u0924)" + }, + "hsb": { + "English": "Upper Sorbian", + "native": "Hornjoserbsce" + }, + "hu": { + "English": "Hungarian", + "native": "magyar" + }, + "hy-AM": { + "English": "Armenian", + "native": "\u0540\u0561\u0575\u0565\u0580\u0565\u0576" + }, + "ia": { + "English": "Interlingua", + "native": "Interlingua" + }, + "id": { + "English": "Indonesian", + "native": "Bahasa Indonesia" + }, + "is": { + "English": "Icelandic", + "native": "\u00edslenska" + }, + "it": { + "English": "Italian", + "native": "Italiano" + }, + "ja": { + "English": "Japanese", + "native": "\u65e5\u672c\u8a9e" + }, + "ja-JP-mac": { + "English": "Japanese", + "native": "\u65e5\u672c\u8a9e" + }, + "kab": { + "English": "Kabyle", + "native": "Taqbaylit" + }, + "kk": { + "English": "Kazakh", + "native": "\u049a\u0430\u0437\u0430\u049b" + }, + "km": { + "English": "Khmer", + "native": "\u1781\u17d2\u1798\u17c2\u179a" + }, + "kn": { + "English": "Kannada", + "native": "\u0c95\u0ca8\u0ccd\u0ca8\u0ca1" + }, + "ko": { + "English": "Korean", + "native": "\ud55c\uad6d\uc5b4" + }, + "kok": { + "English": "Konkani", + "native": "\u0915\u094b\u0902\u0915\u0928\u0940" + }, + "ku": { + "English": "Kurdish", + "native": "Kurd\u00ee" + }, + "ks": { + "English": "Kashmiri", + "native": "\u0643\u0634\u0645\u06cc\u0631\u06cc" + }, + "la": { + "English": "Latin", + "native": "Latina" + }, + "lg": { + "English": "Luganda", + "native": "Luganda" + }, + "lij": { + "English": "Ligurian", + "native": "Ligure" + }, + "lo": { + "English": "Lao", + "native": "\u0e9e\u0eb2\u0eaa\u0eb2\u0ea5\u0eb2\u0ea7" + }, + "lt": { + "English": "Lithuanian", + "native": "Lietuvi\u0173" + }, + "ltg": { + "English": "Latgalian", + "native": "Latgalie\u0161u valoda" + }, + "lv": { + "English": "Latvian", + "native": "Latvie\u0161u" + }, + "mai": { + "English": "Maithili", + "native": "\u092e\u0948\u0925\u093f\u0932\u0940 \u09ae\u09c8\u09a5\u09bf\u09b2\u09c0" + }, + "mi": { + "English": "Maori (Aotearoa)", + "native": "M\u0101ori (Aotearoa)" + }, + "mk": { + "English": "Macedonian", + "native": "\u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438" + }, + "mn": { + "English": "Mongolian", + "native": "\u041c\u043e\u043d\u0433\u043e\u043b" + }, + "mr": { + "English": "Marathi", + "native": "\u092e\u0930\u093e\u0920\u0940" + }, + "ms": { + "English": "Malay", + "native": "Melayu" + }, + "my": { + "English": "Burmese", + "native": "\u1019\u103c\u1014\u103a\u1019\u102c\u1018\u102c\u101e\u102c" + }, + "nb-NO": { + "English": "Norwegian (Bokm\u00e5l)", + "native": "Norsk bokm\u00e5l" + }, + "ne-NP": { + "English": "Nepali", + "native": "\u0928\u0947\u092a\u093e\u0932\u0940" + }, + "nn-NO": { + "English": "Norwegian (Nynorsk)", + "native": "Norsk nynorsk" + }, + "nl": { + "English": "Dutch", + "native": "Nederlands" + }, + "nr": { + "English": "Ndebele, South", + "native": "isiNdebele" + }, + "nso": { + "English": "Northern Sotho", + "native": "Sepedi" + }, + "oc": { + "English": "Occitan (Lengadocian)", + "native": "occitan (lengadocian)" + }, + "or": { + "English": "Odia", + "native": "\u0b13\u0b21\u0b3c\u0b3f\u0b06" + }, + "pa": { + "English": "Punjabi", + "native": "\u0a2a\u0a70\u0a1c\u0a3e\u0a2c\u0a40" + }, + "pa-IN": { + "English": "Punjabi (India)", + "native": "\u0a2a\u0a70\u0a1c\u0a3e\u0a2c\u0a40 (\u0a2d\u0a3e\u0a30\u0a24)" + }, + "pl": { + "English": "Polish", + "native": "Polski" + }, + "pt-BR": { + "English": "Portuguese (Brazilian)", + "native": "Portugu\u00eas (do\u00a0Brasil)" + }, + "pt-PT": { + "English": "Portuguese (Portugal)", + "native": "Portugu\u00eas (Europeu)" + }, + "rm": { + "English": "Romansh", + "native": "rumantsch" + }, + "ru": { + "English": "Russian", + "native": "\u0420\u0443\u0441\u0441\u043a\u0438\u0439" + }, + "rw": { + "English": "Kinyarwanda", + "native": "Ikinyarwanda" + }, + "sa": { + "English": "Sanskrit", + "native": "\u0938\u0902\u0938\u094d\u0915\u0943\u0924" + }, + "sat": { + "English": "Santali", + "native": "\u0938\u0902\u0924\u093e\u0932\u0940" + }, + "sah": { + "English": "Sakha", + "native": "\u0421\u0430\u0445\u0430\u043b\u044b\u044b" + }, + "si": { + "English": "Sinhala", + "native": "\u0dc3\u0dd2\u0d82\u0dc4\u0dbd" + }, + "sk": { + "English": "Slovak", + "native": "sloven\u010dina" + }, + "sl": { + "English": "Slovenian", + "native": "Sloven\u0161\u010dina" + }, + "sr-Cyrl": { + "English": "Serbian", + "native": "\u0421\u0440\u043f\u0441\u043a\u0438" + }, + "ss": { + "English": "Siswati", + "native": "siSwati" + }, + "st": { + "English": "Southern Sotho", + "native": "Sesotho" + }, + "sv-SE": { + "English": "Swedish", + "native": "Svenska" + }, + "ta-IN": { + "English": "Tamil (India)", + "native": "\u0ba4\u0bae\u0bbf\u0bb4\u0bcd (\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe)" + }, + "ta-LK": { + "English": "Tamil (Sri Lanka)", + "native": "\u0ba4\u0bae\u0bbf\u0bb4\u0bcd (\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8)" + }, + "th": { + "English": "Thai", + "native": "\u0e44\u0e17\u0e22" + }, + "tr": { + "English": "Turkish", + "native": "T\u00fcrk\u00e7e" + }, + "trs": { + "English": "Triqui", + "native": "Triqui" + }, + "ts": { + "English": "Tsonga", + "native": "Xitsonga" + }, + "tsz": { + "English": "Pur\u00e9pecha", + "native": "Pur\u00e9pecha" + }, + "tt-RU": { + "English": "Tatar", + "native": "Tatar\u00e7a" + }, + "uk": { + "English": "Ukrainian", + "native": "\u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430" + }, + "ur": { + "English": "Urdu", + "native": "\u0627\u064f\u0631\u062f\u0648" + }, + "uz": { + "English": "Uzbek", + "native": "O\u02bbzbek tili" + }, + "ve": { + "English": "Venda", + "native": "Tshiven\u1e13a" + }, + "vi": { + "English": "Vietnamese", + "native": "Ti\u1ebfng Vi\u1ec7t" + }, + "x-testing": { + "English": "Testing", + "native": "\u0166\u1e17\u015f\u0167\u012b\u019e\u0260" + }, + "zh-CN": { + "English": "Chinese (Simplified)", + "native": "\u4e2d\u6587 (\u7b80\u4f53)" + }, + "zh-TW": { + "English": "Chinese (Traditional)", + "native": "\u6b63\u9ad4\u4e2d\u6587 (\u7e41\u9ad4)" + } +} diff --git a/build/spas.js b/build/spas.js index 09f9e5043975..f948cf3fd08e 100644 --- a/build/spas.js +++ b/build/spas.js @@ -1,7 +1,11 @@ const fs = require("fs"); const path = require("path"); -const { CONTENT_ROOT, CONTENT_TRANSLATED_ROOT } = require("../content"); +const { + CONTENT_ROOT, + CONTENT_TRANSLATED_ROOT, + VALID_LOCALES, +} = require("../content"); const { BUILD_OUT_ROOT, HOMEPAGE_FEED_URL, @@ -11,6 +15,14 @@ const { getFeedEntries } = require("./feedparser"); // eslint-disable-next-line node/no-missing-require const { renderHTML } = require("../ssr/dist/main"); +function getLanguages() { + return new Map( + Object.entries( + JSON.parse(fs.readFileSync(path.join(__dirname, "languages.json"))) + ) + ); +} + async function buildSPAs(options) { let buildCount = 0; @@ -39,10 +51,21 @@ async function buildSPAs(options) { { prefix: "search", pageTitle: "Search" }, { prefix: "signin", pageTitle: "Sign in" }, { prefix: "signup", pageTitle: "Sign up" }, + { prefix: "settings", pageTitle: "Settings" }, ]; for (const { prefix, pageTitle } of SPAs) { const url = `/${locale}/${prefix}`; - const html = renderHTML(url, { pageTitle }); + const context = { pageTitle }; + if (prefix === "settings") { + // This SPA needs a list of all valid locales + const languages = getLanguages(); + context.possibleLocales = [...VALID_LOCALES.values()].map( + (locale) => { + return Object.assign({ locale }, languages.get(locale)); + } + ); + } + const html = renderHTML(url, context); const outPath = path.join(BUILD_OUT_ROOT, locale, prefix); fs.mkdirSync(outPath, { recursive: true }); const filePath = path.join(outPath, "index.html"); @@ -51,6 +74,14 @@ async function buildSPAs(options) { if (options.verbose) { console.log("Wrote", filePath); } + if (prefix === "settings") { + const filePathContext = path.join(outPath, "index.json"); + fs.writeFileSync(filePathContext, JSON.stringify(context)); + buildCount++; + if (options.verbose) { + console.log("Wrote", filePathContext); + } + } } } } diff --git a/client/src/app.tsx b/client/src/app.tsx index 883319bc758a..15b36a19dfa3 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -16,6 +16,7 @@ import { PageContentContainer } from "./ui/atoms/page-content"; import { PageNotFound } from "./page-not-found"; import { Banner } from "./banners"; import { SignIn, SignUp } from "./auth"; +import { Settings } from "./settings"; const AllFlaws = React.lazy(() => import("./flaws")); const DocumentEdit = React.lazy(() => import("./document/forms/edit")); @@ -223,6 +224,14 @@ export function App(appProps) { } /> + + + + } + /> } diff --git a/client/src/index.tsx b/client/src/index.tsx index b53640a04a9c..a80840f20977 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -22,6 +22,7 @@ if (!container) { const docData = (window as any).__data__; const pageNotFound = (window as any).__pageNotFound__; const feedEntries = (window as any).__feedEntries__; +const possibleLocales = (window as any).__possibleLocales__; let app = ( @@ -31,6 +32,7 @@ let app = ( doc={docData} pageNotFound={pageNotFound} feedEntries={feedEntries} + possibleLocales={possibleLocales} /> diff --git a/client/src/settings/app.tsx b/client/src/settings/app.tsx new file mode 100644 index 000000000000..ed7039daf831 --- /dev/null +++ b/client/src/settings/app.tsx @@ -0,0 +1,385 @@ +import React from "react"; +import { Link, useNavigate } from "react-router-dom"; +import useSWR, { mutate } from "swr"; + +import { DISABLE_AUTH } from "../constants"; +import { useUserData } from "../user-context"; +import { useLocale } from "../hooks"; + +interface UserSettings { + csrfmiddlewaretoken: string; + locale: string; +} + +interface Locale { + locale: string; + native: string; + English: string; +} + +interface SettingsData { + possibleLocales: Locale[]; +} + +export default function SettingsApp({ ...appProps }) { + // This app is only ever loaded in the client so we can use `window` + let settingsDataURL = window.location.pathname; + if (!settingsDataURL.endsWith("/")) { + settingsDataURL += "/"; + } + settingsDataURL += "index.json"; + + const { data: settingsData, error: settingsError } = useSWR( + settingsDataURL, + async (url) => { + const response = await fetch(url); + if (!response.ok) { + const text = await response.text(); + throw new Error(`${response.status} on ${url}: ${text}`); + } + return await response.json(); + }, + { + initialData: appProps.possibleLocales + ? { possibleLocales: appProps.possibleLocales } + : undefined, + revalidateOnFocus: false, + } + ); + const userData = useUserData(); + + const { data, error } = useSWR( + userData ? "/api/v1/settings" : null, + async (url) => { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`${response.status} on ${response.url}`); + } + const data = (await response.json()) as UserSettings; + return data; + } + ); + + if (DISABLE_AUTH) { + return ; + } + + if (!userData) { + // The XHR request hasn't finished yet so we don't know if the user is + // signed in or not. + return ; + } + if (!userData.isAuthenticated) { + return ; + } + + if (error) { + return ( +
    +

    Server error

    +

    A server error occurred trying to get your user settings.

    +

    + {error.toString()} +

    + Reload this page and try again. +
    + ); + } + + if (!data) { + return ; + } + + if (settingsError) { + return ( +
    +

    Server error

    +

    Unable to get the current user settings from the server.

    +

    + {settingsError.toString()} +

    + Reload this page and try again. +
    + ); + } + + return ( +
    + {settingsData && + settingsData.possibleLocales && + settingsData.possibleLocales.length && ( + { + // This will "force" a new XHR request in the useUserData hook. + mutate("/api/v1/whoami"); + + mutate("/api/v1/settings"); + }} + /> + )} + +
    + ); +} + +function AuthDisabled() { + return ( +
    +

    Authentication disabled

    +

    Authentication and the user settings app is currently disabled.

    +
    + ); +} + +function Loading() { + return

    Loading...

    ; +} + +function NotSignedIn() { + const locale = useLocale(); + const sp = new URLSearchParams(); + sp.set("next", window.location.pathname); + + return ( +
    +

    You are not signed in

    + Sign in first +
    + ); +} + +interface ValidationErrorMessage { + message: string; + code: string; +} + +interface ValidationError { + [key: string]: ValidationErrorMessage[]; +} +interface ValidationErrors { + errors: ValidationError; +} + +function Settings({ + userSettings, + settingsData, + refreshUserSettings, +}: { + userSettings: UserSettings; + settingsData: SettingsData; + refreshUserSettings: () => void; +}) { + const [locale, setLocale] = React.useState(userSettings.locale); + + const [sent, setSent] = React.useState(false); + const [sendError, setSendError] = React.useState(null); + const [ + validationErrors, + setValidationErrors, + ] = React.useState(null); + + async function sendSettings() { + const formData = new URLSearchParams(); + formData.set("locale", locale); + + const response = await fetch("/api/v1/settings", { + method: "POST", + headers: { + "X-CSRFToken": userSettings.csrfmiddlewaretoken, + "Content-Type": "application/x-www-form-urlencoded", + }, + body: formData, + }); + if (response.status === 400) { + setValidationErrors((await response.json()) as ValidationErrors); + } else if (!response.ok) { + setSendError(new Error(`${response.status} on ${response.url}`)); + } else { + setSent(true); + refreshUserSettings(); + } + } + React.useEffect(() => { + let mounted = true; + setTimeout(() => { + if (mounted) { + setSent(false); + } + }, 5000); + return () => { + mounted = false; + }; + }, [sent]); + + return ( +
    { + event.preventDefault(); + await sendSettings(); + }} + > + {validationErrors && ( + + )} + + {sent && !sendError && ( +
    +

    Settings update sent

    +

    Yay! Settings saved.

    + +
    + )} + {sendError && ( +
    +

    Server submission error

    +

    Something unexpected happened on the server submission.

    +

    + {sendError.toString()} +

    + Reload this page and try again. +
    + )} + +
    + + +
    + + + ); +} + +function CloseAccount({ userSettings }: { userSettings: UserSettings }) { + const navigate = useNavigate(); + const locale = useLocale(); + const [confirm, setConfirm] = React.useState(false); + const [certain, setCertain] = React.useState(false); + + const { error: deleteError } = useSWR( + certain ? "/api/v1/settings" : null, + async (url: string) => { + const response = await fetch(url, { + method: "DELETE", + headers: { + "X-CSRFToken": userSettings.csrfmiddlewaretoken, + }, + }); + if (!response.ok) { + throw new Error(`${response.status} on ${response.url}`); + } + alert("Your account has been closed and you are now signed out."); + + // This will "force" a new XHR request in the useUserData hook. + mutate("/api/v1/whoami"); + + navigate(`/${locale}/`); + return null; + }, + { + revalidateOnFocus: false, + } + ); + + return ( +
    +

    Close account

    +

    Delete your account and all account data.

    + + {deleteError && ( +
    +

    Server error

    +

    A server error occurred trying to close your account.

    +

    + {deleteError.toString()} +

    + Reload this page and try again. +
    + )} + + {confirm ? ( +

    + Are you certain you want to do this? + {" "} + +

    + ) : ( + + )} +
    + ); +} + +function ShowValidationErrors({ errors }: { errors: ValidationError }) { + return ( +
    +

    Validation errors

    +
      + {Object.entries(errors).map(([key, messages]) => { + return ( +
    • + + {key} + +
        + {messages.map((message) => { + return
      • {message.message}
      • ; + })} +
      +
    • + ); + })} +
    +
    + ); +} diff --git a/client/src/settings/index.tsx b/client/src/settings/index.tsx new file mode 100644 index 000000000000..449151d15474 --- /dev/null +++ b/client/src/settings/index.tsx @@ -0,0 +1,31 @@ +import React from "react"; + +import { PageContentContainer } from "../ui/atoms/page-content"; + +const SettingsApp = React.lazy(() => import("./app")); + +export function Settings() { + React.useEffect(() => { + document.title = "Settings"; + }, []); + const isServer = typeof window === "undefined"; + return ( +
    + + {/* The reason for displaying this

    here + is to avoid an unnecessary "flicker". + component here is loaded SSR and is immediately present. + Only the "guts" below is lazy loaded. By having the header already + present the page feels less flickery at a very affordable cost of + allowing this to be part of the main JS bundle. + */} +

    Settings

    + {!isServer && ( + Loading...

    }> + +
    + )} +
    +
    + ); +} diff --git a/server/static.js b/server/static.js index c82837d92200..994dc46f0498 100644 --- a/server/static.js +++ b/server/static.js @@ -2,6 +2,7 @@ const path = require("path"); const express = require("express"); const compression = require("compression"); +const cookieParser = require("cookie-parser"); const { staticMiddlewares } = require("./middlewares"); const { resolveFundamental } = require("../content"); @@ -11,6 +12,8 @@ const app = express(); app.use(express.json()); app.use(compression()); +app.use(express.urlencoded({ extended: true })); + app.use((req, res, next) => { // If we have a fundamental redirect mimic out Lambda@Edge and redirect. const { url: fundamentalRedirectUrl, status } = resolveFundamental(req.url); @@ -22,6 +25,8 @@ app.use((req, res, next) => { app.use(staticMiddlewares); +app.use(cookieParser()); + // This endpoint exists solely to accompany the headless tests. // They will trigger XHR requests to `/api/v1/search?....` // and use different values as a way to make expectations. @@ -90,7 +95,45 @@ app.get("/api/v1/search", async (req, res) => { }); app.get("/api/v1/whoami", async (req, res) => { - res.json({ waffle: { flags: {}, switches: {} } }); + const context = { waffle: { flags: {}, switches: {} } }; + if (req.cookies.fakesessionid) { + context.username = req.cookies.fakesessionid; + context.is_authenticated = true; + context.email = `${req.cookies.fakesessionid}@example.com`; + } + res.json(context); +}); + +const mockSettingsDatabase = new Map(); + +app.get("/api/v1/settings", async (req, res) => { + const defaultContext = { locale: "en-US" }; + if (!req.cookies.fakesessionid) { + res.status(403).send("oh no you don't"); + } else { + if (mockSettingsDatabase.has(req.cookies.fakesessionid)) { + res.json( + Object.assign( + {}, + defaultContext, + mockSettingsDatabase.get(req.cookies.fakesessionid) + ) + ); + } else { + res.json(defaultContext); + } + } +}); + +app.post("/api/v1/settings", async (req, res) => { + if (!req.cookies.fakesessionid) { + res.status(403).send("oh no you don't"); + } else { + mockSettingsDatabase.set(req.cookies.fakesessionid, { + locale: req.body.locale, + }); + res.json({ ok: true }); + } }); // To mimic what CloudFront does. diff --git a/ssr/render.js b/ssr/render.js index fccfc7894dc3..1918621f10bf 100644 --- a/ssr/render.js +++ b/ssr/render.js @@ -144,6 +144,7 @@ export default function render( pageNotFound = false, feedEntries = null, pageTitle = null, + possibleLocales = null, } = {} ) { const buildHtml = readBuildHTML(); @@ -208,6 +209,13 @@ export default function render( } } + if (possibleLocales) { + const possibleLocalesTag = ``; + $("#root").after(possibleLocalesTag); + } + if (pageDescription) { // This overrides the default description. Also assumes there's always // one tag there already. diff --git a/testing/tests/headless.test.js b/testing/tests/headless.test.js index f48e1f3c9fcd..e037f3c0b91e 100644 --- a/testing/tests/headless.test.js +++ b/testing/tests/headless.test.js @@ -289,4 +289,30 @@ describe("Basic viewing of functional pages", () => { ); await expect(page).toMatchElement("button", { text: "Create account" }); }); + + it("should say you're not signed in on the settings page", async () => { + await page.goto(testURL("/en-US/settings")); + await expect(page).toMatchElement("h1", { text: "Settings" }); + await expect(page).toMatchElement("a", { text: "Sign in first" }); + }); + + it("should show your settings page", async () => { + const url = testURL("/en-US/settings"); + // A `fakesessionid` is a special trick to tell the static server we use + // for mocking the `/api/v1`. + await page.setCookie({ + name: "fakesessionid", + value: "peterbe", + domain: new URL(url).host, + }); + + await page.goto(url); + await expect(page).toMatchElement("h1", { text: "Settings" }); + await expect(page).toMatchElement("button", { text: "Close account" }); + + // Change locale to French + await expect(page).toSelect('select[name="locale"]', "French"); + await expect(page).toClick("button", { text: "Save changes" }); + await expect(page).toMatch("Settings update sent"); + }); }); diff --git a/testing/tests/index.test.js b/testing/tests/index.test.js index dcd76fe36236..13696e2ebeac 100644 --- a/testing/tests/index.test.js +++ b/testing/tests/index.test.js @@ -971,6 +971,24 @@ test("sign up page", () => { expect($("title").text()).toContain("Sign up"); }); +test("settings page", () => { + const builtFolder = path.join(buildRoot, "en-us", "settings"); + expect(fs.existsSync(builtFolder)).toBeTruthy(); + const htmlFile = path.join(builtFolder, "index.html"); + const html = fs.readFileSync(htmlFile, "utf-8"); + const $ = cheerio.load(html); + expect($("h1").text()).toContain("Settings"); + expect($("title").text()).toContain("Settings"); + + const jsonFile = path.join(builtFolder, "index.json"); + const data = JSON.parse(fs.readFileSync(jsonFile)); + expect(data.pageTitle).toBe("Settings"); + expect(data.possibleLocales).toBeTruthy(); + const possibleLocale = data.possibleLocales.find((p) => p.locale === "en-US"); + expect(possibleLocale.English).toBe("English (US)"); + expect(possibleLocale.native).toBe("English (US)"); +}); + test("bcd table extraction followed by h3", () => { const builtFolder = path.join( buildRoot, From 1d3f9e7f79fc2091f7ba726608628e747d1b94d0 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Thu, 18 Mar 2021 11:42:35 -0400 Subject: [PATCH 034/288] include native name for translations (#2893) --- build/index.js | 11 +- .../src/document/organisms/metadata/index.tsx | 7 +- client/src/document/types.tsx | 2 +- .../src/ui/molecules/language-menu/index.tsx | 41 +- .../ui/molecules/language-toggle/index.tsx | 11 +- content/languages.json | 518 ++++++++++++++++++ content/translations.js | 12 +- testing/tests/headless.test.js | 6 +- testing/tests/index.test.js | 2 +- 9 files changed, 571 insertions(+), 39 deletions(-) create mode 100644 content/languages.json diff --git a/build/index.js b/build/index.js index 7ebe064858ee..d8766d5afc44 100644 --- a/build/index.js +++ b/build/index.js @@ -26,6 +26,13 @@ const buildOptions = require("./build-options"); const { gather: gatherGitHistory } = require("./git-history"); const { buildSPAs } = require("./spas"); const { renderCache: renderKumascriptCache } = require("../kumascript"); +const LANGUAGES_RAW = require("../content/languages.json"); + +const LANGUAGES = new Map( + Object.entries(LANGUAGES_RAW).map(([locale, data]) => { + return [locale.toLowerCase(), data]; + }) +); const DEFAULT_BRANCH_NAME = "main"; // That's what we use for github.com/mdn/content @@ -351,6 +358,7 @@ async function buildDocument(document, documentOptions = {}) { doc.title = metadata.title; doc.mdn_url = document.url; doc.locale = metadata.locale; + doc.native = LANGUAGES.get(doc.locale.toLowerCase()).native; // Note that 'extractSidebar' will always return a string. // And if it finds a sidebar section, it gets removed from '$' too. @@ -473,9 +481,8 @@ async function buildDocument(document, documentOptions = {}) { if (translationOf) { otherTranslations.push({ locale: "en-US", - // slug: translationOf.metadata.slug, - url: translationOf.url, title: translationOf.metadata.title, + native: LANGUAGES.get("en-us").native, }); } } diff --git a/client/src/document/organisms/metadata/index.tsx b/client/src/document/organisms/metadata/index.tsx index 8424b50aa1e9..7860707bc61e 100644 --- a/client/src/document/organisms/metadata/index.tsx +++ b/client/src/document/organisms/metadata/index.tsx @@ -26,6 +26,7 @@ function LastModified({ value, locale }) { export function Metadata({ doc, locale }) { const translations = doc.other_translations || []; + const { native } = doc; return ( diff --git a/client/src/document/types.tsx b/client/src/document/types.tsx index 930399f823c3..aa97a824a106 100644 --- a/client/src/document/types.tsx +++ b/client/src/document/types.tsx @@ -96,7 +96,7 @@ type Flaws = { export type Translation = { locale: string; - url: string; + native: string; }; export type DocParent = { diff --git a/client/src/ui/molecules/language-menu/index.tsx b/client/src/ui/molecules/language-menu/index.tsx index e4f45e8b4343..9d977d36b275 100644 --- a/client/src/ui/molecules/language-menu/index.tsx +++ b/client/src/ui/molecules/language-menu/index.tsx @@ -1,40 +1,31 @@ import React from "react"; -import { useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import { useGA } from "../../../ga-context"; - -import LANGUAGES_RAW from "../../../languages.json"; import { Translation } from "../../../document/types"; import "./index.scss"; -const LANGUAGES = new Map( - Object.entries(LANGUAGES_RAW).map(([locale, data]) => { - return [locale.toLowerCase(), data]; - }) -); - // This needs to match what's set in 'libs/constants.js' on the server/builder! const PREFERRED_LOCALE_COOKIE_NAME = "preferredlocale"; export function LanguageMenu({ locale, translations, + native, }: { locale: string; translations: Translation[]; + native: string; }) { const ga = useGA(); + const { pathname } = useLocation(); const navigate = useNavigate(); - const [localeURL, setLocaleURL] = React.useState(locale); + const [preferredLocale, setPreferredLocale] = React.useState(locale); - // For the menu label, we want to use the name of the document language. - // We need a special case for English because English documents can - // appear in pages for other locales, and in that case we need a - // translation for the word "English". In all other cases, the - // locale of the page and the locale of the document should match - // and we can just use the document language string without translation. - const verbose = LANGUAGES.get(locale.toLowerCase()); + function translateURL(destinationLocale: string) { + return pathname.replace(`/${locale}/`, `/${destinationLocale}/`); + } return (
    { const { value } = event.target; - setLocaleURL(value); + setPreferredLocale(value); }} > {/* @@ -90,12 +82,11 @@ export function LanguageMenu({ The onChange callback is a protection for doing nothing if the already current locale is chosen. */} - + {translations.map((t) => { - const verbose = LANGUAGES.get(t.locale.toLowerCase()); return ( - ); })} diff --git a/client/src/ui/molecules/language-toggle/index.tsx b/client/src/ui/molecules/language-toggle/index.tsx index da16ebe1d7a0..bf9209071a75 100644 --- a/client/src/ui/molecules/language-toggle/index.tsx +++ b/client/src/ui/molecules/language-toggle/index.tsx @@ -1,4 +1,4 @@ -import { Link } from "react-router-dom"; +import { Link, useLocation } from "react-router-dom"; import { Translation } from "../../../document/types"; import { useGA } from "../../../ga-context"; @@ -13,20 +13,25 @@ export function LanguageToggle({ translations: Translation[]; }) { const ga = useGA(); + const { pathname } = useLocation(); + function translateURL(destinationLocale: string) { + return pathname.replace(`/${locale}/`, `/${destinationLocale}/`); + } function getEnglishLink() { for (const translation of translations) { if (translation.locale.toLowerCase() === "en-us") { + const translationURL = translateURL(translation.locale); return ( { ga("send", { hitType: "event", eventCategory: "Language", eventAction: "Switch to English", - eventLabel: `${window.location.pathname} to ${translation.url}`, + eventLabel: `${window.location.pathname} to ${translationURL}`, }); }} > diff --git a/content/languages.json b/content/languages.json new file mode 100644 index 000000000000..f1a53eb0e021 --- /dev/null +++ b/content/languages.json @@ -0,0 +1,518 @@ +{ + "ach": { + "English": "Acholi", + "native": "Acholi" + }, + "ak": { + "English": "Akan", + "native": "Akan" + }, + "am-et": { + "English": "Amharic", + "native": "\u12a0\u121b\u122d\u129b" + }, + "an": { + "English": "Aragonese", + "native": "aragon\u00e9s" + }, + "ar": { + "English": "Arabic", + "native": "\u0639\u0631\u0628\u064a" + }, + "as": { + "English": "Assamese", + "native": "\u0985\u09b8\u09ae\u09c0\u09af\u09bc\u09be" + }, + "ast": { + "English": "Asturian", + "native": "Asturianu" + }, + "azz": { + "English": "Highland Puebla Nahuatl", + "native": "nahuatl sierra norte Puebla" + }, + "be": { + "English": "Belarusian", + "native": "\u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f" + }, + "bg": { + "English": "Bulgarian", + "native": "\u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438" + }, + "bm": { + "English": "Bambara", + "native": "Bamanankan" + }, + "bn": { + "English": "Bengali", + "native": "\u09ac\u09be\u0982\u09b2\u09be" + }, + "br": { + "English": "Breton", + "native": "Brezhoneg" + }, + "brx": { + "English": "Bodo", + "native": "\u092c\u0930'" + }, + "bs": { + "English": "Bosnian", + "native": "Bosanski" + }, + "ca": { + "English": "Catalan", + "native": "Catal\u00e0" + }, + "ca-valencia": { + "English": "Catalan (Valencian)", + "native": "catal\u00e0 (valenci\u00e0)" + }, + "cak": { + "English": "Kaqchikel", + "native": "Maya Kaqchikel" + }, + "csb": { + "English": "Kashubian", + "native": "Kasz\u00ebbsczi" + }, + "cy": { + "English": "Welsh", + "native": "Cymraeg" + }, + "da": { + "English": "Danish", + "native": "Dansk" + }, + "dbg": { + "English": "Debug Robot", + "native": "\u1e12\u1e17\u0180\u016d\u0260 \u0158\u01ff\u0180\u01ff\u0167" + }, + "de": { + "English": "German", + "native": "Deutsch" + }, + "de-AT": { + "English": "German (Austria)", + "native": "Deutsch (\u00d6sterreich)" + }, + "de-CH": { + "English": "German (Switzerland)", + "native": "Deutsch (Schweiz)" + }, + "de-DE": { + "English": "German (Germany)", + "native": "Deutsch (Deutschland)" + }, + "dsb": { + "English": "Lower Sorbian", + "native": "Dolnoserb\u0161\u0107ina" + }, + "el": { + "English": "Greek", + "native": "\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac" + }, + "en-AU": { + "English": "English (Australian)", + "native": "English (Australian)" + }, + "en-CA": { + "English": "English (Canadian)", + "native": "English (Canadian)" + }, + "en-GB": { + "English": "English (British)", + "native": "English (British)" + }, + "en-NZ": { + "English": "English (New Zealand)", + "native": "English (New Zealand)" + }, + "en-US": { + "English": "English (US)", + "native": "English (US)" + }, + "en-ZA": { + "English": "English (South African)", + "native": "English (South African)" + }, + "eo": { + "English": "Esperanto", + "native": "Esperanto" + }, + "es": { + "English": "Spanish", + "native": "Espa\u00f1ol" + }, + "es-AR": { + "English": "Spanish (Argentina)", + "native": "Espa\u00f1ol (de Argentina)" + }, + "es-CL": { + "English": "Spanish (Chile)", + "native": "Espa\u00f1ol (de Chile)" + }, + "es-ES": { + "English": "Spanish (Spain)", + "native": "Espa\u00f1ol (de Espa\u00f1a)" + }, + "es-MX": { + "English": "Spanish (Mexico)", + "native": "Espa\u00f1ol (de M\u00e9xico)" + }, + "et": { + "English": "Estonian", + "native": "Eesti keel" + }, + "eu": { + "English": "Basque", + "native": "Euskara" + }, + "fa": { + "English": "Persian", + "native": "\u0641\u0627\u0631\u0633\u06cc" + }, + "fi": { + "English": "Finnish", + "native": "suomi" + }, + "fj-FJ": { + "English": "Fijian", + "native": "Vosa vaka-Viti" + }, + "fr": { + "English": "French", + "native": "Fran\u00e7ais" + }, + "fur-IT": { + "English": "Friulian", + "native": "Furlan" + }, + "ga": { + "English": "Irish", + "native": "Gaeilge" + }, + "gd": { + "English": "Gaelic (Scotland)", + "native": "G\u00e0idhlig" + }, + "gl": { + "English": "Galician", + "native": "Galego" + }, + "gn": { + "English": "Guarani", + "native": "Ava\u00f1e'\u1ebd" + }, + "gu": { + "English": "Gujarati", + "native": "\u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0" + }, + "gu-IN": { + "English": "Gujarati (India)", + "native": "\u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0 (\u0aad\u0abe\u0ab0\u0aa4)" + }, + "he": { + "English": "Hebrew", + "native": "\u05e2\u05d1\u05e8\u05d9\u05ea" + }, + "hi": { + "English": "Hindi", + "native": "\u0939\u093f\u0928\u094d\u0926\u0940" + }, + "hi-IN": { + "English": "Hindi (India)", + "native": "\u0939\u093f\u0928\u094d\u0926\u0940 (\u092d\u093e\u0930\u0924)" + }, + "hsb": { + "English": "Upper Sorbian", + "native": "Hornjoserbsce" + }, + "hu": { + "English": "Hungarian", + "native": "magyar" + }, + "hy-AM": { + "English": "Armenian", + "native": "\u0540\u0561\u0575\u0565\u0580\u0565\u0576" + }, + "ia": { + "English": "Interlingua", + "native": "Interlingua" + }, + "id": { + "English": "Indonesian", + "native": "Bahasa Indonesia" + }, + "is": { + "English": "Icelandic", + "native": "\u00edslenska" + }, + "it": { + "English": "Italian", + "native": "Italiano" + }, + "ja": { + "English": "Japanese", + "native": "\u65e5\u672c\u8a9e" + }, + "ja-JP-mac": { + "English": "Japanese", + "native": "\u65e5\u672c\u8a9e" + }, + "kab": { + "English": "Kabyle", + "native": "Taqbaylit" + }, + "kk": { + "English": "Kazakh", + "native": "\u049a\u0430\u0437\u0430\u049b" + }, + "km": { + "English": "Khmer", + "native": "\u1781\u17d2\u1798\u17c2\u179a" + }, + "kn": { + "English": "Kannada", + "native": "\u0c95\u0ca8\u0ccd\u0ca8\u0ca1" + }, + "ko": { + "English": "Korean", + "native": "\ud55c\uad6d\uc5b4" + }, + "kok": { + "English": "Konkani", + "native": "\u0915\u094b\u0902\u0915\u0928\u0940" + }, + "ku": { + "English": "Kurdish", + "native": "Kurd\u00ee" + }, + "ks": { + "English": "Kashmiri", + "native": "\u0643\u0634\u0645\u06cc\u0631\u06cc" + }, + "la": { + "English": "Latin", + "native": "Latina" + }, + "lg": { + "English": "Luganda", + "native": "Luganda" + }, + "lij": { + "English": "Ligurian", + "native": "Ligure" + }, + "lo": { + "English": "Lao", + "native": "\u0e9e\u0eb2\u0eaa\u0eb2\u0ea5\u0eb2\u0ea7" + }, + "lt": { + "English": "Lithuanian", + "native": "Lietuvi\u0173" + }, + "ltg": { + "English": "Latgalian", + "native": "Latgalie\u0161u valoda" + }, + "lv": { + "English": "Latvian", + "native": "Latvie\u0161u" + }, + "mai": { + "English": "Maithili", + "native": "\u092e\u0948\u0925\u093f\u0932\u0940 \u09ae\u09c8\u09a5\u09bf\u09b2\u09c0" + }, + "mi": { + "English": "Maori (Aotearoa)", + "native": "M\u0101ori (Aotearoa)" + }, + "mk": { + "English": "Macedonian", + "native": "\u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438" + }, + "mn": { + "English": "Mongolian", + "native": "\u041c\u043e\u043d\u0433\u043e\u043b" + }, + "mr": { + "English": "Marathi", + "native": "\u092e\u0930\u093e\u0920\u0940" + }, + "ms": { + "English": "Malay", + "native": "Melayu" + }, + "my": { + "English": "Burmese", + "native": "\u1019\u103c\u1014\u103a\u1019\u102c\u1018\u102c\u101e\u102c" + }, + "nb-NO": { + "English": "Norwegian (Bokm\u00e5l)", + "native": "Norsk bokm\u00e5l" + }, + "ne-NP": { + "English": "Nepali", + "native": "\u0928\u0947\u092a\u093e\u0932\u0940" + }, + "nn-NO": { + "English": "Norwegian (Nynorsk)", + "native": "Norsk nynorsk" + }, + "nl": { + "English": "Dutch", + "native": "Nederlands" + }, + "nr": { + "English": "Ndebele, South", + "native": "isiNdebele" + }, + "nso": { + "English": "Northern Sotho", + "native": "Sepedi" + }, + "oc": { + "English": "Occitan (Lengadocian)", + "native": "occitan (lengadocian)" + }, + "or": { + "English": "Odia", + "native": "\u0b13\u0b21\u0b3c\u0b3f\u0b06" + }, + "pa": { + "English": "Punjabi", + "native": "\u0a2a\u0a70\u0a1c\u0a3e\u0a2c\u0a40" + }, + "pa-IN": { + "English": "Punjabi (India)", + "native": "\u0a2a\u0a70\u0a1c\u0a3e\u0a2c\u0a40 (\u0a2d\u0a3e\u0a30\u0a24)" + }, + "pl": { + "English": "Polish", + "native": "Polski" + }, + "pt-BR": { + "English": "Portuguese (Brazilian)", + "native": "Portugu\u00eas (do\u00a0Brasil)" + }, + "pt-PT": { + "English": "Portuguese (Portugal)", + "native": "Portugu\u00eas (Europeu)" + }, + "rm": { + "English": "Romansh", + "native": "rumantsch" + }, + "ru": { + "English": "Russian", + "native": "\u0420\u0443\u0441\u0441\u043a\u0438\u0439" + }, + "rw": { + "English": "Kinyarwanda", + "native": "Ikinyarwanda" + }, + "sa": { + "English": "Sanskrit", + "native": "\u0938\u0902\u0938\u094d\u0915\u0943\u0924" + }, + "sat": { + "English": "Santali", + "native": "\u0938\u0902\u0924\u093e\u0932\u0940" + }, + "sah": { + "English": "Sakha", + "native": "\u0421\u0430\u0445\u0430\u043b\u044b\u044b" + }, + "si": { + "English": "Sinhala", + "native": "\u0dc3\u0dd2\u0d82\u0dc4\u0dbd" + }, + "sk": { + "English": "Slovak", + "native": "sloven\u010dina" + }, + "sl": { + "English": "Slovenian", + "native": "Sloven\u0161\u010dina" + }, + "sr-Cyrl": { + "English": "Serbian", + "native": "\u0421\u0440\u043f\u0441\u043a\u0438" + }, + "ss": { + "English": "Siswati", + "native": "siSwati" + }, + "st": { + "English": "Southern Sotho", + "native": "Sesotho" + }, + "sv-SE": { + "English": "Swedish", + "native": "Svenska" + }, + "ta-IN": { + "English": "Tamil (India)", + "native": "\u0ba4\u0bae\u0bbf\u0bb4\u0bcd (\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe)" + }, + "ta-LK": { + "English": "Tamil (Sri Lanka)", + "native": "\u0ba4\u0bae\u0bbf\u0bb4\u0bcd (\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8)" + }, + "th": { + "English": "Thai", + "native": "\u0e44\u0e17\u0e22" + }, + "tr": { + "English": "Turkish", + "native": "T\u00fcrk\u00e7e" + }, + "trs": { + "English": "Triqui", + "native": "Triqui" + }, + "ts": { + "English": "Tsonga", + "native": "Xitsonga" + }, + "tsz": { + "English": "Pur\u00e9pecha", + "native": "Pur\u00e9pecha" + }, + "tt-RU": { + "English": "Tatar", + "native": "Tatar\u00e7a" + }, + "uk": { + "English": "Ukrainian", + "native": "\u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430" + }, + "ur": { + "English": "Urdu", + "native": "\u0627\u064f\u0631\u062f\u0648" + }, + "uz": { + "English": "Uzbek", + "native": "O\u02bbzbek tili" + }, + "ve": { + "English": "Venda", + "native": "Tshiven\u1e13a" + }, + "vi": { + "English": "Vietnamese", + "native": "Ti\u1ebfng Vi\u1ec7t" + }, + "x-testing": { + "English": "Testing", + "native": "\u0166\u1e17\u015f\u0167\u012b\u019e\u0260" + }, + "zh-CN": { + "English": "Chinese (Simplified)", + "native": "\u4e2d\u6587 (\u7b80\u4f53)" + }, + "zh-TW": { + "English": "Chinese (Traditional)", + "native": "\u6b63\u9ad4\u4e2d\u6587 (\u7e41\u9ad4)" + } +} diff --git a/content/translations.js b/content/translations.js index 2e04aeedace3..0fb1ef757b21 100644 --- a/content/translations.js +++ b/content/translations.js @@ -1,5 +1,12 @@ const Document = require("./document"); const { VALID_LOCALES } = require("./constants"); +const LANGUAGES_RAW = require("./languages.json"); + +const LANGUAGES = new Map( + Object.entries(LANGUAGES_RAW).map(([locale, data]) => { + return [locale.toLowerCase(), data]; + }) +); const TRANSLATIONS_OF = new Map(); @@ -7,12 +14,11 @@ function gatherTranslations() { const iter = Document.findAll().iter(); for (const { metadata: { slug, locale, title }, - url, } of iter) { const translation = { title, - url, locale, + native: LANGUAGES.get(locale.toLowerCase()).native, }; const translations = TRANSLATIONS_OF.get(slug.toLowerCase()); if (translations) { @@ -57,7 +63,7 @@ function findDocumentTranslations(document) { translations.push({ locale, title: translatedDocument.metadata.title, - url: translatedDocument.url, + native: LANGUAGES.get(locale.toLowerCase()).native, }); } } diff --git a/testing/tests/headless.test.js b/testing/tests/headless.test.js index e037f3c0b91e..85ff6886260e 100644 --- a/testing/tests/headless.test.js +++ b/testing/tests/headless.test.js @@ -37,7 +37,7 @@ describe("Basic viewing of functional pages", () => { // Note! It's important that this happens *after* the `.toMatchElement` // on the line above because expect-puppeteer doesn't have a wait to // properly wait for the (pushState) URL to have changed. - expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo")); + expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo/")); }); it("open the /en-US/docs/Web/InteractiveExample page", async () => { @@ -246,13 +246,13 @@ describe("Basic viewing of functional pages", () => { await expect(page).toSelect('select[name="language"]', "English (US)"); await expect(page).toClick("button", { text: "Change language" }); await expect(page).toMatch(": A test tag"); - expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo")); + expect(page.url()).toBe(testURL("/en-US/docs/Web/Foo/")); // And change back to French await expect(page).toSelect('select[name="language"]', "Français"); await expect(page).toClick("button", { text: "Change language" }); await expect(page).toMatch(": Une page de test"); - expect(page.url()).toBe(testURL("/fr/docs/Web/Foo")); + expect(page.url()).toBe(testURL("/fr/docs/Web/Foo/")); }); it("clicking 'Sign in' should offer links to all identity providers", async () => { diff --git a/testing/tests/index.test.js b/testing/tests/index.test.js index 13696e2ebeac..877b75cc1a7c 100644 --- a/testing/tests/index.test.js +++ b/testing/tests/index.test.js @@ -181,7 +181,7 @@ test("content built French foo page", () => { expect(doc.title).toBe(": Une page de test"); expect(doc.isTranslated).toBe(true); expect(doc.other_translations[0].locale).toBe("en-US"); - expect(doc.other_translations[0].url).toBe("/en-US/docs/Web/Foo"); + expect(doc.other_translations[0].native).toBe("English (US)"); expect(doc.other_translations[0].title).toBe(": A test tag"); const htmlFile = path.join(builtFolder, "index.html"); From 0987df89a71fea66b91db118a0a20cd273f570ae Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Thu, 18 Mar 2021 16:07:30 -0400 Subject: [PATCH 035/288] --prune should leave archived S3 keys (#3266) * --prune should leave archived S3 keys Part of #2224 * Update deployer/src/deployer/upload.py Co-authored-by: Ryan Johnson * Update deployer/src/deployer/upload.py Co-authored-by: Ryan Johnson * parse_archived_txt_file as a generator * only one 1 set * add a nice warning about --prune without --archived-files Co-authored-by: Ryan Johnson --- .github/workflows/dev-build.yml | 2 +- .github/workflows/stage-build.yml | 2 +- deployer/src/deployer/main.py | 31 ++++++++++++++++++ deployer/src/deployer/upload.py | 54 +++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index f38427d16951..647da09e1673 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -204,7 +204,7 @@ jobs: # XXX would be nice to validate here that $DEPLOYER_BUCKET_PREFIX is truthy echo "DEPLOYER_BUCKET_PREFIX=$DEPLOYER_BUCKET_PREFIX" - poetry run deployer upload --prune ../client/build + poetry run deployer upload --prune --archived-files ../content/archived.txt ../client/build poetry run deployer update-lambda-functions ./aws-lambda # TODO # Execute command to tell the Dev CloudFront distribution to use the diff --git a/.github/workflows/stage-build.yml b/.github/workflows/stage-build.yml index 29b5790b82f8..c20244921e14 100644 --- a/.github/workflows/stage-build.yml +++ b/.github/workflows/stage-build.yml @@ -240,7 +240,7 @@ jobs: # XXX would be nice to validate here that $DEPLOYER_BUCKET_PREFIX is truthy echo "DEPLOYER_BUCKET_PREFIX=$DEPLOYER_BUCKET_PREFIX" - poetry run deployer upload --prune ../client/build + poetry run deployer upload --prune --archived-files ../content/archived.txt ../client/build poetry run deployer update-lambda-functions ./aws-lambda # TODO: Depending on how long the upload takes, consider switching to diff --git a/deployer/src/deployer/main.py b/deployer/src/deployer/main.py index e401c510f307..c3c053a7d81d 100644 --- a/deployer/src/deployer/main.py +++ b/deployer/src/deployer/main.py @@ -39,6 +39,22 @@ def validate_optional_directory(ctx, param, value): return validate_directory(ctx, param, value) +def validate_file(ctz, param, value): + if not value: + raise click.BadParameter(f"{value!r}") + path = Path(value) + if not path.exists(): + raise click.BadParameter(f"{value} does not exist") + elif not path.is_file(): + raise click.BadParameter(f"{value} is not a file") + return path + + +def validate_optional_file(ctx, param, value): + if value: + return validate_file(ctx, param, value) + + @click.group() @click.option( "--dry-run", @@ -151,6 +167,15 @@ def whatsdeployed(ctx, directory: Path, output: str): show_default=True, is_flag=True, ) +@click.option( + "--archived-files", + help=( + "The path to the file that lists which files are archived. " + "(Only relevant in conjunction with --prune)" + ), + default=None, + callback=validate_optional_file, +) @click.argument("directory", type=click.Path(), callback=validate_directory) @click.pass_context def upload(ctx, directory: Path, **kwargs): @@ -160,6 +185,12 @@ def upload(ctx, directory: Path, **kwargs): content_roots.append(kwargs["content_translated_root"]) if kwargs["content_archived_root"]: content_roots.append(kwargs["content_archived_root"]) + + if kwargs["prune"] and not kwargs["archived_files"]: + log.warning( + "Warning! Running with --prune but NOT ----archived-files will " + "possibly delete all archived content." + ) ctx.obj.update(kwargs) upload_content(directory, content_roots, ctx.obj) diff --git a/deployer/src/deployer/upload.py b/deployer/src/deployer/upload.py index 31c0631f3c30..59db69ca6657 100644 --- a/deployer/src/deployer/upload.py +++ b/deployer/src/deployer/upload.py @@ -498,6 +498,14 @@ def delete(self, keys, on_task_complete=None, dry_run=False): return timer +def parse_archived_txt_file(file: Path): + with open(file) as f: + for line in f: + line = line.strip() + if line and not line.startswith("#"): + yield line + + def upload_content(build_directory, content_roots, config): full_timer = StopWatch().start() @@ -508,6 +516,7 @@ def upload_content(build_directory, content_roots, config): show_progress_bar = not config["no_progressbar"] upload_redirects = not config["no_redirects"] prune = config["prune"] + archived_txt_file = config["archived_files"] log.info(f"Upload files from: {build_directory}") if upload_redirects: @@ -583,6 +592,15 @@ def on_task_complete(task): # now deleted. now = datetime.datetime.utcnow().replace(tzinfo=UTC) delete_keys = [] + + archived_files_as_keys = set() + if archived_txt_file: + for file in parse_archived_txt_file(archived_txt_file): + locale, slug = file.replace("/index.html", "").split("/", 1) + archived_files_as_keys.add(f"{bucket_prefix}/{locale}/docs/{slug}") + if not archived_files_as_keys: + raise Exception(f"found no entries inside {archived_txt_file}") + for key in existing_bucket_objects: if key.startswith(f"{bucket_prefix}/_whatsdeployed/"): # These are special and wouldn't have been uploaded @@ -603,6 +621,42 @@ def on_task_complete(task): if delta.days < 30: continue + # Remember, if `key` is from a "index.html" file it will be represented + # something like this: `main/en-us/docs/web/api/documentorshadowroot` + # with the `/index.html` portion removed. + # But every page usually has a `index.json` file, which might look + # something like this: `main/en-us/docs/web/api/index.json` or + # `main/en-us/docs/web/api/screenshot.png` + + # This if statement protects against possible deleting anything that + # isn't a document. + if "/docs/" in key: + is_archived = False + # Trying to avoid having to do another for-loop with key.startswith() + # so first look for the low-hanging fruit. + if key in archived_files_as_keys: + # This is the easiest and fastest lookup + is_archived = True + elif ( + re.sub(r"/(index\.json|contributors\.txt|bcd\.json)$", "", key) + in archived_files_as_keys + ): + # This is easy and fast too and covers 99% of the other + # possible keys. + is_archived = True + else: + # This is for things like: + # `main/en-us/docs/web/api/screenshot.png` where you can't + # confidently use `path.dirname()` because the key could + # be something like `main/fr/docs/web/api/manifest.json` which + # is actually a "folder". + for archive_file_as_key in archived_files_as_keys: + if key.startswith(archive_file_as_key): + is_archived = True + break + if is_archived: + continue + assert key.startswith(bucket_prefix) delete_keys.append(key) From 20f5599adc6b5042f27ccfb35368d1ba17b97380 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Thu, 18 Mar 2021 16:16:54 -0400 Subject: [PATCH 036/288] fix tools links in writer-home page (#3274) --- client/src/writers-homepage/index.tsx | 49 +++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/client/src/writers-homepage/index.tsx b/client/src/writers-homepage/index.tsx index 487ebc84996a..b3113b2bad34 100644 --- a/client/src/writers-homepage/index.tsx +++ b/client/src/writers-homepage/index.tsx @@ -1,15 +1,16 @@ -import React, { lazy, Suspense } from "react"; +import React from "react"; import { Link } from "react-router-dom"; import { PageContentContainer } from "../ui/atoms/page-content"; import { Search } from "../ui/molecules/search"; - +import { useLocale } from "../hooks"; import "./index.scss"; // Lazy sub-components -const ViewedDocuments = lazy(() => import("./viewed-documents")); +const ViewedDocuments = React.lazy(() => import("./viewed-documents")); export default function WritersHomepage() { const isServer = typeof window === "undefined"; + const locale = useLocale(); return ( @@ -19,62 +20,74 @@ export default function WritersHomepage() { {!isServer && ( - + - + )}

    Sample pages

    • - The Kitchensink + + The Kitchensink (en-US) +
    • - Web/HTML index + Web/HTML index
      • - HTML/video + + HTML/video +
    • - Web/API index + Web/API index
      • - + Using Fetch API
    • - Web/CSS index + Web/CSS index
      • - + CSS Specificity
    • - Web/JavaScript index + + Web/JavaScript index +
      • - + Array.prototype.forEach()
    • - + Page with lots of BCD tables
    • - + Largest BCD table
    • @@ -82,10 +95,10 @@ export default function WritersHomepage() {

      Tools

      • - Sitemap + Sitemap
      • - Flaws Dashboard + Flaws Dashboard
      From c1ac216156dbfac204286e6db9ae21cc51c6c1fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Mar 2021 05:49:59 +0000 Subject: [PATCH 037/288] build(deps): bump @mdn/browser-compat-data from 3.2.0 to 3.2.1 (#3284) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9547951774fd..e91940744c69 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "dependencies": { "@caporal/core": "2.0.2", "@fast-csv/parse": "4.3.6", - "@mdn/browser-compat-data": "3.2.0", + "@mdn/browser-compat-data": "3.2.1", "accept-language-parser": "1.5.0", "chalk": "4.1.0", "cheerio": "1.0.0-rc.5", diff --git a/yarn.lock b/yarn.lock index 7edd6204053b..971c78c0ba18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1882,10 +1882,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@mdn/browser-compat-data@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-3.2.0.tgz#42b8f6c2866a77873a67d962428e417fd73201c2" - integrity sha512-pb3IvMWuDxNwWw8MfD7juJO8i5D0mo02LWNjV6T/LYzUeHSu/LL5e5ufUAyrDjsBw3T1+gqqmUBvj5WtuuPGgQ== +"@mdn/browser-compat-data@3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-3.2.1.tgz#18707a79db035b430d6bab370d00cd14c39e0553" + integrity sha512-rIfqD67k64yP6RfFyZOVSLykDoNfAkeqRrTZnKs13rfa+EAFF/FOYAKTOpKMwMUfTM2/+FGYRGaiFmETnGRjsQ== dependencies: extend "3.0.2" From 9e48dff88e91e060ce5bd12c98aaea58585e51d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Mar 2021 06:48:44 +0000 Subject: [PATCH 038/288] build(deps): bump boto3 from 1.17.30 to 1.17.32 in /deployer (#3285) --- deployer/poetry.lock | 16 ++++++++-------- deployer/pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index 4395de5c1f06..db277b7fcdb0 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -52,20 +52,20 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "boto3" -version = "1.17.30" +version = "1.17.32" description = "The AWS SDK for Python" category = "main" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] -botocore = ">=1.20.30,<1.21.0" +botocore = ">=1.20.32,<1.21.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] name = "botocore" -version = "1.20.30" +version = "1.20.32" description = "Low-level, data-driven core of boto 3." category = "main" optional = false @@ -482,7 +482,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "fece341f13f2a5cc7d43fc902fbbec6318d921445d32969a5215c8bcae13adb2" +content-hash = "fc6df7112afa97a2dc58eee6d5df9c38764dd9eb417d9093b42f6d0367e69e5a" [metadata.files] appdirs = [ @@ -501,12 +501,12 @@ black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] boto3 = [ - {file = "boto3-1.17.30-py2.py3-none-any.whl", hash = "sha256:fe1898c5b10035528207995c9931b78f2f50bb70cf93bac353152aea47c04780"}, - {file = "boto3-1.17.30.tar.gz", hash = "sha256:d39c04b51e60197f5503f8489f043bc904981567cc8431d389367767dc3fd5ae"}, + {file = "boto3-1.17.32-py2.py3-none-any.whl", hash = "sha256:85069e044c871571b7a72b600123761e1747ad18328fa5188f13b097a394251d"}, + {file = "boto3-1.17.32.tar.gz", hash = "sha256:2df49a4360ef0640902c26bf93ac0791b37755db3a2efd0d51a03eddeb9f807e"}, ] botocore = [ - {file = "botocore-1.20.30-py2.py3-none-any.whl", hash = "sha256:63951595a736dfc9759f57e33bec6eaea4f09c4800626ef5309437060b263e48"}, - {file = "botocore-1.20.30.tar.gz", hash = "sha256:98ff1eb210d394a1ffe736b33c8a7be68f30f0a03550b559c5bb6fdf0c29328d"}, + {file = "botocore-1.20.32-py2.py3-none-any.whl", hash = "sha256:fc162b69adc54c9ef037fec31f93d46df0bf8a9c3d201ecb16d0a9ec5f2936ec"}, + {file = "botocore-1.20.32.tar.gz", hash = "sha256:1cef96e716f7481bfb3b8d3c3d45e640d588aa5af613cd6d7f33d784aa2e8d12"}, ] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index e197857897b6..ebe259e4a66d 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.7" click = "^7.1.2" -boto3 = "^1.17.30" +boto3 = "^1.17.32" python-decouple = "^3.4" requests = {extras = ["security"], version = "^2.25.0"} elasticsearch-dsl = "^7.3.0" From 68052d9309d6b935797905429c2c45158ff10712 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Fri, 19 Mar 2021 13:16:59 -0400 Subject: [PATCH 039/288] Ability to build by specific locale(s) (#3268) Fixes #3267 --- build/cli.js | 33 ++++++++++++++++++++++++++------- content/document.js | 21 +++++++++++++++++++-- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/build/cli.js b/build/cli.js index bb55b76a41d0..9b6c03fcaf03 100644 --- a/build/cli.js +++ b/build/cli.js @@ -15,10 +15,9 @@ const { CONTENT_TRANSLATED_ROOT, CONTENT_ARCHIVED_ROOT, } = require("../content"); - +const { VALID_LOCALES } = require("../libs/constants"); // eslint-disable-next-line node/no-missing-require const { renderDocHTML } = require("../ssr/dist/main"); - const options = require("./build-options"); const { buildDocument, renderContributorsTxt } = require("./index"); const SearchIndex = require("./search-index"); @@ -77,13 +76,15 @@ async function buildDocumentInteractive( async function buildDocuments( files = null, quiet = false, - interactive = false + interactive = false, + locales = new Map() ) { // If a list of files was set, it came from the CLI. // Override whatever was in the build options. - const findAllOptions = files - ? Object.assign({}, options, { files: new Set(files) }) - : options; + const findAllOptions = Object.assign({}, options, { locales }); + if (files) { + findAllOptions.files = new Set(files); + } const documents = Document.findAll(findAllOptions); const progressBar = new cliProgress.SingleBar( @@ -278,6 +279,10 @@ program .option("-i, --interactive", "Ask what to do when encountering flaws", { default: false, }) + .option("-l, --locale ", "Filtered specific locales", { + default: [], + validator: [...VALID_LOCALES.keys()], + }) .argument("[files...]", "specific files to build") .action(async ({ args, options }) => { try { @@ -296,11 +301,25 @@ program } } const { files } = args; + + // 'true' means we include this locale and all others get excluded. + // Some day we might make it an option to set `--not-locale` to + // filter out specific locales. + const locales = new Map( + // The `options.locale` is either an empty array (e.g. no --locale used), + // a string (e.g. one single --locale) or an array of strings + // (e.g. multiple --locale options). + (Array.isArray(options.locale) + ? options.locale + : [options.locale] + ).map((locale) => [locale, true]) + ); const t0 = new Date(); const { slugPerLocale, peakHeapBytes, totalFlaws } = await buildDocuments( files, Boolean(options.quiet), - Boolean(options.interactive) + Boolean(options.interactive), + locales ); const t1 = new Date(); const count = Object.values(slugPerLocale).reduce( diff --git a/content/document.js b/content/document.js index 02044ffa3f8a..6b2c63b74a04 100644 --- a/content/document.js +++ b/content/document.js @@ -358,7 +358,11 @@ function findByURL(url, ...args) { return doc; } -function findAll({ files = new Set(), folderSearch = null } = {}) { +function findAll({ + files = new Set(), + folderSearch = null, + locales = new Map(), +} = {}) { if (!(files instanceof Set)) throw new TypeError("'files' not a Set"); if (folderSearch && typeof folderSearch !== "string") throw new TypeError("'folderSearch' not a string"); @@ -373,9 +377,22 @@ function findAll({ files = new Set(), folderSearch = null } = {}) { } roots.push(CONTENT_ROOT); for (const root of roots) { + const searchPattern = [""]; + if (locales.size) { + const localePrefixes = []; + for (const [locale, include] of locales) { + if (!include) { + throw new Error("ability to exclude locales is not supported yet"); + } + localePrefixes.push(locale); + } + searchPattern.push(`+(${localePrefixes.join("|")})`); + } + searchPattern.push("**"); + searchPattern.push(HTML_FILENAME); filePaths.push( ...glob - .sync(path.join(root, "**", HTML_FILENAME)) + .sync(searchPattern.join(path.sep), { root }) .filter((filePath) => { // The 'files' set is either a list of absolute full paths or a // list of endings. From 7b73ce0198756d72b04de56544c75581aad397c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Mar 2021 15:12:58 -0400 Subject: [PATCH 040/288] build(deps): bump open from 7.4.2 to 8.0.3 (#3283) Bumps [open](https://github.com/sindresorhus/open) from 7.4.2 to 8.0.3. - [Release notes](https://github.com/sindresorhus/open/releases) - [Commits](https://github.com/sindresorhus/open/compare/v7.4.2...v8.0.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e91940744c69..fbfbdca3aef8 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "loglevel": "^1.7.1", "lru-cache": "^6.0.0", "mdn-data": "2.0.17", - "open": "^7.4.2", + "open": "^8.0.3", "open-editor": "3.0.0", "prismjs": "1.23.0", "read-chunk": "3.2.0", diff --git a/yarn.lock b/yarn.lock index 971c78c0ba18..e0c52aa18bbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6566,6 +6566,11 @@ defer-to-connect@^2.0.0: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1" integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg== +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -10057,7 +10062,7 @@ is-directory@^0.3.1: resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= -is-docker@^2.0.0: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== @@ -12845,7 +12850,7 @@ open-editor@3.0.0: line-column-path "^2.0.0" open "^7.3.0" -open@^7.0.2, open@^7.0.3, open@^7.3.0, open@^7.4.2: +open@^7.0.2, open@^7.0.3, open@^7.3.0: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== @@ -12853,6 +12858,15 @@ open@^7.0.2, open@^7.0.3, open@^7.3.0, open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" +open@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/open/-/open-8.0.3.tgz#04f4406c950666c35041aad8a621700022116afd" + integrity sha512-7nsHNw3rOIPTwhF5iYkgE+LVM/oUHWC3cgrWNxPqa+W+Wl5Ekvo32qayB5PYX8zNjXzUkrTaJsWpaGmuw8Aspg== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + opencollective-postinstall@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" From 307e1972f4ed297b87cdad2a3d802a853820bded Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Fri, 19 Mar 2021 15:19:14 -0400 Subject: [PATCH 041/288] Analyze pr build (#3282) * deployer analyze-pr-build * hacky fixes * add the new file * add octokitpy * louder * post comment * int * testing something * smarter * bit louder * bit louder * bit louder * bit louder * use glob * it works * github_url * updates * Apply suggestions from code review Co-authored-by: Ryan Johnson * move print to CLI * basic tests Co-authored-by: Ryan Johnson --- deployer/README.md | 65 +++ deployer/poetry.lock | 659 +++++++++++++---------- deployer/pyproject.toml | 1 + deployer/src/deployer/analyze_pr.py | 184 +++++++ deployer/src/deployer/constants.py | 5 + deployer/src/deployer/main.py | 62 ++- deployer/src/deployer/test_analyze_pr.py | 112 ++++ 7 files changed, 798 insertions(+), 290 deletions(-) create mode 100644 deployer/src/deployer/analyze_pr.py create mode 100644 deployer/src/deployer/test_analyze_pr.py diff --git a/deployer/README.md b/deployer/README.md index 62396ca89320..efe4bf1804eb 100644 --- a/deployer/README.md +++ b/deployer/README.md @@ -168,6 +168,71 @@ This will first index all the files whose `index.json` file path (relative to the root) matches `en-us/docs/web`. Then it does all that match `en-us/docs`. And lastly, it does all the files that don't match any of the prefixes. +## Analyze PR builds + +When you've built files you can analyze those built files to produce a Markdown +comment that you can post as a PR issue comment. To do that, run: + +```sh +poetry run deployer analyze-pr-build ../client/build +``` + +But the actions are controlled by various options. You can mix and match these: + +### `--analyze-flaws` + +This will open each built `index.json` and look through the `.flaws` and try to +convert each flaw into a list. + +### `--analyze-dangerous-content` + +It will analyze all the content and look for content that could be "dangerous". +For example, it will list all external URLs found in the content. + +### `--prefix` + +The `prefix` refers to a prefix in the Deployer upload. I.e. what you set when +you run `poetry run deployer upload --prefix=THIS`. +The `prefix` is used to specify the proper Dev subdomain (`{prefix}.content.dev.mdn.mozit.cloud`) for the URLs of the built documents. For example, +if `--prefix experiment1` is specified, it will list: + +```md +## Preview deployment + +- +``` + +...assuming the only page that was built was `build/en-us/docs/mdn/kitchensink`. +Note that this assumes the PR build has been deployed to the Dev server. + +### `--repo` + +This is useful for debugging when the PR you made wasn't on `mdn/content`. For example: + +```sh +poetry run deployer analyze-pr-build ../client/build --repo peterbe/content ... +``` + +### `--github-token` + +By default it will pick up the `$GITHUB_TOKEN` environment variable but with this +option you can override it. + +### `--pr-number` + +This is needed to be able to find the PR (on ) +to post the comment to. + +### A complete example + +This example demonstrates all options. + +```sh +poetry run deployer --dry-run analyze-pr-build ../client/build \ + --analyze-flaws --analyze-dangerous-content --github-token="xxx" \ + --repo=peterbe/content --pr-number=3 +``` + ## Environment variables The following environment variables are supported. diff --git a/deployer/poetry.lock b/deployer/poetry.lock index db277b7fcdb0..244f31633031 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -1,40 +1,41 @@ [[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +name = "appdirs" optional = false python-versions = "*" +version = "1.4.4" [[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." category = "dev" +description = "Atomic file writes." +marker = "sys_platform == \"win32\"" +name = "atomicwrites" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.4.0" [[package]] -name = "attrs" -version = "20.3.0" -description = "Classes Without Boilerplate" category = "dev" +description = "Classes Without Boilerplate" +name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.3.0" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] -name = "black" -version = "20.8b1" -description = "The uncompromising code formatter." category = "dev" +description = "The uncompromising code formatter." +name = "black" optional = false python-versions = ">=3.6" +version = "20.8b1" [package.dependencies] appdirs = "*" @@ -51,12 +52,12 @@ colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] -name = "boto3" -version = "1.17.32" -description = "The AWS SDK for Python" category = "main" +description = "The AWS SDK for Python" +name = "boto3" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +version = "1.17.32" [package.dependencies] botocore = ">=1.20.32,<1.21.0" @@ -64,12 +65,12 @@ jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] -name = "botocore" -version = "1.20.32" -description = "Low-level, data-driven core of boto 3." category = "main" +description = "Low-level, data-driven core of boto 3." +name = "botocore" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +version = "1.20.32" [package.dependencies] jmespath = ">=0.7.1,<1.0.0" @@ -77,77 +78,92 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = ">=1.25.4,<1.27" [package.extras] -crt = ["awscrt (==0.10.8)"] +crt = ["awscrt (0.10.8)"] [[package]] -name = "certifi" -version = "2020.12.5" -description = "Python package for providing Mozilla's CA Bundle." category = "main" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" optional = false python-versions = "*" +version = "2020.12.5" [[package]] -name = "cffi" -version = "1.14.4" -description = "Foreign Function Interface for Python calling C code." category = "main" +description = "Foreign Function Interface for Python calling C code." +name = "cffi" optional = false python-versions = "*" +version = "1.14.5" [package.dependencies] pycparser = "*" [[package]] -name = "chardet" -version = "4.0.0" -description = "Universal encoding detector for Python 2 and 3" category = "main" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "4.0.0" [[package]] -name = "click" -version = "7.1.2" -description = "Composable command line interface toolkit" category = "main" +description = "Composable command line interface toolkit" +name = "click" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" [[package]] -name = "colorama" -version = "0.4.4" -description = "Cross-platform colored terminal text." category = "dev" +description = "Cross-platform colored terminal text." +marker = "sys_platform == \"win32\"" +name = "colorama" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.4" [[package]] -name = "cryptography" -version = "3.3.1" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +name = "cryptography" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" +python-versions = ">=3.6" +version = "3.4.6" [package.dependencies] cffi = ">=1.12" -six = ">=1.4.1" [package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0,<3.1.0 || >3.1.0,<3.1.1 || >3.1.1)", "sphinx-rtd-theme"] docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] + +[[package]] +category = "main" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +name = "deprecated" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.12" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] [[package]] -name = "elasticsearch" -version = "7.10.1" -description = "Python client for Elasticsearch" category = "main" +description = "Python client for Elasticsearch" +name = "elasticsearch" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" +version = "7.11.0" [package.dependencies] certifi = "*" @@ -160,12 +176,12 @@ docs = ["sphinx (<1.7)", "sphinx-rtd-theme"] requests = ["requests (>=2.4.0,<3.0.0)"] [[package]] -name = "elasticsearch-dsl" -version = "7.3.0" -description = "Python client for Elasticsearch" category = "main" +description = "Python client for Elasticsearch" +name = "elasticsearch-dsl" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "7.3.0" [package.dependencies] elasticsearch = ">=7.0.0,<8.0.0" @@ -176,147 +192,185 @@ six = "*" develop = ["mock", "pytest (>=3.0.0)", "pytest-cov", "pytest-mock (<3.0.0)", "pytz", "coverage (<5.0.0)", "sphinx", "sphinx-rtd-theme"] [[package]] -name = "flake8" -version = "3.9.0" -description = "the modular source code checker: pep8 pyflakes and co" category = "dev" +description = "the modular source code checker: pep8 pyflakes and co" +name = "flake8" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "3.9.0" [package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.7.0,<2.8.0" pyflakes = ">=2.3.0,<2.4.0" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + [[package]] -name = "idna" -version = "2.10" -description = "Internationalized Domain Names in Applications (IDNA)" category = "main" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.10" [[package]] -name = "importlib-metadata" -version = "3.3.0" -description = "Read metadata from Python packages" category = "dev" +description = "Read metadata from Python packages" +marker = "python_version < \"3.8\"" +name = "importlib-metadata" optional = false python-versions = ">=3.6" +version = "3.7.3" [package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" +[package.dependencies.typing-extensions] +python = "<3.8" +version = ">=3.6.4" + [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" category = "dev" +description = "iniconfig: brain-dead simple config-ini parsing" +name = "iniconfig" optional = false python-versions = "*" +version = "1.1.1" [[package]] -name = "jmespath" -version = "0.10.0" -description = "JSON Matching Expressions" category = "main" +description = "JSON Matching Expressions" +name = "jmespath" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.10.0" [[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe" optional = false python-versions = "*" +version = "0.6.1" [[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." category = "dev" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +name = "mypy-extensions" optional = false python-versions = "*" +version = "0.4.3" [[package]] -name = "packaging" -version = "20.8" -description = "Core utilities for Python packages" category = "dev" +description = "Core utilities for Python packages" +name = "packaging" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.9" [package.dependencies] pyparsing = ">=2.0.2" [[package]] -name = "pathspec" -version = "0.8.1" -description = "Utility library for gitignore style pattern matching of file paths." category = "dev" +description = "Utility library for gitignore style pattern matching of file paths." +name = "pathspec" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.8.1" [[package]] -name = "pluggy" -version = "0.13.1" -description = "plugin and hook calling mechanisms for python" category = "dev" +description = "plugin and hook calling mechanisms for python" +name = "pluggy" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.13.1" [package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" [package.extras] dev = ["pre-commit", "tox"] [[package]] -name = "py" -version = "1.10.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "py" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.10.0" [[package]] -name = "pycodestyle" -version = "2.7.0" -description = "Python style guide checker" category = "dev" +description = "Python style guide checker" +name = "pycodestyle" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.7.0" [[package]] -name = "pycparser" -version = "2.20" -description = "C parser in Python" category = "main" +description = "C parser in Python" +name = "pycparser" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.20" [[package]] -name = "pyflakes" -version = "2.3.0" -description = "passive checker of Python programs" category = "dev" +description = "passive checker of Python programs" +name = "pyflakes" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.3.0" [[package]] -name = "pyopenssl" -version = "20.0.1" -description = "Python wrapper module around the OpenSSL library" category = "main" +description = "Use the full Github API v3" +name = "pygithub" +optional = false +python-versions = ">=3.6" +version = "1.54.1" + +[package.dependencies] +deprecated = "*" +pyjwt = "<2.0" +requests = ">=2.14.0" + +[package.extras] +integrations = ["cryptography"] + +[[package]] +category = "main" +description = "JSON Web Token implementation in Python" +name = "pyjwt" +optional = false +python-versions = "*" +version = "1.7.1" + +[package.extras] +crypto = ["cryptography (>=1.4)"] +flake8 = ["flake8", "flake8-import-order", "pep8-naming"] +test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner (>=4.2,<5.0.0)"] + +[[package]] +category = "main" +description = "Python wrapper module around the OpenSSL library" +name = "pyopenssl" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +version = "20.0.1" [package.dependencies] cryptography = ">=3.2" @@ -327,162 +381,179 @@ docs = ["sphinx", "sphinx-rtd-theme"] test = ["flaky", "pretend", "pytest (>=3.0.1)"] [[package]] -name = "pyparsing" -version = "2.4.7" -description = "Python parsing module" category = "dev" +description = "Python parsing module" +name = "pyparsing" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.4.7" [[package]] -name = "pytest" -version = "6.2.2" -description = "pytest: simple powerful testing with Python" category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" optional = false python-versions = ">=3.6" +version = "6.2.2" [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +atomicwrites = ">=1.0" attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +colorama = "*" iniconfig = "*" packaging = "*" pluggy = ">=0.12,<1.0.0a1" py = ">=1.8.2" toml = "*" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] -name = "python-dateutil" -version = "2.8.1" -description = "Extensions to the standard Python datetime module" category = "main" +description = "Extensions to the standard Python datetime module" +name = "python-dateutil" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +version = "2.8.1" [package.dependencies] six = ">=1.5" [[package]] -name = "python-decouple" -version = "3.4" -description = "Strict separation of settings from code." category = "main" +description = "Strict separation of settings from code." +name = "python-decouple" optional = false python-versions = "*" +version = "3.4" [[package]] -name = "regex" -version = "2020.11.13" -description = "Alternative regular expression module, to replace re." category = "dev" +description = "Alternative regular expression module, to replace re." +name = "regex" optional = false python-versions = "*" +version = "2021.3.17" [[package]] -name = "requests" -version = "2.25.1" -description = "Python HTTP for Humans." category = "main" +description = "Python HTTP for Humans." +name = "requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.25.1" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<5" -cryptography = {version = ">=1.3.4", optional = true, markers = "extra == \"security\""} idna = ">=2.5,<3" -pyOpenSSL = {version = ">=0.14", optional = true, markers = "extra == \"security\""} urllib3 = ">=1.21.1,<1.27" +[package.dependencies.cryptography] +optional = true +version = ">=1.3.4" + +[package.dependencies.pyOpenSSL] +optional = true +version = ">=0.14" + [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] [[package]] -name = "s3transfer" -version = "0.3.3" -description = "An Amazon S3 Transfer Manager" category = "main" +description = "An Amazon S3 Transfer Manager" +name = "s3transfer" optional = false python-versions = "*" +version = "0.3.6" [package.dependencies] botocore = ">=1.12.36,<2.0a.0" [[package]] -name = "selectolax" -version = "0.2.10" -description = "Fast HTML5 parser with CSS selectors." category = "main" +description = "Fast HTML5 parser with CSS selectors." +name = "selectolax" optional = false python-versions = "*" +version = "0.2.10" [[package]] -name = "six" -version = "1.15.0" -description = "Python 2 and 3 compatibility utilities" category = "main" +description = "Python 2 and 3 compatibility utilities" +name = "six" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.15.0" [[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" category = "dev" +description = "Python Library for Tom's Obvious, Minimal Language" +name = "toml" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.10.2" [[package]] -name = "typed-ast" -version = "1.4.1" -description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" +description = "a fork of Python 2 and 3 ast modules with type comment support" +name = "typed-ast" optional = false python-versions = "*" +version = "1.4.2" [[package]] -name = "typing-extensions" -version = "3.7.4.3" -description = "Backported and Experimental Type Hints for Python 3.5+" category = "dev" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" optional = false python-versions = "*" +version = "3.7.4.3" [[package]] -name = "urllib3" -version = "1.26.2" -description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.26.4" [package.extras] brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[[package]] +category = "main" +description = "Module for decorators, wrappers and monkey patching." +name = "wrapt" +optional = false +python-versions = "*" +version = "1.12.1" [[package]] -name = "zipp" -version = "3.4.0" -description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" +description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\"" +name = "zipp" optional = false python-versions = ">=3.6" +version = "3.4.1" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -lock-version = "1.1" +content-hash = "7119424a717c77cc43df1bc868c91d9f2a3a6a79d3397fc143858718ecb45fe0" python-versions = "^3.7" -content-hash = "fc6df7112afa97a2dc58eee6d5df9c38764dd9eb417d9093b42f6d0367e69e5a" [metadata.files] appdirs = [ @@ -513,43 +584,43 @@ certifi = [ {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, ] cffi = [ - {file = "cffi-1.14.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775"}, - {file = "cffi-1.14.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06"}, - {file = "cffi-1.14.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26"}, - {file = "cffi-1.14.4-cp27-cp27m-win32.whl", hash = "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c"}, - {file = "cffi-1.14.4-cp27-cp27m-win_amd64.whl", hash = "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b"}, - {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d"}, - {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca"}, - {file = "cffi-1.14.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698"}, - {file = "cffi-1.14.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b"}, - {file = "cffi-1.14.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293"}, - {file = "cffi-1.14.4-cp35-cp35m-win32.whl", hash = "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2"}, - {file = "cffi-1.14.4-cp35-cp35m-win_amd64.whl", hash = "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7"}, - {file = "cffi-1.14.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b"}, - {file = "cffi-1.14.4-cp36-cp36m-win32.whl", hash = "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668"}, - {file = "cffi-1.14.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009"}, - {file = "cffi-1.14.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01"}, - {file = "cffi-1.14.4-cp37-cp37m-win32.whl", hash = "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e"}, - {file = "cffi-1.14.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35"}, - {file = "cffi-1.14.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e"}, - {file = "cffi-1.14.4-cp38-cp38-win32.whl", hash = "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d"}, - {file = "cffi-1.14.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375"}, - {file = "cffi-1.14.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e"}, - {file = "cffi-1.14.4-cp39-cp39-win32.whl", hash = "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3"}, - {file = "cffi-1.14.4-cp39-cp39-win_amd64.whl", hash = "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b"}, - {file = "cffi-1.14.4.tar.gz", hash = "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c"}, + {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, + {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, + {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, + {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, + {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, + {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, + {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, + {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, + {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, + {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, + {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, + {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, + {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, + {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, + {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, + {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, + {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, + {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, + {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, + {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, + {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, + {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, + {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, + {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, + {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, ] chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, @@ -561,27 +632,28 @@ click = [ ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] cryptography = [ - {file = "cryptography-3.3.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030"}, - {file = "cryptography-3.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f6b0492d111b43de5f70052e24c1f0951cb9e6022188ebcb1cc3a3d301469b0"}, - {file = "cryptography-3.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a69bd3c68b98298f490e84519b954335154917eaab52cf582fa2c5c7efc6e812"}, - {file = "cryptography-3.3.1-cp27-cp27m-win32.whl", hash = "sha256:84ef7a0c10c24a7773163f917f1cb6b4444597efd505a8aed0a22e8c4780f27e"}, - {file = "cryptography-3.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:594a1db4511bc4d960571536abe21b4e5c3003e8750ab8365fafce71c5d86901"}, - {file = "cryptography-3.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0003a52a123602e1acee177dc90dd201f9bb1e73f24a070db7d36c588e8f5c7d"}, - {file = "cryptography-3.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:83d9d2dfec70364a74f4e7c70ad04d3ca2e6a08b703606993407bf46b97868c5"}, - {file = "cryptography-3.3.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302"}, - {file = "cryptography-3.3.1-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:788a3c9942df5e4371c199d10383f44a105d67d401fb4304178020142f020244"}, - {file = "cryptography-3.3.1-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:69e836c9e5ff4373ce6d3ab311c1a2eed274793083858d3cd4c7d12ce20d5f9c"}, - {file = "cryptography-3.3.1-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:9e21301f7a1e7c03dbea73e8602905a4ebba641547a462b26dd03451e5769e7c"}, - {file = "cryptography-3.3.1-cp36-abi3-win32.whl", hash = "sha256:b4890d5fb9b7a23e3bf8abf5a8a7da8e228f1e97dc96b30b95685df840b6914a"}, - {file = "cryptography-3.3.1-cp36-abi3-win_amd64.whl", hash = "sha256:0e85aaae861d0485eb5a79d33226dd6248d2a9f133b81532c8f5aae37de10ff7"}, - {file = "cryptography-3.3.1.tar.gz", hash = "sha256:7e177e4bea2de937a584b13645cab32f25e3d96fc0bc4a4cf99c27dc77682be6"}, + {file = "cryptography-3.4.6-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799"}, + {file = "cryptography-3.4.6-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7"}, + {file = "cryptography-3.4.6-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3"}, + {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b"}, + {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"}, + {file = "cryptography-3.4.6-cp36-abi3-win32.whl", hash = "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2"}, + {file = "cryptography-3.4.6-cp36-abi3-win_amd64.whl", hash = "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0"}, + {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b"}, + {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df"}, + {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336"}, + {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724"}, + {file = "cryptography-3.4.6.tar.gz", hash = "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87"}, +] +deprecated = [ + {file = "Deprecated-1.2.12-py2.py3-none-any.whl", hash = "sha256:08452d69b6b5bc66e8330adde0a4f8642e969b9e1702904d137eeb29c8ffc771"}, + {file = "Deprecated-1.2.12.tar.gz", hash = "sha256:6d2de2de7931a968874481ef30208fd4e08da39177d61d3d4ebdf4366e7dbca1"}, ] elasticsearch = [ - {file = "elasticsearch-7.10.1-py2.py3-none-any.whl", hash = "sha256:4ebd34fd223b31c99d9f3b6b6236d3ac18b3046191a37231e8235b06ae7db955"}, - {file = "elasticsearch-7.10.1.tar.gz", hash = "sha256:a725dd923d349ca0652cf95d6ce23d952e2153740cf4ab6daf4a2d804feeed48"}, + {file = "elasticsearch-7.11.0-py2.py3-none-any.whl", hash = "sha256:a113cfcee9ba8565cd48a67b60e9903b67a81b3b80ddc6d3fb2c16789a58b763"}, + {file = "elasticsearch-7.11.0.tar.gz", hash = "sha256:1e24b33a82bf381b42d3b0d390f76fdb9d6a9d47b310dea8eaeb0a5933c394c0"}, ] elasticsearch-dsl = [ {file = "elasticsearch-dsl-7.3.0.tar.gz", hash = "sha256:0ed75f6ff037e36b2397a8e92cae0ddde79b83adc70a154b8946064cb62f7301"}, @@ -596,8 +668,8 @@ idna = [ {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.3.0-py3-none-any.whl", hash = "sha256:bf792d480abbd5eda85794e4afb09dd538393f7d6e6ffef6e9f03d2014cf9450"}, - {file = "importlib_metadata-3.3.0.tar.gz", hash = "sha256:5c5a2720817414a6c41f0a49993908068243ae02c1635a228126519b509c8aed"}, + {file = "importlib_metadata-3.7.3-py3-none-any.whl", hash = "sha256:b74159469b464a99cb8cc3e21973e4d96e05d3024d337313fedb618a6e86e6f4"}, + {file = "importlib_metadata-3.7.3.tar.gz", hash = "sha256:742add720a20d0467df2f444ae41704000f50e1234f46174b51f9c6031a1bd71"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -616,8 +688,8 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ - {file = "packaging-20.8-py2.py3-none-any.whl", hash = "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858"}, - {file = "packaging-20.8.tar.gz", hash = "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"}, + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] pathspec = [ {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, @@ -643,6 +715,14 @@ pyflakes = [ {file = "pyflakes-2.3.0-py2.py3-none-any.whl", hash = "sha256:910208209dcea632721cb58363d0f72913d9e8cf64dc6f8ae2e02a3609aba40d"}, {file = "pyflakes-2.3.0.tar.gz", hash = "sha256:e59fd8e750e588358f1b8885e5a4751203a0516e0ee6d34811089ac294c8806f"}, ] +pygithub = [ + {file = "PyGithub-1.54.1-py3-none-any.whl", hash = "sha256:87afd6a67ea582aa7533afdbf41635725f13d12581faed7e3e04b1579c0c0627"}, + {file = "PyGithub-1.54.1.tar.gz", hash = "sha256:300bc16e62886ca6537b0830e8f516ea4bc3ef12d308e0c5aff8bdbd099173d4"}, +] +pyjwt = [ + {file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"}, + {file = "PyJWT-1.7.1.tar.gz", hash = "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"}, +] pyopenssl = [ {file = "pyOpenSSL-20.0.1-py2.py3-none-any.whl", hash = "sha256:818ae18e06922c066f777a33f1fca45786d85edfe71cd043de6379337a7f274b"}, {file = "pyOpenSSL-20.0.1.tar.gz", hash = "sha256:4c231c759543ba02560fcd2480c48dcec4dae34c9da7d3747c508227e0624b51"}, @@ -664,55 +744,55 @@ python-decouple = [ {file = "python_decouple-3.4-py3-none-any.whl", hash = "sha256:a8268466e6389a639a20deab9d880faee186eb1eb6a05e54375bdf158d691981"}, ] regex = [ - {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, - {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, - {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, - {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, - {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, - {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, - {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, - {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, - {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, - {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, - {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, - {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, - {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, + {file = "regex-2021.3.17-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b97ec5d299c10d96617cc851b2e0f81ba5d9d6248413cd374ef7f3a8871ee4a6"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:cb4ee827857a5ad9b8ae34d3c8cc51151cb4a3fe082c12ec20ec73e63cc7c6f0"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:633497504e2a485a70a3268d4fc403fe3063a50a50eed1039083e9471ad0101c"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:a59a2ee329b3de764b21495d78c92ab00b4ea79acef0f7ae8c1067f773570afa"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f85d6f41e34f6a2d1607e312820971872944f1661a73d33e1e82d35ea3305e14"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4651f839dbde0816798e698626af6a2469eee6d9964824bb5386091255a1694f"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:39c44532d0e4f1639a89e52355b949573e1e2c5116106a395642cbbae0ff9bcd"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3d9a7e215e02bd7646a91fb8bcba30bc55fd42a719d6b35cf80e5bae31d9134e"}, + {file = "regex-2021.3.17-cp36-cp36m-win32.whl", hash = "sha256:159fac1a4731409c830d32913f13f68346d6b8e39650ed5d704a9ce2f9ef9cb3"}, + {file = "regex-2021.3.17-cp36-cp36m-win_amd64.whl", hash = "sha256:13f50969028e81765ed2a1c5fcfdc246c245cf8d47986d5172e82ab1a0c42ee5"}, + {file = "regex-2021.3.17-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9d8d286c53fe0cbc6d20bf3d583cabcd1499d89034524e3b94c93a5ab85ca90"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:201e2619a77b21a7780580ab7b5ce43835e242d3e20fef50f66a8df0542e437f"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d47d359545b0ccad29d572ecd52c9da945de7cd6cf9c0cfcb0269f76d3555689"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ea2f41445852c660ba7c3ebf7d70b3779b20d9ca8ba54485a17740db49f46932"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:486a5f8e11e1f5bbfcad87f7c7745eb14796642323e7e1829a331f87a713daaa"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:18e25e0afe1cf0f62781a150c1454b2113785401ba285c745acf10c8ca8917df"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:a2ee026f4156789df8644d23ef423e6194fad0bc53575534101bb1de5d67e8ce"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:4c0788010a93ace8a174d73e7c6c9d3e6e3b7ad99a453c8ee8c975ddd9965643"}, + {file = "regex-2021.3.17-cp37-cp37m-win32.whl", hash = "sha256:575a832e09d237ae5fedb825a7a5bc6a116090dd57d6417d4f3b75121c73e3be"}, + {file = "regex-2021.3.17-cp37-cp37m-win_amd64.whl", hash = "sha256:8e65e3e4c6feadf6770e2ad89ad3deb524bcb03d8dc679f381d0568c024e0deb"}, + {file = "regex-2021.3.17-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a0df9a0ad2aad49ea3c7f65edd2ffb3d5c59589b85992a6006354f6fb109bb18"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b98bc9db003f1079caf07b610377ed1ac2e2c11acc2bea4892e28cc5b509d8d5"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:808404898e9a765e4058bf3d7607d0629000e0a14a6782ccbb089296b76fa8fe"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:5770a51180d85ea468234bc7987f5597803a4c3d7463e7323322fe4a1b181578"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:976a54d44fd043d958a69b18705a910a8376196c6b6ee5f2596ffc11bff4420d"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:63f3ca8451e5ff7133ffbec9eda641aeab2001be1a01878990f6c87e3c44b9d5"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bcd945175c29a672f13fce13a11893556cd440e37c1b643d6eeab1988c8b209c"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:3d9356add82cff75413bec360c1eca3e58db4a9f5dafa1f19650958a81e3249d"}, + {file = "regex-2021.3.17-cp38-cp38-win32.whl", hash = "sha256:f5d0c921c99297354cecc5a416ee4280bd3f20fd81b9fb671ca6be71499c3fdf"}, + {file = "regex-2021.3.17-cp38-cp38-win_amd64.whl", hash = "sha256:14de88eda0976020528efc92d0a1f8830e2fb0de2ae6005a6fc4e062553031fa"}, + {file = "regex-2021.3.17-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4c2e364491406b7888c2ad4428245fc56c327e34a5dfe58fd40df272b3c3dab3"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux1_i686.whl", hash = "sha256:8bd4f91f3fb1c9b1380d6894bd5b4a519409135bec14c0c80151e58394a4e88a"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:882f53afe31ef0425b405a3f601c0009b44206ea7f55ee1c606aad3cc213a52c"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:07ef35301b4484bce843831e7039a84e19d8d33b3f8b2f9aab86c376813d0139"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:360a01b5fa2ad35b3113ae0c07fb544ad180603fa3b1f074f52d98c1096fa15e"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:709f65bb2fa9825f09892617d01246002097f8f9b6dde8d1bb4083cf554701ba"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:c66221e947d7207457f8b6f42b12f613b09efa9669f65a587a2a71f6a0e4d106"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c782da0e45aff131f0bed6e66fbcfa589ff2862fc719b83a88640daa01a5aff7"}, + {file = "regex-2021.3.17-cp39-cp39-win32.whl", hash = "sha256:dc9963aacb7da5177e40874585d7407c0f93fb9d7518ec58b86e562f633f36cd"}, + {file = "regex-2021.3.17-cp39-cp39-win_amd64.whl", hash = "sha256:a0d04128e005142260de3733591ddf476e4902c0c23c1af237d9acf3c96e1b38"}, + {file = "regex-2021.3.17.tar.gz", hash = "sha256:4b8a1fb724904139149a43e172850f35aa6ea97fb0545244dc0b805e0154ed68"}, ] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] s3transfer = [ - {file = "s3transfer-0.3.3-py2.py3-none-any.whl", hash = "sha256:2482b4259524933a022d59da830f51bd746db62f047d6eb213f2f8855dcb8a13"}, - {file = "s3transfer-0.3.3.tar.gz", hash = "sha256:921a37e2aefc64145e7b73d50c71bb4f26f46e4c9f414dc648c6245ff92cf7db"}, + {file = "s3transfer-0.3.6-py2.py3-none-any.whl", hash = "sha256:5d48b1fd2232141a9d5fb279709117aaba506cacea7f86f11bc392f06bfa8fc2"}, + {file = "s3transfer-0.3.6.tar.gz", hash = "sha256:c5dadf598762899d8cfaecf68eba649cd25b0ce93b6c954b156aaa3eed160547"}, ] selectolax = [ {file = "selectolax-0.2.10-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a18f75af342476356e5a437fc5215a3b79b58f52b56d9ea6e1a985cc21895952"}, @@ -769,36 +849,36 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] typed-ast = [ - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, - {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, - {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, - {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d"}, - {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, - {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c"}, - {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072"}, - {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91"}, - {file = "typed_ast-1.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d"}, - {file = "typed_ast-1.4.1-cp39-cp39-win32.whl", hash = "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395"}, - {file = "typed_ast-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c"}, - {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, + {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, + {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, + {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, + {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, + {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, + {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, + {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, + {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, + {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, ] typing-extensions = [ {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, @@ -806,10 +886,13 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] urllib3 = [ - {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, - {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, + {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, + {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, +] +wrapt = [ + {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] zipp = [ - {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, - {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, ] diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index ebe259e4a66d..b63b4d94ed7e 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -15,6 +15,7 @@ python-decouple = "^3.4" requests = {extras = ["security"], version = "^2.25.0"} elasticsearch-dsl = "^7.3.0" selectolax = "^0.2.10" +PyGithub = "^1.54.1" [tool.poetry.dev-dependencies] black = "^20.8b1" diff --git a/deployer/src/deployer/analyze_pr.py b/deployer/src/deployer/analyze_pr.py new file mode 100644 index 000000000000..07929a9d9b62 --- /dev/null +++ b/deployer/src/deployer/analyze_pr.py @@ -0,0 +1,184 @@ +import json +from collections import defaultdict +from pathlib import Path + +from github import Github +from selectolax.parser import HTMLParser + +from .utils import log + + +def analyze_pr(build_directory: Path, config): + """Given a directory of documents built from a PR, look through it and + post a GitHub PR comment or just print it to stdout.""" + + combined_comments = [] + + if config["prefix"]: + combined_comments.append(post_about_deployment(build_directory, **config)) + + if config["analyze_flaws"]: + combined_comments.append(post_about_flaws(build_directory, **config)) + + if config["analyze_dangerous_content"]: + combined_comments.append( + post_about_dangerous_content(build_directory, **config) + ) + + combined_comment = "\n\n".join(x for x in combined_comments if x) + + if not combined_comment: + print("Warning! Nothing to comment at all!") + return + + if not config["repo"]: + print("Warning! No 'repo' config") + elif not config["pr_number"]: + print("Warning! No 'pr_number' config") + elif config["repo"] and config["pr_number"]: + pr_url = f"https://github.com/{config['repo']}/pull/{config['pr_number']}" + if config["dry_run"]: + log.warning(f"Dry-run! Not actually posting any comment to {pr_url}") + else: + if not config["github_token"]: + raise Exception("No 'github_token' so no posting of comments") + + print(f"Posting to {pr_url}") + github = Github(config["github_token"]) + github_repo = github.get_repo(config["repo"]) + github_issue = github_repo.get_issue(number=int(config["pr_number"])) + github_issue.create_comment(combined_comment) + + return combined_comment + + +def post_about_deployment(build_directory: Path, **config): + template = "https://{prefix}.content.dev.mdn.mozit.cloud{mdn_url}" + + links = [] + for doc in get_built_docs(build_directory): + url = template.format(prefix=config["prefix"], mdn_url=doc["mdn_url"]) + links.append(f"- <{url}>") + + heading = "## Preview deployment URLs\n\n" + if links: + return heading + "\n".join(links) + + return heading + "*seems not a single file was built!* 🙀" + + +def post_about_dangerous_content(build_directory: Path, **config): + + OK_URL_PREFIXES = [ + "https://github.com/mdn/", + ] + + comments = [] + + for doc in get_built_docs(build_directory): + rendered_html = "\n".join( + x["value"]["content"] + for x in doc["body"] + if x["type"] == "prose" and x["value"]["content"] + ) + tree = HTMLParser(rendered_html) + external_urls = defaultdict(int) + for node in tree.css("a[href]"): + href = node.attributes.get("href") + href = href.split("#")[0] + # We're only interested in external URLs at the moment + if href.startswith("//") or "://" in href: + if any(href.lower().startswith(x.lower()) for x in OK_URL_PREFIXES): + # exceptions are skipped + continue + external_urls[href] += 1 + + if external_urls: + external_urls_list = [] + for url in sorted(external_urls): + count = external_urls[url] + + external_urls_list.append( + f" - <{url}> ({count} time{'' if count==1 else 's'})" + ) + comments.append((doc, "\n".join(external_urls_list))) + else: + comments.append((doc, "No external URLs")) + + heading = "## External URLs\n\n" + if comments: + per_doc_comments = [] + for doc, comment in comments: + per_doc_comments.append( + f"URL: `{doc['mdn_url']}`\n" + f"Title: `{doc['title']}`\n" + f"[on GitHub]({doc['source']['github_url']})\n" + "\n" + f"{comment}" + ) + return heading + "\n---\n".join(per_doc_comments) + else: + return heading + "*no external links in the built pages* 👱🏽" + + +def post_about_flaws(build_directory: Path, **config): + + comments = [] + + for doc in get_built_docs(build_directory): + if not doc.get("flaws"): + comments.append((doc, "No flaws!")) + continue + else: + flaws_list = [] + for flaw_name, flaw_values in doc["flaws"].items(): + flaws_list.append(f"- **{flaw_name}**:") + for flaw_value in flaw_values: + if isinstance(flaw_value, dict): + explanation = flaw_value.get("explanation") + else: + explanation = str(flaw_value) + if explanation: + flaws_list.append(f" - `{explanation}`") + else: + flaws_list.append(" - *no explanation!*") + + comments.append((doc, "\n".join(flaws_list))) + + def count_flaws(flaws): + count = 0 + for flaw in flaws.values(): + count += len(flaw) + return count + + heading = "## Flaws\n\n" + + if comments: + # Now turn all of these individual comments into one big one + per_doc_comments = [] + for doc, comment in comments: + per_doc_comments.append( + f"URL: `{doc['mdn_url']}`\n" + f"Title: `{doc['title']}`\n" + f"[on GitHub]({doc['source']['github_url']})\n" + f"Flaw count: {count_flaws(doc['flaws'])}\n" + "\n" + f"{comment}" + ) + return heading + "\n---\n".join(per_doc_comments) + else: + return heading + "*none!* 🎉" + + +def get_built_docs(build_directory: Path): + assert build_directory.exists, f"{build_directory} does not exist" + docs = [] + for path in build_directory.rglob("index.json"): + with open(path) as f: + data = json.load(f) + if "doc" not in data: + # Not every build index.json file is for a document. + continue + doc = data["doc"] + docs.append(doc) + return docs diff --git a/deployer/src/deployer/constants.py b/deployer/src/deployer/constants.py index 0911d8caeeda..af9ed8ac98b7 100644 --- a/deployer/src/deployer/constants.py +++ b/deployer/src/deployer/constants.py @@ -49,3 +49,8 @@ # instance of Elasticsearch 7 and start it. Then set this environment variable # value to `http://localhost:9200` ELASTICSEARCH_URL = config("DEPLOYER_ELASTICSEARCH_URL", default=None) + + +DEFAULT_REPO = config("GITHUB_REPOSITORY", default=None) + +DEFAULT_GITHUB_TOKEN = config("GITHUB_TOKEN", default=None) diff --git a/deployer/src/deployer/main.py b/deployer/src/deployer/main.py index c3c053a7d81d..0fec041f18f1 100644 --- a/deployer/src/deployer/main.py +++ b/deployer/src/deployer/main.py @@ -11,6 +11,8 @@ DEFAULT_BUCKET_NAME, DEFAULT_BUCKET_PREFIX, DEFAULT_NO_PROGRESSBAR, + DEFAULT_REPO, + DEFAULT_GITHUB_TOKEN, SPEEDCURVE_DEPLOY_API_KEY, SPEEDCURVE_DEPLOY_SITE_ID, ELASTICSEARCH_URL, @@ -20,6 +22,7 @@ from .utils import log from .whatsdeployed import dump as dump_whatsdeployed from .speedcurve import deploy_ping as speedcurve_deploy_ping +from .analyze_pr import analyze_pr from . import search @@ -129,7 +132,7 @@ def whatsdeployed(ctx, directory: Path, output: str): help="The path to the root folder of the main content (defaults to CONTENT_ROOT)", default=CONTENT_ROOT, show_default=True, - callback=validate_directory, + callback=validate_optional_directory, ) @click.option( "--content-translated-root", @@ -180,11 +183,17 @@ def whatsdeployed(ctx, directory: Path, output: str): @click.pass_context def upload(ctx, directory: Path, **kwargs): log.info(f"Deployer ({__version__})", bold=True) - content_roots = [kwargs["content_root"]] + content_roots = [] + if kwargs["content_root"]: + content_roots.append(kwargs["content_root"]) if kwargs["content_translated_root"]: content_roots.append(kwargs["content_translated_root"]) if kwargs["content_archived_root"]: content_roots.append(kwargs["content_archived_root"]) + if not kwargs["no_redirects"] and not content_roots: + raise Exception( + "if you don't use --no-redirects you have to have at least one content root" + ) if kwargs["prune"] and not kwargs["archived_files"]: log.warning( @@ -195,6 +204,55 @@ def upload(ctx, directory: Path, **kwargs): upload_content(directory, content_roots, ctx.obj) +@cli.command() +@click.option( + "--prefix", + help="What prefix was it uploaded as", + default=None, + show_default=True, +) +@click.option( + "--repo", + help="Name of the repo (e.g. mdn/content)", + default=DEFAULT_REPO, + show_default=True, +) +@click.option( + "--pr-number", + help="Number for the PR", + default=None, +) +@click.option( + "--github-token", + help="Token used to post PR comments", + default=DEFAULT_GITHUB_TOKEN, + show_default=False, +) +@click.option( + "--analyze-flaws", + help="Analyze the .doc.flaws keys in the index.json files", + default=False, + show_default=True, + is_flag=True, +) +@click.option( + "--analyze-dangerous-content", + help='Look through the built content and list "dangerous things"', + default=False, + show_default=True, + is_flag=True, +) +@click.argument("directory", type=click.Path(), callback=validate_directory) +@click.pass_context +def analyze_pr_build(ctx, directory: Path, **kwargs): + log.info(f"Deployer ({__version__})", bold=True) + ctx.obj.update(kwargs) + combined_comment = analyze_pr(directory, ctx.obj) + log.info("POST".center(80, "_"), "\n") + log.info(combined_comment) + log.info("\n", "END POST".center(80, "_")) + + @cli.command() @click.option( "--api-key", diff --git a/deployer/src/deployer/test_analyze_pr.py b/deployer/src/deployer/test_analyze_pr.py new file mode 100644 index 000000000000..9c6734d399fe --- /dev/null +++ b/deployer/src/deployer/test_analyze_pr.py @@ -0,0 +1,112 @@ +import json +import tempfile +from contextlib import contextmanager +from pathlib import Path +from unittest.mock import patch + +from deployer.analyze_pr import analyze_pr + +DEFAULT_CONFIG = { + "prefix": None, + "analyze_flaws": False, + "analyze_dangerous_content": False, + "repo": "mdn/content", + "pr_number": None, + "dry_run": False, + "github_token": "", +} + + +@contextmanager +def mock_build_directory(*docs): + with tempfile.TemporaryDirectory() as tmpdirname: + dirname = Path(tmpdirname) + for i, doc in enumerate(docs): + doc_dirname = dirname / f"doc{i}" + doc_dirname.mkdir() + with open(doc_dirname / "index.json", "w") as f: + json.dump(doc, f) + yield dirname + + +def test_analyze_pr_prefix(): + doc = {"doc": {"mdn_url": "/en-US/docs/Foo"}} + with mock_build_directory(doc) as build_directory: + comment = analyze_pr(build_directory, dict(DEFAULT_CONFIG, prefix="pr007")) + assert "## Preview deployment URLs" in comment + assert "- " in comment + + +def test_analyze_pr_flaws(): + doc = { + "doc": { + "mdn_url": "/en-US/docs/Foo", + "title": "Foo", + "flaws": { + "faux_pas": [ + {"explanation": "Socks in sandals"}, + {"explanation": "Congrats on losing your cat"}, + ], + }, + "source": {"github_url": "https://github.com/foo"}, + } + } + no_flaws_doc = { + "doc": { + "mdn_url": "/en-US/docs/Bar", + "title": "Bar", + "flaws": {}, + "source": {"github_url": "https://github.com/bar"}, + } + } + with mock_build_directory(no_flaws_doc, doc) as build_directory: + comment = analyze_pr(build_directory, dict(DEFAULT_CONFIG, analyze_flaws=True)) + assert "## Flaws" in comment + assert "Flaw count: 0" in comment + assert "Flaw count: 2" in comment + assert len(comment.split("\n---\n")) == 2 + assert "- **faux_pas**:" in comment + assert " - `Socks in sandals`" in comment + assert " - `Congrats on losing your cat`" in comment + + +def test_analyze_pr_dangerous_content(): + doc = { + "doc": { + "mdn_url": "/en-US/docs/Foo", + "title": "Foo", + "body": [ + { + "type": "prose", + "value": { + "content": """ +

      + Peterbe.com +

      + """ + }, + } + ], + "source": {"github_url": "https://github.com/foo"}, + } + } + with mock_build_directory(doc) as build_directory: + comment = analyze_pr( + build_directory, dict(DEFAULT_CONFIG, analyze_dangerous_content=True) + ) + assert "## External URLs" in comment + assert " - (1 time)" in comment + + +@patch("deployer.analyze_pr.Github") +def test_analyze_pr_prefix_and_postcomment(mocked_github): + doc = {"doc": {"mdn_url": "/en-US/docs/Foo"}} + with mock_build_directory(doc) as build_directory: + comment = analyze_pr( + build_directory, + dict(DEFAULT_CONFIG, prefix="pr007", pr_number=123, github_token="abc123"), + ) + assert "## Preview deployment URLs" in comment + assert "- " in comment + + mocked_github().get_repo().get_issue().create_comment.assert_called() From 6d4fde03da6178c1a77c6ac4dbfd5acfdc98abbf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Mar 2021 06:53:25 +0000 Subject: [PATCH 042/288] build(deps-dev): bump html-validate from 4.7.0 to 4.7.1 (#3291) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fbfbdca3aef8..e4e024b196ae 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "fuzzyjs": "4.0.4", "fuzzysearch": "1.0.3", "history": "5.0.0", - "html-validate": "4.7.0", + "html-validate": "4.7.1", "husky": "4.3.8", "ignore-loader": "^0.1.2", "jest-environment-jsdom-sixteen": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index e0c52aa18bbb..3f466f193a8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9333,10 +9333,10 @@ html-tags@^3.1.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== -html-validate@4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/html-validate/-/html-validate-4.7.0.tgz#98df8689a2021f069962294d824697412a2c820d" - integrity sha512-tu6xLlHQY4RkfXtR5d8WjJ8+w2BbZZGtAdgtL3C7tRjepFtVluu3vLpGPEfi3NP9wZf9Xk2/Dgm9RK48StqVpA== +html-validate@4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/html-validate/-/html-validate-4.7.1.tgz#7d7a504ce9555fe83e40a5d1c4c3544929491141" + integrity sha512-GelR6b//NLRrgbdn9K//dCJd/FhU6IPNliPIryLq0EUb/6a9hD1+ihoqIHHoqZHMIdk5e7epKEJpaxEZeRJ1Fg== dependencies: "@babel/code-frame" "^7.10.4" "@html-validate/stylish" "1.0.0" From 179385b3e46325f04ce3c18e2a9c6380d69fc1dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Mar 2021 06:54:11 +0000 Subject: [PATCH 043/288] build(deps): bump open from 8.0.3 to 8.0.4 (#3292) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e4e024b196ae..dcb0353806b7 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "loglevel": "^1.7.1", "lru-cache": "^6.0.0", "mdn-data": "2.0.17", - "open": "^8.0.3", + "open": "^8.0.4", "open-editor": "3.0.0", "prismjs": "1.23.0", "read-chunk": "3.2.0", diff --git a/yarn.lock b/yarn.lock index 3f466f193a8d..3b0c6f70e2bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12858,10 +12858,10 @@ open@^7.0.2, open@^7.0.3, open@^7.3.0: is-docker "^2.0.0" is-wsl "^2.1.1" -open@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/open/-/open-8.0.3.tgz#04f4406c950666c35041aad8a621700022116afd" - integrity sha512-7nsHNw3rOIPTwhF5iYkgE+LVM/oUHWC3cgrWNxPqa+W+Wl5Ekvo32qayB5PYX8zNjXzUkrTaJsWpaGmuw8Aspg== +open@^8.0.4: + version "8.0.4" + resolved "https://registry.yarnpkg.com/open/-/open-8.0.4.tgz#2fb90debffcf20f4d7be537502ed3e3ee9e5dcbc" + integrity sha512-Txc9FOcvjrr5Kv+Zb3w89uKMKiP7wH8mLdYj1xJa+YnhhntEYhbB6cQHjS4O6P+jFwMEzEQVVcpfnu9WkKNuLQ== dependencies: define-lazy-prop "^2.0.0" is-docker "^2.1.1" From d28cb84cdff0b6236272d3dda0a48b580f6e5600 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Mar 2021 06:55:17 +0000 Subject: [PATCH 044/288] build(deps-dev): bump swr from 0.5.3 to 0.5.4 (#3293) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index dcb0353806b7..734dd25a3d9f 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "stylelint-config-sass-guidelines": "^8.0.0", "stylelint-prettier": "^1.2.0", "stylelint-scss": "^3.19.0", - "swr": "^0.5.3", + "swr": "^0.5.4", "ts-loader": "^8.0.18", "typescript": "^4.2.3", "use-debounce": "^5.2.1", diff --git a/yarn.lock b/yarn.lock index 3b0c6f70e2bc..eede4d1412b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16916,10 +16916,10 @@ svgo@^2.1.0: csso "^4.2.0" stable "^0.1.8" -swr@^0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/swr/-/swr-0.5.3.tgz#7290a9a61329d930583ef365317e636b8dbaa8bb" - integrity sha512-RUE3RWn3jt9e4qLPat2A9vbHG/5N6konsc27xKjE65jFSiGv0P7HLD8IGvwAv6DRKktL7Od2UcayX0plKb2awg== +swr@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/swr/-/swr-0.5.4.tgz#9516af6ffd84ba2c23a804ff771be2eb83ba8d46" + integrity sha512-TUSxxuC8uP/4JKV22ml91WQ0tbif+9HVhm683xm8KYfwZIW5ogwcnU634dg3x6N7azpIDIOLokoIi+z5vCz/yA== symbol-tree@^3.2.4: version "3.2.4" From db7148375a30a6674bbb32aa75de30366a76d826 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Mar 2021 06:57:41 +0000 Subject: [PATCH 045/288] build(deps-dev): bump downshift from 6.1.0 to 6.1.1 (#3295) --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 734dd25a3d9f..1d08f7c2c3f5 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "braces": "^3.0.2", "cross-env": "^7.0.3", "diff": "^5.0.0", - "downshift": "^6.1.0", + "downshift": "^6.1.1", "eslint": "^7.18.0", "eslint-gitignore": "^0.1.0", "eslint-plugin-jest": "24.3.2", diff --git a/yarn.lock b/yarn.lock index eede4d1412b9..faf5813253c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5708,10 +5708,10 @@ compression@1.7.4, compression@^1.7.4: safe-buffer "5.1.2" vary "~1.1.2" -compute-scroll-into-view@^1.0.16: - version "1.0.16" - resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088" - integrity sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ== +compute-scroll-into-view@^1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab" + integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg== concat-map@0.0.1: version "0.0.1" @@ -6961,13 +6961,13 @@ download@^7.1.0: p-event "^2.1.0" pify "^3.0.0" -downshift@^6.0.6, downshift@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/downshift/-/downshift-6.1.0.tgz#f008063d9b63935910d9db12ead07979ab51ce66" - integrity sha512-MnEJERij+1pTVAsOPsH3q9MJGNIZuu2sT90uxOCEOZYH6sEzkVGtUcTBVDRQkE8y96zpB7uEbRn24aE9VpHnZg== +downshift@^6.0.6, downshift@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/downshift/-/downshift-6.1.1.tgz#3c8f5a64cc678e1b45a87b80647ea5351af13e5e" + integrity sha512-ch8Sh/j7gVqQd7Kcv3A5TkGfldmxmlQrRPZJYWEhzh24+h7WA4vXssuhcGNJrD8YPJlZYQGHcaX8BNhS0IcOvg== dependencies: "@babel/runtime" "^7.12.5" - compute-scroll-into-view "^1.0.16" + compute-scroll-into-view "^1.0.17" prop-types "^15.7.2" react-is "^17.0.1" From 60d2c008ce1473d3b7c2cbb6042823a3dc1a7ec9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Mar 2021 08:28:14 +0000 Subject: [PATCH 046/288] build(deps): bump boto3 from 1.17.32 to 1.17.33 in /deployer (#3296) --- deployer/poetry.lock | 353 +++++++++++++++++++--------------------- deployer/pyproject.toml | 2 +- 2 files changed, 168 insertions(+), 187 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index 244f31633031..4f01ef85dbef 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -1,41 +1,40 @@ [[package]] -category = "dev" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = "*" -version = "1.4.4" [[package]] -category = "dev" -description = "Atomic file writes." -marker = "sys_platform == \"win32\"" name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.4.0" [[package]] -category = "dev" -description = "Classes Without Boilerplate" name = "attrs" +version = "20.3.0" +description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.3.0" [package.extras] -dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] -category = "dev" -description = "The uncompromising code formatter." name = "black" +version = "20.8b1" +description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.6" -version = "20.8b1" [package.dependencies] appdirs = "*" @@ -52,25 +51,25 @@ colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] -category = "main" -description = "The AWS SDK for Python" name = "boto3" +version = "1.17.33" +description = "The AWS SDK for Python" +category = "main" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" -version = "1.17.32" [package.dependencies] -botocore = ">=1.20.32,<1.21.0" +botocore = ">=1.20.33,<1.21.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] -category = "main" -description = "Low-level, data-driven core of boto 3." name = "botocore" +version = "1.20.33" +description = "Low-level, data-driven core of boto 3." +category = "main" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" -version = "1.20.32" [package.dependencies] jmespath = ">=0.7.1,<1.0.0" @@ -78,78 +77,77 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = ">=1.25.4,<1.27" [package.extras] -crt = ["awscrt (0.10.8)"] +crt = ["awscrt (==0.10.8)"] [[package]] -category = "main" -description = "Python package for providing Mozilla's CA Bundle." name = "certifi" +version = "2020.12.5" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = "*" -version = "2020.12.5" [[package]] -category = "main" -description = "Foreign Function Interface for Python calling C code." name = "cffi" +version = "1.14.5" +description = "Foreign Function Interface for Python calling C code." +category = "main" optional = false python-versions = "*" -version = "1.14.5" [package.dependencies] pycparser = "*" [[package]] -category = "main" -description = "Universal encoding detector for Python 2 and 3" name = "chardet" +version = "4.0.0" +description = "Universal encoding detector for Python 2 and 3" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "4.0.0" [[package]] -category = "main" -description = "Composable command line interface toolkit" name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1.2" [[package]] -category = "dev" -description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\"" name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.4.4" [[package]] -category = "main" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." name = "cryptography" +version = "3.4.6" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" optional = false python-versions = ">=3.6" -version = "3.4.6" [package.dependencies] cffi = ">=1.12" [package.extras] -docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0,<3.1.0 || >3.1.0,<3.1.1 || >3.1.1)", "sphinx-rtd-theme"] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] +test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] -category = "main" -description = "Python @deprecated decorator to deprecate old python classes, functions or methods." name = "deprecated" +version = "1.2.12" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.2.12" [package.dependencies] wrapt = ">=1.10,<2" @@ -158,12 +156,12 @@ wrapt = ">=1.10,<2" dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] [[package]] -category = "main" -description = "Python client for Elasticsearch" name = "elasticsearch" +version = "7.11.0" +description = "Python client for Elasticsearch" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" -version = "7.11.0" [package.dependencies] certifi = "*" @@ -176,12 +174,12 @@ docs = ["sphinx (<1.7)", "sphinx-rtd-theme"] requests = ["requests (>=2.4.0,<3.0.0)"] [[package]] -category = "main" -description = "Python client for Elasticsearch" name = "elasticsearch-dsl" +version = "7.3.0" +description = "Python client for Elasticsearch" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "7.3.0" [package.dependencies] elasticsearch = ">=7.0.0,<8.0.0" @@ -192,156 +190,147 @@ six = "*" develop = ["mock", "pytest (>=3.0.0)", "pytest-cov", "pytest-mock (<3.0.0)", "pytz", "coverage (<5.0.0)", "sphinx", "sphinx-rtd-theme"] [[package]] -category = "dev" -description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" +version = "3.9.0" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "3.9.0" [package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.7.0,<2.8.0" pyflakes = ">=2.3.0,<2.4.0" -[package.dependencies.importlib-metadata] -python = "<3.8" -version = "*" - [[package]] -category = "main" -description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" +version = "2.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.10" [[package]] -category = "dev" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" name = "importlib-metadata" +version = "3.7.3" +description = "Read metadata from Python packages" +category = "dev" optional = false python-versions = ">=3.6" -version = "3.7.3" [package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" -[package.dependencies.typing-extensions] -python = "<3.8" -version = ">=3.6.4" - [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] -category = "dev" -description = "iniconfig: brain-dead simple config-ini parsing" name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" optional = false python-versions = "*" -version = "1.1.1" [[package]] -category = "main" -description = "JSON Matching Expressions" name = "jmespath" +version = "0.10.0" +description = "JSON Matching Expressions" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.10.0" [[package]] -category = "dev" -description = "McCabe checker, plugin for flake8" name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" -version = "0.6.1" [[package]] -category = "dev" -description = "Experimental type system extensions for programs checked with the mypy typechecker." name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" optional = false python-versions = "*" -version = "0.4.3" [[package]] -category = "dev" -description = "Core utilities for Python packages" name = "packaging" +version = "20.9" +description = "Core utilities for Python packages" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.9" [package.dependencies] pyparsing = ">=2.0.2" [[package]] -category = "dev" -description = "Utility library for gitignore style pattern matching of file paths." name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.8.1" [[package]] -category = "dev" -description = "plugin and hook calling mechanisms for python" name = "pluggy" +version = "0.13.1" +description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.13.1" [package.dependencies] -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] [[package]] -category = "dev" -description = "library with cross-python path, ini-parsing, io, code, log facilities" name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.10.0" [[package]] -category = "dev" -description = "Python style guide checker" name = "pycodestyle" +version = "2.7.0" +description = "Python style guide checker" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.7.0" [[package]] -category = "main" -description = "C parser in Python" name = "pycparser" +version = "2.20" +description = "C parser in Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.20" [[package]] -category = "dev" -description = "passive checker of Python programs" name = "pyflakes" +version = "2.3.0" +description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.3.0" [[package]] -category = "main" -description = "Use the full Github API v3" name = "pygithub" +version = "1.54.1" +description = "Use the full Github API v3" +category = "main" optional = false python-versions = ">=3.6" -version = "1.54.1" [package.dependencies] deprecated = "*" @@ -352,12 +341,12 @@ requests = ">=2.14.0" integrations = ["cryptography"] [[package]] -category = "main" -description = "JSON Web Token implementation in Python" name = "pyjwt" +version = "1.7.1" +description = "JSON Web Token implementation in Python" +category = "main" optional = false python-versions = "*" -version = "1.7.1" [package.extras] crypto = ["cryptography (>=1.4)"] @@ -365,12 +354,12 @@ flake8 = ["flake8", "flake8-import-order", "pep8-naming"] test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner (>=4.2,<5.0.0)"] [[package]] -category = "main" -description = "Python wrapper module around the OpenSSL library" name = "pyopenssl" +version = "20.0.1" +description = "Python wrapper module around the OpenSSL library" +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -version = "20.0.1" [package.dependencies] cryptography = ">=3.2" @@ -381,179 +370,170 @@ docs = ["sphinx", "sphinx-rtd-theme"] test = ["flaky", "pretend", "pytest (>=3.0.1)"] [[package]] -category = "dev" -description = "Python parsing module" name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.7" [[package]] -category = "dev" -description = "pytest: simple powerful testing with Python" name = "pytest" +version = "6.2.2" +description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.6" -version = "6.2.2" [package.dependencies] -atomicwrites = ">=1.0" +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" -colorama = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<1.0.0a1" py = ">=1.8.2" toml = "*" -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" - [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] -category = "main" -description = "Extensions to the standard Python datetime module" name = "python-dateutil" +version = "2.8.1" +description = "Extensions to the standard Python datetime module" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -version = "2.8.1" [package.dependencies] six = ">=1.5" [[package]] -category = "main" -description = "Strict separation of settings from code." name = "python-decouple" +version = "3.4" +description = "Strict separation of settings from code." +category = "main" optional = false python-versions = "*" -version = "3.4" [[package]] -category = "dev" -description = "Alternative regular expression module, to replace re." name = "regex" +version = "2021.3.17" +description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = "*" -version = "2021.3.17" [[package]] -category = "main" -description = "Python HTTP for Humans." name = "requests" +version = "2.25.1" +description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.25.1" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<5" +cryptography = {version = ">=1.3.4", optional = true, markers = "extra == \"security\""} idna = ">=2.5,<3" +pyOpenSSL = {version = ">=0.14", optional = true, markers = "extra == \"security\""} urllib3 = ">=1.21.1,<1.27" -[package.dependencies.cryptography] -optional = true -version = ">=1.3.4" - -[package.dependencies.pyOpenSSL] -optional = true -version = ">=0.14" - [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] -category = "main" -description = "An Amazon S3 Transfer Manager" name = "s3transfer" +version = "0.3.6" +description = "An Amazon S3 Transfer Manager" +category = "main" optional = false python-versions = "*" -version = "0.3.6" [package.dependencies] botocore = ">=1.12.36,<2.0a.0" [[package]] -category = "main" -description = "Fast HTML5 parser with CSS selectors." name = "selectolax" +version = "0.2.10" +description = "Fast HTML5 parser with CSS selectors." +category = "main" optional = false python-versions = "*" -version = "0.2.10" [[package]] -category = "main" -description = "Python 2 and 3 compatibility utilities" name = "six" +version = "1.15.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.15.0" [[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.10.2" [[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" +version = "1.4.2" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false python-versions = "*" -version = "1.4.2" [[package]] -category = "dev" -description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" +version = "3.7.4.3" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" optional = false python-versions = "*" -version = "3.7.4.3" [[package]] -category = "main" -description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" +version = "1.26.4" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.26.4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotlipy (>=0.6.0)"] [[package]] -category = "main" -description = "Module for decorators, wrappers and monkey patching." name = "wrapt" +version = "1.12.1" +description = "Module for decorators, wrappers and monkey patching." +category = "main" optional = false python-versions = "*" -version = "1.12.1" [[package]] -category = "dev" -description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" name = "zipp" +version = "3.4.1" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" optional = false python-versions = ">=3.6" -version = "3.4.1" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -content-hash = "7119424a717c77cc43df1bc868c91d9f2a3a6a79d3397fc143858718ecb45fe0" +lock-version = "1.1" python-versions = "^3.7" +content-hash = "6ec3c53b11db10e780442e1608e422d4b7559576e9c469b75675dca567817257" [metadata.files] appdirs = [ @@ -572,12 +552,12 @@ black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] boto3 = [ - {file = "boto3-1.17.32-py2.py3-none-any.whl", hash = "sha256:85069e044c871571b7a72b600123761e1747ad18328fa5188f13b097a394251d"}, - {file = "boto3-1.17.32.tar.gz", hash = "sha256:2df49a4360ef0640902c26bf93ac0791b37755db3a2efd0d51a03eddeb9f807e"}, + {file = "boto3-1.17.33-py2.py3-none-any.whl", hash = "sha256:3306dad87f993703b102a0a70ca19c549b7f41e7f70fa7b4c579735c9f79351d"}, + {file = "boto3-1.17.33.tar.gz", hash = "sha256:0cac2fffc1ba915f7bb5ecee539318532db51f218c928a228fafe3e501e9472e"}, ] botocore = [ - {file = "botocore-1.20.32-py2.py3-none-any.whl", hash = "sha256:fc162b69adc54c9ef037fec31f93d46df0bf8a9c3d201ecb16d0a9ec5f2936ec"}, - {file = "botocore-1.20.32.tar.gz", hash = "sha256:1cef96e716f7481bfb3b8d3c3d45e640d588aa5af613cd6d7f33d784aa2e8d12"}, + {file = "botocore-1.20.33-py2.py3-none-any.whl", hash = "sha256:a33e862685259fe22d9790d9c9f3567feda8b824d44d3c62a3617af1133543a4"}, + {file = "botocore-1.20.33.tar.gz", hash = "sha256:e355305309699d3aca1e0050fc21d48595b40db046cb0d2491cd57ff5b26920b"}, ] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, @@ -632,6 +612,7 @@ click = [ ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] cryptography = [ {file = "cryptography-3.4.6-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799"}, diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index b63b4d94ed7e..c5ebc653442e 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.7" click = "^7.1.2" -boto3 = "^1.17.32" +boto3 = "^1.17.33" python-decouple = "^3.4" requests = {extras = ["security"], version = "^2.25.0"} elasticsearch-dsl = "^7.3.0" From 7be490ae3f2e3dcab652423088110ea0cde2ea3b Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 22 Mar 2021 09:13:19 -0400 Subject: [PATCH 047/288] /pagenotfound is rendering the homepage route (#3288) * /pagenotfound is rendering the homepage route Fixes #3224 Fixes #3287 * refactor --- client/src/app.tsx | 38 +++++++++++-------- client/src/constants.ts | 41 +++++++++++++++++++++ client/src/hooks.ts | 17 ++++++++- client/src/page-not-found/fallback-link.tsx | 2 +- server/index.js | 13 ++++--- 5 files changed, 88 insertions(+), 23 deletions(-) diff --git a/client/src/app.tsx b/client/src/app.tsx index 15b36a19dfa3..2fbf8c25f227 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -58,9 +58,9 @@ function DocumentLayout({ children }) { * originally not found. Perhaps, this new location that the client is * requesting is going to work. */ -function DocumentOrPageNotFound(props) { +function PageOrPageNotFound({ pageNotFound, children }) { // It's true by default if the SSR rendering says so. - const [notFound, setNotFound] = React.useState(!!props.pageNotFound); + const [notFound, setNotFound] = React.useState(!!pageNotFound); const { pathname } = useLocation(); const initialPathname = React.useRef(pathname); React.useEffect(() => { @@ -74,9 +74,7 @@ function DocumentOrPageNotFound(props) { ) : ( - - - + children ); } @@ -97,7 +95,17 @@ export function App(appProps) { // But if the App is loaded from the code that builds the SPAs, then `isServer` // is true. So you have to have `isServer && CRUD_MODE` at the same time. const homePage = - !isServer && CRUD_MODE ? : ; + !isServer && CRUD_MODE ? ( + + + + ) : ( + + + + + + ); const routes = ( @@ -107,10 +115,7 @@ export function App(appProps) { having a locale. So it'll be `/en-US` (for example) by the time it hits any React code. */} - {homePage}} - /> + )} - {homePage}} - /> + } + element={ + + + + + + } /> component can know what it needs to render but what's problematic +// is that all and any other app will think that the locale is `some-random-word` +// just because it's the first portion of the URL. +// So, for example, the top navbar will think it can use the `useLocale()` hook +// and get the current locale from the react-router context. Now the navbar menu +// items, for example, will think the locale is `some-random-word` and make links +// like `/some-random-word/docs/Web`. +import { VALID_LOCALES } from "./constants"; + export function useLocale() { - return useParams().locale || "en-US"; + const { locale } = useParams(); + return locale && VALID_LOCALES.has(locale) ? locale : "en-US"; } diff --git a/client/src/page-not-found/fallback-link.tsx b/client/src/page-not-found/fallback-link.tsx index 8df0170c463e..8ae959325a27 100644 --- a/client/src/page-not-found/fallback-link.tsx +++ b/client/src/page-not-found/fallback-link.tsx @@ -42,7 +42,7 @@ export default function FallbackLink({ url }: { url: string }) { ); React.useEffect(() => { - if (url && locale.toLowerCase() !== "en-us") { + if (url && url.includes("/docs/") && locale.toLowerCase() !== "en-us") { // What if we attempt to see if it would be something there in English? // We'll use the `index.json` version of the URL let enUSURL = url.replace(`/${locale}/`, "/en-US/"); diff --git a/server/index.js b/server/index.js index 21d6b1147948..f6f0aeafc90a 100644 --- a/server/index.js +++ b/server/index.js @@ -162,7 +162,7 @@ app.get("/*/contributors.txt", async (req, res) => { }); app.get("/*", async (req, res) => { - if (req.url.startsWith("_")) { + if (req.url.startsWith("/_")) { // URLs starting with _ is exclusively for the meta-work and if there // isn't already a handler, it's something wrong. return res.status(404).send("Page not found"); @@ -182,11 +182,12 @@ app.get("/*", async (req, res) => { } if (!req.url.includes("/docs/")) { - // This should really only be expected for "single page apps". - // All *documents* should be handled by the - // `if (req.url.includes("/docs/"))` test above. - res.sendFile(path.join(STATIC_ROOT, "/index.html")); - return; + // If it's a known SPA, like `/en-US/search` then that should have been + // matched to its file and not end up here in the catchall handler. + // Simulate what we do in the Lambda@Edge. + return res + .status(404) + .sendFile(path.join(STATIC_ROOT, "en-us", "_spas", "404.html")); } // TODO: Would be nice to have a list of all supported file extensions From 8e45ae190ad8bb9d669c3680a441adc24525c2e2 Mon Sep 17 00:00:00 2001 From: Schalk Neethling Date: Mon, 22 Mar 2021 16:55:04 +0200 Subject: [PATCH 048/288] fix: heading underline on hover and focus (#3289) Add underline on hover and focus for linked headings Fix #3205 --- client/src/document/index.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/document/index.scss b/client/src/document/index.scss index 2fabb76d400a..8ebc651a793a 100644 --- a/client/src/document/index.scss +++ b/client/src/document/index.scss @@ -125,6 +125,11 @@ a:visited { text-decoration: none; } + + a:hover, + a:focus { + text-decoration: underline; + } } table { From f3b6f22a81370dc254ed6943440f372ce0e5737b Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Mon, 22 Mar 2021 13:54:44 -0700 Subject: [PATCH 049/288] start pruning prod builds (#3302) --- .github/workflows/prod-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod-build.yml b/.github/workflows/prod-build.yml index c69e4e379b7a..54ea3f46eef3 100644 --- a/.github/workflows/prod-build.yml +++ b/.github/workflows/prod-build.yml @@ -227,7 +227,7 @@ jobs: # XXX would be nice to validate here that $DEPLOYER_BUCKET_PREFIX is truthy echo "DEPLOYER_BUCKET_PREFIX=$DEPLOYER_BUCKET_PREFIX" - poetry run deployer upload ../client/build + poetry run deployer upload --prune --archived-files ../content/archived.txt ../client/build poetry run deployer update-lambda-functions ./aws-lambda # TODO: Depending on how long the upload takes, consider switching to From 61131c214c841a35a711e32e6fcee358bcf7fd83 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 22 Mar 2021 17:22:32 -0400 Subject: [PATCH 050/288] correct spacing for simpler diff (#3303) --- .github/workflows/stage-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stage-build.yml b/.github/workflows/stage-build.yml index c20244921e14..7c3e89fc70b2 100644 --- a/.github/workflows/stage-build.yml +++ b/.github/workflows/stage-build.yml @@ -240,7 +240,7 @@ jobs: # XXX would be nice to validate here that $DEPLOYER_BUCKET_PREFIX is truthy echo "DEPLOYER_BUCKET_PREFIX=$DEPLOYER_BUCKET_PREFIX" - poetry run deployer upload --prune --archived-files ../content/archived.txt ../client/build + poetry run deployer upload --prune --archived-files ../content/archived.txt ../client/build poetry run deployer update-lambda-functions ./aws-lambda # TODO: Depending on how long the upload takes, consider switching to From ab5b6df96ee525e1996ccb292d4d208d5528b2fd Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 22 Mar 2021 17:48:50 -0400 Subject: [PATCH 051/288] don't even attempt files URIs that start with // (#3305) * don't even attempt files URIs that start with // Fixes #3225 * Update deployer/aws-lambda/content-origin-request/index.js Co-authored-by: Ryan Johnson --- .../aws-lambda/content-origin-request/index.js | 13 ++++--------- .../content-origin-request/server.test.js | 14 +++++++++----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/deployer/aws-lambda/content-origin-request/index.js b/deployer/aws-lambda/content-origin-request/index.js index 5a352d8e842b..79ba52eb3ee4 100644 --- a/deployer/aws-lambda/content-origin-request/index.js +++ b/deployer/aws-lambda/content-origin-request/index.js @@ -80,7 +80,7 @@ exports.handler = async (event) => { // If the URL was something like `https://domain/en-US/search/`, our code // would make a that a redirect to `/en-US/search` (stripping the trailing slash). - // But if it was `https://domain//en-US/search/` it'd make a redirect + // But if it was `https://domain//en-US/search/` it *would* make a redirect // to `//en-US/search`. // However, if pathname starts with `//` the Location header might look // relative but it's actually an absolute URL. @@ -88,15 +88,10 @@ exports.handler = async (event) => { // opening `https://evil.com/` in the browser, because the browser will // treat `//evil.com/ == https://evil.com/`. // Prevent any pathnames that start with a double //. + // This essentially means that a request for `GET /////anything` becomes + // 302 with `Location: /anything`. if (request.uri.startsWith("//")) { - return { - status: 404, - statusDescription: "Not found", - headers: { - "content-type": [{ key: "Content-Type", value: "text/plain" }], - }, - body: "URL pathname can't start with //\n", - }; + return redirect(`/${request.uri.replace(/^\/+/g, "")}`); } const { url, status } = resolveFundamental(request.uri); diff --git a/deployer/aws-lambda/content-origin-request/server.test.js b/deployer/aws-lambda/content-origin-request/server.test.js index 15d2bb580803..a350cf57e481 100644 --- a/deployer/aws-lambda/content-origin-request/server.test.js +++ b/deployer/aws-lambda/content-origin-request/server.test.js @@ -188,11 +188,15 @@ describe("always check for fundamental redirects first", () => { }); }); -describe("avoid double-slash redirects", () => { - it("should 404 on any pathname that starts with //", async () => { +describe("redirect double-slash prefix URIs", () => { + it("should 302 redirect anything that starts with //", async () => { const r = await get(`//en-US/search/`); - expect(r.statusCode).toBe(404); - expect(r.headers["location"]).toBeFalsy(); - expect(r.body).toContain("URL pathname can't start with //"); + expect(r.statusCode).toBe(302); + expect(r.headers["location"]).toBe("/en-US/search/"); + }); + it("should 302 redirect anything that starts with // on anything", async () => { + const r = await get(`//blablabla`); + expect(r.statusCode).toBe(302); + expect(r.headers["location"]).toBe("/blablabla"); }); }); From 7befe0e53f4dfd42d8057d948d303f2814604767 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Mon, 22 Mar 2021 19:29:50 -0400 Subject: [PATCH 052/288] fix: Don't double brace some CSS refs (#3281) * fix: Don't double brace some CSS refs * Update kumascript/macros/cssxref.ejs * fix: Use endsWith for function check Co-authored-by: Ryan Johnson * fix cssxref.test.js Co-authored-by: Ryan Johnson Co-authored-by: rjohnson --- kumascript/macros/cssxref.ejs | 2 +- kumascript/tests/macros/cssxref.test.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kumascript/macros/cssxref.ejs b/kumascript/macros/cssxref.ejs index 19a30db78a34..c77d1b8aed67 100644 --- a/kumascript/macros/cssxref.ejs +++ b/kumascript/macros/cssxref.ejs @@ -60,7 +60,7 @@ const thisPage = (!$1 || !$2) ? wiki.getPage(urlWithoutAnchor) : null; if (!$1) { // Append parameter brackets to CSS functions - if (page.hasTag(thisPage, "CSS Function")) { + if (page.hasTag(thisPage, "CSS Function") && !str.endsWith("()")) { str += "()"; } // Enclose CSS data types in arrow brackets diff --git a/kumascript/tests/macros/cssxref.test.js b/kumascript/tests/macros/cssxref.test.js index 8dcadcb8e985..a4fdaa4d2d4d 100644 --- a/kumascript/tests/macros/cssxref.test.js +++ b/kumascript/tests/macros/cssxref.test.js @@ -37,9 +37,9 @@ const MOCK_PAGES = { }, }, attr: { - url: [CSS_BASE_URL, "attr"].join("/"), + url: [CSS_BASE_URL, "attr()"].join("/"), data: { - url: [CSS_BASE_URL, "attr"].join("/"), + url: [CSS_BASE_URL, "attr()"].join("/"), summary: 'The attr() CSS function is used to retrieve the value of an attribute of the selected element and use it in the style sheet.', tags: ["CSS", "Reference", "Web", "CSS Function", "Layout"], @@ -107,7 +107,7 @@ const TEST_CASE = [ }, { title: "One argument (CSS function)", - input: ["attr"], + input: ["attr()"], output: makeExpect( MOCK_PAGES.attr.url, MOCK_PAGES.attr.data.summary, From e1fec4e73afc44618da4938cba8507b0934a11ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Mar 2021 06:04:57 +0000 Subject: [PATCH 053/288] build(deps-dev): bump react-is from 17.0.1 to 17.0.2 (#3307) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1d08f7c2c3f5..74bf9de44652 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "puppeteer": "2", "react": "17.0.1", "react-dom": "17.0.1", - "react-is": "^17.0.1", + "react-is": "^17.0.2", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-scripts": "4.0.3", diff --git a/yarn.lock b/yarn.lock index faf5813253c8..bbb285648f73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14813,10 +14813,10 @@ react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" - integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== +react-is@^17.0.1, react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== react-lifecycles-compat@^3.0.4: version "3.0.4" From 2e12e84a138c5d4bf2516ee5ece5788f4aed6a80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Mar 2021 06:07:30 +0000 Subject: [PATCH 054/288] build(deps-dev): bump @types/react-dom from 17.0.2 to 17.0.3 (#3309) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 74bf9de44652..17d8ef320a40 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "@testing-library/react": "^11.2.5", "@types/jest": "^26.0.21", "@types/react": "^17.0.3", - "@types/react-dom": "^17.0.2", + "@types/react-dom": "^17.0.3", "braces": "^3.0.2", "cross-env": "^7.0.3", "diff": "^5.0.0", diff --git a/yarn.lock b/yarn.lock index bbb285648f73..a7ff0084d51c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3152,10 +3152,10 @@ "@types/react" "*" "@types/reactcss" "*" -"@types/react-dom@^17.0.2": - version "17.0.2" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.2.tgz#35654cf6c49ae162d5bc90843d5437dc38008d43" - integrity sha512-Icd9KEgdnFfJs39KyRyr0jQ7EKhq8U6CcHRMGAS45fp5qgUvxL3ujUCfWFttUK2UErqZNj97t9gsVPNAqcwoCg== +"@types/react-dom@^17.0.3": + version "17.0.3" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.3.tgz#7fdf37b8af9d6d40127137865bb3fff8871d7ee1" + integrity sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w== dependencies: "@types/react" "*" From 50272952b67cfcb9e2caf3d2fcc58df53d94df2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Mar 2021 07:05:35 +0000 Subject: [PATCH 055/288] build(deps): bump boto3 from 1.17.33 to 1.17.34 in /deployer (#3310) --- deployer/poetry.lock | 16 ++++++++-------- deployer/pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deployer/poetry.lock b/deployer/poetry.lock index 4f01ef85dbef..27e42f4c85b3 100644 --- a/deployer/poetry.lock +++ b/deployer/poetry.lock @@ -52,20 +52,20 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "boto3" -version = "1.17.33" +version = "1.17.34" description = "The AWS SDK for Python" category = "main" optional = false python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] -botocore = ">=1.20.33,<1.21.0" +botocore = ">=1.20.34,<1.21.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" [[package]] name = "botocore" -version = "1.20.33" +version = "1.20.34" description = "Low-level, data-driven core of boto 3." category = "main" optional = false @@ -533,7 +533,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "6ec3c53b11db10e780442e1608e422d4b7559576e9c469b75675dca567817257" +content-hash = "cfd5df43411d7eb1b3f68bd6070e0b764a88692b014c95b83bc84db4b5f2ab0b" [metadata.files] appdirs = [ @@ -552,12 +552,12 @@ black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] boto3 = [ - {file = "boto3-1.17.33-py2.py3-none-any.whl", hash = "sha256:3306dad87f993703b102a0a70ca19c549b7f41e7f70fa7b4c579735c9f79351d"}, - {file = "boto3-1.17.33.tar.gz", hash = "sha256:0cac2fffc1ba915f7bb5ecee539318532db51f218c928a228fafe3e501e9472e"}, + {file = "boto3-1.17.34-py2.py3-none-any.whl", hash = "sha256:1ddd597e3d8b7553432f84b32b9519cc90aad91c4dc3873725375163c9f98353"}, + {file = "boto3-1.17.34.tar.gz", hash = "sha256:8f33cb3d2fc42b0547a5560a6d7397aa93336f50899386762b2450682c0e992b"}, ] botocore = [ - {file = "botocore-1.20.33-py2.py3-none-any.whl", hash = "sha256:a33e862685259fe22d9790d9c9f3567feda8b824d44d3c62a3617af1133543a4"}, - {file = "botocore-1.20.33.tar.gz", hash = "sha256:e355305309699d3aca1e0050fc21d48595b40db046cb0d2491cd57ff5b26920b"}, + {file = "botocore-1.20.34-py2.py3-none-any.whl", hash = "sha256:c4fe4fea1d6a3934dd8c670ee83b128f935a64078786fe8afb8a662446304926"}, + {file = "botocore-1.20.34.tar.gz", hash = "sha256:749bdb151e340329f1b25600bfe9d223e930f8ba26bd74b71478ca5781f2feaf"}, ] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, diff --git a/deployer/pyproject.toml b/deployer/pyproject.toml index c5ebc653442e..76688a661a20 100644 --- a/deployer/pyproject.toml +++ b/deployer/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.7" click = "^7.1.2" -boto3 = "^1.17.33" +boto3 = "^1.17.34" python-decouple = "^3.4" requests = {extras = ["security"], version = "^2.25.0"} elasticsearch-dsl = "^7.3.0" From 101625610444b5eb117178925390cc4029509cc1 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 23 Mar 2021 06:51:42 -0400 Subject: [PATCH 056/288] Deal with "No BCD data" more gracefully? (#3248) * Deal with "No BCD data" more gracefully? Fixes #3168 * feedbacked --- build/bcd-urls.js | 11 ++++++++ build/document-extractor.js | 14 +++++++++- client/src/document/lazy-bcd-table.tsx | 38 ++++++++++++-------------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/build/bcd-urls.js b/build/bcd-urls.js index 4a688f95cfa2..f8180a5c2f9d 100644 --- a/build/bcd-urls.js +++ b/build/bcd-urls.js @@ -56,6 +56,11 @@ function normalizeBCDURLs(doc, options) { for (const section of doc.body) { if (section.type !== "browser_compatibility") continue; + + // This happens if a query is "broken". + // E.g.
      + if (!section.value.data) continue; + for (const [key, data] of Object.entries(section.value.data)) { // First block from the BCD data does not have its name as the root key // so mdn_url is accessible at the root. If the block has a key for @@ -119,6 +124,12 @@ function extractBCDData(doc) { for (const section of doc.body) { if (section.type === "browser_compatibility") { // Most pages only have exactly 1 so no need to put the prefix on them. + + if (!section.value.data) { + // This happens if a query is "broken". + // E.g.
      + continue; + } const fileName = ++nextId > 1 ? `bcd-${nextId}.json` : "bcd.json"; const dataURL = `${doc.mdn_url}/${fileName}`; data.push({ diff --git a/build/document-extractor.js b/build/document-extractor.js index 4a8df450f5b5..ec94e6b07bc6 100644 --- a/build/document-extractor.js +++ b/build/document-extractor.js @@ -264,7 +264,19 @@ function _addSingleSectionBCD($) { const query = dataQuery.replace(/^bcd:/, ""); const { browsers, data } = packageBCD(query); if (data === undefined) { - return []; + return [ + { + type: "browser_compatibility", + value: { + title, + id, + isH3, + data: null, + query, + browsers: null, + }, + }, + ]; } // First extract a map of all release data, keyed by (normalized) browser diff --git a/client/src/document/lazy-bcd-table.tsx b/client/src/document/lazy-bcd-table.tsx index 43bbec8d726e..263a9fb1cc8f 100644 --- a/client/src/document/lazy-bcd-table.tsx +++ b/client/src/document/lazy-bcd-table.tsx @@ -30,24 +30,32 @@ export function LazyBrowserCompatibilityTable({ title: string; isH3: boolean; query: string; - dataURL: string; + dataURL: string | null; }) { return ( <> {title && !isH3 && } {title && isH3 && } - + {dataURL ? ( + + ) : ( +
      +

      + No compatibility data found for {query}.
      + Check for problems with this page or + contribute missing data to{" "} + + mdn/browser-compat-data + + . +

      +
      + )} ); } -function LazyBrowserCompatibilityTableInner({ - dataURL, - query, -}: { - dataURL: string; - query: string; -}) { +function LazyBrowserCompatibilityTableInner({ dataURL }: { dataURL: string }) { const locale = useLocale(); const [bcdDataURL, setBCDDataURL] = useState(""); @@ -76,18 +84,6 @@ function LazyBrowserCompatibilityTableInner({ if (error) { return

      Error loading BCD data

      ; } - if (!data.data) { - return ( -

      - No compatibility data found for {query}. Check the spelling - or contribute data to{" "} - - mdn/browser-compat-data - - . -

      - ); - } return ( }> From 2e4323b6276452ea70c220911b0e7aecfd75c5e7 Mon Sep 17 00:00:00 2001 From: Schalk Neethling Date: Tue, 23 Mar 2021 14:57:45 +0200 Subject: [PATCH 057/288] fix: sign-in and sing-up page ui (#3264) Co-authored-by: Peter Bengtsson --- client/src/auth/index.scss | 30 +++ client/src/auth/index.tsx | 21 +-- client/src/auth/sign-in.scss | 17 ++ client/src/auth/sign-in.tsx | 71 ++++--- client/src/auth/sign-up.scss | 55 +++++- client/src/auth/sign-up.tsx | 207 ++++++++++----------- client/src/ui/atoms/avatar/avatar.scss | 18 ++ client/src/ui/atoms/page-content/index.tsx | 6 +- testing/tests/headless.test.js | 30 ++- testing/tests/index.test.js | 4 +- 10 files changed, 292 insertions(+), 167 deletions(-) create mode 100644 client/src/auth/index.scss create mode 100644 client/src/auth/sign-in.scss create mode 100644 client/src/ui/atoms/avatar/avatar.scss diff --git a/client/src/auth/index.scss b/client/src/auth/index.scss new file mode 100644 index 000000000000..66f35dfc2d17 --- /dev/null +++ b/client/src/auth/index.scss @@ -0,0 +1,30 @@ +@import "~@mdn/minimalist/sass/vars/layout"; + +.page-content-container.auth-page-container { + align-items: center; + display: flex; + flex-flow: column; + justify-content: center; + + @media #{$mq-tablet-and-up} { + margin: ($base-spacing * 2); + } + + @media #{$mq-large-desktop-and-up} { + margin: ($base-spacing * 3) auto; + } + + h1 { + margin: $base-spacing 0; + } + + .lead { + max-width: 35rem; + max-width: 60ch; + text-align: center; + } + + .notecard { + width: 35%; + } +} diff --git a/client/src/auth/index.tsx b/client/src/auth/index.tsx index 99e08f30bce7..9bd731b65f0e 100644 --- a/client/src/auth/index.tsx +++ b/client/src/auth/index.tsx @@ -6,37 +6,34 @@ const SignInApp = React.lazy(() => import("./sign-in")); const SignUpApp = React.lazy(() => import("./sign-up")); function Container({ - pageTitle, children, className, }: { - pageTitle: string; children: React.ReactNode; className: string; }) { const isServer = typeof window === "undefined"; + const pageTitle = "Sign in to MDN Web Docs"; React.useEffect(() => { document.title = pageTitle; - }, [pageTitle]); + }, []); return ( -
      - - {/* The reason for displaying this

      here (and for SignUp too) + + {/* The reason for displaying this

      here (and for SignUp too) is to avoid an unnecessary "flicker". component here is loaded SSR and is immediately present. Only the "guts" below is lazy loaded. By having the header already present the page feels less flickery at a very affordable cost of allowing this to be part of the main JS bundle. */} -

      {pageTitle}

      - {!isServer && children} -
      -

      +

      {pageTitle}

      + {!isServer && children} + ); } export function SignIn() { return ( - + Loading...

      }>
      @@ -45,7 +42,7 @@ export function SignIn() { } export function SignUp() { return ( - + Loading...

      }>
      diff --git a/client/src/auth/sign-in.scss b/client/src/auth/sign-in.scss new file mode 100644 index 000000000000..5551f7706980 --- /dev/null +++ b/client/src/auth/sign-in.scss @@ -0,0 +1,17 @@ +@import "~@mdn/minimalist/sass/vars/layout"; + +.sign-in { + .auth-buttons { + margin: 0 auto; + max-width: 250px; + width: 100%; + + li { + margin-bottom: $base-spacing; + } + } + + .sign-out-form { + text-align: center; + } +} diff --git a/client/src/auth/sign-in.tsx b/client/src/auth/sign-in.tsx index 148789756472..803145c1c240 100644 --- a/client/src/auth/sign-in.tsx +++ b/client/src/auth/sign-in.tsx @@ -3,6 +3,12 @@ import { useSearchParams } from "react-router-dom"; import { useUserData } from "../user-context"; import { useLocale } from "../hooks"; +import { ReactComponent as GithubLogo } from "@mdn/dinocons/brands/github-mark-small.svg"; +import { ReactComponent as GoogleLogo } from "@mdn/dinocons/brands/google-mono.svg"; + +import "./index.scss"; +import "./sign-in.scss"; + export default function SignInApp() { const [searchParams] = useSearchParams(); const locale = useLocale(); @@ -41,7 +47,7 @@ export default function SignInApp() { sp.set("yarisignup", "1"); return ( -
      + <> {/* We need to wait for the userData (/api/v1/whoami) because it will determine what we display. We *could* render on the optimism that people most likely will be @@ -50,42 +56,53 @@ export default function SignInApp() { completely different without it being due to a user action. */} {userData ? ( - <> - {userData.isAuthenticated ? ( - -

      - You're already signed in. -

      - - {/* XXX Here it would be great to link to the account settings page */} - - - -

      - Or, return to the home page. -

      - - ) : ( -
      + ); } diff --git a/client/src/auth/sign-up.scss b/client/src/auth/sign-up.scss index 3c6a4daffa88..5d2dac3e60fb 100644 --- a/client/src/auth/sign-up.scss +++ b/client/src/auth/sign-up.scss @@ -1,11 +1,52 @@ +@import "../ui/atoms/avatar/avatar"; + .sign-up { - form { - button[disabled] { - opacity: 0.5; + text-align: center; + + .provider-name { + font-weight: bold; + } + + a:link, + a:visited { + text-decoration: underline; + } + + a:hover, + a:focus { + text-decoration: none; + } + + .complete-sign-in { + align-items: center; + display: flex; + flex-flow: column; + margin-bottom: $base-spacing; + max-width: 250px; + + .button { + margin-top: $base-spacing / 2; + } + } + + .back { + &::before { + background: transparent url("~@mdn/dinocons/arrows/arrow.svg") 0 0/14px + no-repeat; + content: ""; + display: inline-block; + height: 14px; + margin-right: $base-spacing / 4; + transform: rotate(-90deg); + vertical-align: middle; + width: 14px; + } + + &:hover, + &:focus { + &::before { + margin-right: $base-spacing / 3; + } } } - // .user-details img.picture { - // width: 100px; - // border-radius: 50px; - // } } diff --git a/client/src/auth/sign-up.tsx b/client/src/auth/sign-up.tsx index 043458eca1a5..6980add7181e 100644 --- a/client/src/auth/sign-up.tsx +++ b/client/src/auth/sign-up.tsx @@ -5,8 +5,14 @@ import { mutate } from "swr"; import { useLocale } from "../hooks"; import { useUserData } from "../user-context"; +import "./index.scss"; import "./sign-up.scss"; +interface UserDetails { + name?: string; + avatar_url?: string; +} + export default function SignUpApp() { const userData = useUserData(); const navigate = useNavigate(); @@ -25,25 +31,10 @@ export default function SignUpApp() {

      You're already signed up

      {/* XXX Include a link to the settings page */} - Return to the home page. -
      - ); - } - - if (searchParams.get("errors")) { - console.warn("Errors", searchParams.get("errors")); - const errors = JSON.parse(searchParams.get("errors") || "{}"); - return ( -
      -

      Sign-up errors

      -

      An error occurred trying to sign you up.

      -
      {JSON.stringify(errors, null, 2)}
      -

      - - Try starting over the sign-in process - - . -

      + + Return to the home page + + .
      ); } @@ -52,13 +43,11 @@ export default function SignUpApp() { const provider = searchParams.get("provider"); if (!csrfMiddlewareToken || !provider) { return ( -
      -

      Invalid Sign up URL

      -

      You arrived here on this page without the necessary details.

      +
      +

      Invalid URL

      +

      You arrived here without the necessary details.

      - - Try starting over the sign-in process - + Please retry the sign-in process .

      @@ -117,106 +106,106 @@ export default function SignUpApp() { } } + let userDetails: UserDetails = {}; + try { + userDetails = JSON.parse(searchParams.get("user_details") || "{}"); + } catch (jsonParseError) { + console.warn("The 'user_details' was not valid JSON"); + } + return ( -
      { - event.preventDefault(); - if (checkedTerms) { - submitSignUp(); - } - }} - > + <> + {userDetails.avatar_url && ( + User profile avatar_url + )} + + {provider && ( + + )} + {signupError && ( -
      -

      Signup Error

      +

      - {signupError.toString()} + Signup error {signupError.toString()}

      )} - - - - + { + event.preventDefault(); + if (checkedTerms) { + submitSignUp(); + } + }} + > + - - + + + ); } -function DisplaySignupProvider({ provider }: { provider: string }) { - if (!provider) { - // Exit early because there's nothing useful we can say - return null; - } +function DisplaySignupDetails({ + provider, + username, +}: { + provider: string; + username: string; +}) { let providerVerbose = provider.charAt(0).toUpperCase() + provider.slice(1); if (provider === "github") { providerVerbose = "GitHub"; } return ( -

      - You are signing in to MDN Web Docs with {providerVerbose}. +

      + You are signing in to MDN Web Docs with{" "} + {providerVerbose} + {username && ` as ${username}`}.

      ); } - -interface UserDetails { - name?: string; - avatar_url?: string; -} - -function DisplayUserDetails({ details }: { details: string }) { - if (!details) { - // Exit early because there's nothing useful we can say - return null; - } - - const userDetails: UserDetails = JSON.parse(details); - - return ( -
      -

      - {userDetails.avatar_url && ( - User profile avatar_url - )} - - {userDetails.name && ` as ${userDetails.name}`} -

      -
      - ); -} diff --git a/client/src/ui/atoms/avatar/avatar.scss b/client/src/ui/atoms/avatar/avatar.scss new file mode 100644 index 000000000000..ab9a1c1e2160 --- /dev/null +++ b/client/src/ui/atoms/avatar/avatar.scss @@ -0,0 +1,18 @@ +@import "~@mdn/minimalist/sass/vars/layout"; + +.avatar { + margin: 0 auto; +} + +.auth-page-container { + .avatar { + height: 60px; + margin-bottom: $base-spacing; + width: 60px; + + @media #{$mq-tablet-and-up} { + height: 80px; + width: 80px; + } + } +} diff --git a/client/src/ui/atoms/page-content/index.tsx b/client/src/ui/atoms/page-content/index.tsx index 2a2e9a88d09b..ec5e4b83c0ab 100644 --- a/client/src/ui/atoms/page-content/index.tsx +++ b/client/src/ui/atoms/page-content/index.tsx @@ -24,11 +24,15 @@ export function MainContentContainer({ // What we use on almost all pages export function PageContentContainer({ children, + extraClasses, }: { children: React.ReactNode; + extraClasses?: string; }) { return ( - + {children} ); diff --git a/testing/tests/headless.test.js b/testing/tests/headless.test.js index 85ff6886260e..cad7a472468c 100644 --- a/testing/tests/headless.test.js +++ b/testing/tests/headless.test.js @@ -268,26 +268,38 @@ describe("Basic viewing of functional pages", () => { it("going to 'Sign up' page without query string", async () => { await page.goto(testURL("/en-US/signup")); - await expect(page).toMatchElement("h1", { text: "Sign up" }); - await expect(page).toMatch("Invalid Sign up URL"); + await expect(page).toMatchElement("h1", { + text: "Sign in to MDN Web Docs", + }); + await expect(page).toMatch("Invalid URL"); await expect(page).toMatchElement("a", { - text: "Try starting over the sign-in process", + text: "Please retry the sign-in process", }); }); it("going to 'Sign up' page with realistic (fake) query string", async () => { - await page.goto( - testURL("/en-US/signup?csrfmiddlewaretoken=abc&provider=github") + const sp = new URLSearchParams(); + sp.set("csrfmiddlewaretoken", "abc"); + sp.set("provider", "github"); + sp.set( + "user_details", + JSON.stringify({ + name: "Peter B", + }) ); - await expect(page).toMatchElement("h1", { text: "Sign up" }); - await expect(page).not.toMatch("Invalid Sign up URL"); + + await page.goto(testURL(`/en-US/signup?${sp.toString()}`)); + await expect(page).toMatchElement("h1", { + text: "Sign in to MDN Web Docs", + }); + await expect(page).not.toMatch("Invalid URL"); await expect(page).toMatch( - "You are signing in to MDN Web Docs with GitHub." + "You are signing in to MDN Web Docs with GitHub as Peter B." ); await expect(page).toMatch( "I agree to Mozilla's Terms and Privacy Notice." ); - await expect(page).toMatchElement("button", { text: "Create account" }); + await expect(page).toMatchElement("button", { text: "Complete sign-in" }); }); it("should say you're not signed in on the settings page", async () => { diff --git a/testing/tests/index.test.js b/testing/tests/index.test.js index 877b75cc1a7c..03e41dffdb41 100644 --- a/testing/tests/index.test.js +++ b/testing/tests/index.test.js @@ -957,7 +957,7 @@ test("sign in page", () => { const htmlFile = path.join(builtFolder, "index.html"); const html = fs.readFileSync(htmlFile, "utf-8"); const $ = cheerio.load(html); - expect($("h1").text()).toContain("Sign in"); + expect($("h1").text()).toContain("Sign in to MDN Web Docs"); expect($("title").text()).toContain("Sign in"); }); @@ -967,7 +967,7 @@ test("sign up page", () => { const htmlFile = path.join(builtFolder, "index.html"); const html = fs.readFileSync(htmlFile, "utf-8"); const $ = cheerio.load(html); - expect($("h1").text()).toContain("Sign up"); + expect($("h1").text()).toContain("Sign in to MDN Web Docs"); expect($("title").text()).toContain("Sign up"); }); From 95bd5213b7a7eab4b0b8c78ba1631f5d0976ce0a Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 23 Mar 2021 09:50:17 -0400 Subject: [PATCH 058/288] .page-not-create can appear outside article and .main-content (#3273) Fixes #3031 --- client/src/document/index.scss | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/document/index.scss b/client/src/document/index.scss index 8ebc651a793a..ef6188a51d42 100644 --- a/client/src/document/index.scss +++ b/client/src/document/index.scss @@ -36,6 +36,14 @@ } } +/* page-not-created is the preferred class name, `new` is + here for backwards compatibility */ +a.page-not-created, +a.new { + color: $red-300; + cursor: not-allowed; +} + .main-page-content { padding: ($base-spacing / 2) $base-spacing $base-spacing; @@ -136,14 +144,6 @@ margin-bottom: $base-spacing * 2; } - /* page-not-created is the preferred class name, `new` is - here for backwards compatibility */ - .page-not-created, - .new { - color: $red-300; - cursor: not-allowed; - } - /* readonly inline badges needs a slightly darker background color in general article content */ .inline { &.optional, From ff7dfb0772cf2af5d6a34d2fb3545f7a4c8ecd09 Mon Sep 17 00:00:00 2001 From: Schalk Neethling Date: Tue, 23 Mar 2021 16:33:26 +0200 Subject: [PATCH 059/288] Style account settings app (#3298) * fix: sign-in and sing-up page ui Add styling for the sign-in and sign-up pages Fix #2449 * remove extra period * fix failing tests * remove populate-search-index-benchmark * feedback on sign-up styling PR * changes based on review feedback * fix: account settings ui Styling for the account settings page Fix #2505 * small ui and test updates * small text update * update color for top border * fix tests in pull/3298 Co-authored-by: Peter Bengtsson --- client/src/settings/app.tsx | 120 ++++++++++++++++----------------- client/src/settings/index.scss | 91 +++++++++++++++++++++++++ client/src/settings/index.tsx | 4 +- testing/tests/headless.test.js | 12 ++-- 4 files changed, 160 insertions(+), 67 deletions(-) create mode 100644 client/src/settings/index.scss diff --git a/client/src/settings/app.tsx b/client/src/settings/app.tsx index ed7039daf831..6ed10898f517 100644 --- a/client/src/settings/app.tsx +++ b/client/src/settings/app.tsx @@ -6,6 +6,8 @@ import { DISABLE_AUTH } from "../constants"; import { useUserData } from "../user-context"; import { useLocale } from "../hooks"; +import "./index.scss"; + interface UserSettings { csrfmiddlewaretoken: string; locale: string; @@ -75,7 +77,7 @@ export default function SettingsApp({ ...appProps }) { if (error) { return ( -
      +

      Server error

      A server error occurred trying to get your user settings.

      @@ -92,7 +94,7 @@ export default function SettingsApp({ ...appProps }) { if (settingsError) { return ( -

      +

      Server error

      Unable to get the current user settings from the server.

      @@ -104,7 +106,7 @@ export default function SettingsApp({ ...appProps }) { } return ( -

      +
      {settingsData && settingsData.possibleLocales && settingsData.possibleLocales.length && ( @@ -143,10 +145,12 @@ function NotSignedIn() { sp.set("next", window.location.pathname); return ( -
      -

      You are not signed in

      - Sign in first -
      + <> +

      You have not signed in

      + + Please sign in to continue + + ); } @@ -215,6 +219,7 @@ function Settings({ return (
      { event.preventDefault(); await sendSettings(); @@ -224,34 +229,27 @@ function Settings({ )} - {sent && !sendError && ( -
      -

      Settings update sent

      -

      Yay! Settings saved.

      - -
      - )} - {sendError && ( -
      -

      Server submission error

      -

      Something unexpected happened on the server submission.

      -

      - {sendError.toString()} -

      - Reload this page and try again. -
      - )} +
      + + + {sent && !sendError && ( +
      +

      Yay! Updated settings successfully saved.

      +
      + )} + {sendError && ( +
      +

      Server submission error

      +

      Something unexpected happened during server submission.

      +

      + {sendError.toString()} +

      + Reload page to try again. +
      + )} -
      -