@hed-hog/cli 0.0.55 → 0.0.60

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/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/cli",
3
- "version": "0.0.55",
3
+ "version": "0.0.60",
4
4
  "description": "HedHog CLI tool",
5
5
  "author": "HedHog",
6
6
  "private": false,
@@ -11,4 +11,5 @@ export declare class DatabaseService {
11
11
  executeQuery(cwd: string, query: string, params?: any[]): Promise<any>;
12
12
  testConnection(type: 'mysql' | 'postgres', host: string, user: string, password: string, database: string, port: number, silent?: boolean): Promise<boolean | undefined>;
13
13
  generateEnvFileIfNotExists(appPath: string, dockerComposeFilePath: string): Promise<void>;
14
+ private upsertEnvVariable;
14
15
  }
@@ -142,13 +142,18 @@ let DatabaseService = class DatabaseService {
142
142
  }
143
143
  async generateEnvFileIfNotExists(appPath, dockerComposeFilePath) {
144
144
  const envFilePath = (0, path_1.resolve)(`${appPath}/.env`);
145
+ const envExamplePath = (0, path_1.resolve)(`${appPath}/.env.example`);
145
146
  let envContent = '';
146
- let shouldWrite = false;
147
147
  try {
148
148
  envContent = await (0, promises_1.readFile)(envFilePath, 'utf8');
149
149
  }
150
150
  catch {
151
- shouldWrite = true;
151
+ try {
152
+ envContent = await (0, promises_1.readFile)(envExamplePath, 'utf8');
153
+ }
154
+ catch {
155
+ envContent = '';
156
+ }
152
157
  }
153
158
  const dockerComposeContent = await (0, promises_1.readFile)(dockerComposeFilePath, 'utf8');
154
159
  const dbServiceMatch = dockerComposeContent.match(/(\w+):\s*image:\s*(postgres|mysql)/);
@@ -157,6 +162,11 @@ let DatabaseService = class DatabaseService {
157
162
  let user = 'hedhog';
158
163
  let password = 'changeme';
159
164
  let db = 'hedhog';
165
+ let port = dbType === 'postgres' ? '5432' : '3306';
166
+ const portMatch = dockerComposeContent.match(/ports:\s*\r?\n\s*-\s*["']?(\d+):(5432|3306)["']?/);
167
+ if (portMatch) {
168
+ port = portMatch[1];
169
+ }
160
170
  if (dbType === 'postgres') {
161
171
  user =
162
172
  dockerComposeContent.match(/POSTGRES_USER:\s*(\w+)/)?.[1] || user;
@@ -164,10 +174,8 @@ let DatabaseService = class DatabaseService {
164
174
  dockerComposeContent.match(/POSTGRES_PASSWORD:\s*(\w+)/)?.[1] ||
165
175
  password;
166
176
  db = dockerComposeContent.match(/POSTGRES_DB:\s*(\w+)/)?.[1] || db;
167
- const newEnv = `DATABASE_URL="postgresql://${user}:${password}@localhost:5432/${db}"`;
168
- if (!envContent.includes(newEnv)) {
169
- await (0, promises_1.writeFile)(envFilePath, newEnv, 'utf8');
170
- }
177
+ const newEnv = `DATABASE_URL="postgresql://${user}:${password}@localhost:${port}/${db}"`;
178
+ envContent = this.upsertEnvVariable(envContent, 'DATABASE_URL', newEnv);
171
179
  }
172
180
  else if (dbType === 'mysql') {
173
181
  user = dockerComposeContent.match(/MYSQL_USER:\s*(\w+)/)?.[1] || user;
@@ -175,12 +183,24 @@ let DatabaseService = class DatabaseService {
175
183
  dockerComposeContent.match(/MYSQL_PASSWORD:\s*(\w+)/)?.[1] ||
176
184
  password;
177
185
  db = dockerComposeContent.match(/MYSQL_DATABASE:\s*(\w+)/)?.[1] || db;
178
- const newEnv = `DATABASE_URL="mysql://${user}:${password}@localhost:3306/${db}"`;
179
- if (!envContent.includes(newEnv)) {
180
- await (0, promises_1.writeFile)(envFilePath, newEnv, 'utf8');
181
- }
186
+ const newEnv = `DATABASE_URL="mysql://${user}:${password}@localhost:${port}/${db}"`;
187
+ envContent = this.upsertEnvVariable(envContent, 'DATABASE_URL', newEnv);
182
188
  }
189
+ await (0, promises_1.writeFile)(envFilePath, envContent, 'utf8');
190
+ }
191
+ }
192
+ upsertEnvVariable(envContent, variableName, variableLine) {
193
+ const variablePattern = new RegExp(`^${variableName}=.*$`, 'm');
194
+ if (variablePattern.test(envContent)) {
195
+ return envContent.replace(variablePattern, variableLine);
196
+ }
197
+ if (!envContent.trim()) {
198
+ return `${variableLine}\n`;
183
199
  }
200
+ const normalizedEnvContent = envContent.endsWith('\n')
201
+ ? envContent
202
+ : `${envContent}\n`;
203
+ return `${normalizedEnvContent}${variableLine}\n`;
184
204
  }
185
205
  };
186
206
  exports.DatabaseService = DatabaseService;
@@ -1 +1 @@
1
- {"version":3,"file":"database.service.js","sourceRoot":"","sources":["../../../../src/modules/database/database.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.service.js","sourceRoot":"","sources":["../../../../src/modules/database/database.service.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,7 @@ export declare class DeveloperService {
29
29
  private getCurrentKubeContext;
30
30
  private getKubeNamespaces;
31
31
  private getKubeClusters;
32
+ private getDigitalOceanClusters;
32
33
  private extractContainerPort;
33
34
  private getDefaultAppPort;
34
35
  private extractDockerfileExposedPort;
@@ -49,6 +50,10 @@ export declare class DeveloperService {
49
50
  private generateDockerignore;
50
51
  private generateGitHubActionsWorkflow;
51
52
  private generateKubernetesManifests;
53
+ private parseDotEnv;
54
+ private getAppEnvVariables;
55
+ private isPostgresService;
56
+ private generatePostgresStatefulSetManifests;
52
57
  private generateIngressManifest;
53
58
  private generateCertManagerIssuer;
54
59
  private generateDeploymentReadme;
@@ -548,6 +548,21 @@ let DeveloperService = class DeveloperService {
548
548
  return [];
549
549
  }
550
550
  }
551
+ async getDigitalOceanClusters() {
552
+ try {
553
+ const result = await this.runner.executeCommand(runner_service_1.ProgramName.DOCTL, ['kubernetes', 'cluster', 'list', '--output', 'json'], {}, true);
554
+ const parsed = JSON.parse(result.stdout || '[]');
555
+ return parsed
556
+ .filter((cluster) => !!cluster.id)
557
+ .map((cluster) => ({
558
+ name: `${cluster.name || 'cluster'} (${cluster.id})`,
559
+ value: String(cluster.id),
560
+ }));
561
+ }
562
+ catch {
563
+ return [];
564
+ }
565
+ }
551
566
  extractContainerPort(ports) {
552
567
  for (const portEntry of ports || []) {
553
568
  if (typeof portEntry === 'number' && portEntry > 0) {
@@ -847,8 +862,16 @@ CMD ["sh", "-c", "${startCmd}"]
847
862
  const currentContext = await this.getCurrentKubeContext();
848
863
  const availableNamespaces = await this.getKubeNamespaces();
849
864
  const availableClusters = await this.getKubeClusters();
865
+ const digitalOceanClusters = await this.getDigitalOceanClusters();
850
866
  const composeData = await this.getDockerComposeServices(path);
851
867
  const availableApps = await this.getAvailableApps(path);
868
+ const selectableClusterChoices = [
869
+ ...digitalOceanClusters,
870
+ ...availableClusters.map((cluster) => ({
871
+ name: `${cluster} (kubectl)`,
872
+ value: cluster,
873
+ })),
874
+ ];
852
875
  spinner.stop();
853
876
  if (currentContext) {
854
877
  console.log(chalk.gray(`Current kubectl context: ${chalk.cyan(currentContext)}\n`));
@@ -864,6 +887,7 @@ CMD ["sh", "-c", "${startCmd}"]
864
887
  console.log(chalk.gray(`Detected ${composeData.fileName}, but no image-based services were found.\n`));
865
888
  }
866
889
  }
890
+ const doClusterIdPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
867
891
  const answers = await inquirer_1.default.prompt([
868
892
  {
869
893
  type: 'list',
@@ -905,31 +929,66 @@ CMD ["sh", "-c", "${startCmd}"]
905
929
  {
906
930
  type: 'list',
907
931
  name: 'clusterSelection',
908
- message: 'How would you like to specify your cluster?',
909
- choices: availableClusters.length > 0
932
+ message: 'How would you like to define K8S_CLUSTER_ID?',
933
+ choices: selectableClusterChoices.length > 0
910
934
  ? [
911
- { name: 'Use current context', value: 'current' },
912
- { name: 'Select from available clusters', value: 'select' },
913
- { name: 'Enter cluster name manually', value: 'manual' },
935
+ {
936
+ name: 'Use current context (you can still replace with UUID next step)',
937
+ value: 'current',
938
+ },
939
+ {
940
+ name: 'Select from available clusters (includes DigitalOcean UUIDs)',
941
+ value: 'select',
942
+ },
943
+ { name: 'Enter cluster ID manually', value: 'manual' },
914
944
  ]
915
- : [{ name: 'Enter cluster name manually', value: 'manual' }],
916
- default: availableClusters.length > 0 ? 'current' : 'manual',
917
- when: () => availableClusters.length > 0 || !currentContext,
945
+ : [{ name: 'Enter cluster ID manually', value: 'manual' }],
946
+ default: selectableClusterChoices.length > 0 ? 'current' : 'manual',
947
+ when: () => selectableClusterChoices.length > 0 || !currentContext,
918
948
  },
919
949
  {
920
950
  type: 'list',
921
- name: 'clusterName',
922
- message: 'Select your Kubernetes cluster:',
923
- choices: availableClusters,
951
+ name: 'clusterCandidate',
952
+ message: 'Select your Kubernetes cluster (used as default for K8S_CLUSTER_ID):',
953
+ choices: selectableClusterChoices,
924
954
  when: (answers) => answers.clusterSelection === 'select',
925
955
  },
926
956
  {
927
957
  type: 'input',
928
- name: 'clusterName',
929
- message: 'Enter your Kubernetes cluster name:',
930
- validate: (input) => input.length > 0 || 'Cluster name is required',
958
+ name: 'clusterCandidate',
959
+ message: 'Enter your Kubernetes cluster ID (DigitalOcean UUID, e.g. 05c7d4fa-4bc2-4dbf-80b6-757ecec43bff):',
960
+ validate: (input) => {
961
+ const value = String(input || '').trim();
962
+ if (!value)
963
+ return 'Cluster ID is required';
964
+ if (!doClusterIdPattern.test(value)) {
965
+ return 'Use a valid UUID format for DigitalOcean cluster ID';
966
+ }
967
+ return true;
968
+ },
931
969
  when: (answers) => answers.clusterSelection === 'manual',
932
970
  },
971
+ {
972
+ type: 'input',
973
+ name: 'k8sClusterId',
974
+ message: 'Enter K8S_CLUSTER_ID for GitHub Actions (DigitalOcean UUID):',
975
+ default: (answers) => String(answers.clusterCandidate || currentContext || '').trim(),
976
+ validate: (input) => {
977
+ const value = String(input || '').trim();
978
+ if (!value)
979
+ return 'K8S_CLUSTER_ID is required';
980
+ if (!doClusterIdPattern.test(value)) {
981
+ return 'K8S_CLUSTER_ID must be a UUID (example: 05c7d4fa-4bc2-4dbf-80b6-757ecec43bff)';
982
+ }
983
+ return true;
984
+ },
985
+ when: (answers) => {
986
+ const candidate = String(answers.clusterCandidate ||
987
+ (answers.clusterSelection === 'current' ? currentContext : '') ||
988
+ '').trim();
989
+ return !doClusterIdPattern.test(candidate);
990
+ },
991
+ },
933
992
  {
934
993
  type: 'list',
935
994
  name: 'namespaceSelection',
@@ -1009,6 +1068,14 @@ CMD ["sh", "-c", "${startCmd}"]
1009
1068
  })),
1010
1069
  validate: (selected) => (selected || []).length > 0 || 'Select at least one app',
1011
1070
  },
1071
+ {
1072
+ type: 'input',
1073
+ name: 'frontendUrls',
1074
+ message: 'Enter FRONTEND_URLS for frontend runtime (optional, comma-separated if needed):',
1075
+ default: (answers) => answers.domain ? `https://${String(answers.domain).trim()}` : '',
1076
+ filter: (input) => String(input || '').trim(),
1077
+ when: (answers) => (answers.apps || []).includes('admin'),
1078
+ },
1012
1079
  {
1013
1080
  type: 'checkbox',
1014
1081
  name: 'selectedInfraServices',
@@ -1054,11 +1121,13 @@ CMD ["sh", "-c", "${startCmd}"]
1054
1121
  if (!answers.confirmGeneration) {
1055
1122
  return null;
1056
1123
  }
1057
- // Set cluster name from current context if using current
1124
+ // Set cluster candidate from current context if using current
1058
1125
  if (answers.clusterSelection === 'current' && currentContext) {
1059
- // Extract cluster name from context (format may vary)
1060
- answers.clusterName = currentContext;
1126
+ answers.clusterCandidate = currentContext;
1061
1127
  }
1128
+ // Keep explicit K8S cluster ID and preserve backward compatibility
1129
+ answers.k8sClusterId = String(answers.k8sClusterId || answers.clusterCandidate || '').trim();
1130
+ const clusterName = answers.k8sClusterId;
1062
1131
  // Store if namespace needs to be created
1063
1132
  const createNamespace = answers.namespaceSelection === 'new';
1064
1133
  const parseReplicaCount = (value) => {
@@ -1091,6 +1160,7 @@ CMD ["sh", "-c", "${startCmd}"]
1091
1160
  const appPorts = await this.getAppPortsFromDockerfiles(path, answers.apps || []);
1092
1161
  return {
1093
1162
  ...answers,
1163
+ clusterName,
1094
1164
  createNamespace,
1095
1165
  appReplicas,
1096
1166
  appPorts,
@@ -1117,7 +1187,7 @@ CMD ["sh", "-c", "${startCmd}"]
1117
1187
  await this.generateGitHubActionsWorkflow(workflowsDir, config);
1118
1188
  // Generate Kubernetes manifests for each app
1119
1189
  for (const app of config.apps) {
1120
- await this.generateKubernetesManifests(k8sDir, app, config);
1190
+ await this.generateKubernetesManifests(path, k8sDir, app, config);
1121
1191
  }
1122
1192
  // Generate Ingress if requested
1123
1193
  if (config.setupIngress) {
@@ -1127,6 +1197,8 @@ CMD ["sh", "-c", "${startCmd}"]
1127
1197
  if (config.setupSSL) {
1128
1198
  await this.generateCertManagerIssuer(k8sDir, config);
1129
1199
  }
1200
+ // Generate PostgreSQL StatefulSet manifest for postgres infra service
1201
+ await this.generatePostgresStatefulSetManifests(k8sDir, config);
1130
1202
  // Generate optional Helm charts for detected docker-compose services
1131
1203
  await this.generateComposeServiceHelmCharts(path, config);
1132
1204
  // Generate README with deployment instructions
@@ -1231,12 +1303,17 @@ temp
1231
1303
  await (0, promises_1.writeFile)(workflowPath, workflowContent, 'utf8');
1232
1304
  this.log(chalk.green(`Created GitHub Actions workflow: ${workflowPath}`));
1233
1305
  }
1234
- async generateKubernetesManifests(dir, app, config) {
1306
+ async generateKubernetesManifests(projectPath, dir, app, config) {
1235
1307
  const appDir = pathModule.join(dir, app);
1236
1308
  await (0, promises_1.mkdir)(appDir, { recursive: true });
1309
+ const appEnv = await this.getAppEnvVariables(projectPath, app);
1237
1310
  const deploymentTemplatePath = pathModule.join(__dirname, '..', '..', 'templates', 'deployment', 'k8s.deployment.yaml.ejs');
1238
1311
  const deploymentTemplate = await (0, promises_1.readFile)(deploymentTemplatePath, 'utf8');
1239
- const deploymentContent = await (0, ejs_1.render)(deploymentTemplate, { config, app });
1312
+ const deploymentContent = await (0, ejs_1.render)(deploymentTemplate, {
1313
+ config,
1314
+ app,
1315
+ appEnv,
1316
+ });
1240
1317
  await (0, promises_1.writeFile)(pathModule.join(appDir, 'deployment.yaml'), this.normalizeYamlContent(deploymentContent, `k8s/${app}/deployment.yaml`), 'utf8');
1241
1318
  const serviceTemplatePath = pathModule.join(__dirname, '..', '..', 'templates', 'deployment', 'k8s.service.yaml.ejs');
1242
1319
  const serviceTemplate = await (0, promises_1.readFile)(serviceTemplatePath, 'utf8');
@@ -1244,6 +1321,84 @@ temp
1244
1321
  await (0, promises_1.writeFile)(pathModule.join(appDir, 'service.yaml'), this.normalizeYamlContent(serviceContent, `k8s/${app}/service.yaml`), 'utf8');
1245
1322
  this.log(chalk.green(`Created Kubernetes manifests for ${app}`));
1246
1323
  }
1324
+ parseDotEnv(content) {
1325
+ const result = {};
1326
+ for (const rawLine of content.split(/\r?\n/)) {
1327
+ const line = rawLine.trim();
1328
+ if (!line || line.startsWith('#')) {
1329
+ continue;
1330
+ }
1331
+ const normalized = line.startsWith('export ')
1332
+ ? line.slice('export '.length).trim()
1333
+ : line;
1334
+ const separatorIndex = normalized.indexOf('=');
1335
+ if (separatorIndex < 1) {
1336
+ continue;
1337
+ }
1338
+ const key = normalized.slice(0, separatorIndex).trim();
1339
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
1340
+ continue;
1341
+ }
1342
+ let value = normalized.slice(separatorIndex + 1).trim();
1343
+ if ((value.startsWith('"') && value.endsWith('"')) ||
1344
+ (value.startsWith("'") && value.endsWith("'"))) {
1345
+ value = value.slice(1, -1);
1346
+ }
1347
+ result[key] = value;
1348
+ }
1349
+ return result;
1350
+ }
1351
+ async getAppEnvVariables(projectPath, app) {
1352
+ const envPath = pathModule.join(projectPath, 'apps', app, '.env');
1353
+ if (!(0, fs_1.existsSync)(envPath)) {
1354
+ return {};
1355
+ }
1356
+ try {
1357
+ const envContent = await (0, promises_1.readFile)(envPath, 'utf8');
1358
+ return this.parseDotEnv(envContent);
1359
+ }
1360
+ catch {
1361
+ return {};
1362
+ }
1363
+ }
1364
+ isPostgresService(service) {
1365
+ const serviceName = String(service?.name || '').toLowerCase();
1366
+ const imageName = String(service?.image || '').toLowerCase();
1367
+ return serviceName.includes('postgres') || imageName.includes('postgres');
1368
+ }
1369
+ async generatePostgresStatefulSetManifests(k8sDir, config) {
1370
+ const infraServices = (config.infraServices || []);
1371
+ const postgresService = infraServices.find((service) => this.isPostgresService(service));
1372
+ if (!postgresService) {
1373
+ return;
1374
+ }
1375
+ const postgresDir = pathModule.join(k8sDir, 'postgres');
1376
+ await (0, promises_1.mkdir)(postgresDir, { recursive: true });
1377
+ const templatePath = pathModule.join(__dirname, '..', '..', 'templates', 'deployment', 'k8s.postgres.statefulset.yaml.ejs');
1378
+ const templateContent = await (0, promises_1.readFile)(templatePath, 'utf8');
1379
+ const statefulSetContent = await (0, ejs_1.render)(templateContent, {
1380
+ config,
1381
+ service: postgresService,
1382
+ postgresDbName: config.appName,
1383
+ });
1384
+ await (0, promises_1.writeFile)(pathModule.join(postgresDir, 'statefulset.yaml'), this.normalizeYamlContent(statefulSetContent, 'k8s/postgres/statefulset.yaml'), 'utf8');
1385
+ const serviceTemplatePath = pathModule.join(__dirname, '..', '..', 'templates', 'deployment', 'k8s.postgres.service.yaml.ejs');
1386
+ const serviceTemplateContent = await (0, promises_1.readFile)(serviceTemplatePath, 'utf8');
1387
+ const serviceContent = await (0, ejs_1.render)(serviceTemplateContent, {
1388
+ config,
1389
+ });
1390
+ await (0, promises_1.writeFile)(pathModule.join(postgresDir, 'service.yaml'), this.normalizeYamlContent(serviceContent, 'k8s/postgres/service.yaml'), 'utf8');
1391
+ const readmeTemplatePath = pathModule.join(__dirname, '..', '..', 'templates', 'deployment', 'k8s.postgres.readme.ms.ejs');
1392
+ const readmeTemplateContent = await (0, promises_1.readFile)(readmeTemplatePath, 'utf8');
1393
+ const readmeContent = await (0, ejs_1.render)(readmeTemplateContent, {
1394
+ config,
1395
+ postgresDbName: config.appName,
1396
+ postgresResourceName: `postgresql-${config.appName}`,
1397
+ k8sClusterId: config.k8sClusterId || config.clusterName,
1398
+ });
1399
+ await (0, promises_1.writeFile)(pathModule.join(postgresDir, 'README.ms'), readmeContent, 'utf8');
1400
+ this.log(chalk.green('Created PostgreSQL Kubernetes manifests and README'));
1401
+ }
1247
1402
  async generateIngressManifest(dir, config) {
1248
1403
  const templatePath = pathModule.join(__dirname, '..', '..', 'templates', 'deployment', 'k8s.ingress.yaml.ejs');
1249
1404
  const templateContent = await (0, promises_1.readFile)(templatePath, 'utf8');
@@ -1273,7 +1428,8 @@ temp
1273
1428
  console.log(chalk.white('Deploy Branch: ') +
1274
1429
  chalk.cyan(config.deployBranch || 'production'));
1275
1430
  }
1276
- console.log(chalk.white('Cluster: ') + chalk.cyan(config.clusterName));
1431
+ console.log(chalk.white('K8S Cluster ID: ') +
1432
+ chalk.cyan(config.k8sClusterId || config.clusterName));
1277
1433
  console.log(chalk.white('Namespace: ') +
1278
1434
  chalk.cyan(config.namespace) +
1279
1435
  chalk.gray(config.createNamespace ? ' (will be created)' : ' (existing)'));
@@ -1282,6 +1438,9 @@ temp
1282
1438
  if (config.domain) {
1283
1439
  console.log(chalk.white('Domain: ') + chalk.cyan(config.domain));
1284
1440
  }
1441
+ if (config.frontendUrls) {
1442
+ console.log(chalk.white('Frontend URLs: ') + chalk.cyan(config.frontendUrls));
1443
+ }
1285
1444
  console.log(chalk.white('Apps: ') + chalk.cyan(config.apps.join(', ')));
1286
1445
  console.log(chalk.white('Replicas: ') +
1287
1446
  chalk.cyan(config.apps
@@ -1298,6 +1457,7 @@ temp
1298
1457
  console.log(chalk.green.bold('\n✓ Generated Files:\n'));
1299
1458
  console.log(chalk.gray(' .dockerignore'));
1300
1459
  console.log(chalk.gray(' .github/workflows/deploy.yml'));
1460
+ const hasPostgresInfra = (config.infraServices || []).some((service) => this.isPostgresService(service));
1301
1461
  config.apps.forEach((app) => {
1302
1462
  console.log(chalk.gray(` k8s/${app}/deployment.yaml`));
1303
1463
  console.log(chalk.gray(` k8s/${app}/service.yaml`));
@@ -1311,6 +1471,11 @@ temp
1311
1471
  if (config.setupSSL) {
1312
1472
  console.log(chalk.gray(' k8s/cert-manager-issuer.yaml'));
1313
1473
  }
1474
+ if (hasPostgresInfra) {
1475
+ console.log(chalk.gray(' k8s/postgres/service.yaml'));
1476
+ console.log(chalk.gray(' k8s/postgres/statefulset.yaml'));
1477
+ console.log(chalk.gray(' k8s/postgres/README.ms'));
1478
+ }
1314
1479
  if ((config.infraServices || []).length > 0) {
1315
1480
  config.infraServices.forEach((service) => {
1316
1481
  console.log(chalk.gray(` helm/services/${service.name}/Chart.yaml`));