Update source/src/commands/validate-template.cpp
All checks were successful
Build-Test-Publish / build (linux/amd64) (push) Successful in 34s
Build-Test-Publish / build (linux/arm64) (push) Successful in 1m11s

This commit is contained in:
j
2026-01-15 12:58:24 +13:00
parent 9dd5206732
commit 120f7ca695

View File

@@ -286,6 +286,83 @@ ValidationResult check_uninstall_preserves_volumes(const std::filesystem::path&
return result;
}
// Check if template exposes ports but lacks ports.sh
ValidationResult check_ports_script(const std::filesystem::path& template_path) {
ValidationResult result;
result.passed = true;
bool has_ports_sh = std::filesystem::exists(template_path / "ports.sh");
bool exposes_ports = false;
std::string detection_reason;
// Check service.env for *_PORT variables
std::filesystem::path service_env_path = template_path / "config" / "service.env";
if (std::filesystem::exists(service_env_path)) {
std::ifstream env_file(service_env_path);
std::string line;
std::regex port_var_pattern(R"(^[A-Z_]*PORT\s*=)");
while (std::getline(env_file, line)) {
if (std::regex_search(line, port_var_pattern)) {
exposes_ports = true;
detection_reason = "Found PORT variable in service.env";
break;
}
}
}
// Check start.sh for -p flag
if (!exposes_ports) {
std::filesystem::path start_sh = template_path / "start.sh";
if (std::filesystem::exists(start_sh)) {
std::ifstream file(start_sh);
std::string line;
std::regex port_flag_pattern(R"(-p\s+[\"']?\$?\{?[A-Za-z_]*\}?:\d+)");
std::regex port_flag_pattern2(R"(-p\s+\d+:\d+)");
while (std::getline(file, line)) {
if (std::regex_search(line, port_flag_pattern) || std::regex_search(line, port_flag_pattern2)) {
exposes_ports = true;
detection_reason = "Found -p port mapping in start.sh";
break;
}
}
}
}
// Check docker-compose files for ports: section
if (!exposes_ports) {
for (const auto& compose_name : {"docker-compose.yml", "docker-compose.yml.template"}) {
std::filesystem::path compose_path = template_path / compose_name;
if (std::filesystem::exists(compose_path)) {
std::ifstream file(compose_path);
std::string line;
std::regex ports_pattern(R"(^\s*ports:\s*$)");
while (std::getline(file, line)) {
if (std::regex_search(line, ports_pattern)) {
exposes_ports = true;
detection_reason = "Found ports: section in " + std::string(compose_name);
break;
}
}
if (exposes_ports) break;
}
}
}
if (exposes_ports && !has_ports_sh) {
result.passed = false;
result.message = "Template exposes ports but ports.sh is missing";
result.details = detection_reason + ". Add ports.sh to output exposed port numbers.";
} else if (exposes_ports && has_ports_sh) {
result.message = "ports.sh exists for port-exposing template";
} else if (!exposes_ports && has_ports_sh) {
result.message = "ports.sh exists (no port exposure detected)";
} else {
result.message = "No ports exposed (ports.sh not required)";
}
return result;
}
// Check if scripts contain interactive commands
int check_interactive_commands(const std::filesystem::path& template_path, std::vector<std::filesystem::path>& scripts) {
int issues = 0;
@@ -484,6 +561,22 @@ int validate_handler(const CommandContext& ctx) {
}
std::cout << std::endl;
// Step 9: Check for ports.sh when ports are exposed
info << "=== Port Exposure Check ===" << std::endl;
{
ValidationResult result = check_ports_script(template_path);
if (result.passed) {
info << "" << result.message << std::endl;
} else {
warning << "" << result.message << std::endl;
if (!result.details.empty()) {
warning << " " << result.details << std::endl;
}
warnings++;
}
}
std::cout << std::endl;
// Summary
maketitle("Validation Summary");
if (errors == 0 && warnings == 0) {