#!/bin/bash # Build Verification Script for Cloudron Packages # Tests Docker builds for a sample of applications to verify Dockerfiles work correctly set -e WORKSPACE="/home/localuser/TSYSDevStack/Cloudron/CloudronPackages-Workspace" # Sample applications to test (one from each language) TEST_APPS=( "goalert:go" # Go - we have source code "webhook:go" # Go - simple webhook server "runme:node" # Node.js - markdown runner "netbox:python" # Python - IPAM system "rundeck:java" # Java - job scheduler "hyperswitch:rust" # Rust - payment processor "corteza:php" # PHP - low-code platform "huginn:ruby" # Ruby - web agents ) # Function to test build test_build() { local app_name="$1" local app_type="$2" local app_dir="$WORKSPACE/$app_name" echo "🐳 Testing build for $app_name ($app_type)..." if [ ! -d "$app_dir/app" ]; then echo "❌ No app directory for $app_name" return 1 fi # Create a minimal source structure for testing (since we don't have actual source) create_test_source "$app_name" "$app_type" "$app_dir" cd "$app_dir/app" # Try to build the Docker image local image_name="test-$app_name:latest" echo " 🔨 Building Docker image..." if timeout 300 docker build -t "$image_name" . 2>/dev/null; then echo " ✅ Build successful for $app_name" # Test if image runs (briefly) echo " 🏃 Testing container startup..." if timeout 10 docker run --rm "$image_name" 2>/dev/null || true; then echo " ✅ Container starts successfully" else echo " ⚠️ Container has startup issues (expected without real source)" fi # Clean up docker rmi "$image_name" 2>/dev/null || true return 0 else echo " ❌ Build failed for $app_name" return 1 fi } # Function to create minimal test source files create_test_source() { local app_name="$1" local app_type="$2" local app_dir="$3" echo " 📁 Creating test source structure for $app_type..." case "$app_type" in "go") # Create minimal Go application mkdir -p "$app_dir/cmd/$app_name" cat > "$app_dir/go.mod" << EOF module github.com/test/$app_name go 1.21 EOF cat > "$app_dir/cmd/$app_name/main.go" << 'EOF' package main import ( "fmt" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from %s", "app") }) fmt.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } EOF ;; "node") # Create minimal Node.js application cat > "$app_dir/package.json" << EOF { "name": "$app_name", "version": "1.0.0", "main": "server.js", "scripts": { "start": "node server.js" }, "dependencies": { "express": "^4.18.0" } } EOF cat > "$app_dir/server.js" << 'EOF' const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello from Node.js app!'); }); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); }); EOF ;; "python") # Create minimal Python application cat > "$app_dir/requirements.txt" << EOF flask==2.3.0 EOF cat > "$app_dir/app.py" << 'EOF' from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return 'Hello from Python Flask app!' if __name__ == '__main__': app.run(host='0.0.0.0', port=8000) EOF ;; "java") # Create minimal Java application mkdir -p "$app_dir/src/main/java/com/test" cat > "$app_dir/pom.xml" << EOF 4.0.0 com.test $app_name 1.0.0 17 17 org.springframework.boot spring-boot-starter-web 3.1.0 EOF cat > "$app_dir/src/main/java/com/test/App.java" << EOF package com.test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } @GetMapping("/") public String home() { return "Hello from Java Spring Boot app!"; } } EOF ;; "rust") # Create minimal Rust application cat > "$app_dir/Cargo.toml" << EOF [package] name = "$app_name" version = "0.1.0" edition = "2021" [dependencies] tokio = { version = "1.0", features = ["full"] } EOF mkdir -p "$app_dir/src" cat > "$app_dir/src/main.rs" << 'EOF' use tokio::net::TcpListener; use tokio::io::{AsyncReadExt, AsyncWriteExt}; #[tokio::main] async fn main() { let listener = TcpListener::bind("0.0.0.0:8080").await.unwrap(); println!("Server listening on port 8080"); loop { let (mut socket, _) = listener.accept().await.unwrap(); tokio::spawn(async move { let mut buf = [0; 1024]; loop { let n = socket.read(&mut buf).await.unwrap(); if n == 0 { break; } let response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, Rust!"; socket.write_all(response.as_bytes()).await.unwrap(); break; } }); } } EOF ;; "php") # Create minimal PHP application cat > "$app_dir/composer.json" << EOF { "name": "$app_name/app", "require": { "php": "^8.0" } } EOF cat > "$app_dir/index.php" << 'EOF' EOF ;; "ruby") # Create minimal Ruby application cat > "$app_dir/Gemfile" << EOF source 'https://rubygems.org' gem 'sinatra' EOF cat > "$app_dir/app.rb" << 'EOF' require 'sinatra' get '/' do 'Hello from Ruby Sinatra app!' end EOF ;; esac } # Main execution echo "🚀 Starting Docker build verification..." echo "📁 Workspace: $WORKSPACE" echo "" # Check if Docker is available if ! command -v docker &> /dev/null; then echo "❌ Docker is not available. Skipping build tests." exit 1 fi success_count=0 total_count=${#TEST_APPS[@]} for app_info in "${TEST_APPS[@]}"; do IFS=':' read -r app_name app_type <<< "$app_info" if test_build "$app_name" "$app_type"; then ((success_count++)) fi echo "" done echo "🎉 Build verification complete!" echo "📊 Results: $success_count/$total_count builds successful" echo "" if [ "$success_count" -eq "$total_count" ]; then echo "✅ All Dockerfile templates are working correctly!" else echo "⚠️ Some builds failed - Dockerfiles may need adjustments" fi