UNPKG

app-wizard-cli

Version:

CLI pour gérer votre projet Nest/Angular

133 lines (132 loc) 6.86 kB
import fs from 'fs-extra'; import path from 'path'; import yaml from 'js-yaml'; import { DockerComposeService } from './docker-compose-service.js'; import { TemplateConfigService } from './template-config-service.js'; export class ServiceConfigManager { /** * Vérifie si le fichier de configuration du service existe et est conforme. * S'il est absent ou incomplet (à l'exception du champ healthCheck qui est récupéré depuis docker-compose), * cette fonction ne modifie que les clés manquantes et préserve toutes celles déjà présentes. * Le fichier est situé dans le contexte de build (déduit du docker-compose) et doit s'appeler `${serviceName}.yaml`. * Le fichier doit contenir obligatoirement le champ "order". * * @param serviceName Nom du service tel que défini dans le docker-compose. * @param env Environnement ('dev' ou 'prod'). * @returns La configuration complète du service sous forme d'ExtendedServiceConfig. */ static async checkConfigsAndRepair(serviceName, env) { var _a, _b, _c; const buildContext = await DockerComposeService.getServiceBuildContext(serviceName, env); const serviceConfigPath = path.join(buildContext, `${serviceName}.yaml`); // Lire la configuration existante depuis le fichier let config = {}; if (await fs.pathExists(serviceConfigPath)) { try { const fileContents = await fs.readFile(serviceConfigPath, 'utf8'); config = yaml.load(fileContents) || {}; console.log(`Configuration trouvée pour ${serviceName}:`, config); } catch (error) { console.warn(`Erreur lors de la lecture de la config pour ${serviceName}: ${error}`); } } // On s'attend à ce que config.secrets soit déjà un tableau (grâce à la lecture du YAML) // Si ce n'est pas le cas, on utilise un tableau vide (mais le YAML de départ doit être conforme) const mergedSecrets = Array.isArray(config.secrets) ? config.secrets : []; // Compléter les valeurs manquantes const order = (_a = config.order) !== null && _a !== void 0 ? _a : await DockerComposeService.getServiceOrder(serviceName, env); const healthCheck = await DockerComposeService.getServiceHealthCheck(serviceName, env); // Conserver toutes les propriétés déjà définies, sans les modifier, et construire l'objet de sortie const output = { name: serviceName, order: order, vaultRole: (_b = config.vaultRole) !== null && _b !== void 0 ? _b : `${serviceName}-role`, prodAddress: (_c = config.prodAddress) !== null && _c !== void 0 ? _c : "", healthCheck: healthCheck, secrets: mergedSecrets }; // Écrire la configuration dans le fichier. La librairie yaml.dump respectera l'ordre d'insertion. await fs.writeFile(serviceConfigPath, yaml.dump(output)); return output; } /** * Charge la configuration d'un service à partir du fichier YAML situé dans le contexte de build. * Utilise checkConfigsAndRepair pour s'assurer que la configuration est présente et conforme. * * @param serviceName Nom du service. * @param env Environnement ('dev' ou 'prod'). * @returns La configuration complète du service ou null s'il n'est pas configuré. */ static async loadServiceConfig(serviceName, env) { try { const config = await ServiceConfigManager.checkConfigsAndRepair(serviceName, env); return config; } catch (error) { console.warn(`Aucune configuration valide trouvée pour ${serviceName}: ${error}`); return null; } } /** * Liste l'ensemble des services définis dans le fichier docker-compose.(dev|prod).yml. * Pour chaque service présent dans le docker-compose, tente de charger et réparer le fichier de configuration * situé dans le contexte de build. * Retourne la liste des ExtendedServiceConfig triée par ordre croissant (champ "order"). * * @param env Environnement ('dev' ou 'prod'). * @returns La liste triée des configurations de service. */ static async listServices(env) { const composeFileName = DockerComposeService.getComposeFileName(env); const composePath = path.join(process.cwd(), composeFileName); if (!(await fs.pathExists(composePath))) { throw new Error(`Fichier ${composeFileName} introuvable dans ${process.cwd()}`); } const composeContent = await fs.readFile(composePath, 'utf8'); const composeData = yaml.load(composeContent); const serviceNames = Object.keys(composeData.services || {}); const services = []; for (const serviceName of serviceNames) { try { const config = await ServiceConfigManager.loadServiceConfig(serviceName, env); if (config) { services.push(config); } } catch (error) { console.warn(`⚠️ Service '${serviceName}' ignoré: ${error}`); } } services.sort((a, b) => a.order - b.order); return services; } /** * Vérifie globalement la configuration du template et de tous les services définis dans le docker-compose.(dev|prod).yml. * Affiche des avertissements en cas de réparation. * * @param env Environnement ('dev' ou 'prod'). */ static async checkAllConfigs(env) { const templateConfig = await TemplateConfigService.checkTemplateConfig(); console.log(`Template: ${templateConfig.name} - Version: ${templateConfig.version}`); const composeFileName = DockerComposeService.getComposeFileName(env); const composePath = path.join(process.cwd(), composeFileName); if (!(await fs.pathExists(composePath))) { console.warn(`⚠️ Fichier ${composeFileName} introuvable dans ${process.cwd()}`); return; } const composeContent = await fs.readFile(composePath, 'utf8'); const composeData = yaml.load(composeContent); const serviceNames = Object.keys(composeData.services || {}); for (const serviceName of serviceNames) { try { const serviceConfig = await ServiceConfigManager.checkConfigsAndRepair(serviceName, env); console.log(`Service '${serviceName}' (order: ${serviceConfig.order}) configuré avec prodAddress: ${serviceConfig.prodAddress}`); } catch (error) { console.warn(`⚠️ Erreur lors de la vérification du service '${serviceName}': ${error}`); } } } }