@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,274 @@
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.generateCircleCI = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const template_loader_1 = require("./template-loader");
11
+ async function generateCircleCI(outputDir, options) {
12
+ const circleDir = path_1.default.join(outputDir, ".circleci");
13
+ fs_1.default.mkdirSync(circleDir, { recursive: true });
14
+ // Try remote template, fall back to embedded
15
+ const result = await (0, template_loader_1.loadCICDTemplate)("circleci", options.strategy, options, generateCircleCIContentEmbedded);
16
+ (0, template_loader_1.logTemplateSource)("CircleCI", result.source);
17
+ const filePath = path_1.default.join(circleDir, "config.yml");
18
+ fs_1.default.writeFileSync(filePath, result.content, "utf-8");
19
+ console.log(chalk_1.default.green(` ✓ Created .circleci/config.yml`));
20
+ }
21
+ exports.generateCircleCI = generateCircleCI;
22
+ /**
23
+ * Embedded template generator (fallback when remote templates unavailable)
24
+ */
25
+ function generateCircleCIContentEmbedded(options) {
26
+ const { nodeVersion, packageManager, strategy, includeSecurity, includeE2E, includeCoverage, deployTarget, branch, } = options;
27
+ const installCmd = packageManager === "pnpm"
28
+ ? "pnpm install"
29
+ : packageManager === "yarn"
30
+ ? "yarn install"
31
+ : "npm ci";
32
+ const testCmd = packageManager === "pnpm"
33
+ ? "pnpm test"
34
+ : packageManager === "yarn"
35
+ ? "yarn test"
36
+ : "npm test";
37
+ const buildCmd = packageManager === "pnpm"
38
+ ? "pnpm build"
39
+ : packageManager === "yarn"
40
+ ? "yarn build"
41
+ : "npm run build";
42
+ const lintCmd = packageManager === "pnpm"
43
+ ? "pnpm lint"
44
+ : packageManager === "yarn"
45
+ ? "yarn lint"
46
+ : "npm run lint";
47
+ let content = `# CircleCI Configuration
48
+ # Generated by ExpressoTS CLI
49
+ # Strategy: ${strategy}
50
+
51
+ version: 2.1
52
+
53
+ orbs:
54
+ node: circleci/node@5.2
55
+ docker: circleci/docker@2.5
56
+
57
+ executors:
58
+ node-executor:
59
+ docker:
60
+ - image: cimg/node:${nodeVersion}
61
+ working_directory: ~/project
62
+
63
+ commands:
64
+ install-deps:
65
+ steps:
66
+ - restore_cache:
67
+ keys:
68
+ - v1-deps-{{ checksum "package-lock.json" }}
69
+ - v1-deps-
70
+ - run:
71
+ name: Install dependencies
72
+ command: ${installCmd}
73
+ - save_cache:
74
+ key: v1-deps-{{ checksum "package-lock.json" }}
75
+ paths:
76
+ - node_modules
77
+
78
+ jobs:
79
+ lint:
80
+ executor: node-executor
81
+ steps:
82
+ - checkout
83
+ - install-deps
84
+ - run:
85
+ name: Run linter
86
+ command: ${lintCmd}
87
+
88
+ test:
89
+ executor: node-executor
90
+ steps:
91
+ - checkout
92
+ - install-deps
93
+ - run:
94
+ name: Run tests
95
+ command: ${testCmd}${includeCoverage ? ` --coverage` : ""}
96
+ `;
97
+ if (includeCoverage) {
98
+ content += ` - store_artifacts:
99
+ path: coverage
100
+ - run:
101
+ name: Upload coverage
102
+ command: |
103
+ if [ -n "$CODECOV_TOKEN" ]; then
104
+ npx codecov
105
+ fi
106
+
107
+ `;
108
+ }
109
+ else {
110
+ content += `
111
+ `;
112
+ }
113
+ // Security job
114
+ if (includeSecurity &&
115
+ (strategy === "comprehensive" || strategy === "security-focused")) {
116
+ content += ` security:
117
+ docker:
118
+ - image: aquasec/trivy:latest
119
+ steps:
120
+ - checkout
121
+ - run:
122
+ name: Run security scan
123
+ command: trivy fs --exit-code 0 --severity HIGH,CRITICAL .
124
+
125
+ `;
126
+ }
127
+ // E2E tests
128
+ if (includeE2E) {
129
+ content += ` e2e:
130
+ executor: node-executor
131
+ steps:
132
+ - checkout
133
+ - install-deps
134
+ - run:
135
+ name: Build application
136
+ command: ${buildCmd}
137
+ - run:
138
+ name: Start application
139
+ command: npm start
140
+ background: true
141
+ - run:
142
+ name: Wait for app
143
+ command: sleep 10
144
+ - run:
145
+ name: Run E2E tests
146
+ command: npm run test:e2e
147
+
148
+ `;
149
+ }
150
+ // Build job
151
+ content += ` build:
152
+ executor: node-executor
153
+ steps:
154
+ - checkout
155
+ - install-deps
156
+ - run:
157
+ name: Build application
158
+ command: ${buildCmd}
159
+ - persist_to_workspace:
160
+ root: .
161
+ paths:
162
+ - dist
163
+
164
+ docker-build:
165
+ executor: docker/docker
166
+ steps:
167
+ - checkout
168
+ - setup_remote_docker:
169
+ version: 20.10.24
170
+ - docker/check
171
+ - docker/build:
172
+ image: $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
173
+ tag: $CIRCLE_SHA1,latest
174
+ - docker/push:
175
+ image: $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
176
+ tag: $CIRCLE_SHA1,latest
177
+
178
+ `;
179
+ // Deploy job
180
+ if (deployTarget !== "none") {
181
+ content += generateCircleCIDeployJob(deployTarget);
182
+ }
183
+ // Workflows
184
+ content += `workflows:
185
+ build-and-deploy:
186
+ jobs:
187
+ - lint:
188
+ filters:
189
+ branches:
190
+ only:
191
+ - ${branch}
192
+ - /^feature/.*/
193
+ - test:
194
+ requires:
195
+ - lint
196
+ `;
197
+ if (includeSecurity &&
198
+ (strategy === "comprehensive" || strategy === "security-focused")) {
199
+ content += ` - security:
200
+ requires:
201
+ - lint
202
+ `;
203
+ }
204
+ if (includeE2E) {
205
+ content += ` - e2e:
206
+ requires:
207
+ - test
208
+ `;
209
+ }
210
+ content += ` - build:
211
+ requires:
212
+ - test
213
+ `;
214
+ if (includeSecurity &&
215
+ (strategy === "comprehensive" || strategy === "security-focused")) {
216
+ content += ` - security
217
+ `;
218
+ }
219
+ content += ` - docker-build:
220
+ requires:
221
+ - build
222
+ filters:
223
+ branches:
224
+ only: ${branch}
225
+ `;
226
+ if (deployTarget !== "none") {
227
+ content += ` - deploy:
228
+ requires:
229
+ - docker-build
230
+ filters:
231
+ branches:
232
+ only: ${branch}
233
+ `;
234
+ }
235
+ return content;
236
+ }
237
+ function generateCircleCIDeployJob(target) {
238
+ switch (target) {
239
+ case "kubernetes":
240
+ return ` deploy:
241
+ docker:
242
+ - image: bitnami/kubectl:latest
243
+ steps:
244
+ - run:
245
+ name: Deploy to Kubernetes
246
+ command: |
247
+ kubectl set image deployment/expressots-app app=$DOCKER_IMAGE:$CIRCLE_SHA1
248
+ kubectl rollout status deployment/expressots-app
249
+
250
+ `;
251
+ case "railway":
252
+ return ` deploy:
253
+ executor: node-executor
254
+ steps:
255
+ - checkout
256
+ - run:
257
+ name: Install Railway CLI
258
+ command: npm install -g @railway/cli
259
+ - run:
260
+ name: Deploy to Railway
261
+ command: railway up
262
+
263
+ `;
264
+ default:
265
+ return ` deploy:
266
+ executor: node-executor
267
+ steps:
268
+ - run:
269
+ name: Deploy
270
+ command: echo "Deploy to ${target}"
271
+
272
+ `;
273
+ }
274
+ }
@@ -0,0 +1,14 @@
1
+ export interface GeneratorOptions {
2
+ projectName: string;
3
+ nodeVersion: string;
4
+ packageManager: string;
5
+ strategy: string;
6
+ includeSecurity: boolean;
7
+ includeE2E: boolean;
8
+ includeCoverage: boolean;
9
+ dockerRegistry?: string;
10
+ deployTarget: string;
11
+ branch: string;
12
+ port: number;
13
+ }
14
+ export declare function generateGitHubActions(outputDir: string, options: GeneratorOptions): Promise<void>;
@@ -0,0 +1,426 @@
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.generateGitHubActions = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const template_loader_1 = require("./template-loader");
11
+ async function generateGitHubActions(outputDir, options) {
12
+ const workflowsDir = path_1.default.join(outputDir, ".github", "workflows");
13
+ // Create directory if it doesn't exist
14
+ fs_1.default.mkdirSync(workflowsDir, { recursive: true });
15
+ // Try remote template, fall back to embedded
16
+ const result = await (0, template_loader_1.loadCICDTemplate)("github", options.strategy, options, generateWorkflowContentEmbedded);
17
+ (0, template_loader_1.logTemplateSource)("GitHub Actions", result.source);
18
+ const filePath = path_1.default.join(workflowsDir, "ci.yml");
19
+ fs_1.default.writeFileSync(filePath, result.content, "utf-8");
20
+ console.log(chalk_1.default.green(` ✓ Created .github/workflows/ci.yml`));
21
+ }
22
+ exports.generateGitHubActions = generateGitHubActions;
23
+ /**
24
+ * Embedded template generator (fallback when remote templates unavailable)
25
+ */
26
+ function generateWorkflowContentEmbedded(options) {
27
+ const { projectName, nodeVersion, packageManager, strategy, includeSecurity, includeE2E, includeCoverage, dockerRegistry, deployTarget, branch, } = options;
28
+ const registry = dockerRegistry || "ghcr.io";
29
+ const installCmd = packageManager === "pnpm"
30
+ ? "pnpm install"
31
+ : packageManager === "yarn"
32
+ ? "yarn install"
33
+ : "npm ci";
34
+ const testCmd = packageManager === "pnpm"
35
+ ? "pnpm test"
36
+ : packageManager === "yarn"
37
+ ? "yarn test"
38
+ : "npm test";
39
+ const buildCmd = packageManager === "pnpm"
40
+ ? "pnpm build"
41
+ : packageManager === "yarn"
42
+ ? "yarn build"
43
+ : "npm run build";
44
+ const lintCmd = packageManager === "pnpm"
45
+ ? "pnpm lint"
46
+ : packageManager === "yarn"
47
+ ? "yarn lint"
48
+ : "npm run lint";
49
+ let workflow = `# GitHub Actions CI/CD Pipeline
50
+ # Generated by ExpressoTS CLI
51
+ # Strategy: ${strategy}
52
+
53
+ name: CI/CD Pipeline
54
+
55
+ on:
56
+ push:
57
+ branches: [${branch}]
58
+ pull_request:
59
+ branches: [${branch}]
60
+
61
+ env:
62
+ NODE_VERSION: '${nodeVersion}'
63
+ REGISTRY: ${registry}
64
+ IMAGE_NAME: \${{ github.repository }}
65
+
66
+ jobs:
67
+ `;
68
+ // Lint job
69
+ workflow += ` lint:
70
+ name: Lint
71
+ runs-on: ubuntu-latest
72
+ steps:
73
+ - uses: actions/checkout@v4
74
+
75
+ - name: Setup Node.js
76
+ uses: actions/setup-node@v4
77
+ with:
78
+ node-version: \${{ env.NODE_VERSION }}
79
+ cache: '${packageManager}'
80
+
81
+ - name: Install dependencies
82
+ run: ${installCmd}
83
+
84
+ - name: Run linter
85
+ run: ${lintCmd}
86
+
87
+ `;
88
+ // Test job
89
+ workflow += ` test:
90
+ name: Test
91
+ runs-on: ubuntu-latest
92
+ needs: lint
93
+ steps:
94
+ - uses: actions/checkout@v4
95
+
96
+ - name: Setup Node.js
97
+ uses: actions/setup-node@v4
98
+ with:
99
+ node-version: \${{ env.NODE_VERSION }}
100
+ cache: '${packageManager}'
101
+
102
+ - name: Install dependencies
103
+ run: ${installCmd}
104
+
105
+ - name: Run tests
106
+ run: ${testCmd}
107
+ `;
108
+ // Add coverage if enabled
109
+ if (includeCoverage) {
110
+ workflow += `
111
+ - name: Run tests with coverage
112
+ run: ${testCmd} -- --coverage
113
+
114
+ - name: Upload coverage to Codecov
115
+ uses: codecov/codecov-action@v4
116
+ with:
117
+ token: \${{ secrets.CODECOV_TOKEN }}
118
+ fail_ci_if_error: false
119
+
120
+ `;
121
+ }
122
+ else {
123
+ workflow += `
124
+ `;
125
+ }
126
+ // Security job (comprehensive and security-focused strategies)
127
+ if (includeSecurity &&
128
+ (strategy === "comprehensive" || strategy === "security-focused")) {
129
+ workflow += ` security:
130
+ name: Security Scan
131
+ runs-on: ubuntu-latest
132
+ needs: lint
133
+ steps:
134
+ - uses: actions/checkout@v4
135
+
136
+ - name: Run Trivy vulnerability scanner
137
+ uses: aquasecurity/trivy-action@master
138
+ with:
139
+ scan-type: 'fs'
140
+ scan-ref: '.'
141
+ format: 'sarif'
142
+ output: 'trivy-results.sarif'
143
+
144
+ - name: Upload Trivy scan results
145
+ uses: github/codeql-action/upload-sarif@v3
146
+ if: always()
147
+ with:
148
+ sarif_file: 'trivy-results.sarif'
149
+ `;
150
+ if (strategy === "security-focused") {
151
+ workflow += `
152
+ - name: Run Snyk security scan
153
+ uses: snyk/actions/node@master
154
+ continue-on-error: true
155
+ env:
156
+ SNYK_TOKEN: \${{ secrets.SNYK_TOKEN }}
157
+ with:
158
+ args: --severity-threshold=high
159
+
160
+ - name: OWASP Dependency Check
161
+ uses: dependency-check/Dependency-Check_Action@main
162
+ with:
163
+ project: '${projectName}'
164
+ path: '.'
165
+ format: 'HTML'
166
+ `;
167
+ }
168
+ workflow += `
169
+ `;
170
+ }
171
+ // E2E tests (if enabled)
172
+ if (includeE2E) {
173
+ workflow += ` e2e:
174
+ name: E2E Tests
175
+ runs-on: ubuntu-latest
176
+ needs: test
177
+ steps:
178
+ - uses: actions/checkout@v4
179
+
180
+ - name: Setup Node.js
181
+ uses: actions/setup-node@v4
182
+ with:
183
+ node-version: \${{ env.NODE_VERSION }}
184
+ cache: '${packageManager}'
185
+
186
+ - name: Install dependencies
187
+ run: ${installCmd}
188
+
189
+ - name: Build application
190
+ run: ${buildCmd}
191
+
192
+ - name: Start application
193
+ run: |
194
+ npm start &
195
+ sleep 10
196
+
197
+ - name: Run E2E tests
198
+ run: npm run test:e2e
199
+
200
+ `;
201
+ }
202
+ // Build job
203
+ workflow += ` build:
204
+ name: Build
205
+ runs-on: ubuntu-latest
206
+ needs: [test${includeSecurity && (strategy === "comprehensive" || strategy === "security-focused") ? ", security" : ""}${includeE2E ? ", e2e" : ""}]
207
+ steps:
208
+ - uses: actions/checkout@v4
209
+
210
+ - name: Setup Node.js
211
+ uses: actions/setup-node@v4
212
+ with:
213
+ node-version: \${{ env.NODE_VERSION }}
214
+ cache: '${packageManager}'
215
+
216
+ - name: Install dependencies
217
+ run: ${installCmd}
218
+
219
+ - name: Build application
220
+ run: ${buildCmd}
221
+
222
+ - name: Upload build artifacts
223
+ uses: actions/upload-artifact@v4
224
+ with:
225
+ name: dist
226
+ path: dist/
227
+ retention-days: 7
228
+
229
+ `;
230
+ // Docker build job
231
+ workflow += ` docker:
232
+ name: Docker Build
233
+ runs-on: ubuntu-latest
234
+ needs: build
235
+ if: github.event_name == 'push' && github.ref == 'refs/heads/${branch}'
236
+ permissions:
237
+ contents: read
238
+ packages: write
239
+ steps:
240
+ - uses: actions/checkout@v4
241
+
242
+ - name: Set up Docker Buildx
243
+ uses: docker/setup-buildx-action@v3
244
+
245
+ - name: Log in to Container Registry
246
+ uses: docker/login-action@v3
247
+ with:
248
+ registry: \${{ env.REGISTRY }}
249
+ username: \${{ github.actor }}
250
+ password: \${{ secrets.GITHUB_TOKEN }}
251
+
252
+ - name: Extract metadata
253
+ id: meta
254
+ uses: docker/metadata-action@v5
255
+ with:
256
+ images: \${{ env.REGISTRY }}/\${{ env.IMAGE_NAME }}
257
+ tags: |
258
+ type=ref,event=branch
259
+ type=sha,prefix=
260
+ type=raw,value=latest,enable={{is_default_branch}}
261
+
262
+ - name: Build and push
263
+ uses: docker/build-push-action@v5
264
+ with:
265
+ context: .
266
+ push: true
267
+ tags: \${{ steps.meta.outputs.tags }}
268
+ labels: \${{ steps.meta.outputs.labels }}
269
+ cache-from: type=gha
270
+ cache-to: type=gha,mode=max
271
+ `;
272
+ // Add container vulnerability scan
273
+ if (includeSecurity) {
274
+ workflow += `
275
+ - name: Scan container for vulnerabilities
276
+ uses: aquasecurity/trivy-action@master
277
+ with:
278
+ image-ref: \${{ env.REGISTRY }}/\${{ env.IMAGE_NAME }}:latest
279
+ format: 'sarif'
280
+ output: 'container-scan.sarif'
281
+
282
+ - name: Upload container scan results
283
+ uses: github/codeql-action/upload-sarif@v3
284
+ if: always()
285
+ with:
286
+ sarif_file: 'container-scan.sarif'
287
+ `;
288
+ }
289
+ workflow += `
290
+ `;
291
+ // Deploy job (if configured)
292
+ if (deployTarget !== "none") {
293
+ workflow += generateDeployJob(deployTarget, options);
294
+ }
295
+ return workflow;
296
+ }
297
+ function generateDeployJob(target, options) {
298
+ const { branch } = options;
299
+ switch (target) {
300
+ case "kubernetes":
301
+ return ` deploy:
302
+ name: Deploy to Kubernetes
303
+ runs-on: ubuntu-latest
304
+ needs: docker
305
+ if: github.event_name == 'push' && github.ref == 'refs/heads/${branch}'
306
+ environment: production
307
+ steps:
308
+ - uses: actions/checkout@v4
309
+
310
+ - name: Set up kubectl
311
+ uses: azure/setup-kubectl@v3
312
+
313
+ - name: Configure kubectl
314
+ run: |
315
+ echo "\${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig.yaml
316
+ export KUBECONFIG=kubeconfig.yaml
317
+
318
+ - name: Deploy to Kubernetes
319
+ run: |
320
+ kubectl set image deployment/expressots-app \\
321
+ app=\${{ env.REGISTRY }}/\${{ env.IMAGE_NAME }}:\${{ github.sha }}
322
+ kubectl rollout status deployment/expressots-app
323
+
324
+ `;
325
+ case "railway":
326
+ return ` deploy:
327
+ name: Deploy to Railway
328
+ runs-on: ubuntu-latest
329
+ needs: docker
330
+ if: github.event_name == 'push' && github.ref == 'refs/heads/${branch}'
331
+ environment: production
332
+ steps:
333
+ - uses: actions/checkout@v4
334
+
335
+ - name: Install Railway CLI
336
+ run: npm install -g @railway/cli
337
+
338
+ - name: Deploy to Railway
339
+ run: railway up
340
+ env:
341
+ RAILWAY_TOKEN: \${{ secrets.RAILWAY_TOKEN }}
342
+
343
+ `;
344
+ case "render":
345
+ return ` deploy:
346
+ name: Deploy to Render
347
+ runs-on: ubuntu-latest
348
+ needs: docker
349
+ if: github.event_name == 'push' && github.ref == 'refs/heads/${branch}'
350
+ environment: production
351
+ steps:
352
+ - name: Deploy to Render
353
+ run: |
354
+ curl -X POST \\
355
+ -H "Authorization: Bearer \${{ secrets.RENDER_API_KEY }}" \\
356
+ -H "Content-Type: application/json" \\
357
+ "\${{ secrets.RENDER_DEPLOY_HOOK_URL }}"
358
+
359
+ `;
360
+ case "fly":
361
+ return ` deploy:
362
+ name: Deploy to Fly.io
363
+ runs-on: ubuntu-latest
364
+ needs: docker
365
+ if: github.event_name == 'push' && github.ref == 'refs/heads/${branch}'
366
+ environment: production
367
+ steps:
368
+ - uses: actions/checkout@v4
369
+
370
+ - name: Setup Fly CLI
371
+ uses: superfly/flyctl-actions/setup-flyctl@master
372
+
373
+ - name: Deploy to Fly.io
374
+ run: flyctl deploy --remote-only
375
+ env:
376
+ FLY_API_TOKEN: \${{ secrets.FLY_API_TOKEN }}
377
+
378
+ `;
379
+ case "ecs":
380
+ return ` deploy:
381
+ name: Deploy to AWS ECS
382
+ runs-on: ubuntu-latest
383
+ needs: docker
384
+ if: github.event_name == 'push' && github.ref == 'refs/heads/${branch}'
385
+ environment: production
386
+ steps:
387
+ - name: Configure AWS credentials
388
+ uses: aws-actions/configure-aws-credentials@v4
389
+ with:
390
+ aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }}
391
+ aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }}
392
+ aws-region: \${{ secrets.AWS_REGION }}
393
+
394
+ - name: Update ECS service
395
+ run: |
396
+ aws ecs update-service \\
397
+ --cluster \${{ secrets.ECS_CLUSTER }} \\
398
+ --service \${{ secrets.ECS_SERVICE }} \\
399
+ --force-new-deployment
400
+
401
+ `;
402
+ case "cloudrun":
403
+ return ` deploy:
404
+ name: Deploy to Cloud Run
405
+ runs-on: ubuntu-latest
406
+ needs: docker
407
+ if: github.event_name == 'push' && github.ref == 'refs/heads/${branch}'
408
+ environment: production
409
+ steps:
410
+ - name: Authenticate to Google Cloud
411
+ uses: google-github-actions/auth@v2
412
+ with:
413
+ credentials_json: \${{ secrets.GCP_CREDENTIALS }}
414
+
415
+ - name: Deploy to Cloud Run
416
+ uses: google-github-actions/deploy-cloudrun@v2
417
+ with:
418
+ service: expressots-app
419
+ image: \${{ env.REGISTRY }}/\${{ env.IMAGE_NAME }}:\${{ github.sha }}
420
+ region: \${{ secrets.GCP_REGION }}
421
+
422
+ `;
423
+ default:
424
+ return "";
425
+ }
426
+ }
@@ -0,0 +1,2 @@
1
+ import type { GeneratorOptions } from "./github-actions";
2
+ export declare function generateGitLabCI(outputDir: string, options: GeneratorOptions): Promise<void>;