quidproquo-cli 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/cli/commandRegistry.js +5 -0
- package/lib/commonjs/cli/commandRegistry.js.map +1 -1
- package/lib/commonjs/commands/checkCircular.d.ts +1 -0
- package/lib/commonjs/commands/checkCircular.js +70 -0
- package/lib/commonjs/commands/checkCircular.js.map +1 -0
- package/lib/commonjs/commands/synth.js +12 -1
- package/lib/commonjs/commands/synth.js.map +1 -1
- package/lib/commonjs/lib/circularImports.d.ts +3 -0
- package/lib/commonjs/lib/circularImports.js +79 -0
- package/lib/commonjs/lib/circularImports.js.map +1 -0
- package/lib/commonjs/lib/runCommand.d.ts +1 -0
- package/lib/commonjs/lib/runCommand.js +28 -3
- package/lib/commonjs/lib/runCommand.js.map +1 -1
- package/lib/commonjs/platforms/aws/goDocker.js +17 -32
- package/lib/commonjs/platforms/aws/goDocker.js.map +1 -1
- package/lib/esm/cli/commandRegistry.js +5 -0
- package/lib/esm/cli/commandRegistry.js.map +1 -1
- package/lib/esm/commands/checkCircular.d.ts +1 -0
- package/lib/esm/commands/checkCircular.js +55 -0
- package/lib/esm/commands/checkCircular.js.map +1 -0
- package/lib/esm/commands/synth.js +12 -1
- package/lib/esm/commands/synth.js.map +1 -1
- package/lib/esm/lib/circularImports.d.ts +3 -0
- package/lib/esm/lib/circularImports.js +61 -0
- package/lib/esm/lib/circularImports.js.map +1 -0
- package/lib/esm/lib/runCommand.d.ts +1 -0
- package/lib/esm/lib/runCommand.js +25 -2
- package/lib/esm/lib/runCommand.js.map +1 -1
- package/lib/esm/platforms/aws/goDocker.js +17 -32
- package/lib/esm/platforms/aws/goDocker.js.map +1 -1
- package/package.json +11 -10
|
@@ -98,6 +98,11 @@ exports.cliCommands = [
|
|
|
98
98
|
summary: 'Flip manifests to the uploaded versions',
|
|
99
99
|
run: (a) => require('../commands/publish').publishDeployCommand(a),
|
|
100
100
|
},
|
|
101
|
+
{
|
|
102
|
+
name: 'check:circular',
|
|
103
|
+
summary: 'Scan workspace sources for circular imports (fails on cycles; --warn to only report)',
|
|
104
|
+
run: (a) => require('../commands/checkCircular').checkCircularCommand(a),
|
|
105
|
+
},
|
|
101
106
|
{
|
|
102
107
|
name: 'hooks',
|
|
103
108
|
usageArgs: '<name>',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandRegistry.js","sourceRoot":"","sources":["../../../src/cli/commandRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["// Single source of truth for every qpq command: its name, the one-line\n// summary (shared by `qpq help` and the interactive menu) and a runner.\n//\n// Command modules are required lazily inside each runner so a simple\n// `qpq help` doesn't pay for the whole toolchain, and so ts-node can be\n// registered before any command module (or anything it requires) loads.\nimport { promptText } from '../lib/prompts';\n\nexport type CliCommand = {\n name: string;\n // Argument hint shown in the usage text, e.g. '[svc] [stack]'.\n usageArgs?: string;\n summary: string;\n // Extra usage-only detail lines, indented under the summary.\n usageExtra?: string[];\n // Menu-only: commands that need a positional argument (which the menu has\n // no argv to carry) gather it here before running.\n promptArgs?: () => Promise<string[]>;\n run: (commandArgv: string[]) => Promise<void>;\n};\n\n// `qpq hooks` needs a hook name; when launched from the menu there is no\n// argv to pass it in, so ask.\nconst promptHookName = async (): Promise<string[]> => [\n await promptText('Hook name (runs qpq:<name>, or plain <name>, in every app/package that defines it):'),\n];\n\n/* eslint-disable @typescript-eslint/no-require-imports */\nexport const cliCommands: CliCommand[] = [\n {\n name: 'go',\n usageArgs: '[svc] [stack]',\n summary: 'Deploy services (interactive; platform from deploy.config.json, default aws).',\n usageExtra: [\n 'Pass positional args to skip prompts, e.g. qpq go all all — svc is',\n \"'all' | comma-list | account | domain | bootstrap; stack is all|inf|api|web|views.\",\n \"A full 'all all' (or 'all api') deploy also publishes federated backends.\",\n ],\n run: (a) => require('../commands/go').goCommand(a),\n },\n {\n name: 'go:docker',\n summary: 'Same as go (incl. positional args), but deploys in parallel via docker',\n run: (a) => require('../commands/goDocker').goDockerCommand(a),\n },\n {\n name: 'go:dev',\n summary: 'Run the full local dev stack (api + web) in one process',\n run: (a) => require('../commands/goDev').goDevCommand(a),\n },\n {\n name: 'go:dev:api',\n summary: 'Run the local API dev server (hot reload)',\n run: (a) => require('../commands/goDevApi').goDevApiCommand(a),\n },\n {\n name: 'go:dev:web',\n summary: 'Run every views microfrontend dev server',\n run: (a) => require('../commands/goDevWeb').goDevWebCommand(a),\n },\n {\n name: 'teardown',\n summary: 'Destroy web/api/inf stacks for selected services (interactive)',\n run: (a) => require('../commands/teardown').teardownCommand(a),\n },\n {\n name: 'clear-resources',\n summary: 'Empty selected buckets/tables (data only, stacks untouched; interactive)',\n run: (a) => require('../commands/clearResources').clearResourcesCommand(a),\n },\n {\n name: 'synth',\n usageArgs: '[service]',\n summary: 'Synth QPQ configs to dist/apps/<app>/infrastructure',\n run: (a) => require('../commands/synth').synthCommand(a),\n },\n {\n name: 'prep',\n summary: 'Regenerate apps/<app>/tsconfig.federated.json',\n run: (a) => require('../commands/prep').prepCommand(a),\n },\n {\n name: 'publish',\n summary: 'Build + upload + deploy federated remotes',\n run: (a) => require('../commands/publish').publishCommand(a),\n },\n {\n name: 'publish:build',\n summary: 'Build federated remotes locally',\n run: (a) => require('../commands/publish').publishBuildCommand(a),\n },\n {\n name: 'publish:upload',\n summary: 'Upload built version dirs (nothing goes live)',\n run: (a) => require('../commands/publish').publishUploadCommand(a),\n },\n {\n name: 'publish:deploy',\n summary: 'Flip manifests to the uploaded versions',\n run: (a) => require('../commands/publish').publishDeployCommand(a),\n },\n {\n name: 'hooks',\n usageArgs: '<name>',\n summary: 'Run qpq:<name> (or plain <name>) in every app/package that defines it (dependency ordered, parallel; --jobs=N)',\n promptArgs: promptHookName,\n run: (a) => require('../commands/hooks').hooksCommand(a),\n },\n];\n/* eslint-enable @typescript-eslint/no-require-imports */\n\n// Width of the \"name [args]\" column in the usage text.\nconst usageColumnWidth = 17;\n\nexport const buildUsage = (): string => {\n const commandLines = cliCommands.flatMap((command) => {\n const nameAndArgs = command.usageArgs ? `${command.name} ${command.usageArgs}` : command.name;\n const extraLines = (command.usageExtra ?? []).map((line) => ` ${''.padEnd(usageColumnWidth)}${line}`);\n return [` ${nameAndArgs.padEnd(usageColumnWidth)}${command.summary}`, ...extraLines];\n });\n\n return [\n 'qpq — build, dev and deploy orchestration for QPQ apps',\n '',\n 'Usage: qpq <command> [--app <name>] [--env <name>] [--platform <name>]',\n ' qpq (no command opens an interactive menu)',\n '',\n 'Commands:',\n ...commandLines,\n '',\n ].join('\\n');\n};\n"]}
|
|
1
|
+
{"version":3,"file":"commandRegistry.js","sourceRoot":"","sources":["../../../src/cli/commandRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["// Single source of truth for every qpq command: its name, the one-line\n// summary (shared by `qpq help` and the interactive menu) and a runner.\n//\n// Command modules are required lazily inside each runner so a simple\n// `qpq help` doesn't pay for the whole toolchain, and so ts-node can be\n// registered before any command module (or anything it requires) loads.\nimport { promptText } from '../lib/prompts';\n\nexport type CliCommand = {\n name: string;\n // Argument hint shown in the usage text, e.g. '[svc] [stack]'.\n usageArgs?: string;\n summary: string;\n // Extra usage-only detail lines, indented under the summary.\n usageExtra?: string[];\n // Menu-only: commands that need a positional argument (which the menu has\n // no argv to carry) gather it here before running.\n promptArgs?: () => Promise<string[]>;\n run: (commandArgv: string[]) => Promise<void>;\n};\n\n// `qpq hooks` needs a hook name; when launched from the menu there is no\n// argv to pass it in, so ask.\nconst promptHookName = async (): Promise<string[]> => [\n await promptText('Hook name (runs qpq:<name>, or plain <name>, in every app/package that defines it):'),\n];\n\n/* eslint-disable @typescript-eslint/no-require-imports */\nexport const cliCommands: CliCommand[] = [\n {\n name: 'go',\n usageArgs: '[svc] [stack]',\n summary: 'Deploy services (interactive; platform from deploy.config.json, default aws).',\n usageExtra: [\n 'Pass positional args to skip prompts, e.g. qpq go all all — svc is',\n \"'all' | comma-list | account | domain | bootstrap; stack is all|inf|api|web|views.\",\n \"A full 'all all' (or 'all api') deploy also publishes federated backends.\",\n ],\n run: (a) => require('../commands/go').goCommand(a),\n },\n {\n name: 'go:docker',\n summary: 'Same as go (incl. positional args), but deploys in parallel via docker',\n run: (a) => require('../commands/goDocker').goDockerCommand(a),\n },\n {\n name: 'go:dev',\n summary: 'Run the full local dev stack (api + web) in one process',\n run: (a) => require('../commands/goDev').goDevCommand(a),\n },\n {\n name: 'go:dev:api',\n summary: 'Run the local API dev server (hot reload)',\n run: (a) => require('../commands/goDevApi').goDevApiCommand(a),\n },\n {\n name: 'go:dev:web',\n summary: 'Run every views microfrontend dev server',\n run: (a) => require('../commands/goDevWeb').goDevWebCommand(a),\n },\n {\n name: 'teardown',\n summary: 'Destroy web/api/inf stacks for selected services (interactive)',\n run: (a) => require('../commands/teardown').teardownCommand(a),\n },\n {\n name: 'clear-resources',\n summary: 'Empty selected buckets/tables (data only, stacks untouched; interactive)',\n run: (a) => require('../commands/clearResources').clearResourcesCommand(a),\n },\n {\n name: 'synth',\n usageArgs: '[service]',\n summary: 'Synth QPQ configs to dist/apps/<app>/infrastructure',\n run: (a) => require('../commands/synth').synthCommand(a),\n },\n {\n name: 'prep',\n summary: 'Regenerate apps/<app>/tsconfig.federated.json',\n run: (a) => require('../commands/prep').prepCommand(a),\n },\n {\n name: 'publish',\n summary: 'Build + upload + deploy federated remotes',\n run: (a) => require('../commands/publish').publishCommand(a),\n },\n {\n name: 'publish:build',\n summary: 'Build federated remotes locally',\n run: (a) => require('../commands/publish').publishBuildCommand(a),\n },\n {\n name: 'publish:upload',\n summary: 'Upload built version dirs (nothing goes live)',\n run: (a) => require('../commands/publish').publishUploadCommand(a),\n },\n {\n name: 'publish:deploy',\n summary: 'Flip manifests to the uploaded versions',\n run: (a) => require('../commands/publish').publishDeployCommand(a),\n },\n {\n name: 'check:circular',\n summary: 'Scan workspace sources for circular imports (fails on cycles; --warn to only report)',\n run: (a) => require('../commands/checkCircular').checkCircularCommand(a),\n },\n {\n name: 'hooks',\n usageArgs: '<name>',\n summary: 'Run qpq:<name> (or plain <name>) in every app/package that defines it (dependency ordered, parallel; --jobs=N)',\n promptArgs: promptHookName,\n run: (a) => require('../commands/hooks').hooksCommand(a),\n },\n];\n/* eslint-enable @typescript-eslint/no-require-imports */\n\n// Width of the \"name [args]\" column in the usage text.\nconst usageColumnWidth = 17;\n\nexport const buildUsage = (): string => {\n const commandLines = cliCommands.flatMap((command) => {\n const nameAndArgs = command.usageArgs ? `${command.name} ${command.usageArgs}` : command.name;\n const extraLines = (command.usageExtra ?? []).map((line) => ` ${''.padEnd(usageColumnWidth)}${line}`);\n return [` ${nameAndArgs.padEnd(usageColumnWidth)}${command.summary}`, ...extraLines];\n });\n\n return [\n 'qpq — build, dev and deploy orchestration for QPQ apps',\n '',\n 'Usage: qpq <command> [--app <name>] [--env <name>] [--platform <name>]',\n ' qpq (no command opens an interactive menu)',\n '',\n 'Commands:',\n ...commandLines,\n '',\n ].join('\\n');\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const checkCircularCommand: (argv: string[]) => Promise<void>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.checkCircularCommand = void 0;
|
|
13
|
+
// `qpq check:circular` — scan every workspace's src for circular imports (the
|
|
14
|
+
// class of bug that TDZ-crashes ESM bundles and silently drops exports under
|
|
15
|
+
// CJS). Cycles fail the command (exit 1) — they are never acceptable; --warn or
|
|
16
|
+
// QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without
|
|
17
|
+
// failing while fixing.
|
|
18
|
+
const circularImports_1 = require("../lib/circularImports");
|
|
19
|
+
const discovery_1 = require("../lib/discovery");
|
|
20
|
+
// madge reports every distinct loop path; one tangled module can produce dozens
|
|
21
|
+
// of chains through the same files. Merge chains that share any file into one
|
|
22
|
+
// group so the report shows each tangle once, with its full blast radius.
|
|
23
|
+
const groupCycles = (cycles) => {
|
|
24
|
+
var _a;
|
|
25
|
+
const parent = new Map();
|
|
26
|
+
const find = (file) => {
|
|
27
|
+
var _a;
|
|
28
|
+
const found = (_a = parent.get(file)) !== null && _a !== void 0 ? _a : file;
|
|
29
|
+
if (found === file) {
|
|
30
|
+
return file;
|
|
31
|
+
}
|
|
32
|
+
const rootFile = find(found);
|
|
33
|
+
parent.set(file, rootFile);
|
|
34
|
+
return rootFile;
|
|
35
|
+
};
|
|
36
|
+
for (const cycle of cycles) {
|
|
37
|
+
for (const file of cycle) {
|
|
38
|
+
parent.set(find(file), find(cycle[0]));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const groups = new Map();
|
|
42
|
+
for (const cycle of cycles) {
|
|
43
|
+
const key = find(cycle[0]);
|
|
44
|
+
const group = (_a = groups.get(key)) !== null && _a !== void 0 ? _a : { files: [], chainCount: 0 };
|
|
45
|
+
group.chainCount += 1;
|
|
46
|
+
group.files = [...new Set([...group.files, ...cycle])];
|
|
47
|
+
groups.set(key, group);
|
|
48
|
+
}
|
|
49
|
+
return [...groups.values()];
|
|
50
|
+
};
|
|
51
|
+
const checkCircularCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
|
52
|
+
const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;
|
|
53
|
+
const cycles = yield (0, circularImports_1.findWorkspaceImportCycles)((0, discovery_1.getRoot)());
|
|
54
|
+
if (cycles.length === 0) {
|
|
55
|
+
console.log('check:circular: no circular imports found');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const groups = groupCycles(cycles);
|
|
59
|
+
const colour = warnOnly ? '\x1b[33m' : '\x1b[31m';
|
|
60
|
+
for (const group of groups) {
|
|
61
|
+
const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';
|
|
62
|
+
console.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\n ${group.files.join('\n ')}\x1b[0m`);
|
|
63
|
+
}
|
|
64
|
+
console.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\x1b[0m`);
|
|
65
|
+
if (!warnOnly) {
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
exports.checkCircularCommand = checkCircularCommand;
|
|
70
|
+
//# sourceMappingURL=checkCircular.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkCircular.js","sourceRoot":"","sources":["../../../src/commands/checkCircular.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq check:circular` — scan every workspace's src for circular imports (the\n// class of bug that TDZ-crashes ESM bundles and silently drops exports under\n// CJS). Cycles fail the command (exit 1) — they are never acceptable; --warn or\n// QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without\n// failing while fixing.\nimport { findWorkspaceImportCycles, ImportCycle } from '../lib/circularImports';\nimport { getRoot } from '../lib/discovery';\n\ntype CycleGroup = { files: string[]; chainCount: number };\n\n// madge reports every distinct loop path; one tangled module can produce dozens\n// of chains through the same files. Merge chains that share any file into one\n// group so the report shows each tangle once, with its full blast radius.\nconst groupCycles = (cycles: ImportCycle[]): CycleGroup[] => {\n const parent = new Map<string, string>();\n\n const find = (file: string): string => {\n const found = parent.get(file) ?? file;\n if (found === file) {\n return file;\n }\n const rootFile = find(found);\n parent.set(file, rootFile);\n return rootFile;\n };\n\n for (const cycle of cycles) {\n for (const file of cycle) {\n parent.set(find(file), find(cycle[0]));\n }\n }\n\n const groups = new Map<string, CycleGroup>();\n for (const cycle of cycles) {\n const key = find(cycle[0]);\n const group = groups.get(key) ?? { files: [], chainCount: 0 };\n group.chainCount += 1;\n group.files = [...new Set([...group.files, ...cycle])];\n groups.set(key, group);\n }\n\n return [...groups.values()];\n};\n\nexport const checkCircularCommand = async (argv: string[]): Promise<void> => {\n const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;\n\n const cycles = await findWorkspaceImportCycles(getRoot());\n\n if (cycles.length === 0) {\n console.log('check:circular: no circular imports found');\n return;\n }\n\n const groups = groupCycles(cycles);\n\n const colour = warnOnly ? '\\x1b[33m' : '\\x1b[31m';\n for (const group of groups) {\n const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';\n console.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\\n ${group.files.join('\\n ')}\\x1b[0m`);\n }\n console.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\\x1b[0m`);\n\n if (!warnOnly) {\n process.exitCode = 1;\n }\n};\n"]}
|
|
@@ -63,7 +63,18 @@ const synthCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
63
63
|
// invoked inside a deploy they're already primed; standalone synth primes
|
|
64
64
|
// them from deploy.config.json (development default).
|
|
65
65
|
(0, deployEnv_1.primeDeployEnvFromConfig)(appName);
|
|
66
|
-
|
|
66
|
+
// Validate a specified service against the app's discovered services before it
|
|
67
|
+
// reaches loadServiceQpqConfig -> require. The bare-service-name branch above
|
|
68
|
+
// already checks this; the --app/env branch used to skip it, letting a typo hit
|
|
69
|
+
// a cryptic module-resolution error and a `../` value normalize into an arbitrary
|
|
70
|
+
// require target. Both paths now validate identically.
|
|
71
|
+
const appServices = (0, discovery_1.getServiceNamesWithSubdir)(appName, 'service');
|
|
72
|
+
if (specifiedServiceName && !appServices.includes(specifiedServiceName)) {
|
|
73
|
+
console.error(`Service '${specifiedServiceName}' not found in app '${appName}'`);
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const serviceNames = specifiedServiceName ? [specifiedServiceName] : appServices;
|
|
67
78
|
for (const folderName of serviceNames) {
|
|
68
79
|
try {
|
|
69
80
|
processConfig(folderName, appName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synth.js","sourceRoot":"","sources":["../../../src/commands/synth.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"synth.js","sourceRoot":"","sources":["../../../src/commands/synth.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq synth [service]` — synthesizes each backend service's QPQ config to\n// dist/apps/<app>/infrastructure/<module>-config.json.\n//\n// Runs with ts-node hooks registered (see runCli), which transpiles each\n// service's infrastructure.ts on require. Cross-package `@scope/*` imports\n// resolve through the workspace node_modules symlinks to already-built dist.\nimport { qpqCoreUtils } from 'quidproquo-core';\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { getPositionalArgs } from '../lib/args';\nimport { primeDeployEnvFromConfig } from '../lib/deployEnv';\nimport { getAvailableApps, getRoot, getServiceNamesWithSubdir } from '../lib/discovery';\nimport { loadServiceQpqConfig } from '../lib/qpqConfigs';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\n\nconst processConfig = (folderName: string, appName: string): void => {\n console.log(`Processing infrastructure: [${folderName}] for app [${appName}]`);\n const qpqConfig = loadServiceQpqConfig(appName, folderName);\n const moduleName = qpqCoreUtils.getApplicationModuleName(qpqConfig);\n\n const directoryPath = path.join(getRoot(), 'dist', 'apps', appName, 'infrastructure');\n fs.mkdirSync(directoryPath, { recursive: true });\n fs.writeFileSync(path.join(directoryPath, `${moduleName}-config.json`), JSON.stringify(qpqConfig, null, 2));\n console.log(` -> ${appName}/infrastructure/${moduleName}-config.json`);\n};\n\nexport const synthCommand = async (argv: string[]): Promise<void> => {\n const [specifiedServiceName] = getPositionalArgs(argv, ['--app', '--env']);\n\n const hasExplicitApp =\n argv.includes('--app') || argv.some((a) => a.startsWith('--app=')) || !!process.env.npm_config_app || !!process.env.DEPLOY_APP_NAME;\n\n let appNames: string[];\n if (specifiedServiceName && !hasExplicitApp) {\n // A bare service name is unambiguous — synth it in whichever app owns it.\n const appWithService = getAvailableApps().find((appName) => getServiceNamesWithSubdir(appName, 'service').includes(specifiedServiceName));\n if (!appWithService) {\n console.error(`Service '${specifiedServiceName}' not found in any app`);\n process.exit(1);\n }\n appNames = [appWithService];\n } else {\n const selection = await resolveAppSelection({\n argv,\n envVar: 'DEPLOY_APP_NAME',\n allowAll: true,\n });\n appNames = selection === 'all' ? getAvailableApps() : [selection];\n }\n\n console.log(`QPQ synthesizing apps: ${appNames.join(', ')}`);\n\n for (const appName of appNames) {\n // Service configs read ENVIRONMENT / AWS_DEFAULT_* at require time. When\n // invoked inside a deploy they're already primed; standalone synth primes\n // them from deploy.config.json (development default).\n primeDeployEnvFromConfig(appName);\n\n // Validate a specified service against the app's discovered services before it\n // reaches loadServiceQpqConfig -> require. The bare-service-name branch above\n // already checks this; the --app/env branch used to skip it, letting a typo hit\n // a cryptic module-resolution error and a `../` value normalize into an arbitrary\n // require target. Both paths now validate identically.\n const appServices = getServiceNamesWithSubdir(appName, 'service');\n if (specifiedServiceName && !appServices.includes(specifiedServiceName)) {\n console.error(`Service '${specifiedServiceName}' not found in app '${appName}'`);\n process.exitCode = 1;\n continue;\n }\n\n const serviceNames = specifiedServiceName ? [specifiedServiceName] : appServices;\n\n for (const folderName of serviceNames) {\n try {\n processConfig(folderName, appName);\n } catch (error) {\n console.error(`Failed to process ${folderName} in ${appName}:`, error);\n process.exitCode = 1;\n }\n }\n }\n};\n"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.findWorkspaceImportCycles = exports.getWorkspaceDirectories = void 0;
|
|
16
|
+
// Source-level circular import detection over the consumer repo's npm
|
|
17
|
+
// workspaces, powered by madge (AST-based dependency graph + cycle detection).
|
|
18
|
+
// Complements the rspack CircularCheckRspackPlugin (which needs a bundle to
|
|
19
|
+
// run): this scans TypeScript sources directly, so it can run inside tsc-only
|
|
20
|
+
// flows like `npm run validate-ts` with no bundling.
|
|
21
|
+
//
|
|
22
|
+
// Scope: each workspace's src, relative imports. Cross-package cycles are
|
|
23
|
+
// already impossible — TypeScript project references refuse to build them — so
|
|
24
|
+
// every runtime-relevant cycle lives inside one package's src. Type-only
|
|
25
|
+
// imports are skipped (skipTypeImports): tsc erases them, so they never create
|
|
26
|
+
// a runtime cycle.
|
|
27
|
+
const fs_1 = __importDefault(require("fs"));
|
|
28
|
+
const path_1 = __importDefault(require("path"));
|
|
29
|
+
// madge ships no type definitions; declare the narrow slice we use.
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
31
|
+
const madge = require('madge');
|
|
32
|
+
// Expand npm workspace globs (plain path segments and `*` segments only — the
|
|
33
|
+
// only forms npm workspaces use in practice) into existing directories.
|
|
34
|
+
const expandWorkspaceGlob = (root, pattern) => {
|
|
35
|
+
let candidates = [root];
|
|
36
|
+
for (const segment of pattern.split('/')) {
|
|
37
|
+
if (segment === '*') {
|
|
38
|
+
candidates = candidates.flatMap((dir) => fs_1.default.existsSync(dir)
|
|
39
|
+
? fs_1.default
|
|
40
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
41
|
+
.filter((entry) => entry.isDirectory())
|
|
42
|
+
.map((entry) => path_1.default.join(dir, entry.name))
|
|
43
|
+
: []);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
candidates = candidates.map((dir) => path_1.default.join(dir, segment));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return candidates.filter((dir) => fs_1.default.existsSync(dir) && fs_1.default.statSync(dir).isDirectory());
|
|
50
|
+
};
|
|
51
|
+
const getWorkspaceDirectories = (root) => {
|
|
52
|
+
var _a;
|
|
53
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(path_1.default.join(root, 'package.json'), 'utf8'));
|
|
54
|
+
const patterns = (_a = packageJson.workspaces) !== null && _a !== void 0 ? _a : [];
|
|
55
|
+
return patterns.flatMap((pattern) => expandWorkspaceGlob(root, pattern));
|
|
56
|
+
};
|
|
57
|
+
exports.getWorkspaceDirectories = getWorkspaceDirectories;
|
|
58
|
+
const findWorkspaceImportCycles = (root) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
|
+
const sourceDirs = (0, exports.getWorkspaceDirectories)(root)
|
|
60
|
+
.map((dir) => path_1.default.join(dir, 'src'))
|
|
61
|
+
.filter((dir) => fs_1.default.existsSync(dir));
|
|
62
|
+
// Excludes: node_modules and built output (dist/lib), declaration files
|
|
63
|
+
// (type-only, can't cycle at runtime), and anything madge resolves to outside
|
|
64
|
+
// the repo root (linked framework packages — their cycles surface through the
|
|
65
|
+
// rspack CircularCheckRspackPlugin instead, this command owns the consumer
|
|
66
|
+
// repo). Out-of-root paths start with '..' because baseDir is the repo root.
|
|
67
|
+
const result = yield madge(sourceDirs, {
|
|
68
|
+
baseDir: root,
|
|
69
|
+
fileExtensions: ['ts', 'tsx'],
|
|
70
|
+
excludeRegExp: [/node_modules/, /(^|\/)(dist|lib)\//, /\.d\.ts$/, /^\.\./],
|
|
71
|
+
detectiveOptions: {
|
|
72
|
+
ts: { skipTypeImports: true },
|
|
73
|
+
tsx: { skipTypeImports: true },
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
return result.circular();
|
|
77
|
+
});
|
|
78
|
+
exports.findWorkspaceImportCycles = findWorkspaceImportCycles;
|
|
79
|
+
//# sourceMappingURL=circularImports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circularImports.js","sourceRoot":"","sources":["../../../src/lib/circularImports.ts"],"names":[],"mappings":"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","sourcesContent":["// Source-level circular import detection over the consumer repo's npm\n// workspaces, powered by madge (AST-based dependency graph + cycle detection).\n// Complements the rspack CircularCheckRspackPlugin (which needs a bundle to\n// run): this scans TypeScript sources directly, so it can run inside tsc-only\n// flows like `npm run validate-ts` with no bundling.\n//\n// Scope: each workspace's src, relative imports. Cross-package cycles are\n// already impossible — TypeScript project references refuse to build them — so\n// every runtime-relevant cycle lives inside one package's src. Type-only\n// imports are skipped (skipTypeImports): tsc erases them, so they never create\n// a runtime cycle.\nimport fs from 'fs';\nimport path from 'path';\n\n// madge ships no type definitions; declare the narrow slice we use.\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst madge = require('madge') as (paths: string[], config: object) => Promise<{ circular(): string[][] }>;\n\nexport type ImportCycle = string[];\n\n// Expand npm workspace globs (plain path segments and `*` segments only — the\n// only forms npm workspaces use in practice) into existing directories.\nconst expandWorkspaceGlob = (root: string, pattern: string): string[] => {\n let candidates = [root];\n\n for (const segment of pattern.split('/')) {\n if (segment === '*') {\n candidates = candidates.flatMap((dir) =>\n fs.existsSync(dir)\n ? fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => path.join(dir, entry.name))\n : [],\n );\n } else {\n candidates = candidates.map((dir) => path.join(dir, segment));\n }\n }\n\n return candidates.filter((dir) => fs.existsSync(dir) && fs.statSync(dir).isDirectory());\n};\n\nexport const getWorkspaceDirectories = (root: string): string[] => {\n const packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));\n const patterns: string[] = packageJson.workspaces ?? [];\n return patterns.flatMap((pattern) => expandWorkspaceGlob(root, pattern));\n};\n\nexport const findWorkspaceImportCycles = async (root: string): Promise<ImportCycle[]> => {\n const sourceDirs = getWorkspaceDirectories(root)\n .map((dir) => path.join(dir, 'src'))\n .filter((dir) => fs.existsSync(dir));\n\n // Excludes: node_modules and built output (dist/lib), declaration files\n // (type-only, can't cycle at runtime), and anything madge resolves to outside\n // the repo root (linked framework packages — their cycles surface through the\n // rspack CircularCheckRspackPlugin instead, this command owns the consumer\n // repo). Out-of-root paths start with '..' because baseDir is the repo root.\n const result = await madge(sourceDirs, {\n baseDir: root,\n fileExtensions: ['ts', 'tsx'],\n excludeRegExp: [/node_modules/, /(^|\\/)(dist|lib)\\//, /\\.d\\.ts$/, /^\\.\\./],\n detectiveOptions: {\n ts: { skipTypeImports: true },\n tsx: { skipTypeImports: true },\n },\n });\n\n return result.circular();\n};\n"]}
|
|
@@ -4,6 +4,7 @@ export type RunCommandOptions = {
|
|
|
4
4
|
logCommand?: boolean;
|
|
5
5
|
};
|
|
6
6
|
export declare const runCommand: (command: string, args: string[], options?: RunCommandOptions) => Promise<void>;
|
|
7
|
+
export declare const runCommandBestEffort: (command: string, args: string[], options?: RunCommandOptions) => Promise<void>;
|
|
7
8
|
export type RunCommandPrefixedOptions = {
|
|
8
9
|
env?: Record<string, string>;
|
|
9
10
|
cwd?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runCommandPrefixed = exports.nextPrefixColor = exports.runCommand = void 0;
|
|
3
|
+
exports.runCommandPrefixed = exports.nextPrefixColor = exports.runCommandBestEffort = exports.runCommand = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
// Spawn a command, inheriting stdio, resolving on success. A non-zero exit
|
|
6
6
|
// REJECTS so a failed build/deploy stops the run.
|
|
@@ -12,7 +12,11 @@ const runCommand = (command, args, options = {}) => new Promise((resolve, reject
|
|
|
12
12
|
}
|
|
13
13
|
const child = (0, child_process_1.spawn)(command, validArgs, {
|
|
14
14
|
stdio: 'inherit',
|
|
15
|
-
|
|
15
|
+
// Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run
|
|
16
|
+
// without a shell so the already-array args are passed straight to the
|
|
17
|
+
// program and can't be re-interpreted by `sh -c` — no command injection via
|
|
18
|
+
// interpolated values (stack names, CI-supplied env, etc.).
|
|
19
|
+
shell: process.platform === 'win32',
|
|
16
20
|
cwd: (_a = options.cwd) !== null && _a !== void 0 ? _a : process.cwd(),
|
|
17
21
|
env: Object.assign(Object.assign({}, process.env), ((_b = options.env) !== null && _b !== void 0 ? _b : {})),
|
|
18
22
|
});
|
|
@@ -26,6 +30,23 @@ const runCommand = (command, args, options = {}) => new Promise((resolve, reject
|
|
|
26
30
|
});
|
|
27
31
|
});
|
|
28
32
|
exports.runCommand = runCommand;
|
|
33
|
+
// Run a command for its side effect only, swallowing both its output and its
|
|
34
|
+
// exit code — for best-effort cleanup steps (e.g. `docker rm -f` of a container
|
|
35
|
+
// that may not exist) that must never fail the run. Without a shell there's no
|
|
36
|
+
// `>/dev/null 2>&1 || true`, so quieting and non-failing happen here instead.
|
|
37
|
+
const runCommandBestEffort = (command, args, options = {}) => new Promise((resolve) => {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
const validArgs = args.filter((a) => !!a);
|
|
40
|
+
const child = (0, child_process_1.spawn)(command, validArgs, {
|
|
41
|
+
stdio: 'ignore',
|
|
42
|
+
shell: process.platform === 'win32',
|
|
43
|
+
cwd: (_a = options.cwd) !== null && _a !== void 0 ? _a : process.cwd(),
|
|
44
|
+
env: Object.assign(Object.assign({}, process.env), ((_b = options.env) !== null && _b !== void 0 ? _b : {})),
|
|
45
|
+
});
|
|
46
|
+
child.on('error', () => resolve());
|
|
47
|
+
child.on('exit', () => resolve());
|
|
48
|
+
});
|
|
49
|
+
exports.runCommandBestEffort = runCommandBestEffort;
|
|
29
50
|
const PREFIX_COLORS = [36, 32, 33, 35, 34, 96, 92, 93, 95, 94];
|
|
30
51
|
let colorIndex = 0;
|
|
31
52
|
// Hand each concurrent task a distinct prefix color so interleaved output is
|
|
@@ -45,7 +66,11 @@ const runCommandPrefixed = (label, command, args, options = {}) => new Promise((
|
|
|
45
66
|
const prefix = `\x1b[${(_a = options.color) !== null && _a !== void 0 ? _a : 36}m[${label}]\x1b[0m `;
|
|
46
67
|
const child = (0, child_process_1.spawn)(command, validArgs, {
|
|
47
68
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
48
|
-
|
|
69
|
+
// Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run
|
|
70
|
+
// without a shell so the already-array args are passed straight to the
|
|
71
|
+
// program and can't be re-interpreted by `sh -c` — no command injection via
|
|
72
|
+
// interpolated values (stack names, CI-supplied env, etc.).
|
|
73
|
+
shell: process.platform === 'win32',
|
|
49
74
|
cwd: (_b = options.cwd) !== null && _b !== void 0 ? _b : process.cwd(),
|
|
50
75
|
env: Object.assign(Object.assign({}, process.env), ((_c = options.env) !== null && _c !== void 0 ? _c : {})),
|
|
51
76
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../../../src/lib/runCommand.ts"],"names":[],"mappings":";;;AAAA,iDAAsC;AAYtC,2EAA2E;AAC3E,kDAAkD;AAC3C,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,IAAc,EAAE,UAA6B,EAAE,EAAiB,EAAE,CAC5G,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;;IAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1C,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,KAAK,GAAG,IAAA,qBAAK,EAAC,OAAO,EAAE,SAAS,EAAE;QACtC,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../../../src/lib/runCommand.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'child_process';\nimport type { Readable } from 'stream';\n\nexport type RunCommandOptions = {\n // Extra environment variables merged over the parent process env.\n env?: Record<string, string>;\n // Working directory for the child (defaults to cwd).\n cwd?: string;\n // Echo the command before running it.\n logCommand?: boolean;\n};\n\n// Spawn a command, inheriting stdio, resolving on success. A non-zero exit\n// REJECTS so a failed build/deploy stops the run.\nexport const runCommand = (command: string, args: string[], options: RunCommandOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n const validArgs = args.filter((a) => !!a);\n\n if (options.logCommand) {\n console.log(`Running command: ${command} ${validArgs.join(' ')}`);\n }\n\n const child = spawn(command, validArgs, {\n stdio: 'inherit',\n // Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run\n // without a shell so the already-array args are passed straight to the\n // program and can't be re-interpreted by `sh -c` — no command injection via\n // interpolated values (stack names, CI-supplied env, etc.).\n shell: process.platform === 'win32',\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n child.on('error', (error) => reject(error));\n\n child.on('exit', (code, signal) => {\n if (signal) return reject(new Error(`${command} was killed with signal ${signal}`));\n if (code) return reject(new Error(`${command} ${validArgs.join(' ')} exited with code ${code}`));\n return resolve();\n });\n });\n\n// Run a command for its side effect only, swallowing both its output and its\n// exit code — for best-effort cleanup steps (e.g. `docker rm -f` of a container\n// that may not exist) that must never fail the run. Without a shell there's no\n// `>/dev/null 2>&1 || true`, so quieting and non-failing happen here instead.\nexport const runCommandBestEffort = (command: string, args: string[], options: RunCommandOptions = {}): Promise<void> =>\n new Promise((resolve) => {\n const validArgs = args.filter((a) => !!a);\n\n const child = spawn(command, validArgs, {\n stdio: 'ignore',\n shell: process.platform === 'win32',\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n child.on('error', () => resolve());\n child.on('exit', () => resolve());\n });\n\nexport type RunCommandPrefixedOptions = {\n env?: Record<string, string>;\n cwd?: string;\n // ANSI color code for the prefix (see nextPrefixColor).\n color?: number;\n};\n\nconst PREFIX_COLORS = [36, 32, 33, 35, 34, 96, 92, 93, 95, 94];\nlet colorIndex = 0;\n\n// Hand each concurrent task a distinct prefix color so interleaved output is\n// scannable.\nexport const nextPrefixColor = (): number => {\n const color = PREFIX_COLORS[colorIndex % PREFIX_COLORS.length];\n colorIndex += 1;\n return color;\n};\n\n// Like runCommand, but pipes output and prefixes every line with a colored\n// [label] — for running many commands concurrently without unreadable\n// interleaving. Rejects on non-zero exit.\nexport const runCommandPrefixed = (label: string, command: string, args: string[], options: RunCommandPrefixedOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n const validArgs = args.filter((a) => !!a);\n const prefix = `\\x1b[${options.color ?? 36}m[${label}]\\x1b[0m `;\n\n const child = spawn(command, validArgs, {\n stdio: ['ignore', 'pipe', 'pipe'],\n // Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run\n // without a shell so the already-array args are passed straight to the\n // program and can't be re-interpreted by `sh -c` — no command injection via\n // interpolated values (stack names, CI-supplied env, etc.).\n shell: process.platform === 'win32',\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n const attach = (stream: Readable, out: NodeJS.WriteStream): void => {\n let buffered = '';\n stream.on('data', (chunk: Buffer) => {\n buffered += chunk.toString();\n const lines = buffered.split('\\n');\n buffered = lines.pop() ?? '';\n lines.forEach((line) => out.write(`${prefix}${line}\\n`));\n });\n stream.on('end', () => {\n if (buffered) out.write(`${prefix}${buffered}\\n`);\n });\n };\n\n attach(child.stdout as Readable, process.stdout);\n attach(child.stderr as Readable, process.stderr);\n\n child.on('error', (error) => reject(error));\n\n child.on('exit', (code, signal) => {\n if (signal) return reject(new Error(`[${label}] ${command} was killed with signal ${signal}`));\n if (code) return reject(new Error(`[${label}] ${command} exited with code ${code}`));\n return resolve();\n });\n });\n"]}
|
|
@@ -73,9 +73,14 @@ const AWS_ENV_PASSTHROUGH = [
|
|
|
73
73
|
'AWS_DEFAULT_ACCOUNT',
|
|
74
74
|
];
|
|
75
75
|
const assemblyDir = (appName, serviceName) => path_1.default.join((0, discovery_1.getRoot)(), 'dist', 'qpq', 'cdk-docker', appName, serviceName);
|
|
76
|
+
// A container left behind by an interrupted run would block reusing its name.
|
|
77
|
+
// Clear it first, best-effort: a missing container (exit 1) must not fail the
|
|
78
|
+
// deploy. Was a `docker rm -f … >/dev/null 2>&1 ;` prefix on the run command,
|
|
79
|
+
// but that only worked under `shell: true`; as a separate call it's shell-free.
|
|
80
|
+
const removeContainer = (containerName) => (0, runCommand_1.runCommandBestEffort)('docker', ['rm', '-f', containerName]);
|
|
76
81
|
const assertDockerRunning = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
77
82
|
try {
|
|
78
|
-
yield (0, runCommand_1.runCommand)('docker', ['info', '--format', '
|
|
83
|
+
yield (0, runCommand_1.runCommand)('docker', ['info', '--format', 'docker daemon ok — server {{.ServerVersion}}']);
|
|
79
84
|
}
|
|
80
85
|
catch (_a) {
|
|
81
86
|
throw new Error('Docker daemon is not running (start Docker Desktop and retry).');
|
|
@@ -94,31 +99,23 @@ const buildDeployerImage = () => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
94
99
|
// The assembly mounts read-only and is copied container-local first — the CDK
|
|
95
100
|
// CLI writes lock files next to the assembly it reads, and the copy keeps
|
|
96
101
|
// parallel api/web deploys of the same service fully isolated.
|
|
97
|
-
const dockerDeployStack = (color, appName, serviceName, stackType, stackName) => {
|
|
102
|
+
const dockerDeployStack = (color, appName, serviceName, stackType, stackName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
103
|
const containerName = `${serviceName}-${stackType}`;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// name — clear it quietly first.
|
|
102
|
-
'rm',
|
|
103
|
-
'-f',
|
|
104
|
-
containerName,
|
|
105
|
-
'>/dev/null',
|
|
106
|
-
'2>&1',
|
|
107
|
-
';',
|
|
108
|
-
'docker',
|
|
104
|
+
yield removeContainer(containerName);
|
|
105
|
+
yield (0, runCommand_1.runCommandPrefixed)(`${stackType}:${serviceName}`, 'docker', [
|
|
109
106
|
'run',
|
|
110
107
|
'--rm',
|
|
111
108
|
'--name',
|
|
112
109
|
containerName,
|
|
113
110
|
'-v',
|
|
114
|
-
|
|
111
|
+
`${assemblyDir(appName, serviceName)}:/assembly:ro`,
|
|
115
112
|
...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),
|
|
116
113
|
IMAGE_TAG,
|
|
117
114
|
'bash',
|
|
118
115
|
'-c',
|
|
119
|
-
`
|
|
116
|
+
`cp -r /assembly /work/assembly && cdk deploy ${stackName} --app /work/assembly --require-approval never --progress events`,
|
|
120
117
|
], { color });
|
|
121
|
-
};
|
|
118
|
+
});
|
|
122
119
|
// Sync one service's pre-built views to S3 in a throwaway aws-cli container
|
|
123
120
|
// named <service>-views. The official image's entrypoint is `aws`. Multiple
|
|
124
121
|
// destinations (shell → website root + views prefix) run sequentially within
|
|
@@ -126,20 +123,14 @@ const dockerDeployStack = (color, appName, serviceName, stackType, stackName) =>
|
|
|
126
123
|
const dockerSyncViews = (color, appName, serviceName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
127
124
|
const containerName = `${serviceName}-views`;
|
|
128
125
|
for (const destination of (0, viewsSync_1.getViewsS3Destinations)(appName, serviceName)) {
|
|
126
|
+
yield removeContainer(containerName);
|
|
129
127
|
yield (0, runCommand_1.runCommandPrefixed)(`views:${serviceName}`, 'docker', [
|
|
130
|
-
'rm',
|
|
131
|
-
'-f',
|
|
132
|
-
containerName,
|
|
133
|
-
'>/dev/null',
|
|
134
|
-
'2>&1',
|
|
135
|
-
';',
|
|
136
|
-
'docker',
|
|
137
128
|
'run',
|
|
138
129
|
'--rm',
|
|
139
130
|
'--name',
|
|
140
131
|
containerName,
|
|
141
132
|
'-v',
|
|
142
|
-
|
|
133
|
+
`${(0, views_1.getViewsDistDir)(appName, serviceName)}:/views:ro`,
|
|
143
134
|
...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),
|
|
144
135
|
AWS_CLI_IMAGE,
|
|
145
136
|
's3',
|
|
@@ -165,20 +156,14 @@ const dockerPublishRemote = (color, appName, serviceName) => __awaiter(void 0, v
|
|
|
165
156
|
['s3', 'cp', '/publish/manifest.json', `s3://${bucketName}/${servicePrefix}/manifest.json`],
|
|
166
157
|
];
|
|
167
158
|
for (const s3Operation of s3Operations) {
|
|
159
|
+
yield removeContainer(containerName);
|
|
168
160
|
yield (0, runCommand_1.runCommandPrefixed)(`publish:${serviceName}`, 'docker', [
|
|
169
|
-
'rm',
|
|
170
|
-
'-f',
|
|
171
|
-
containerName,
|
|
172
|
-
'>/dev/null',
|
|
173
|
-
'2>&1',
|
|
174
|
-
';',
|
|
175
|
-
'docker',
|
|
176
161
|
'run',
|
|
177
162
|
'--rm',
|
|
178
163
|
'--name',
|
|
179
164
|
containerName,
|
|
180
165
|
'-v',
|
|
181
|
-
|
|
166
|
+
`${publishPath}:/publish:ro`,
|
|
182
167
|
...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),
|
|
183
168
|
AWS_CLI_IMAGE,
|
|
184
169
|
...s3Operation,
|
|
@@ -287,7 +272,7 @@ const awsGoDocker = (appName, plan) => __awaiter(void 0, void 0, void 0, functio
|
|
|
287
272
|
run: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
288
273
|
const outputDir = assemblyDir(appName, service);
|
|
289
274
|
fs_1.default.rmSync(outputDir, { recursive: true, force: true });
|
|
290
|
-
yield (0, runCommand_1.runCommandPrefixed)(`cdk-synth:${service}`, 'npx', ['cdk', 'synth', '--quiet', '--app',
|
|
275
|
+
yield (0, runCommand_1.runCommandPrefixed)(`cdk-synth:${service}`, 'npx', ['cdk', 'synth', '--quiet', '--app', (0, cdkApp_1.getCdkAppCommand)(), '--output', outputDir], {
|
|
291
276
|
cwd: (0, discovery_1.getRoot)(),
|
|
292
277
|
env: { DEPLOY_SERVICE_NAME: service, DEPLOY_APP_NAME: appName },
|
|
293
278
|
color: (0, runCommand_1.nextPrefixColor)(),
|