From 074d1b2f1f3e72a2ce825a6f68a43daaf1229e99 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Fri, 6 Sep 2024 18:47:59 +0200 Subject: [PATCH 01/12] Linting update --- applications/samples/frontend/.eslintrc.cjs | 25 +- applications/samples/frontend/yarn.lock | 616 +++++++++++++++++++- 2 files changed, 613 insertions(+), 28 deletions(-) diff --git a/applications/samples/frontend/.eslintrc.cjs b/applications/samples/frontend/.eslintrc.cjs index c73cf24e4..976123ecd 100644 --- a/applications/samples/frontend/.eslintrc.cjs +++ b/applications/samples/frontend/.eslintrc.cjs @@ -6,7 +6,11 @@ module.exports = { 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', ], - ignorePatterns: ['dist', '.eslintrc.cjs', 'src/rest/*'], + ignorePatterns: [ + 'dist', + '.eslintrc.cjs', + 'src/rest/*' // do not lint generated code + ], parser: '@typescript-eslint/parser', plugins: ['react-refresh'], rules: { @@ -14,6 +18,23 @@ module.exports = { 'warn', { allowConstantExport: true }, ], - '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-explicit-any': "off", // No strict typing (annoying especially with React elements and events callbacks) + "indent": ["error", 2, { "SwitchCase": 1 }], + "curly": "error", // enforce braces for one-line blocks + "no-tabs": "error", // enforce no tabs + + "no-console": ["warn", { allow: ["warn", "error", "debug"] }], + "consistent-return": "warn", // https://eslint.org/docs/latest/rules/consistent-return + "prefer-arrow-callback": ["warn"], + "object-curly-spacing": ["warn", "always"], // enforce consistent spacing inside braces + + "func-style": "off", // function expressions or arrow functions are equally valid + + "no-unneeded-ternary": "warn", // disallow unnecessary ternary expressions + // React rules: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules + "react/prop-types": "off", // PropTypes are not forced + "react/forbid-prop-types": "off", // all PropTypes are allowed + "react-hooks/rules-of-hooks": "error", // https://react.dev/reference/rules/rules-of-hooks + "react-hooks/exhaustive-deps": "warn", // Hooks dependency array, sometimes it's better to ignore } } diff --git a/applications/samples/frontend/yarn.lock b/applications/samples/frontend/yarn.lock index 3b6f86c4c..c7ae36fea 100644 --- a/applications/samples/frontend/yarn.lock +++ b/applications/samples/frontend/yarn.lock @@ -683,7 +683,7 @@ acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== -ajv@^6.12.4: +ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -693,11 +693,26 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + integrity sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" @@ -712,6 +727,11 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -722,25 +742,65 @@ array-union@^2.1.0: resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" - integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== - dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.0" - proxy-from-env "^1.1.0" +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.13.2" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" + integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +biome@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/biome/-/biome-0.3.3.tgz#71c29633f84a486186bec97675da6f33a925575c" + integrity sha512-4LXjrQYbn9iTXu9Y4SKT7ABzTV0WnLDHCVSd2fPUOKsy1gQ+E4xPFmlY1zcWexoi0j7fGHItlL6OWA2CZ/yYAQ== + dependencies: + bluebird "^3.4.1" + chalk "^1.1.3" + commander "^2.9.0" + editor "^1.0.0" + fs-promise "^0.5.0" + inquirer-promise "0.0.3" + request-promise "^3.0.0" + untildify "^3.0.2" + user-home "^2.0.0" + +bluebird@^3.3, bluebird@^3.4.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -783,6 +843,22 @@ caniuse-lite@^1.0.30001640: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz" integrity sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg== +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +chalk@^1.0.0, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -800,6 +876,23 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + integrity sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A== + dependencies: + restore-cursor "^1.0.1" + +cli-width@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-1.1.1.tgz#a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d" + integrity sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg== + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" @@ -824,13 +917,18 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.8: +combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" +commander@^2.9.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" @@ -841,6 +939,16 @@ convert-source-map@^2.0.0: resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +core-js@^2.4.0: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -855,6 +963,13 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.5" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" @@ -886,6 +1001,29 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +earlgrey-runtime@>=0.0.10, earlgrey-runtime@>=0.0.11: + version "0.1.2" + resolved "https://registry.yarnpkg.com/earlgrey-runtime/-/earlgrey-runtime-0.1.2.tgz#5e7ea308924f107842877d59bb40bc2a9d9a29f8" + integrity sha512-T4qoScXi5TwALDv8nlGTvOuCT8jXcKcxtO8qVdqv46IA2GHJfQzwoBPbkOmORnyhu3A98cVVuhWLsM2CzPljJg== + dependencies: + core-js "^2.4.0" + kaiser ">=0.0.4" + lodash "^4.17.2" + regenerator-runtime "^0.9.5" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +editor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + integrity sha512-SoRmbGStwNYHgKfjOrX2L0mUvp9bUVv0uPppZSOMAntEbcFtoC3MKF5b3T6HQPXKIV+QGY3xPO3JK5it5lVkuw== + electron-to-chromium@^1.4.820: version "1.5.2" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.2.tgz" @@ -925,7 +1063,7 @@ escalade@^3.1.2: resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== -escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -1035,6 +1173,26 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + integrity sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg== + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" @@ -1068,6 +1226,14 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + integrity sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ== + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1104,20 +1270,41 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== -follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" - combined-stream "^1.0.8" + combined-stream "^1.0.6" mime-types "^2.1.12" +fs-extra@^0.26.5: + version "0.26.7" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + integrity sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-promise@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-0.5.0.tgz#4347d6bf624655a7061a4319213c393276ad3ef3" + integrity sha512-Y+4F4ujhEcayCJt6JmzcOun9MYGQwz+bVUiuBmTkJImhBHKpBvmVPZR9wtfiF7k3ffwAOAuurygQe+cPLSFQhw== + dependencies: + any-promise "^1.0.0" + fs-extra "^0.26.5" + mz "^2.3.1" + thenify-all "^1.6.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" @@ -1133,6 +1320,13 @@ gensync@^1.0.0-beta.2: resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -1183,11 +1377,36 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== + dependencies: + ansi-regex "^2.0.0" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" @@ -1198,6 +1417,15 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + ignore@^5.2.0, ignore@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" @@ -1229,11 +1457,45 @@ inherits@2: resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inquirer-promise@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/inquirer-promise/-/inquirer-promise-0.0.3.tgz#2fa71387ef51ea3f0e22f668501d415abb8e42e2" + integrity sha512-82CQX586JAV9GAgU9yXZsMDs+NorjA0nLhkfFx9+PReyOnuoHRbHrC1Z90sS95bFJI1Tm1gzMObuE0HabzkJpg== + dependencies: + earlgrey-runtime ">=0.0.11" + inquirer "^0.11.3" + +inquirer@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.11.4.tgz#81e3374e8361beaff2d97016206d359d0b32fa4d" + integrity sha512-QR+2TW90jnKk9LUUtbcA3yQXKt2rDEKMh6+BAZQIeumtzHexnwVLdPakSslGijXYLJCzFv7GMXbFCn0pA00EUw== + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^1.0.1" + figures "^1.3.5" + lodash "^3.3.1" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== + dependencies: + number-is-nan "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -1251,11 +1513,21 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -1268,6 +1540,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" @@ -1283,16 +1560,50 @@ json-schema-traverse@^0.4.1: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + json5@^2.2.3: version "2.2.3" resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== + optionalDependencies: + graceful-fs "^4.1.6" + +jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +kaiser@>=0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/kaiser/-/kaiser-0.0.4.tgz#d25ddf800640857fadde08dba59ffc7a5a4f5c38" + integrity sha512-m8ju+rmBqvclZmyrOXgGGhOYSjKJK6RN1NhqEltemY87UqZOxEkizg9TOy1vQSyJ01Wx6SAPuuN0iO2Mgislvw== + dependencies: + earlgrey-runtime ">=0.0.10" + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -1300,6 +1611,13 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== + optionalDependencies: + graceful-fs "^4.1.9" + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1320,6 +1638,16 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash@^3.3.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + integrity sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ== + +lodash@^4.17.2, lodash@^4.6.1: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + loose-envify@^1.1.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -1352,7 +1680,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12: +mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -1378,6 +1706,20 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + integrity sha512-EbrziT4s8cWPmzr47eYVW3wimS4HsvlnV5ri1xw1aR6JQo/OrJX5rkl32K/QQHdxeabJETtfeaROGhd8W7uBgg== + +mz@^2.3.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nanoid@^3.3.7: version "3.3.7" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" @@ -1393,6 +1735,21 @@ node-releases@^2.0.14: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + once@^1.3.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" @@ -1400,6 +1757,11 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + integrity sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A== + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -1412,6 +1774,11 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" @@ -1453,6 +1820,11 @@ path-type@^4.0.0: resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + picocolors@^1.0.0, picocolors@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" @@ -1477,16 +1849,21 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +psl@^1.1.28: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +qs@~6.5.2: + version "6.5.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" @@ -1512,16 +1889,80 @@ react@^18.3.1: dependencies: loose-envify "^1.1.0" +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + integrity sha512-8/td4MmwUB6PkZUbV25uKz7dfrmjYWxsW8DVfibWdlHRk/l/DfHKn4pU+dfcoGLFgWOdyGCzINRQD7jn+Bv+/g== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +regenerator-runtime@^0.9.5: + version "0.9.6" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + integrity sha512-D0Y/JJ4VhusyMOd/o25a3jdUqN/bC85EFsaoL9Oqmy/O4efCh+xhp7yj2EEOsj974qvMkcW8AwUzJ1jB/MbxCw== + +request-promise@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-3.0.0.tgz#be1edb26f41c49cd1d5656c6753d6842a1249f46" + integrity sha512-wVGUX+BoKxYsavTA72i6qHcyLbjzM4LR4y/AmDCqlbuMAursZdDWO7PmgbGAUvD2SeEJ5iB99VSq/U51i/DNbw== + dependencies: + bluebird "^3.3" + lodash "^4.6.1" + request "^2.34" + +request@^2.34: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + integrity sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw== + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@^2.2.8: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" @@ -1554,6 +1995,13 @@ rollup@^4.13.0: "@rollup/rollup-win32-x64-msvc" "4.19.0" fsevents "~2.3.2" +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + integrity sha512-qOX+w+IxFgpUpJfkv2oGN0+ExPs68F4sZHfaRRx4dDexAQkG83atugKVEylyT5ARees3HBbfmuvnjbrd8j9Wjw== + dependencies: + once "^1.3.0" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -1561,6 +2009,21 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + integrity sha512-1I1+G2gteLB8Tkt8YI1sJvSIfa0lWuRtC8GjvtyPBcLSF5jBCCJJqKrpER5JU5r6Bhe+i9/pK3VMuUcXu0kdwQ== + +safe-buffer@^5.0.1, safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + scheduler@^0.23.2: version "0.23.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" @@ -1600,6 +2063,37 @@ source-map-js@^1.2.0: resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== +sshpk@^1.7.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -1612,6 +2106,11 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" @@ -1631,6 +2130,25 @@ text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thenify-all@^1.0.0, thenify-all@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" @@ -1643,11 +2161,31 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -1670,6 +2208,11 @@ undici-types@~6.11.1: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.11.1.tgz#432ea6e8efd54a48569705a699e62d8f4981b197" integrity sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ== +untildify@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9" + integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA== + update-browserslist-db@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz" @@ -1685,6 +2228,27 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + integrity sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ== + dependencies: + os-homedir "^1.0.0" + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + vite@^5.3.4: version "5.3.5" resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.5.tgz#b847f846fb2b6cb6f6f4ed50a830186138cb83d8" From 33180a7a2d3da56da43245b0ae50dd5a8446a67e Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Mon, 9 Sep 2024 16:57:42 +0200 Subject: [PATCH 02/12] CH-147 fix linting WIP --- .../base/test/api/test_st.py | 3 +- .../django-app/api/test_st.py | 5 +- .../django-app/backend/__APP_NAME__/asgi.py | 4 +- .../backend/__APP_NAME__/settings.py | 6 +- .../django-app/backend/__APP_NAME__/urls.py | 2 +- .../django-app/backend/__APP_NAME__/wsgi.py | 4 +- .../backend/api/controllers/__init__.py | 2 +- .../backend/__APP_NAME__/__main__.py | 1 - .../flask-server/backend/setup.py | 1 - .../webapp/backend/__APP_NAME__/__main__.py | 1 - applications/common/server/common/__main__.py | 2 +- applications/common/server/common/config.py | 1 - .../common/controllers/accounts_controller.py | 1 + .../common/controllers/config_controller.py | 1 + .../controllers/security_controller_.py | 2 - .../common/controllers/sentry_controller.py | 1 + applications/common/server/common/models.py | 2 +- .../common/server/common/repository/sentry.py | 34 +++++---- .../common/test/test_sentry_controller.py | 2 +- applications/common/server/common/util.py | 8 +- applications/common/server/setup.py | 1 - .../deploy/resources/hub/jupyterhub_config.py | 26 +++---- .../jupyterhub/deploy/resources/hub/z2jh.py | 4 +- .../chauthenticator/chauthenticator/auth.py | 34 +++++---- .../harness_jupyter/jupyterhub.py | 27 ++++--- .../release-tools/boilerplate/boilerplate.py | 13 +++- .../server/notifications/__main__.py | 1 - .../notifications/adapters/base_adapter.py | 2 +- .../notifications/backends/console_backend.py | 2 +- .../notifications/backends/email_backend.py | 3 +- .../notifications/controllers/helpers.py | 4 +- .../controllers/notifications_controller.py | 7 +- applications/notifications/server/setup.py | 1 - .../samples/controllers/auth_controller.py | 2 +- .../controllers/security_controller_.py | 2 - .../samples/controllers/test_controller.py | 9 ++- .../samples/service/resource_service.py | 3 +- .../backend/samples/test/test_sample.py | 2 +- applications/samples/backend/samples/util.py | 10 +-- applications/samples/backend/setup.py | 1 - applications/samples/tasks/sum/main.py | 4 +- applications/samples/test/api/test_st.py | 9 ++- applications/volumemanager/server/setup.py | 1 - .../controllers/rest_controller.py | 5 +- .../controllers/security_controller_.py | 2 - .../test/test_rest_controller.py | 10 +-- .../server/volumemanager/util.py | 8 +- applications/workflows/server/setup.py | 1 - .../server/workflows_api/__main__.py | 2 - .../test/test_create_and_access_controller.py | 8 +- .../workflows/server/workflows_api/util.py | 8 +- .../workflows/tasks/notify-queue/main.py | 4 +- .../workflows/tasks/send-result-event/main.py | 13 ++-- .../cloudharness_django/admin.py | 2 + .../cloudharness_django/exceptions.py | 7 +- .../cloudharness_django/middleware.py | 5 +- .../cloudharness_django/models.py | 7 +- .../cloudharness_django/services/__init__.py | 5 +- .../cloudharness_django/services/auth.py | 2 +- .../cloudharness_django/services/events.py | 4 +- .../cloudharness_django/services/user.py | 12 +-- .../cloudharness_django/settings.py | 32 ++++---- libraries/client/cloudharness_cli/setup.py | 2 +- .../cloudharness/__init__.py | 13 +++- .../cloudharness/auth/exceptions.py | 5 +- .../cloudharness/auth/keycloak.py | 73 +++++++++---------- .../cloudharness/errors.py | 7 +- .../cloudharness/events/client.py | 16 ++-- .../cloudharness/infrastructure/k8s.py | 12 ++- .../cloudharness/middleware/__init__.py | 2 + .../cloudharness/models.py | 2 +- .../cloudharness/sentry/__init__.py | 7 +- .../cloudharness/service/pvc.py | 17 +++-- .../cloudharness/utils/__init__.py | 4 +- .../cloudharness/utils/config.py | 8 +- .../cloudharness/utils/env.py | 22 ++++-- .../cloudharness/utils/secrets.py | 2 +- .../cloudharness/utils/settings.py | 1 - .../cloudharness/workflows/argo.py | 12 +-- .../cloudharness/workflows/tasks.py | 4 +- .../cloudharness/workflows/utils.py | 4 + .../tests/test_applications.py | 15 ++-- .../cloudharness-common/tests/test_env.py | 8 +- .../tests/test_infrastructure.py | 2 +- .../tests/test_middleware.py | 3 + .../cloudharness-common/tests/test_quota.py | 15 ++-- .../tests/test_workflow.py | 60 ++++++++------- .../cloudharness_utils/constants.py | 2 +- .../cloudharness_utils/testing/api.py | 2 +- .../cloudharness_utils/testing/util.py | 5 +- lint.sh | 13 ++++ .../cloudharness_test/api.py | 3 +- .../cloudharness_test/e2e.py | 33 ++++----- .../cloudharness_test/utils.py | 3 +- tools/cloudharness-test/harness-test | 10 +-- tools/cloudharness-test/setup.py | 1 - .../ch_cli_tools/__init__.py | 2 +- .../ch_cli_tools/codefresh.py | 28 +++---- .../deployment-cli-tools/ch_cli_tools/helm.py | 14 ++-- .../ch_cli_tools/models.py | 2 +- .../ch_cli_tools/preprocessing.py | 39 +++++----- .../ch_cli_tools/skaffold.py | 25 +++---- .../ch_cli_tools/utils.py | 10 ++- .../deployment-cli-tools/harness-application | 5 +- tools/deployment-cli-tools/harness-deployment | 5 +- tools/deployment-cli-tools/setup.py | 1 - .../myapp/venv/matplotlib/__main__.py | 2 +- .../myapp2/venv/matplotlib/__main__.py | 2 +- .../tests/test_codefresh.py | 17 ++--- tools/deployment-cli-tools/tests/test_helm.py | 30 +++----- .../tests/test_preprocessing.py | 21 +++--- .../tests/test_skaffold.py | 8 +- .../deployment-cli-tools/tests/test_utils.py | 7 +- 113 files changed, 514 insertions(+), 480 deletions(-) create mode 100644 lint.sh diff --git a/application-templates/base/test/api/test_st.py b/application-templates/base/test/api/test_st.py index cb4e97994..902e2bd5e 100644 --- a/application-templates/base/test/api/test_st.py +++ b/application-templates/base/test/api/test_st.py @@ -3,7 +3,7 @@ import schemathesis as st from schemathesis.checks import response_schema_conformance, not_a_server_error -from cloudharness_test import apitest_init # include to perform default authorization +from cloudharness_test import apitest_init # include to perform default authorization app_url = os.environ.get("APP_URL", "http://samples.ch.local/api") @@ -15,4 +15,3 @@ def test_ping(case): response = case.call() pprint(response.__dict__) assert response.status_code == 200, "this api errors on purpose" - diff --git a/application-templates/django-app/api/test_st.py b/application-templates/django-app/api/test_st.py index fb852433d..a7527b804 100644 --- a/application-templates/django-app/api/test_st.py +++ b/application-templates/django-app/api/test_st.py @@ -3,7 +3,7 @@ import schemathesis as st from schemathesis.checks import response_schema_conformance, not_a_server_error -from cloudharness_test import apitest_init # include to perform default authorization +from cloudharness_test import apitest_init # include to perform default authorization app_url = os.environ.get("APP_URL", "http://samples.ch.local/api") @@ -20,8 +20,9 @@ def test_ping(case): pprint(response.__dict__) assert response.status_code == 200, "this api errors on purpose" + def test_state_machine(): schema.as_state_machine().run() # APIWorkflow = schema.as_state_machine() # APIWorkflow.run() -# TestAPI = APIWorkflow.TestCase \ No newline at end of file +# TestAPI = APIWorkflow.TestCase diff --git a/application-templates/django-app/backend/__APP_NAME__/asgi.py b/application-templates/django-app/backend/__APP_NAME__/asgi.py index 43321f43d..6d1bf4d96 100644 --- a/application-templates/django-app/backend/__APP_NAME__/asgi.py +++ b/application-templates/django-app/backend/__APP_NAME__/asgi.py @@ -16,9 +16,9 @@ application = get_asgi_application() # init the auth service -from cloudharness_django.services import init_services +from cloudharness_django.services import init_services # noqa E402 init_services() # start the kafka event listener -import cloudharness_django.services.events +import cloudharness_django.services.events # noqa E402 diff --git a/application-templates/django-app/backend/__APP_NAME__/settings.py b/application-templates/django-app/backend/__APP_NAME__/settings.py index e9ad5dc58..9b3c6d221 100644 --- a/application-templates/django-app/backend/__APP_NAME__/settings.py +++ b/application-templates/django-app/backend/__APP_NAME__/settings.py @@ -120,13 +120,13 @@ # *********************************************************************** # * __APP_NAME__ settings # *********************************************************************** -from cloudharness.applications import get_configuration -from cloudharness.utils.config import ALLVALUES_PATH, CloudharnessConfig +from cloudharness.applications import get_configuration # noqa E402 +from cloudharness.utils.config import ALLVALUES_PATH, CloudharnessConfig # noqa E402 # *********************************************************************** # * import base CloudHarness Django settings # *********************************************************************** -from cloudharness_django.settings import * +from cloudharness_django.settings import * # noqa E402 # add the local apps INSTALLED_APPS += [ diff --git a/application-templates/django-app/backend/__APP_NAME__/urls.py b/application-templates/django-app/backend/__APP_NAME__/urls.py index 185efb49a..ce1b9629e 100644 --- a/application-templates/django-app/backend/__APP_NAME__/urls.py +++ b/application-templates/django-app/backend/__APP_NAME__/urls.py @@ -24,7 +24,7 @@ urlpatterns = [path("admin/", admin.site.urls)] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + \ - static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += [re_path(r"^(?P.*)$", index, name="index")] admin.site.site_header = "__APP_NAME__ Admin" diff --git a/application-templates/django-app/backend/__APP_NAME__/wsgi.py b/application-templates/django-app/backend/__APP_NAME__/wsgi.py index 34560de81..678932f0f 100644 --- a/application-templates/django-app/backend/__APP_NAME__/wsgi.py +++ b/application-templates/django-app/backend/__APP_NAME__/wsgi.py @@ -16,9 +16,9 @@ application = get_wsgi_application() # init the auth service -from cloudharness_django.services import init_services +from cloudharness_django.services import init_services # noqa E402 init_services() # start the kafka event listener -import cloudharness_django.services.events +import cloudharness_django.services.events # noqa E402 diff --git a/application-templates/django-app/backend/api/controllers/__init__.py b/application-templates/django-app/backend/api/controllers/__init__.py index d716607ef..1344f5cc9 100644 --- a/application-templates/django-app/backend/api/controllers/__init__.py +++ b/application-templates/django-app/backend/api/controllers/__init__.py @@ -1 +1 @@ -import api.controllers.test as test_controller \ No newline at end of file +import api.controllers.test as test_controller diff --git a/application-templates/flask-server/backend/__APP_NAME__/__main__.py b/application-templates/flask-server/backend/__APP_NAME__/__main__.py index 1ce1af97d..f2f198da0 100644 --- a/application-templates/flask-server/backend/__APP_NAME__/__main__.py +++ b/application-templates/flask-server/backend/__APP_NAME__/__main__.py @@ -7,4 +7,3 @@ if __name__ == '__main__': main() - diff --git a/application-templates/flask-server/backend/setup.py b/application-templates/flask-server/backend/setup.py index e3caeb8c3..e7700bac9 100644 --- a/application-templates/flask-server/backend/setup.py +++ b/application-templates/flask-server/backend/setup.py @@ -38,4 +38,3 @@ __APP_NAME__ """ ) - diff --git a/application-templates/webapp/backend/__APP_NAME__/__main__.py b/application-templates/webapp/backend/__APP_NAME__/__main__.py index c6becb111..a4b264cb9 100644 --- a/application-templates/webapp/backend/__APP_NAME__/__main__.py +++ b/application-templates/webapp/backend/__APP_NAME__/__main__.py @@ -7,4 +7,3 @@ if __name__ == '__main__': main() - diff --git a/applications/common/server/common/__main__.py b/applications/common/server/common/__main__.py index 4bd6ef172..0a81a3f80 100644 --- a/applications/common/server/common/__main__.py +++ b/applications/common/server/common/__main__.py @@ -7,13 +7,13 @@ from common.controllers.sentry_controller import global_dsn - def init_fn(app): log.info("initializing database from app") cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) if not global_dsn: open_db(app) + app = init_flask(init_app_fn=init_fn) if __name__ == '__main__': diff --git a/applications/common/server/common/config.py b/applications/common/server/common/config.py index 23d0636f3..6e29d747a 100644 --- a/applications/common/server/common/config.py +++ b/applications/common/server/common/config.py @@ -22,7 +22,6 @@ class Config(object): log.error("Cannot configure SENTRY") - class ProductionConfig(Config): DEBUG = False diff --git a/applications/common/server/common/controllers/accounts_controller.py b/applications/common/server/common/controllers/accounts_controller.py index 90202ef36..b09613be9 100644 --- a/applications/common/server/common/controllers/accounts_controller.py +++ b/applications/common/server/common/controllers/accounts_controller.py @@ -3,6 +3,7 @@ from cloudharness import applications from cloudharness.utils.config import CloudharnessConfig + def get_config(): # noqa: E501 """ Gets the config for logging in into accounts diff --git a/applications/common/server/common/controllers/config_controller.py b/applications/common/server/common/controllers/config_controller.py index 169a04788..72f4fdd38 100644 --- a/applications/common/server/common/controllers/config_controller.py +++ b/applications/common/server/common/controllers/config_controller.py @@ -11,6 +11,7 @@ from cloudharness.utils.config import CloudharnessConfig from cloudharness_model.models import HarnessMainConfig + def get_version(): # noqa: E501 """get_version diff --git a/applications/common/server/common/controllers/security_controller_.py b/applications/common/server/common/controllers/security_controller_.py index ecac40558..7d686cba7 100644 --- a/applications/common/server/common/controllers/security_controller_.py +++ b/applications/common/server/common/controllers/security_controller_.py @@ -1,3 +1 @@ from typing import List - - diff --git a/applications/common/server/common/controllers/sentry_controller.py b/applications/common/server/common/controllers/sentry_controller.py index 1daee66fa..4d0727825 100644 --- a/applications/common/server/common/controllers/sentry_controller.py +++ b/applications/common/server/common/controllers/sentry_controller.py @@ -13,6 +13,7 @@ except: global_dsn = None + def getdsn(appname): # noqa: E501 """ Gets the Sentry DSN for a given application or returns the global dsn when set diff --git a/applications/common/server/common/models.py b/applications/common/server/common/models.py index 8817fa654..843e9d20d 100644 --- a/applications/common/server/common/models.py +++ b/applications/common/server/common/models.py @@ -16,4 +16,4 @@ def __init__(self, url, result_all, result_no_stop_words): self.result_no_stop_words = result_no_stop_words def __repr__(self): - return ''.format(self.id) \ No newline at end of file + return ''.format(self.id) diff --git a/applications/common/server/common/repository/sentry.py b/applications/common/server/common/repository/sentry.py index f53349951..4ad449ac0 100644 --- a/applications/common/server/common/repository/sentry.py +++ b/applications/common/server/common/repository/sentry.py @@ -1,14 +1,16 @@ -import sqlalchemy +import sqlalchemy from sqlalchemy.sql import text from cloudharness.utils.env import get_service_public_address from .db import get_db + class SentryProjectNotFound(Exception): pass + def _get_api_token(): # ToDo: may be we can use here a dynamic token, but for now let's use a hard coded one api_token = 'afe75d802007405dbc0c2fb1db4cc8b06b981017f58944d0afac700f743ee06a' @@ -16,31 +18,33 @@ def _get_api_token(): select token from sentry_apitoken where token=:api_token ''') - token = get_db().engine.execute(s, - api_token=api_token - ).fetchall() + token = get_db().engine.execute(s, + api_token=api_token + ).fetchall() if len(token) == 0: # token is not present in the Sentry database, let's create it s = text(''' insert into sentry_apitoken(user_id, token, scopes, date_added, scope_list) values (1, :api_token, 0, now(), :scope_list) ''') - get_db().engine.execute(s, - api_token=api_token, - scope_list='{event:admin,event:read,' - 'member:read,member:admin,' - 'project:read,project:releases,project:admin,project:write,' - 'team:read,team:write,team:admin,' - 'org:read,org:write,org:admin}' - ) + get_db().engine.execute(s, + api_token=api_token, + scope_list='{event:admin,event:read,' + 'member:read,member:admin,' + 'project:read,project:releases,project:admin,project:write,' + 'team:read,team:write,team:admin,' + 'org:read,org:write,org:admin}' + ) return _get_api_token() else: # return the first column from the first row of the query result return token[0][0] + def get_token(): return _get_api_token() + def get_dsn(appname): s = text(''' select public_key, p.id @@ -49,9 +53,9 @@ def get_dsn(appname): where p.slug=:project_slug ''') try: - public_key = get_db().engine.execute(s, - project_slug=appname - ).fetchall() + public_key = get_db().engine.execute(s, + project_slug=appname + ).fetchall() except sqlalchemy.exc.OperationalError: raise SentryProjectNotFound('Sentry is not initialized.') diff --git a/applications/common/server/common/test/test_sentry_controller.py b/applications/common/server/common/test/test_sentry_controller.py index a01d90c91..6f881ad0d 100644 --- a/applications/common/server/common/test/test_sentry_controller.py +++ b/applications/common/server/common/test/test_sentry_controller.py @@ -17,7 +17,7 @@ def test_getdsn(self): Gets the Sentry DSN for a given application """ - headers = { + headers = { 'Accept': 'application/json', } response = self.client.open( diff --git a/applications/common/server/common/util.py b/applications/common/server/common/util.py index fcaed08fa..8e7e71e62 100644 --- a/applications/common/server/common/util.py +++ b/applications/common/server/common/util.py @@ -68,8 +68,8 @@ def deserialize_date(string): :rtype: date """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string).date() @@ -88,8 +88,8 @@ def deserialize_datetime(string): :rtype: datetime """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string) diff --git a/applications/common/server/setup.py b/applications/common/server/setup.py index 007ca859b..838cb45c4 100644 --- a/applications/common/server/setup.py +++ b/applications/common/server/setup.py @@ -38,4 +38,3 @@ Cloud Harness Platform - Reference CH service API """ ) - diff --git a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py index 8fdfa8c18..688ba72a8 100755 --- a/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py +++ b/applications/jupyterhub/deploy/resources/hub/jupyterhub_config.py @@ -1,4 +1,11 @@ # load the config object (satisfies linters) +from z2jh import ( + get_config, + get_name, + get_name_env, + get_secret_value, + set_config_if_not_none, +) c = get_config() # noqa import glob @@ -10,12 +17,12 @@ from kubernetes_asyncio import client from tornado.httpclient import AsyncHTTPClient -#CLOUDHARNESS: EDIT START +# CLOUDHARNESS: EDIT START import logging try: from harness_jupyter.jupyterhub import harness_hub - harness_hub() # activates harness hooks on jupyterhub + harness_hub() # activates harness hooks on jupyterhub except Exception as e: logging.error("could not import harness_jupyter", exc_info=True) # CLOUDHARNESS: EDIT END @@ -24,14 +31,6 @@ configuration_directory = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, configuration_directory) -from z2jh import ( - get_config, - get_name, - get_name_env, - get_secret_value, - set_config_if_not_none, -) - def camelCaseify(s): """convert snake_case to camelCase @@ -513,9 +512,9 @@ def camelCaseify(s): email_domain = 'local' common_oauth_traits = ( - ('client_id', None), - ('client_secret', None), - ('oauth_callback_url', 'callbackUrl'), + ('client_id', None), + ('client_secret', None), + ('oauth_callback_url', 'callbackUrl'), ) print("Auth type", auth_type) if auth_type == 'ch': @@ -560,4 +559,3 @@ def camelCaseify(s): c.domain = get_config('root.domain') c.namespace = get_config('root.namespace') # CLOUDHARNESS: EDIT END - \ No newline at end of file diff --git a/applications/jupyterhub/deploy/resources/hub/z2jh.py b/applications/jupyterhub/deploy/resources/hub/z2jh.py index 2fe0d25b8..24bba5552 100755 --- a/applications/jupyterhub/deploy/resources/hub/z2jh.py +++ b/applications/jupyterhub/deploy/resources/hub/z2jh.py @@ -121,12 +121,12 @@ def get_config(key, default=None): # EDIT: CLOUDHARNESS START import re if value and isinstance(value, str): - replace_var = re.search("{{.*?}}", value) + replace_var = re.search("{{.*?}}", value) if replace_var: variable = replace_var.group(0)[2:-2].strip() repl = get_config(variable) - + if repl: print("replace", variable, "in", value, ":", repl) value = re.sub("{{.*?}}", repl, value) diff --git a/applications/jupyterhub/src/chauthenticator/chauthenticator/auth.py b/applications/jupyterhub/src/chauthenticator/chauthenticator/auth.py index e7b4cb0dc..ba4489fce 100644 --- a/applications/jupyterhub/src/chauthenticator/chauthenticator/auth.py +++ b/applications/jupyterhub/src/chauthenticator/chauthenticator/auth.py @@ -13,11 +13,13 @@ handler.setLevel(logging.DEBUG) logging.getLogger().addHandler(handler) + class CloudHarnessAuthenticateHandler(BaseHandler): """ Handler for /chkclogin Creates a new user based on the keycloak user, and auto starts their server """ + def initialize(self, force_new_server, process_user): super().initialize() self.force_new_server = force_new_server @@ -28,23 +30,23 @@ def get(self): self.clear_login_cookie() try: - - accessToken = self.request.cookies.get( - 'kc-access', None) or self.request.cookies.get('accessToken', None) - print("Token", accessToken) - if accessToken == '-1' or not accessToken: - self.redirect('/hub/logout') - - accessToken = accessToken.value - user_data = AuthClient.decode_token(accessToken) - username = user_data['sub'] - print("Username", username, "-",user_data['preferred_username']) - raw_user = self.user_from_username(username) - print("JH user: ", raw_user.__dict__) - self.set_login_cookie(raw_user) + + accessToken = self.request.cookies.get( + 'kc-access', None) or self.request.cookies.get('accessToken', None) + print("Token", accessToken) + if accessToken == '-1' or not accessToken: + self.redirect('/hub/logout') + + accessToken = accessToken.value + user_data = AuthClient.decode_token(accessToken) + username = user_data['sub'] + print("Username", username, "-", user_data['preferred_username']) + raw_user = self.user_from_username(username) + print("JH user: ", raw_user.__dict__) + self.set_login_cookie(raw_user) except Exception as e: - logging.error("Error getting user from session", exc_info=True) - raise + logging.error("Error getting user from session", exc_info=True) + raise user = yield gen.maybe_future(self.process_user(raw_user, self)) self.redirect(self.get_next_url(user)) diff --git a/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py b/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py index ac7dafa66..3c9679e34 100644 --- a/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py +++ b/applications/jupyterhub/src/harness_jupyter/harness_jupyter/jupyterhub.py @@ -116,7 +116,7 @@ def change_pod_manifest(self: KubeSpawner): quota_ws_open = user_quotas.get("quota-ws-open") # Default value, might be overwritten by the app config - self.storage_pvc_ensure = bool(self.pvc_name) + self.storage_pvc_ensure = bool(self.pvc_name) if quota_ws_open: # get user number of pods running @@ -124,11 +124,11 @@ def change_pod_manifest(self: KubeSpawner): num_of_pods = len([s for s in servers if s.active]) if num_of_pods > int(quota_ws_open): raise PodSpawnException( - "You reached your quota of {} concurrent servers." - " One must be deleted before a new server can be started".format( - quota_ws_open - ), - ) + "You reached your quota of {} concurrent servers." + " One must be deleted before a new server can be started".format( + quota_ws_open + ), + ) try: subdomain = self.handler.request.host.split( str(self.config['domain']))[0][0:-1] @@ -263,13 +263,12 @@ def change_pod_manifest(self: KubeSpawner): from pprint import pprint pprint(self.storage_class) - # If there's a timeout, just let it propagate asyncio.ensure_future(exponential_backoff( - partial( - self._make_create_pvc_request, pvc, self.k8s_api_request_timeout - ), - f'Could not create PVC {self.pvc_name}', - # Each req should be given k8s_api_request_timeout seconds. - timeout=self.k8s_api_request_retry_timeout, - )) + partial( + self._make_create_pvc_request, pvc, self.k8s_api_request_timeout + ), + f'Could not create PVC {self.pvc_name}', + # Each req should be given k8s_api_request_timeout seconds. + timeout=self.k8s_api_request_retry_timeout, + )) diff --git a/applications/nfsserver/nfs-subdir-external-provisioner/release-tools/boilerplate/boilerplate.py b/applications/nfsserver/nfs-subdir-external-provisioner/release-tools/boilerplate/boilerplate.py index 5618b9ab8..26a2412ac 100755 --- a/applications/nfsserver/nfs-subdir-external-provisioner/release-tools/boilerplate/boilerplate.py +++ b/applications/nfsserver/nfs-subdir-external-provisioner/release-tools/boilerplate/boilerplate.py @@ -50,6 +50,7 @@ verbose_out = sys.stderr if args.verbose else open("/dev/null", "w") + def get_refs(): refs = {} @@ -63,6 +64,7 @@ def get_refs(): return refs + def file_passes(filename, refs, regexs): try: f = open(filename, 'r') @@ -127,13 +129,16 @@ def file_passes(filename, refs, regexs): return True + def file_extension(filename): return os.path.splitext(filename)[1].split(".")[-1].lower() + skipped_dirs = ['Godeps', 'third_party', '_gopath', '_output', '.git', 'cluster/env.sh', 'vendor', 'test/e2e/generated/bindata.go', 'repo-infra/verify/boilerplate/test', '.glide'] + def normalize_files(files): newfiles = [] for pathname in files: @@ -142,6 +147,7 @@ def normalize_files(files): newfiles.append(pathname) return newfiles + def get_files(extensions): files = [] if len(args.filenames) > 0: @@ -170,13 +176,14 @@ def get_files(extensions): outfiles.append(pathname) return outfiles + def get_regexs(): regexs = {} # Search for "YEAR" which exists in the boilerplate, but shouldn't in the real thing - regexs["year"] = re.compile( 'YEAR' ) + regexs["year"] = re.compile('YEAR') # dates can be 2014, 2015, 2016, ..., CURRENT_YEAR, company holder names can be anything years = range(2014, date.today().year + 1) - regexs["date"] = re.compile( '(%s)' % "|".join(map(lambda l: str(l), years)) ) + regexs["date"] = re.compile('(%s)' % "|".join(map(lambda l: str(l), years))) # strip // +build \n\n build constraints regexs["go_build_constraints"] = re.compile(r"^(// \+build.*\n)+\n", re.MULTILINE) # strip #!.* from shell scripts @@ -184,7 +191,6 @@ def get_regexs(): return regexs - def main(): regexs = get_regexs() refs = get_refs() @@ -196,5 +202,6 @@ def main(): return 0 + if __name__ == "__main__": sys.exit(main()) diff --git a/applications/notifications/server/notifications/__main__.py b/applications/notifications/server/notifications/__main__.py index 38389bde9..03c83f863 100644 --- a/applications/notifications/server/notifications/__main__.py +++ b/applications/notifications/server/notifications/__main__.py @@ -8,4 +8,3 @@ def main(): if __name__ == '__main__': main() - diff --git a/applications/notifications/server/notifications/adapters/base_adapter.py b/applications/notifications/server/notifications/adapters/base_adapter.py index 4ea030fe7..5ecf70f9e 100644 --- a/applications/notifications/server/notifications/adapters/base_adapter.py +++ b/applications/notifications/server/notifications/adapters/base_adapter.py @@ -65,7 +65,7 @@ def __init__(self, notification, channel, backend): os.path.join( self.channel["templateFolder"], self.notification["template"] - )) + )) @abc.abstractmethod def send(self, context): diff --git a/applications/notifications/server/notifications/backends/console_backend.py b/applications/notifications/server/notifications/backends/console_backend.py index 0a1fd005d..a50bc8030 100644 --- a/applications/notifications/server/notifications/backends/console_backend.py +++ b/applications/notifications/server/notifications/backends/console_backend.py @@ -18,4 +18,4 @@ def __init__(self, *args, **kwargs): def send(self): log.info("Send notification") log.info(f"args:{self.args}") - log.info("kwargs:\n"+"\n".join("{0}: {1!r}".format(k,v) for k,v in self.kwargs.items())) + log.info("kwargs:\n" + "\n".join("{0}: {1!r}".format(k, v) for k, v in self.kwargs.items())) diff --git a/applications/notifications/server/notifications/backends/email_backend.py b/applications/notifications/server/notifications/backends/email_backend.py index 53f71ec82..8a3ae77df 100644 --- a/applications/notifications/server/notifications/backends/email_backend.py +++ b/applications/notifications/server/notifications/backends/email_backend.py @@ -22,7 +22,6 @@ def __init__(self, email_from=None, email_to=None, subject=None, message=None, * self.subject = subject self.message = message - def send(self): logger.info(f"Sending notification email to {self.email_to}") msg = EmailMessage() @@ -35,7 +34,7 @@ def send(self): email_pass = get_secret_or_empty('email-password') email_host = conf.get_configuration()["smtp"]["host"] email_port = conf.get_configuration()["smtp"]["port"] - email_tls = conf.get_configuration()["smtp"].get("use_tls") + email_tls = conf.get_configuration()["smtp"].get("use_tls") smtp = smtplib.SMTP(email_host, email_port) if email_user or email_pass: diff --git a/applications/notifications/server/notifications/controllers/helpers.py b/applications/notifications/server/notifications/controllers/helpers.py index 090abd485..355e0894e 100644 --- a/applications/notifications/server/notifications/controllers/helpers.py +++ b/applications/notifications/server/notifications/controllers/helpers.py @@ -14,9 +14,9 @@ def send(operation, context): if not channel: continue - + for b in channel["backends"]: - if b == "email": + if b == "email": channel_backend = NotificationEmailBackend elif b == "console": channel_backend = NotificationConsoleBackend diff --git a/applications/notifications/server/notifications/controllers/notifications_controller.py b/applications/notifications/server/notifications/controllers/notifications_controller.py index a0afde4ae..cd4634c52 100644 --- a/applications/notifications/server/notifications/controllers/notifications_controller.py +++ b/applications/notifications/server/notifications/controllers/notifications_controller.py @@ -43,6 +43,7 @@ def handle_event(self, message: CDCEvent): } ) + class NotificationsController: _notification_handlers = [] @@ -52,7 +53,7 @@ def __init__(self): @staticmethod def handler(app, event_client, message): - log.debug("Handler received message: %s",message) + log.debug("Handler received message: %s", message) for nh in [nh for nh in NotificationsController._notification_handlers if nh.message_type == message.get("message_type")]: nh.handle_event(CDCEvent.from_dict(message)) @@ -64,8 +65,8 @@ def _init_handlers(self): log.info(f"Init handler for event {notification_app['app']}.{notification_type['name']} type {event_type}") nss = NotificationHandler( event_type, - notification_app["app"], - notification_type["name"], + notification_app["app"], + notification_type["name"], notification_type["events"]) if not nss.topic_id in (handler.topic_id for handler in NotificationsController._notification_handlers): self._consume_topic(nss.topic_id) diff --git a/applications/notifications/server/setup.py b/applications/notifications/server/setup.py index e126c6655..4f4ecf1b6 100644 --- a/applications/notifications/server/setup.py +++ b/applications/notifications/server/setup.py @@ -34,4 +34,3 @@ notifications """ ) - diff --git a/applications/samples/backend/samples/controllers/auth_controller.py b/applications/samples/backend/samples/controllers/auth_controller.py index 5d3ecb47b..e2930680d 100644 --- a/applications/samples/backend/samples/controllers/auth_controller.py +++ b/applications/samples/backend/samples/controllers/auth_controller.py @@ -24,4 +24,4 @@ def valid_cookie(): # noqa: E501 :rtype: List[Valid] """ - return 'OK!' \ No newline at end of file + return 'OK!' diff --git a/applications/samples/backend/samples/controllers/security_controller_.py b/applications/samples/backend/samples/controllers/security_controller_.py index 8dd254a23..c052e680f 100644 --- a/applications/samples/backend/samples/controllers/security_controller_.py +++ b/applications/samples/backend/samples/controllers/security_controller_.py @@ -13,5 +13,3 @@ def info_from_bearerAuth(token): :rtype: dict | None """ return {'uid': 'user_id'} - - diff --git a/applications/samples/backend/samples/controllers/test_controller.py b/applications/samples/backend/samples/controllers/test_controller.py index ff1089736..f3580dc3d 100644 --- a/applications/samples/backend/samples/controllers/test_controller.py +++ b/applications/samples/backend/samples/controllers/test_controller.py @@ -24,13 +24,13 @@ def ping(): # noqa: E501 """ import os - + expected_environment_variables = { 'WORKERS': '3', 'ENVIRONMENT_TEST_A': 'value', 'ENVIRONMENT_TEST_B': '123', } - + for key, expected_value in expected_environment_variables.items(): try: environment_value = os.environ[key] @@ -38,9 +38,10 @@ def ping(): # noqa: E501 raise Exception(f'Expected environment variable {key} to be {expected_value}, but got {environment_value}') except KeyError: raise Exception(f'Expected to have an environment variable {key} defined') - + import time return time.time() + def serialization(): - return User(last_name="Last", first_name="First") \ No newline at end of file + return User(last_name="Last", first_name="First") diff --git a/applications/samples/backend/samples/service/resource_service.py b/applications/samples/backend/samples/service/resource_service.py index 64765ad24..9fbba7b45 100644 --- a/applications/samples/backend/samples/service/resource_service.py +++ b/applications/samples/backend/samples/service/resource_service.py @@ -8,6 +8,7 @@ counter = 0 resources = {} + class ResourceNotFound(Exception): pass @@ -34,7 +35,7 @@ def get_sample_resource(sampleresource_id: int): # noqa: E501 def get_sample_resources() -> List[SampleResource]: - return [v for v in resources.values()] + return [v for v in resources.values()] def update_sample_resource(sampleresource_id: int, sample_resource: SampleResource) -> List[SampleResource]: diff --git a/applications/samples/backend/samples/test/test_sample.py b/applications/samples/backend/samples/test/test_sample.py index a6f1c78f9..62acfabab 100644 --- a/applications/samples/backend/samples/test/test_sample.py +++ b/applications/samples/backend/samples/test/test_sample.py @@ -1,2 +1,2 @@ def test_sample(): - assert True \ No newline at end of file + assert True diff --git a/applications/samples/backend/samples/util.py b/applications/samples/backend/samples/util.py index 5b241814f..b802fafda 100644 --- a/applications/samples/backend/samples/util.py +++ b/applications/samples/backend/samples/util.py @@ -67,8 +67,8 @@ def deserialize_date(string): :rtype: date """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string).date() @@ -87,8 +87,8 @@ def deserialize_datetime(string): :rtype: datetime """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string) @@ -144,4 +144,4 @@ def _deserialize_dict(data, boxed_type): :rtype: dict """ return {k: _deserialize(v, boxed_type) - for k, v in data.items() } + for k, v in data.items()} diff --git a/applications/samples/backend/setup.py b/applications/samples/backend/setup.py index 16908eb68..fe7e0ce52 100644 --- a/applications/samples/backend/setup.py +++ b/applications/samples/backend/setup.py @@ -37,4 +37,3 @@ CloudHarness Sample api """ ) - diff --git a/applications/samples/tasks/sum/main.py b/applications/samples/tasks/sum/main.py index 578c49520..30a94736e 100644 --- a/applications/samples/tasks/sum/main.py +++ b/applications/samples/tasks/sum/main.py @@ -1,9 +1,9 @@ +from cloudharness.workflows.utils import get_shared_directory import sys import os assert len(sys.argv) > 2, 'Arguments not specified. Cannot proceed' -from cloudharness.workflows.utils import get_shared_directory a = float(sys.argv[1]) b = float(sys.argv[2]) @@ -15,4 +15,4 @@ print("File name is", file_name) with open(file_name, "w") as f: - f.write(str(a+b)) + f.write(str(a + b)) diff --git a/applications/samples/test/api/test_st.py b/applications/samples/test/api/test_st.py index afac61dc2..e67cb3e55 100644 --- a/applications/samples/test/api/test_st.py +++ b/applications/samples/test/api/test_st.py @@ -3,7 +3,7 @@ import schemathesis as st from schemathesis.checks import response_schema_conformance, not_a_server_error -from cloudharness_test import apitest_init # include to perform default authorization +from cloudharness_test import apitest_init # include to perform default authorization app_url = os.environ.get("APP_URL", "http://samples.ch.local/api") @@ -16,18 +16,21 @@ def test_api(case): pprint(response.__dict__) assert response.status_code >= 500, "this api errors on purpose" + @schema.parametrize(endpoint="/valid") def test_bearer(case): response = case.call() - + case.validate_response(response, checks=(response_schema_conformance,)) + @schema.parametrize(endpoint="/valid-cookie") def test_cookie(case): response = case.call() case.validate_response(response, checks=(response_schema_conformance,)) + @schema.parametrize(endpoint="/sampleresources", method="POST") def test_response(case): response = case.call() - case.validate_response(response, checks=(response_schema_conformance,)) \ No newline at end of file + case.validate_response(response, checks=(response_schema_conformance,)) diff --git a/applications/volumemanager/server/setup.py b/applications/volumemanager/server/setup.py index 5efc5693c..2d6ff8de9 100644 --- a/applications/volumemanager/server/setup.py +++ b/applications/volumemanager/server/setup.py @@ -36,4 +36,3 @@ CloudHarness Volumes manager API """ ) - diff --git a/applications/volumemanager/server/volumemanager/controllers/rest_controller.py b/applications/volumemanager/server/volumemanager/controllers/rest_controller.py index 879fb7434..5eb30a4f5 100644 --- a/applications/volumemanager/server/volumemanager/controllers/rest_controller.py +++ b/applications/volumemanager/server/volumemanager/controllers/rest_controller.py @@ -8,6 +8,7 @@ from volumemanager.models.persistent_volume_claim_create import PersistentVolumeClaimCreate # noqa: E501 from volumemanager import util + def pvc_name_get(name): # noqa: E501 """Used to retrieve a Persistent Volume Claim from the Kubernetes repository. @@ -26,7 +27,7 @@ def pvc_name_get(name): # noqa: E501 name=pvc.metadata.name, namespace=pvc.metadata.namespace, accessmode=pvc.status.access_modes[0], - size=pvc.status.capacity.get('storage','') + size=pvc.status.capacity.get('storage', '') ) return pvc @@ -44,7 +45,7 @@ def pvc_post(): # noqa: E501 if connexion.request.is_json: persistent_volume_claim_create = PersistentVolumeClaimCreate.from_dict(connexion.request.get_json()) # noqa: E501 create_persistent_volume_claim( - name=persistent_volume_claim_create.name, + name=persistent_volume_claim_create.name, size=persistent_volume_claim_create.size, logger=flask.current_app.logger) return 'Saved!' diff --git a/applications/volumemanager/server/volumemanager/controllers/security_controller_.py b/applications/volumemanager/server/volumemanager/controllers/security_controller_.py index 8dd254a23..c052e680f 100644 --- a/applications/volumemanager/server/volumemanager/controllers/security_controller_.py +++ b/applications/volumemanager/server/volumemanager/controllers/security_controller_.py @@ -13,5 +13,3 @@ def info_from_bearerAuth(token): :rtype: dict | None """ return {'uid': 'user_id'} - - diff --git a/applications/volumemanager/server/volumemanager/test/test_rest_controller.py b/applications/volumemanager/server/volumemanager/test/test_rest_controller.py index d62a1dbff..ec05bbbd5 100644 --- a/applications/volumemanager/server/volumemanager/test/test_rest_controller.py +++ b/applications/volumemanager/server/volumemanager/test/test_rest_controller.py @@ -19,7 +19,7 @@ def test_pvc_name_get(self): Used to retrieve a Persistent Volume Claim from the Kubernetes repository. """ - headers = { + headers = { 'Accept': 'application/json', 'Authorization': 'Bearer special-key', } @@ -36,10 +36,10 @@ def test_pvc_post(self): Used to create a Persistent Volume Claim in Kubernetes """ persistent_volume_claim_create = { - "size" : "2Gi (see also https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/resources.md#resource-quantities)", - "name" : "pvc-1" -} - headers = { + "size": "2Gi (see also https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/resources.md#resource-quantities)", + "name": "pvc-1" + } + headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'Bearer special-key', diff --git a/applications/volumemanager/server/volumemanager/util.py b/applications/volumemanager/server/volumemanager/util.py index 0c0ee9983..6f7117ad0 100644 --- a/applications/volumemanager/server/volumemanager/util.py +++ b/applications/volumemanager/server/volumemanager/util.py @@ -68,8 +68,8 @@ def deserialize_date(string): :rtype: date """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string).date() @@ -88,8 +88,8 @@ def deserialize_datetime(string): :rtype: datetime """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string) diff --git a/applications/workflows/server/setup.py b/applications/workflows/server/setup.py index 796a48125..c89f97a9b 100644 --- a/applications/workflows/server/setup.py +++ b/applications/workflows/server/setup.py @@ -36,4 +36,3 @@ Workflows API """ ) - diff --git a/applications/workflows/server/workflows_api/__main__.py b/applications/workflows/server/workflows_api/__main__.py index a49051eb4..bafa51099 100644 --- a/applications/workflows/server/workflows_api/__main__.py +++ b/applications/workflows/server/workflows_api/__main__.py @@ -6,5 +6,3 @@ if __name__ == '__main__': main() - - diff --git a/applications/workflows/server/workflows_api/test/test_create_and_access_controller.py b/applications/workflows/server/workflows_api/test/test_create_and_access_controller.py index 04b7ca3b5..ca147dadf 100644 --- a/applications/workflows/server/workflows_api/test/test_create_and_access_controller.py +++ b/applications/workflows/server/workflows_api/test/test_create_and_access_controller.py @@ -20,7 +20,7 @@ def test_delete_operation(self): deletes operation by name """ - headers = { + headers = { } response = self.client.open( '/operations/{name}'.format(name='name_example'), @@ -34,7 +34,7 @@ def test_get_operation(self): get operation by name """ - headers = { + headers = { 'Accept': 'application/json', } response = self.client.open( @@ -52,7 +52,7 @@ def test_list_operations(self): query_string = [('status', QUEUED), ('previous_search_token', 'previous_search_token_example'), ('limit', 10)] - headers = { + headers = { 'Accept': 'application/json', } response = self.client.open( @@ -68,7 +68,7 @@ def test_log_operation(self): get operation by name """ - headers = { + headers = { 'Accept': 'text/plain', } response = self.client.open( diff --git a/applications/workflows/server/workflows_api/util.py b/applications/workflows/server/workflows_api/util.py index d161f16fb..04f3df25e 100644 --- a/applications/workflows/server/workflows_api/util.py +++ b/applications/workflows/server/workflows_api/util.py @@ -68,8 +68,8 @@ def deserialize_date(string): :rtype: date """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string).date() @@ -88,8 +88,8 @@ def deserialize_datetime(string): :rtype: datetime """ if string is None: - return None - + return None + try: from dateutil.parser import parse return parse(string) diff --git a/applications/workflows/tasks/notify-queue/main.py b/applications/workflows/tasks/notify-queue/main.py index 8c58da54d..882833551 100644 --- a/applications/workflows/tasks/notify-queue/main.py +++ b/applications/workflows/tasks/notify-queue/main.py @@ -1,13 +1,15 @@ + import sys import os import logging +from cloudharness.workflows.utils import notify_queue + logging.basicConfig(stream=sys.stdout, level=logging.INFO) assert len( sys.argv) > 3, 'Not all arguments not specified. Cannot notify queue. Usage: [workflow status] [queue name] [payload]' -from cloudharness.workflows.utils import notify_queue queue = sys.argv[2] message = {'status': sys.argv[1], 'payload': sys.argv[3], 'workflow': os.getenv('CH_WORKFLOW_NAME')} diff --git a/applications/workflows/tasks/send-result-event/main.py b/applications/workflows/tasks/send-result-event/main.py index a8cad83c3..b8f81e7b0 100644 --- a/applications/workflows/tasks/send-result-event/main.py +++ b/applications/workflows/tasks/send-result-event/main.py @@ -1,17 +1,20 @@ import sys import os -print("Starting send-result-event") + import glob from cloudharness import log, set_debug from cloudharness.workflows.utils import notify_queue -MAX_FILE_SIZE = 2 ** 20 # 1MB + from cloudharness.events.client import EventClient from cloudharness.workflows.utils import get_workflow_name + +MAX_FILE_SIZE = 2 ** 20 # 1MB +print("Starting send-result-event") set_debug() -topic_name = get_workflow_name() # Coming from the workflow name +topic_name = get_workflow_name() # Coming from the workflow name log.info("Topic name is: " + topic_name) @@ -23,7 +26,6 @@ log.info("Sending content of directory `{}` to event queue topic `{}`".format(shared_directory, topic_name)) - assert os.path.exists(shared_directory), shared_directory + " does not exist." for file_path in glob.glob(f"{shared_directory}/*"): @@ -31,7 +33,7 @@ size = os.path.getsize(file_path) if size > MAX_FILE_SIZE: log.warning(f"{file_path} size is {size}, which is greater than the maximum of {MAX_FILE_SIZE}." - "The content will not be sent to the queue") + "The content will not be sent to the queue") notify_queue(topic_name, {file_path: "Error: size exceeded"}) log.info("Sending content for file `{}`".format(file_path)) @@ -42,5 +44,4 @@ log.error("Error reading file " + file_path + " " + str(e)) continue - notify_queue(topic_name, {os.path.basename(file_path): content}) diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/admin.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/admin.py index f3db25938..493384e07 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/admin.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/admin.py @@ -12,6 +12,7 @@ admin.site.unregister(User) admin.site.unregister(Group) + class CHUserAdmin(ExtraButtonsMixin, UserAdmin): def has_add_permission(self, request): @@ -45,5 +46,6 @@ def sync_keycloak(self, request): get_user_service().sync_kc_users_groups() self.message_user(request, 'Keycloak users & groups synced.') + admin.site.register(User, CHUserAdmin) admin.site.register(Group, CHGroupAdmin) diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/exceptions.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/exceptions.py index 4b14452af..8c8b7eab7 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/exceptions.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/exceptions.py @@ -1,16 +1,21 @@ from keycloak.exceptions import KeycloakOperationError + class KeycloakOIDCNoAdminRole(KeycloakOperationError): pass + class KeycloakOIDCNoDefaultUserRole(KeycloakOperationError): pass + class KeycloakOIDCNoProjectError(KeycloakOperationError): pass + class KeycloakOIDCAuthServiceNotInitError(KeycloakOperationError): pass + class KeycloakOIDUserServiceNotInitError(KeycloakOperationError): - pass \ No newline at end of file + pass diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/middleware.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/middleware.py index dfe399c11..56f707e79 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/middleware.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/middleware.py @@ -10,6 +10,7 @@ from cloudharness_django.services import get_user_service, get_auth_service from cloudharness import log + def _get_user(): bearer = get_authentication_token() if bearer: @@ -31,12 +32,12 @@ def _get_user(): except Exception as e: log.exception("User mapping error, %s", payload["email"]) return None - + return None class BearerTokenMiddleware: - def __init__(self, get_response = None): + def __init__(self, get_response=None): # One-time configuration and initialization. self.get_response = get_response diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/models.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/models.py index 2a44315bb..99ea89cb6 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/models.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/models.py @@ -2,9 +2,11 @@ from django.contrib.auth.models import Group, User # Create your models here. + + class Team(models.Model): group = models.OneToOneField(Group, on_delete=models.CASCADE) - kc_id = models.CharField(max_length = 100) + kc_id = models.CharField(max_length=100) owner = models.ForeignKey(User, on_delete=models.DO_NOTHING) def __str__(self): @@ -13,8 +15,7 @@ def __str__(self): class Member(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) - kc_id = models.CharField(max_length = 100, db_index=True) + kc_id = models.CharField(max_length=100, db_index=True) def __str__(self): return f"{self.user.first_name} {self.user.last_name}" - diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/__init__.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/__init__.py index 2bee296bf..4efca5168 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/__init__.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/__init__.py @@ -10,25 +10,28 @@ _auth_service = None _user_service = None + def get_auth_service(): global _auth_service if not _auth_service: raise KeycloakOIDCAuthServiceNotInitError("Auth Service not initialized") return _auth_service + def get_user_service(): global _user_service if not _user_service: raise KeycloakOIDUserServiceNotInitError("User Service not initialized") return _user_service + def init_services( client_name: str = settings.KC_CLIENT_NAME, client_roles: List[str] = settings.KC_ALL_ROLES, privileged_roles: List[str] = settings.KC_PRIVILEGED_ROLES, admin_role: str = settings.KC_ADMIN_ROLE, default_user_role: str = settings.KC_DEFAULT_USER_ROLE - ): +): from cloudharness_django.services.auth import AuthService from cloudharness_django.services.user import UserService global _auth_service, _user_service diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/auth.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/auth.py index cb3a9ae87..5c808e9e9 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/auth.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/auth.py @@ -22,7 +22,7 @@ class AuthorizationLevel(Enum): # create the auth client if os.path.isfile(ALLVALUES_PATH): try: - # CH values exists so running with a valid config + # CH values exists so running with a valid config auth_client = AuthClient(os.getenv("ACCOUNTS_ADMIN_USERNAME", None), os.getenv("ACCOUNTS_ADMIN_PASSWORD", None)) except: log.exception("Failed to initialize auth client") diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/events.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/events.py index b20fd1a70..55909afe2 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/events.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/events.py @@ -23,7 +23,7 @@ def event_handler(app, event_client, message): resource_path = message["resource-path"].split("/") log.info(f"{event_client} {message}") - if resource in ["CLIENT_ROLE_MAPPING","GROUP","USER","GROUP_MEMBERSHIP"]: + if resource in ["CLIENT_ROLE_MAPPING", "GROUP", "USER", "GROUP_MEMBERSHIP"]: try: init_services() user_service = get_user_service() @@ -71,7 +71,7 @@ def setup_event_service(self): from cloudharness.applications import get_current_configuration current_app = get_current_configuration() - self.test_kafka_running() # if the test fails (raises an exception) then k8s will restart the application + self.test_kafka_running() # if the test fails (raises an exception) then k8s will restart the application # init the topics self.init_topics() except ConfigurationCallException as e: diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/user.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/user.py index e2ec82192..fc49ba368 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/user.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/services/user.py @@ -3,12 +3,14 @@ from cloudharness_django.models import Team, Member from cloudharness_django.services.auth import AuthorizationLevel + def get_user_by_kc_id(kc_id) -> User: try: return Member.objects.get(kc_id=kc_id).user except Member.DoesNotExist: return None + class UserService: def __init__(self, auth_service): self.auth_service = auth_service @@ -35,7 +37,7 @@ def _map_kc_user(self, user, kc_user=None, is_superuser=False, delete=False): user.first_name = kc_user.get("firstName", "") user.last_name = kc_user.get("lastName", "") user.email = kc_user.get("email", "") - + user.is_active = kc_user.get("enabled", delete) return user @@ -80,7 +82,7 @@ def sync_kc_group(self, kc_group): superusers = User.objects.filter(is_superuser=True) if superusers and len(superusers) > 0: team = Team.objects.create( - owner=superusers[0], # one of the superusers will be the default team owner + owner=superusers[0], # one of the superusers will be the default team owner kc_id=kc_group["id"], group=group) team.save() @@ -95,14 +97,14 @@ def sync_kc_groups(self, kc_groups=None): def sync_kc_user(self, kc_user, is_superuser=False, delete=False): # sync the kc user with the django user - + user, created = User.objects.get_or_create(username=kc_user["username"]) - + Member.objects.get_or_create(user=user, kc_id=kc_user["id"]) user = self._map_kc_user(user, kc_user, is_superuser, delete) user.save() return user - + def sync_kc_user_groups(self, kc_user): # Sync the user usergroups and memberships user = User.objects.get(username=kc_user["email"]) diff --git a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/settings.py b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/settings.py index 27c6d5c7f..b9efd5726 100644 --- a/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/settings.py +++ b/infrastructure/common-images/cloudharness-django/libraries/cloudharness-django/cloudharness_django/settings.py @@ -12,19 +12,19 @@ INSTALLED_APPS = getattr( settings, 'INSTALLED_APPS', - []) + [ 'admin_extra_buttons',] + []) + ['admin_extra_buttons', ] # add the local apps -INSTALLED_APPS += ['cloudharness_django',] +INSTALLED_APPS += ['cloudharness_django', ] # add the CloudHarness Django auto login middleware MIDDLEWARE = getattr( - settings, - 'MIDDLEWARE', - [] - ) + [ - 'cloudharness_django.middleware.BearerTokenMiddleware', - ] + settings, + 'MIDDLEWARE', + [] +) + [ + 'cloudharness_django.middleware.BearerTokenMiddleware', +] # test if the kubernetes CH all values exists, if so then set up specific k8s stuff # IMPROTANT NOTE: @@ -35,10 +35,10 @@ app_name = settings.PROJECT_NAME.lower() try: current_app = applications.get_current_configuration() - + # if secured then set USE_X_FORWARDED_HOST because we are behind the GK proxy USE_X_FORWARDED_HOST = current_app.harness.secured - + # CSRF, set CSRF_TRUSTED_ORIGINS CH_DOMAIN = conf.get_domain() CSRF_TRUSTED_ORIGINS = getattr( @@ -65,14 +65,14 @@ if current_app.harness.database.type == "sqlite3": DATABASE_ENGINE = "django.db.backends.sqlite3" - DATABASE_NAME = os.path.join(getattr(settings,"PERSISTENT_ROOT","."), f"{app_name}.sqlite3") + DATABASE_NAME = os.path.join(getattr(settings, "PERSISTENT_ROOT", "."), f"{app_name}.sqlite3") DATABSE_HOST = None DATABASE_PORT = None elif current_app.harness.database.type == "postgres": - DATABASE_ENGINE = "django.db.backends.postgresql" - DATABASE_NAME = current_app.harness.database.postgres.initialdb - DATABSE_HOST = current_app.harness.database.name - DATABASE_PORT = current_app.harness.database.postgres.ports[0].port + DATABASE_ENGINE = "django.db.backends.postgresql" + DATABASE_NAME = current_app.harness.database.postgres.initialdb + DATABSE_HOST = current_app.harness.database.name + DATABASE_PORT = current_app.harness.database.postgres.ports[0].port # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases @@ -86,7 +86,7 @@ "PORT": DATABASE_PORT, "TEST": { "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(getattr(settings,"PERSISTENT_ROOT","."), "testdb.sqlite3"), + "NAME": os.path.join(getattr(settings, "PERSISTENT_ROOT", "."), "testdb.sqlite3"), }, }, } diff --git a/libraries/client/cloudharness_cli/setup.py b/libraries/client/cloudharness_cli/setup.py index 890b95c25..ba088ed6e 100644 --- a/libraries/client/cloudharness_cli/setup.py +++ b/libraries/client/cloudharness_cli/setup.py @@ -37,4 +37,4 @@ long_description="""\ CloudHarness Python API Client # noqa: E501 """ -) \ No newline at end of file +) diff --git a/libraries/cloudharness-common/cloudharness/__init__.py b/libraries/cloudharness-common/cloudharness/__init__.py index 333321f25..b09092791 100644 --- a/libraries/cloudharness-common/cloudharness/__init__.py +++ b/libraries/cloudharness-common/cloudharness/__init__.py @@ -1,37 +1,42 @@ +import json as js +from cloudharness_model.encoder import CloudHarnessJSONEncoder import logging import sys log = logging -from cloudharness_model.encoder import CloudHarnessJSONEncoder FORMAT = "%(asctime)s [%(levelname)s] %(module)s.%(funcName)s: %(message)s" logging.basicConfig(stream=sys.stdout, format=FORMAT, level=logging.INFO) + def set_debug(): logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) # TODO log will write through a rest service -import json as js json_dumps = js.dumps + def dumps(o, *args, **kwargs): try: - if "cls" not in kwargs: + if "cls" not in kwargs: return json_dumps(o, cls=CloudHarnessJSONEncoder, *args, **kwargs) return json_dumps(o, *args, **kwargs) except: logging.error(repr(o)) raise + json = js json.dumps = dumps + class NotCorrectlyInitialized(Exception): pass + def init(appname: str): """ Init cloudharness functionality for the current app @@ -52,5 +57,5 @@ def init(appname: str): except Exception as e: log.warning(f'Error enabling Sentry for {appname}', exc_info=True) -__all__ = ['log', 'init'] +__all__ = ['log', 'init'] diff --git a/libraries/cloudharness-common/cloudharness/auth/exceptions.py b/libraries/cloudharness-common/cloudharness/auth/exceptions.py index 254340b8d..3cc1e4eb1 100644 --- a/libraries/cloudharness-common/cloudharness/auth/exceptions.py +++ b/libraries/cloudharness-common/cloudharness/auth/exceptions.py @@ -1,11 +1,14 @@ from keycloak.exceptions import KeycloakAuthenticationError, KeycloakGetError + class UserNotFound(KeycloakGetError): pass + class InvalidToken(Exception): pass + class AuthSecretNotFound(Exception): def __init__(self, secret_name): - Exception.__init__(self, f"Secret {secret_name} not found.") \ No newline at end of file + Exception.__init__(self, f"Secret {secret_name} not found.") diff --git a/libraries/cloudharness-common/cloudharness/auth/keycloak.py b/libraries/cloudharness-common/cloudharness/auth/keycloak.py index c86aed3af..443ebdade 100644 --- a/libraries/cloudharness-common/cloudharness/auth/keycloak.py +++ b/libraries/cloudharness-common/cloudharness/auth/keycloak.py @@ -21,9 +21,6 @@ ALLVALUES_PATH, exc_info=True) - - - def get_api_password() -> str: name = "api_user_password" AUTH_SECRET_PATH = os.environ.get( @@ -76,16 +73,18 @@ def get_server_url(): def get_auth_realm(): return conf.get_namespace() + def get_token(username, password): conf = get_configuration("accounts") keycloak_openid = KeycloakOpenID( - server_url=get_server_url(), - realm_name=get_auth_realm(), - client_id=conf["webclient"]["id"], + server_url=get_server_url(), + realm_name=get_auth_realm(), + client_id=conf["webclient"]["id"], client_secret_key=conf["webclient"]["secret"]) return keycloak_openid.token(username, password)['access_token'] + def is_uuid(s): import uuid try: @@ -116,7 +115,7 @@ def _get_keycloak_user_id(): keycloak_user_id = "-1" # No authorization --> no user else: token = authentication_token.split(' ')[-1] - + keycloak_user_id = AuthClient.decode_token(token)['sub'] return keycloak_user_id @@ -127,10 +126,9 @@ def __init__(self, username=None, password=None): """ self.user = username or os.getenv('ACCOUNTS_ADMIN_USERNAME', None) or "admin_api" - self.passwd = password or os.getenv('ACCOUNTS_ADMIN_PASSWORD', None) or get_api_password() + self.passwd = password or os.getenv('ACCOUNTS_ADMIN_PASSWORD', None) or get_api_password() # test if we can connect to the Keycloak server dummy_client = self.get_admin_client() - def get_admin_client(self): """ @@ -143,8 +141,6 @@ def get_admin_client(self): :return: KeycloakAdmin """ - - if not getattr(self, "_admin_client", None): self._admin_client = KeycloakAdmin( server_url=get_server_url(), @@ -189,7 +185,7 @@ def decode_token(cls, token, audience="web-client"): """ try: decoded = jwt.decode(token, cls.get_public_key(), - algorithms='RS256', audience=audience) + algorithms='RS256', audience=audience) except jwt.exceptions.InvalidTokenError as e: raise InvalidToken(e) from e return decoded @@ -270,7 +266,7 @@ def create_client_role(self, client_id, role): def get_group(self, group_id, with_members=False, with_details=False) -> UserGroup: """ Return the group in the application realm - + :param group_id: the group id to get :param with_members: Default False, when set to True all members of the group are also retrieved :param with_details: Default False, when set to True all attributes of the group are also retrieved @@ -307,7 +303,7 @@ def get_groups(self, with_members=False) -> List[UserGroup]: """ admin_client = self.get_admin_client() return [ - UserGroup.from_dict(self.get_group(group['id'], with_members)) + UserGroup.from_dict(self.get_group(group['id'], with_members)) for group in admin_client.get_groups() ] @@ -394,7 +390,7 @@ def group_user_remove(self, user_id, group_id): def get_users(self, query=None, with_details=False) -> List[User]: """ Return a list of all users in the application realm - + :param query: Default None, the query filter for getting the users :param with_details: Default False, when set to True all attributes of the group are also retrieved @@ -413,7 +409,7 @@ def get_users(self, query=None, with_details=False) -> List[User]: user.update({ "userGroups": admin_client.get_user_groups(user['id'], brief_representation=not with_details), 'realmRoles': admin_client.get_realm_roles_of_user(user['id']) - }) + }) users.append(User.from_dict(user)) return users @@ -442,23 +438,22 @@ def get_user(self, user_id, with_details=False) -> User: raise UserNotFound(user_id) except InvalidToken as e: raise UserNotFound(user_id) - - + else: found_users = admin_client.get_users({"username": user_id, "exact": True}) if len(found_users) == 0: raise UserNotFound(user_id) try: - user = admin_client.get_user(found_users[0]['id']) # Load full data + user = admin_client.get_user(found_users[0]['id']) # Load full data except KeycloakGetError as e: raise UserNotFound(user_id) except InvalidToken as e: raise UserNotFound(user_id) - + user.update({ - "userGroups": admin_client.get_user_groups(user_id=user['id'], brief_representation=not with_details), - 'realmRoles': admin_client.get_realm_roles_of_user(user['id']) - }) + "userGroups": admin_client.get_user_groups(user_id=user['id'], brief_representation=not with_details), + 'realmRoles': admin_client.get_realm_roles_of_user(user['id']) + }) return User.from_dict(user) def get_current_user(self) -> User: @@ -474,7 +469,7 @@ def get_current_user(self) -> User: :return: UserRepresentation + GroupRepresentation """ return self.get_user(self._get_keycloak_user_id()) - + @with_refreshtoken def get_user_realm_roles(self, user_id) -> List[str]: """ @@ -487,7 +482,7 @@ def get_user_realm_roles(self, user_id) -> List[str]: :return: (array RoleRepresentation) """ - admin_client=self.get_admin_client() + admin_client = self.get_admin_client() return admin_client.get_realm_roles_of_user(user_id) def get_current_user_realm_roles(self) -> List[str]: @@ -510,8 +505,8 @@ def get_user_client_roles(self, user_id, client_name) -> List[str]: :param client_name: Client name :return: (array RoleRepresentation) """ - admin_client=self.get_admin_client() - client_id=admin_client.get_client_id(client_name) + admin_client = self.get_admin_client() + client_id = admin_client.get_client_id(client_name) return admin_client.get_client_roles_of_user(user_id, client_id) def get_current_user_client_roles(self, client_name) -> List[str]: @@ -521,7 +516,7 @@ def get_current_user_client_roles(self, client_name) -> List[str]: :param client_name: Client name :return: UserRepresentation + GroupRepresentation """ - cur_user_id=self._get_keycloak_user_id() + cur_user_id = self._get_keycloak_user_id() return self.get_user_client_roles(cur_user_id, client_name) def user_has_client_role(self, user_id, client_name, role) -> bool: @@ -532,7 +527,7 @@ def user_has_client_role(self, user_id, client_name, role) -> bool: :param client_name: Name of the client :param role: Name of the role """ - roles=[user_client_role for user_client_role in self.get_user_client_roles( + roles = [user_client_role for user_client_role in self.get_user_client_roles( user_id, client_name) if user_client_role['name'] == role] return roles != [] @@ -543,7 +538,7 @@ def user_has_realm_role(self, user_id, role) -> bool: :param user_id: User id :param role: Name of the role """ - roles=[user_realm_role for user_realm_role in self.get_user_realm_roles( + roles = [user_realm_role for user_realm_role in self.get_user_realm_roles( user_id) if user_realm_role['name'] == role] return roles != [] @@ -577,8 +572,8 @@ def get_client_role_members(self, client_name, role) -> List[User]: :param client_name: Client name :param role: Role name """ - admin_client=self.get_admin_client() - client_id=admin_client.get_client_id(client_name) + admin_client = self.get_admin_client() + client_id = admin_client.get_client_id(client_name) return [User.from_dict(u) for u in admin_client.get_client_role_members(client_id, role)] @with_refreshtoken @@ -591,10 +586,10 @@ def user_add_update_attribute(self, user_id, attribute_name, attribute_value): param attribute_value: value of the attribute """ - admin_client=self.get_admin_client() - user=self.get_user(user_id) - attributes=user.get('attributes', {}) or {} - attributes[attribute_name]=attribute_value + admin_client = self.get_admin_client() + user = self.get_user(user_id) + attributes = user.get('attributes', {}) or {} + attributes[attribute_name] = attribute_value admin_client.update_user( user_id, { @@ -610,9 +605,9 @@ def user_delete_attribute(self, user_id, attribute_name): param attribute_name: name of the attribute to delete :return: boolean True on success, False is attribute not in user attributes """ - admin_client=self.get_admin_client() - user=self.get_user(user_id) - attributes=user.get('attributes', None) + admin_client = self.get_admin_client() + user = self.get_user(user_id) + attributes = user.get('attributes', None) if attributes and attribute_name in attributes: del attributes[attribute_name] admin_client.update_user( diff --git a/libraries/cloudharness-common/cloudharness/errors.py b/libraries/cloudharness-common/cloudharness/errors.py index b53436922..1304cdaa9 100644 --- a/libraries/cloudharness-common/cloudharness/errors.py +++ b/libraries/cloudharness-common/cloudharness/errors.py @@ -3,23 +3,28 @@ def __init__(self, topic_id): self.topic_id = topic_id Exception.__init__(self, f'Events: unable to produce message to topic -> {topic_id}') + class EventTopicCreationException(Exception): def __init__(self, topic_id): self.topic_id = topic_id Exception.__init__(self, f'Events: unable to create topic -> {topic_id}') + class EventTopicConsumeException(Exception): def __init__(self, topic_id): self.topic_id = topic_id Exception.__init__(self, f'Events: unable to consume messages from topic -> {topic_id}') + class EventTopicDeleteException(Exception): def __init__(self, topic_id): self.topic_id = topic_id Exception.__init__(self, f'Events: unable to delete topic -> {topic_id}') + class EventGeneralException(Exception): pass + class MongoDBConfError(Exception): - pass \ No newline at end of file + pass diff --git a/libraries/cloudharness-common/cloudharness/events/client.py b/libraries/cloudharness-common/cloudharness/events/client.py index 0dad22546..f7c00391f 100644 --- a/libraries/cloudharness-common/cloudharness/events/client.py +++ b/libraries/cloudharness-common/cloudharness/events/client.py @@ -28,6 +28,7 @@ AUTH_CLIENT = None CURRENT_APP_NAME = config.get_current_app_name() + def get_authclient(): global AUTH_CLIENT if not AUTH_CLIENT: @@ -55,13 +56,12 @@ def _get_consumer(self, group_id='default') -> KafkaConsumer: group_id=group_id, value_deserializer=lambda x: json.loads(x.decode('utf-8'))) - def create_topic(self): """ Connects to cloudharness Events and creates a new topic Return: True if topic was created correctly, False otherwise. """ - ## Connect to kafka + # Connect to kafka admin_client = KafkaAdminClient(bootstrap_servers=self._get_bootstrap_servers(), client_id=self._get_client_id()) # ## Create topic @@ -184,7 +184,6 @@ def send_event(message_type, operation, obj, uid="id", func_name=None, func_args except Exception as e: log.error('send_event error.', exc_info=True) - def consume_all_cdc(self, group_id='default') -> Generator[CDCEvent, None, None]: """ Return a list of object modification messages published in the topic @@ -222,10 +221,10 @@ def consume_all(self, group_id='default') -> list: def delete_topic(self) -> bool: log.debug("Deleting topic " + self.topic_id) - ## Connect to kafka + # Connect to kafka admin_client = KafkaAdminClient(bootstrap_servers=self._get_bootstrap_servers(), client_id=self._get_client_id()) - ## Delete topic + # Delete topic try: admin_client.delete_topics([self.topic_id]) return True @@ -254,8 +253,8 @@ def _consume_task(self, app=None, group_id=None, handler=None): log.error(f"Error during execution of the consumer Topic {self.topic_id} --> {e}", exc_info=True) self.consumer.close() except Exception as e: - log.error(f"Error during execution of the consumer Topic {self.topic_id} --> {e}", exc_info=True) - time.sleep(15) + log.error(f"Error during execution of the consumer Topic {self.topic_id} --> {e}", exc_info=True) + time.sleep(15) def async_consume(self, app=None, handler=None, group_id='default'): log.debug('creating thread') @@ -263,7 +262,7 @@ def async_consume(self, app=None, handler=None, group_id='default'): log.debug('get current object from app') app = app._get_current_object() self._consumer_thread = threading.Thread( - target=self._consume_task, + target=self._consume_task, kwargs={'app': app, 'group_id': group_id, 'handler': handler}) @@ -271,6 +270,7 @@ def async_consume(self, app=None, handler=None, group_id='default'): self._consumer_thread.start() log.debug('thread started') + if __name__ == "__main__": # creat the required os env variables os.environ['CLOUDHARNESS_EVENTS_CLIENT_ID'] = env.get_cloudharness_events_client_id() diff --git a/libraries/cloudharness-common/cloudharness/infrastructure/k8s.py b/libraries/cloudharness-common/cloudharness/infrastructure/k8s.py index 530921421..9af64a7a7 100644 --- a/libraries/cloudharness-common/cloudharness/infrastructure/k8s.py +++ b/libraries/cloudharness-common/cloudharness/infrastructure/k8s.py @@ -5,24 +5,22 @@ """ import kubernetes -import yaml -import os -from pathlib import Path - from cloudharness import log # TODO handle group -version = 'v1alpha1' +from cloudharness.utils.config import CloudharnessConfig as conf + # determine the namespace of the current app and run the workflow in that namespace -from cloudharness.utils.config import CloudharnessConfig as conf namespace = conf.get_namespace() +version = 'v1alpha1' # --- Api functions --- ` + def get_api_client(): configuration = get_configuration() api_instance = kubernetes.client.CoreV1Api(kubernetes.client.ApiClient(get_configuration())) @@ -51,7 +49,7 @@ def create_namespace(): try: api_response = api_instance.create_namespace(body) - except Exception as e: + except Exception as e: raise Exception(f"Error creating namespace: {namespace}") from e diff --git a/libraries/cloudharness-common/cloudharness/middleware/__init__.py b/libraries/cloudharness-common/cloudharness/middleware/__init__.py index 780ebd49d..c3e0531ad 100644 --- a/libraries/cloudharness-common/cloudharness/middleware/__init__.py +++ b/libraries/cloudharness-common/cloudharness/middleware/__init__.py @@ -2,9 +2,11 @@ _authentication_token = ContextVar("ch_authentication_token", default=None) + def set_authentication_token(authentication_token): if authentication_token: _authentication_token.set(authentication_token) + def get_authentication_token(): return _authentication_token.get() diff --git a/libraries/cloudharness-common/cloudharness/models.py b/libraries/cloudharness-common/cloudharness/models.py index 83e950b37..a9719b604 100644 --- a/libraries/cloudharness-common/cloudharness/models.py +++ b/libraries/cloudharness-common/cloudharness/models.py @@ -1 +1 @@ -from cloudharness_model import * \ No newline at end of file +from cloudharness_model import * diff --git a/libraries/cloudharness-common/cloudharness/sentry/__init__.py b/libraries/cloudharness-common/cloudharness/sentry/__init__.py index fd1b3e5a4..ccc093165 100644 --- a/libraries/cloudharness-common/cloudharness/sentry/__init__.py +++ b/libraries/cloudharness-common/cloudharness/sentry/__init__.py @@ -6,6 +6,7 @@ sentry_environment = os.environ.get("DOMAIN", "Production") + def get_dsn(appname): """ Helper function for getting the Sentry DSN of the project of the application @@ -21,15 +22,16 @@ def get_dsn(appname): Usage examples: from cloudharness.sentry import get_dsn dsn = get_dsn('notifications') - """ + """ url = get_common_service_cluster_address() + f'/api/sentry/getdsn/{appname}' response = requests.get(url, verify=False).json() dsn = response['dsn'] - if dsn and len(dsn)>0: + if dsn and len(dsn) > 0: return dsn else: return None + def init(appname=None, traces_sample_rate=0, integrations=None, **kwargs): """ Init cloudharness Sentry functionality for the current app @@ -65,4 +67,5 @@ def init(appname=None, traces_sample_rate=0, integrations=None, **kwargs): **kwargs ) + __all__ = ['get_dsn', 'init'] diff --git a/libraries/cloudharness-common/cloudharness/service/pvc.py b/libraries/cloudharness-common/cloudharness/service/pvc.py index 18c4f725c..1bca54aff 100644 --- a/libraries/cloudharness-common/cloudharness/service/pvc.py +++ b/libraries/cloudharness-common/cloudharness/service/pvc.py @@ -64,6 +64,7 @@ def _get_default_storage_class() -> str: break return selected_sc + def create_persistent_volume_claim(name, size, logger, storage_class=None, useNFS=False, template=None, access_mode=None, **kwargs): """ Create a Persistent Volume Claim in the Kubernetes cluster. @@ -87,7 +88,7 @@ def create_persistent_volume_claim(name, size, logger, storage_class=None, useNF if not size: raise Exception(f"Size must be set. Got {size!r}.") - + if not storage_class: if not useNFS: storage_class = _get_default_storage_class() @@ -102,18 +103,18 @@ def create_persistent_volume_claim(name, size, logger, storage_class=None, useNF path = os.path.join(os.path.dirname(__file__), 'templates', 'pvc.yaml') template = open(path, 'rt').read() text = template.format( - name=name, - size=size, - storageClass=storage_class) + name=name, + size=size, + storageClass=storage_class) data = dict_merge(yaml.safe_load(text), kwargs) if access_mode: data["spec"]["accessModes"] = [access_mode] obj = _get_corev1_api().create_namespaced_persistent_volume_claim( - namespace=conf.get_configuration()['namespace'], - body=data, - ) + namespace=conf.get_configuration()['namespace'], + body=data, + ) logger.info(f"PVC child is created: %s", obj) @@ -123,7 +124,7 @@ def persistent_volume_claim_exists(name): Args: name (string): the name of the PVC - + Returns: boolean: True if the PVC exists, False is the PVC doesn't exist """ diff --git a/libraries/cloudharness-common/cloudharness/utils/__init__.py b/libraries/cloudharness-common/cloudharness/utils/__init__.py index 26e0b0f7a..cca07dacb 100644 --- a/libraries/cloudharness-common/cloudharness/utils/__init__.py +++ b/libraries/cloudharness-common/cloudharness/utils/__init__.py @@ -28,8 +28,8 @@ def dict_merge(dct, merge_dct, add_keys=True): } for k, v in merge_dct.items(): - if (k in dct and isinstance(dct[k], dict) - and isinstance(merge_dct[k], collections.abc.Mapping)): + if (k in dct and isinstance(dct[k], dict) and + isinstance(merge_dct[k], collections.abc.Mapping)): dct[k] = dict_merge(dct[k], merge_dct[k], add_keys=add_keys) else: dct[k] = merge_dct[k] diff --git a/libraries/cloudharness-common/cloudharness/utils/config.py b/libraries/cloudharness-common/cloudharness/utils/config.py index 13108d7d3..f7024e9d6 100644 --- a/libraries/cloudharness-common/cloudharness/utils/config.py +++ b/libraries/cloudharness-common/cloudharness/utils/config.py @@ -24,15 +24,16 @@ def __getitem__(self, key_or_path: str): obj = obj[k] return obj + class CloudharnessConfig: """ Helper class for the Cloud Harness configuration The CH configuration will be loaded from the values.yaml generated by helm via the harness-deployment script - + """ - allvalues={} + allvalues = {} @classmethod def _get_all_values(cls) -> dict: @@ -63,7 +64,6 @@ def get_current_app_name(cls): def get_domain(cls): return cls.get_configuration()['domain'] - @classmethod def get_registry_name(cls): return cls.get_configuration()['registry']['name'] @@ -122,7 +122,7 @@ def get_application_by_filter(cls, **filter): tmp_obj = tmp_obj[key] if (tmp_obj == filter_value) or \ (filter_value == False and tmp_obj is None) or \ - (filter_value == True and tmp_obj is not None): + (filter_value == True and tmp_obj is not None): apps.append(app) except KeyError: pass diff --git a/libraries/cloudharness-common/cloudharness/utils/env.py b/libraries/cloudharness-common/cloudharness/utils/env.py index 05588aadc..cf3d47b8d 100644 --- a/libraries/cloudharness-common/cloudharness/utils/env.py +++ b/libraries/cloudharness-common/cloudharness/utils/env.py @@ -25,21 +25,22 @@ def set_default_environment(): values = conf.get_configuration() if values and 'env' in values: - os.environ.update({v['name']: str(v["value"]) for v in values['env'] if v['name'] not in os.environ}) - - + os.environ.update({v['name']: str(v["value"]) for v in values['env'] if v['name'] not in os.environ}) set_default_environment() + def get_namespace(): try: - namespace=conf.get_configuration()['namespace'] + namespace = conf.get_configuration()['namespace'] except: - namespace='' + namespace = '' return namespace -namespace=get_namespace() + +namespace = get_namespace() + class VariableNotFound(Exception): def __init__(self, variable_name): @@ -71,6 +72,7 @@ def get_image_registry(): return DEFAULT_IMAGE_REGISTRY + def name_to_variable(application_name): return application_name.upper().replace('-', '_') @@ -92,7 +94,7 @@ def get_service_cluster_address(cloudharness_app_name): def cluster_service_address(service_name): - return f'{service_name}.{namespace}.svc.cluster.local' + return f'{service_name}.{namespace}.svc.cluster.local' def use_public_services(): @@ -101,6 +103,7 @@ def use_public_services(): except VariableNotFound: return False + def get_sub_variable(*vars): return get_variable(name_to_variable('_'.join(vars))) @@ -116,19 +119,24 @@ def get_public_domain(): def get_cloudharness_workflows_service_url(): return get_service_public_address('workflows') + def get_cloudharness_sentry_service_url(): return get_configuration('sentry').get_public_address() + def get_sentry_service_cluster_address(): return get_configuration('sentry').get_service_address() + def get_cloudharness_common_service_url(): return get_configuration('common').get_public_address() + def get_common_service_cluster_address(): common_app = get_configuration('common') return common_app.get_service_address() + def get_auth_service_cluster_address(): return get_configuration('accounts').get_service_address() diff --git a/libraries/cloudharness-common/cloudharness/utils/secrets.py b/libraries/cloudharness-common/cloudharness/utils/secrets.py index 7e39013a9..dc9dc1422 100644 --- a/libraries/cloudharness-common/cloudharness/utils/secrets.py +++ b/libraries/cloudharness-common/cloudharness/utils/secrets.py @@ -13,7 +13,7 @@ def get_secret(name: str) -> str: Helper class for the CloudHarness application secrets The application secret will be read from the secret file - + Args: name (str): name of the secret key (str): name of the data key in the secret diff --git a/libraries/cloudharness-common/cloudharness/utils/settings.py b/libraries/cloudharness-common/cloudharness/utils/settings.py index 8b1378917..e69de29bb 100644 --- a/libraries/cloudharness-common/cloudharness/utils/settings.py +++ b/libraries/cloudharness-common/cloudharness/utils/settings.py @@ -1 +0,0 @@ - diff --git a/libraries/cloudharness-common/cloudharness/workflows/argo.py b/libraries/cloudharness-common/cloudharness/workflows/argo.py index 46595beb3..4f1c4cdcd 100644 --- a/libraries/cloudharness-common/cloudharness/workflows/argo.py +++ b/libraries/cloudharness-common/cloudharness/workflows/argo.py @@ -133,11 +133,11 @@ def get_workflows(status=None, limit=10, continue_token=None, timeout_seconds=3, service = WorkflowServiceApi(api_client=get_api_client()) try: - api_response = service.list_workflows(namespace, list_options_limit=limit, list_options_continue=continue_token, - list_options_label_selector=f"workflows.argoproj.io/phase={status}" if status else None, - _request_timeout=timeout_seconds, - list_options_field_selector=field_selector, fields=fields, **kwargs) - + api_response = service.list_workflows(namespace, list_options_limit=limit, list_options_continue=continue_token, + list_options_label_selector=f"workflows.argoproj.io/phase={status}" if status else None, + _request_timeout=timeout_seconds, + list_options_field_selector=field_selector, fields=fields, **kwargs) + except ValueError: # Exception is raised when no results are found return SearchResult(V1alpha1WorkflowList(items=[], metadata={})) @@ -203,4 +203,4 @@ def get_workflow_logs_list(workflow_name): conf.get_configuration()['test'] = True res = get_workflows() pprint(res) - # pprint(get_workflow('hello-world-sfzd4')) \ No newline at end of file + # pprint(get_workflow('hello-world-sfzd4')) diff --git a/libraries/cloudharness-common/cloudharness/workflows/tasks.py b/libraries/cloudharness-common/cloudharness/workflows/tasks.py index c88ccc215..550ef8489 100644 --- a/libraries/cloudharness-common/cloudharness/workflows/tasks.py +++ b/libraries/cloudharness-common/cloudharness/workflows/tasks.py @@ -11,7 +11,7 @@ class Task(argo.ArgoObject): Abstract interface for a task. """ - def __init__(self, name, resources={}, volume_mounts=[], **env_args): + def __init__(self, name, resources={}, volume_mounts=[], **env_args): self.name = name.replace(' ', '-').lower() self.resources = resources self.__envs = get_cloudharness_variables() @@ -33,7 +33,7 @@ def affinity_spec(self): return affinity_spec(([PodExecutionContext('usesvolume', self.external_volumes[0], True)] if self.external_volumes else []) + [ PodExecutionContext(f'usesvolume-{v}', 'true', True) for v in self.external_volumes - ] ) + ]) @property def image_name(self): diff --git a/libraries/cloudharness-common/cloudharness/workflows/utils.py b/libraries/cloudharness-common/cloudharness/workflows/utils.py index 2ad94fd2b..f65d65917 100644 --- a/libraries/cloudharness-common/cloudharness/workflows/utils.py +++ b/libraries/cloudharness-common/cloudharness/workflows/utils.py @@ -8,6 +8,7 @@ SHARED_DIRECTORY_VARIABLE_NAME = "shared_directory" + class PodExecutionContext: """ Key-value pair representing the execution context with other pods. @@ -19,15 +20,18 @@ def __init__(self, key, value, required=False): self.value = str(value) self.required = required + def get_workflow_name(): """Get the workflow name from inside a workflow""" name = get_variable(WORKFLOW_NAME_VARIABLE_NAME) remove = name.split("-")[-1] return name[0:-len(remove) - 1] + def volume_requires_affinity(v): return ':' in v and 'rwx' not in v[-4:] + def get_shared_directory(): return os.getenv(SHARED_DIRECTORY_VARIABLE_NAME) diff --git a/libraries/cloudharness-common/tests/test_applications.py b/libraries/cloudharness-common/tests/test_applications.py index 73da5bfe9..b1df3d198 100644 --- a/libraries/cloudharness-common/tests/test_applications.py +++ b/libraries/cloudharness-common/tests/test_applications.py @@ -1,15 +1,13 @@ +from cloudharness.utils.config import CloudharnessConfig, ConfigObject +from cloudharness.applications import ApplicationConfiguration, get_configuration from .test_env import set_default_environment set_default_environment() -from cloudharness.applications import ApplicationConfiguration, get_configuration -from cloudharness.utils.config import CloudharnessConfig, ConfigObject - - conf_1 = { 'name': 'app1', - + 'harness': { 'name': 'app1', 'subdomain': 'myapp', @@ -72,6 +70,7 @@ def test_application_conf(): assert uut.conf.admin.role == 'administrator' assert uut.conf["admin.role"] == 'administrator' + def test_get_configuration(): CloudharnessConfig.apps = { 'a': conf_1, @@ -89,8 +88,7 @@ def test_get_configuration(): assert uut["freefield"]["a"] == 1 assert uut["freefield"].a == 1 assert uut["freefield.a"] == 1 - - + assert uut.freefield.a == 1 uut = get_configuration('app2') @@ -100,9 +98,6 @@ def test_get_configuration(): assert not uut.is_auto_deployment() assert uut.is_sentry_enabled() - - - # TODO subapp support # uut = get_configuration('app2sub') diff --git a/libraries/cloudharness-common/tests/test_env.py b/libraries/cloudharness-common/tests/test_env.py index b4f2638c4..6956b6663 100644 --- a/libraries/cloudharness-common/tests/test_env.py +++ b/libraries/cloudharness-common/tests/test_env.py @@ -1,3 +1,5 @@ +from cloudharness.utils.config import CloudharnessConfig as conf +from cloudharness.utils.env import set_default_environment import pytest import os import yaml @@ -5,11 +7,9 @@ HERE = os.path.dirname(os.path.realpath(__file__)) os.environ["CH_VALUES_PATH"] = os.path.join(HERE, "values.yaml") -from cloudharness.utils.env import set_default_environment -from cloudharness.utils.config import CloudharnessConfig as conf def set_test_environment(): - + values_file = os.environ["CH_VALUES_PATH"] if not os.path.exists(values_file): @@ -21,5 +21,3 @@ def set_test_environment(): pprint(values) conf.get_configuration().update(values) set_default_environment() - - diff --git a/libraries/cloudharness-common/tests/test_infrastructure.py b/libraries/cloudharness-common/tests/test_infrastructure.py index c9395467b..ab060d8e8 100644 --- a/libraries/cloudharness-common/tests/test_infrastructure.py +++ b/libraries/cloudharness-common/tests/test_infrastructure.py @@ -1,8 +1,8 @@ +from cloudharness.infrastructure import k8s from .test_env import set_test_environment set_test_environment() -from cloudharness.infrastructure import k8s kubectl_enabled = False diff --git a/libraries/cloudharness-common/tests/test_middleware.py b/libraries/cloudharness-common/tests/test_middleware.py index 053a13378..bd438fae5 100644 --- a/libraries/cloudharness-common/tests/test_middleware.py +++ b/libraries/cloudharness-common/tests/test_middleware.py @@ -11,6 +11,7 @@ def new_init(self): pass + def new_decode_token(token): # if everything went fine then the token contains the value of sub # let's return it @@ -18,10 +19,12 @@ def new_decode_token(token): 'sub': token } + def test_setting_and_getting_auth_token(): set_authentication_token(TEST_AUTHENTICATION_TOKEN) assert get_authentication_token() == TEST_AUTHENTICATION_TOKEN + def test_decoding(): mocker = AuthClient mocker.decode_token = new_decode_token diff --git a/libraries/cloudharness-common/tests/test_quota.py b/libraries/cloudharness-common/tests/test_quota.py index 707ea8a6e..4c886bd76 100644 --- a/libraries/cloudharness-common/tests/test_quota.py +++ b/libraries/cloudharness-common/tests/test_quota.py @@ -1,28 +1,31 @@ +from cloudharness.auth.quota import get_user_quotas +from cloudharness.applications import get_configuration +from cloudharness import set_debug from .test_env import set_test_environment set_test_environment() -from cloudharness import set_debug -from cloudharness.applications import get_configuration -from cloudharness.auth.quota import get_user_quotas set_debug() jh_config = get_configuration("jupyterhub") assert jh_config is not None + def test_get_quotas(mocker): def mock_get_admin_client(self): return None + def mock_get_current_user(self): - return {"id":"123"} + return {"id": "123"} + def mock_get_user(self, user_id, with_details): return { "attributes": { "quota-ws-guaranteemem": [0.5] }, "userGroups": [ - {"path": "/Base", "attributes": {'quota-ws-maxmem': [2.5], 'quota-ws-maxcpu': [1], 'quota-ws-open': [3], "quota-ws-guaranteemem": [0.1]} }, + {"path": "/Base", "attributes": {'quota-ws-maxmem': [2.5], 'quota-ws-maxcpu': [1], 'quota-ws-open': [3], "quota-ws-guaranteemem": [0.1]}}, {"path": "/Base/Base 1/Base 1 1", "attributes": {'quota-ws-maxcpu': [2], 'quota-ws-open': [10]}}, {"path": "/Base/Base 2", "attributes": {'quota-ws-maxmem': [8], 'quota-ws-maxcpu': [0.25], 'quota-ws-guaranteecpu': [0.25]}}, {"path": "/Low CU", "attributes": {'quota-ws-maxmem': [3], 'quota-ws-maxcpu': [2.5], 'quota-ws-open': [1]}} @@ -32,7 +35,7 @@ def mock_get_user(self, user_id, with_details): mocker.patch('cloudharness.auth.keycloak.AuthClient.get_current_user', mock_get_current_user) mocker.patch('cloudharness.auth.keycloak.AuthClient.get_user', mock_get_user) user_quotas_jh = get_user_quotas(jh_config, user_id=None) - + assert user_quotas_jh.get("quota-ws-maxmem") == 8.0 assert user_quotas_jh.get("quota-ws-maxcpu") == 2.5 assert user_quotas_jh.get("quota-ws-open") == 10.0 diff --git a/libraries/cloudharness-common/tests/test_workflow.py b/libraries/cloudharness-common/tests/test_workflow.py index 18a2c6d15..c66dbbd03 100644 --- a/libraries/cloudharness-common/tests/test_workflow.py +++ b/libraries/cloudharness-common/tests/test_workflow.py @@ -1,4 +1,8 @@ """Notice, this test needs a fully operating kubernetes with argo environment in the container running the test""" +from cloudharness.utils.config import CloudharnessConfig +from cloudharness.workflows import argo +from cloudharness import set_debug +from cloudharness.workflows import operations, tasks, utils import requests import yaml @@ -7,10 +11,6 @@ set_test_environment() -from cloudharness.workflows import operations, tasks, utils -from cloudharness import set_debug -from cloudharness.workflows import argo -from cloudharness.utils.config import CloudharnessConfig set_debug() @@ -19,17 +19,20 @@ assert 'registry' in CloudharnessConfig.get_configuration() + def check_wf(wf): - + assert wf["kind"] == "Workflow" assert "spec" in wf + def test_volume_affinity_check(): assert not utils.volume_requires_affinity("a") assert utils.volume_requires_affinity("a:b") assert utils.volume_requires_affinity("a:b:ro") assert not utils.volume_requires_affinity("a:b:rwx") + def test_sync_workflow(): def f(): import time @@ -41,8 +44,7 @@ def f(): op = operations.DistributedSyncOperation('test-sync-op-', task) # print('\n', yaml.dump(op.to_workflow())) wf = op.to_workflow() - - + if execute: print(op.execute()) @@ -120,7 +122,7 @@ def test_single_task_shared(): accounts_offset = 1 if is_accounts_present() else 0 assert len(op.volumes) == 1 assert len(wf['spec']['volumes']) == 2 + accounts_offset - assert wf['spec']['volumes'][1+accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' + assert wf['spec']['volumes'][1 + accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' if accounts_offset == 1: assert wf['spec']['volumes'][1]['secret']['secretName'] == 'accounts' assert len(wf['spec']['templates'][0]['container']['volumeMounts']) == 2 + accounts_offset @@ -135,19 +137,20 @@ def test_single_task_shared(): if execute: print(op.execute()) + def test_pipeline_shared(): shared_directory = 'myclaim:/mnt/shared' task_write = operations.CustomTask('download-file', 'workflows-extract-download', url='https://raw.githubusercontent.com/openworm/org.geppetto/master/README.md') task_script = tasks.BashTask('print-file', source="ls -la") op = operations.PipelineOperation('test-custom-connected-op-', [task_write, task_script], - shared_directory=shared_directory, shared_volume_size=100) + shared_directory=shared_directory, shared_volume_size=100) wf = op.to_workflow() accounts_offset = 1 if is_accounts_present() else 0 assert len(op.volumes) == 1 assert len(wf['spec']['volumes']) == 2 + accounts_offset - assert wf['spec']['volumes'][1+accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' + assert wf['spec']['volumes'][1 + accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' if accounts_offset == 1: assert wf['spec']['volumes'][1]['secret']['secretName'] == 'accounts' assert len(wf['spec']['templates'][1]['container']['volumeMounts']) == 2 + accounts_offset @@ -160,7 +163,8 @@ def test_pipeline_shared(): assert affinity_glob['values'][0] == 'myclaim' if execute: - print(op.execute()) + print(op.execute()) + def test_single_task_shared_rwx(): shared_directory = 'myclaim:/mnt/shared:rwx' @@ -174,16 +178,14 @@ def test_single_task_shared_rwx(): accounts_offset = 1 if is_accounts_present() else 0 assert len(op.volumes) == 1 assert len(wf['spec']['volumes']) == 2 + accounts_offset - assert wf['spec']['volumes'][1+accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' + assert wf['spec']['volumes'][1 + accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' if accounts_offset == 1: assert wf['spec']['volumes'][1]['secret']['secretName'] == 'accounts' assert len(wf['spec']['templates'][0]['container']['volumeMounts']) == 2 + accounts_offset - - - assert not 'affinity' in wf['spec'], "Pod affinity should not be added for rwx volumes" + def test_single_task_volume_notshared(): task_write = operations.CustomTask('download-file', 'workflows-extract-download', volume_mounts=["a:b"], @@ -194,12 +196,11 @@ def test_single_task_volume_notshared(): accounts_offset = 1 if is_accounts_present() else 0 assert len(op.volumes) == 0 assert len(wf['spec']['volumes']) == 2 + accounts_offset - assert wf['spec']['volumes'][1+accounts_offset]['persistentVolumeClaim']['claimName'] == 'a' + assert wf['spec']['volumes'][1 + accounts_offset]['persistentVolumeClaim']['claimName'] == 'a' if accounts_offset == 1: assert wf['spec']['volumes'][1]['secret']['secretName'] == 'accounts' assert len(wf['spec']['templates'][0]['container']['volumeMounts']) == 2 + accounts_offset - assert 'affinity' not in wf['spec'] affinity_tpl = \ @@ -211,6 +212,7 @@ def test_single_task_volume_notshared(): if execute: print(op.execute()) + def test_single_task_volumes_notshared(): shared_directory = 'myclaim:/mnt/shared' task_write = operations.CustomTask('download-file', 'workflows-extract-download', volume_mounts=["a:b"], @@ -221,7 +223,7 @@ def test_single_task_volumes_notshared(): accounts_offset = 1 if is_accounts_present() else 0 assert len(op.volumes) == 1 assert len(wf['spec']['volumes']) == 3 + accounts_offset - assert wf['spec']['volumes'][1+accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' + assert wf['spec']['volumes'][1 + accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' if accounts_offset == 1: assert wf['spec']['volumes'][1]['secret']['secretName'] == 'accounts' assert len(wf['spec']['templates'][0]['container']['volumeMounts']) == 3 + accounts_offset @@ -241,6 +243,7 @@ def test_single_task_volumes_notshared(): if execute: print(op.execute()) + def test_single_task_shared_multiple(): shared_directory = ['myclaim:/mnt/shared', 'myclaim2:/mnt/shared2:ro'] task_write = operations.CustomTask('download-file', 'workflows-extract-download', @@ -253,16 +256,16 @@ def test_single_task_shared_multiple(): assert len(op.volumes) == 2 assert len(wf['spec']['volumes']) == 3 + accounts_offset - assert wf['spec']['volumes'][1+accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' + assert wf['spec']['volumes'][1 + accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' assert len(wf['spec']['templates'][0]['container']['volumeMounts']) == 3 + accounts_offset - assert wf['spec']['templates'][0]['container']['volumeMounts'][2+accounts_offset]['readonly'] + assert wf['spec']['templates'][0]['container']['volumeMounts'][2 + accounts_offset]['readonly'] assert wf['spec']['templates'][0]['metadata']['labels']['usesvolume'] assert 'affinity' in wf['spec'] assert len(wf['spec']['affinity']['podAffinity'][ - 'requiredDuringSchedulingIgnoredDuringExecution']) == 2, "A pod affinity for each volume is expected" + 'requiredDuringSchedulingIgnoredDuringExecution']) == 2, "A pod affinity for each volume is expected" affinity_expr = \ wf['spec']['affinity']['podAffinity']['requiredDuringSchedulingIgnoredDuringExecution'][0]['labelSelector'][ 'matchExpressions'][0] @@ -272,7 +275,6 @@ def test_single_task_shared_multiple(): print(op.execute()) - def test_single_task_shared_script(): shared_directory = 'myclaim:/mnt/shared' task_write = tasks.BashTask('download-file', source="ls -la") @@ -283,12 +285,9 @@ def test_single_task_shared_script(): accounts_offset = 1 if is_accounts_present() else 0 assert len(op.volumes) == 1 - assert len(wf['spec']['volumes']) == 2+accounts_offset - assert wf['spec']['volumes'][1+accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' - assert len(wf['spec']['templates'][0]['script']['volumeMounts']) == 2+accounts_offset - - - + assert len(wf['spec']['volumes']) == 2 + accounts_offset + assert wf['spec']['volumes'][1 + accounts_offset]['persistentVolumeClaim']['claimName'] == 'myclaim' + assert len(wf['spec']['templates'][0]['script']['volumeMounts']) == 2 + accounts_offset def test_result_task_workflow(): @@ -385,7 +384,7 @@ def f(): operations.PodExecutionContext('a', 'b'), operations.PodExecutionContext('c', 'd', required=True), operations.PodExecutionContext('e', 'f') - )) + )) workflow = op.to_workflow() assert 'affinity' in workflow['spec'] preferred = workflow['spec']['affinity']['podAffinity']['preferredDuringSchedulingIgnoredDuringExecution'] @@ -417,7 +416,6 @@ def f(): def test_gpu_workflow(): - from cloudharness.workflows import operations, tasks my_task = tasks.CustomTask('my-gpu', 'myapp-mytask', resources={"limits": {"nvidia.com/gpu": 1}}) @@ -426,4 +424,4 @@ def test_gpu_workflow(): if verbose: print('\n', yaml.dump(wf)) - assert "nvidia.com/gpu" in wf['spec']['templates'][1]["container"]["resources"]["limits"] \ No newline at end of file + assert "nvidia.com/gpu" in wf['spec']['templates'][1]["container"]["resources"]["limits"] diff --git a/libraries/cloudharness-utils/cloudharness_utils/constants.py b/libraries/cloudharness-utils/cloudharness_utils/constants.py index 53282691f..ced46d232 100644 --- a/libraries/cloudharness-utils/cloudharness_utils/constants.py +++ b/libraries/cloudharness-utils/cloudharness_utils/constants.py @@ -44,4 +44,4 @@ E2E_TESTS_DIRNAME = 'e2e' API_TESTS_DIRNAME = 'api' -E2E_TESTS_PROJECT_PATH = "test/test-e2e" \ No newline at end of file +E2E_TESTS_PROJECT_PATH = "test/test-e2e" diff --git a/libraries/cloudharness-utils/cloudharness_utils/testing/api.py b/libraries/cloudharness-utils/cloudharness_utils/testing/api.py index d71719139..57032519e 100644 --- a/libraries/cloudharness-utils/cloudharness_utils/testing/api.py +++ b/libraries/cloudharness-utils/cloudharness_utils/testing/api.py @@ -12,7 +12,7 @@ def get_api_filename(app_dir): def get_schemathesis_command(api_filename, app_config: ApplicationHarnessConfig, app_domain: str): - return ["st", "--pre-run", "cloudharness_test.apitest_init", "run", api_filename, *get_schemathesis_params(app_config, app_domain)] + return ["st", "--pre-run", "cloudharness_test.apitest_init", "run", api_filename, *get_schemathesis_params(app_config, app_domain)] def get_schemathesis_params(app_config: ApplicationHarnessConfig, app_domain: str): diff --git a/libraries/cloudharness-utils/cloudharness_utils/testing/util.py b/libraries/cloudharness-utils/cloudharness_utils/testing/util.py index da758d871..528f611d6 100644 --- a/libraries/cloudharness-utils/cloudharness_utils/testing/util.py +++ b/libraries/cloudharness-utils/cloudharness_utils/testing/util.py @@ -4,13 +4,14 @@ from cloudharness_model.models import ApplicationUser, ApplicationTestConfig, ApplicationHarnessConfig, E2ETestsConfig + def get_user_password(main_user: ApplicationUser): return main_user.password or "test" + def get_app_environment(app_config: ApplicationHarnessConfig, app_domain, use_local_env=True): my_env = os.environ.copy() if use_local_env else {} my_env["APP_URL"] = app_domain - if app_config.accounts and app_config.accounts.users: main_user: ApplicationUser = app_config.accounts.users[0] @@ -25,4 +26,4 @@ def get_app_environment(app_config: ApplicationHarnessConfig, app_domain, use_lo my_env["IGNORE_CONSOLE_ERRORS"] = "true" if e2e_config.ignoreRequestErrors: my_env["IGNORE_REQUEST_ERRORS"] = "true" - return my_env \ No newline at end of file + return my_env diff --git a/lint.sh b/lint.sh new file mode 100644 index 000000000..3f4557023 --- /dev/null +++ b/lint.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Run autopep8 with --diff and capture the output +diff_output=$(autopep8 --select=E1,E2,E3,W,E4,E7,E502 --recursive --diff\ + --exclude '**/cloudharness_cli/**/*'\ + --exclude '**/models/*'\ + --exclude '**/model/*'\ + .) +# Check if the output is non-empty +if [ -n "$diff_output" ]; then + echo $diff_output + echo "Code style issues found in the above files. Please run autopep8 to fix them." + exit 1 +fi \ No newline at end of file diff --git a/tools/cloudharness-test/cloudharness_test/api.py b/tools/cloudharness-test/cloudharness_test/api.py index 5193902d4..216a669c2 100644 --- a/tools/cloudharness-test/cloudharness_test/api.py +++ b/tools/cloudharness-test/cloudharness_test/api.py @@ -6,7 +6,7 @@ from ch_cli_tools.preprocessing import get_build_paths -from cloudharness_model.models import HarnessMainConfig, ApiTestsConfig, ApplicationHarnessConfig +from cloudharness_model.models import HarnessMainConfig, ApiTestsConfig, ApplicationHarnessConfig from cloudharness_utils.testing.util import get_app_environment from cloudharness_utils.testing.api import get_api_filename, get_urls_from_api_file, get_schemathesis_command @@ -90,4 +90,3 @@ def run_api_tests(root_paths, helm_values: HarnessMainConfig, base_domain, inclu logging.error( "Some api test failed. Check output for more information.") exit(1) - diff --git a/tools/cloudharness-test/cloudharness_test/e2e.py b/tools/cloudharness-test/cloudharness_test/e2e.py index 388ed36dc..d164d9151 100644 --- a/tools/cloudharness-test/cloudharness_test/e2e.py +++ b/tools/cloudharness-test/cloudharness_test/e2e.py @@ -6,7 +6,7 @@ from cloudharness_model.models import ApplicationHarnessConfig -from cloudharness_utils.constants import E2E_TESTS_PROJECT_PATH, E2E_TESTS_DIRNAME +from cloudharness_utils.constants import E2E_TESTS_PROJECT_PATH, E2E_TESTS_DIRNAME from ch_cli_tools.preprocessing import get_build_paths from cloudharness_utils.testing.util import get_app_environment @@ -16,6 +16,7 @@ E2E_TESTS_PROJECT_ROOT = os.path.abspath(E2E_TESTS_PROJECT_PATH) if os.path.exists( E2E_TESTS_PROJECT_PATH) else os.path.join(ROOT, E2E_TESTS_PROJECT_PATH) + def run_e2e_tests(root_paths, helm_values, base_domain, included_applications=[], headless=False): if which("npm") is None: @@ -24,55 +25,53 @@ def run_e2e_tests(root_paths, helm_values, base_domain, included_applications=[] node_modules_path = os.path.join(E2E_TESTS_PROJECT_ROOT, "node_modules") if not os.path.exists(node_modules_path): - logging.info("Installing Jest-Puppeteer base project") - subprocess.run(["npm", "install"], cwd=E2E_TESTS_PROJECT_ROOT) + logging.info("Installing Jest-Puppeteer base project") + subprocess.run(["npm", "install"], cwd=E2E_TESTS_PROJECT_ROOT) artifacts = get_build_paths( - helm_values=helm_values, root_paths=root_paths) + helm_values=helm_values, root_paths=root_paths) failed = False for appkey in helm_values.apps: app_config: ApplicationHarnessConfig = helm_values.apps[appkey].harness appname = app_config.name - + if included_applications and appname not in included_applications: continue if not app_config.test.e2e.enabled: continue tests_dir = os.path.join( - artifacts[appkey.replace("_", "-")], "test", E2E_TESTS_DIRNAME) - + artifacts[appkey.replace("_", "-")], "test", E2E_TESTS_DIRNAME) + if not app_config.domain and not app_config.subdomain: logging.warn( - "Application %s has a test folder but no subdomain/domain is specified", appname) + "Application %s has a test folder but no subdomain/domain is specified", appname) continue app_domain = f"http{'s' if helm_values.tls else ''}://" + \ - (app_config.domain or f"{app_config.subdomain}.{base_domain}") - - - + (app_config.domain or f"{app_config.subdomain}.{base_domain}") + env = get_app_environment(app_config, app_domain) if not headless and os.environ.get('DISPLAY'): env["PUPPETEER_DISPLAY"] = "display" if os.path.exists(tests_dir): - + app_node_modules_path = os.path.join(tests_dir, "node_modules") if not os.path.exists(app_node_modules_path): logging.info("Linking tests libraries to %s", - app_node_modules_path) + app_node_modules_path) os.symlink(node_modules_path, app_node_modules_path) env["APP"] = artifacts[appkey.replace("_", "-")] logging.info( - "Running tests for application %s on domain %s", appname, app_domain) + "Running tests for application %s on domain %s", appname, app_domain) result = subprocess.run(["npm", "run", "test:app"], - cwd=E2E_TESTS_PROJECT_ROOT, env=env) + cwd=E2E_TESTS_PROJECT_ROOT, env=env) if result.returncode > 0: failed = True if failed: logging.error("Some end to end test failed. Check output for more information.") - exit(1) \ No newline at end of file + exit(1) diff --git a/tools/cloudharness-test/cloudharness_test/utils.py b/tools/cloudharness-test/cloudharness_test/utils.py index d00464563..e8a4aa21a 100644 --- a/tools/cloudharness-test/cloudharness_test/utils.py +++ b/tools/cloudharness-test/cloudharness_test/utils.py @@ -1,5 +1,6 @@ import requests + def url_check(url): try: # Get Url @@ -11,4 +12,4 @@ def url_check(url): except requests.exceptions.RequestException as e: # print URL with Errs - return False \ No newline at end of file + return False diff --git a/tools/cloudharness-test/harness-test b/tools/cloudharness-test/harness-test index 43c2d5016..fa69ddf88 100644 --- a/tools/cloudharness-test/harness-test +++ b/tools/cloudharness-test/harness-test @@ -41,7 +41,7 @@ if __name__ == "__main__": help=f'Run only end to end tests (default: run both api and end to end tests') parser.add_argument('-a', '--api', dest='run_api', action="store_const", default=None, const=True, help=f'Run only end to end tests (default: run both api and end to end tests') - + parser.add_argument('-hl', '--headless', dest='headless', action="store_true", default=False, help=f'Run headless end to end tests') args, unknown = parser.parse_known_args(sys.argv[1:]) @@ -61,24 +61,22 @@ if __name__ == "__main__": with open(helm_values_path) as f: helm_values_raw = yaml.load(f) - - if args.domain: - helm_values_raw["domain"] = args.domain + helm_values_raw["domain"] = args.domain with open(helm_values_path, 'w') as f: yaml.dump(helm_values_raw, f) helm_values = HarnessMainConfig.from_dict(helm_values_raw) base_domain = args.domain or helm_values.domain - + logging.info("Base domain is %s", base_domain) from cloudharness.utils.config import CloudharnessConfig CloudharnessConfig.allvalues["domain"] = base_domain if not url_check(f"http{'s' if helm_values.tls else ''}://{base_domain}"): logging.error( "Base domain unreachable. Is your deployment up and running? If yes, check your DNS/hosts settings.") - + included_applications = args.include if args.run_api == True or args.run_e2e is None: run_api_tests(root_paths, helm_values, base_domain, included_applications) diff --git a/tools/cloudharness-test/setup.py b/tools/cloudharness-test/setup.py index acb76ab4e..5f07dfd6a 100644 --- a/tools/cloudharness-test/setup.py +++ b/tools/cloudharness-test/setup.py @@ -28,7 +28,6 @@ ] - setup( name=NAME, version=VERSION, diff --git a/tools/deployment-cli-tools/ch_cli_tools/__init__.py b/tools/deployment-cli-tools/ch_cli_tools/__init__.py index 3df254d48..cca88e9b6 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/__init__.py +++ b/tools/deployment-cli-tools/ch_cli_tools/__init__.py @@ -12,4 +12,4 @@ HERE = os.path.dirname(os.path.realpath(__file__)) -CH_ROOT = os.getenv("CH_ROOT") or dn(dn(dn(dn(os.path.realpath(__file__))))).replace(os.path.sep, '/') \ No newline at end of file +CH_ROOT = os.getenv("CH_ROOT") or dn(dn(dn(dn(os.path.realpath(__file__))))).replace(os.path.sep, '/') diff --git a/tools/deployment-cli-tools/ch_cli_tools/codefresh.py b/tools/deployment-cli-tools/ch_cli_tools/codefresh.py index 3fc5e833a..5bf5c1a2e 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/codefresh.py +++ b/tools/deployment-cli-tools/ch_cli_tools/codefresh.py @@ -34,6 +34,7 @@ def literal_presenter(dumper, data): yaml.add_representer(str, literal_presenter) + def get_main_domain(url): try: url = url.split("//")[1].split("/")[0] @@ -45,6 +46,7 @@ def get_main_domain(url): except: return "${{ DEFAULT_REPO }}" + def clone_step_spec(conf: GitDependencyConfig, context_path: str): return { "title": f"Cloning {os.path.basename(conf.url)} repository...", @@ -52,9 +54,10 @@ def clone_step_spec(conf: GitDependencyConfig, context_path: str): "repo": conf.url, "revision": conf.branch_tag, "working_directory": join(context_path, "dependencies", conf.path or ""), - "git": get_main_domain(conf.url) # Cannot really tell what's the git config name, usually the name of the repo + "git": get_main_domain(conf.url) # Cannot really tell what's the git config name, usually the name of the repo } + def write_env_file(helm_values: HarnessMainConfig, filename, registry_secret=None): env = {} logging.info("Create env file with image info %s", filename) @@ -74,8 +77,6 @@ def check_image_exists(name, image): else: env[app_specific_tag_variable(name) + "_NEW"] = 1 - - for app in helm_values.apps.values(): if app.harness and app.harness.deployment.image: env[app_specific_tag_variable(app.name)] = extract_tag(app.harness.deployment.image) @@ -95,8 +96,6 @@ def check_image_exists(name, image): f.write(f"{k}={v}\n") - - def create_codefresh_deployment_scripts(root_paths, envs=(), include=(), exclude=(), template_name=CF_TEMPLATE_PATH, base_image_name=None, helm_values: HarnessMainConfig = None, save=True): @@ -128,7 +127,7 @@ def create_codefresh_deployment_scripts(root_paths, envs=(), include=(), exclude for root_path in root_paths: for e in envs: - + template_name = f"codefresh-template-{e}.yaml" template_path = join( root_path, DEPLOYMENT_CONFIGURATION_PATH, template_name) @@ -144,7 +143,7 @@ def create_codefresh_deployment_scripts(root_paths, envs=(), include=(), exclude steps = codefresh['steps'] def get_app_domain(app_config: ApplicationHarnessConfig): - base_domain=[c for c in codefresh['steps']['prepare_deployment']['commands'] if 'harness-deployment' in c][0].split("-d ")[1].split(" ")[0] + base_domain = [c for c in codefresh['steps']['prepare_deployment']['commands'] if 'harness-deployment' in c][0].split("-d ")[1].split(" ")[0] return f"https://{app_config.subdomain}.{base_domain}" def e2e_test_environment(app_config: ApplicationHarnessConfig, app_domain: str = None): @@ -245,7 +244,6 @@ def codefresh_steps_from_base_path(base_path, build_step, fixed_context=None, in clean_path(dockerfile_relative_to_root), app_name), environment=e2e_test_environment(app_config) ) - def add_unit_test_step(app_config: ApplicationHarnessConfig): # Create a run step for each application with tests/unit.yaml file using the corresponding image built at the previous step @@ -265,7 +263,7 @@ def add_unit_test_step(app_config: ApplicationHarnessConfig): codefresh_steps_from_base_path(join(root_path, BASE_IMAGES_PATH), CD_BUILD_STEP_BASE, fixed_context=relpath(root_path, os.getcwd()), include=helm_values[KEY_TASK_IMAGES].keys()) codefresh_steps_from_base_path(join(root_path, STATIC_IMAGES_PATH), CD_BUILD_STEP_STATIC, - include=helm_values[KEY_TASK_IMAGES].keys()) + include=helm_values[KEY_TASK_IMAGES].keys()) codefresh_steps_from_base_path(join( root_path, APPS_PATH), CD_BUILD_STEP_PARALLEL) @@ -281,7 +279,7 @@ def add_unit_test_step(app_config: ApplicationHarnessConfig): codefresh_steps_from_base_path(join( root_path, TEST_IMAGES_PATH), CD_BUILD_STEP_TEST, include=(name,), fixed_context=relpath(root_path, os.getcwd()), publish=False) steps[CD_API_TEST_STEP]["image"] = image_tag_with_variables(name, app_specific_tag_variable(name), base_name=base_image_name) - + if not codefresh: logging.warning( "No template file found. Codefresh script not created.") @@ -402,9 +400,10 @@ def codefresh_app_publish_spec(app_name, build_tag, base_name=None): step_spec['tags'].append('latest') return step_spec + def image_tag_with_variables(app_name, build_tag, base_name=""): return "${{REGISTRY}}/%s:${{%s}}" % (get_image_name( - app_name, base_name), build_tag or '${{DEPLOYMENT_TAG}}') + app_name, base_name), build_tag or '${{DEPLOYMENT_TAG}}') def app_specific_tag_variable(app_name): @@ -421,7 +420,7 @@ def codefresh_app_build_spec(app_name, app_context_path, dockerfile_path="Docker title=title, working_directory='./' + app_context_path, dockerfile=dockerfile_path) - + tag = app_specific_tag_variable(app_name) build["tag"] = "${{%s}}" % tag @@ -451,11 +450,12 @@ def add_arg_dependencies(dependencies): helm_values.apps[values_key].harness.dependencies.build) except (KeyError, AttributeError): add_arg_dependencies(helm_values['task-images']) - + when_condition = existing_build_when_condition(tag) build["when"] = when_condition return build + def existing_build_when_condition(tag): """ See https://codefresh.io/docs/docs/pipelines/conditional-execution-of-steps/#execute-steps-according-to-the-presence-of-a-variable @@ -472,5 +472,5 @@ def existing_build_when_condition(tag): } } } - + return when_condition diff --git a/tools/deployment-cli-tools/ch_cli_tools/helm.py b/tools/deployment-cli-tools/ch_cli_tools/helm.py index 2552dcbe2..80d6f08eb 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/helm.py +++ b/tools/deployment-cli-tools/ch_cli_tools/helm.py @@ -212,7 +212,7 @@ def __init_base_images(self, base_image_name): self.static_images.update(find_dockerfiles_paths( os.path.join(root_path, STATIC_IMAGES_PATH))) return self.base_images - + def __init_test_images(self, base_image_name): test_images = {} for root_path in self.root_paths: @@ -224,7 +224,6 @@ def __init_test_images(self, base_image_name): return test_images - def __find_static_dockerfile_paths(self, root_path): return find_dockerfiles_paths(os.path.join(root_path, BASE_IMAGES_PATH)) + find_dockerfiles_paths(os.path.join(root_path, STATIC_IMAGES_PATH)) @@ -324,7 +323,6 @@ def __finish_helm_values(self, values): if self.registry: logging.info(f"Registry set: {self.registry}") - if self.local: values['registry']['secret'] = '' if self.registry_secret: @@ -415,19 +413,19 @@ def image_tag(self, image_name, build_context_path=None, dependencies=()): tag = generate_tag_from_content(build_context_path, ignore) logging.info(f"Content hash: {tag}") dependencies = dependencies or guess_build_dependencies_from_dockerfile(build_context_path) - tag = sha1((tag + "".join(self.all_images.get(n , '') for n in dependencies)).encode("utf-8")).hexdigest() + tag = sha1((tag + "".join(self.all_images.get(n, '') for n in dependencies)).encode("utf-8")).hexdigest() logging.info(f"Generated tag: {tag}") - app_name = image_name.split("/")[-1] # the image name can have a prefix + app_name = image_name.split("/")[-1] # the image name can have a prefix self.all_images[app_name] = tag return self.registry + image_name + (f':{tag}' if tag else '') - + def create_app_values_spec(self, app_name, app_path, base_image_name=None): logging.info('Generating values script for ' + app_name) specific_template_path = os.path.join(app_path, 'deploy', 'values.yaml') if os.path.exists(specific_template_path): logging.info("Specific values template found: " + - specific_template_path) + specific_template_path) values = get_template(specific_template_path) else: values = {} @@ -459,7 +457,7 @@ def create_app_values_spec(self, app_name, app_path, base_image_name=None): if len(image_paths) > 0: image_name = image_name_from_dockerfile_path(os.path.relpath( image_paths[0], os.path.dirname(app_path)), base_image_name) - + values['image'] = self.image_tag( image_name, build_context_path=app_path, dependencies=build_dependencies) elif KEY_HARNESS in values and not values[KEY_HARNESS].get(KEY_DEPLOYMENT, {}).get('image', None) and values[ diff --git a/tools/deployment-cli-tools/ch_cli_tools/models.py b/tools/deployment-cli-tools/ch_cli_tools/models.py index 83e950b37..a9719b604 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/models.py +++ b/tools/deployment-cli-tools/ch_cli_tools/models.py @@ -1 +1 @@ -from cloudharness_model import * \ No newline at end of file +from cloudharness_model import * diff --git a/tools/deployment-cli-tools/ch_cli_tools/preprocessing.py b/tools/deployment-cli-tools/ch_cli_tools/preprocessing.py index 8fc973131..f19fe9bfe 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/preprocessing.py +++ b/tools/deployment-cli-tools/ch_cli_tools/preprocessing.py @@ -8,8 +8,7 @@ from .helm import KEY_APPS, KEY_TASK_IMAGES from .utils import app_name_from_path, merge_app_directories, merge_configuration_directories, find_subdirs -from cloudharness_utils.constants import APPS_PATH,BASE_IMAGES_PATH, STATIC_IMAGES_PATH, DEFAULT_MERGE_PATH - +from cloudharness_utils.constants import APPS_PATH, BASE_IMAGES_PATH, STATIC_IMAGES_PATH, DEFAULT_MERGE_PATH def preprocess_build_overrides(root_paths, helm_values, merge_build_path=DEFAULT_MERGE_PATH): @@ -27,15 +26,12 @@ def preprocess_build_overrides(root_paths, helm_values, merge_build_path=DEFAULT def merge_appdir(root_path, base_path): app_name = app_name_from_path(basename(base_path)) dest_path = join( - merge_build_path, - relpath( base_path, root_path) - ) + merge_build_path, + relpath(base_path, root_path) + ) merge_configuration_directories(artifacts[app_name], dest_path) merge_configuration_directories(base_path, dest_path) - - - for root_path in root_paths: for base_path in find_subdirs(join(root_path, BASE_IMAGES_PATH)): @@ -70,18 +66,19 @@ def merge_appdir(root_path, base_path): elif app_name.replace("-", "_") in helm_values[KEY_APPS]: merge_appdir(root_path, base_path) merged = True - + if exists(merge_build_path): with open(join(merge_build_path, ".dockerignore"), "a") as dst: - + for root_path in root_paths: ignore_file = join(root_path, ".dockerignore") if os.path.exists(ignore_file): with open(ignore_file) as src: dst.write(src.read()) - + return (root_paths + [merge_build_path]) if merged else root_paths + def get_build_paths(root_paths, helm_values, merge_build_path=DEFAULT_MERGE_PATH): """ Gets the same paths from preprocess_build_overrides @@ -101,12 +98,12 @@ def get_build_paths(root_paths, helm_values, merge_build_path=DEFAULT_MERGE_PATH artifacts[app_name] = base_path else: artifacts[app_name] = join( - merge_build_path, - relpath( base_path, root_path) - ) + merge_build_path, + relpath(base_path, root_path) + ) for root_path in root_paths: for base_path in find_subdirs(join(root_path, STATIC_IMAGES_PATH)): - + app_name = app_name_from_path(basename(base_path)) if app_name not in helm_values[KEY_TASK_IMAGES]: continue @@ -114,9 +111,9 @@ def get_build_paths(root_paths, helm_values, merge_build_path=DEFAULT_MERGE_PATH artifacts[app_name] = base_path else: artifacts[app_name] = join( - merge_build_path, - relpath( base_path, root_path) - ) + merge_build_path, + relpath(base_path, root_path) + ) for root_path in root_paths: for base_path in find_subdirs(join(root_path, APPS_PATH)): @@ -127,8 +124,8 @@ def get_build_paths(root_paths, helm_values, merge_build_path=DEFAULT_MERGE_PATH artifacts[app_name] = base_path else: artifacts[app_name] = join( - merge_build_path, - relpath( base_path, root_path) - ) + merge_build_path, + relpath(base_path, root_path) + ) return artifacts diff --git a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py index e2fbf1c9b..ab39f491d 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/skaffold.py +++ b/tools/deployment-cli-tools/ch_cli_tools/skaffold.py @@ -14,11 +14,13 @@ from . import HERE + def relpath_if(p1, p2): if os.path.isabs(p1): return p1 return relpath(p1, p2) + def create_skaffold_configuration(root_paths, helm_values: HarnessMainConfig, output_path='.', manage_task_images=True): skaffold_conf = get_template('skaffold-template.yaml', True) apps = helm_values.apps @@ -64,7 +66,6 @@ def build_artifact( in requirements] return artifact_spec - base_images = set() def process_build_dockerfile( @@ -106,7 +107,6 @@ def process_build_dockerfile( for dockerfile_path in base_dockerfiles: process_build_dockerfile(dockerfile_path, root_path, global_context=True) - release_config = skaffold_conf['deploy']['helm']['releases'][0] release_config['name'] = helm_values.namespace release_config['namespace'] = helm_values.namespace @@ -120,7 +120,6 @@ def process_build_dockerfile( for dockerfile_path in static_dockerfiles: process_build_dockerfile(dockerfile_path, root_path) - for root_path in root_paths: apps_path = join(root_path, APPS_PATH) app_dockerfiles = find_dockerfiles_paths(apps_path) @@ -171,7 +170,7 @@ def identify_unicorn_based_main(candidates): import re gunicorn_pattern = re.compile(r"gunicorn") # sort candidates, shortest path first - for candidate in sorted(candidates,key=lambda x: len(x.split("/"))): + for candidate in sorted(candidates, key=lambda x: len(x.split("/"))): dockerfile_path = f"{candidate}/.." while not exists(f"{dockerfile_path}/Dockerfile") and abspath(dockerfile_path) != abspath(root_path): dockerfile_path += "/.." @@ -205,17 +204,17 @@ def identify_unicorn_based_main(candidates): test_config: ApplicationTestConfig = helm_values.apps[app_key].harness.test if test_config.unit.enabled and test_config.unit.commands: - skaffold_conf['test'].append(dict( - image=get_image_tag(app_name), - custom=[dict(command="docker run $IMAGE " + cmd) for cmd in test_config.unit.commands] - )) - + skaffold_conf['test'].append(dict( + image=get_image_tag(app_name), + custom=[dict(command="docker run $IMAGE " + cmd) for cmd in test_config.unit.commands] + )) skaffold_conf['build']['artifacts'] = [v for v in artifacts.values()] merge_to_yaml_file(skaffold_conf, os.path.join( output_path, 'skaffold.yaml')) return skaffold_conf + def git_clone_hook(conf: GitDependencyConfig, context_path: str): return { 'command': [ @@ -223,10 +222,11 @@ def git_clone_hook(conf: GitDependencyConfig, context_path: str): join(os.path.dirname(os.path.dirname(HERE)), 'clone.sh'), conf.branch_tag, conf.url, - join(context_path, "dependencies", conf.path or os.path.basename(conf.url).split('.')[0]) + join(context_path, "dependencies", conf.path or os.path.basename(conf.url).split('.')[0]) ] } + def create_vscode_debug_configuration(root_paths, helm_values): logging.info( "Creating VS code cloud build configuration.\nCloud build extension is needed to debug.") @@ -267,11 +267,10 @@ def get_image_tag(name): "sourceFileMap": { "justMyCode": False, f"${{workspaceFolder}}/{app_relative_to_root}": apps[app_key].harness.get('sourceRoot', - "/usr/src/app"), + "/usr/src/app"), } }) - if not os.path.exists(os.path.dirname(vscode_launch_path)): os.makedirs(os.path.dirname(vscode_launch_path)) with open(vscode_launch_path, 'w') as f: @@ -285,4 +284,4 @@ def get_additional_build_args(helm_values: HarnessMainConfig, app_key: str) -> d if not (helm_values.apps[app_key].harness.dockerfile and helm_values.apps[app_key].harness.dockerfile.buildArgs): return None - return helm_values.apps[app_key].harness.dockerfile.buildArgs \ No newline at end of file + return helm_values.apps[app_key].harness.dockerfile.buildArgs diff --git a/tools/deployment-cli-tools/ch_cli_tools/utils.py b/tools/deployment-cli-tools/ch_cli_tools/utils.py index 3ec8e6f38..cb167110f 100644 --- a/tools/deployment-cli-tools/ch_cli_tools/utils.py +++ b/tools/deployment-cli-tools/ch_cli_tools/utils.py @@ -145,9 +145,11 @@ def get_template(yaml_path, base_default=False): def file_is_yaml(fname): return fname[-4:] == 'yaml' or fname[-3:] == 'yml' + def file_is_json(fname): return fname[-4:] == 'json' + def replaceindir(root_src_dir, source, replace): """ Does copy and merge (shutil.copytree requires that the destination does not exist) @@ -290,11 +292,13 @@ def merge_yaml_files(fname, fdest): content_src = yaml.load(f) merge_to_yaml_file(content_src, fdest) + def merge_json_files(fname, fdest): with open(fname) as f: content_src = json.load(f) merge_to_json_file(content_src, fdest) + def merge_to_json_file(content_src, fdest): if not content_src: return @@ -313,6 +317,7 @@ def merge_to_json_file(content_src, fdest): json.dump(merged, f, indent=2) return merged + def merge_to_yaml_file(content_src, fdest): if not content_src: return @@ -364,8 +369,8 @@ def dict_merge(dct, merge_dct, add_keys=True): } for k, v in merge_dct.items(): - if (k in dct and isinstance(dct[k], dict) - and isinstance(merge_dct[k], collections.abc.Mapping)): + if (k in dct and isinstance(dct[k], dict) and + isinstance(merge_dct[k], collections.abc.Mapping)): dct[k] = dict_merge(dct[k], merge_dct[k], add_keys=add_keys) else: dct[k] = merge_dct[k] @@ -424,6 +429,7 @@ def check_docker_manifest_exists(registry, image_name, tag, registry_secret=None resp = requests.get(api_url) return resp.status_code == 200 + def get_git_commit_hash(path): # return the short git commit hash in that path # if the path is not a git repo, return None diff --git a/tools/deployment-cli-tools/harness-application b/tools/deployment-cli-tools/harness-application index 37bec8089..580352870 100644 --- a/tools/deployment-cli-tools/harness-application +++ b/tools/deployment-cli-tools/harness-application @@ -26,7 +26,7 @@ if __name__ == "__main__": description='Creates a new Application.') parser.add_argument('name', metavar='name', type=str, help='Application name') - parser.add_argument('-t', '--template', dest='templates', action="append", default=['base',], + parser.add_argument('-t', '--template', dest='templates', action="append", default=['base', ], help="""Add a template name. Available templates: @@ -65,13 +65,12 @@ if __name__ == "__main__": if 'webapp' in templates: if os.path.exists(os.path.join(app_path, 'frontend')): shutil.rmtree(os.path.join(app_path, 'frontend')) - cmd = ["yarn", "create", "vite", args.name, "--template", "react-ts"] + cmd = ["yarn", "create", "vite", args.name, "--template", "react-ts"] logging.info(f"Running command: {' '.join(cmd)}") subprocess.run(cmd, cwd=app_path) shutil.move(os.path.join(app_path, args.name), os.path.join(app_path, 'frontend')) generate_ts_client(openapi_file=os.path.join(app_path, 'api/openapi.yaml')) - if 'server' in templates: with tempfile.TemporaryDirectory() as tmp_dirname: copymergedir(os.path.join(CH_ROOT, APPLICATION_TEMPLATE_PATH, template_name), tmp_dirname) diff --git a/tools/deployment-cli-tools/harness-deployment b/tools/deployment-cli-tools/harness-deployment index a9cecabbf..2a0bdd0b2 100644 --- a/tools/deployment-cli-tools/harness-deployment +++ b/tools/deployment-cli-tools/harness-deployment @@ -60,8 +60,7 @@ if __name__ == "__main__": parser.add_argument('-N', '--no-cd', dest='no_cd_gen', action="store_const", default=None, const=True, help=f'Do not generate ci/cd files') parser.add_argument('-we', '--write-env', dest='write_env', action="store_const", default=None, const=True, - help=f'Write build env to .env file in {DEPLOYMENT_PATH}') - + help=f'Write build env to .env file in {DEPLOYMENT_PATH}') args, unknown = parser.parse_known_args(sys.argv[1:]) @@ -108,7 +107,7 @@ if __name__ == "__main__": envs=envs, base_image_name=helm_values['name'], helm_values=helm_values) - + if args.write_env: write_env_file(helm_values, os.path.join(root_paths[-1], DEPLOYMENT_PATH, ".env")) diff --git a/tools/deployment-cli-tools/setup.py b/tools/deployment-cli-tools/setup.py index 92814c43e..b01b2ae24 100644 --- a/tools/deployment-cli-tools/setup.py +++ b/tools/deployment-cli-tools/setup.py @@ -32,7 +32,6 @@ ] - setup( name=NAME, version=VERSION, diff --git a/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp/venv/matplotlib/__main__.py b/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp/venv/matplotlib/__main__.py index 37de2b0b6..4d9acb290 100644 --- a/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp/venv/matplotlib/__main__.py +++ b/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp/venv/matplotlib/__main__.py @@ -4,4 +4,4 @@ def fake_content(): - ... \ No newline at end of file + ... diff --git a/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp2/venv/matplotlib/__main__.py b/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp2/venv/matplotlib/__main__.py index 37de2b0b6..4d9acb290 100644 --- a/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp2/venv/matplotlib/__main__.py +++ b/tools/deployment-cli-tools/tests/resources_buggy/applications/myapp2/venv/matplotlib/__main__.py @@ -4,4 +4,4 @@ def fake_content(): - ... \ No newline at end of file + ... diff --git a/tools/deployment-cli-tools/tests/test_codefresh.py b/tools/deployment-cli-tools/tests/test_codefresh.py index 8d118d40b..4de2a07f1 100644 --- a/tools/deployment-cli-tools/tests/test_codefresh.py +++ b/tools/deployment-cli-tools/tests/test_codefresh.py @@ -13,6 +13,7 @@ if not os.path.exists(os.path.join(myapp_path, "dependencies/a/.git")): os.makedirs(os.path.join(myapp_path, "dependencies/a/.git")) + def test_create_codefresh_configuration(): values = create_helm_chart( [CLOUDHARNESS_ROOT, RESOURCES], @@ -126,7 +127,7 @@ def test_create_codefresh_configuration(): assert len( tstep['commands']) == 2, "Unit test commands are not properly loaded from the unit test configuration file" assert tstep['commands'][0] == "tox", "Unit test commands are not properly loaded from the unit test configuration file" - + assert len(l1_steps[CD_BUILD_STEP_DEPENDENCIES]['steps']) == 3, "3 clone steps should be included as we have 2 dependencies from myapp, plus cloudharness" finally: shutil.rmtree(BUILD_MERGE_DIR) @@ -153,12 +154,12 @@ def test_create_codefresh_configuration_multienv(): ) build_included = [app['harness']['name'] - for app in values['apps'].values() if 'harness' in app] + for app in values['apps'].values() if 'harness' in app] cf = create_codefresh_deployment_scripts(root_paths, include=build_included, - envs=['dev', 'test'], - base_image_name=values['name'], - helm_values=values, save=False) + envs=['dev', 'test'], + base_image_name=values['name'], + helm_values=values, save=False) assert cf['test_step'] == 'test' assert cf['test'] == True @@ -173,7 +174,6 @@ def test_create_codefresh_configuration_multienv(): shutil.rmtree(BUILD_MERGE_DIR) - def test_create_codefresh_configuration_tests(): values = create_helm_chart( [CLOUDHARNESS_ROOT, RESOURCES], @@ -213,8 +213,6 @@ def test_create_codefresh_configuration_tests(): assert "test-api" in st_build_test_steps["test-api"]["dockerfile"], "test-api image must be built from root context" - - e2e_steps = l1_steps[CD_E2E_TEST_STEP]['scale'] assert "samples_e2e_test" in e2e_steps, "samples e2e test step must be included" @@ -245,13 +243,12 @@ def test_create_codefresh_configuration_tests(): for volume in test_step["volumes"]: assert "server" not in volume - assert any("CLOUDHARNESS_BASE" in arg for arg in st_build_test_steps["test-api"] ["build_arguments"]), "Missing build dependency on api test image" finally: shutil.rmtree(BUILD_MERGE_DIR) - + values = create_helm_chart( [CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, diff --git a/tools/deployment-cli-tools/tests/test_helm.py b/tools/deployment-cli-tools/tests/test_helm.py index ed53ab863..da0073f09 100644 --- a/tools/deployment-cli-tools/tests/test_helm.py +++ b/tools/deployment-cli-tools/tests/test_helm.py @@ -148,17 +148,16 @@ def test_collect_helm_values_precedence(): assert values[KEY_APPS]['events']['kafka']['resources']['limits']['memory'] == 'overridden' assert values[KEY_APPS]['events']['kafka']['resources']['limits']['cpu'] == 'overridden-prod' + def test_collect_helm_values_multiple_envs(): values = create_helm_chart([CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, domain="my.local", namespace='test', env=['dev', 'test'], local=False, tag=1, include=["myapp"]) - assert values[KEY_APPS]['myapp']['test'] == True, 'values-test not loaded' assert values[KEY_APPS]['myapp']['dev'] == True, 'values-dev not loaded' assert values[KEY_APPS]['myapp']['a'] == 'test', 'values-test not overriding' - def test_collect_helm_values_wrong_dependencies_validate(): try: values = create_helm_chart([CLOUDHARNESS_ROOT, f"{RESOURCES}/wrong-dependencies"], output_path=OUT, domain="my.local", @@ -209,21 +208,21 @@ def test_collect_helm_values_build_dependencies(): assert 'cloudharness-base-debian' not in values[KEY_TASK_IMAGES], "Cloudharness-base-debian is not included in any dependency" assert 'cloudharness-frontend-build' not in values[KEY_TASK_IMAGES], "cloudharness-frontend-build is not included in any dependency" + def test_collect_helm_values_build_dependencies_nodeps(): values = create_helm_chart([CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, domain="my.local", namespace='test', env='prod', local=False, tag=1, include=["events"]) - assert 'cloudharness-flask' not in values[KEY_TASK_IMAGES], "Cloudharness-flask is not included in the build dependencies" assert 'cloudharness-base' not in values[KEY_TASK_IMAGES], "Cloudharness-base is not included in the build dependencies" assert 'cloudharness-base-debian' not in values[KEY_TASK_IMAGES], "Cloudharness-base-debian is not included in any dependency" assert 'cloudharness-frontend-build' not in values[KEY_TASK_IMAGES], "cloudharness-frontend-build is not included in any dependency" + def test_collect_helm_values_build_dependencies_exclude(): values = create_helm_chart([CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, domain="my.local", namespace='test', env='prod', local=False, tag=1, include=["workflows"], exclude=["workflows-extract-download"]) - assert 'cloudharness-flask' in values[KEY_TASK_IMAGES], "Cloudharness-flask is included in the build dependencies" assert 'cloudharness-base' in values[KEY_TASK_IMAGES], "Cloudharness-base is included in cloudharness-flask Dockerfile and it should be guessed" assert 'workflows-extract-download' not in values[KEY_TASK_IMAGES], "workflows-extract-download has been explicitly excluded" @@ -274,6 +273,7 @@ def test_clear_all_dbconfig_if_nodb(): db_config = values[KEY_APPS]['myapp'][KEY_HARNESS][KEY_DATABASE] assert db_config is None + def test_tag_hash_generation(): v1 = generate_tag_from_content(RESOURCES) v2 = generate_tag_from_content(RESOURCES, ignore=['myapp']) @@ -297,18 +297,19 @@ def test_tag_hash_generation(): finally: os.remove(fname) + def test_collect_helm_values_auto_tag(): def create(): return create_helm_chart([CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, include=['samples', 'myapp'], - exclude=['events'], domain="my.local", - namespace='test', env='dev', local=False, tag=None, registry='reg') - + exclude=['events'], domain="my.local", + namespace='test', env='dev', local=False, tag=None, registry='reg') + BASE_KEY = "cloudharness-base" values = create() # Auto values are set by using the directory hash assert 'reg/cloudharness/myapp:' in values[KEY_APPS]['myapp'][KEY_HARNESS]['deployment']['image'] - assert 'reg/cloudharness/myapp:' in values.apps['myapp'].harness.deployment.image + assert 'reg/cloudharness/myapp:' in values.apps['myapp'].harness.deployment.image assert 'cloudharness/myapp-mytask' in values[KEY_TASK_IMAGES]['myapp-mytask'] assert values[KEY_APPS]['myapp'][KEY_HARNESS]['deployment']['image'] == values.apps['myapp'].harness.deployment.image v1 = values.apps['myapp'].harness.deployment.image @@ -320,7 +321,6 @@ def create(): assert v1 == values.apps['myapp'].harness.deployment.image, "Nothing changed the hash value" assert values["task-images"][BASE_KEY] == b1, "Base image should not change following the root .dockerignore" - try: fname = os.path.join(RESOURCES, 'applications', 'myapp', 'afile.txt') with open(fname, 'w') as f: @@ -333,7 +333,6 @@ def create(): finally: os.remove(fname) - try: with open(fname, 'w') as f: f.write('a') @@ -343,7 +342,6 @@ def create(): finally: os.remove(fname) - fname = os.path.join(RESOURCES, 'applications', 'myapp', 'afile.ignored') try: with open(fname, 'w') as f: @@ -355,8 +353,6 @@ def create(): assert v1 == values.apps['myapp'].harness.deployment.image, "Nothing should change the hash value as the file is ignored in the .dockerignore" finally: os.remove(fname) - - # Dependencies test: if a dependency is changed, the hash should change fname = os.path.join(RESOURCES, 'infrastructure/common-images', 'my-common', 'afile') @@ -366,25 +362,21 @@ def create(): f.write('a') values = create() - + assert c1 != values["task-images"]["my-common"], "If content of a static image is changed, the hash should change" assert v1 != values.apps['myapp'].harness.deployment.image, "If a static image dependency is changed, the hash should change" finally: os.remove(fname) - fname = os.path.join(CLOUDHARNESS_ROOT, 'atestfile') try: with open(fname, 'w') as f: f.write('a') values = create() - + assert b1 != values["task-images"][BASE_KEY], "Content for base image is changed, the hash should change" assert d1 != values["task-images"]["cloudharness-flask"], "Content for base image is changed, the static image should change" assert v1 != values.apps['myapp'].harness.deployment.image, "2 levels dependency: If a base image dependency is changed, the hash should change" finally: os.remove(fname) - - - diff --git a/tools/deployment-cli-tools/tests/test_preprocessing.py b/tools/deployment-cli-tools/tests/test_preprocessing.py index b09711788..37c4bc66a 100644 --- a/tools/deployment-cli-tools/tests/test_preprocessing.py +++ b/tools/deployment-cli-tools/tests/test_preprocessing.py @@ -9,6 +9,7 @@ CLOUDHARNESS_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE))) MERGE_BUILD_DIR = "/tmp/build" + def test_get_build_paths(): values = create_helm_chart([CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, include=['samples', 'myapp'], exclude=['events'], domain="my.local", @@ -16,30 +17,30 @@ def test_get_build_paths(): artifacts = get_build_paths(root_paths=[CLOUDHARNESS_ROOT, RESOURCES], helm_values=values, merge_build_path=MERGE_BUILD_DIR) assert 'cloudharness-base' in artifacts assert "events" not in artifacts - assert "samples" in artifacts + assert "samples" in artifacts assert artifacts['cloudharness-base'] == os.path.join(MERGE_BUILD_DIR, BASE_IMAGES_PATH, "cloudharness-base") assert artifacts['samples'] == os.path.join(CLOUDHARNESS_ROOT, APPS_PATH, "samples") + def test_preprocess_build_overrides(): values = create_helm_chart([CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, include=['samples', 'myapp'], exclude=['events'], domain="my.local", namespace='test', env='dev', local=False, tag=1, registry='reg') - res = preprocess_build_overrides(root_paths=[CLOUDHARNESS_ROOT, RESOURCES], helm_values=values, merge_build_path=MERGE_BUILD_DIR) assert len(res) == 3 assert MERGE_BUILD_DIR in res[2] assert os.path.exists(MERGE_BUILD_DIR) - assert os.path.exists(os.path.join(MERGE_BUILD_DIR, BASE_IMAGES_PATH, "cloudharness-base/testfile")) - assert os.path.exists(os.path.join(MERGE_BUILD_DIR, BASE_IMAGES_PATH, "cloudharness-base/Dockerfile")) - assert not os.path.exists(os.path.join(MERGE_BUILD_DIR, BASE_IMAGES_PATH, "cloudharness-base-debian")) - assert not os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "events")) + assert os.path.exists(os.path.join(MERGE_BUILD_DIR, BASE_IMAGES_PATH, "cloudharness-base/testfile")) + assert os.path.exists(os.path.join(MERGE_BUILD_DIR, BASE_IMAGES_PATH, "cloudharness-base/Dockerfile")) + assert not os.path.exists(os.path.join(MERGE_BUILD_DIR, BASE_IMAGES_PATH, "cloudharness-base-debian")) + assert not os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "events")) - assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "accounts/deploy/values.yaml")) - assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "workflows/tasks/new-task/Dockerfile")) - assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "workflows/tasks/notify-queue/new-file")) - assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "workflows/tasks/notify-queue/Dockerfile")) + assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "accounts/deploy/values.yaml")) + assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "workflows/tasks/new-task/Dockerfile")) + assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "workflows/tasks/notify-queue/new-file")) + assert os.path.exists(os.path.join(MERGE_BUILD_DIR, APPS_PATH, "workflows/tasks/notify-queue/Dockerfile")) shutil.rmtree(MERGE_BUILD_DIR) diff --git a/tools/deployment-cli-tools/tests/test_skaffold.py b/tools/deployment-cli-tools/tests/test_skaffold.py index 999ad6396..3c545d214 100644 --- a/tools/deployment-cli-tools/tests/test_skaffold.py +++ b/tools/deployment-cli-tools/tests/test_skaffold.py @@ -70,10 +70,9 @@ def test_create_skaffold_configuration(): cloudharness_flask_artifact = next( a for a in sk['build']['artifacts'] if a['image'] == 'reg/cloudharness/cloudharness-flask') - assert os.path.samefile(cloudharness_flask_artifact['context'], - join(CLOUDHARNESS_ROOT, 'infrastructure/common-images/cloudharness-flask') - ) + join(CLOUDHARNESS_ROOT, 'infrastructure/common-images/cloudharness-flask') + ) assert len(cloudharness_flask_artifact['requires']) == 1 @@ -94,7 +93,6 @@ def test_create_skaffold_configuration(): a for a in sk['build']['artifacts'] if a['image'] == 'reg/cloudharness/accounts') assert os.path.samefile(accounts_artifact['context'], '/tmp/build/applications/accounts') - # Custom unit tests assert len(sk['test']) == 2, 'Unit tests should be included' @@ -181,4 +179,4 @@ def test_create_skaffold_configuration_with_conflicting_dependencies_requirement assert 'matplotlib' not in release['overrides']['apps'] myapp_config = release['overrides']['apps']['myapp2'] - assert myapp_config['harness']['deployment']['args'][0] == '/usr/src/app/myapp_code/__main__.py' \ No newline at end of file + assert myapp_config['harness']['deployment']['args'][0] == '/usr/src/app/myapp_code/__main__.py' diff --git a/tools/deployment-cli-tools/tests/test_utils.py b/tools/deployment-cli-tools/tests/test_utils.py index cade77700..78e843334 100644 --- a/tools/deployment-cli-tools/tests/test_utils.py +++ b/tools/deployment-cli-tools/tests/test_utils.py @@ -76,13 +76,14 @@ def test_check_docker_manifest_exists(): assert check_docker_manifest_exists("gcr.io/metacellllc", "cloudharness/cloudharness-base", "latest") assert not check_docker_manifest_exists("gcr.io/metacellllc", "cloudharness/cloudharness-base", "RANDOM_TAG") + def test_find_dockerfile_paths(): - + myapp_path = os.path.join(HERE, "resources/applications/myapp") if not os.path.exists(os.path.join(myapp_path, "dependencies/a/.git")): os.makedirs(os.path.join(myapp_path, "dependencies/a/.git")) - + dockerfiles = find_dockerfiles_paths(myapp_path) assert len(dockerfiles) == 2 assert next(d for d in dockerfiles if d.endswith("myapp")), "Must find the Dockerfile in the root directory" - assert next(d for d in dockerfiles if d.endswith("myapp/tasks/mytask")), "Must find the Dockerfile in the tasks directory" \ No newline at end of file + assert next(d for d in dockerfiles if d.endswith("myapp/tasks/mytask")), "Must find the Dockerfile in the tasks directory" From 8e0ff82b797aa218196eff9c3fa6ead031d805ea Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Mon, 9 Sep 2024 17:11:53 +0200 Subject: [PATCH 03/12] CH-147 linting automation --- .github/workflows/lint-check.yml | 23 +++++++++++++++++++ .../samples/paths/operation_async/get.py | 4 +--- lint.sh => lint-check.sh | 6 +---- 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/lint-check.yml rename lint.sh => lint-check.sh (75%) diff --git a/.github/workflows/lint-check.yml b/.github/workflows/lint-check.yml new file mode 100644 index 000000000..efee9f91a --- /dev/null +++ b/.github/workflows/lint-check.yml @@ -0,0 +1,23 @@ +name: Lint Check + +on: + push + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install autopep8 + run: pip install autopep8 + + - name: Run lint-check.sh + run: bash lint-check.sh \ No newline at end of file diff --git a/libraries/client/cloudharness_cli/cloudharness_cli/samples/paths/operation_async/get.py b/libraries/client/cloudharness_cli/cloudharness_cli/samples/paths/operation_async/get.py index 24318033d..a18549299 100644 --- a/libraries/client/cloudharness_cli/cloudharness_cli/samples/paths/operation_async/get.py +++ b/libraries/client/cloudharness_cli/cloudharness_cli/samples/paths/operation_async/get.py @@ -25,7 +25,7 @@ from cloudharness_cli.samples import schemas # noqa: F401 -from cloudharness_cli/samples.model.inline_response202 import InlineResponse202 +from cloudharness_cli.samples.model.inline_response202 import InlineResponse202 from . import path @@ -231,5 +231,3 @@ def get( timeout=timeout, skip_deserialization=skip_deserialization ) - - diff --git a/lint.sh b/lint-check.sh similarity index 75% rename from lint.sh rename to lint-check.sh index 3f4557023..426bfaff8 100644 --- a/lint.sh +++ b/lint-check.sh @@ -1,10 +1,6 @@ #!/bin/bash # Run autopep8 with --diff and capture the output -diff_output=$(autopep8 --select=E1,E2,E3,W,E4,E7,E502 --recursive --diff\ - --exclude '**/cloudharness_cli/**/*'\ - --exclude '**/models/*'\ - --exclude '**/model/*'\ - .) +diff_output=$(autopep8 --select=E1,E2,E3,W,E4,E7,E502 --recursive --diff --exclude '**/cloudharness_cli/**/*,**/models/*,**/model/*' .) # Check if the output is non-empty if [ -n "$diff_output" ]; then echo $diff_output From 8c2e86079374c819b5204797816b64450ddc487c Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 12:46:31 +0200 Subject: [PATCH 04/12] CH-32 Add Neo4j browser --- applications/neo4j/.gitignore | 1 + applications/neo4j/README.md | 22 ++++++++++ .../deploy/templates/reverseProxyServer.yaml | 37 ++++++++++++++++ applications/neo4j/deploy/values.yaml | 41 ++++++++++++++++++ applications/neo4j/docs/browser-login.png | Bin 0 -> 25106 bytes .../helm/templates/auto-database-neo4j.yaml | 2 + 6 files changed, 103 insertions(+) create mode 100644 applications/neo4j/.gitignore create mode 100644 applications/neo4j/README.md create mode 100644 applications/neo4j/deploy/templates/reverseProxyServer.yaml create mode 100644 applications/neo4j/deploy/values.yaml create mode 100644 applications/neo4j/docs/browser-login.png diff --git a/applications/neo4j/.gitignore b/applications/neo4j/.gitignore new file mode 100644 index 000000000..7c5616916 --- /dev/null +++ b/applications/neo4j/.gitignore @@ -0,0 +1 @@ +helm-charts \ No newline at end of file diff --git a/applications/neo4j/README.md b/applications/neo4j/README.md new file mode 100644 index 000000000..49dadb607 --- /dev/null +++ b/applications/neo4j/README.md @@ -0,0 +1,22 @@ +# Neo4j browser helm chart + +Enable this application to deploy a Neo4j server with the neo4j browser enabled. + +## How to use +The browser will be enabled at neo4j.[DOMAIN]. + +![Neo4j browser login](docs/browser-login.png) + +The default credentials are set in the [application configuration file](deploy/values.yaml). + +It is recommended to change the password during the first login, such as: + +``` +ALTER USER default SET PASSWORD '' +``` + +## Implementation +This implementation uses the Neo4j reverse proxy server to enable usage via Ingress and http(s). + +For more information, see https://neo4j.com/docs/operations-manual/current/kubernetes/accessing-neo4j-ingress/ + diff --git a/applications/neo4j/deploy/templates/reverseProxyServer.yaml b/applications/neo4j/deploy/templates/reverseProxyServer.yaml new file mode 100644 index 000000000..f273acb96 --- /dev/null +++ b/applications/neo4j/deploy/templates/reverseProxyServer.yaml @@ -0,0 +1,37 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.apps.neo4j.harness.deployment.name }} + labels: + app: {{ .Values.apps.neo4j.harness.deployment.name }} + namespace: "{{ .Release.Namespace }}" +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Values.apps.neo4j.harness.deployment.name }} + template: + metadata: + name: {{ .Values.apps.neo4j.harness.deployment.name }} + labels: + name: {{ .Values.apps.neo4j.harness.deployment.name }} + app: {{ .Values.apps.neo4j.harness.deployment.name }} + spec: + securityContext: {{ toYaml .Values.apps.neo4j.reverseProxy.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Values.apps.neo4j.harness.deployment.name }} + image: {{ .Values.apps.neo4j.reverseProxy.image }} + imagePullPolicy: Always + securityContext: {{ toYaml .Values.apps.neo4j.reverseProxy.containerSecurityContext | nindent 12 }} + ports: + - containerPort: {{ .Values.apps.neo4j.harness.deployment.port }} + env: + - name: SERVICE_NAME + value: {{ .Values.apps.neo4j.harness.database.name }} + - name: PORT + value: {{ .Values.apps.neo4j.harness.deployment.port | quote }} + - name: DOMAIN + value: {{ .Values.apps.neo4j.reverseProxy.domain | default "cluster.local" }} + - name: NAMESPACE + value: {{ .Release.Namespace }} +--- \ No newline at end of file diff --git a/applications/neo4j/deploy/values.yaml b/applications/neo4j/deploy/values.yaml new file mode 100644 index 000000000..4a9a45a4d --- /dev/null +++ b/applications/neo4j/deploy/values.yaml @@ -0,0 +1,41 @@ +harness: + subdomain: neo4j + database: + auto: true + name: neo4j-db + type: neo4j + user: default + pass: default + deployment: + auto: false + service: + auto: true +# Parameters for reverse proxy +reverseProxy: + image: "neo4j/helm-charts-reverse-proxy:5.23" + + # Name of the kubernetes service. This service should have the ports 7474 and 7687 open. + # This could be the admin service ex: "standalone-admin" or the loadbalancer service ex: "standalone" created via the neo4j helm chart + # serviceName , namespace , domain together will form the complete k8s service url. Ex: standalone-admin.default.svc.cluster.local + # When used against a cluster ensure the service being used is pointing to all the cluster instances. + # This could be the loadbalancer from neo4j helm chart or the headless service installed via neo4j-headless-service helm chart + serviceName: "" + # default is set to cluster.local + domain: "cluster.local" + + # securityContext defines privilege and access control settings for a Container. Making sure that we dont run Neo4j as root user. + containerSecurityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 7474 + runAsGroup: 7474 + capabilities: + drop: + - all + + podSecurityContext: + runAsNonRoot: true + runAsUser: 7474 + runAsGroup: 7474 + fsGroup: 7474 + fsGroupChangePolicy: "Always" diff --git a/applications/neo4j/docs/browser-login.png b/applications/neo4j/docs/browser-login.png new file mode 100644 index 0000000000000000000000000000000000000000..86e1db1ee173602f66e72c70a99ca8398586bfc9 GIT binary patch literal 25106 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 Y`|v9LOSv0t(NuH}= Date: Tue, 10 Sep 2024 12:57:45 +0200 Subject: [PATCH 05/12] CH-32 Add option to directly access a database --- deployment-configuration/helm/templates/auto-database.yaml | 2 +- deployment-configuration/value-template.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index 6ec31380d..a53ea6861 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -101,7 +101,7 @@ metadata: app: {{ .app.harness.deployment.name | quote }} {{ include "deploy_utils.labels" .root | indent 4 }} spec: - type: ClusterIP + type: {{-if .app.harness.database.expose }}LoadBalancer{{- else }}ClusterIP{{- end }} selector: app: {{ .app.harness.database.name | quote }} ports: diff --git a/deployment-configuration/value-template.yaml b/deployment-configuration/value-template.yaml index c04439a3b..222aa7f67 100644 --- a/deployment-configuration/value-template.yaml +++ b/deployment-configuration/value-template.yaml @@ -75,6 +75,8 @@ harness: pass: metacell # -- image ref for referencing images from the build, e.g. image_ref: myownpgimage image_ref: + # -- expose database to the public with ingress + expose: false # -- settings for mongo database (for type==mongo) mongo: image: mongo:5 From 0e282101a4d1b066ea74f51bfc72059e571dd132 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 13:07:15 +0200 Subject: [PATCH 06/12] CH-32 Update Neo4j --- deployment-configuration/value-template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment-configuration/value-template.yaml b/deployment-configuration/value-template.yaml index 222aa7f67..ff2814668 100644 --- a/deployment-configuration/value-template.yaml +++ b/deployment-configuration/value-template.yaml @@ -92,7 +92,7 @@ harness: port: 5432 # -- settings for neo4j database (for type==neo4j) neo4j: - image: neo4j:4.1.9 + image: neo4j:5 memory: size: 256M pagecache: From f334040bf6ff9b7ca291935f1650bf696c002c06 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 13:07:27 +0200 Subject: [PATCH 07/12] CH-32 Add documentation --- docs/applications/databases.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/applications/databases.md b/docs/applications/databases.md index 89bd2868b..96498f6cd 100644 --- a/docs/applications/databases.md +++ b/docs/applications/databases.md @@ -35,6 +35,9 @@ harness: `image_ref`: Optional setting, used for referencing a base/static image from the build. The complete image name with tag will automagically being generated from the values.yaml file. This setting overrides the `image` setting specific for the database type (e.g. postgres/image). Note: the referenced image must be included as a build dependency in order to be built by the pipelines. +`expose`: This option allows you to expose the database port through a load balancer. +Do not use on production! + ### Specific database settings @@ -91,7 +94,24 @@ harness #### Neo4j -Not yet supported! +Defaults: +```yaml +harness + database: + neo4j: + dbms_security_auth_enabled: "false" + image: neo4j:5 + memory: + heap: { initial: 64M, max: 128M } + pagecache: { size: 64M } + size: 256M + ports: + - { name: http, port: 7474 } + - { name: bolt, port: 7687 } +``` + +Not that the default resource values are not optimized and increasing the default memory is recommended for production. +Mapping memory configuration with Kubernetes resource requests is also recommended. ## Programmatic API From 06f99f12ca329c1c49684dd2f0e59220f17d1f41 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 14:15:19 +0200 Subject: [PATCH 08/12] CH-32 Fix --- deployment-configuration/helm/templates/auto-database.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment-configuration/helm/templates/auto-database.yaml b/deployment-configuration/helm/templates/auto-database.yaml index a53ea6861..2e0c15864 100644 --- a/deployment-configuration/helm/templates/auto-database.yaml +++ b/deployment-configuration/helm/templates/auto-database.yaml @@ -101,7 +101,7 @@ metadata: app: {{ .app.harness.deployment.name | quote }} {{ include "deploy_utils.labels" .root | indent 4 }} spec: - type: {{-if .app.harness.database.expose }}LoadBalancer{{- else }}ClusterIP{{- end }} + type: {{ if .app.harness.database.expose }}LoadBalancer{{ else }}ClusterIP{{ end }} selector: app: {{ .app.harness.database.name | quote }} ports: From 2dc0b2c9fc6924771b81a82f3d089d9ecaff49a5 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Tue, 10 Sep 2024 18:45:11 +0200 Subject: [PATCH 09/12] CH-147 Linting update in samples and templates --- .../webapp/frontend/.eslintrc.cjs | 19 - .../webapp/frontend/eslint.config.js | 56 + .../webapp/frontend/package.json | 3 +- applications/samples/frontend/.eslintrc.cjs | 40 - .../samples/frontend/eslint.config.js | 56 + applications/samples/frontend/package.json | 20 +- applications/samples/frontend/src/App.tsx | 16 +- applications/samples/frontend/vite.config.ts | 32 +- applications/samples/frontend/yarn.lock | 1260 ++++------------- 9 files changed, 421 insertions(+), 1081 deletions(-) delete mode 100644 application-templates/webapp/frontend/.eslintrc.cjs create mode 100644 application-templates/webapp/frontend/eslint.config.js delete mode 100644 applications/samples/frontend/.eslintrc.cjs create mode 100644 applications/samples/frontend/eslint.config.js diff --git a/application-templates/webapp/frontend/.eslintrc.cjs b/application-templates/webapp/frontend/.eslintrc.cjs deleted file mode 100644 index c73cf24e4..000000000 --- a/application-templates/webapp/frontend/.eslintrc.cjs +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - root: true, - env: { browser: true, es2020: true }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - ], - ignorePatterns: ['dist', '.eslintrc.cjs', 'src/rest/*'], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], - rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - '@typescript-eslint/no-explicit-any': 'off', - } -} diff --git a/application-templates/webapp/frontend/eslint.config.js b/application-templates/webapp/frontend/eslint.config.js new file mode 100644 index 000000000..5fbd4636c --- /dev/null +++ b/application-templates/webapp/frontend/eslint.config.js @@ -0,0 +1,56 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + + +export default tseslint.config( + { + ignores: [ + 'dist', + 'node_modules', + '.yalc', + 'src/rest/*' // do not lint generated code + ] + }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx,js,jsx}'], + languageOptions: { + ecmaVersion: "latest", + globals: globals.browser, + sourceType: "module" + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + indent: ["error", 2, { + SwitchCase: 1, + }], + curly: "error", // enforce braces for one-line blocks + "no-tabs": "error", // enforce no tabs + "no-console": ["warn", { + allow: ["warn", "error", "debug"], + }], + "@typescript-eslint/no-explicit-any": "off", // No strict typing (annoying especially with React elements and events callbacks) + "consistent-return": "warn", // https://eslint.org/docs/latest/rules/consistent-return + "prefer-arrow-callback": ["warn"], + "object-curly-spacing": ["warn", "always"], // enforce consistent spacing inside braces + "func-style": "off", // function expressions or arrow functions are equally valid + "no-unneeded-ternary": "warn", // disallow unnecessary ternary expressions + // React rules: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules + "react/prop-types": "off", // PropTypes are not forced + "react/forbid-prop-types": "off", // all PropTypes are allowed + "react-hooks/rules-of-hooks": "error", // https://react.dev/reference/rules/rules-of-hooks + "react-hooks/exhaustive-deps": "warn", // Hooks dependency array, sometimes it's better to ignore + }, + } +) \ No newline at end of file diff --git a/application-templates/webapp/frontend/package.json b/application-templates/webapp/frontend/package.json index b8d452789..4d852c343 100644 --- a/application-templates/webapp/frontend/package.json +++ b/application-templates/webapp/frontend/package.json @@ -6,6 +6,7 @@ "start:dev": "DOMAIN=https://test.ch.metacell.us vite", "start:local": "DOMAIN=http://samples.ch vite", "prebuild": "eslint .", - "build": "vite build" + "build": "vite build", + "lint": "eslint src --report-unused-disable-directives --fix" } } diff --git a/applications/samples/frontend/.eslintrc.cjs b/applications/samples/frontend/.eslintrc.cjs deleted file mode 100644 index 976123ecd..000000000 --- a/applications/samples/frontend/.eslintrc.cjs +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = { - root: true, - env: { browser: true, es2020: true }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - ], - ignorePatterns: [ - 'dist', - '.eslintrc.cjs', - 'src/rest/*' // do not lint generated code - ], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], - rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - '@typescript-eslint/no-explicit-any': "off", // No strict typing (annoying especially with React elements and events callbacks) - "indent": ["error", 2, { "SwitchCase": 1 }], - "curly": "error", // enforce braces for one-line blocks - "no-tabs": "error", // enforce no tabs - - "no-console": ["warn", { allow: ["warn", "error", "debug"] }], - "consistent-return": "warn", // https://eslint.org/docs/latest/rules/consistent-return - "prefer-arrow-callback": ["warn"], - "object-curly-spacing": ["warn", "always"], // enforce consistent spacing inside braces - - "func-style": "off", // function expressions or arrow functions are equally valid - - "no-unneeded-ternary": "warn", // disallow unnecessary ternary expressions - // React rules: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules - "react/prop-types": "off", // PropTypes are not forced - "react/forbid-prop-types": "off", // all PropTypes are allowed - "react-hooks/rules-of-hooks": "error", // https://react.dev/reference/rules/rules-of-hooks - "react-hooks/exhaustive-deps": "warn", // Hooks dependency array, sometimes it's better to ignore - } -} diff --git a/applications/samples/frontend/eslint.config.js b/applications/samples/frontend/eslint.config.js new file mode 100644 index 000000000..5fbd4636c --- /dev/null +++ b/applications/samples/frontend/eslint.config.js @@ -0,0 +1,56 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + + +export default tseslint.config( + { + ignores: [ + 'dist', + 'node_modules', + '.yalc', + 'src/rest/*' // do not lint generated code + ] + }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx,js,jsx}'], + languageOptions: { + ecmaVersion: "latest", + globals: globals.browser, + sourceType: "module" + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + indent: ["error", 2, { + SwitchCase: 1, + }], + curly: "error", // enforce braces for one-line blocks + "no-tabs": "error", // enforce no tabs + "no-console": ["warn", { + allow: ["warn", "error", "debug"], + }], + "@typescript-eslint/no-explicit-any": "off", // No strict typing (annoying especially with React elements and events callbacks) + "consistent-return": "warn", // https://eslint.org/docs/latest/rules/consistent-return + "prefer-arrow-callback": ["warn"], + "object-curly-spacing": ["warn", "always"], // enforce consistent spacing inside braces + "func-style": "off", // function expressions or arrow functions are equally valid + "no-unneeded-ternary": "warn", // disallow unnecessary ternary expressions + // React rules: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules + "react/prop-types": "off", // PropTypes are not forced + "react/forbid-prop-types": "off", // all PropTypes are allowed + "react-hooks/rules-of-hooks": "error", // https://react.dev/reference/rules/rules-of-hooks + "react-hooks/exhaustive-deps": "warn", // Hooks dependency array, sometimes it's better to ignore + }, + } +) \ No newline at end of file diff --git a/applications/samples/frontend/package.json b/applications/samples/frontend/package.json index a104f3afc..6d468d9a6 100644 --- a/applications/samples/frontend/package.json +++ b/applications/samples/frontend/package.json @@ -8,9 +8,9 @@ "start": "DOMAIN=http://localhost:5000 vite", "start:dev": "DOMAIN=https://test.ch.metacell.us vite", "start:local": "DOMAIN=http://samples.ch vite", - "prebuild": "eslint .", + "prebuild": "eslint src", "build": "vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint": "eslint src --report-unused-disable-directives --fix", "preview": "vite preview" }, "dependencies": { @@ -18,16 +18,16 @@ "react-dom": "^18.3.1" }, "devDependencies": { - "@types/node": "^22.0.0", + "@eslint/js": "^9.9.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.15.0", - "@typescript-eslint/parser": "^7.15.0", "@vitejs/plugin-react": "^4.3.1", - "eslint": "^8.57.0", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-react-refresh": "^0.4.7", - "typescript": "^5.2.2", - "vite": "^5.3.4" + "eslint": "^9.9.0", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.9", + "globals": "^15.9.0", + "typescript": "^5.5.3", + "typescript-eslint": "^8.0.1", + "vite": "^5.4.1" } } diff --git a/applications/samples/frontend/src/App.tsx b/applications/samples/frontend/src/App.tsx index eb8c0452e..a6a2ac789 100644 --- a/applications/samples/frontend/src/App.tsx +++ b/applications/samples/frontend/src/App.tsx @@ -3,14 +3,14 @@ import Version from './components/Version'; const Main = () => ( - <> - -

Sample React application is working!

- - -

See api documentation here

- - ) + <> + +

Sample React application is working!

+ + +

See api documentation here

+ +) export default Main; diff --git a/applications/samples/frontend/vite.config.ts b/applications/samples/frontend/vite.config.ts index 15155d738..8bb506cbf 100644 --- a/applications/samples/frontend/vite.config.ts +++ b/applications/samples/frontend/vite.config.ts @@ -22,21 +22,21 @@ export default defineConfig(({ mode }) => { return { - plugins: [react()], - server: { - port: 9000, - proxy: { - '/api/': { - target: replaceHost( proxyTarget, 'samples'), - secure: false, - changeOrigin: true, - }, - '/proxy/common/api': { - target: replaceHost( proxyTarget, 'common'), - secure: false, - changeOrigin: true, - rewrite: (path) => path.replace(/^\/proxy\/common\/api/, '/api') + plugins: [react()], + server: { + port: 9000, + proxy: { + '/api/': { + target: replaceHost( proxyTarget, 'samples'), + secure: false, + changeOrigin: true, + }, + '/proxy/common/api': { + target: replaceHost( proxyTarget, 'common'), + secure: false, + changeOrigin: true, + rewrite: (path) => path.replace(/^\/proxy\/common\/api/, '/api') + } } - } -}}} + } }} ) diff --git a/applications/samples/frontend/yarn.lock b/applications/samples/frontend/yarn.lock index c7ae36fea..5fe49fa26 100644 --- a/applications/samples/frontend/yarn.lock +++ b/applications/samples/frontend/yarn.lock @@ -334,49 +334,61 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": version "4.11.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@9.10.0", "@eslint/js@^9.9.0": + version "9.10.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.10.0.tgz#eaa3cb0baec497970bb29e43a153d0d5650143c6" + integrity sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g== -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@eslint/plugin-kit@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz#809b95a0227ee79c3195adfb562eb94352e77974" + integrity sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ== dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" + levn "^0.4.1" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@humanwhocodes/retry@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570" + integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew== "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" @@ -431,85 +443,85 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@rollup/rollup-android-arm-eabi@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.0.tgz#3d9fd50164b94964f5de68c3c4ce61933b3a338d" - integrity sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w== - -"@rollup/rollup-android-arm64@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.0.tgz#e1a6d4bca2eb08c84fd996a4bf896ce4b6f4014c" - integrity sha512-RDxUSY8D1tWYfn00DDi5myxKgOk6RvWPxhmWexcICt/MEC6yEMr4HNCu1sXXYLw8iAsg0D44NuU+qNq7zVWCrw== - -"@rollup/rollup-darwin-arm64@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.0.tgz#0a3fffea69489a24a96079af414b0be78df8abbc" - integrity sha512-emvKHL4B15x6nlNTBMtIaC9tLPRpeA5jMvRLXVbl/W9Ie7HhkrE7KQjvgS9uxgatL1HmHWDXk5TTS4IaNJxbAA== - -"@rollup/rollup-darwin-x64@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.0.tgz#13fbdb15f58f090871b0ffff047ece06ad6ad74c" - integrity sha512-fO28cWA1dC57qCd+D0rfLC4VPbh6EOJXrreBmFLWPGI9dpMlER2YwSPZzSGfq11XgcEpPukPTfEVFtw2q2nYJg== - -"@rollup/rollup-linux-arm-gnueabihf@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.0.tgz#e9d9219ddf6f6e946e2ee322198af12466d2c868" - integrity sha512-2Rn36Ubxdv32NUcfm0wB1tgKqkQuft00PtM23VqLuCUR4N5jcNWDoV5iBC9jeGdgS38WK66ElncprqgMUOyomw== - -"@rollup/rollup-linux-arm-musleabihf@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.0.tgz#4ba804a00b5e793196a622f6977e05f23e01f59a" - integrity sha512-gJuzIVdq/X1ZA2bHeCGCISe0VWqCoNT8BvkQ+BfsixXwTOndhtLUpOg0A1Fcx/+eA6ei6rMBzlOz4JzmiDw7JQ== - -"@rollup/rollup-linux-arm64-gnu@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.0.tgz#d871e3f41de759a6db27fc99235b782ba47c15cc" - integrity sha512-0EkX2HYPkSADo9cfeGFoQ7R0/wTKb7q6DdwI4Yn/ULFE1wuRRCHybxpl2goQrx4c/yzK3I8OlgtBu4xvted0ug== - -"@rollup/rollup-linux-arm64-musl@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.0.tgz#6e63f7ad4cc51bd2c693a2826fd279de9eaa05b5" - integrity sha512-GlIQRj9px52ISomIOEUq/IojLZqzkvRpdP3cLgIE1wUWaiU5Takwlzpz002q0Nxxr1y2ZgxC2obWxjr13lvxNQ== - -"@rollup/rollup-linux-powerpc64le-gnu@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.0.tgz#1540b284d91c440bc9fa7a1714cfb71a5597e94d" - integrity sha512-N6cFJzssruDLUOKfEKeovCKiHcdwVYOT1Hs6dovDQ61+Y9n3Ek4zXvtghPPelt6U0AH4aDGnDLb83uiJMkWYzQ== - -"@rollup/rollup-linux-riscv64-gnu@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.0.tgz#70ae58103b5bc7ba2e2235738b51d97022c8ef92" - integrity sha512-2DnD3mkS2uuam/alF+I7M84koGwvn3ZVD7uG+LEWpyzo/bq8+kKnus2EVCkcvh6PlNB8QPNFOz6fWd5N8o1CYg== - -"@rollup/rollup-linux-s390x-gnu@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.0.tgz#579ca5f271421a961d3c73d221202c79e02ff03a" - integrity sha512-D6pkaF7OpE7lzlTOFCB2m3Ngzu2ykw40Nka9WmKGUOTS3xcIieHe82slQlNq69sVB04ch73thKYIWz/Ian8DUA== - -"@rollup/rollup-linux-x64-gnu@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.0.tgz#f0282d761b8b4e7b92b236813475248e37231849" - integrity sha512-HBndjQLP8OsdJNSxpNIN0einbDmRFg9+UQeZV1eiYupIRuZsDEoeGU43NQsS34Pp166DtwQOnpcbV/zQxM+rWA== - -"@rollup/rollup-linux-x64-musl@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.0.tgz#65da807ac66c505ad14b76f1e5976006cb67dd5f" - integrity sha512-HxfbvfCKJe/RMYJJn0a12eiOI9OOtAUF4G6ozrFUK95BNyoJaSiBjIOHjZskTUffUrB84IPKkFG9H9nEvJGW6A== - -"@rollup/rollup-win32-arm64-msvc@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.0.tgz#1eed24b91f421c2eea8bb7ca8889ba0c867e1780" - integrity sha512-HxDMKIhmcguGTiP5TsLNolwBUK3nGGUEoV/BO9ldUBoMLBssvh4J0X8pf11i1fTV7WShWItB1bKAKjX4RQeYmg== - -"@rollup/rollup-win32-ia32-msvc@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.0.tgz#1ed93c9cdc84e185359797a686f4d1576afcea58" - integrity sha512-xItlIAZZaiG/u0wooGzRsx11rokP4qyc/79LkAOdznGRAbOFc+SfEdfUOszG1odsHNgwippUJavag/+W/Etc6Q== - -"@rollup/rollup-win32-x64-msvc@4.19.0": - version "4.19.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.0.tgz#baf9b65023ea2ecc5e6ec68f787a0fecfd8ee84c" - integrity sha512-xNo5fV5ycvCCKqiZcpB65VMR11NJB+StnxHz20jdqRAktfdfzhgjTiJ2doTDQE/7dqGaV5I7ZGqKpgph6lCIag== +"@rollup/rollup-android-arm-eabi@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz#0412834dc423d1ff7be4cb1fc13a86a0cd262c11" + integrity sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg== + +"@rollup/rollup-android-arm64@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz#baf1a014b13654f3b9e835388df9caf8c35389cb" + integrity sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA== + +"@rollup/rollup-darwin-arm64@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz#0a2c364e775acdf1172fe3327662eec7c46e55b1" + integrity sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q== + +"@rollup/rollup-darwin-x64@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz#a972db75890dfab8df0da228c28993220a468c42" + integrity sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w== + +"@rollup/rollup-linux-arm-gnueabihf@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz#1609d0630ef61109dd19a278353e5176d92e30a1" + integrity sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w== + +"@rollup/rollup-linux-arm-musleabihf@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz#3c1dca5f160aa2e79e4b20ff6395eab21804f266" + integrity sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w== + +"@rollup/rollup-linux-arm64-gnu@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz#c2fe376e8b04eafb52a286668a8df7c761470ac7" + integrity sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw== + +"@rollup/rollup-linux-arm64-musl@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz#e62a4235f01e0f66dbba587c087ca6db8008ec80" + integrity sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w== + +"@rollup/rollup-linux-powerpc64le-gnu@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz#24b3457e75ee9ae5b1c198bd39eea53222a74e54" + integrity sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ== + +"@rollup/rollup-linux-riscv64-gnu@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz#38edfba9620fe2ca8116c97e02bd9f2d606bde09" + integrity sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg== + +"@rollup/rollup-linux-s390x-gnu@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz#a3bfb8bc5f1e802f8c76cff4a4be2e9f9ac36a18" + integrity sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ== + +"@rollup/rollup-linux-x64-gnu@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz#0dadf34be9199fcdda44b5985a086326344f30ad" + integrity sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw== + +"@rollup/rollup-linux-x64-musl@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz#7b7deddce240400eb87f2406a445061b4fed99a8" + integrity sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg== + +"@rollup/rollup-win32-arm64-msvc@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz#a0ca0c5149c2cfb26fab32e6ba3f16996fbdb504" + integrity sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ== + +"@rollup/rollup-win32-ia32-msvc@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz#aae2886beec3024203dbb5569db3a137bc385f8e" + integrity sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw== + +"@rollup/rollup-win32-x64-msvc@4.21.2": + version "4.21.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz#e4291e3c1bc637083f87936c333cdbcad22af63b" + integrity sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA== "@types/babel__core@^7.20.5": version "7.20.5" @@ -549,13 +561,6 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== -"@types/node@^22.0.0": - version "22.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.0.0.tgz#04862a2a71e62264426083abe1e27e87cac05a30" - integrity sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw== - dependencies: - undici-types "~6.11.1" - "@types/prop-types@*": version "15.7.12" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" @@ -576,92 +581,87 @@ "@types/prop-types" "*" csstype "^3.0.2" -"@typescript-eslint/eslint-plugin@^7.15.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz#c8ed1af1ad2928ede5cdd207f7e3090499e1f77b" - integrity sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A== +"@typescript-eslint/eslint-plugin@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.5.0.tgz#7c1863693a98371703686e1c0fac64ffc576cdb1" + integrity sha512-lHS5hvz33iUFQKuPFGheAB84LwcJ60G8vKnEhnfcK1l8kGVLro2SFYW6K0/tj8FUhRJ0VHyg1oAfg50QGbPPHw== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.17.0" - "@typescript-eslint/type-utils" "7.17.0" - "@typescript-eslint/utils" "7.17.0" - "@typescript-eslint/visitor-keys" "7.17.0" + "@typescript-eslint/scope-manager" "8.5.0" + "@typescript-eslint/type-utils" "8.5.0" + "@typescript-eslint/utils" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@^7.15.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.17.0.tgz#be8e32c159190cd40a305a2121220eadea5a88e7" - integrity sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A== +"@typescript-eslint/parser@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.5.0.tgz#d590e1ef9f31f26d423999ad3f687723247e6bcc" + integrity sha512-gF77eNv0Xz2UJg/NbpWJ0kqAm35UMsvZf1GHj8D9MRFTj/V3tAciIWXfmPLsAAF/vUlpWPvUDyH1jjsr0cMVWw== dependencies: - "@typescript-eslint/scope-manager" "7.17.0" - "@typescript-eslint/types" "7.17.0" - "@typescript-eslint/typescript-estree" "7.17.0" - "@typescript-eslint/visitor-keys" "7.17.0" + "@typescript-eslint/scope-manager" "8.5.0" + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/typescript-estree" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz#e072d0f914662a7bfd6c058165e3c2b35ea26b9d" - integrity sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA== +"@typescript-eslint/scope-manager@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.5.0.tgz#385341de65b976f02b295b8aca54bb4ffd6b5f07" + integrity sha512-06JOQ9Qgj33yvBEx6tpC8ecP9o860rsR22hWMEd12WcTRrfaFgHr2RB/CA/B+7BMhHkXT4chg2MyboGdFGawYg== dependencies: - "@typescript-eslint/types" "7.17.0" - "@typescript-eslint/visitor-keys" "7.17.0" + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" -"@typescript-eslint/type-utils@7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz#c5da78feb134c9c9978cbe89e2b1a589ed22091a" - integrity sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA== +"@typescript-eslint/type-utils@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.5.0.tgz#6215b23aa39dbbd8dde0a4ef9ee0f745410c29b1" + integrity sha512-N1K8Ix+lUM+cIDhL2uekVn/ZD7TZW+9/rwz8DclQpcQ9rk4sIL5CAlBC0CugWKREmDjBzI/kQqU4wkg46jWLYA== dependencies: - "@typescript-eslint/typescript-estree" "7.17.0" - "@typescript-eslint/utils" "7.17.0" + "@typescript-eslint/typescript-estree" "8.5.0" + "@typescript-eslint/utils" "8.5.0" debug "^4.3.4" ts-api-utils "^1.3.0" -"@typescript-eslint/types@7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.17.0.tgz#7ce8185bdf06bc3494e73d143dbf3293111b9cff" - integrity sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A== +"@typescript-eslint/types@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.5.0.tgz#4465d99331d1276f8fb2030e4f9c73fe01a05bf9" + integrity sha512-qjkormnQS5wF9pjSi6q60bKUHH44j2APxfh9TQRXK8wbYVeDYYdYJGIROL87LGZZ2gz3Rbmjc736qyL8deVtdw== -"@typescript-eslint/typescript-estree@7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz#dcab3fea4c07482329dd6107d3c6480e228e4130" - integrity sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw== +"@typescript-eslint/typescript-estree@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.5.0.tgz#6e5758cf2f63aa86e9ddfa4e284e2e0b81b87557" + integrity sha512-vEG2Sf9P8BPQ+d0pxdfndw3xIXaoSjliG0/Ejk7UggByZPKXmJmw3GW5jV2gHNQNawBUyfahoSiCFVov0Ruf7Q== dependencies: - "@typescript-eslint/types" "7.17.0" - "@typescript-eslint/visitor-keys" "7.17.0" + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" debug "^4.3.4" - globby "^11.1.0" + fast-glob "^3.3.2" is-glob "^4.0.3" minimatch "^9.0.4" semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.17.0.tgz#815cd85b9001845d41b699b0ce4f92d6dfb84902" - integrity sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw== +"@typescript-eslint/utils@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.5.0.tgz#4d4ffed96d0654546a37faa5b84bdce16d951634" + integrity sha512-6yyGYVL0e+VzGYp60wvkBHiqDWOpT63pdMV2CVG4LVDd5uR6q1qQN/7LafBZtAtNIn/mqXjsSeS5ggv/P0iECw== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "7.17.0" - "@typescript-eslint/types" "7.17.0" - "@typescript-eslint/typescript-estree" "7.17.0" + "@typescript-eslint/scope-manager" "8.5.0" + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/typescript-estree" "8.5.0" -"@typescript-eslint/visitor-keys@7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz#680465c734be30969e564b4647f38d6cdf49bfb0" - integrity sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A== +"@typescript-eslint/visitor-keys@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.5.0.tgz#13028df3b866d2e3e2e2cc4193cf2c1e0e04c4bf" + integrity sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw== dependencies: - "@typescript-eslint/types" "7.17.0" + "@typescript-eslint/types" "8.5.0" eslint-visitor-keys "^3.4.3" -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - "@vitejs/plugin-react@^4.3.1": version "4.3.1" resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz#d0be6594051ded8957df555ff07a991fb618b48e" @@ -678,12 +678,12 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.9.0: +acorn@^8.12.0: version "8.12.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== -ajv@^6.12.3, ajv@^6.12.4: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -693,26 +693,11 @@ ajv@^6.12.3, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - integrity sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" @@ -727,80 +712,16 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== - argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== - -aws4@^1.8.0: - version "1.13.2" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" - integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== - dependencies: - tweetnacl "^0.14.3" - -biome@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/biome/-/biome-0.3.3.tgz#71c29633f84a486186bec97675da6f33a925575c" - integrity sha512-4LXjrQYbn9iTXu9Y4SKT7ABzTV0WnLDHCVSd2fPUOKsy1gQ+E4xPFmlY1zcWexoi0j7fGHItlL6OWA2CZ/yYAQ== - dependencies: - bluebird "^3.4.1" - chalk "^1.1.3" - commander "^2.9.0" - editor "^1.0.0" - fs-promise "^0.5.0" - inquirer-promise "0.0.3" - request-promise "^3.0.0" - untildify "^3.0.2" - user-home "^2.0.0" - -bluebird@^3.3, bluebird@^3.4.1: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -843,22 +764,6 @@ caniuse-lite@^1.0.30001640: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz" integrity sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg== -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== - -chalk@^1.0.0, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -876,23 +781,6 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A== - dependencies: - restore-cursor "^1.0.1" - -cli-width@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-1.1.1.tgz#a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d" - integrity sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg== - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" @@ -917,18 +805,6 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@^2.9.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" @@ -939,16 +815,6 @@ convert-source-map@^2.0.0: resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -core-js@^2.4.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" - integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== - cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -963,13 +829,6 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== - dependencies: - assert-plus "^1.0.0" - debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.5" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" @@ -982,48 +841,6 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -earlgrey-runtime@>=0.0.10, earlgrey-runtime@>=0.0.11: - version "0.1.2" - resolved "https://registry.yarnpkg.com/earlgrey-runtime/-/earlgrey-runtime-0.1.2.tgz#5e7ea308924f107842877d59bb40bc2a9d9a29f8" - integrity sha512-T4qoScXi5TwALDv8nlGTvOuCT8jXcKcxtO8qVdqv46IA2GHJfQzwoBPbkOmORnyhu3A98cVVuhWLsM2CzPljJg== - dependencies: - core-js "^2.4.0" - kaiser ">=0.0.4" - lodash "^4.17.2" - regenerator-runtime "^0.9.5" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -editor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" - integrity sha512-SoRmbGStwNYHgKfjOrX2L0mUvp9bUVv0uPppZSOMAntEbcFtoC3MKF5b3T6HQPXKIV+QGY3xPO3JK5it5lVkuw== - electron-to-chromium@^1.4.820: version "1.5.2" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.2.tgz" @@ -1063,7 +880,7 @@ escalade@^3.1.2: resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -1073,66 +890,67 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-react-hooks@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" - integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== +eslint-plugin-react-hooks@^5.1.0-rc.0: + version "5.1.0-rc-fb9a90fa48-20240614" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz#206a7ec005f0b286aaf7091f4e566083d310b189" + integrity sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w== -eslint-plugin-react-refresh@^0.4.7: - version "0.4.9" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.9.tgz#bf870372b353b12e1e6fb7fc41b282d9cbc8d93d" - integrity sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA== +eslint-plugin-react-refresh@^0.4.9: + version "0.4.11" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.11.tgz#e450761a2bdb260aa10cfb73f846209a737827cb" + integrity sha512-wrAKxMbVr8qhXTtIKfXqAn5SAtRZt0aXxe5P23Fh4pUAdC6XEsybGLB8P0PI4j1yYqOgUEUlzKAGDfo7rJOjcw== -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.2.tgz#5cbb33d4384c9136083a71190d548158fe128f94" + integrity sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.57.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== +eslint-visitor-keys@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" + integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== + +eslint@^9.9.0: + version "9.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.10.0.tgz#0bd74d7fe4db77565d0e7f57c7df6d2b04756806" + integrity sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.10.0" + "@eslint/plugin-kit" "^0.1.0" "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.0" "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" + eslint-scope "^8.0.2" + eslint-visitor-keys "^4.0.0" + espree "^10.1.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" @@ -1140,16 +958,16 @@ eslint@^8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^10.0.1, espree@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56" + integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA== dependencies: - acorn "^8.9.0" + acorn "^8.12.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" + eslint-visitor-keys "^4.0.0" -esquery@^1.4.2: +esquery@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== @@ -1173,34 +991,14 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - integrity sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg== - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.9: +fast-glob@^3.3.2: version "3.3.2" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -1226,20 +1024,12 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" fill-range@^7.1.1: version "7.1.1" @@ -1256,60 +1046,19 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" + keyv "^4.5.4" flatted@^3.2.9: version "3.3.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -fs-extra@^0.26.5: - version "0.26.7" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" - integrity sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - -fs-promise@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-0.5.0.tgz#4347d6bf624655a7061a4319213c393276ad3ef3" - integrity sha512-Y+4F4ujhEcayCJt6JmzcOun9MYGQwz+bVUiuBmTkJImhBHKpBvmVPZR9wtfiF7k3ffwAOAuurygQe+cPLSFQhw== - dependencies: - any-promise "^1.0.0" - fs-extra "^0.26.5" - mz "^2.3.1" - thenify-all "^1.6.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -1320,13 +1069,6 @@ gensync@^1.0.0-beta.2: resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== - dependencies: - assert-plus "^1.0.0" - glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -1341,72 +1083,26 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.19.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +globals@^15.9.0: + version "15.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.9.0.tgz#e9de01771091ffbc37db5714dab484f9f69ff399" + integrity sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA== graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== - dependencies: - ansi-regex "^2.0.0" - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" @@ -1417,15 +1113,6 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - ignore@^5.2.0, ignore@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" @@ -1444,58 +1131,11 @@ imurmurhash@^0.1.4: resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inquirer-promise@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/inquirer-promise/-/inquirer-promise-0.0.3.tgz#2fa71387ef51ea3f0e22f668501d415abb8e42e2" - integrity sha512-82CQX586JAV9GAgU9yXZsMDs+NorjA0nLhkfFx9+PReyOnuoHRbHrC1Z90sS95bFJI1Tm1gzMObuE0HabzkJpg== - dependencies: - earlgrey-runtime ">=0.0.11" - inquirer "^0.11.3" - -inquirer@^0.11.3: - version "0.11.4" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.11.4.tgz#81e3374e8361beaff2d97016206d359d0b32fa4d" - integrity sha512-QR+2TW90jnKk9LUUtbcA3yQXKt2rDEKMh6+BAZQIeumtzHexnwVLdPakSslGijXYLJCzFv7GMXbFCn0pA00EUw== - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^1.0.1" - figures "^1.3.5" - lodash "^3.3.1" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== - dependencies: - number-is-nan "^1.0.0" - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -1513,21 +1153,11 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -1540,11 +1170,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" @@ -1560,64 +1185,23 @@ json-schema-traverse@^0.4.1: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - json5@^2.2.3: version "2.2.3" resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== - optionalDependencies: - graceful-fs "^4.1.6" - -jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - -kaiser@>=0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/kaiser/-/kaiser-0.0.4.tgz#d25ddf800640857fadde08dba59ffc7a5a4f5c38" - integrity sha512-m8ju+rmBqvclZmyrOXgGGhOYSjKJK6RN1NhqEltemY87UqZOxEkizg9TOy1vQSyJ01Wx6SAPuuN0iO2Mgislvw== - dependencies: - earlgrey-runtime ">=0.0.10" - -keyv@^4.5.3: +keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== - optionalDependencies: - graceful-fs "^4.1.9" - levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1638,16 +1222,6 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^3.3.1: - version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" - integrity sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ== - -lodash@^4.17.2, lodash@^4.6.1: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - loose-envify@^1.1.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -1662,7 +1236,7 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -1675,19 +1249,7 @@ micromatch@^4.0.4: braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -1706,20 +1268,6 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - integrity sha512-EbrziT4s8cWPmzr47eYVW3wimS4HsvlnV5ri1xw1aR6JQo/OrJX5rkl32K/QQHdxeabJETtfeaROGhd8W7uBgg== - -mz@^2.3.1: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - nanoid@^3.3.7: version "3.3.7" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" @@ -1735,33 +1283,6 @@ node-releases@^2.0.14: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - integrity sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A== - optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -1774,11 +1295,6 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== - p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" @@ -1805,26 +1321,11 @@ path-exists@^4.0.0: resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== - picocolors@^1.0.0, picocolors@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" @@ -1835,10 +1336,10 @@ picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -postcss@^8.4.39: - version "8.4.40" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.40.tgz#eb81f2a4dd7668ed869a6db25999e02e9ad909d8" - integrity sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q== +postcss@^8.4.43: + version "8.4.45" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.45.tgz#538d13d89a16ef71edbf75d895284ae06b79e603" + integrity sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q== dependencies: nanoid "^3.3.7" picocolors "^1.0.1" @@ -1849,21 +1350,11 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -psl@^1.1.28: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" @@ -1889,119 +1380,41 @@ react@^18.3.1: dependencies: loose-envify "^1.1.0" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - integrity sha512-8/td4MmwUB6PkZUbV25uKz7dfrmjYWxsW8DVfibWdlHRk/l/DfHKn4pU+dfcoGLFgWOdyGCzINRQD7jn+Bv+/g== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - -regenerator-runtime@^0.9.5: - version "0.9.6" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" - integrity sha512-D0Y/JJ4VhusyMOd/o25a3jdUqN/bC85EFsaoL9Oqmy/O4efCh+xhp7yj2EEOsj974qvMkcW8AwUzJ1jB/MbxCw== - -request-promise@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-3.0.0.tgz#be1edb26f41c49cd1d5656c6753d6842a1249f46" - integrity sha512-wVGUX+BoKxYsavTA72i6qHcyLbjzM4LR4y/AmDCqlbuMAursZdDWO7PmgbGAUvD2SeEJ5iB99VSq/U51i/DNbw== - dependencies: - bluebird "^3.3" - lodash "^4.6.1" - request "^2.34" - -request@^2.34: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - integrity sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw== - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - reusify@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^2.2.8: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rollup@^4.13.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.19.0.tgz#83b08cc0b2bc38c26c194cb7f2cdabd84a2a8c02" - integrity sha512-5r7EYSQIowHsK4eTZ0Y81qpZuJz+MUuYeqmmYmRMl1nwhdmbiYqt5jwzf6u7wyOzJgYqtCRMtVRKOtHANBz7rA== +rollup@^4.20.0: + version "4.21.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.2.tgz#f41f277a448d6264e923dd1ea179f0a926aaf9b7" + integrity sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.19.0" - "@rollup/rollup-android-arm64" "4.19.0" - "@rollup/rollup-darwin-arm64" "4.19.0" - "@rollup/rollup-darwin-x64" "4.19.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.19.0" - "@rollup/rollup-linux-arm-musleabihf" "4.19.0" - "@rollup/rollup-linux-arm64-gnu" "4.19.0" - "@rollup/rollup-linux-arm64-musl" "4.19.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.19.0" - "@rollup/rollup-linux-riscv64-gnu" "4.19.0" - "@rollup/rollup-linux-s390x-gnu" "4.19.0" - "@rollup/rollup-linux-x64-gnu" "4.19.0" - "@rollup/rollup-linux-x64-musl" "4.19.0" - "@rollup/rollup-win32-arm64-msvc" "4.19.0" - "@rollup/rollup-win32-ia32-msvc" "4.19.0" - "@rollup/rollup-win32-x64-msvc" "4.19.0" + "@rollup/rollup-android-arm-eabi" "4.21.2" + "@rollup/rollup-android-arm64" "4.21.2" + "@rollup/rollup-darwin-arm64" "4.21.2" + "@rollup/rollup-darwin-x64" "4.21.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.21.2" + "@rollup/rollup-linux-arm-musleabihf" "4.21.2" + "@rollup/rollup-linux-arm64-gnu" "4.21.2" + "@rollup/rollup-linux-arm64-musl" "4.21.2" + "@rollup/rollup-linux-powerpc64le-gnu" "4.21.2" + "@rollup/rollup-linux-riscv64-gnu" "4.21.2" + "@rollup/rollup-linux-s390x-gnu" "4.21.2" + "@rollup/rollup-linux-x64-gnu" "4.21.2" + "@rollup/rollup-linux-x64-musl" "4.21.2" + "@rollup/rollup-win32-arm64-msvc" "4.21.2" + "@rollup/rollup-win32-ia32-msvc" "4.21.2" + "@rollup/rollup-win32-x64-msvc" "4.21.2" fsevents "~2.3.2" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - integrity sha512-qOX+w+IxFgpUpJfkv2oGN0+ExPs68F4sZHfaRRx4dDexAQkG83atugKVEylyT5ARees3HBbfmuvnjbrd8j9Wjw== - dependencies: - once "^1.3.0" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -2009,21 +1422,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - integrity sha512-1I1+G2gteLB8Tkt8YI1sJvSIfa0lWuRtC8GjvtyPBcLSF5jBCCJJqKrpER5JU5r6Bhe+i9/pK3VMuUcXu0kdwQ== - -safe-buffer@^5.0.1, safe-buffer@^5.1.2: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - scheduler@^0.23.2: version "0.23.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" @@ -2053,47 +1451,11 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== -sshpk@^1.7.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" - integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== - dependencies: - ansi-regex "^2.0.0" - strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -2106,11 +1468,6 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" @@ -2130,25 +1487,6 @@ text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -thenify-all@^1.0.0, thenify-all@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" @@ -2161,31 +1499,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -2193,25 +1511,19 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -typescript@^5.2.2: - version "5.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== - -undici-types@~6.11.1: - version "6.11.1" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.11.1.tgz#432ea6e8efd54a48569705a699e62d8f4981b197" - integrity sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ== +typescript-eslint@^8.0.1: + version "8.5.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.5.0.tgz#041f6c302d0e9a8e116a33d60b0bb19f34036dd7" + integrity sha512-uD+XxEoSIvqtm4KE97etm32Tn5MfaZWgWfMMREStLxR6JzvHkc2Tkj7zhTEK5XmtpTmKHNnG8Sot6qDfhHtR1Q== + dependencies: + "@typescript-eslint/eslint-plugin" "8.5.0" + "@typescript-eslint/parser" "8.5.0" + "@typescript-eslint/utils" "8.5.0" -untildify@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9" - integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA== +typescript@^5.5.3: + version "5.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" + integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== update-browserslist-db@^1.1.0: version "1.1.0" @@ -2228,35 +1540,14 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - integrity sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ== - dependencies: - os-homedir "^1.0.0" - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vite@^5.3.4: - version "5.3.5" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.5.tgz#b847f846fb2b6cb6f6f4ed50a830186138cb83d8" - integrity sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA== +vite@^5.4.1: + version "5.4.3" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.3.tgz#771c470e808cb6732f204e1ee96c2ed65b97a0eb" + integrity sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q== dependencies: esbuild "^0.21.3" - postcss "^8.4.39" - rollup "^4.13.0" + postcss "^8.4.43" + rollup "^4.20.0" optionalDependencies: fsevents "~2.3.3" @@ -2272,11 +1563,6 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" From 9f5130f78bb58a2cf4ac5be424a7413c8601b2b3 Mon Sep 17 00:00:00 2001 From: Filippo Ledda <46561561+filippomc@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:12:34 +0200 Subject: [PATCH 10/12] Update applications/neo4j/README.md Co-authored-by: Alex --- applications/neo4j/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/neo4j/README.md b/applications/neo4j/README.md index 49dadb607..cd46617d4 100644 --- a/applications/neo4j/README.md +++ b/applications/neo4j/README.md @@ -3,7 +3,7 @@ Enable this application to deploy a Neo4j server with the neo4j browser enabled. ## How to use -The browser will be enabled at neo4j.[DOMAIN]. +The neo4j browser will be enabled at neo4j.[DOMAIN]. ![Neo4j browser login](docs/browser-login.png) From fefad142c8c588d34689845cb537d7ff457dd867 Mon Sep 17 00:00:00 2001 From: Filippo Ledda Date: Wed, 11 Sep 2024 15:19:27 +0200 Subject: [PATCH 11/12] CH-32 Fix neo4j 5 config --- .../helm/templates/auto-database-neo4j.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deployment-configuration/helm/templates/auto-database-neo4j.yaml b/deployment-configuration/helm/templates/auto-database-neo4j.yaml index bddbab24b..d56ca21e3 100644 --- a/deployment-configuration/helm/templates/auto-database-neo4j.yaml +++ b/deployment-configuration/helm/templates/auto-database-neo4j.yaml @@ -5,22 +5,22 @@ image: {{ .app.harness.database.neo4j.image }} {{- end }} env: - - name: NEO4J_dbms_directories_data + - name: NEO4J_server_directories_data value: /data/db/data - - name: NEO4J_dbms_directories_logs + - name: NEO4J_server_directories_logs value: /data/db/logs - - name: NEO4J_dbms_directories_metrics + - name: NEO4J_server_directories_metrics value: /data/db/metrics - - name: NEO4J_dbms_memory_size - value: {{ .app.harness.database.neo4j.memory.size }} - - name: NEO4J_dbms_memory_pagecache_size + - name: NEO4J_server_memory_pagecache_size value: {{ .app.harness.database.neo4j.memory.pagecache.size }} - - name: NEO4J_dbms_memory_heap_initial__size + - name: NEO4J_server_memory_heap_initial__size value: {{ .app.harness.database.neo4j.memory.heap.initial }} - - name: NEO4J_dbms_memory_heap_max__size + - name: NEO4J_server_memory_heap_max__size value: {{ .app.harness.database.neo4j.memory.heap.max }} - name: NEO4J_dbms_security_auth__enabled value: {{ .app.harness.database.neo4j.dbms_security_auth_enabled | quote }} - name: NEO4J_auth value: {{ .app.harness.database.user }}/{{ .app.harness.database.pass }} + - name: NEO4J_server_config_strict__validation_enabled + value: "false" {{- end }} \ No newline at end of file From 32f637574792c46b963b64bd1d3ab2cfc8765844 Mon Sep 17 00:00:00 2001 From: Jake Conkerton-Darby Date: Thu, 12 Sep 2024 11:35:49 +0100 Subject: [PATCH 12/12] CH-145 Add spec.ingressClassName to ingress template --- deployment-configuration/helm/templates/ingress.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deployment-configuration/helm/templates/ingress.yaml b/deployment-configuration/helm/templates/ingress.yaml index 276d999c8..6e08b7565 100644 --- a/deployment-configuration/helm/templates/ingress.yaml +++ b/deployment-configuration/helm/templates/ingress.yaml @@ -32,7 +32,7 @@ kind: Ingress metadata: name: {{ .Values.ingress.name | quote }} annotations: - kubernetes.io/ingress.class: nginx + kubernetes.io/ingress.class: nginx # Deprecated by Kubernetes, however still required for GKE {{- if and (not .Values.local) $tls }} kubernetes.io/tls-acme: 'true' cert-manager.io/issuer: {{ printf "%s-%s" "letsencrypt" .Values.namespace }} @@ -47,6 +47,7 @@ metadata: nginx.ingress.kubernetes.io/proxy-send-timeout: {{ .Values.proxy.timeout.send | quote }} nginx.ingress.kubernetes.io/use-forwarded-headers: {{ .Values.proxy.forwardedHeaders | quote }} spec: + ingressClassName: nginx rules: {{- range $app := .Values.apps }} {{- if (and $mainapp (and $app.harness.name (eq $app.harness.name $mainapp))) }}