From cbf73a8dd39394ebe084a93526b2e4dc231b804e Mon Sep 17 00:00:00 2001 From: ArnaudTa <33383276+ArnaudTA@users.noreply.github.com> Date: Wed, 29 Jan 2025 20:57:58 +0100 Subject: [PATCH] feat: support new naming system --- .github/workflows/release.yml | 2 +- files/logo.png | Bin 0 -> 6907 bytes package-lock.json | 346 +++++++++++++++------------------- package.json | 12 +- src/env.d.ts | 2 + src/function.ts | 65 ++++--- src/gitlab.ts | 1 - src/index.ts | 6 +- src/infos.ts | 44 ++++- src/utils.ts | 11 +- src/yaml.ts | 93 ++++----- 11 files changed, 299 insertions(+), 283 deletions(-) create mode 100644 files/logo.png diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6413c58..5e86552 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,7 +39,7 @@ jobs: run: rm -rf ./node_modules && npm install --ignore-scripts --omit=dev - name: Zip build folder - run: zip -r ./package.zip ./package.json ./dist ./node_modules + run: zip -r ./package.zip ./package.json ./dist ./node_modules ./files - name: Upload release artifact uses: actions/upload-release-asset@v1 diff --git a/files/logo.png b/files/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c085573b59c9972efc31b44ddcdc50d417bdc5c1 GIT binary patch literal 6907 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.0.0" + }, + "peerDependencies": { + "typescript": "3.x || 4.x || 5.x", + "vitest": ">=2.0.0" + } + }, + "node_modules/@cpn-console/hooks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cpn-console/hooks/-/hooks-4.0.0.tgz", + "integrity": "sha512-/T2I2TtpuofqXOheh/uXXK8ivLbBHBsYQS18o2G/rhd80yzL0GGIXERjw1OElfEpqyQynTz5f4Y9iTXwybI6lw==", + "dependencies": { + "@cpn-console/shared": "^1.3.0", + "json-schema": "^0.4.0", + "vitest-mock-extended": "^2.0.2", + "zod": "^3.24.1" + } + }, "node_modules/@cpn-console/keycloak-plugin": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@cpn-console/keycloak-plugin/-/keycloak-plugin-2.0.6.tgz", - "integrity": "sha512-ofez61fJW8kV8NbflhcOBQ78wucmaty7D9r2AZMt/p4u3NcdDnJ3Qi9yflaD00p/0ui96YZDPoMlNtwQxZLctw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cpn-console/keycloak-plugin/-/keycloak-plugin-2.1.0.tgz", + "integrity": "sha512-ZME+tYZtnLVDLHHQdZNyIPsG/s7HQJdpSUWiTf0svgqmnI6RLfrwrKULabDU75VwJ3IqfPi8lbDulFzadU6Hrw==", "dev": true, "dependencies": { - "@cpn-console/hooks": "^2.5.0", - "@cpn-console/shared": "^1.2.0", + "@cpn-console/hooks": "^3.0.0", + "@cpn-console/shared": "^1.3.0", "@keycloak/keycloak-admin-client": "^26.0.7", "axios": "^1.7.9" } }, + "node_modules/@cpn-console/keycloak-plugin/node_modules/@cpn-console/hooks": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cpn-console/hooks/-/hooks-3.0.0.tgz", + "integrity": "sha512-D146UvkHGLhHEdCmszq00XXeJBfx8T9pZcoJLx2FiaZyyPuRCXMIN06z9x5NcXz/loWBTvl2gHWpwT9xQk0UjA==", + "dev": true, + "dependencies": { + "@cpn-console/shared": "^1.2.0", + "json-schema": "^0.4.0", + "vitest-mock-extended": "^2.0.2", + "zod": "^3.24.1" + } + }, "node_modules/@cpn-console/kubernetes-plugin": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@cpn-console/kubernetes-plugin/-/kubernetes-plugin-2.1.1.tgz", - "integrity": "sha512-BtAeUZgj0Q+G//QcJBSZ7mKOApLH0bLkm15WxCfoiMgWJwwPPSbQ6kTJRw3yMI1L0x30XBFEU+8F0FZo6tNVlQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@cpn-console/kubernetes-plugin/-/kubernetes-plugin-2.3.0.tgz", + "integrity": "sha512-0XyT8fGNpLrgR+7YsA3gw7Y3fYqHEHPo1xcgtKz7kh5BLZ0gG6iblh+Dc6Fu87ZWSd6T3fpxFy6qiLxXzk3hDQ==", "dev": true, "dependencies": { - "@cpn-console/hooks": "^2.5.0", + "@cpn-console/hooks": "^3.0.0", "@cpn-console/shared": "^1.2.0", "@kubernetes-models/argo-cd": "^2.6.2", "@kubernetes/client-node": "^0.22.3", @@ -332,6 +370,18 @@ "request": "^2.88.2" } }, + "node_modules/@cpn-console/kubernetes-plugin/node_modules/@cpn-console/hooks": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cpn-console/hooks/-/hooks-3.0.0.tgz", + "integrity": "sha512-D146UvkHGLhHEdCmszq00XXeJBfx8T9pZcoJLx2FiaZyyPuRCXMIN06z9x5NcXz/loWBTvl2gHWpwT9xQk0UjA==", + "dev": true, + "dependencies": { + "@cpn-console/shared": "^1.2.0", + "json-schema": "^0.4.0", + "vitest-mock-extended": "^2.0.2", + "zod": "^3.24.1" + } + }, "node_modules/@cpn-console/kubernetes-plugin/node_modules/@kubernetes/client-node": { "version": "0.22.3", "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.22.3.tgz", @@ -355,13 +405,14 @@ } }, "node_modules/@cpn-console/shared": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@cpn-console/shared/-/shared-1.2.0.tgz", - "integrity": "sha512-NvZwaumEMqiYvZrGOzElLdhyvnYgHGzfNqZsSduiKCgCpIXUAg9LagJwru/SXElYzqLGHjWg3+h3YHipVXPp1A==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@cpn-console/shared/-/shared-1.3.0.tgz", + "integrity": "sha512-c6lhxGzEQ8Kdaw4LHCUU67Ww5z/HbC6oku3SIG9dOhI7dpbPWGFEClT3ZdkURf/EkfgrTPNEhJPyT98Ez2DhjA==", "dependencies": { - "@ts-rest/core": "^3.45.2", - "zod": "^3.23.8", - "zod-validation-error": "^3.3.0" + "@ts-rest/core": "^3.51.0", + "short-uuid": "^5.2.0", + "zod": "^3.24.1", + "zod-validation-error": "^3.4.0" } }, "node_modules/@cpn-console/ts-config": { @@ -371,124 +422,65 @@ "dev": true }, "node_modules/@cpn-console/vault-plugin": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@cpn-console/vault-plugin/-/vault-plugin-2.2.1.tgz", - "integrity": "sha512-klojPozsy/+R8rVSxuvoUU15M27dxqger7LJyukSkAqNyUsCrq2XxIKzuJGV1E95oOQi1SeqKU2V4ncPLAbKNA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cpn-console/vault-plugin/-/vault-plugin-2.2.2.tgz", + "integrity": "sha512-6ZhzGgWWwH5W+TqlRG7f4eWr3DHKQH8TrPxdNZlmXI7suOcYOVY4dkZVtrtU1qKHI+0JBd1RY6FHtAWbPgZ0cg==", "dev": true, "dependencies": { "@cpn-console/hooks": "^2.5.0", "@cpn-console/shared": "^1.2.0", - "@kubernetes/client-node": "^0.21.0", - "axios": "^1.7.2" + "@kubernetes/client-node": "^0.22.3", + "axios": "^1.7.9" + } + }, + "node_modules/@cpn-console/vault-plugin/node_modules/@cpn-console/hooks": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cpn-console/hooks/-/hooks-2.5.0.tgz", + "integrity": "sha512-3SkGxPLEWX+7teNpN8G/m1wZA2zr80aJoTsFBtjQuS56ld1N9QW7y6TMtjdAlsu86bc3L7YMmbcZPnU+qDbpUw==", + "dev": true, + "dependencies": { + "@cpn-console/shared": "^1.2.0", + "json-schema": "^0.4.0", + "vitest-mock-extended": "^1.3.1", + "zod": "^3.23.8" } }, "node_modules/@cpn-console/vault-plugin/node_modules/@kubernetes/client-node": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.21.0.tgz", - "integrity": "sha512-yYRbgMeyQbvZDHt/ZqsW3m4lRefzhbbJEuj8sVXM+bufKrgmzriA2oq7lWPH/k/LQIicAME9ixPUadTrxIF6dQ==", + "version": "0.22.3", + "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.22.3.tgz", + "integrity": "sha512-dG8uah3+HDJLpJEESshLRZlAZ4PgDeV9mZXT0u1g7oy4KMRzdZ7n5g0JEIlL6QhK51/2ztcIqURAnjfjJt6Z+g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@types/js-yaml": "^4.0.1", - "@types/node": "^20.1.1", - "@types/request": "^2.47.1", - "@types/ws": "^8.5.3", "byline": "^5.0.0", "isomorphic-ws": "^5.0.0", "js-yaml": "^4.1.0", - "jsonpath-plus": "^8.0.0", + "jsonpath-plus": "^10.2.0", "request": "^2.88.0", "rfc4648": "^1.3.0", "stream-buffers": "^3.0.2", "tar": "^7.0.0", "tslib": "^2.4.1", - "ws": "^8.11.0" + "ws": "^8.18.0" }, "optionalDependencies": { - "openid-client": "^5.3.0" - } - }, - "node_modules/@cpn-console/vault-plugin/node_modules/@types/node": { - "version": "20.17.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.14.tgz", - "integrity": "sha512-w6qdYetNL5KRBiSClK/KWai+2IMEJuAj+EujKCumalFOwXtvOXaEan9AuwcRID2IcOIAWSIfR495hBtgKlx2zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@cpn-console/vault-plugin/node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", - "dev": true, - "license": "MIT", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/@cpn-console/vault-plugin/node_modules/jsonpath-plus": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-8.1.0.tgz", - "integrity": "sha512-qVTiuKztFGw0dGhYi3WNqvddx3/SHtyDT0xJaeyz4uP0d1tkpG+0y5uYQ4OcIo1TLAz3PE/qDOW9F0uDt3+CTw==", - "dev": true, - "license": "MIT", - "bin": { - "jsonpath": "bin/jsonpath-cli.js", - "jsonpath-plus": "bin/jsonpath-cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@cpn-console/vault-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "openid-client": "^6.1.3" } }, - "node_modules/@cpn-console/vault-plugin/node_modules/openid-client": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz", - "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==", + "node_modules/@cpn-console/vault-plugin/node_modules/vitest-mock-extended": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/vitest-mock-extended/-/vitest-mock-extended-1.3.2.tgz", + "integrity": "sha512-wnpym69MFYBUbUT6vrM/E4sF0bylow+N/RBBTZWn4rO/UFLusvuCrb3CMe3K4663+iBzplrhk0hQ2O246rFrqQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "jose": "^4.15.9", - "lru-cache": "^6.0.0", - "object-hash": "^2.2.0", - "oidc-token-hash": "^5.0.3" + "ts-essentials": ">=10.0.0" }, - "funding": { - "url": "https://github.com/sponsors/panva" + "peerDependencies": { + "typescript": "3.x || 4.x || 5.x", + "vitest": ">=2.0.0" } }, - "node_modules/@cpn-console/vault-plugin/node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cpn-console/vault-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/@es-joy/jsdoccomment": { "version": "0.50.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.0.tgz", @@ -1275,13 +1267,6 @@ } } }, - "node_modules/@types/caseless": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", - "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -1384,35 +1369,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/request": { - "version": "2.48.12", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", - "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - } - }, - "node_modules/@types/request/node_modules/form-data": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.2.tgz", - "integrity": "sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/@types/stream-buffers": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.7.tgz", @@ -1441,13 +1397,6 @@ "node": ">=8" } }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -1942,6 +1891,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", + "license": "MIT" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -6060,17 +6015,6 @@ "url": "https://github.com/sponsors/panva" } }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", @@ -6083,17 +6027,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/oidc-token-hash": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", - "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": "^10.13.0 || >=12.0.0" - } - }, "node_modules/onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -7008,6 +6941,32 @@ "node": ">=8" } }, + "node_modules/short-uuid": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/short-uuid/-/short-uuid-5.2.0.tgz", + "integrity": "sha512-296/Nzi4DmANh93iYBwT4NoYRJuHnKEzefrkSagQbTH/A6NTaB68hSPDjm5IlbI5dx9FXdmtqPcj6N5H+CPm6w==", + "license": "MIT", + "dependencies": { + "any-base": "^1.1.0", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/short-uuid/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -7603,9 +7562,10 @@ } }, "node_modules/ts-essentials": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-10.0.1.tgz", - "integrity": "sha512-HPH+H2bkkO8FkMDau+hFvv7KYozzned9Zr1Urn7rRPXMF4mZmCKOq+u4AI1AAW+2bofIOXTuSdKo9drQuni2dQ==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-10.0.4.tgz", + "integrity": "sha512-lwYdz28+S4nicm+jFi6V58LaAIpxzhg9rLdgNC1VsdP/xiFBseGhF1M/shwCk6zMmwahBZdXcl34LVHrEang3A==", + "license": "MIT", "peerDependencies": { "typescript": ">=4.5.0" }, @@ -8025,9 +7985,10 @@ } }, "node_modules/vitest-mock-extended": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/vitest-mock-extended/-/vitest-mock-extended-1.3.2.tgz", - "integrity": "sha512-wnpym69MFYBUbUT6vrM/E4sF0bylow+N/RBBTZWn4rO/UFLusvuCrb3CMe3K4663+iBzplrhk0hQ2O246rFrqQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/vitest-mock-extended/-/vitest-mock-extended-2.0.2.tgz", + "integrity": "sha512-n3MBqVITKyclZ0n0y66hkT4UiiEYFQn9tteAnIxT0MPz1Z8nFcPUG3Cf0cZOyoPOj/cq6Ab1XFw2lM/qM5EDWQ==", + "license": "MIT", "dependencies": { "ts-essentials": ">=10.0.0" }, @@ -8451,9 +8412,10 @@ } }, "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index a2987e4..e8acfe9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@cpn-console/observability-plugin", "type": "module", - "version": "0.1.2", + "version": "0.1.3-rc1", "description": "Loki plugin for DSO console", "exports": { ".": { @@ -26,7 +26,7 @@ "prepare": "husky" }, "dependencies": { - "@cpn-console/hooks": "^2.5.0", + "@cpn-console/hooks": "^4.0.0", "@gitbeaker/core": "~40.6.0", "@gitbeaker/requester-utils": "~40.6.0", "@gitbeaker/rest": "~40.6.0", @@ -39,12 +39,12 @@ "devDependencies": { "@antfu/eslint-config": "^3.16.0", "@cpn-console/eslint-config": "^1.0.2", - "@cpn-console/gitlab-plugin": "^3.0.0", - "@cpn-console/keycloak-plugin": "^2.0.6", - "@cpn-console/kubernetes-plugin": "^2.1.1", + "@cpn-console/gitlab-plugin": "^3.1.0", + "@cpn-console/keycloak-plugin": "^2.1.0", + "@cpn-console/kubernetes-plugin": "^2.3.0", "@cpn-console/shared": "^1.2.0", "@cpn-console/ts-config": "^1.1.0", - "@cpn-console/vault-plugin": "^2.2.1", + "@cpn-console/vault-plugin": "^2.2.2", "@types/js-yaml": "^4.0.9", "@types/node": "^22.10.7", "@types/uuid": "^10.0.0", diff --git a/src/env.d.ts b/src/env.d.ts index a2f8c1e..2ffe8e6 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -2,3 +2,5 @@ /// /// /// +/// +/// diff --git a/src/function.ts b/src/function.ts index e4ad5e5..959f970 100644 --- a/src/function.ts +++ b/src/function.ts @@ -1,13 +1,19 @@ -import type { Environment, Project, StepCall, UserObject } from '@cpn-console/hooks' +import type { Environment, PluginResult, Project, StepCall, UserObject } from '@cpn-console/hooks' +import type { KeycloakProjectApi } from '@cpn-console/keycloak-plugin/types/class.js' import type { Gitlab as GitlabInterface } from '@gitbeaker/core' -import type { BaseParams, Stage } from './utils.js' -import { parseError } from '@cpn-console/hooks' -import { removeTrailingSlash, requiredEnv } from '@cpn-console/shared' +import { parseError, specificallyDisabled } from '@cpn-console/hooks' +import { compressUUID, removeTrailingSlash, requiredEnv } from '@cpn-console/shared' import { Gitlab } from '@gitbeaker/rest' import { deleteKeycloakGroup, ensureKeycloakGroups } from './keycloak.js' +import { isNewNsName, type TenantKeycloakMapper } from './utils.js' import { deleteGitlabYamlConfig, upsertGitlabConfig } from './yaml.js' -const getBaseParams = (project: Project, stage: Stage): BaseParams => ({ organizationName: project.organization.name, projectName: project.name, stage }) +const okSkipped: PluginResult = { + status: { + result: 'OK', + message: 'Plugin disabled', + }, +} export type ListPerms = Record<'prod' | 'hors-prod', Record<'view' | 'edit', UserObject['id'][]>> @@ -58,35 +64,46 @@ function getGitlabApi(): GitlabInterface { export const upsertProject: StepCall = async (payload) => { try { + if (specificallyDisabled(payload.config.observability?.enabled)) { + return okSkipped + } // init args const project = payload.args - const keycloakApi = payload.apis.keycloak - const vaultApi = payload.apis.vault + const keycloakApi = payload.apis.keycloak as KeycloakProjectApi // init gitlab api const gitlabApi = getGitlabApi() const keycloakRootGroupPath = await keycloakApi.getProjectGroupPath() + const tenantRbacProd = [`${keycloakRootGroupPath}/grafana/prod-RW`, `${keycloakRootGroupPath}/grafana/prod-RO`] + const tenantRbacHProd = [`${keycloakRootGroupPath}/grafana/hprod-RW`, `${keycloakRootGroupPath}/grafana/hprod-RO`] + + const compressedUUID = compressUUID(project.id) + + const tenantsToCreate: TenantKeycloakMapper = {} + + for (const environment of payload.args.environments) { + if (!environment.apis.kubernetes) { + throw new Error(`no kubernetes apis on environment ${environment.name}`) + } + const gen = isNewNsName(await environment.apis.kubernetes.getNsName()) ? compressedUUID : project.slug + if (environment.stage === 'prod') { + tenantsToCreate[`prod-${gen}`] = tenantRbacProd + } else { + tenantsToCreate[`hprod-${gen}`] = tenantRbacHProd + } + } - const hasProd = project.environments.find(env => env.stage === 'prod') - const hasNonProd = project.environments.find(env => env.stage !== 'prod') - const hProdParams = getBaseParams(project, 'hprod') - const prodParams = getBaseParams(project, 'prod') const listPerms = getListPrems(project.environments) - await Promise.all([ + const [_, yamlResult] = await Promise.all([ ensureKeycloakGroups(listPerms, keycloakApi), // Upsert or delete Gitlab config based on prod/non-prod environment - ...(hasProd - ? [await upsertGitlabConfig(prodParams, keycloakRootGroupPath, project, gitlabApi, vaultApi)] - : [await deleteGitlabYamlConfig(prodParams, project, gitlabApi)]), - ...(hasNonProd - ? [await upsertGitlabConfig(hProdParams, keycloakRootGroupPath, project, gitlabApi, vaultApi)] - : [await deleteGitlabYamlConfig(hProdParams, project, gitlabApi)]), + upsertGitlabConfig(project, gitlabApi, tenantsToCreate), ]) return { status: { result: 'OK', - message: 'Created', + message: yamlResult, }, } } catch (error) { @@ -102,16 +119,16 @@ export const upsertProject: StepCall = async (payload) => { export const deleteProject: StepCall = async (payload) => { try { + if (specificallyDisabled(payload.config.observability?.enabled)) { + return okSkipped + } const project = payload.args const gitlabApi = getGitlabApi() - const keycloakApi = payload.apis.keycloak - const hProdParams = getBaseParams(project, 'hprod') - const prodParams = getBaseParams(project, 'prod') + const keycloakApi = payload.apis.keycloak as KeycloakProjectApi await Promise.all([ deleteKeycloakGroup(keycloakApi), - deleteGitlabYamlConfig(prodParams, project, gitlabApi), - deleteGitlabYamlConfig(hProdParams, project, gitlabApi), + deleteGitlabYamlConfig(project, gitlabApi), ]) return { diff --git a/src/gitlab.ts b/src/gitlab.ts index d7cd501..b02502b 100644 --- a/src/gitlab.ts +++ b/src/gitlab.ts @@ -55,7 +55,6 @@ export async function getGitlabYamlFileContent(api: IGitlab, project: Project, f // Fonction pour éditer, committer et pousser un fichier YAML export async function commitAndPushYamlFile(api: IGitlab, project: Project, filePath: string, branch: string, commitMessage: string, yamlString: string): Promise { - console.log('yamlString: ', yamlString) const encodedContent = Buffer.from(yamlString).toString('utf-8') try { // Vérifier si le fichier existe déjà diff --git a/src/index.ts b/src/index.ts index 82c2785..43ecc41 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import type { Plugin } from '@cpn-console/hooks' +import type { DeclareModuleGenerator, Plugin } from '@cpn-console/hooks' import { requiredEnv } from '@cpn-console/shared' import { deleteProject, upsertProject } from './function.js' import infos from './infos.js' @@ -19,3 +19,7 @@ export const plugin: Plugin = { }, start: () => { requiredEnv('GRAFANA_URL') }, // to check is the variable is set, unless it crashes the app } + +declare module '@cpn-console/hooks' { + interface Config extends DeclareModuleGenerator {} +} diff --git a/src/infos.ts b/src/infos.ts index d7f07bb..3565237 100644 --- a/src/infos.ts +++ b/src/infos.ts @@ -1,21 +1,49 @@ import type { ServiceInfos } from '@cpn-console/hooks' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { compressUUID, ENABLED } from '@cpn-console/shared' import { getConfig } from './utils.js' -const infos: ServiceInfos = { +const imageData = Buffer.from((readFileSync(join(import.meta.dirname, '../files/logo.png'))).toString('base64')) + +const infos = { name: 'observability', - to: ({ project, organization }) => [ + to: ({ project }) => [ + { + to: `${getConfig().grafanaUrl}/prod-${compressUUID(project.id)}`, + description: 'Production', + }, + { + to: `${getConfig().grafanaUrl}/prod-${project.slug}`, + description: 'Production, ancien', + }, { - to: `${getConfig().grafanaUrl}/hprod-${organization}-${project}`, - title: 'Hors production', + to: `${getConfig().grafanaUrl}/hprod-${compressUUID(project.id)}`, + description: 'Hors production', }, { - to: `${getConfig().grafanaUrl}/prod-${organization}-${project}`, - title: 'Production', + to: `${getConfig().grafanaUrl}/hprod-${project.slug}`, + description: 'Hors production, ancien', }, ], title: 'Grafana', - imgSrc: 'https://upload.wikimedia.org/wikipedia/commons/a/a1/Grafana_logo.svg', + imgSrc: `data:image/png;base64,${imageData}`, description: 'Grafana est un outil de métrique et de logs', -} + config: { + global: [{ + kind: 'switch', + key: 'enabled', + initialValue: ENABLED, + permissions: { + admin: { read: true, write: true }, + user: { read: true, write: false }, + }, + title: 'Activer le plugin', + value: ENABLED, + description: 'Activer le plugin', + }], + project: [], + }, +} as const satisfies ServiceInfos export default infos diff --git a/src/utils.ts b/src/utils.ts index 2e8ebc8..9347ba5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -62,8 +62,11 @@ export function getCustomK8sApi(): CustomObjectsApi { export type Stage = 'prod' | 'hprod' -export interface BaseParams { - organizationName: string - projectName: string - stage: Stage +export interface TenantKeycloakMapper { + [x: string]: string[] +} + +const re = /[a-z0-9]{25}--[a-z0-9]{25}/ +export function isNewNsName(ns: string) { + return re.test(ns) } diff --git a/src/yaml.ts b/src/yaml.ts index bbf2e52..5d97f42 100644 --- a/src/yaml.ts +++ b/src/yaml.ts @@ -1,11 +1,10 @@ import type { Project } from '@cpn-console/hooks' -import type { VaultProjectApi } from '@cpn-console/vault-plugin/types/class.js' import type { Gitlab as GitlabInterface } from '@gitbeaker/core' import type { Project as GitlabProject, Group, } from './gitlab.js' -import type { BaseParams } from './utils.js' +import type { TenantKeycloakMapper } from './utils.js' // @ts-ignore import yaml from 'js-yaml' import { @@ -98,7 +97,7 @@ async function findOrCreateValuesFile(gitlabApi: GitlabInterface, project: Gitla } } -export async function upsertGitlabConfig(params: BaseParams, keycloakRootGroupPath: string, project: Project, gitlabApi: GitlabInterface, _vaultApi: VaultProjectApi) { +export async function upsertGitlabConfig(project: Project, gitlabApi: GitlabInterface, tenants: TenantKeycloakMapper) { // Déplacer toute la logique de création ou de récupération de groupe et de repo ici const lokiGroupName = 'observability' const lokiRepoName = 'observability' @@ -109,35 +108,53 @@ export async function upsertGitlabConfig(params: BaseParams, keycloakRootGroupPa const file = await findOrCreateValuesFile(gitlabApi, gitlabLokiRepo) let yamlFile = await readYamlFile(Buffer.from(file, 'utf-8').toString('utf-8')) - const tenantName = `${params.stage}-${params.organizationName}-${params.projectName}` - const tenantRbac = [`${keycloakRootGroupPath}/grafana/${params.stage}-RW`, `${keycloakRootGroupPath}/grafana/${params.stage}-RO`] - - // const infraReposUrls: string[] = [] - // for (const repo of project.repositories) { - // if (repo.isInfra) { - // const repoInternalUrl = (await vaultApi.read(`${params.organizationName}/${params.projectName}/${repo.internalRepoName}-mirror`)).data.GIT_OUTPUT_URL as string - // if (repoInternalUrl) { - // infraReposUrls.push(`https://${repoInternalUrl}`) - // } - // } - // } - - const projectData: ProjectLoki = { - name: tenantName, - groups: tenantRbac, + let needUpdates = false + + const shouldBeRemoved: string[] = [] + let notFoundTenants: string[] = Object.keys(tenants) + + for (const tenant of yamlFile.global.tenants) { + if (tenant.uuid !== project.id) continue + if (tenant.name in tenants) { + if (tenant.groups.toString() !== tenants[tenant.name].toString()) { + needUpdates = true + tenant.groups = structuredClone(tenants[tenant.name]) + } + notFoundTenants = notFoundTenants.filter(notFoundTenant => notFoundTenant !== tenant.name) + } else { + needUpdates = true + shouldBeRemoved.push(tenant.name) + } + } + + const newTenants = notFoundTenants.map((notFoundTenant): ProjectLoki => ({ + groups: structuredClone(tenants[notFoundTenant]), + name: notFoundTenant, uuid: project.id, - // urls: infraReposUrls, + })) + + console.log({ + existing: yamlFile.global.tenants, + newTenants, + shouldBeRemoved, + toWrite: [...yamlFile.global.tenants.filter(tenant => tenant.uuid !== project.id || !shouldBeRemoved.includes(tenant.name)), ...newTenants], + }) + + yamlFile = { + ...yamlFile, + global: { + ...yamlFile.global, + tenants: [...yamlFile.global.tenants.filter(tenant => tenant.uuid !== project.id || !shouldBeRemoved.includes(tenant.name)), ...newTenants], + }, } - if (findTenantByName(yamlFile, tenantName)) { - return + if (!needUpdates && !newTenants.length) { + return 'Already up-to-date' } - // Modifier le fichier YAML et commiter - yamlFile = addYamlObjectToRepo(yamlFile, projectData) const yamlString = writeYamlFile(yamlFile) - return commitAndPushYamlFile( + await commitAndPushYamlFile( gitlabApi, gitlabLokiRepo, valuesPath, @@ -145,9 +162,10 @@ export async function upsertGitlabConfig(params: BaseParams, keycloakRootGroupPa `Add project ${project.name}`, yamlString, ) + return `created: ${newTenants.map(tenant => tenant.name)}, deleted: ${shouldBeRemoved}` } -export async function deleteGitlabYamlConfig(params: BaseParams, project: Project, gitlabApi: GitlabInterface) { +export async function deleteGitlabYamlConfig(project: Project, gitlabApi: GitlabInterface) { // Même logique de groupe et de repo que pour l'upsert const lokiGroupName = 'observability' const lokiRepoName = 'observability' @@ -158,16 +176,13 @@ export async function deleteGitlabYamlConfig(params: BaseParams, project: Projec const file = await findOrCreateValuesFile(gitlabApi, gitlabLokiRepo) let yamlFile = await readYamlFile(Buffer.from(file, 'utf-8').toString('utf-8')) - const tenantName = `${params.stage}-${params.organizationName}-${params.projectName}` - // Rechercher le projet à supprimer - const projectToDelete = yamlFile.global.tenants.find(tenant => tenant.name === tenantName) - if (!projectToDelete) { + if (!yamlFile.global.tenants.find(tenant => tenant.uuid === project.id)) { return } // Modifier le fichier YAML et commiter - yamlFile = removeRepo(yamlFile, projectToDelete.uuid) + yamlFile = removeProject(yamlFile, project.id) const yamlString = writeYamlFile(yamlFile) return commitAndPushYamlFile( @@ -180,21 +195,7 @@ export async function deleteGitlabYamlConfig(params: BaseParams, project: Projec ) } -function addYamlObjectToRepo(data: YamlLokiData, newProject: ProjectLoki): YamlLokiData { - return { - ...data, - global: { - ...data.global, - tenants: [...data.global.tenants, newProject], - }, - } -} - -function findTenantByName(data: YamlLokiData, name: string): ProjectLoki | undefined { - return data.global.tenants.find(tenant => tenant.name === name) -} - -function removeRepo(data: YamlLokiData, uuid: string): YamlLokiData { +function removeProject(data: YamlLokiData, uuid: string): YamlLokiData { return { ...data, global: {