New Templates (#586)

* feat(librechat): add LibreChat blueprint with compose, toml, metadata, links and tags

* fix: rename templates to template.toml

* fix(librechat): rename api service to librechat in docker-compose.yml

* Update blueprints/librechat/template.toml

* Update blueprints/librechat/template.toml

* fix(librechat): add version under [config] and remove stray [config.mounts] header

* fix(librechat): remove predefined persistent volume mounts from template.toml

* docs(librechat): add authentication reference link to docker-compose.yml

* feat: add Rote template

- Add Rote deployment template with frontend, backend, and PostgreSQL services
- Configure domain routing for frontend (port 80) and backend (port 3000)
- Set up automatic password generation and environment variables
- Use latest image tag by default
- Add logo and metadata to meta.json

* fix: process meta.json to fix formatting and sorting

* Update GitHub workflows to target 'canary' branch for meta validation

* Update pnpm-lock.yaml to upgrade various dependencies, including '@codemirror/autocomplete', '@radix-ui/react-dialog', and React packages to their latest versions. This includes updates to '@types/react' and '@types/react-dom' for improved compatibility and performance.

* Enhance GitHub workflows: add production deployment configuration and target 'canary' branch for pull requests.

* Refactor GitHub workflow: comment out build preview steps for clarity and future modifications.

* Remove unnecessary blank line in deploy-preview.yml for improved readability.

* Refactor GitHub workflow: uncomment build preview steps for improved deployment process and clarity.

* Update template.toml (#555)

* Update template.toml

* Update template.toml

* Update template.toml

* fix: change VITE_API_BASE to http:// for traefik.me compatibility

* changed image from sknnr/enshrouded-dedicated-server to mornedhels/enshrouded-server for autoupdate and easier config

* Add Openinary Template (#567)

* feat: add Openinary template

* feat: update Openinary configuration to support ALLOWED_ORIGIN and refactor domain variable

* fix: correct DEFAULT_DOMAIN environment variable reference in docker-compose.yml (#562)

* add rustfs template (#568)

* feat: add pull request template for improved contribution guidelines

* fix: update pull request template to clarify issue closing keywords

* feat: add validation scripts and configuration for Docker Compose and template files

- Introduced a GitHub Actions workflow to validate Docker Compose files and template.toml on pull requests.
- Added helper functions for generating random values and processing variables in templates.
- Implemented validation scripts for checking the structure, syntax, and best practices of Docker Compose and template files.
- Created necessary TypeScript types and configuration files for the build scripts.

* Add Passbolt template blueprint to Dokploy templates (#376)

* feat(templates): add Passbolt blueprint for Dokploy
- Add docker-compose.yml defining services for Passbolt and MariaDB
- Create template.toml with configurable domain, email, and database credentials
- Add meta.json with metadata, tags, and link to logo

* fix(meta): sort meta.json entries

* fix: passbolt template had several issues that broke deployment

- env variables were using old array format, changed to new table format
- mariadb healthcheck was broken (wrong command for mariadb 11)
- missing volume mounts for gpg keys, jwt tokens, and database
- setup instructions weren't visible to users, moved to docker-compose
- email config had circular references causing warnings
- tested admin user creation and confirmed working

everything works now, fully tested

* Update blueprints/passbolt/template.toml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* feat: Add Kokoro TTS FastAPI template (#353) (#403)

* feat: Add Kokoro TTS FastAPI template (#353)  - Add CPU-optimized docker-compose.yml with source build - Add GPU-optimized docker-compose-gpu.yml for NVIDIA support - Add comprehensive template.toml with OpenAI-compatible API docs - Add kokoro-tts.svg logo and meta.json entry - Support streaming audio, timestamps, and multi-language TTS - Resolves #353

* updated the meta.json for the build errors

* removed the docker-compose-gpu.yml file

* Update docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* chore: remove package-lock.json file from the app directory

* chore: update Tolgee to latest version and fix SMTP config typo (#432)

* chore: update Tolgee to latest version and fix SMTP config typo

* Update docker-compose.yml

* Update docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* fix: improve Docker Compose validation workflow to handle subshell issues

- Converted the handling of COMPOSE_FILES from a pipe to an array to ensure error propagation in the parent shell.
- Updated the loop to iterate over the array for better reliability in the validation process.

* refactor: enhance Docker Compose validation workflow to improve error handling

- Replaced the pipe with an array to handle directory names, ensuring that errors within the loop propagate correctly to the parent shell.
- Updated the loop structure for better reliability in processing the directories.

* Feat: Add parseable (#460)

* Add parseable

* Update docker-compose.yml

* Update docker-compose.yml

* Update blueprints/parseable/template.toml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>

* feat: add ChirpStack LoRaWAN Network Server template (#486)

* feat: add ChirpStack LoRaWAN Network Server template

  Add complete ChirpStack v4 template with:
  - Main ChirpStack server with web UI
  - UDP and Basics Station gateway bridges
  - REST API interface
  - PostgreSQL database with PostGIS extensions
  - Redis cache
  - Mosquitto MQTT broker

Default configuration for EU868 region with secure random credentials. Supports all LoRaWAN frequency bands globally.

* fix(chirpstack): use original configurations from chirpstack-docker repo

Update template.toml to use exact configuration files from the
chirpstack-docker repository instead of simplified versions:

- Use original chirpstack.toml with all 15 enabled regions
- Use original gateway bridge configuration with documentation links
- Use complete Basics Station EU868 config with frequency plans
- Keep original Mosquitto and PostgreSQL initialization scripts

Template size increased from 131 to 219 lines (4.7KB) to include
comprehensive default configurations that match the official setup.

* feat: add all 38 region configuration files

* fix(chirpstack): add volume mounts to expose config files to containers

* fix(chirpstack): remove read-only flag

* fix(chirpstack): correct file paths for configuration mounts in docker-compose and template files

* fix: update volume paths to be on correct directory level

* fix: configure template for dokploy-network with proper DNS resolution

- Add dokploy-network configuration to docker-compose.yml
- Replace environment variable placeholders with actual service hostnames
- Change PostgreSQL DSN from $POSTGRESQL_HOST to postgres
- Change Redis server from $REDIS_HOST to redis
- Replace $MQTT_BROKER_HOST with mosquitto in all 39 region configurations

These changes ensure Docker DNS resolution works correctly by:
- Using dokploy-network (overlay) instead of bridge network
- Using service names directly in TOML config files (TOML doesn't expand env vars)
- Enabling proper service discovery between containers

This resolves DNS resolution failures that caused ChirpStack to fail connecting
to PostgreSQL and MQTT services during deployment.

* fix: add missing network configurations for all services in docker-compose

* feat: add internal services to config.domains for proper network configuration

* Update docker-compose.yml

* fix: enhance domain validation in template validator

- Updated the TemplateValidator to ensure that if the 'host' field is provided, it must be a valid string.
- Added comments to clarify that 'host' is optional for internal services.

* refactor: remove redundant host validation in template validator

- Removed the validation for the 'host' field in the TemplateValidator, as it is optional for internal services and does not require a type check if not provided.

* refactor: remove internal service domain configurations from template

- Eliminated the domain configurations for internal services (Postgres, Redis, Mosquitto) from the template.toml file, streamlining the configuration for better clarity and maintainability.

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>

* Update section title from 'Suggestions' to 'Requirements'

* Feat : Add MCSManager template support (#521) (#522)

* feat: Add MCSManager template support (#521)

* Update docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* feat: Add MediaCMS template (#524)

* Feat : Add Quant-Ux template -#173 (#525)

* Feat : Add Quant-Ux template -#173

* Remove extra newline in docker-compose.yml

* Update blueprints/quant-ux/docker-compose.yml

* Update blueprints/quant-ux/docker-compose.yml

* Update blueprints/quant-ux/docker-compose.yml

* Update blueprints/quant-ux/docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* fix(rustdesk): use explicit ports, use port 21118 on hbbs instead of hbbr (#526)

* fix: use explicit ports, use port 21118 on hbbs instead of hbbr

* fix: whitespace character in rustdesk

* feat: Add anytype template (#527)

* add anytype template

* sort

* Update name field for Anytype in meta.json

* Update meta.json

* Update docker-compose.yml

* Update blueprints/anytype/docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* refactor: remove dokploy-network configurations from multiple docker-compose files

- Removed the external dokploy-network configuration from various services' docker-compose.yml files to streamline network management.
- This change simplifies the setup and ensures consistency across blueprints.

* chore: upgrade Infisical from v0.90.1 to v0.135.0 (#529)

* chore: upgrade Infisical from v0.90.1 to v0.135.0

* Update docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* fix: update pull request template link for clarity

- Changed the link in the pull request template from 'general suggestions' to 'general requirements' to better reflect the content and ensure users follow the correct guidelines when creating templates.

* chore: add section for screenshots or videos in pull request template

- Introduced a new section in the pull request template to encourage contributors to include screenshots or videos, enhancing the clarity and context of their submissions.

* Feat : Add MuleSoft ESB Runtime  Template (#498)

* added the mulesoft esb template

* updated the compose and the meta.json

* feat(mulesoft-esb): update image and add dynamic env configuration  - Updated image to hari1367709/mule-esb:latest - Added dynamic HTTP_PORT for runtime port configuration - Added MULE_VERSION environment variable for Mule ESB version selection

* updated the meta.json to use the version as latest

* added a comment line to the template file

* updated the mule runtime image

* fix(mulesoft-esb): update ports configuration to follow guidelines

* updated the port to use the env(HTTP_PORT)

* Update docker-compose.yml

* Update docker-compose.yml

* Update blueprints/mulesoft-esb/docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* feat(blueprint): update trmnl-byos-laravel template (#533)

* feat(blueprint): update trmnl-byos-laravel template

* Update docker-compose.yml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* feat(blueprint): peerdb template (#579)

* feat(blueprint): initial attempt at peerdb template

* fix: entrypoint and healthcheck

* fix: entrypoint

* fix: temporarily remove network

* fix: temporal port

* chore: remove 36987 for minio

* fix: remove peerdb 9900 port exposure

* fix: port for console

* fix: minio env fix

* fix: expose peerdb and minio to dokploy network

* fix(peerdb): add defaults

* fix: remove extra hosts

* fix: remove network entries

* fix: use consistent environment variables

* feat: add Bluesky PDS template (#542)

* feat: Bluesky PDS template

* chore: add bluesky pds svg

* chore: metadata for bluesky pds

* yaml > yml

* pnpm lock

* fix: correct rotation key config

* fix volumes

* fix: volumes in the pds compose

* define volumes in compose

* fix: 32 bit rotation key

* create pds.env correctly

* some extra fixes

* more extra fixes

* a blank line

* update pnpm lock

* Add dokploy-prom-monitoring-extension template with comprehensive tests and documentation (#548)

* Add dokploy-prom-monitoring-extension template with comprehensive tests and documentation

* Fix METRICS_CONFIG environment variable: use single-line JSON format

* Fix template.toml: use correct [config.env] syntax for environment variables

* Fix docker-compose.yml: add env_file reference to load environment variables

* Delete blueprints/dokploy-prom-monitoring-extension/README.md

* Delete test-dokploy-prom-monitoring-extension.sh

---------

Co-authored-by: Sanjeevi Subramani <ssanjeevi.ss@gmail.com>
Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* feat: improve RustDesk template configuration (#571)

* feat: improve RustDesk template configuration

- Add comprehensive environment variables for RustDesk server
- Add RELAY_HOST, API_SERVER, ID_SERVER, and ENCRYPTION_KEY variables
- Follow Dokploy best practices (no container_name, proper port format)
- Use restart: unless-stopped policy
- Add encryption key generation with password helper

* fix: use explicit port mapping for RustDesk services

RustDesk requires explicit port bindings (host:container format) to function properly. The service uses specific ports for:
- 21115-21116 (TCP/UDP): hbbs service for ID and NAT traversal
- 21117-21119 (TCP): hbbr relay service

Without explicit port mapping, RustDesk clients cannot establish connections to the server.

This is an exception to Dokploy's general port guidelines due to RustDesk's specific networking requirements.

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* feat: add Mumble voice chat server template (#572)

* feat: add Mumble voice chat server template

- Add Mumble VoIP server blueprint with docker-compose.yml
- Configure environment variables for superuser password, welcome text, and max users
- Add template.toml with auto-generated secure password
- Follow Dokploy best practices (no container_name, proper port format)
- Add Mumble metadata to meta.json with proper tags
- Support for TCP and UDP on port 64738

* Update template.toml

* fix: correct JSON formatting in meta.json for Mumble template entry

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>

* fix: update WireGuard Easy template for proper functionality (#573)

* fix: update WireGuard Easy template for proper functionality

- Changed to named volume (etc_wireguard) instead of host path mount
- Added explicit port mappings (51820:51820/udp, 51821:51821/tcp) required for WireGuard
- Updated environment variables to use correct WG_HOST and PASSWORD format
- Added all required WireGuard environment variables:
  - WG_PORT, PORT, WG_MTU, WG_DEFAULT_DNS, WG_ALLOWED_IPS
  - WG_POST_UP/WG_POST_DOWN for iptables rules
- Added NET_RAW capability for proper network operations
- Simplified template.toml to use WIREGUARD_HOST and WIREGUARD_PASSWORD
- Removed explicit networks config to enable Dokploy's isolated deployment
- Template now works with Dokploy's automatic network isolation

This configuration has been tested and confirmed working with isolated deployment enabled.

* Update template.toml

---------

Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>

* add: restart policy to MinIO service (#576)

restart: unless-stopped is a Docker restart policy that automatically restarts a container if it stops due to an error or Docker daemon restart

---------

Co-authored-by: Sunil Shrestha <sunil.shrestha@tekkon.com.np>
Co-authored-by: Rabithua <rabithua@gmail.com>
Co-authored-by: Mauricio Siu <siumauricio@hotmail.com>
Co-authored-by: Scan <103391616+scanash00@users.noreply.github.com>
Co-authored-by: Crackvignoule <kiki.kalagan@gmail.com>
Co-authored-by: florianheysen <39408021+florianheysen@users.noreply.github.com>
Co-authored-by: Thiago MadPin <madpin@gmail.com>
Co-authored-by: BlinkStrike <18644035+BlinkStrike@users.noreply.github.com>
Co-authored-by: M Jupri Amin <127651222+Juupeee@users.noreply.github.com>
Co-authored-by: Harikrishnan Dhanasekaran <harikrishnan@mulecraft.in>
Co-authored-by: Kamil Dzieniszewski <kamil.dzieniszewski@gmail.com>
Co-authored-by: Nick Anderson <nbrookie@gmail.com>
Co-authored-by: lefolalan <alan.lefol@omirion.com>
Co-authored-by: Chris <31969757+ChrisvanChip@users.noreply.github.com>
Co-authored-by: kipavy <88386090+kipavy@users.noreply.github.com>
Co-authored-by: Benjamin Nussbaum <bnussbau@users.noreply.github.com>
Co-authored-by: Khiet Tam Nguyen <86177399+nktnet1@users.noreply.github.com>
Co-authored-by: Vidhya LKG for IT <24915474+VidhyaSanjeevi@users.noreply.github.com>
Co-authored-by: Sanjeevi Subramani <ssanjeevi.ss@gmail.com>
Co-authored-by: Muzaffer Kadir YILMAZ <34358176+muzafferkadir@users.noreply.github.com>
Co-authored-by: Jemg <murksopps@gmail.com>
This commit is contained in:
Mauricio Siu
2025-12-14 23:40:25 -06:00
committed by GitHub
parent 3fcc9f2b93
commit 53c2ddb2fa
106 changed files with 15667 additions and 5200 deletions

View File

@@ -0,0 +1,357 @@
#!/usr/bin/env tsx
/**
* Validation script for docker-compose.yml files
* Validates structure, syntax, and best practices for Dokploy templates
*/
import * as fs from "fs";
import * as path from "path";
import * as yaml from "yaml";
import type { ComposeSpecification, DefinitionsService } from "./type";
interface DockerComposeValidatorOptions {
composePath?: string | null;
verbose?: boolean;
exitOnError?: boolean;
}
interface ValidationResult {
valid: boolean;
errors: string[];
warnings: string[];
}
type LogLevel = "info" | "success" | "warning" | "error" | "debug";
class DockerComposeValidator {
private options: Required<DockerComposeValidatorOptions>;
private errors: string[] = [];
private warnings: string[] = [];
constructor(options: DockerComposeValidatorOptions = {}) {
this.options = {
composePath: options.composePath || null,
verbose: options.verbose || false,
exitOnError: options.exitOnError !== false,
...options,
};
}
private log(message: string, level: LogLevel = "info"): void {
if (!this.options.verbose && level === "debug") return;
const prefix: Record<LogLevel, string> = {
info: "🔍",
success: "✅",
warning: "⚠️",
error: "❌",
debug: "🔍",
};
console.log(`${prefix[level] || ""} ${message}`);
}
private error(message: string): void {
this.errors.push(message);
this.log(message, "error");
}
private warning(message: string): void {
this.warnings.push(message);
this.log(message, "warning");
}
/**
* Parse docker-compose.yml file
*/
private parseCompose(composePath: string): ComposeSpecification | null {
try {
if (!fs.existsSync(composePath)) {
this.error(`docker-compose.yml not found at ${composePath}`);
return null;
}
const content = fs.readFileSync(composePath, "utf8");
const compose = yaml.parse(content) as ComposeSpecification;
if (!compose || typeof compose !== "object") {
this.error(`Invalid docker-compose.yml structure at ${composePath}`);
return null;
}
return compose;
} catch (error: any) {
this.error(`Failed to parse docker-compose.yml: ${error.message}`);
return null;
}
}
/**
* Validate that docker-compose.yml can be processed by Docker Compose
*/
private validateDockerComposeSyntax(composePath: string): boolean {
// This would ideally use docker compose config, but for now we validate structure
// The actual syntax validation happens in the CI/CD workflow with docker compose config
const compose = this.parseCompose(composePath);
return compose !== null;
}
/**
* Validate services don't use container_name (Dokploy best practice)
*/
private validateNoContainerName(services: Record<string, DefinitionsService>): void {
Object.entries(services).forEach(([serviceName, service]) => {
if (service.container_name) {
this.error(
`Service '${serviceName}': Found 'container_name' field. According to README, container_name should not be used. Dokploy manages container names automatically.`
);
}
});
}
/**
* Validate no explicit networks (Dokploy creates networks automatically)
*/
private validateNoExplicitNetworks(
compose: ComposeSpecification,
services: Record<string, DefinitionsService>
): void {
// Check for dokploy-network specifically
const hasDokployNetwork = compose.networks && "dokploy-network" in compose.networks;
// Check if any service uses explicit networks
Object.entries(services).forEach(([serviceName, service]) => {
if (service.networks) {
if (typeof service.networks === "object" && !Array.isArray(service.networks)) {
const networkNames = Object.keys(service.networks);
if (networkNames.includes("dokploy-network")) {
this.error(
`Service '${serviceName}': Uses 'dokploy-network'. Dokploy creates networks automatically, explicit networks are not needed.`
);
} else if (networkNames.length > 0) {
this.error(
`Service '${serviceName}': Uses explicit network configuration. Dokploy creates networks automatically, explicit networks are not needed.`
);
}
} else if (Array.isArray(service.networks)) {
if (service.networks.includes("dokploy-network")) {
this.error(
`Service '${serviceName}': Uses 'dokploy-network'. Dokploy creates networks automatically, explicit networks are not needed.`
);
} else if (service.networks.length > 0) {
this.error(
`Service '${serviceName}': Uses explicit network configuration. Dokploy creates networks automatically, explicit networks are not needed.`
);
}
}
}
});
// Check if networks section exists at root level
if (hasDokployNetwork) {
this.error(
"Found 'dokploy-network' in networks section. Dokploy creates networks automatically, explicit networks are not needed."
);
}
if (compose.networks && Object.keys(compose.networks).length > 0) {
this.error(
"Found explicit networks section. Dokploy creates networks automatically, explicit networks are not needed."
);
}
}
/**
* Validate ports are not mapped (should be just numbers, not host:container)
*/
private validatePortsFormat(services: Record<string, DefinitionsService>): void {
Object.entries(services).forEach(([serviceName, service]) => {
if (service.ports) {
service.ports.forEach((port, index) => {
if (typeof port === "string") {
// Check for port mapping format (e.g., "3000:3000" or "8080:80")
if (/^\d+:\d+/.test(port)) {
this.error(
`Service '${serviceName}': ports[${index}] uses port mapping format '${port}'. According to README, use only port number (e.g., '3000') instead of '3000:3000'. Dokploy handles port routing.`
);
}
} else if (typeof port === "object" && port !== null) {
// Check for published port mapping
if (port.published && port.target) {
this.error(
`Service '${serviceName}': ports[${index}] uses port mapping (published: ${port.published}, target: ${port.target}). According to README, use only port number. Dokploy handles port routing.`
);
}
}
});
}
});
}
/**
* Validate services exist
*/
private validateServicesExist(compose: ComposeSpecification): boolean {
if (!compose.services || Object.keys(compose.services).length === 0) {
this.error("No services found in docker-compose.yml");
return false;
}
const serviceNames = Object.keys(compose.services);
this.log(`Found ${serviceNames.length} service(s): ${serviceNames.join(", ")}`, "debug");
return true;
}
/**
* Validate service names follow best practices
*/
private validateServiceNames(services: Record<string, DefinitionsService>): void {
Object.keys(services).forEach((serviceName) => {
// Service names should be lowercase and use hyphens
if (serviceName !== serviceName.toLowerCase()) {
this.warning(
`Service '${serviceName}': Service names should be lowercase. Consider using '${serviceName.toLowerCase()}'.`
);
}
// Service names should not contain underscores (use hyphens instead)
if (serviceName.includes("_")) {
this.warning(
`Service '${serviceName}': Service names should use hyphens instead of underscores. Consider using '${serviceName.replace(/_/g, "-")}'.`
);
}
});
}
/**
* Main validation method
*/
validate(): ValidationResult {
if (!this.options.composePath) {
this.error("composePath option is required");
if (this.options.exitOnError) {
process.exit(1);
}
return { valid: false, errors: this.errors, warnings: this.warnings };
}
const composePath = this.options.composePath;
const templateName = path.basename(path.dirname(composePath));
this.log(`Validating docker-compose.yml: ${templateName}`);
// Parse and validate syntax
if (!this.validateDockerComposeSyntax(composePath)) {
if (this.options.exitOnError) {
process.exit(1);
}
return { valid: false, errors: this.errors, warnings: this.warnings };
}
const compose = this.parseCompose(composePath);
if (!compose) {
if (this.options.exitOnError) {
process.exit(1);
}
return { valid: false, errors: this.errors, warnings: this.warnings };
}
// Validate services exist
if (!this.validateServicesExist(compose)) {
if (this.options.exitOnError) {
process.exit(1);
}
return { valid: false, errors: this.errors, warnings: this.warnings };
}
const services = compose.services || {};
// Run all validations
this.validateNoContainerName(services);
this.validateNoExplicitNetworks(compose, services);
this.validatePortsFormat(services);
this.validateServiceNames(services);
// Show summary
if (this.errors.length === 0) {
this.log("Docker Compose file structure is valid", "success");
if (this.options.verbose) {
this.log("📋 Services found:", "info");
Object.keys(services).forEach((serviceName) => {
const service = services[serviceName];
const image = typeof service.image === "string" ? service.image : "N/A";
this.log(` - ${serviceName}: ${image}`, "debug");
});
}
}
const valid = this.errors.length === 0;
if (!valid && this.options.exitOnError) {
process.exit(1);
}
return { valid, errors: this.errors, warnings: this.warnings };
}
}
// CLI usage
if (require.main === module) {
const args = process.argv.slice(2);
const options: DockerComposeValidatorOptions = {};
let composePath: string | null = null;
// Parse command line arguments
for (let i = 0; i < args.length; i++) {
const arg = args[i];
switch (arg) {
case "--file":
case "-f":
composePath = args[++i];
break;
case "--verbose":
case "-v":
options.verbose = true;
break;
case "--help":
case "-h":
console.log(`
Usage: tsx validate-docker-compose.ts [options]
Options:
-f, --file <path> Docker Compose file path (required)
-v, --verbose Verbose output
-h, --help Show this help message
Examples:
tsx validate-docker-compose.ts --file blueprints/grafana/docker-compose.yml
tsx validate-docker-compose.ts -f blueprints/grafana/docker-compose.yml --verbose
`);
process.exit(0);
break;
}
}
if (!composePath) {
console.error("❌ Error: --file option is required");
console.error("Use --help for usage information");
process.exit(1);
}
const validator = new DockerComposeValidator({
composePath,
...options,
});
const result = validator.validate();
// Exit with appropriate code
process.exit(result.valid ? 0 : 1);
}
export default DockerComposeValidator;