@expressots/cli 3.0.0-beta.4 → 4.0.0-preview.2

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 (180) hide show
  1. package/README.md +41 -95
  2. package/bin/cicd/cli.d.ts +6 -0
  3. package/bin/cicd/cli.js +126 -0
  4. package/bin/cicd/form.d.ts +29 -0
  5. package/bin/cicd/form.js +345 -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 -1
  25. package/bin/cli.js +18 -3
  26. package/bin/commands/project.commands.d.ts +19 -6
  27. package/bin/commands/project.commands.js +390 -61
  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 +154 -0
  40. package/bin/containerize/generators/ci-generator.d.ts +31 -0
  41. package/bin/containerize/generators/ci-generator.js +936 -0
  42. package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
  43. package/bin/containerize/generators/docker-compose-generator.js +186 -0
  44. package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
  45. package/bin/containerize/generators/dockerfile-generator.js +635 -0
  46. package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
  47. package/bin/containerize/generators/kubernetes-generator.js +133 -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 +183 -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 +134 -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.js +29 -2
  81. package/bin/generate/form.d.ts +5 -1
  82. package/bin/generate/form.js +3 -3
  83. package/bin/generate/templates/nonopinionated/config.tpl +12 -0
  84. package/bin/generate/templates/nonopinionated/event.tpl +10 -0
  85. package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
  86. package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
  87. package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
  88. package/bin/generate/templates/opinionated/config.tpl +47 -0
  89. package/bin/generate/templates/opinionated/entity.tpl +1 -8
  90. package/bin/generate/templates/opinionated/event.tpl +15 -0
  91. package/bin/generate/templates/opinionated/guard.tpl +41 -0
  92. package/bin/generate/templates/opinionated/handler.tpl +23 -0
  93. package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
  94. package/bin/generate/utils/command-utils.d.ts +7 -3
  95. package/bin/generate/utils/command-utils.js +95 -31
  96. package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
  97. package/bin/generate/utils/nonopininated-cmd.js +100 -1
  98. package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
  99. package/bin/generate/utils/opinionated-cmd.js +112 -7
  100. package/bin/generate/utils/string-utils.d.ts +6 -0
  101. package/bin/generate/utils/string-utils.js +13 -1
  102. package/bin/help/form.js +11 -3
  103. package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
  104. package/bin/migrate/analyzers/platform-detector.js +116 -0
  105. package/bin/migrate/cli.d.ts +6 -0
  106. package/bin/migrate/cli.js +96 -0
  107. package/bin/migrate/form.d.ts +25 -0
  108. package/bin/migrate/form.js +347 -0
  109. package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
  110. package/bin/migrate/generators/compose-to-k8s.js +324 -0
  111. package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
  112. package/bin/migrate/generators/compose-to-railway.js +138 -0
  113. package/bin/migrate/generators/compose-to-render.d.ts +2 -0
  114. package/bin/migrate/generators/compose-to-render.js +148 -0
  115. package/bin/migrate/generators/generic-migration.d.ts +9 -0
  116. package/bin/migrate/generators/generic-migration.js +221 -0
  117. package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
  118. package/bin/migrate/generators/heroku-to-fly.js +291 -0
  119. package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
  120. package/bin/migrate/generators/heroku-to-railway.js +283 -0
  121. package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
  122. package/bin/migrate/generators/heroku-to-render.js +148 -0
  123. package/bin/migrate/generators/index.d.ts +7 -0
  124. package/bin/migrate/generators/index.js +17 -0
  125. package/bin/migrate/generators/template-loader.d.ts +21 -0
  126. package/bin/migrate/generators/template-loader.js +59 -0
  127. package/bin/migrate/index.d.ts +1 -0
  128. package/bin/migrate/index.js +5 -0
  129. package/bin/new/cli.js +21 -6
  130. package/bin/new/form.d.ts +25 -4
  131. package/bin/new/form.js +285 -70
  132. package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
  133. package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
  134. package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
  135. package/bin/profile/analyzers/image-analyzer.js +85 -0
  136. package/bin/profile/cli.d.ts +4 -0
  137. package/bin/profile/cli.js +92 -0
  138. package/bin/profile/form.d.ts +56 -0
  139. package/bin/profile/form.js +400 -0
  140. package/bin/profile/index.d.ts +1 -0
  141. package/bin/profile/index.js +5 -0
  142. package/bin/profile/optimizers/index.d.ts +19 -0
  143. package/bin/profile/optimizers/index.js +137 -0
  144. package/bin/providers/add/form.d.ts +1 -1
  145. package/bin/providers/add/form.js +27 -6
  146. package/bin/providers/create/form.js +2 -1
  147. package/bin/scripts/form.js +27 -5
  148. package/bin/studio/cli.d.ts +15 -0
  149. package/bin/studio/cli.js +166 -0
  150. package/bin/studio/index.d.ts +5 -0
  151. package/bin/studio/index.js +9 -0
  152. package/bin/templates/cache.d.ts +54 -0
  153. package/bin/templates/cache.js +180 -0
  154. package/bin/templates/cli.d.ts +8 -0
  155. package/bin/templates/cli.js +292 -0
  156. package/bin/templates/fetcher.d.ts +49 -0
  157. package/bin/templates/fetcher.js +208 -0
  158. package/bin/templates/index.d.ts +11 -0
  159. package/bin/templates/index.js +37 -0
  160. package/bin/templates/manager.d.ts +116 -0
  161. package/bin/templates/manager.js +323 -0
  162. package/bin/templates/renderer.d.ts +49 -0
  163. package/bin/templates/renderer.js +204 -0
  164. package/bin/templates/types.d.ts +51 -0
  165. package/bin/templates/types.js +5 -0
  166. package/bin/utils/add-module-to-container.d.ts +2 -2
  167. package/bin/utils/add-module-to-container.js +15 -5
  168. package/bin/utils/cli-ui.d.ts +30 -3
  169. package/bin/utils/cli-ui.js +95 -13
  170. package/bin/utils/index.d.ts +4 -0
  171. package/bin/utils/index.js +4 -0
  172. package/bin/utils/input-validation.d.ts +50 -0
  173. package/bin/utils/input-validation.js +143 -0
  174. package/bin/utils/package-manager-commands.d.ts +24 -0
  175. package/bin/utils/package-manager-commands.js +50 -0
  176. package/bin/utils/safe-spawn.d.ts +35 -0
  177. package/bin/utils/safe-spawn.js +51 -0
  178. package/bin/utils/update-tsconfig-paths.d.ts +35 -0
  179. package/bin/utils/update-tsconfig-paths.js +286 -0
  180. package/package.json +154 -154
@@ -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 = {};
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: ["c"],
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,154 @@
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 chalk_1 = __importDefault(require("chalk"));
8
+ const cli_ui_1 = require("../utils/cli-ui");
9
+ const project_analyzer_1 = require("./analyzers/project-analyzer");
10
+ const dockerfile_generator_1 = require("./generators/dockerfile-generator");
11
+ const kubernetes_generator_1 = require("./generators/kubernetes-generator");
12
+ const docker_compose_generator_1 = require("./generators/docker-compose-generator");
13
+ const ci_generator_1 = require("./generators/ci-generator");
14
+ const bootstrap_analyzer_1 = require("./analyzers/bootstrap-analyzer");
15
+ const containerizeProject = async (options) => {
16
+ try {
17
+ console.log(chalk_1.default.bold.cyan("\n🐳 ExpressoTS Containerization\n"));
18
+ // Step 1: Analyze project (if enabled)
19
+ let analysis;
20
+ if (options.analyze) {
21
+ console.log(chalk_1.default.yellow("📊 Analyzing your project...\n"));
22
+ analysis = await (0, project_analyzer_1.analyzeProject)();
23
+ console.log(chalk_1.default.white("Project Analysis:"));
24
+ console.log(chalk_1.default.gray(` Node version: ${analysis.nodeVersion}`));
25
+ console.log(chalk_1.default.gray(` Package manager: ${analysis.packageManager}`));
26
+ console.log(chalk_1.default.gray(` Dependencies: ${analysis.dependencies.length}`));
27
+ console.log(chalk_1.default.gray(` Controllers: ${analysis.controllers.length}`));
28
+ // Warn about local dependencies
29
+ if (analysis.hasLocalDependencies) {
30
+ console.log(chalk_1.default.yellow(`\n⚠️ Warning: Detected ${analysis.localDependencyPaths.length} local file dependencies`));
31
+ console.log(chalk_1.default.gray(" These will be copied into the Docker image. For production,"));
32
+ console.log(chalk_1.default.gray(" consider publishing to npm registry instead."));
33
+ }
34
+ // Bootstrap configuration analysis
35
+ printBootstrapAnalysis(analysis);
36
+ console.log("");
37
+ }
38
+ // Step 2: Generate based on target
39
+ switch (options.target) {
40
+ case "docker":
41
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
42
+ if (!options.skipCompose) {
43
+ await (0, docker_compose_generator_1.generateDockerCompose)(options, analysis);
44
+ }
45
+ break;
46
+ case "kubernetes":
47
+ case "k8s":
48
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
49
+ await (0, kubernetes_generator_1.generateKubernetesConfigs)(options, analysis);
50
+ break;
51
+ case "compose":
52
+ // Compose `build:` blocks reference Dockerfiles by
53
+ // path (Dockerfile or Dockerfile.development), so the
54
+ // compose-only target must also emit them — otherwise
55
+ // `docker compose up --build` fails with "no such file
56
+ // or directory".
57
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
58
+ await (0, docker_compose_generator_1.generateDockerCompose)(options, analysis);
59
+ break;
60
+ default:
61
+ await (0, dockerfile_generator_1.generateDockerfiles)(options, analysis);
62
+ break;
63
+ }
64
+ // Step 3: Generate CI/CD config (if requested)
65
+ if (options.includeCi) {
66
+ await (0, ci_generator_1.generateCIConfig)(options, analysis);
67
+ }
68
+ // Step 4: Success message
69
+ console.log(chalk_1.default.bold.green("\n✅ Container configuration generated successfully!\n"));
70
+ console.log(chalk_1.default.white("📋 Summary:"));
71
+ console.log(chalk_1.default.gray(" • Generated files are fully customizable"));
72
+ console.log(chalk_1.default.gray(" • Edit them to fit your specific needs"));
73
+ console.log(chalk_1.default.gray(" • Run 'expressots container profile' to optimize"));
74
+ console.log(chalk_1.default.cyan("\n📖 Next steps:"));
75
+ if (analysis?.hasLocalDependencies) {
76
+ console.log(chalk_1.default.white(" 1. Review generated files"));
77
+ console.log(chalk_1.default.white(" 2. Run setup: npm run docker:setup"));
78
+ console.log(chalk_1.default.white(" 3. Build: docker build -t myapp ."));
79
+ console.log(chalk_1.default.white(" 4. Run: docker-compose up"));
80
+ console.log(chalk_1.default.yellow("\n💡 Tip: The docker-setup.sh script copies local dependencies"));
81
+ console.log(chalk_1.default.yellow(" to .docker-deps/ for the Docker build context."));
82
+ }
83
+ else {
84
+ console.log(chalk_1.default.white(" 1. Review generated files"));
85
+ console.log(chalk_1.default.white(" 2. Customize as needed"));
86
+ console.log(chalk_1.default.white(" 3. Build: docker build -t myapp ."));
87
+ console.log(chalk_1.default.white(" 4. Run: docker-compose up"));
88
+ }
89
+ console.log("");
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
+ console.log(chalk_1.default.cyan("\n📋 Bootstrap Configuration:"));
106
+ // Show detected env file config
107
+ if (bootstrapConfig.skipFileLoading || bootstrapConfig.ciMode) {
108
+ console.log(chalk_1.default.green(" ✓ Container-ready configuration detected"));
109
+ console.log(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
+ console.log(chalk_1.default.yellow(" ⚠️ Environment file configuration detected"));
116
+ // Show existing env files
117
+ if (bootstrapConfig.existingEnvFiles.length > 0) {
118
+ console.log(chalk_1.default.gray(" Existing env files:"));
119
+ bootstrapConfig.existingEnvFiles.forEach((file) => {
120
+ console.log(chalk_1.default.green(` ✓ ${file}`));
121
+ });
122
+ }
123
+ // Show missing env files
124
+ if (bootstrapConfig.missingEnvFiles.length > 0) {
125
+ console.log(chalk_1.default.gray(" Missing env files:"));
126
+ bootstrapConfig.missingEnvFiles.forEach((file) => {
127
+ console.log(chalk_1.default.red(` ✗ ${file}`));
128
+ });
129
+ }
130
+ // Show required variables
131
+ if (bootstrapConfig.requiredVariables.length > 0) {
132
+ console.log(chalk_1.default.gray(" Required variables:"));
133
+ bootstrapConfig.requiredVariables.forEach((varName) => {
134
+ console.log(chalk_1.default.yellow(` • ${varName}`));
135
+ });
136
+ }
137
+ }
138
+ // Show recommendations
139
+ if (bootstrapConfig.recommendations.length > 0) {
140
+ console.log(chalk_1.default.cyan("\n💡 Recommendations:"));
141
+ bootstrapConfig.recommendations.forEach((rec) => {
142
+ console.log(chalk_1.default.gray(` • ${rec}`));
143
+ });
144
+ }
145
+ // Special warning for missing required env files
146
+ if (!bootstrapConfig.isContainerReady) {
147
+ console.log(chalk_1.default.red("\n⚠️ Container may fail to start!"));
148
+ console.log(chalk_1.default.gray(" The bootstrap configuration requires env files that are missing."));
149
+ console.log(chalk_1.default.gray(" Options:"));
150
+ console.log(chalk_1.default.gray(" 1. Create the missing env files before building"));
151
+ console.log(chalk_1.default.gray(" 2. Update bootstrap to use skipFileLoading: true"));
152
+ console.log(chalk_1.default.gray(" 3. Set environment variables in docker-compose.yml"));
153
+ }
154
+ }
@@ -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 {};