/** * Update application command. * * Updates an existing Coolify application configuration. * * @module */ import { isErr } from "@mks2508/no-throw"; import chalk from "chalk"; import { getCoolifyService } from "../../coolify/index.js"; import { cacheAppSettings } from "../../coolify/config.js"; import type { ICoolifyUpdateOptions } from "../../coolify/types.js"; import { resolveUuid } from "../coolify-state.js"; import { resolveAppNameOrUuid } from "../name-resolver.js"; /** * Options for the update command. */ interface IUpdateCommandOptions { uuid?: string; name?: string; description?: string; buildPack?: string; gitBranch?: string; ports?: string; installCommand?: string; buildCommand?: string; startCommand?: string; dockerfileLocation?: string; baseDirectory?: string; domains?: string; autoDeploy?: boolean; watchPaths?: string; clearWatchPaths?: boolean; forceHttps?: boolean; healthCheckEnabled?: boolean; healthCheckPath?: string; healthCheckPort?: string; healthCheckInterval?: string; healthCheckTimeout?: string; healthCheckRetries?: string; healthCheckStartPeriod?: string; } /** * Executes the update command. * * @param options - Command options */ export async function updateCommand( options: IUpdateCommandOptions, ): Promise { let uuid = resolveUuid(options.uuid); if (!uuid && options.uuid) { uuid = await resolveAppNameOrUuid(options.uuid); } if (!uuid) { console.error( chalk.red("Error: No UUID/name provided and no .coolify.json found"), ); return; } options.uuid = uuid; console.log(chalk.cyan(`Updating application ${chalk.bold(uuid)}...`)); const service = getCoolifyService(); const initResult = await service.init(); if (isErr(initResult)) { console.error(chalk.red("Failed to initialize Coolify service")); console.error(chalk.gray(initResult.error.message)); process.exit(1); } const updateOptions: ICoolifyUpdateOptions = {}; if (options.name) updateOptions.name = options.name; if (options.description) updateOptions.description = options.description; if (options.buildPack) updateOptions.buildPack = options.buildPack as | "dockerfile" | "nixpacks" | "static" | "dockercompose"; if (options.gitBranch) updateOptions.gitBranch = options.gitBranch; if (options.ports) updateOptions.portsExposes = options.ports; if (options.installCommand) updateOptions.installCommand = options.installCommand; if (options.buildCommand) updateOptions.buildCommand = options.buildCommand; if (options.startCommand) updateOptions.startCommand = options.startCommand; if (options.dockerfileLocation) updateOptions.dockerfileLocation = options.dockerfileLocation; if (options.baseDirectory) updateOptions.baseDirectory = options.baseDirectory; if (options.domains) updateOptions.domains = options.domains; if (options.autoDeploy !== undefined) updateOptions.isAutoDeployEnabled = options.autoDeploy; if (options.clearWatchPaths) { updateOptions.watchPaths = null; } else if (options.watchPaths) { updateOptions.watchPaths = options.watchPaths.replace(/\\n/g, "\n"); } if (options.forceHttps) updateOptions.isForceHttpsEnabled = true; if (options.healthCheckEnabled !== undefined) updateOptions.healthCheckEnabled = options.healthCheckEnabled; if (options.healthCheckPath) updateOptions.healthCheckPath = options.healthCheckPath; if (options.healthCheckPort) updateOptions.healthCheckPort = options.healthCheckPort; if (options.healthCheckInterval) updateOptions.healthCheckInterval = parseInt(options.healthCheckInterval, 10); if (options.healthCheckTimeout) updateOptions.healthCheckTimeout = parseInt(options.healthCheckTimeout, 10); if (options.healthCheckRetries) updateOptions.healthCheckRetries = parseInt(options.healthCheckRetries, 10); if (options.healthCheckStartPeriod) updateOptions.healthCheckStartPeriod = parseInt(options.healthCheckStartPeriod, 10); if (Object.keys(updateOptions).length === 0) { console.warn( chalk.yellow( "No update options provided. Use --help to see available options.", ), ); process.exit(0); } const result = await service.updateApplication(options.uuid, updateOptions); if (isErr(result)) { console.error(chalk.red("Failed to update application")); console.error(chalk.gray(result.error.message)); process.exit(1); } console.log(chalk.green("Application updated successfully")); console.log(chalk.gray(`UUID: ${result.value.uuid}`)); console.log(chalk.gray(`Name: ${result.value.name}`)); if (result.value.description) { console.log(chalk.gray(`Description: ${result.value.description}`)); } // Cache and display auto-deploy and watch_paths settings if ( options.autoDeploy !== undefined || options.watchPaths || options.clearWatchPaths ) { // Cache settings locally (API GET doesn't return is_auto_deploy_enabled) const settingsToCache: Record = {}; if (options.autoDeploy !== undefined) { settingsToCache.isAutoDeployEnabled = options.autoDeploy; } if (options.clearWatchPaths) { settingsToCache.watchPaths = null; } else if (options.watchPaths) { settingsToCache.watchPaths = updateOptions.watchPaths; } await cacheAppSettings(options.uuid, settingsToCache); // Display what was set if (options.autoDeploy !== undefined) { console.log( chalk.gray(`Auto-deploy: `) + (options.autoDeploy ? chalk.green("ON") : chalk.red("OFF")), ); } // Verify watch_paths from API (this field IS returned by GET) const verifyResult = await service.getApplication(options.uuid); if (!isErr(verifyResult)) { const app = verifyResult.value; if (app.watch_paths) { console.log(chalk.gray(`Watch paths:`)); for (const p of app.watch_paths.split("\n").filter(Boolean)) { console.log(chalk.gray(` ${p}`)); } } else { console.log( chalk.gray(`Watch paths: `) + chalk.yellow("none (deploys on all changes)"), ); } } } }