@expressots/cli 3.0.0 โ†’ 4.0.0-preview.3

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.
Files changed (194) hide show
  1. package/README.md +41 -95
  2. package/bin/cicd/cli.d.ts +6 -0
  3. package/bin/cicd/cli.js +128 -0
  4. package/bin/cicd/form.d.ts +29 -0
  5. package/bin/cicd/form.js +346 -0
  6. package/bin/cicd/generators/azure-devops.d.ts +2 -0
  7. package/bin/cicd/generators/azure-devops.js +370 -0
  8. package/bin/cicd/generators/bitbucket.d.ts +2 -0
  9. package/bin/cicd/generators/bitbucket.js +217 -0
  10. package/bin/cicd/generators/circleci.d.ts +2 -0
  11. package/bin/cicd/generators/circleci.js +274 -0
  12. package/bin/cicd/generators/github-actions.d.ts +14 -0
  13. package/bin/cicd/generators/github-actions.js +426 -0
  14. package/bin/cicd/generators/gitlab-ci.d.ts +2 -0
  15. package/bin/cicd/generators/gitlab-ci.js +237 -0
  16. package/bin/cicd/generators/index.d.ts +6 -0
  17. package/bin/cicd/generators/index.js +15 -0
  18. package/bin/cicd/generators/jenkins.d.ts +2 -0
  19. package/bin/cicd/generators/jenkins.js +248 -0
  20. package/bin/cicd/generators/template-loader.d.ts +17 -0
  21. package/bin/cicd/generators/template-loader.js +128 -0
  22. package/bin/cicd/index.d.ts +1 -0
  23. package/bin/cicd/index.js +5 -0
  24. package/bin/cli.d.ts +1 -5
  25. package/bin/cli.js +72 -7
  26. package/bin/commands/project.commands.d.ts +19 -6
  27. package/bin/commands/project.commands.js +602 -66
  28. package/bin/config/index.d.ts +5 -0
  29. package/bin/config/index.js +10 -0
  30. package/bin/config/manager.d.ts +98 -0
  31. package/bin/config/manager.js +222 -0
  32. package/bin/containerize/analyzers/bootstrap-analyzer.d.ts +46 -0
  33. package/bin/containerize/analyzers/bootstrap-analyzer.js +187 -0
  34. package/bin/containerize/analyzers/project-analyzer.d.ts +20 -0
  35. package/bin/containerize/analyzers/project-analyzer.js +150 -0
  36. package/bin/containerize/cli.d.ts +4 -0
  37. package/bin/containerize/cli.js +113 -0
  38. package/bin/containerize/form.d.ts +15 -0
  39. package/bin/containerize/form.js +152 -0
  40. package/bin/containerize/generators/ci-generator.d.ts +31 -0
  41. package/bin/containerize/generators/ci-generator.js +940 -0
  42. package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
  43. package/bin/containerize/generators/docker-compose-generator.js +187 -0
  44. package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
  45. package/bin/containerize/generators/dockerfile-generator.js +657 -0
  46. package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
  47. package/bin/containerize/generators/kubernetes-generator.js +134 -0
  48. package/bin/containerize/generators/template-loader.d.ts +36 -0
  49. package/bin/containerize/generators/template-loader.js +129 -0
  50. package/bin/containerize/index.d.ts +4 -0
  51. package/bin/containerize/index.js +13 -0
  52. package/bin/containerize/presets/preset-registry.d.ts +20 -0
  53. package/bin/containerize/presets/preset-registry.js +102 -0
  54. package/bin/costs/cli.d.ts +5 -0
  55. package/bin/costs/cli.js +185 -0
  56. package/bin/costs/form.d.ts +44 -0
  57. package/bin/costs/form.js +412 -0
  58. package/bin/costs/index.d.ts +4 -0
  59. package/bin/costs/index.js +25 -0
  60. package/bin/costs/pricing-manager.d.ts +84 -0
  61. package/bin/costs/pricing-manager.js +342 -0
  62. package/bin/costs/providers/index.d.ts +32 -0
  63. package/bin/costs/providers/index.js +153 -0
  64. package/bin/costs/sources/api-source.d.ts +10 -0
  65. package/bin/costs/sources/api-source.js +32 -0
  66. package/bin/costs/sources/index.d.ts +6 -0
  67. package/bin/costs/sources/index.js +15 -0
  68. package/bin/costs/sources/local-json-source.d.ts +23 -0
  69. package/bin/costs/sources/local-json-source.js +59 -0
  70. package/bin/costs/sources/remote-json-source.d.ts +11 -0
  71. package/bin/costs/sources/remote-json-source.js +53 -0
  72. package/bin/costs/types.d.ts +53 -0
  73. package/bin/costs/types.js +5 -0
  74. package/bin/dev/cli.d.ts +4 -0
  75. package/bin/dev/cli.js +136 -0
  76. package/bin/dev/form.d.ts +36 -0
  77. package/bin/dev/form.js +254 -0
  78. package/bin/dev/index.d.ts +1 -0
  79. package/bin/dev/index.js +5 -0
  80. package/bin/generate/cli.d.ts +1 -1
  81. package/bin/generate/cli.js +29 -2
  82. package/bin/generate/form.d.ts +5 -1
  83. package/bin/generate/form.js +3 -3
  84. package/bin/generate/templates/nonopinionated/config.tpl +12 -0
  85. package/bin/generate/templates/nonopinionated/event.tpl +10 -0
  86. package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
  87. package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
  88. package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
  89. package/bin/generate/templates/opinionated/config.tpl +47 -0
  90. package/bin/generate/templates/opinionated/entity.tpl +1 -8
  91. package/bin/generate/templates/opinionated/event.tpl +15 -0
  92. package/bin/generate/templates/opinionated/guard.tpl +41 -0
  93. package/bin/generate/templates/opinionated/handler.tpl +23 -0
  94. package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
  95. package/bin/generate/utils/command-utils.d.ts +20 -5
  96. package/bin/generate/utils/command-utils.js +145 -48
  97. package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
  98. package/bin/generate/utils/nonopininated-cmd.js +100 -1
  99. package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
  100. package/bin/generate/utils/opinionated-cmd.js +128 -16
  101. package/bin/generate/utils/string-utils.d.ts +6 -0
  102. package/bin/generate/utils/string-utils.js +13 -1
  103. package/bin/help/cli.d.ts +1 -1
  104. package/bin/help/command-help-registry.d.ts +23 -0
  105. package/bin/help/command-help-registry.js +303 -0
  106. package/bin/help/command-help.d.ts +36 -0
  107. package/bin/help/command-help.js +56 -0
  108. package/bin/help/form.js +127 -22
  109. package/bin/help/main-help.d.ts +8 -0
  110. package/bin/help/main-help.js +126 -0
  111. package/bin/help/render.d.ts +32 -0
  112. package/bin/help/render.js +46 -0
  113. package/bin/info/cli.d.ts +1 -1
  114. package/bin/info/form.d.ts +1 -1
  115. package/bin/info/form.js +11 -11
  116. package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
  117. package/bin/migrate/analyzers/platform-detector.js +116 -0
  118. package/bin/migrate/cli.d.ts +6 -0
  119. package/bin/migrate/cli.js +98 -0
  120. package/bin/migrate/form.d.ts +25 -0
  121. package/bin/migrate/form.js +348 -0
  122. package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
  123. package/bin/migrate/generators/compose-to-k8s.js +324 -0
  124. package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
  125. package/bin/migrate/generators/compose-to-railway.js +138 -0
  126. package/bin/migrate/generators/compose-to-render.d.ts +2 -0
  127. package/bin/migrate/generators/compose-to-render.js +148 -0
  128. package/bin/migrate/generators/generic-migration.d.ts +9 -0
  129. package/bin/migrate/generators/generic-migration.js +221 -0
  130. package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
  131. package/bin/migrate/generators/heroku-to-fly.js +291 -0
  132. package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
  133. package/bin/migrate/generators/heroku-to-railway.js +283 -0
  134. package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
  135. package/bin/migrate/generators/heroku-to-render.js +148 -0
  136. package/bin/migrate/generators/index.d.ts +7 -0
  137. package/bin/migrate/generators/index.js +17 -0
  138. package/bin/migrate/generators/template-loader.d.ts +21 -0
  139. package/bin/migrate/generators/template-loader.js +59 -0
  140. package/bin/migrate/index.d.ts +1 -0
  141. package/bin/migrate/index.js +5 -0
  142. package/bin/new/cli.d.ts +5 -1
  143. package/bin/new/cli.js +77 -14
  144. package/bin/new/form.d.ts +27 -4
  145. package/bin/new/form.js +605 -75
  146. package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
  147. package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
  148. package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
  149. package/bin/profile/analyzers/image-analyzer.js +85 -0
  150. package/bin/profile/cli.d.ts +4 -0
  151. package/bin/profile/cli.js +94 -0
  152. package/bin/profile/form.d.ts +56 -0
  153. package/bin/profile/form.js +401 -0
  154. package/bin/profile/index.d.ts +1 -0
  155. package/bin/profile/index.js +5 -0
  156. package/bin/profile/optimizers/index.d.ts +19 -0
  157. package/bin/profile/optimizers/index.js +137 -0
  158. package/bin/providers/add/form.d.ts +1 -1
  159. package/bin/providers/add/form.js +27 -6
  160. package/bin/providers/create/form.js +53 -3
  161. package/bin/scripts/form.js +27 -5
  162. package/bin/studio/cli.d.ts +15 -0
  163. package/bin/studio/cli.js +172 -0
  164. package/bin/studio/index.d.ts +5 -0
  165. package/bin/studio/index.js +9 -0
  166. package/bin/templates/cache.d.ts +54 -0
  167. package/bin/templates/cache.js +180 -0
  168. package/bin/templates/cli.d.ts +8 -0
  169. package/bin/templates/cli.js +294 -0
  170. package/bin/templates/fetcher.d.ts +49 -0
  171. package/bin/templates/fetcher.js +208 -0
  172. package/bin/templates/index.d.ts +11 -0
  173. package/bin/templates/index.js +37 -0
  174. package/bin/templates/manager.d.ts +116 -0
  175. package/bin/templates/manager.js +323 -0
  176. package/bin/templates/renderer.d.ts +49 -0
  177. package/bin/templates/renderer.js +204 -0
  178. package/bin/templates/types.d.ts +51 -0
  179. package/bin/templates/types.js +5 -0
  180. package/bin/utils/add-module-to-container.d.ts +14 -3
  181. package/bin/utils/add-module-to-container.js +327 -98
  182. package/bin/utils/cli-ui.d.ts +49 -3
  183. package/bin/utils/cli-ui.js +133 -13
  184. package/bin/utils/index.d.ts +4 -0
  185. package/bin/utils/index.js +4 -0
  186. package/bin/utils/input-validation.d.ts +50 -0
  187. package/bin/utils/input-validation.js +143 -0
  188. package/bin/utils/package-manager-commands.d.ts +24 -0
  189. package/bin/utils/package-manager-commands.js +50 -0
  190. package/bin/utils/safe-spawn.d.ts +35 -0
  191. package/bin/utils/safe-spawn.js +51 -0
  192. package/bin/utils/update-tsconfig-paths.d.ts +35 -0
  193. package/bin/utils/update-tsconfig-paths.js +326 -0
  194. package/package.json +165 -156
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.analyzeProject = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const compiler_1 = __importDefault(require("../../utils/compiler"));
10
+ const bootstrap_analyzer_1 = require("./bootstrap-analyzer");
11
+ async function analyzeProject() {
12
+ const cwd = process.cwd();
13
+ const packageJsonPath = path_1.default.join(cwd, "package.json");
14
+ if (!fs_1.default.existsSync(packageJsonPath)) {
15
+ throw new Error("package.json not found in current directory");
16
+ }
17
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, "utf-8"));
18
+ // Detect Node version
19
+ const nodeVersion = packageJson.engines?.node || process.version.replace("v", "");
20
+ // Detect package manager
21
+ const packageManager = detectPackageManager(cwd);
22
+ // Get dependencies
23
+ const dependencies = Object.keys(packageJson.dependencies || {});
24
+ const devDependencies = Object.keys(packageJson.devDependencies || {});
25
+ // Detect local file dependencies
26
+ const allDeps = {
27
+ ...packageJson.dependencies,
28
+ ...packageJson.devDependencies,
29
+ };
30
+ const localDependencyPaths = [];
31
+ let hasLocalDependencies = false;
32
+ for (const [name, version] of Object.entries(allDeps)) {
33
+ if (typeof version === "string" && version.startsWith("file:")) {
34
+ hasLocalDependencies = true;
35
+ const relativePath = version.replace("file:", "");
36
+ localDependencyPaths.push(relativePath);
37
+ }
38
+ }
39
+ // Detect database
40
+ const hasDatabase = dependencies.some((dep) => dep.includes("pg") ||
41
+ dep.includes("mysql") ||
42
+ dep.includes("mongodb") ||
43
+ dep.includes("prisma") ||
44
+ dep.includes("typeorm"));
45
+ // Detect Redis
46
+ const hasRedis = dependencies.some((dep) => dep.includes("redis") || dep.includes("ioredis"));
47
+ // Detect CORS
48
+ const hasCors = dependencies.some((dep) => dep.includes("cors"));
49
+ // Find controllers
50
+ const controllers = await findControllers(cwd);
51
+ // Detect health check paths
52
+ const healthCheckPaths = await detectHealthCheckPaths(cwd);
53
+ // Estimate resources
54
+ const estimatedMemory = estimateMemoryUsage(dependencies);
55
+ const estimatedCpu = "250m"; // Default conservative estimate
56
+ // Detect port
57
+ const port = await detectPort(cwd);
58
+ // Analyze bootstrap configuration
59
+ const bootstrapConfig = await (0, bootstrap_analyzer_1.analyzeBootstrapConfig)();
60
+ return {
61
+ nodeVersion,
62
+ packageManager,
63
+ dependencies,
64
+ devDependencies,
65
+ controllers,
66
+ hasDatabase,
67
+ hasRedis,
68
+ hasCors,
69
+ estimatedMemory,
70
+ estimatedCpu,
71
+ healthCheckPaths,
72
+ port,
73
+ hasLocalDependencies,
74
+ localDependencyPaths,
75
+ bootstrapConfig,
76
+ };
77
+ }
78
+ exports.analyzeProject = analyzeProject;
79
+ function detectPackageManager(cwd) {
80
+ if (fs_1.default.existsSync(path_1.default.join(cwd, "pnpm-lock.yaml")))
81
+ return "pnpm";
82
+ if (fs_1.default.existsSync(path_1.default.join(cwd, "yarn.lock")))
83
+ return "yarn";
84
+ if (fs_1.default.existsSync(path_1.default.join(cwd, "bun.lockb")))
85
+ return "bun";
86
+ return "npm";
87
+ }
88
+ async function findControllers(cwd) {
89
+ const controllers = [];
90
+ const srcDir = path_1.default.join(cwd, "src");
91
+ if (!fs_1.default.existsSync(srcDir)) {
92
+ return controllers;
93
+ }
94
+ const findControllersRecursive = (dir) => {
95
+ const files = fs_1.default.readdirSync(dir);
96
+ for (const file of files) {
97
+ const fullPath = path_1.default.join(dir, file);
98
+ const stat = fs_1.default.statSync(fullPath);
99
+ if (stat.isDirectory()) {
100
+ findControllersRecursive(fullPath);
101
+ }
102
+ else if (file.endsWith(".controller.ts")) {
103
+ controllers.push(fullPath);
104
+ }
105
+ }
106
+ };
107
+ findControllersRecursive(srcDir);
108
+ return controllers;
109
+ }
110
+ async function detectHealthCheckPaths(cwd) {
111
+ const paths = [];
112
+ const controllers = await findControllers(cwd);
113
+ for (const controller of controllers) {
114
+ const content = fs_1.default.readFileSync(controller, "utf-8");
115
+ // Look for common health check patterns
116
+ if (content.includes("/health") || content.includes("health")) {
117
+ paths.push("/health");
118
+ }
119
+ if (content.includes("/ready") || content.includes("readiness")) {
120
+ paths.push("/ready");
121
+ }
122
+ if (content.includes("/live") || content.includes("liveness")) {
123
+ paths.push("/live");
124
+ }
125
+ }
126
+ // Remove duplicates
127
+ return [...new Set(paths)];
128
+ }
129
+ async function detectPort(cwd) {
130
+ try {
131
+ const config = await compiler_1.default.loadConfig();
132
+ // Check for port in config
133
+ // Default to 3000
134
+ return 3000;
135
+ }
136
+ catch {
137
+ return 3000;
138
+ }
139
+ }
140
+ function estimateMemoryUsage(dependencies) {
141
+ // Basic estimation based on dependency count
142
+ const depCount = dependencies.length;
143
+ if (depCount < 10)
144
+ return "128Mi";
145
+ if (depCount < 30)
146
+ return "256Mi";
147
+ if (depCount < 50)
148
+ return "512Mi";
149
+ return "1Gi";
150
+ }
@@ -0,0 +1,4 @@
1
+ import { CommandModule } from "yargs";
2
+ type CommandModuleArgs = Record<string, never>;
3
+ declare const containerize: () => CommandModule<CommandModuleArgs, any>;
4
+ export { containerize };
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.containerize = void 0;
4
+ const form_1 = require("./form");
5
+ const containerize = () => {
6
+ return {
7
+ command: "containerize [target] [environment]",
8
+ describe: "Generate container configurations for your ExpressoTS application.",
9
+ aliases: ["ctr"],
10
+ builder: (yargs) => {
11
+ yargs.positional("target", {
12
+ choices: ["docker", "kubernetes", "k8s", "compose"],
13
+ describe: "Target platform for containerization",
14
+ type: "string",
15
+ default: "docker",
16
+ });
17
+ yargs.positional("environment", {
18
+ choices: [
19
+ "development",
20
+ "staging",
21
+ "production",
22
+ "all",
23
+ ],
24
+ describe: "Target environment",
25
+ type: "string",
26
+ alias: "env",
27
+ default: "production",
28
+ });
29
+ yargs.option("preset", {
30
+ choices: [
31
+ "minimal",
32
+ "secure",
33
+ "fast-startup",
34
+ "dev",
35
+ "multi-arch",
36
+ "standard",
37
+ ],
38
+ describe: "Container preset to use",
39
+ type: "string",
40
+ default: "standard",
41
+ });
42
+ yargs.option("analyze", {
43
+ describe: "Analyze project before generating",
44
+ type: "boolean",
45
+ default: true,
46
+ });
47
+ yargs.option("skip-compose", {
48
+ describe: "Skip docker-compose.yml generation",
49
+ type: "boolean",
50
+ default: false,
51
+ });
52
+ yargs.option("include-ci", {
53
+ describe: "Include CI/CD pipeline configuration",
54
+ type: "boolean",
55
+ default: false,
56
+ });
57
+ yargs.option("ci-platform", {
58
+ choices: [
59
+ "github",
60
+ "gitlab",
61
+ "circleci",
62
+ "jenkins",
63
+ "bitbucket",
64
+ "azure",
65
+ "all",
66
+ ],
67
+ describe: "CI/CD platform to generate configuration for",
68
+ type: "string",
69
+ default: "github",
70
+ });
71
+ yargs.option("ci-strategy", {
72
+ choices: [
73
+ "basic",
74
+ "comprehensive",
75
+ "security-focused",
76
+ ],
77
+ describe: "CI/CD pipeline strategy",
78
+ type: "string",
79
+ default: "comprehensive",
80
+ });
81
+ yargs.option("include-security-scans", {
82
+ describe: "Include security scanning (Trivy, Snyk)",
83
+ type: "boolean",
84
+ default: true,
85
+ });
86
+ yargs.option("include-e2e", {
87
+ describe: "Include end-to-end tests in CI pipeline",
88
+ type: "boolean",
89
+ default: false,
90
+ });
91
+ // `--deployment-strategy` was previously exposed here but
92
+ // the value was never read by the K8s generator. The dead
93
+ // flag was removed; re-introduce it together with a real
94
+ // implementation in `kubernetes-generator.ts`.
95
+ return yargs;
96
+ },
97
+ handler: async ({ target, environment, preset, analyze, skipCompose, includeCi, ciPlatform, ciStrategy, includeSecurityScans, includeE2e, }) => {
98
+ await (0, form_1.containerizeProject)({
99
+ target,
100
+ environment,
101
+ preset,
102
+ analyze,
103
+ skipCompose,
104
+ includeCi,
105
+ ciPlatform,
106
+ ciStrategy,
107
+ includeSecurityScans,
108
+ includeE2E: includeE2e,
109
+ });
110
+ },
111
+ };
112
+ };
113
+ exports.containerize = containerize;
@@ -0,0 +1,15 @@
1
+ import { type CIPlatform, type CIStrategy } from "./generators/ci-generator";
2
+ type ContainerizeOptions = {
3
+ target: string;
4
+ environment: string;
5
+ preset: string;
6
+ analyze: boolean;
7
+ skipCompose: boolean;
8
+ includeCi: boolean;
9
+ ciPlatform?: CIPlatform;
10
+ ciStrategy?: CIStrategy;
11
+ includeSecurityScans?: boolean;
12
+ includeE2E?: boolean;
13
+ };
14
+ export declare const containerizeProject: (options: ContainerizeOptions) => Promise<void>;
15
+ export {};
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.containerizeProject = void 0;
7
+ const process_1 = require("process");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const cli_ui_1 = require("../utils/cli-ui");
10
+ const project_analyzer_1 = require("./analyzers/project-analyzer");
11
+ const dockerfile_generator_1 = require("./generators/dockerfile-generator");
12
+ const kubernetes_generator_1 = require("./generators/kubernetes-generator");
13
+ const docker_compose_generator_1 = require("./generators/docker-compose-generator");
14
+ const ci_generator_1 = require("./generators/ci-generator");
15
+ const bootstrap_analyzer_1 = require("./analyzers/bootstrap-analyzer");
16
+ const containerizeProject = async (options) => {
17
+ try {
18
+ (0, cli_ui_1.printSection)("๐Ÿณ ExpressoTS Containerization");
19
+ // Step 1: Analyze project (if enabled)
20
+ let analysis;
21
+ if (options.analyze) {
22
+ (0, cli_ui_1.printSection)("๐Ÿ“Š Project Analysis");
23
+ analysis = await (0, project_analyzer_1.analyzeProject)();
24
+ (0, cli_ui_1.printKeyValue)("Node version", analysis.nodeVersion);
25
+ (0, cli_ui_1.printKeyValue)("Package manager", analysis.packageManager);
26
+ (0, cli_ui_1.printKeyValue)("Dependencies", String(analysis.dependencies.length));
27
+ (0, cli_ui_1.printKeyValue)("Controllers", String(analysis.controllers.length));
28
+ if (analysis.hasLocalDependencies) {
29
+ process_1.stdout.write("\n");
30
+ (0, cli_ui_1.printWarning)(`Detected ${analysis.localDependencyPaths.length} local file dependencies`, "containerize");
31
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray("These will be copied into the Docker image. For production,"));
32
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray("consider publishing to npm registry instead."));
33
+ }
34
+ printBootstrapAnalysis(analysis);
35
+ }
36
+ // Step 2: Generate based on target
37
+ switch (options.target) {
38
+ case "docker":
39
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
40
+ if (!options.skipCompose) {
41
+ await (0, docker_compose_generator_1.generateDockerCompose)(options, analysis);
42
+ }
43
+ break;
44
+ case "kubernetes":
45
+ case "k8s":
46
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
47
+ await (0, kubernetes_generator_1.generateKubernetesConfigs)(options, analysis);
48
+ break;
49
+ case "compose":
50
+ // Compose `build:` blocks reference Dockerfiles by
51
+ // path (Dockerfile or Dockerfile.development), so the
52
+ // compose-only target must also emit them โ€” otherwise
53
+ // `docker compose up --build` fails with "no such file
54
+ // or directory".
55
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
56
+ await (0, docker_compose_generator_1.generateDockerCompose)(options, analysis);
57
+ break;
58
+ default:
59
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
60
+ break;
61
+ }
62
+ // Step 3: Generate CI/CD config (if requested)
63
+ if (options.includeCi) {
64
+ await (0, ci_generator_1.generateCIConfig)(options, analysis);
65
+ }
66
+ // Step 4: Success message
67
+ process_1.stdout.write("\n");
68
+ (0, cli_ui_1.printSuccess)("Container configuration generated successfully", "containerize");
69
+ (0, cli_ui_1.printSection)("๐Ÿ“‹ Summary");
70
+ (0, cli_ui_1.printBullet)("Generated files are fully customizable");
71
+ (0, cli_ui_1.printBullet)("Edit them to fit your specific needs");
72
+ (0, cli_ui_1.printBullet)(`Run ${chalk_1.default.cyan("expressots container profile")} to optimize`);
73
+ (0, cli_ui_1.printSection)("๐Ÿ“– Next steps");
74
+ if (analysis?.hasLocalDependencies) {
75
+ const pm = analysis.packageManager;
76
+ (0, cli_ui_1.printBullet)(`Review generated files`);
77
+ (0, cli_ui_1.printBullet)(`Run setup: ${chalk_1.default.cyan(`${pm} run docker:setup`)}`);
78
+ (0, cli_ui_1.printBullet)(`Build: ${chalk_1.default.cyan("docker build -t myapp .")}`);
79
+ (0, cli_ui_1.printBullet)(`Run: ${chalk_1.default.cyan("docker compose up")}`);
80
+ process_1.stdout.write("\n");
81
+ (0, cli_ui_1.printWarning)("docker-setup.js copies local dependencies to .docker-deps/ for the Docker build context.", "containerize");
82
+ }
83
+ else {
84
+ (0, cli_ui_1.printBullet)("Review generated files");
85
+ (0, cli_ui_1.printBullet)("Customize as needed");
86
+ (0, cli_ui_1.printBullet)(`Build: ${chalk_1.default.cyan("docker build -t myapp .")}`);
87
+ (0, cli_ui_1.printBullet)(`Run: ${chalk_1.default.cyan("docker compose up")}`);
88
+ }
89
+ process_1.stdout.write("\n");
90
+ }
91
+ catch (error) {
92
+ (0, cli_ui_1.printError)(`Containerization failed: ${error instanceof Error ? error.message : String(error)}`, "containerize");
93
+ throw error;
94
+ }
95
+ };
96
+ exports.containerizeProject = containerizeProject;
97
+ /**
98
+ * Print bootstrap configuration analysis and recommendations
99
+ */
100
+ function printBootstrapAnalysis(analysis) {
101
+ const bootstrapConfig = analysis.bootstrapConfig;
102
+ if (!bootstrapConfig.hasEnvFileConfig) {
103
+ return; // No env file config, nothing to warn about
104
+ }
105
+ (0, cli_ui_1.printSection)("๐Ÿ“‹ Bootstrap Configuration");
106
+ // Show detected env file config
107
+ if (bootstrapConfig.skipFileLoading || bootstrapConfig.ciMode) {
108
+ (0, cli_ui_1.printSuccess)("Container-ready configuration detected", "bootstrap");
109
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray(`Using ${bootstrapConfig.skipFileLoading ? "skipFileLoading" : "ciMode"} mode`));
110
+ return;
111
+ }
112
+ // Check if env files are needed
113
+ const copyEnvFiles = (0, bootstrap_analyzer_1.shouldCopyEnvFiles)(bootstrapConfig);
114
+ if (copyEnvFiles) {
115
+ (0, cli_ui_1.printWarning)("Environment file configuration detected", "bootstrap");
116
+ if (bootstrapConfig.existingEnvFiles.length > 0) {
117
+ (0, cli_ui_1.printBullet)(chalk_1.default.bold("Existing env files:"));
118
+ bootstrapConfig.existingEnvFiles.forEach((file) => {
119
+ (0, cli_ui_1.printBullet)(chalk_1.default.green(` โœ“ ${file}`));
120
+ });
121
+ }
122
+ if (bootstrapConfig.missingEnvFiles.length > 0) {
123
+ (0, cli_ui_1.printBullet)(chalk_1.default.bold("Missing env files:"));
124
+ bootstrapConfig.missingEnvFiles.forEach((file) => {
125
+ (0, cli_ui_1.printBullet)(chalk_1.default.red(` โœ— ${file}`));
126
+ });
127
+ }
128
+ if (bootstrapConfig.requiredVariables.length > 0) {
129
+ (0, cli_ui_1.printBullet)(chalk_1.default.bold("Required variables:"));
130
+ bootstrapConfig.requiredVariables.forEach((varName) => {
131
+ (0, cli_ui_1.printBullet)(chalk_1.default.yellow(` โ€ข ${varName}`));
132
+ });
133
+ }
134
+ }
135
+ // Show recommendations
136
+ if (bootstrapConfig.recommendations.length > 0) {
137
+ (0, cli_ui_1.printSection)("๐Ÿ’ก Recommendations");
138
+ bootstrapConfig.recommendations.forEach((rec) => {
139
+ (0, cli_ui_1.printBullet)(rec);
140
+ });
141
+ }
142
+ // Special warning for missing required env files
143
+ if (!bootstrapConfig.isContainerReady) {
144
+ process_1.stdout.write("\n");
145
+ (0, cli_ui_1.printError)("Container may fail to start!", "bootstrap");
146
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray("The bootstrap configuration requires env files that are missing."));
147
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray("Options:"));
148
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray(" 1. Create the missing env files before building"));
149
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray(" 2. Update bootstrap to use skipFileLoading: true"));
150
+ (0, cli_ui_1.printBullet)(chalk_1.default.gray(" 3. Set environment variables in docker-compose.yml"));
151
+ }
152
+ }
@@ -0,0 +1,31 @@
1
+ import type { ProjectAnalysis } from "../analyzers/project-analyzer";
2
+ export type CIPlatform = "github" | "gitlab" | "circleci" | "jenkins" | "bitbucket" | "azure" | "all";
3
+ export type CIStrategy = "basic" | "comprehensive" | "security-focused";
4
+ /**
5
+ * Note on naming and scope (see CLI Deployment Hardening Plan ยง6):
6
+ *
7
+ * This generator is the **CD half** of ExpressoTS' pipeline tooling.
8
+ * It is invoked by `expressots containerize --include-ci` and emits
9
+ * a Docker-centric workflow (build โ†’ push โ†’ deploy).
10
+ *
11
+ * The **CI half** is `expressots cicd init`, which writes a
12
+ * lint/test/coverage workflow at `.github/workflows/ci.yml` (and
13
+ * the canonical config files for other platforms).
14
+ *
15
+ * On GitHub Actions both files coexist (`ci.yml` + `cd-docker.yml`).
16
+ * Other platforms (GitLab, CircleCI, Jenkins, Bitbucket, Azure)
17
+ * only support a single canonical config file, so running both
18
+ * generators against those platforms would overwrite each other โ€”
19
+ * we print a warning when that happens.
20
+ */
21
+ type GeneratorOptions = {
22
+ environment: string;
23
+ preset: string;
24
+ ciPlatform?: CIPlatform;
25
+ ciStrategy?: CIStrategy;
26
+ includeSecurityScans?: boolean;
27
+ includeE2E?: boolean;
28
+ [key: string]: any;
29
+ };
30
+ export declare function generateCIConfig(options: GeneratorOptions, analysis?: ProjectAnalysis): Promise<void>;
31
+ export {};