@expressots/cli 3.0.0 → 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.
- package/README.md +41 -95
- package/bin/cicd/cli.d.ts +6 -0
- package/bin/cicd/cli.js +126 -0
- package/bin/cicd/form.d.ts +29 -0
- package/bin/cicd/form.js +345 -0
- package/bin/cicd/generators/azure-devops.d.ts +2 -0
- package/bin/cicd/generators/azure-devops.js +370 -0
- package/bin/cicd/generators/bitbucket.d.ts +2 -0
- package/bin/cicd/generators/bitbucket.js +217 -0
- package/bin/cicd/generators/circleci.d.ts +2 -0
- package/bin/cicd/generators/circleci.js +274 -0
- package/bin/cicd/generators/github-actions.d.ts +14 -0
- package/bin/cicd/generators/github-actions.js +426 -0
- package/bin/cicd/generators/gitlab-ci.d.ts +2 -0
- package/bin/cicd/generators/gitlab-ci.js +237 -0
- package/bin/cicd/generators/index.d.ts +6 -0
- package/bin/cicd/generators/index.js +15 -0
- package/bin/cicd/generators/jenkins.d.ts +2 -0
- package/bin/cicd/generators/jenkins.js +248 -0
- package/bin/cicd/generators/template-loader.d.ts +17 -0
- package/bin/cicd/generators/template-loader.js +128 -0
- package/bin/cicd/index.d.ts +1 -0
- package/bin/cicd/index.js +5 -0
- package/bin/cli.d.ts +1 -1
- package/bin/cli.js +18 -3
- package/bin/commands/project.commands.d.ts +19 -6
- package/bin/commands/project.commands.js +390 -61
- package/bin/config/index.d.ts +5 -0
- package/bin/config/index.js +10 -0
- package/bin/config/manager.d.ts +98 -0
- package/bin/config/manager.js +222 -0
- package/bin/containerize/analyzers/bootstrap-analyzer.d.ts +46 -0
- package/bin/containerize/analyzers/bootstrap-analyzer.js +187 -0
- package/bin/containerize/analyzers/project-analyzer.d.ts +20 -0
- package/bin/containerize/analyzers/project-analyzer.js +150 -0
- package/bin/containerize/cli.d.ts +4 -0
- package/bin/containerize/cli.js +113 -0
- package/bin/containerize/form.d.ts +15 -0
- package/bin/containerize/form.js +154 -0
- package/bin/containerize/generators/ci-generator.d.ts +31 -0
- package/bin/containerize/generators/ci-generator.js +936 -0
- package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
- package/bin/containerize/generators/docker-compose-generator.js +186 -0
- package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
- package/bin/containerize/generators/dockerfile-generator.js +635 -0
- package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
- package/bin/containerize/generators/kubernetes-generator.js +133 -0
- package/bin/containerize/generators/template-loader.d.ts +36 -0
- package/bin/containerize/generators/template-loader.js +129 -0
- package/bin/containerize/index.d.ts +4 -0
- package/bin/containerize/index.js +13 -0
- package/bin/containerize/presets/preset-registry.d.ts +20 -0
- package/bin/containerize/presets/preset-registry.js +102 -0
- package/bin/costs/cli.d.ts +5 -0
- package/bin/costs/cli.js +183 -0
- package/bin/costs/form.d.ts +44 -0
- package/bin/costs/form.js +412 -0
- package/bin/costs/index.d.ts +4 -0
- package/bin/costs/index.js +25 -0
- package/bin/costs/pricing-manager.d.ts +84 -0
- package/bin/costs/pricing-manager.js +342 -0
- package/bin/costs/providers/index.d.ts +32 -0
- package/bin/costs/providers/index.js +153 -0
- package/bin/costs/sources/api-source.d.ts +10 -0
- package/bin/costs/sources/api-source.js +32 -0
- package/bin/costs/sources/index.d.ts +6 -0
- package/bin/costs/sources/index.js +15 -0
- package/bin/costs/sources/local-json-source.d.ts +23 -0
- package/bin/costs/sources/local-json-source.js +59 -0
- package/bin/costs/sources/remote-json-source.d.ts +11 -0
- package/bin/costs/sources/remote-json-source.js +53 -0
- package/bin/costs/types.d.ts +53 -0
- package/bin/costs/types.js +5 -0
- package/bin/dev/cli.d.ts +4 -0
- package/bin/dev/cli.js +134 -0
- package/bin/dev/form.d.ts +36 -0
- package/bin/dev/form.js +254 -0
- package/bin/dev/index.d.ts +1 -0
- package/bin/dev/index.js +5 -0
- package/bin/generate/cli.js +29 -2
- package/bin/generate/form.d.ts +5 -1
- package/bin/generate/form.js +3 -3
- package/bin/generate/templates/nonopinionated/config.tpl +12 -0
- package/bin/generate/templates/nonopinionated/event.tpl +10 -0
- package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
- package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
- package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
- package/bin/generate/templates/opinionated/config.tpl +47 -0
- package/bin/generate/templates/opinionated/entity.tpl +1 -8
- package/bin/generate/templates/opinionated/event.tpl +15 -0
- package/bin/generate/templates/opinionated/guard.tpl +41 -0
- package/bin/generate/templates/opinionated/handler.tpl +23 -0
- package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
- package/bin/generate/utils/command-utils.d.ts +7 -3
- package/bin/generate/utils/command-utils.js +95 -31
- package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
- package/bin/generate/utils/nonopininated-cmd.js +100 -1
- package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
- package/bin/generate/utils/opinionated-cmd.js +112 -7
- package/bin/generate/utils/string-utils.d.ts +6 -0
- package/bin/generate/utils/string-utils.js +13 -1
- package/bin/help/form.js +11 -3
- package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
- package/bin/migrate/analyzers/platform-detector.js +116 -0
- package/bin/migrate/cli.d.ts +6 -0
- package/bin/migrate/cli.js +96 -0
- package/bin/migrate/form.d.ts +25 -0
- package/bin/migrate/form.js +347 -0
- package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
- package/bin/migrate/generators/compose-to-k8s.js +324 -0
- package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
- package/bin/migrate/generators/compose-to-railway.js +138 -0
- package/bin/migrate/generators/compose-to-render.d.ts +2 -0
- package/bin/migrate/generators/compose-to-render.js +148 -0
- package/bin/migrate/generators/generic-migration.d.ts +9 -0
- package/bin/migrate/generators/generic-migration.js +221 -0
- package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
- package/bin/migrate/generators/heroku-to-fly.js +291 -0
- package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
- package/bin/migrate/generators/heroku-to-railway.js +283 -0
- package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
- package/bin/migrate/generators/heroku-to-render.js +148 -0
- package/bin/migrate/generators/index.d.ts +7 -0
- package/bin/migrate/generators/index.js +17 -0
- package/bin/migrate/generators/template-loader.d.ts +21 -0
- package/bin/migrate/generators/template-loader.js +59 -0
- package/bin/migrate/index.d.ts +1 -0
- package/bin/migrate/index.js +5 -0
- package/bin/new/cli.js +21 -6
- package/bin/new/form.d.ts +25 -4
- package/bin/new/form.js +285 -70
- package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
- package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
- package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
- package/bin/profile/analyzers/image-analyzer.js +85 -0
- package/bin/profile/cli.d.ts +4 -0
- package/bin/profile/cli.js +92 -0
- package/bin/profile/form.d.ts +56 -0
- package/bin/profile/form.js +400 -0
- package/bin/profile/index.d.ts +1 -0
- package/bin/profile/index.js +5 -0
- package/bin/profile/optimizers/index.d.ts +19 -0
- package/bin/profile/optimizers/index.js +137 -0
- package/bin/providers/add/form.d.ts +1 -1
- package/bin/providers/add/form.js +27 -6
- package/bin/providers/create/form.js +2 -1
- package/bin/scripts/form.js +27 -5
- package/bin/studio/cli.d.ts +15 -0
- package/bin/studio/cli.js +166 -0
- package/bin/studio/index.d.ts +5 -0
- package/bin/studio/index.js +9 -0
- package/bin/templates/cache.d.ts +54 -0
- package/bin/templates/cache.js +180 -0
- package/bin/templates/cli.d.ts +8 -0
- package/bin/templates/cli.js +292 -0
- package/bin/templates/fetcher.d.ts +49 -0
- package/bin/templates/fetcher.js +208 -0
- package/bin/templates/index.d.ts +11 -0
- package/bin/templates/index.js +37 -0
- package/bin/templates/manager.d.ts +116 -0
- package/bin/templates/manager.js +323 -0
- package/bin/templates/renderer.d.ts +49 -0
- package/bin/templates/renderer.js +204 -0
- package/bin/templates/types.d.ts +51 -0
- package/bin/templates/types.js +5 -0
- package/bin/utils/add-module-to-container.d.ts +2 -2
- package/bin/utils/add-module-to-container.js +15 -5
- package/bin/utils/cli-ui.d.ts +30 -3
- package/bin/utils/cli-ui.js +95 -13
- package/bin/utils/index.d.ts +4 -0
- package/bin/utils/index.js +4 -0
- package/bin/utils/input-validation.d.ts +50 -0
- package/bin/utils/input-validation.js +143 -0
- package/bin/utils/package-manager-commands.d.ts +24 -0
- package/bin/utils/package-manager-commands.js +50 -0
- package/bin/utils/safe-spawn.d.ts +35 -0
- package/bin/utils/safe-spawn.js +51 -0
- package/bin/utils/update-tsconfig-paths.d.ts +35 -0
- package/bin/utils/update-tsconfig-paths.js +286 -0
- 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,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 {};
|