diff --git a/.eslintrc.js b/.eslintrc.js index 0a7b0bbfa3..3c6634e03b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,6 +52,7 @@ module.exports = { "no-process-exit": [0], "node/no-unsupported-features/es-syntax": [0], "node/shebang": [0], + "no-ex-assign": [0], "import/no-commonjs": [0], "import/no-dynamic-require": [0], "import/no-extraneous-dependencies": noExtraneousRule, diff --git a/packages/common/config/load-config.js b/packages/common/config/load-config.js index ff3606079f..9d2bbedb32 100644 --- a/packages/common/config/load-config.js +++ b/packages/common/config/load-config.js @@ -1,6 +1,7 @@ const os = require("os") const path = require("path") const { mkdtemp } = require("fs/promises") +const { v4: uuidv4 } = require("uuid") const { satisfies } = require("compare-versions") const fs = require("fs-extra") @@ -241,6 +242,9 @@ const loadConfig = async ( env: "KS_FORCE_NEW_DEPLOY", envParser: envParserYaml, }, + pipelineUUID: { + defaultFunction: () => uuidv4(), + }, pipelineId: { defaultFunction: (config) => { const { diff --git a/packages/common/package.json b/packages/common/package.json index 5dad39450d..c92806bd02 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -31,6 +31,7 @@ "slugify": "^1.6.5", "sonic-boom": "^3.0.0", "tiged": "^2.12.4", + "uuid": "^10.0.0", "which": "^3.0.0", "yaml": "^2.3.1", "zx": "^7.1.1" diff --git a/packages/common/utils/flatten-aggregate-error.js b/packages/common/utils/flatten-aggregate-error.js index 242a682882..f1342746b6 100644 --- a/packages/common/utils/flatten-aggregate-error.js +++ b/packages/common/utils/flatten-aggregate-error.js @@ -1,7 +1,8 @@ const indent = require("./indent") -module.exports = (aggregateError) => - new Error( +module.exports = (aggregateError) => { + console.log("aggregateError", aggregateError) + return new Error( `${aggregateError.name} ${aggregateError.message}: \n${indent( aggregateError.errors .map((error) => `${error.stack.toString()}`) @@ -9,3 +10,4 @@ module.exports = (aggregateError) => 2 )}` ) +} diff --git a/packages/kontinuous/src/build/builder.js b/packages/kontinuous/src/build/builder.js index beb15f4d68..ddfa49bb51 100644 --- a/packages/kontinuous/src/build/builder.js +++ b/packages/kontinuous/src/build/builder.js @@ -17,10 +17,12 @@ const loadDependencies = require("./load-dependencies") module.exports = async (_options = {}) => { const config = ctx.require("config") + const logger = ctx.require("logger") - const { buildPath, buildProjectPath, workspaceKsPath } = config + logger.info("🌀 [LIFECYCLE]: pre-build") + // TODO: - const logger = ctx.require("logger") + const { buildPath, buildProjectPath, workspaceKsPath } = config if (await fs.pathExists(workspaceKsPath)) { await fs.copy(workspaceKsPath, buildProjectPath, { @@ -77,6 +79,9 @@ module.exports = async (_options = {}) => { await debugManifests(manifests, values) + logger.info("🌀 [LIFECYCLE]: post-build") + // TODO: + return { manifestsFile, manifests: manifestsDump, diff --git a/packages/kontinuous/src/build/validate-manifests.js b/packages/kontinuous/src/build/validate-manifests.js index e71e6b3c54..7ab021c299 100644 --- a/packages/kontinuous/src/build/validate-manifests.js +++ b/packages/kontinuous/src/build/validate-manifests.js @@ -17,5 +17,16 @@ module.exports = async (manifests) => { logger.info("🌀 [LIFECYCLE]: validators") const context = createContext({ type: "validators", ValidationError }) const { buildProjectPath } = config - await pluginFunction(`${buildProjectPath}/validators`)(manifests, {}, context) + try { + await pluginFunction(`${buildProjectPath}/validators`)( + manifests, + {}, + context + ) + } catch (err) { + if (!(err instanceof ValidationError)) { + err = new ValidationError(err.message) + } + throw err + } } diff --git a/plugins/fabrique/kontinuous.yaml b/plugins/fabrique/kontinuous.yaml index 619abbff62..d1897f88e2 100644 --- a/plugins/fabrique/kontinuous.yaml +++ b/plugins/fabrique/kontinuous.yaml @@ -10,6 +10,8 @@ patches: repositoryUrl: https://github.com/SocialGouv/infra-resources.git dependencies: + kontinuous-ui: + import: socialgouv/kontinuous/plugins/kontinuous-ui contrib: import: socialgouv/kontinuous/plugins/contrib diff --git a/plugins/kontinuous-ui/.gitignore b/plugins/kontinuous-ui/.gitignore new file mode 100644 index 0000000000..4c49bd78f1 --- /dev/null +++ b/plugins/kontinuous-ui/.gitignore @@ -0,0 +1 @@ +.env diff --git a/plugins/kontinuous-ui/.yarn/install-state.gz b/plugins/kontinuous-ui/.yarn/install-state.gz new file mode 100644 index 0000000000..eae5142ca1 Binary files /dev/null and b/plugins/kontinuous-ui/.yarn/install-state.gz differ diff --git a/plugins/kontinuous-ui/deploy-sidecars/kontinuous-ui.js b/plugins/kontinuous-ui/deploy-sidecars/kontinuous-ui.js new file mode 100644 index 0000000000..7d2efa2358 --- /dev/null +++ b/plugins/kontinuous-ui/deploy-sidecars/kontinuous-ui.js @@ -0,0 +1,109 @@ +const { setTimeout: sleep } = require("timers/promises") +const supabase = require("../lib/supabase") + +module.exports = async (_options, { config, dryRun, ctx }) => { + if (dryRun) { + return + } + + const { + gitSha, + projectName, + environment, + gitBranch, + repositoryName, + gitRepositoryUrl, + pipelineUUID, + } = config + + const values = { + uuid: pipelineUUID, + commit_hash: gitSha, + project: projectName, + environment, + branch: gitBranch, + repository: repositoryName, + repository_url: gitRepositoryUrl, + } + + const eventsBucket = ctx.require("eventsBucket") + // const abortController = ctx.require("abortController") + + // resource:waiting + // resource:failed + // resource:ready + // resource:closed + + async function insertValues(data) { + const { error } = await supabase.from("deployments_logs").insert([data]) + if (error) throw error + } + + const waitingFor = [] + eventsBucket.on("resource:waiting", () => { + waitingFor.push( + new Promise(async (resolve, reject) => { + try { + const valuesToInsert = { ...values, status: "waiting" } + await insertValues(valuesToInsert) + resolve() + } catch (e) { + reject(e) + } + // await + }) + ) + }) + + eventsBucket.on("resource:ready", () => { + waitingFor.push( + new Promise(async (resolve, reject) => { + try { + const valuesToInsert = { ...values, status: "ready" } + await insertValues(valuesToInsert) + resolve() + } catch (e) { + reject(e) + } + // await + }) + ) + }) + + eventsBucket.on("resource:failed", () => { + waitingFor.push( + new Promise(async (resolve, reject) => { + try { + const valuesToInsert = { ...values, status: "failed" } + await insertValues(valuesToInsert) + resolve() + } catch (e) { + reject(e) + } + // await + }) + ) + }) + + let finished + eventsBucket.on("deploy-with:finish", () => { + finished = true + }) + + return new Promise(async (res, rej) => { + while (true) { + if (finished) { + console.log("WAITING FOR...") + try { + await Promise.all(waitingFor) + res() + } catch (err) { + console.log("ERROR", err) + rej(err) + } + return + } + await sleep(1) + } + }) +} diff --git a/plugins/kontinuous-ui/kontinuous.yaml b/plugins/kontinuous-ui/kontinuous.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/kontinuous-ui/lib/supabase.js b/plugins/kontinuous-ui/lib/supabase.js new file mode 100644 index 0000000000..223f85ac61 --- /dev/null +++ b/plugins/kontinuous-ui/lib/supabase.js @@ -0,0 +1,7 @@ +const { createClient } = require("@supabase/supabase-js") + +const { SUPABASE_URL: supabaseUrl, SUPABASE_KEY: supabaseKey } = process.env + +const supabase = createClient(supabaseUrl, supabaseKey) + +module.exports = supabase diff --git a/plugins/kontinuous-ui/package.json b/plugins/kontinuous-ui/package.json new file mode 100644 index 0000000000..8bbaab8647 --- /dev/null +++ b/plugins/kontinuous-ui/package.json @@ -0,0 +1,13 @@ +{ + "name": "~kontinuous-ui", + "dependencies": { + "@socialgouv/parse-manifests": "^1.16.4", + "@supabase/supabase-js": "2.45.4" + }, + "license": "MIT", + "private": true, + "packageManager": "yarn@4.0.0-rc.39", + "engines": { + "node": "^16.17 || ^18 || ^20" + } +} diff --git a/plugins/kontinuous-ui/pre-deploy/01-deployment_event.js b/plugins/kontinuous-ui/pre-deploy/01-deployment_event.js new file mode 100644 index 0000000000..a3a9f04c76 --- /dev/null +++ b/plugins/kontinuous-ui/pre-deploy/01-deployment_event.js @@ -0,0 +1,30 @@ +const supabase = require("../lib/supabase") + +module.exports = async (_manifests, _options, { config, logger }) => { + const { + gitSha, + projectName, + environment, + gitBranch, + repositoryName, + gitRepositoryUrl, + pipelineUUID, + } = config + + const values = { + uuid: pipelineUUID, + status: "pre-deploy", + commit_hash: gitSha, + project: projectName, + environment, + branch: gitBranch, + repository: repositoryName, + repository_url: gitRepositoryUrl, + } + + const { error } = await supabase.from("deployments_logs").insert([values]) + + if (error) throw error + + logger.info(values, "FINISHED") +} diff --git a/plugins/kontinuous-ui/values.yaml b/plugins/kontinuous-ui/values.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/kontinuous-ui/yarn.lock b/plugins/kontinuous-ui/yarn.lock new file mode 100644 index 0000000000..17e9fb651f --- /dev/null +++ b/plugins/kontinuous-ui/yarn.lock @@ -0,0 +1,183 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 7 + cacheKey: 9 + +"@socialgouv/parse-manifests@npm:^1.16.4": + version: 1.16.4 + resolution: "@socialgouv/parse-manifests@npm:1.16.4" + dependencies: + get-stdin: "npm:^9.0.0" + yaml: "npm:^1.10.2" + bin: + parse-manifests: bin/index.js + checksum: 3a335f1d21623c4c14424d31937cf63b9de4484edda35c66f5a194766a5fda4218521942543c3f36dfa14f0f70313af801627ea8e0c5cd86e8f252a6492f40c9 + languageName: node + linkType: hard + +"@supabase/auth-js@npm:2.65.0": + version: 2.65.0 + resolution: "@supabase/auth-js@npm:2.65.0" + dependencies: + "@supabase/node-fetch": "npm:^2.6.14" + checksum: ba3f33be8baad6e4d5347738d9d81bd2580fcf540daba7db09e1ed44dcc4e26d3d5db43b1d8e4d8fea065abf86ffbecb86ebd01d15cb068d698a7a4ab622e011 + languageName: node + linkType: hard + +"@supabase/functions-js@npm:2.4.1": + version: 2.4.1 + resolution: "@supabase/functions-js@npm:2.4.1" + dependencies: + "@supabase/node-fetch": "npm:^2.6.14" + checksum: a1b55a47dd0932deab63a0fb09bd5e866488b0ceffd969ed37bc1313a6351b65b764bd21717fe2419daab1061f9c0b2d9ad0fa7d226cccfb0862f4df8ea3400b + languageName: node + linkType: hard + +"@supabase/node-fetch@npm:2.6.15, @supabase/node-fetch@npm:^2.6.14": + version: 2.6.15 + resolution: "@supabase/node-fetch@npm:2.6.15" + dependencies: + whatwg-url: "npm:^5.0.0" + checksum: f590ec20a8d7f85a5c66e8294f068bf6244d791ebc9f26daa59dc7cb1603bb2b1ef48792baf7918ff1fd4ff02bcb5870649ced1d7e1e33d02217c83e96d06214 + languageName: node + linkType: hard + +"@supabase/postgrest-js@npm:1.16.1": + version: 1.16.1 + resolution: "@supabase/postgrest-js@npm:1.16.1" + dependencies: + "@supabase/node-fetch": "npm:^2.6.14" + checksum: 957c59d9f628403740f551127f8ea6dc7cf5c39be8f0468af5b1c83595fa1346a7d29cd78a0e25127986b977d4accc71fe2cd4beede7c0929156d1fd731e8463 + languageName: node + linkType: hard + +"@supabase/realtime-js@npm:2.10.2": + version: 2.10.2 + resolution: "@supabase/realtime-js@npm:2.10.2" + dependencies: + "@supabase/node-fetch": "npm:^2.6.14" + "@types/phoenix": "npm:^1.5.4" + "@types/ws": "npm:^8.5.10" + ws: "npm:^8.14.2" + checksum: 919e8f99083c347cbeb7daa33e22de0cd3f3855ce23e435925c6722727db4cedeeb22f9341370640b5a41d2331ee22c3516dbd4fb9cd858d854fb02f7f90e671 + languageName: node + linkType: hard + +"@supabase/storage-js@npm:2.7.0": + version: 2.7.0 + resolution: "@supabase/storage-js@npm:2.7.0" + dependencies: + "@supabase/node-fetch": "npm:^2.6.14" + checksum: 234d92a6c68e1b6e7352aaee8fa3366537af3581782474b8304cfa8d6d72f1124987071ff3f267ae7fefe36defee7e130615041fecaa221f5d91daff197bbbce + languageName: node + linkType: hard + +"@supabase/supabase-js@npm:2.45.4": + version: 2.45.4 + resolution: "@supabase/supabase-js@npm:2.45.4" + dependencies: + "@supabase/auth-js": "npm:2.65.0" + "@supabase/functions-js": "npm:2.4.1" + "@supabase/node-fetch": "npm:2.6.15" + "@supabase/postgrest-js": "npm:1.16.1" + "@supabase/realtime-js": "npm:2.10.2" + "@supabase/storage-js": "npm:2.7.0" + checksum: f094696be5baca51329f77d93049cc59b9b2e06a95b1b97ff9ef444f73854f8739c93808c363c087e04aa99c10cdfa0aa26d2f4597ccedc5c9e02fc118b8a8c2 + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 22.5.4 + resolution: "@types/node@npm:22.5.4" + dependencies: + undici-types: "npm:~6.19.2" + checksum: b7884378612778f6412904a0ad278146276dc407f9660a1229783b4c8dbebb05d6d0e7d485f6df541b9ae84aa2dce8571694f9c0733ff50286f85b299fba348d + languageName: node + linkType: hard + +"@types/phoenix@npm:^1.5.4": + version: 1.6.5 + resolution: "@types/phoenix@npm:1.6.5" + checksum: 5b2b2b7aabad5d54cb3475c4910ea111c8bb63440d14048649b2e6c57301ad07a234eb48ce982dc1d6382ec2bcfe36017fa96b43d5998140b55e922ee91452dc + languageName: node + linkType: hard + +"@types/ws@npm:^8.5.10": + version: 8.5.12 + resolution: "@types/ws@npm:8.5.12" + dependencies: + "@types/node": "npm:*" + checksum: c8bd2d3656444852698d91778ca1027e2c7dc536cfc03576ad7c19c3a68bb968e867a2d0e6012e32abea55f242f5d1e96888fc2c75be983c9c84aacea8015b12 + languageName: node + linkType: hard + +"get-stdin@npm:^9.0.0": + version: 9.0.0 + resolution: "get-stdin@npm:9.0.0" + checksum: 3adee5758c111b3432b2855cba6af7d342a679330a85867bf076bfc51b03f8747f34a5057f33e4a8909af4589acdc909a28eda82b3a4050b88e1d400696b6efe + languageName: node + linkType: hard + +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: c670667f2df1c0983b48ee7e81d6013ab304f73573e9e4292233821b2219504307bedffc303c32df30813a9138114b8b084c81dea94fb68f08aca7770af98578 + languageName: node + linkType: hard + +"undici-types@npm:~6.19.2": + version: 6.19.8 + resolution: "undici-types@npm:6.19.8" + checksum: 27c8b8f8e484976a6dd4f5f997fcbdf20ad85213575061a37306e4fb12b9963c311d383625aa6db874f8f6c4ed88d509fd007a10b90b359b04819fb239418951 + languageName: node + linkType: hard + +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: 57c8c5fdd986be5432ea6adacd87d6757144289d3b48b33441e7310bd4f4f6d782dd34acbd74d61e923c142cc50333d27ba58235692fa7248541c0bcce2563e1 + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: "npm:~0.0.3" + webidl-conversions: "npm:^3.0.0" + checksum: bd0cc6b75b84b3d032e30712e2f40eefbc07ecd14f093e87b2f81bb68bce10a3961e8eb646a7a8cc9c2352548fb501eeff668c8b2595fd7c6ea91d1406ce11ee + languageName: node + linkType: hard + +"ws@npm:^8.14.2": + version: 8.18.0 + resolution: "ws@npm:8.18.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 14a08117aa8615f098d168b3ac7a8fd24e4d21b43d3fc2e06e5cbf94ac5f3ad3e8e0c1ecd048b7e705d81e4f64ee6f723ae3c1961e0bd7b4bf84eda4e7f38ea0 + languageName: node + linkType: hard + +"yaml@npm:^1.10.2": + version: 1.10.2 + resolution: "yaml@npm:1.10.2" + checksum: d6f04384bdf1105256581aef39991f825e358f3f48f081974b0e0f39ff5240c60ccafb5842cb79d1287517efa2b9ee172c702f2e4855ba6cc46948b40a43aa6e + languageName: node + linkType: hard + +"~kontinuous-ui@workspace:.": + version: 0.0.0-use.local + resolution: "~kontinuous-ui@workspace:." + dependencies: + "@socialgouv/parse-manifests": "npm:^1.16.4" + "@supabase/supabase-js": "npm:2.45.4" + languageName: unknown + linkType: soft diff --git a/yarn.lock b/yarn.lock index 3f48b7185e..4ff49c7535 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15698,6 +15698,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^10.0.0": + version: 10.0.0 + resolution: "uuid@npm:10.0.0" + bin: + uuid: dist/bin/uuid + checksum: 9ea91ef753d88b03746de0a22192251c355bbe595d9cb3a67520aacf693c793df7e85c4ad0378aecb133c372a5e7bb7ec0f3b14db477ab7e3b6ff29792e047b9 + languageName: node + linkType: hard + "uuid@npm:^9.0.0": version: 9.0.0 resolution: "uuid@npm:9.0.0" @@ -16253,6 +16262,7 @@ __metadata: slugify: "npm:^1.6.5" sonic-boom: "npm:^3.0.0" tiged: "npm:^2.12.4" + uuid: "npm:^10.0.0" which: "npm:^3.0.0" yaml: "npm:^2.3.1" zx: "npm:^7.1.1"