diff --git a/core/cli/src/help.ts b/core/cli/src/help.ts index 9a4e4711f..3c31cc373 100644 --- a/core/cli/src/help.ts +++ b/core/cli/src/help.ts @@ -5,6 +5,7 @@ import YAML from 'yaml' import $t from 'endent' import { CommandTask, OptionsForTask } from '@dotcom-tool-kit/plugin' import { ValidConfig } from '@dotcom-tool-kit/config' +import { runInit } from './init' const toolKitIntro = s.box( $t` @@ -84,6 +85,8 @@ export default async function showHelp(logger: Logger, commands: string[]): Prom commands = Object.keys(config.commandTasks).sort() } + await runInit(logger, config) + logger.info(toolKitIntro) const definedCommands = commands.filter((command) => config.commandTasks[command]) diff --git a/core/cli/src/init.ts b/core/cli/src/init.ts index 26b116da0..2296298dc 100644 --- a/core/cli/src/init.ts +++ b/core/cli/src/init.ts @@ -16,5 +16,7 @@ export async function runInit(logger: Logger, config: ValidConfig): Promise init.init())) + await Promise.all(inits.map(async (init) => init.init({ + cwd: config.root + }))) } diff --git a/lib/base/src/init.ts b/lib/base/src/init.ts index 42b99279f..8c2a1d899 100644 --- a/lib/base/src/init.ts +++ b/lib/base/src/init.ts @@ -2,6 +2,10 @@ import type { Logger } from 'winston' import { initSymbol, typeSymbol } from './symbols' import { Base } from './base' +export type InitContext = { + cwd: string +} + export abstract class Init extends Base { logger: Logger @@ -18,7 +22,7 @@ export abstract class Init extends Base { return initSymbol } - abstract init(): Promise + abstract init(context: InitContext): Promise } export type InitConstructor = { diff --git a/lib/schemas/src/tasks.ts b/lib/schemas/src/tasks.ts index d037042c7..70b7a37dc 100644 --- a/lib/schemas/src/tasks.ts +++ b/lib/schemas/src/tasks.ts @@ -13,6 +13,7 @@ import { SmokeTestSchema } from './tasks/n-test' import { CypressSchema } from './tasks/cypress' import { HerokuProductionSchema } from './tasks/heroku-production' import { ServerlessRunSchema } from './tasks/serverless-run' +import { WorkspaceCommandSchema } from './tasks/workspace-command' import { z } from 'zod' export const TaskSchemas = { @@ -39,7 +40,8 @@ export const TaskSchemas = { ServerlessTeardown: z.object({}).describe('Tear down existing serverless functions'), TypeScript: TypeScriptSchema, UploadAssetsToS3: UploadAssetsToS3Schema, - Webpack: WebpackSchema + Webpack: WebpackSchema, + WorkspaceCommand: WorkspaceCommandSchema } export type TaskOptions = InferSchemaOptions diff --git a/lib/schemas/src/tasks/workspace-command.ts b/lib/schemas/src/tasks/workspace-command.ts new file mode 100644 index 000000000..715157c26 --- /dev/null +++ b/lib/schemas/src/tasks/workspace-command.ts @@ -0,0 +1,65 @@ +import { z } from 'zod' + +export const WorkspaceCommandSchema = z.object({ + command: z.string().optional().describe('A specific command to run instead of the command that ran this task.'), + packageFilter: z.string().optional().describe('By default, the command will run in every workspace command that has that command assigned to a task. This option is a glob pattern to filter the packages the command will run on. For example, if your workspace has packages in the `plugins` and `lib` folders, set `packageFilter` to `plugins/*` to only run only in the packages in `plugins`.'), +}).describe(`Runs a Tool Kit command in all workspace packages that have that command. By default, runs the command that was used to run this task. + +For example, imagine a monorepo with these \`.toolkitrc.yml\` files: + +
.toolkitrc.yml + +~~~yml +commands: + run:local: WorkspaceCommand + build:local: WorkspaceCommand +~~~ + +
+ +
packages/api/.toolkitrc.yml + +~~~yml +commands: + run:local: Node +~~~ + +
+ +
packages/client/.toolkitrc.yml + +~~~yml +commands: + build:local: TypeScript +~~~ + +
+ +
packages/components/.toolkitrc.yml + +~~~yml +commands: + build:local: Webpack + run:local: + Webpack: + watch: true +~~~ + +
+ +Running \`dotcom-tool-kit run:local\` at the root level will run the \`Node\` task in \`packages/api\` and the \`Webpack\` task in watch mode in \`packages/components\`; running \`dotcom-tool-kit build:local\` will run \`TypeScript\` in \`packages/client\` and \`Webpack\` in \`packages/components\`. + +To run a particular command in the workspace instead of dynamically inferring the command from which was run at root level, set the \`command\` option for the task: + +~~~yml +commands: + build:ci: + WorkspaceCommand: + command: build:local +~~~ + +`) + +export type WorkspaceCommandOptions = z.infer + +export const Schema = WorkspaceCommandSchema diff --git a/package-lock.json b/package-lock.json index d43cb2ca7..ced9d98af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,17 +50,17 @@ }, "core/cli": { "name": "dotcom-tool-kit", - "version": "4.0.6", + "version": "4.1.0", "license": "MIT", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/config": "^1.0.2", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/config": "^1.0.3", "@dotcom-tool-kit/conflict": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "@dotcom-tool-kit/plugin": "^1.0.0", "@dotcom-tool-kit/state": "^4.0.0", - "@dotcom-tool-kit/validated": "^1.0.0", + "@dotcom-tool-kit/validated": "^1.0.1", "@dotcom-tool-kit/wait-for-ok": "^4.0.0", "endent": "^2.1.0", "lodash": "^4.17.21", @@ -142,16 +142,16 @@ }, "core/create": { "name": "@dotcom-tool-kit/create", - "version": "4.0.6", + "version": "4.1.0", "license": "ISC", "dependencies": { "@aws-sdk/client-iam": "^3.282.0", "@aws-sdk/client-sts": "^3.282.0", - "@dotcom-tool-kit/doppler": "^2.0.2", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/doppler": "^2.0.3", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "@dotcom-tool-kit/plugin": "^1.0.0", - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@octokit/rest": "^19.0.5", "@quarterto/parse-makefile-rules": "^1.1.0", "cli-highlight": "^2.1.11", @@ -178,7 +178,7 @@ "@types/node-fetch": "^2.6.2", "@types/pacote": "^11.1.3", "@types/prompts": "^2.0.14", - "dotcom-tool-kit": "^4.0.6", + "dotcom-tool-kit": "^4.1.0", "type-fest": "^3.13.1" }, "engines": { @@ -1112,17 +1112,17 @@ }, "lib/base": { "name": "@dotcom-tool-kit/base", - "version": "1.0.0", + "version": "1.1.0", "license": "ISC", "dependencies": { "@dotcom-tool-kit/conflict": "^1.0.0", - "@dotcom-tool-kit/validated": "^1.0.0", + "@dotcom-tool-kit/validated": "^1.0.1", "semver": "^7.5.4", "winston": "^3.11.0" }, "devDependencies": { - "@dotcom-tool-kit/config": "^1.0.2", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/config": "^1.0.3", + "@dotcom-tool-kit/logger": "^4.0.1", "@dotcom-tool-kit/plugin": "^1.0.0", "type-fest": "^4.29.1", "winston": "^3.11.0", @@ -1212,13 +1212,13 @@ }, "lib/config": { "name": "@dotcom-tool-kit/config", - "version": "1.0.2", + "version": "1.0.3", "license": "ISC", "dependencies": { "@dotcom-tool-kit/conflict": "^1.0.0", "@dotcom-tool-kit/plugin": "^1.0.0", - "@dotcom-tool-kit/schemas": "^1.1.1", - "@dotcom-tool-kit/validated": "^1.0.0" + "@dotcom-tool-kit/schemas": "^1.2.0", + "@dotcom-tool-kit/validated": "^1.0.1" } }, "lib/conflict": { @@ -1231,15 +1231,15 @@ }, "lib/doppler": { "name": "@dotcom-tool-kit/doppler", - "version": "2.0.2", + "version": "2.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "spawk": "^1.8.1", "winston": "^3.5.1" }, @@ -1255,7 +1255,7 @@ }, "lib/error": { "name": "@dotcom-tool-kit/error", - "version": "4.0.0", + "version": "4.0.1", "license": "ISC", "dependencies": { "tslib": "^2.3.1" @@ -1272,11 +1272,11 @@ }, "lib/logger": { "name": "@dotcom-tool-kit/logger", - "version": "4.0.0", + "version": "4.0.1", "license": "ISC", "dependencies": { "@apaleslimghost/boxen": "^5.1.3", - "@dotcom-tool-kit/error": "^4.0.0", + "@dotcom-tool-kit/error": "^4.0.1", "ansi-regex": "^5.0.1", "triple-beam": "^1.3.0", "tslib": "^2.3.1", @@ -1338,10 +1338,10 @@ }, "lib/schemas": { "name": "@dotcom-tool-kit/schemas", - "version": "1.1.1", + "version": "1.2.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/logger": "^4.0.0" + "@dotcom-tool-kit/logger": "^4.0.1" }, "devDependencies": { "prompts": "^2.4.2", @@ -1436,10 +1436,10 @@ }, "lib/validated": { "name": "@dotcom-tool-kit/validated", - "version": "1.0.0", + "version": "1.0.1", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/error": "^4.0.0" + "@dotcom-tool-kit/error": "^4.0.1" } }, "lib/vault": { @@ -6517,6 +6517,10 @@ "resolved": "plugins/mocha", "link": true }, + "node_modules/@dotcom-tool-kit/monorepo": { + "resolved": "plugins/monorepo", + "link": true + }, "node_modules/@dotcom-tool-kit/n-test": { "resolved": "plugins/n-test", "link": true @@ -7464,6 +7468,95 @@ "dev": true, "license": "ISC" }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "license": "ISC", @@ -9155,6 +9248,99 @@ "node": ">= 10" } }, + "node_modules/@npmcli/map-workspaces": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz", + "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/move-file": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", @@ -9168,6 +9354,14 @@ "node": ">=10" } }, + "node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", + "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/node-gyp": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", @@ -9474,12 +9668,27 @@ "@octokit/openapi-types": "^11.2.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@quarterto/parse-makefile-rules": { "version": "1.1.0" }, "node_modules/@quarterto/strip-ansi": { "version": "1.2.0" }, + "node_modules/@relmify/jest-serializer-strip-ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@relmify/jest-serializer-strip-ansi/-/jest-serializer-strip-ansi-1.0.2.tgz", + "integrity": "sha512-cJv6weXt7Bk0PEpWNtw0UGOddIbEvNLPlbYb+594xxe5WXs3SSA29tCK57Vg6q46wHEpY1kOCmgQhE8EcIXPKw==", + "dev": true + }, "node_modules/@serverless/dashboard-plugin": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/@serverless/dashboard-plugin/-/dashboard-plugin-6.2.3.tgz", @@ -10184,6 +10393,15 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/cacache": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/cacache/-/cacache-17.0.2.tgz", + "integrity": "sha512-IrqHzVX2VRMDQQKa7CtKRnuoCLdRJiLW6hWU+w7i7+AaQ0Ii5bKwJxd5uRK4zBCyrHd3tG6G8zOm2LplxbSfQg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -10315,9 +10533,10 @@ "license": "MIT" }, "node_modules/@types/minimatch": { - "version": "3.0.5", - "dev": true, - "license": "MIT" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -10374,6 +10593,46 @@ "@types/ssri": "*" } }, + "node_modules/@types/npmcli__arborist": { + "version": "5.6.6", + "resolved": "https://registry.npmjs.org/@types/npmcli__arborist/-/npmcli__arborist-5.6.6.tgz", + "integrity": "sha512-uJyeAINDxppb8uxDe/r9EqvHrA3huz8RcdOX2IVbiU+cb+NaNATSQ8oyCF1HQ3EMferzrQJ8wmP7/b9Z4BlvNw==", + "dev": true, + "dependencies": { + "@npm/types": "*", + "@types/cacache": "*", + "@types/node": "*", + "@types/npmcli__package-json": "*", + "@types/pacote": "*" + } + }, + "node_modules/@types/npmcli__map-workspaces": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/npmcli__map-workspaces/-/npmcli__map-workspaces-3.0.4.tgz", + "integrity": "sha512-NKs2WY8V24b21xBSmofuQEJX/XHIGaQT5UmiOYzdrmIR7dZh9ED9TDXeV8GcAAH0t12J3kMufbxtsli50Zjm9w==", + "dev": true, + "dependencies": { + "@types/glob": "~8.1.0", + "@types/npmcli__arborist": "*", + "@types/npmcli__package-json": "*" + } + }, + "node_modules/@types/npmcli__map-workspaces/node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/npmcli__package-json": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/npmcli__package-json/-/npmcli__package-json-4.0.4.tgz", + "integrity": "sha512-6QjlFUSHBmZJWuC08bz1ZCx6tm4t+7+OJXAdvM6tL2pI7n6Bh5SIp/YxQvnOLFf8MzCXs2ijyFgrzaiu1UFBGA==", + "dev": true + }, "node_modules/@types/npmlog": { "version": "4.1.4", "dev": true, @@ -14666,8 +14925,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "peer": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ecc-jsbn": { "version": "0.1.2", @@ -16362,6 +16620,78 @@ "node": ">=0.10.0" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/foreground-child/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "license": "Apache-2.0", @@ -18424,6 +18754,23 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/java-invoke-local": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/java-invoke-local/-/java-invoke-local-0.0.6.tgz", @@ -24098,6 +24445,37 @@ "version": "1.0.7", "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-type": { "version": "4.0.0", "license": "MIT", @@ -27588,6 +27966,20 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -27663,6 +28055,18 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "license": "MIT", @@ -30131,6 +30535,23 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "license": "ISC" @@ -30482,18 +30903,18 @@ }, "plugins/babel": { "name": "@dotcom-tool-kit/babel", - "version": "4.0.2", + "version": "4.1.0", "license": "MIT", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "fast-glob": "^3.2.11", "tslib": "^2.3.1" }, "devDependencies": { "@babel/preset-env": "^7.16.11", - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "winston": "^3.5.1" }, @@ -30529,13 +30950,13 @@ }, "plugins/backend-heroku-app": { "name": "@dotcom-tool-kit/backend-heroku-app", - "version": "4.0.2", + "version": "4.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/circleci-deploy": "^4.0.2", - "@dotcom-tool-kit/heroku": "^4.0.2", - "@dotcom-tool-kit/node": "^4.0.2", - "@dotcom-tool-kit/npm": "^4.0.2" + "@dotcom-tool-kit/circleci-deploy": "^4.0.3", + "@dotcom-tool-kit/heroku": "^4.0.3", + "@dotcom-tool-kit/node": "^4.1.0", + "@dotcom-tool-kit/npm": "^4.1.0" }, "engines": { "node": "18.x || 20.x", @@ -30547,13 +30968,13 @@ }, "plugins/backend-serverless-app": { "name": "@dotcom-tool-kit/backend-serverless-app", - "version": "4.0.2", + "version": "4.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/circleci-deploy": "^4.0.2", - "@dotcom-tool-kit/node": "^4.0.2", - "@dotcom-tool-kit/npm": "^4.0.2", - "@dotcom-tool-kit/serverless": "^3.0.2" + "@dotcom-tool-kit/circleci-deploy": "^4.0.3", + "@dotcom-tool-kit/node": "^4.1.0", + "@dotcom-tool-kit/npm": "^4.1.0", + "@dotcom-tool-kit/serverless": "^3.1.0" }, "engines": { "node": "18.x || 20.x", @@ -30565,13 +30986,13 @@ }, "plugins/circleci": { "name": "@dotcom-tool-kit/circleci", - "version": "7.0.2", + "version": "7.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", + "@dotcom-tool-kit/base": "^1.1.0", "@dotcom-tool-kit/conflict": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "@dotcom-tool-kit/state": "^4.0.0", "jest-diff": "^29.5.0", "lodash": "^4.17.21", @@ -30581,7 +31002,7 @@ }, "devDependencies": { "@dotcom-tool-kit/plugin": "^1.0.0", - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "@types/jest": "^27.4.0", "@types/js-yaml": "^4.0.3", @@ -30600,10 +31021,10 @@ }, "plugins/circleci-deploy": { "name": "@dotcom-tool-kit/circleci-deploy", - "version": "4.0.2", + "version": "4.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/circleci": "^7.0.2", + "@dotcom-tool-kit/circleci": "^7.1.0", "tslib": "^2.3.1" }, "devDependencies": { @@ -30642,11 +31063,11 @@ }, "plugins/circleci-npm": { "name": "@dotcom-tool-kit/circleci-npm", - "version": "6.0.3", + "version": "6.0.4", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/circleci": "^7.0.2", - "@dotcom-tool-kit/npm": "^4.0.2", + "@dotcom-tool-kit/circleci": "^7.1.0", + "@dotcom-tool-kit/npm": "^4.1.0", "tslib": "^2.3.1" }, "engines": { @@ -30763,11 +31184,11 @@ }, "plugins/commitlint": { "name": "@dotcom-tool-kit/commitlint", - "version": "1.0.0", + "version": "1.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/logger": "^4.0.0" + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/logger": "^4.0.1" }, "engines": { "node": "18.x || 20.x", @@ -31477,11 +31898,11 @@ }, "plugins/component": { "name": "@dotcom-tool-kit/component", - "version": "5.0.3", + "version": "5.0.4", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/circleci-npm": "^6.0.3", - "@dotcom-tool-kit/npm": "^4.0.2" + "@dotcom-tool-kit/circleci-npm": "^6.0.4", + "@dotcom-tool-kit/npm": "^4.1.0" }, "engines": { "node": "18.x || 20.x", @@ -31493,17 +31914,17 @@ }, "plugins/cypress": { "name": "@dotcom-tool-kit/cypress", - "version": "5.0.2", + "version": "5.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/doppler": "^2.0.2", - "@dotcom-tool-kit/logger": "^4.0.0", - "@dotcom-tool-kit/package-json-hook": "^5.0.2", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/doppler": "^2.0.3", + "@dotcom-tool-kit/logger": "^4.0.1", + "@dotcom-tool-kit/package-json-hook": "^5.0.3", "@dotcom-tool-kit/state": "^4.0.0" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1" + "@dotcom-tool-kit/schemas": "^1.2.0" }, "engines": { "node": "18.x || 20.x", @@ -31516,16 +31937,16 @@ "plugins/doppler": {}, "plugins/eslint": { "name": "@dotcom-tool-kit/eslint", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "@types/eslint": "^7.2.13", "@types/temp": "^0.9.4", @@ -31741,12 +32162,12 @@ }, "plugins/frontend-app": { "name": "@dotcom-tool-kit/frontend-app", - "version": "4.0.2", + "version": "4.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/backend-heroku-app": "^4.0.2", - "@dotcom-tool-kit/upload-assets-to-s3": "^4.0.2", - "@dotcom-tool-kit/webpack": "^4.0.2" + "@dotcom-tool-kit/backend-heroku-app": "^4.0.3", + "@dotcom-tool-kit/upload-assets-to-s3": "^4.1.0", + "@dotcom-tool-kit/webpack": "^4.1.0" }, "engines": { "node": "18.x || 20.x", @@ -31758,15 +32179,15 @@ }, "plugins/heroku": { "name": "@dotcom-tool-kit/heroku", - "version": "4.0.2", + "version": "4.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/doppler": "^2.0.2", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", - "@dotcom-tool-kit/npm": "^4.0.2", - "@dotcom-tool-kit/package-json-hook": "^5.0.2", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/doppler": "^2.0.3", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", + "@dotcom-tool-kit/npm": "^4.1.0", + "@dotcom-tool-kit/package-json-hook": "^5.0.3", "@dotcom-tool-kit/state": "^4.0.0", "@dotcom-tool-kit/wait-for-ok": "^4.0.0", "@octokit/request": "^5.6.0", @@ -31777,7 +32198,7 @@ "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@types/financial-times__package-json": "^1.9.0", "@types/p-retry": "^3.0.1", "winston": "^3.5.1" @@ -31797,10 +32218,10 @@ }, "plugins/husky-npm": { "name": "@dotcom-tool-kit/husky-npm", - "version": "5.0.2", + "version": "5.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/package-json-hook": "^5.0.2", + "@dotcom-tool-kit/package-json-hook": "^5.0.3", "tslib": "^2.3.1" }, "engines": { @@ -31819,15 +32240,15 @@ }, "plugins/jest": { "name": "@dotcom-tool-kit/jest", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/logger": "^4.0.1", "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "winston": "^3.5.1" }, "engines": { @@ -31846,12 +32267,12 @@ }, "plugins/lint-staged": { "name": "@dotcom-tool-kit/lint-staged", - "version": "5.0.2", + "version": "5.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", - "@dotcom-tool-kit/package-json-hook": "^5.0.2", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/logger": "^4.0.1", + "@dotcom-tool-kit/package-json-hook": "^5.0.3", "lint-staged": "^11.2.3", "tslib": "^2.3.1" }, @@ -31865,12 +32286,12 @@ }, "plugins/lint-staged-npm": { "name": "@dotcom-tool-kit/lint-staged-npm", - "version": "4.0.2", + "version": "4.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/husky-npm": "^5.0.2", - "@dotcom-tool-kit/lint-staged": "^5.0.2", - "@dotcom-tool-kit/package-json-hook": "^5.0.2", + "@dotcom-tool-kit/husky-npm": "^5.0.3", + "@dotcom-tool-kit/lint-staged": "^5.1.0", + "@dotcom-tool-kit/package-json-hook": "^5.0.3", "tslib": "^2.3.1" }, "engines": { @@ -31943,17 +32364,17 @@ }, "plugins/mocha": { "name": "@dotcom-tool-kit/mocha", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "glob": "^7.1.7", "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "@types/glob": "^7.1.3", "@types/mocha": "^8.2.2", @@ -31974,21 +32395,64 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "plugins/monorepo": { - "extraneous": true + "name": "@dotcom-tool-kit/monorepo", + "version": "0.1.0", + "license": "ISC", + "dependencies": { + "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/schemas": "^1.1.1", + "@npmcli/map-workspaces": "^3.0.6", + "minimatch": "^10.0.1", + "pluralize": "^8.0.0" + }, + "devDependencies": { + "@relmify/jest-serializer-strip-ansi": "^1.0.2", + "@types/npmcli__map-workspaces": "^3.0.4", + "@types/pluralize": "^0.0.33" + }, + "engines": { + "node": "18.x || 20.x", + "npm": "7.x || 8.x || 9.x" + }, + "peerDependencies": { + "dotcom-tool-kit": "4.x" + } + }, + "plugins/monorepo/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "plugins/monorepo/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "plugins/n-test": { "name": "@dotcom-tool-kit/n-test", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/logger": "^4.0.1", "@dotcom-tool-kit/state": "^4.0.0", "@financial-times/n-test": "^6.1.0-beta.1", "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "@types/jest": "^27.4.0", "winston": "^3.5.1" @@ -32100,19 +32564,19 @@ }, "plugins/next-router": { "name": "@dotcom-tool-kit/next-router", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/doppler": "^2.0.2", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/doppler": "^2.0.3", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "@dotcom-tool-kit/state": "^4.0.0", "ft-next-router": "^3.0.0", "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1" + "@dotcom-tool-kit/schemas": "^1.2.0" }, "engines": { "node": "18.x || 20.x", @@ -32234,19 +32698,19 @@ }, "plugins/node": { "name": "@dotcom-tool-kit/node", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/doppler": "^2.0.2", - "@dotcom-tool-kit/error": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/doppler": "^2.0.3", + "@dotcom-tool-kit/error": "^4.0.1", "@dotcom-tool-kit/state": "^4.0.0", "get-port": "^5.1.1", "tslib": "^2.3.1", "wait-port": "^0.2.9" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1" + "@dotcom-tool-kit/schemas": "^1.2.0" }, "engines": { "node": "18.x || 20.x", @@ -32263,18 +32727,18 @@ }, "plugins/nodemon": { "name": "@dotcom-tool-kit/nodemon", - "version": "4.0.2", + "version": "4.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/doppler": "^2.0.2", - "@dotcom-tool-kit/error": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/doppler": "^2.0.3", + "@dotcom-tool-kit/error": "^4.0.1", "@dotcom-tool-kit/state": "^4.0.0", "get-port": "^5.1.1", "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@types/nodemon": "^1.19.1" }, "engines": { @@ -32293,12 +32757,12 @@ }, "plugins/npm": { "name": "@dotcom-tool-kit/npm", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/package-json-hook": "^5.0.2", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/package-json-hook": "^5.0.3", "@dotcom-tool-kit/state": "^4.0.0", "libnpmpack": "^3.1.0", "libnpmpublish": "^5.0.1", @@ -32530,10 +32994,10 @@ }, "plugins/package-json-hook": { "name": "@dotcom-tool-kit/package-json-hook", - "version": "5.0.2", + "version": "5.0.3", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", + "@dotcom-tool-kit/base": "^1.1.0", "@dotcom-tool-kit/conflict": "^1.0.0", "@dotcom-tool-kit/plugin": "^1.0.0", "@financial-times/package-json": "^3.0.0", @@ -32541,7 +33005,7 @@ "tslib": "^2.3.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "@types/lodash": "^4.14.185", "winston": "^3.5.1", @@ -32565,13 +33029,13 @@ }, "plugins/prettier": { "name": "@dotcom-tool-kit/prettier", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", - "@dotcom-tool-kit/package-json-hook": "^5.0.2", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", + "@dotcom-tool-kit/package-json-hook": "^5.0.3", "fast-glob": "^3.2.7", "hook-std": "^2.0.0", "prettier": "^2.2.1", @@ -32621,19 +33085,19 @@ }, "plugins/serverless": { "name": "@dotcom-tool-kit/serverless", - "version": "3.0.2", + "version": "3.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/doppler": "^2.0.2", - "@dotcom-tool-kit/error": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/doppler": "^2.0.3", + "@dotcom-tool-kit/error": "^4.0.1", "@dotcom-tool-kit/state": "^4.0.0", "get-port": "^5.1.1", "tslib": "^2.3.1", "wait-port": "^0.2.9" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1" + "@dotcom-tool-kit/schemas": "^1.2.0" }, "engines": { "node": "18.x || 20.x", @@ -32651,14 +33115,14 @@ }, "plugins/typescript": { "name": "@dotcom-tool-kit/typescript", - "version": "3.0.2", + "version": "3.1.0", "license": "ISC", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/logger": "^4.0.0" + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/logger": "^4.0.1" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^29.3.1", "typescript": "^4.9.4", "winston": "^3.8.2" @@ -32873,20 +33337,20 @@ }, "plugins/upload-assets-to-s3": { "name": "@dotcom-tool-kit/upload-assets-to-s3", - "version": "4.0.2", + "version": "4.1.0", "license": "ISC", "dependencies": { "@aws-sdk/client-s3": "^3.256.0", - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "glob": "^7.1.6", "mime": "^2.5.2", "tslib": "^2.3.1" }, "devDependencies": { "@aws-sdk/types": "^3.13.1", - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "@types/glob": "^7.1.3", "@types/jest": "^27.4.0", @@ -32908,17 +33372,17 @@ }, "plugins/webpack": { "name": "@dotcom-tool-kit/webpack", - "version": "4.0.2", + "version": "4.1.0", "license": "MIT", "dependencies": { - "@dotcom-tool-kit/base": "^1.0.0", - "@dotcom-tool-kit/error": "^4.0.0", - "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/base": "^1.1.0", + "@dotcom-tool-kit/error": "^4.0.1", + "@dotcom-tool-kit/logger": "^4.0.1", "tslib": "^2.3.1", "webpack-cli": "^4.6.0" }, "devDependencies": { - "@dotcom-tool-kit/schemas": "^1.1.1", + "@dotcom-tool-kit/schemas": "^1.2.0", "@jest/globals": "^27.4.6", "ts-node": "^10.0.0", "webpack": "^4.42.1", diff --git a/plugins/monorepo/.toolkitrc.yml b/plugins/monorepo/.toolkitrc.yml new file mode 100644 index 000000000..43d663a33 --- /dev/null +++ b/plugins/monorepo/.toolkitrc.yml @@ -0,0 +1,7 @@ +version: 2 + +init: + - ./lib/load-workspace-configs.js + +tasks: + WorkspaceCommand: ./lib/tasks/workspace-command.js diff --git a/plugins/monorepo/jest.config.js b/plugins/monorepo/jest.config.js new file mode 100644 index 000000000..2ea38bb31 --- /dev/null +++ b/plugins/monorepo/jest.config.js @@ -0,0 +1,5 @@ +const base = require('../../jest.config.base') + +module.exports = { + ...base.config +} diff --git a/plugins/monorepo/package.json b/plugins/monorepo/package.json new file mode 100644 index 000000000..6a5a1a5ff --- /dev/null +++ b/plugins/monorepo/package.json @@ -0,0 +1,45 @@ +{ + "name": "@dotcom-tool-kit/monorepo", + "version": "0.1.0", + "description": "", + "main": "lib", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "FT.com Platforms Team ", + "license": "ISC", + "repository": { + "type": "git", + "url": "https://github.com/financial-times/dotcom-tool-kit.git", + "directory": "plugins/monorepo" + }, + "bugs": "https://github.com/financial-times/dotcom-tool-kit/issues", + "homepage": "https://github.com/financial-times/dotcom-tool-kit/tree/main/plugins/monorepo", + "files": [ + "/lib", + ".toolkitrc.yml" + ], + "engines": { + "node": "18.x || 20.x", + "npm": "7.x || 8.x || 9.x" + }, + "volta": { + "extends": "../../package.json" + }, + "peerDependencies": { + "dotcom-tool-kit": "4.x" + }, + "dependencies": { + "@dotcom-tool-kit/logger": "^4.0.0", + "@dotcom-tool-kit/schemas": "^1.1.1", + "@npmcli/map-workspaces": "^3.0.6", + "minimatch": "^10.0.1", + "pluralize": "^8.0.0" + }, + "devDependencies": { + "@relmify/jest-serializer-strip-ansi": "^1.0.2", + "@types/npmcli__map-workspaces": "^3.0.4", + "@types/pluralize": "^0.0.33" + } +} diff --git a/plugins/monorepo/readme.md b/plugins/monorepo/readme.md new file mode 100644 index 000000000..085ea7ad3 --- /dev/null +++ b/plugins/monorepo/readme.md @@ -0,0 +1,119 @@ +# @dotcom-tool-kit/monorepo + +Enables Tool Kit to run commands across monorepo workspace packages. + +## Installation + +Install `@dotcom-tool-kit/monorepo` as a `devDependency` in your app: + +```sh +npm install --save-dev @dotcom-tool-kit/monorepo +``` + +Add the plugin to your [Tool Kit configuration](https://github.com/financial-times/dotcom-tool-kit/blob/main/readme.md#configuration): + +```yaml +plugins: + - '@dotcom-tool-kit/monorepo' +``` + +## Tool Kit monorepo workflows + +Most monorepos won't actually need to use this plugin. + +### When you _don't_ need the plugin + +Some common tooling, such as TypeScript and Jest, are already workspace-aware using configuration such as TypeScript's [project references](https://www.typescriptlang.org/docs/handbook/project-references.html). You can run these at the root level of your monorepo across all packages instead of running them package-by-package via Tool Kit and this plugin. + +In almost all cases that will work better; for example, running Jest separately in workspace packages will produce separate test summaries for each package, instead of one summary for all test suites across your monorepo. + +### When you _do_ need the plugin + +Where tooling isn't monorepo-aware itself, or you have tooling that you only want to run in a subset of your workspace packages, the `@dotcom-tool-kit/monorepo` plugin allows the root-level `.toolkitrc.yml` to run commands from workspace-package-level `.toolkitrc.yml` files. + +With this plugin, each workspace package is an independent Tool Kit root, which installs separate plugins for its own use cases. For example, a monorepo with an `api` package which is deployed to Heroku would install the `@dotcom-tool-kit/heroku` plugin as a dependency of the package, not at the root level, and would then include that plugin in the package `.toolkitrc.yml`. + +The root-level `.toolkitrc.yml` can then use the [`WorkspaceCommand`](#workspacecommand) task to forward commands such as `deploy:production` to just the workspace packages that have that command defined (in this case, the `api` package). + +### `@dotcom-tool-kit/monorepo` vs `npm run --workspaces` + +It's also possible to run `package.json` scripts in workspace packages using `npm run --workspaces`, and you can acheive a similar workflow by adding these commands as `package.json` scripts at the root level. Depending on your use case that may be preferable for your team or project, but be aware of these tradeoffs: + +- If we find there are common monorepo use cases between multiple projects, we can extract the Tool Kit configuration for that into a plugin that can be shared between projects. We can't do that if you're using `package.json` scripts. +- Mixing between `package.json` scripts and Tool Kit tasks would require chaining them with shell syntax in the `package.json` script, which is harder to read and less maintainable than having all the configuration in `.toolkitrc.yml`, and has worse error-handling behaviour. +- Due to a [limitation](#plugin-limitations) in this plugin, `package.json` scripts in workspace packages can't be managed by Tool Kit. Any Tool Kit tasks in workspace packages you'd want to run via `npm run --workspaces` would have to be manually maintained as `package.json` scripts, risking your scripts becoming out of sync with the Tool Kit tasks you expect to be running. + +### Plugin limitations + +- Hooks in workspace packages are not installed, so configuration files like `package.json` in workspace packages can't be managed by Tool Kit. If you have a use case for this, please contact the Platforms team. + + +## Tasks + +### `WorkspaceCommand` + +Runs a Tool Kit command in all workspace packages that have that command. By default, runs the command that was used to run this task. + +For example, imagine a monorepo with these `.toolkitrc.yml` files: + +
.toolkitrc.yml + +~~~yml +commands: + run:local: WorkspaceCommand + build:local: WorkspaceCommand +~~~ + +
+ +
packages/api/.toolkitrc.yml + +~~~yml +commands: + run:local: Node +~~~ + +
+ +
packages/client/.toolkitrc.yml + +~~~yml +commands: + build:local: TypeScript +~~~ + +
+ +
packages/components/.toolkitrc.yml + +~~~yml +commands: + build:local: Webpack + run:local: + Webpack: + watch: true +~~~ + +
+ +Running `dotcom-tool-kit run:local` at the root level will run the `Node` task in `packages/api` and the `Webpack` task in watch mode in `packages/components`; running `dotcom-tool-kit build:local` will run `TypeScript` in `packages/client` and `Webpack` in `packages/components`. + +To run a particular command in the workspace instead of dynamically inferring the command from which was run at root level, set the `command` option for the task: + +~~~yml +commands: + build:ci: + WorkspaceCommand: + command: build:local +~~~ + + +#### Task options + +| Property | Description | Type | +| :-------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | +| `command` | A specific command to run instead of the command that ran this task. | `string` | +| `packageFilter` | By default, the command will run in every workspace command that has that command assigned to a task. This option is a glob pattern to filter the packages the command will run on. For example, if your workspace has packages in the `plugins` and `lib` folders, set `packageFilter` to `plugins/*` to only run only in the packages in `plugins`. | `string` | + +_All properties are optional._ + diff --git a/plugins/monorepo/src/load-workspace-configs.ts b/plugins/monorepo/src/load-workspace-configs.ts new file mode 100644 index 000000000..081bfc198 --- /dev/null +++ b/plugins/monorepo/src/load-workspace-configs.ts @@ -0,0 +1,58 @@ +import { Init, InitContext } from '@dotcom-tool-kit/base' +import path from 'path' +import fs from 'fs/promises' +import { ValidConfig } from '@dotcom-tool-kit/config' +import { loadConfig } from 'dotcom-tool-kit/lib/config' +import mapWorkspaces from '@npmcli/map-workspaces' +import { styles } from '@dotcom-tool-kit/logger' +import pluralize from 'pluralize' + +interface WorkspaceConfig { + packageId: string + root: string + config: ValidConfig +} + +export default class LoadWorkspaceConfigs extends Init { + private static _configs: WorkspaceConfig[] = [] + + static get configs() { + return LoadWorkspaceConfigs._configs + } + + private static set configs(configs: WorkspaceConfig[]) { + LoadWorkspaceConfigs._configs = configs + } + + async init({ cwd }: InitContext) { + const pkg = JSON.parse(await fs.readFile(path.join(cwd, 'package.json'), 'utf8')) + const workspaces = await mapWorkspaces({ cwd, pkg }) + const results = await Promise.allSettled( + Array.from(workspaces, async ([packageId, root]) => ({ + packageId, + root, + config: await loadConfig(this.logger, { root }).catch((error) => { + error.name = `${styles.plugin(packageId)} → ${error.name}` + throw error + }) + })) + ) + + const erroredConfigs = results.filter( + (result): result is PromiseRejectedResult => result.status === 'rejected' + ) + + if (erroredConfigs.length) { + throw new AggregateError( + erroredConfigs.map((result) => result.reason), + `${pluralize('error', erroredConfigs.length, true)} loading ${styles.filepath( + '.toolkitrc.yml' + )} in workspace packages` + ) + } + + LoadWorkspaceConfigs.configs = results + .filter((result): result is PromiseFulfilledResult => result.status === 'fulfilled') + .map((result) => result.value) + } +} diff --git a/plugins/monorepo/src/tasks/workspace-command.ts b/plugins/monorepo/src/tasks/workspace-command.ts new file mode 100644 index 000000000..20e50dd18 --- /dev/null +++ b/plugins/monorepo/src/tasks/workspace-command.ts @@ -0,0 +1,44 @@ +import { Task, TaskRunContext } from '@dotcom-tool-kit/base' +import { runTasksFromConfig } from 'dotcom-tool-kit/lib/tasks' +import { WorkspaceCommandSchema } from '@dotcom-tool-kit/schemas/lib/tasks/workspace-command' +import {minimatch} from 'minimatch' +import pluralize from 'pluralize' +import { styles } from '@dotcom-tool-kit/logger' +import LoadWorkspaceConfigs from '../load-workspace-configs' + + +export default class WorkspaceCommand extends Task<{ task: typeof WorkspaceCommandSchema }> { + async run({ command, files }: TaskRunContext) { + const configsWithCommand = LoadWorkspaceConfigs.configs.filter( + ({config}) => command in config.commandTasks + ) + + this.logger.info(`Running ${styles.command(command)} in: +${configsWithCommand.map(({ packageId }) => `- ${styles.plugin(packageId)}`).join('\n')} +`) + + const results = await Promise.allSettled( + configsWithCommand.map(async ({ config, packageId, root }) => { + if(!this.options.packageFilter || minimatch(root, this.options.packageFilter)) { + await runTasksFromConfig(this.logger.child({ packageId }), config, [command], files).catch( + error => { + error.name = `${styles.plugin(packageId)} → ${error.name}` + throw error + } + ) + } + }) + ) + + const erroredCommands = results.filter( + (result): result is PromiseRejectedResult => result.status === 'rejected' + ) + + if (erroredCommands.length) { + throw new AggregateError( + erroredCommands.map(result => result.reason), + `${pluralize('error', erroredCommands.length, true)} running command ${styles.command(this.options.command ?? command)} in workspace packages` + ) + } + } +} diff --git a/plugins/monorepo/test/__snapshots__/load-workspace-configs.test.ts.snap b/plugins/monorepo/test/__snapshots__/load-workspace-configs.test.ts.snap new file mode 100644 index 000000000..f030469bd --- /dev/null +++ b/plugins/monorepo/test/__snapshots__/load-workspace-configs.test.ts.snap @@ -0,0 +1,1766 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LoadWorkspaceConfigs should load multiple tool kit configs from workspace packages 1`] = ` +[ + { + "config": { + "commandTasks": { + "build:ci": { + "id": "build:ci", + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + "tasks": [ + { + "options": { + "envName": "production", + }, + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + "task": "Webpack", + }, + ], + }, + "build:local": { + "id": "build:local", + "plugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "tasks": [ + { + "options": { + "envName": "development", + }, + "plugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "task": "Webpack", + }, + ], + }, + "build:remote": { + "id": "build:remote", + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + "tasks": [ + { + "options": { + "envName": "production", + }, + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + "task": "Webpack", + }, + ], + }, + "run:local": { + "id": "run:local", + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + "tasks": [ + { + "options": { + "envName": "development", + "watch": true, + }, + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + "task": "Webpack", + }, + ], + }, + }, + "hookManagedFiles": Set {}, + "hooks": {}, + "inits": [], + "pluginOptions": { + "app root": { + "forPlugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "options": { + "allowNativeFetch": false, + }, + "plugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + }, + }, + "plugins": { + "@dotcom-tool-kit/webpack": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + "app root": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + }, + "resolutionTrackers": { + "reducedInstallationPlugins": Set {}, + "resolvedPluginOptions": Set { + "@dotcom-tool-kit/webpack", + "app root", + }, + "resolvedPlugins": Set { + "@dotcom-tool-kit/webpack", + "app root", + }, + "substitutedPlugins": Set { + "@dotcom-tool-kit/webpack", + "app root", + }, + }, + "root": "plugins/monorepo/test/files/successful/a", + "taskOptions": {}, + "tasks": { + "Webpack": { + "modulePath": "./lib/tasks/webpack", + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/webpack", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Webpack": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/webpack", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/a", + }, + "rcFile": { + "commands": { + "build:ci": { + "Webpack": { + "envName": "production", + }, + }, + "build:local": { + "Webpack": { + "envName": "development", + }, + }, + "build:remote": { + "Webpack": { + "envName": "production", + }, + }, + "run:local": { + "Webpack": { + "envName": "development", + "watch": true, + }, + }, + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Webpack": "./lib/tasks/webpack", + }, + "version": 2, + }, + "root": "plugins/webpack", + }, + }, + }, + }, + "packageId": "@monorepo-plugin-tests/a", + "root": "plugins/monorepo/test/files/successful/a", + }, + { + "config": { + "commandTasks": { + "build:ci": { + "id": "build:ci", + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + "tasks": [ + { + "options": {}, + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + "task": "Babel", + }, + ], + }, + "build:local": { + "id": "build:local", + "plugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "tasks": [ + { + "options": { + "envName": "development", + }, + "plugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "task": "Babel", + }, + ], + }, + "build:remote": { + "id": "build:remote", + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + "tasks": [ + { + "options": {}, + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + "task": "Babel", + }, + ], + }, + }, + "hookManagedFiles": Set {}, + "hooks": {}, + "inits": [], + "pluginOptions": { + "app root": { + "forPlugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "options": { + "allowNativeFetch": false, + }, + "plugin": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + }, + }, + "plugins": { + "@dotcom-tool-kit/babel": { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + "app root": { + "children": [ + { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": [Circular], + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + }, + "resolutionTrackers": { + "reducedInstallationPlugins": Set {}, + "resolvedPluginOptions": Set { + "@dotcom-tool-kit/babel", + "app root", + }, + "resolvedPlugins": Set { + "@dotcom-tool-kit/babel", + "app root", + }, + "substitutedPlugins": Set { + "@dotcom-tool-kit/babel", + "app root", + }, + }, + "root": "plugins/monorepo/test/files/successful/b", + "taskOptions": {}, + "tasks": { + "Babel": { + "modulePath": "./lib/tasks/babel", + "plugin": { + "children": [], + "id": "@dotcom-tool-kit/babel", + "parent": { + "children": [ + [Circular], + ], + "id": "app root", + "parent": undefined, + "rcFile": { + "commands": { + "build:local": [ + { + "Babel": { + "envName": "development", + }, + }, + ], + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [ + "@dotcom-tool-kit/babel", + ], + "tasks": {}, + "version": undefined, + }, + "root": "plugins/monorepo/test/files/successful/b", + }, + "rcFile": { + "commands": { + "build:ci": "Babel", + "build:local": "Babel", + "build:remote": "Babel", + }, + "hooks": undefined, + "init": [], + "installs": {}, + "options": { + "hooks": [], + "plugins": {}, + "tasks": {}, + }, + "plugins": [], + "tasks": { + "Babel": "./lib/tasks/babel", + }, + "version": 2, + }, + "root": "plugins/babel", + }, + }, + }, + }, + "packageId": "@monorepo-plugin-tests/b", + "root": "plugins/monorepo/test/files/successful/b", + }, +] +`; diff --git a/plugins/monorepo/test/files/invalid/a/.toolkitrc.yml b/plugins/monorepo/test/files/invalid/a/.toolkitrc.yml new file mode 100644 index 000000000..cc65c3b03 --- /dev/null +++ b/plugins/monorepo/test/files/invalid/a/.toolkitrc.yml @@ -0,0 +1,7 @@ +plugins: + - @dotcom-tool-kit/webpack + +commands: + build:local: + - Webpack: + envName: development diff --git a/plugins/monorepo/test/files/invalid/a/package.json b/plugins/monorepo/test/files/invalid/a/package.json new file mode 100644 index 000000000..beed862e3 --- /dev/null +++ b/plugins/monorepo/test/files/invalid/a/package.json @@ -0,0 +1,3 @@ +{ + "name": "@monorepo-plugin-tests/a" +} diff --git a/plugins/monorepo/test/files/invalid/b/.toolkitrc.yml b/plugins/monorepo/test/files/invalid/b/.toolkitrc.yml new file mode 100644 index 000000000..75dc6be0e --- /dev/null +++ b/plugins/monorepo/test/files/invalid/b/.toolkitrc.yml @@ -0,0 +1,4 @@ +plugins: + - @dotcom-tool-kit/serverless + +# deliberately missing plugin options to fail validation diff --git a/plugins/monorepo/test/files/invalid/b/package.json b/plugins/monorepo/test/files/invalid/b/package.json new file mode 100644 index 000000000..695332fd9 --- /dev/null +++ b/plugins/monorepo/test/files/invalid/b/package.json @@ -0,0 +1,3 @@ +{ + "name": "@monorepo-plugin-tests/b" +} diff --git a/plugins/monorepo/test/files/invalid/c/.toolkitrc.yml b/plugins/monorepo/test/files/invalid/c/.toolkitrc.yml new file mode 100644 index 000000000..fad8276d7 --- /dev/null +++ b/plugins/monorepo/test/files/invalid/c/.toolkitrc.yml @@ -0,0 +1,4 @@ +plugins: + - @dotcom-tool-kit/heroku + +# deliberately missing plugin options to fail validation diff --git a/plugins/monorepo/test/files/invalid/c/package.json b/plugins/monorepo/test/files/invalid/c/package.json new file mode 100644 index 000000000..32d72cd2b --- /dev/null +++ b/plugins/monorepo/test/files/invalid/c/package.json @@ -0,0 +1,3 @@ +{ + "name": "@monorepo-plugin-tests/c" +} diff --git a/plugins/monorepo/test/files/invalid/package.json b/plugins/monorepo/test/files/invalid/package.json new file mode 100644 index 000000000..c12dcfa8d --- /dev/null +++ b/plugins/monorepo/test/files/invalid/package.json @@ -0,0 +1,7 @@ +{ + "workspaces": [ + "./a", + "./b", + "./c" + ] +} diff --git a/plugins/monorepo/test/files/successful/a/.toolkitrc.yml b/plugins/monorepo/test/files/successful/a/.toolkitrc.yml new file mode 100644 index 000000000..cc65c3b03 --- /dev/null +++ b/plugins/monorepo/test/files/successful/a/.toolkitrc.yml @@ -0,0 +1,7 @@ +plugins: + - @dotcom-tool-kit/webpack + +commands: + build:local: + - Webpack: + envName: development diff --git a/plugins/monorepo/test/files/successful/a/package.json b/plugins/monorepo/test/files/successful/a/package.json new file mode 100644 index 000000000..beed862e3 --- /dev/null +++ b/plugins/monorepo/test/files/successful/a/package.json @@ -0,0 +1,3 @@ +{ + "name": "@monorepo-plugin-tests/a" +} diff --git a/plugins/monorepo/test/files/successful/b/.toolkitrc.yml b/plugins/monorepo/test/files/successful/b/.toolkitrc.yml new file mode 100644 index 000000000..69cceb6d6 --- /dev/null +++ b/plugins/monorepo/test/files/successful/b/.toolkitrc.yml @@ -0,0 +1,7 @@ +plugins: + - @dotcom-tool-kit/babel + +commands: + build:local: + - Babel: + envName: development diff --git a/plugins/monorepo/test/files/successful/b/package.json b/plugins/monorepo/test/files/successful/b/package.json new file mode 100644 index 000000000..695332fd9 --- /dev/null +++ b/plugins/monorepo/test/files/successful/b/package.json @@ -0,0 +1,3 @@ +{ + "name": "@monorepo-plugin-tests/b" +} diff --git a/plugins/monorepo/test/files/successful/package.json b/plugins/monorepo/test/files/successful/package.json new file mode 100644 index 000000000..9fe54da0c --- /dev/null +++ b/plugins/monorepo/test/files/successful/package.json @@ -0,0 +1,6 @@ +{ + "workspaces": [ + "./a", + "./b" + ] +} diff --git a/plugins/monorepo/test/load-workspace-configs.test.ts b/plugins/monorepo/test/load-workspace-configs.test.ts new file mode 100644 index 000000000..375be3533 --- /dev/null +++ b/plugins/monorepo/test/load-workspace-configs.test.ts @@ -0,0 +1,99 @@ +import path from 'path' +import LoadWorkspaceConfigs from '../src/load-workspace-configs' +import winston, { Logger } from 'winston' +import { stripAnsi } from '@relmify/jest-serializer-strip-ansi' + +const logger = winston as unknown as Logger + +// force resolveRoot to return relative paths for machine-agnostic snapshots +jest.mock('../../../core/cli/lib/plugin/resolve-root', () => { + const { resolveRoot } = jest.requireActual('../../../core/cli/lib/plugin/resolve-root') + return { + resolveRoot(id: string, root: string) { + return path.relative(process.cwd(), resolveRoot(id, root)) + } + } +}) + +expect.addSnapshotSerializer(stripAnsi) + +expect.addSnapshotSerializer({ + test(value) { + return value instanceof Error && value.name === 'AggregateError' + }, + + serialize(val, config, indentation, depth, refs, printer) { + return `AggregateError ${printer(val.message, config, indentation, depth, refs)} ${printer( + { errors: val.errors }, + config, + indentation, + depth, + refs + )}` + } +}) + +expect.addSnapshotSerializer({ + test(value) { + return value instanceof Error && value.constructor.name === 'ToolKitError' + }, + + serialize(val, config, indentation, depth, refs, printer) { + return `${printer(val.name, config, indentation, depth, refs)} ${printer( + val.message, + config, + indentation, + depth, + refs + )} ${printer({ details: val.details }, config, indentation, depth, refs)}` + } +}) + +describe('LoadWorkspaceConfigs', () => { + beforeEach(() => { + // clear the singleton before each test + LoadWorkspaceConfigs['configs'] = [] + }) + + it('should load multiple tool kit configs from workspace packages', async () => { + const lwc = new LoadWorkspaceConfigs(logger) + + await expect( + lwc.init({ + cwd: path.relative(process.cwd(), path.resolve(__dirname, './files/successful')) + }) + ).resolves.toBeUndefined() + + expect(LoadWorkspaceConfigs.configs).toMatchSnapshot() + }) + + it('should report all config load failures as an AggregateError', async () => { + const lwc = new LoadWorkspaceConfigs(logger) + + await expect( + lwc.init({ + cwd: path.relative(process.cwd(), path.resolve(__dirname, './files/invalid')) + }) + ).rejects.toMatchInlineSnapshot(` + AggregateError "2 errors loading .toolkitrc.yml in workspace packages" { + "errors": [ + "@monorepo-plugin-tests/b → ToolKitError" "There are options in your .toolkitrc.yml that aren't what Tool Kit expected." { + "details": "Please update the options so that they are the expected types. + ! 2 issues in @dotcom-tool-kit/serverless: + - Required at "awsAccountId" + - Required at "systemCode" + + You can refer to the README for the plugin for examples and descriptions of the options used.", + }, + "@monorepo-plugin-tests/c → ToolKitError" "There are options in your .toolkitrc.yml that aren't what Tool Kit expected." { + "details": "Please update the options so that they are the expected types. + ! 1 issue in @dotcom-tool-kit/heroku: + - Required at "pipeline" + + You can refer to the README for the plugin for examples and descriptions of the options used.", + }, + ], + } + `) + }) +}) diff --git a/plugins/monorepo/tsconfig.json b/plugins/monorepo/tsconfig.json new file mode 100644 index 000000000..60a7a7627 --- /dev/null +++ b/plugins/monorepo/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../tsconfig.settings.json", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src" + }, + "references": [ + { + "path": "../../lib/base" + }, + { + "path": "../../lib/schemas" + }, + { + "path": "../../lib/logger" + } + ], + "include": [ + "src/**/*" + ] +} diff --git a/plugins/nodemon/src/tasks/nodemon.ts b/plugins/nodemon/src/tasks/nodemon.ts index 9a901c4b8..5d1869c22 100644 --- a/plugins/nodemon/src/tasks/nodemon.ts +++ b/plugins/nodemon/src/tasks/nodemon.ts @@ -1,4 +1,4 @@ -import { hookFork } from '@dotcom-tool-kit/logger' +import { hookFork, styles } from '@dotcom-tool-kit/logger' import { Task, TaskRunContext } from '@dotcom-tool-kit/base' import { NodemonSchema } from '@dotcom-tool-kit/schemas/lib/tasks/nodemon' import { writeState } from '@dotcom-tool-kit/state' @@ -7,15 +7,28 @@ import getPort from 'get-port' import nodemon from 'nodemon' import { Readable } from 'stream' import { shouldDisableNativeFetch } from 'dotcom-tool-kit' +import { ToolKitError } from '@dotcom-tool-kit/error' export default class Nodemon extends Task<{ task: typeof NodemonSchema }> { - async run({ config }: TaskRunContext): Promise { + async run({ config, cwd }: TaskRunContext): Promise { const { entry, configPath, useDoppler, ports } = this.options + if (cwd !== process.cwd()) { + const error = new ToolKitError('the Nodemon task does not support monorepos') + error.details = `Nodemon's support for running in specific directories changes the global environment, so it's not supported for use in monorepos. Use the ${styles.task( + 'Node' + )} task with ${styles.code('watch: true')} instead.` + throw error + } + let dopplerEnv = {} if (useDoppler) { - const doppler = new DopplerEnvVars(this.logger, 'dev', config.pluginOptions['@dotcom-tool-kit/doppler']?.options) + const doppler = new DopplerEnvVars( + this.logger, + 'dev', + config.pluginOptions['@dotcom-tool-kit/doppler']?.options + ) dopplerEnv = await doppler.get() } diff --git a/plugins/typescript/src/tasks/typescript.ts b/plugins/typescript/src/tasks/typescript.ts index 9834e2a7d..ff93d43f1 100644 --- a/plugins/typescript/src/tasks/typescript.ts +++ b/plugins/typescript/src/tasks/typescript.ts @@ -3,10 +3,9 @@ import { Task, TaskRunContext } from '@dotcom-tool-kit/base' import type { TypeScriptSchema } from '@dotcom-tool-kit/schemas/lib/tasks/typescript' import { fork } from 'child_process' -const tscPath = require.resolve('typescript/bin/tsc') - export default class TypeScript extends Task<{ task: typeof TypeScriptSchema }> { - async run({cwd}: TaskRunContext): Promise { + async run({ cwd }: TaskRunContext): Promise { + const tscPath = require.resolve('typescript/bin/tsc', { paths: [cwd] }) const args = [] // TODO:KB:20240408 refactor this diff --git a/scripts/create-plugin.js b/scripts/create-plugin.js index f33e804ed..d0339f1a3 100755 --- a/scripts/create-plugin.js +++ b/scripts/create-plugin.js @@ -38,6 +38,9 @@ pkg.engines = { node: '18.x || 20.x', npm: '7.x || 8.x || 9.x' } +pkg.volta = { + extends: '../../package.json' +} pkg.peerDependencies = { 'dotcom-tool-kit': '3.x' } diff --git a/scripts/generate-docs.js b/scripts/generate-docs.js index 356727a38..51be65c26 100644 --- a/scripts/generate-docs.js +++ b/scripts/generate-docs.js @@ -114,9 +114,9 @@ async function main() { const readmePath = path.join('plugins', plugin, 'readme.md') const generatedOptionsMarkdown = await formatPluginSchemas(plugin) - const originalReadme = await fs.readFile(readmePath, 'utf-8') - try { + const originalReadme = await fs.readFile(readmePath, 'utf-8') + const replacedReadme = replaceBetween( originalReadme, generatedOptionsMarkdown, @@ -127,7 +127,11 @@ async function main() { await fs.writeFile(readmePath, replacedReadme, 'utf-8') console.log(`written ${readmePath}`) } catch (e) { - console.error(`no replacement markers in ${readmePath}`) + if (e.code === 'ENOENT') { + console.error(`${plugin} has no readme`) + } else { + console.error(`no replacement markers in ${readmePath}`) + } } }) ) diff --git a/tsconfig.json b/tsconfig.json index f214674fd..3a440f206 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -120,6 +120,9 @@ }, { "path": "lib/schemas" + }, + { + "path": "plugins/monorepo" } ] }