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/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..4775b82 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,28 @@ +{ + "recommendations": [ + // Cross-editor config + "editorconfig.editorconfig", + // Git + "mhutchie.git-graph", + "eamodio.gitlens", + // Node / npm + "christian-kohler.npm-intellisense", + // JavaScript + "dbaeumer.vscode-eslint", + // Vue.js + "vue.volar", + "vue.vscode-typescript-vue-plugin", + // Vitejs + "antfu.vite", + "antfu.browse-lite", + // CSS + "csstools.postcss", + "stylelint.vscode-stylelint", + // YAML + "redhat.vscode-yaml", + // Makdown + "yzhang.markdown-all-in-one", + // Kubernetes + "ms-kubernetes-tools.vscode-kubernetes-tools" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..55297a8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. + // Pointez pour afficher la description des attributs existants. + // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Remote", + "type": "node", + "request": "attach", + "port": 9229, + "address": "127.0.0.1", + "restart": true, + "localRoot": "${workspaceFolder}/apps/server", + "remoteRoot": "/app/apps/server", + "skipFiles": [ + "/**", + "${workspaceFolder}/node_modules/**/*.js" + ] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5e7fe75 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,120 @@ +{ + // visuals + "window.autoDetectColorScheme": true, + "editor.fontLigatures": "'ss01', 'ss02', 'ss03', 'ss06', 'zero'", + "editor.cursorBlinking": "phase", + "editor.suggestSelection": "first", + "editor.wordWrap": "on", + "editor.bracketPairColorization.enabled": true, + "editor.tabSize": 2, + "search.exclude": { + "**/.git": true, + "**/.nuxt": true, + "**/.pnpm": true, + "**/.yarn": true, + "**/.turbo": true, + "**/dist/**": true, + "**/out/**": true, + "**/logs": true, + "**/node_modules": true, + "**/package-lock.json": true, + "**/pnpm-lock.yaml": true, + "**/yarn.lock": true + }, + // general + "editor.unicodeHighlight.invisibleCharacters": false, + "workbench.startupEditor": "none", + // git + "git.autofetch": true, + "git.untrackedChanges": "separate", + // github + "githubPullRequests.pullBranch": "never", + // eslint + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "vue", + "html", + "markdown", + "json", + "jsonc", + "yaml", + "github-actions-workflow", + "toml", + "xml", + "gql", + "graphql", + "astro", + "svelte", + "css", + "less", + "scss", + "pcss", + "postcss" + ], + // stylelint + "css.validate": true, + "less.validate": true, + "scss.validate": true, + "files.associations": { + "*.css": "css" + }, + // languages + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "javascript.preferences.quoteStyle": "single", + "javascript.preferences.importModuleSpecifierEnding": "js", + "javascript.suggest.completeJSDocs": true, + "javascript.suggest.jsdoc.generateReturns": true, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "typescript.preferences.quoteStyle": "single", + "typescript.preferences.importModuleSpecifierEnding": "js", + "typescript.suggest.completeJSDocs": true, + "typescript.suggest.jsdoc.generateReturns": true, + "[vue]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[css]": { + "editor.defaultFormatter": "stylelint.vscode-stylelint" + }, + "[html]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[markdown]": { + "editor.quickSuggestions": { + "other": true, + "comments": true, + "strings": true + }, + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "editor.defaultFormatter": "yzhang.markdown-all-in-one" + }, + // conventional commits + "conventionalCommits.showNewVersionNotes": false, + // kubernetes + "vs-kubernetes": { + "vs-kubernetes.crd-code-completion": "enabled" + }, + "vscode-kubernetes.log-viewer.follow": true, + "vscode-kubernetes.log-viewer.timestamp": false, + "vscode-kubernetes.log-viewer.since": -1, + "vscode-kubernetes.log-viewer.tail": -1, + "vscode-kubernetes.log-viewer.destination": "Webview", + "vscode-kubernetes.log-viewer.wrap": true, + // sonarqube + "sonarlint.connectedMode.project": { + "connectionId": "https://sonarqube.fabrique-numerique.fr", + "projectKey": "cloud-pi-native_console_AYsa46O31ebDtzs-pYyZ" + }, + "prisma-smart-formatter.typescript.defaultFormatter": "dbaeumer.vscode-eslint", + "prisma-smart-formatter.prisma.defaultFormatter": "Prisma.prisma" +} diff --git a/files/logo.png b/files/logo.png new file mode 100644 index 0000000..2ac9ef9 Binary files /dev/null and b/files/logo.png differ diff --git a/package-lock.json b/package-lock.json index 664650d..da4ce02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,14 @@ { - "name": "@cpn-console/loki-plugin", - "version": "0.0.1", + "name": "@cpn-console/observability-plugin", + "version": "0.1.3-rc1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@cpn-console/loki-plugin", - "version": "0.0.1", + "name": "@cpn-console/observability-plugin", + "version": "0.1.3-rc1", "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", @@ -21,12 +21,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", @@ -279,9 +279,9 @@ "license": "ISC" }, "node_modules/@cpn-console/gitlab-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cpn-console/gitlab-plugin/-/gitlab-plugin-3.0.0.tgz", - "integrity": "sha512-qo8ILQtxjbGiJkN/UjhWe0HERZnnwPg01hGqAdPdrlhCIRFYN8z9UG8mJifzVqw/k8C/nRjdCPoOOFRfkGv5vA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@cpn-console/gitlab-plugin/-/gitlab-plugin-3.1.0.tgz", + "integrity": "sha512-ZO/aPhAXpVXd+FrqrQkg9oUx1qid0pWTQagx8y+aZS7rE6nKmGF8f27T1nt8m0FzmDcboLw8ITTLPeolkX4F6g==", "dev": true, "dependencies": { "@cpn-console/hooks": "^2.5.0", @@ -294,10 +294,11 @@ "js-yaml": "4.1.0" } }, - "node_modules/@cpn-console/hooks": { + "node_modules/@cpn-console/gitlab-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", @@ -305,25 +306,62 @@ "zod": "^3.23.8" } }, + "node_modules/@cpn-console/gitlab-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", + "dependencies": { + "ts-essentials": ">=10.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..bc8ca7a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@cpn-console/observability-plugin", "type": "module", - "version": "0.1.2", + "version": "1.0.0", "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..40bab4b 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 { deleteGitlabYamlConfig, upsertGitlabConfig } from './yaml.js' +import { isNewNsName } from './utils.js' +import { deleteGitlabYamlConfig, type ProjectLoki, type Type, 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,67 @@ 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 projectValue: ProjectLoki = { + projectName: project.slug, + envs: { + hprod: { + groups: tenantRbacHProd, + tenants: {}, + }, + prod: { + groups: tenantRbacProd, + tenants: {}, + }, + }, + } + + for (const environment of payload.args.environments) { + if (!environment.apis.kubernetes) { + throw new Error(`no kubernetes apis on environment ${environment.name}`) + } + const namespace = await environment.apis.kubernetes.getNsName() + const name = isNewNsName(namespace) ? compressedUUID : project.slug + console.log({ namespace, name }) + const env: Type = environment.stage === 'prod' ? 'prod' : 'hprod' + projectValue.envs[env].tenants[`${env}-${name}`] = {} + } + + if (projectValue.envs.hprod && !Object.values(projectValue.envs.hprod?.tenants).length) { + // @ts-ignore + delete projectValue.envs.hprod + } + if (projectValue.envs.prod && !Object.values(projectValue.envs.prod?.tenants).length) { + // @ts-ignore + delete projectValue.envs.prod + } - 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([ - 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)]), - ]) + // Upsert or delete Gitlab config based on prod/non-prod environment + const yamlResult = await upsertGitlabConfig(project, gitlabApi, projectValue) + await ensureKeycloakGroups(listPerms, keycloakApi) return { status: { result: 'OK', - message: 'Created', + message: yamlResult, + }, + store: { + instances: Object.keys(projectValue.envs).join(','), }, } } catch (error) { @@ -102,16 +140,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..3a9d14e 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,8 @@ 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 {} + interface ProjectStore extends DeclareModuleGenerator {} +} diff --git a/src/infos.ts b/src/infos.ts index d7f07bb..cc0b108 100644 --- a/src/infos.ts +++ b/src/infos.ts @@ -1,21 +1,75 @@ import type { ServiceInfos } from '@cpn-console/hooks' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { 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: `${getConfig().grafanaUrl}/hprod-${organization}-${project}`, - title: 'Hors production', - }, - { - to: `${getConfig().grafanaUrl}/prod-${organization}-${project}`, - title: 'Production', - }, - ], + // @ts-ignore retro compatibility + to: ({ project, projectId, organization, store }) => { + let isInfV9 = false + const params = { + id: '', + slug: '', + } + const grafanaUrl = getConfig().grafanaUrl + if (typeof project === 'string' && typeof organization === 'string') { + params.id = projectId + params.slug = `${organization}-${project}` + isInfV9 = true + } else { + params.id = project.id + params.slug = project.slug + } + const urls: Array<{ to: string, title?: string, description: string }> = [] + const instances = store.observability?.instances?.split(',') ?? [] + if (instances.includes('hprod')) { + urls.push({ + to: `${grafanaUrl}/hprod-${params.slug}`, + title: isInfV9 ? 'Hors production' : undefined, + description: 'Hors production', + }) + } + if (instances.includes('prod')) { + urls.push({ + to: `${grafanaUrl}/prod-${params.slug}`, + title: isInfV9 ? 'Production' : undefined, + description: 'Production', + }) + } + return urls + }, 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: [{ + kind: 'text', + key: 'instances', + permissions: { + admin: { read: false, write: false }, + user: { read: false, write: false }, + }, + title: 'Instances actives', + value: '', + description: '', + }], + }, +} as const satisfies ServiceInfos export default infos diff --git a/src/utils.ts b/src/utils.ts index 2e8ebc8..28c829c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -62,8 +62,16 @@ export function getCustomK8sApi(): CustomObjectsApi { export type Stage = 'prod' | 'hprod' -export interface BaseParams { - organizationName: string - projectName: string - stage: Stage +export interface TenantInfo { + groups: string[] + type: 'prod' | 'hprod' + name: string // tenant name, short-uuid or slug +} +export interface TenantKeycloakMapper { + [x: string]: TenantInfo // fullName, type + (short-uuid or slug) +} + +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..f8f8526 100644 --- a/src/yaml.ts +++ b/src/yaml.ts @@ -1,11 +1,9 @@ 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' // @ts-ignore import yaml from 'js-yaml' import { @@ -20,16 +18,29 @@ import { const valuesPath = 'helm/values.yaml' const valuesBranch = 'main' -interface ProjectLoki { - name: string - groups: string[] - uuid: string +export type Type = 'prod' | 'hprod' +interface Tenant {} + +interface Env { + groups?: string[] + tenants: { + [x: `${Type}-${string}`]: Tenant + } +} +export interface ProjectLoki { + projectName: string // slug + envs: { + prod: Env + hprod: Env + } // urls: string[] } interface YamlLokiData { - global: { - tenants: ProjectLoki[] + global?: { + projects?: { + [x: string]: ProjectLoki + } } } @@ -98,7 +109,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, projectValue: ProjectLoki) { // 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' @@ -107,47 +118,30 @@ export async function upsertGitlabConfig(params: BaseParams, keycloakRootGroupPa // Récupérer ou créer le fichier values.yaml 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, - uuid: project.id, - // urls: infraReposUrls, - } - - if (findTenantByName(yamlFile, tenantName)) { - return - } + const yamlFile = await readYamlFile(Buffer.from(file, 'utf-8').toString('utf-8')) - // Modifier le fichier YAML et commiter - yamlFile = addYamlObjectToRepo(yamlFile, projectData) - const yamlString = writeYamlFile(yamlFile) + const projects = yamlFile.global?.projects || {} + projects[project.id] = projectValue + const yamlString = writeYamlFile({ + ...yamlFile, + global: { + ...yamlFile.global, + projects, + }, + }) - return commitAndPushYamlFile( + await commitAndPushYamlFile( gitlabApi, gitlabLokiRepo, valuesPath, valuesBranch, - `Add project ${project.name}`, + `Update project ${project.slug}`, yamlString, ) + return `Update: ${project.slug}` } -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' @@ -156,19 +150,16 @@ export async function deleteGitlabYamlConfig(params: BaseParams, project: Projec // Récupérer le fichier values.yaml 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 yamlFile = await readYamlFile(Buffer.from(file, 'utf-8').toString('utf-8')) // Rechercher le projet à supprimer - const projectToDelete = yamlFile.global.tenants.find(tenant => tenant.name === tenantName) - if (!projectToDelete) { + if (yamlFile.global?.projects && !(project.id in yamlFile.global.projects)) { return } // Modifier le fichier YAML et commiter - yamlFile = removeRepo(yamlFile, projectToDelete.uuid) - const yamlString = writeYamlFile(yamlFile) + const yamlFileStripped = removeProject(yamlFile, project.id) + const yamlString = writeYamlFile(yamlFileStripped) return commitAndPushYamlFile( gitlabApi, @@ -180,26 +171,38 @@ 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 removeProject(data: YamlLokiData, uuid: string): YamlLokiData { + const strippedData = structuredClone(data) + delete strippedData.global?.projects?.[uuid] + return strippedData } -function findTenantByName(data: YamlLokiData, name: string): ProjectLoki | undefined { - return data.global.tenants.find(tenant => tenant.name === name) -} +// function _doesValuesDiff(actuaValues: ProjectLoki, expectedValue: ProjectLoki): boolean { +// if (actuaValues.projectName !== expectedValue.projectName) +// return true -function removeRepo(data: YamlLokiData, uuid: string): YamlLokiData { - return { - ...data, - global: { - ...data.global, - tenants: data.global.tenants.filter(tenant => tenant.uuid !== uuid), - }, - } -} +// const actualEnvKeys = Object.entries(actuaValues.envs) as [['prod' | 'hprod', Env] ] +// if (actualEnvKeys.length !== Object.keys(expectedValue.envs).length) +// return true + +// for (const [envName, envValue] of actualEnvKeys) { +// if (!(envName in expectedValue.envs)) +// return true + +// if (!envValue.groups) return true +// if (!expectedValue.envs[envName]?.groups) return true + +// if (envValue.groups.toString() !== expectedValue.envs[envName]?.groups.toString()) +// return true + +// const envTenants = Object.keys(envValue.tenants) +// if (envTenants.length !== Object.keys(expectedValue.envs[envName]?.tenants ?? {}).length) +// return true + +// for (const tenantName of envTenants) { +// if (expectedValue.envs[envName] && !(tenantName in expectedValue.envs[envName].tenants)) +// return true +// } +// } +// return false +// }