From e66e29475455a29406f45af99afaa83c0c4cf7c3 Mon Sep 17 00:00:00 2001 From: Jack Westbrook Date: Fri, 14 Mar 2025 18:13:33 +0100 Subject: [PATCH 1/2] feat(create-plugin): introduce a migration to update docker compose to extend from .config --- .gitignore | 3 +- .../001-update-grafana-compose-extend.test.ts | 122 ++++++++++++++++++ .../001-update-grafana-compose-extend.ts | 57 ++++++++ 3 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.test.ts create mode 100644 packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.ts diff --git a/.gitignore b/.gitignore index 974c76357..edd381d95 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,5 @@ playwright/.auth # Used in CI to pass built packages to the next job packed-artifacts/ -.mise.toml \ No newline at end of file +.mise.toml +.cursor/ \ No newline at end of file diff --git a/packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.test.ts b/packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.test.ts new file mode 100644 index 000000000..f25ba6c8b --- /dev/null +++ b/packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.test.ts @@ -0,0 +1,122 @@ +import { describe, it, expect } from 'vitest'; +import { createDefaultContext } from '../test-utils.js'; +import migrate from './001-update-grafana-compose-extend.js'; +import { parse, stringify } from 'yaml'; + +describe('001-update-grafana-compose-extend', () => { + it('should not modify anything if docker-compose.yaml does not exist', async () => { + const context = createDefaultContext(); + const initialChanges = context.listChanges(); + await migrate(context); + expect(context.listChanges()).toEqual(initialChanges); + }); + + it('should not modify if grafana service with correct build context is missing', async () => { + const context = createDefaultContext(); + context.addFile( + './docker-compose.yaml', + stringify({ + services: { + grafana: { + build: { + context: './wrong-path', + }, + }, + }, + }) + ); + const initialChanges = context.listChanges(); + await migrate(context); + expect(context.listChanges()).toEqual(initialChanges); + }); + + it('should not modify if base compose file is missing', async () => { + const context = createDefaultContext(); + context.addFile( + './docker-compose.yaml', + stringify({ + services: { + grafana: { + build: { + context: './.config', + }, + }, + }, + }) + ); + const initialChanges = context.listChanges(); + await migrate(context); + expect(context.listChanges()).toEqual(initialChanges); + }); + + it('should update compose file and preserve build args', async () => { + const context = createDefaultContext(); + context.addFile( + './docker-compose.yaml', + stringify({ + services: { + grafana: { + build: { + context: './.config', + args: { + grafana_image: 'custom-image', + grafana_version: '10.0.0', + other_arg: 'value', + }, + }, + }, + }, + }) + ); + context.addFile( + './.config/docker-compose-base.yaml', + stringify({ + services: { + grafana: { + build: { + context: '.', + }, + }, + }, + }) + ); + + await migrate(context); + + const result = parse(context.getFile('./docker-compose.yaml') || ''); + expect(result.services.grafana).toEqual({ + extends: { + file: '.config/docker-compose-base.yaml', + service: 'grafana', + }, + build: { + args: { + grafana_image: 'custom-image', + grafana_version: '10.0.0', + }, + }, + }); + }); + + it('should be idempotent', async () => { + const context = createDefaultContext(); + context.addFile( + './docker-compose.yaml', + stringify({ + services: { + grafana: { + build: { + context: './.config', + args: { + grafana_image: 'custom-image', + grafana_version: '10.0.0', + }, + }, + }, + }, + }) + ); + context.addFile('./.config/docker-compose-base.yaml', 'exists'); + await expect(migrate).toBeIdempotent(context); + }); +}); diff --git a/packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.ts b/packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.ts new file mode 100644 index 000000000..f6b0906b7 --- /dev/null +++ b/packages/create-plugin/src/migrations/scripts/001-update-grafana-compose-extend.ts @@ -0,0 +1,57 @@ +import { type Context } from '../context.js'; +import { parse, stringify } from 'yaml'; + +export default async function migrate(context: Context) { + // Check if docker-compose.yaml exists + if (!context.doesFileExist('./docker-compose.yaml')) { + return context; + } + + // Read and parse the docker-compose file + const composeContent = context.getFile('./docker-compose.yaml'); + if (!composeContent) { + return context; + } + + const composeData = parse(composeContent); + + // Check if grafana service exists with the specified build context + if (composeData?.services?.grafana?.build?.context !== './.config') { + return context; + } + + // Check if base compose file exists + if (!context.doesFileExist('./.config/docker-compose-base.yaml')) { + return context; + } + + // Preserve build args if they exist + const existingBuildArgs = composeData.services.grafana.build.args; + const preservedArgs: Record = {}; + if (existingBuildArgs?.grafana_image || existingBuildArgs?.grafana_version) { + if (existingBuildArgs.grafana_image) { + preservedArgs['grafana_image'] = existingBuildArgs.grafana_image; + } + if (existingBuildArgs.grafana_version) { + preservedArgs['grafana_version'] = existingBuildArgs.grafana_version; + } + } + + // Update the grafana service configuration + composeData.services.grafana = { + extends: { + file: '.config/docker-compose-base.yaml', + service: 'grafana', + }, + ...(Object.keys(preservedArgs).length > 0 && { + build: { + args: preservedArgs, + }, + }), + }; + + // Write the updated compose file + context.updateFile('./docker-compose.yaml', stringify(composeData, { lineWidth: 0 })); + + return context; +} From 084e33ebc25e6dae705235b27c1b71366f61c052 Mon Sep 17 00:00:00 2001 From: Jack Westbrook Date: Fri, 14 Mar 2025 18:24:24 +0100 Subject: [PATCH 2/2] chore(create-plugin): add yaml dependency --- package-lock.json | 94 +++++++++-------------------- packages/create-plugin/package.json | 3 +- 2 files changed, 32 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index a50af53af..cc41b8383 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3236,7 +3236,7 @@ }, "node_modules/@docusaurus/faster": { "version": "3.7.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@docusaurus/types": "3.7.0", @@ -3258,7 +3258,7 @@ }, "node_modules/@docusaurus/faster/node_modules/@rspack/binding": { "version": "1.2.0-alpha.0", - "dev": true, + "devOptional": true, "license": "MIT", "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.2.0-alpha.0", @@ -3300,7 +3300,7 @@ }, "node_modules/@docusaurus/faster/node_modules/@rspack/core": { "version": "1.2.0-alpha.0", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@module-federation/runtime-tools": "0.8.4", @@ -3322,7 +3322,7 @@ }, "node_modules/@docusaurus/faster/node_modules/tslib": { "version": "2.8.1", - "dev": true, + "devOptional": true, "license": "0BSD" }, "node_modules/@docusaurus/logger": { @@ -4099,7 +4099,6 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.12.1", - "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -4107,7 +4106,6 @@ }, "node_modules/@eslint/config-array": { "version": "0.19.2", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.6", @@ -4120,7 +4118,6 @@ }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -4129,7 +4126,6 @@ }, "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -4140,7 +4136,6 @@ }, "node_modules/@eslint/config-helpers": { "version": "0.1.0", - "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4148,7 +4143,6 @@ }, "node_modules/@eslint/core": { "version": "0.12.0", - "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -4159,7 +4153,6 @@ }, "node_modules/@eslint/eslintrc": { "version": "3.3.0", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -4181,7 +4174,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -4190,7 +4182,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -4201,7 +4192,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -4212,7 +4202,6 @@ }, "node_modules/@eslint/js": { "version": "9.22.0", - "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4220,7 +4209,6 @@ }, "node_modules/@eslint/object-schema": { "version": "2.1.6", - "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4228,7 +4216,6 @@ }, "node_modules/@eslint/plugin-kit": { "version": "0.2.7", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.12.0", @@ -4957,7 +4944,6 @@ }, "node_modules/@humanfs/core": { "version": "0.19.1", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -4965,7 +4951,6 @@ }, "node_modules/@humanfs/node": { "version": "0.16.6", - "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", @@ -4977,7 +4962,6 @@ }, "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { "version": "0.3.1", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -4989,7 +4973,6 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -5001,7 +4984,6 @@ }, "node_modules/@humanwhocodes/retry": { "version": "0.4.2", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -5968,12 +5950,12 @@ }, "node_modules/@module-federation/error-codes": { "version": "0.8.4", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@module-federation/runtime": { "version": "0.8.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@module-federation/error-codes": "0.8.4", @@ -5982,7 +5964,7 @@ }, "node_modules/@module-federation/runtime-tools": { "version": "0.8.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@module-federation/runtime": "0.8.4", @@ -5991,7 +5973,7 @@ }, "node_modules/@module-federation/sdk": { "version": "0.8.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "isomorphic-rslog": "0.0.6" @@ -5999,7 +5981,7 @@ }, "node_modules/@module-federation/webpack-bundler-runtime": { "version": "0.8.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@module-federation/runtime": "0.8.4", @@ -7524,7 +7506,7 @@ }, "node_modules/@rspack/lite-tapable": { "version": "1.0.1", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=16.0.0" @@ -7957,7 +7939,7 @@ }, "node_modules/@swc/core": { "version": "1.11.9", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -8009,12 +7991,12 @@ }, "node_modules/@swc/counter": { "version": "0.1.3", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@swc/html": { "version": "1.10.14", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3" @@ -8221,7 +8203,7 @@ }, "node_modules/@swc/types": { "version": "0.1.19", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3" @@ -12485,7 +12467,6 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "dev": true, "license": "MIT" }, "node_modules/deepmerge": { @@ -12640,7 +12621,7 @@ }, "node_modules/detect-libc": { "version": "1.0.3", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "detect-libc": "bin/detect-libc.js" @@ -13508,7 +13489,6 @@ }, "node_modules/eslint": { "version": "9.22.0", - "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -13716,7 +13696,6 @@ }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -13725,7 +13704,6 @@ }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -13740,7 +13718,6 @@ }, "node_modules/eslint/node_modules/eslint-scope": { "version": "8.3.0", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -13755,7 +13732,6 @@ }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -13770,7 +13746,6 @@ }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -13781,7 +13756,6 @@ }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -13795,7 +13769,6 @@ }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -13806,7 +13779,6 @@ }, "node_modules/eslint/node_modules/p-limit": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -13820,7 +13792,6 @@ }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -13834,7 +13805,6 @@ }, "node_modules/eslint/node_modules/path-exists": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13842,7 +13812,6 @@ }, "node_modules/eslint/node_modules/yocto-queue": { "version": "0.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -13853,7 +13822,6 @@ }, "node_modules/espree": { "version": "10.3.0", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.14.0", @@ -13880,7 +13848,6 @@ }, "node_modules/esquery": { "version": "1.6.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -14223,7 +14190,6 @@ }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "dev": true, "license": "MIT" }, "node_modules/fast-shallow-equal": { @@ -14330,7 +14296,6 @@ }, "node_modules/file-entry-cache": { "version": "8.0.0", - "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -14489,7 +14454,6 @@ }, "node_modules/flat-cache": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -14501,7 +14465,6 @@ }, "node_modules/flatted": { "version": "3.3.2", - "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { @@ -17960,7 +17923,7 @@ }, "node_modules/isomorphic-rslog": { "version": "0.0.6", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=14.17.6" @@ -18341,7 +18304,6 @@ }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "dev": true, "license": "MIT" }, "node_modules/json-stringify-nice": { @@ -19135,7 +19097,6 @@ }, "node_modules/levn": { "version": "0.4.1", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -19195,7 +19156,7 @@ }, "node_modules/lightningcss": { "version": "1.29.1", - "dev": true, + "devOptional": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^1.0.3" @@ -19231,6 +19192,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19252,6 +19214,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19273,6 +19236,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19294,6 +19258,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19315,6 +19280,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19336,6 +19302,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19377,6 +19344,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19398,6 +19366,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19419,6 +19388,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19440,6 +19410,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -19752,7 +19723,6 @@ }, "node_modules/lodash.merge": { "version": "4.6.2", - "dev": true, "license": "MIT" }, "node_modules/lodash.sortby": { @@ -22876,7 +22846,6 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "dev": true, "license": "MIT" }, "node_modules/negotiator": { @@ -23707,7 +23676,6 @@ }, "node_modules/optionator": { "version": "0.9.4", - "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -25984,7 +25952,6 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -29409,7 +29376,7 @@ }, "node_modules/swc-loader": { "version": "0.2.6", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@swc/counter": "^0.1.3" @@ -30312,7 +30279,6 @@ }, "node_modules/type-check": { "version": "0.4.0", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -31829,7 +31795,6 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -32344,7 +32309,8 @@ "minimist": "^1.2.8", "semver": "^7.3.5", "title-case": "^4.3.0", - "which": "^5.0.0" + "which": "^5.0.0", + "yaml": "^2.7.0" }, "bin": { "create-plugin": "dist/bin/run.js" diff --git a/packages/create-plugin/package.json b/packages/create-plugin/package.json index 8a146efe7..f8591ce2e 100644 --- a/packages/create-plugin/package.json +++ b/packages/create-plugin/package.json @@ -41,7 +41,8 @@ "minimist": "^1.2.8", "semver": "^7.3.5", "title-case": "^4.3.0", - "which": "^5.0.0" + "which": "^5.0.0", + "yaml": "^2.7.0" }, "devDependencies": { "@types/glob": "^8.1.0",