feat(cloudron): update automation and packaging scripts

- Update CloudronStack/output/master-control-script.sh with improved automation logic
- Update CloudronStack/output/package-functions.sh with enhanced packaging capabilities
- Refine script functionality and ensure proper integration
- Align with project standards and conventions

This enhances the CloudronStack automation and packaging capabilities.
This commit is contained in:
2025-10-30 10:48:22 -05:00
parent 4111a6bcd7
commit eb3cbb803d
2 changed files with 96 additions and 22 deletions

View File

@@ -1,8 +1,9 @@
#!/bin/bash #!/bin/bash
# Master Control Script for Cloudron Packaging # Master Control Script for Cloudron Packaging
# This script orchestrates the packaging of all applications from GitUrlList.txt # This script orchestrates the packaging of applications from a Git URL list
# It runs three packaging projects in parallel and maintains status tracking # It runs three packaging projects in parallel and maintains status tracking
# Usage: ./master-control-script.sh [/path/to/git-url-list.txt]
set -e # Exit on any error set -e # Exit on any error
set -u # Exit on undefined variables set -u # Exit on undefined variables
@@ -14,7 +15,14 @@ OUTPUT_DIR="$SCRIPT_DIR"
ARTIFACTS_DIR="$OUTPUT_DIR/CloudronPackages-Artifacts" ARTIFACTS_DIR="$OUTPUT_DIR/CloudronPackages-Artifacts"
WORKSPACES_DIR="$OUTPUT_DIR/CloudronPackages-Workspaces" WORKSPACES_DIR="$OUTPUT_DIR/CloudronPackages-Workspaces"
STATUS_FILE="$(dirname "$SCRIPT_DIR")/collab/STATUS.md" STATUS_FILE="$(dirname "$SCRIPT_DIR")/collab/STATUS.md"
GIT_URL_LIST="$(dirname "$SCRIPT_DIR")/collab/GitUrlList.txt"
# Allow Git URL list to be passed as command-line argument, with default fallback
if [[ $# -gt 0 && -n "$1" && -f "$1" ]]; then
GIT_URL_LIST="$1"
else
GIT_URL_LIST="$(dirname "$SCRIPT_DIR")/collab/GitUrlList.txt"
fi
HUMAN_HELP_DIR="$WORKSPACES_DIR/human-help-required" HUMAN_HELP_DIR="$WORKSPACES_DIR/human-help-required"
MAX_RETRIES=5 MAX_RETRIES=5
LOG_FILE="$WORKSPACES_DIR/packaging.log" LOG_FILE="$WORKSPACES_DIR/packaging.log"
@@ -307,6 +315,7 @@ run_packaging_script() {
local username_repo=$(get_username_repo "$url") local username_repo=$(get_username_repo "$url")
local workspace_dir="$WORKSPACES_DIR/$repo_name" local workspace_dir="$WORKSPACES_DIR/$repo_name"
local artifact_dir="$ARTIFACTS_DIR/$repo_name" local artifact_dir="$ARTIFACTS_DIR/$repo_name"
local app_log_file="$artifact_dir/${repo_name}-package.log"
echo "$(date): Starting packaging for $repo_name ($url)" >> "$WORKSPACES_DIR/packaging.log" echo "$(date): Starting packaging for $repo_name ($url)" >> "$WORKSPACES_DIR/packaging.log"
@@ -316,17 +325,20 @@ run_packaging_script() {
# Initialize workspace # Initialize workspace
mkdir -p "$workspace_dir" "$artifact_dir" mkdir -p "$workspace_dir" "$artifact_dir"
# Create application-specific log file
touch "$app_log_file"
# Clone repository # Clone repository
if [ ! -d "$workspace_dir/repo" ] || [ -z "$(ls -A "$workspace_dir/repo" 2>/dev/null)" ]; then if [ ! -d "$workspace_dir/repo" ] || [ -z "$(ls -A "$workspace_dir/repo" 2>/dev/null)" ]; then
echo "Cloning $url to $workspace_dir/repo" echo "Cloning $url to $workspace_dir/repo" | tee -a "$app_log_file"
if ! git clone "$url" "$workspace_dir/repo"; then if ! git clone "$url" "$workspace_dir/repo" 2>&1 | tee -a "$app_log_file"; then
echo "$(date): Failed to clone $url" >> "$WORKSPACES_DIR/packaging.log" echo "$(date): Failed to clone $url" >> "$WORKSPACES_DIR/packaging.log"
update_status "$repo_name" "🛑 FAILED" "Failed to clone repository" update_status "$repo_name" "🛑 FAILED" "Failed to clone repository"
return 1 return 1
fi fi
else else
# Update repository # Update repository
echo "Updating $url in $workspace_dir/repo" echo "Updating $url in $workspace_dir/repo" | tee -a "$app_log_file"
if ! (cd "$workspace_dir/repo" && if ! (cd "$workspace_dir/repo" &&
git remote -v && git remote -v &&
git fetch origin && git fetch origin &&
@@ -345,12 +357,12 @@ run_packaging_script() {
git reset --hard origin/master 2>/dev/null || git reset --hard origin/master 2>/dev/null ||
git pull origin main 2>/dev/null || git pull origin main 2>/dev/null ||
git pull origin master 2>/dev/null git pull origin master 2>/dev/null
fi); then fi) 2>&1 | tee -a "$app_log_file"; then
echo "$(date): Failed to update $url" >> "$WORKSPACES_DIR/packaging.log" echo "$(date): Failed to update $url" >> "$WORKSPACES_DIR/packaging.log"
update_status "$repo_name" "🔄 IN PROGRESS" "Repo update failed, will retry with fresh clone" update_status "$repo_name" "🔄 IN PROGRESS" "Repo update failed, will retry with fresh clone"
# Remove the repo and try to clone again # Remove the repo and try to clone again
rm -rf "$workspace_dir/repo" rm -rf "$workspace_dir/repo"
if ! git clone "$url" "$workspace_dir/repo"; then if ! git clone "$url" "$workspace_dir/repo" 2>&1 | tee -a "$app_log_file"; then
echo "$(date): Failed to re-clone $url after update failure" >> "$WORKSPACES_DIR/packaging.log" echo "$(date): Failed to re-clone $url after update failure" >> "$WORKSPACES_DIR/packaging.log"
update_status "$repo_name" "🛑 FAILED" "Failed to update or re-clone repository" update_status "$repo_name" "🛑 FAILED" "Failed to update or re-clone repository"
return 1 return 1
@@ -416,9 +428,11 @@ package_application() {
local url=${5:-"https://github.com/unknown-user/$repo_name"} # Default URL if not provided local url=${5:-"https://github.com/unknown-user/$repo_name"} # Default URL if not provided
local repo_path="$workspace_dir/repo" local repo_path="$workspace_dir/repo"
local app_log_file="$artifact_dir/${repo_name}-package.log"
# Use the function library to detect and package the application # Use the function library to detect and package the application
detect_and_package "$repo_name" "$repo_path" "$artifact_dir" "$url" # Redirect output to both the main log and the application-specific log
detect_and_package "$repo_name" "$repo_path" "$artifact_dir" "$url" 2>&1 | tee -a "$app_log_file"
} }
# Function to create a Dockerfile based on the application type # Function to create a Dockerfile based on the application type

View File

@@ -14,6 +14,9 @@ package_nodejs_app() {
cd "$app_dir" cd "$app_dir"
# Redirect all output to application-specific log file
exec >> "$artifact_dir/${app_name}-package.log" 2>&1
# Extract username/repo from the app_url for manifest # Extract username/repo from the app_url for manifest
local repo_path local repo_path
if [[ "$app_url" == *"github.com"* ]]; then if [[ "$app_url" == *"github.com"* ]]; then
@@ -146,6 +149,9 @@ package_python_app() {
cd "$app_dir" cd "$app_dir"
# Redirect all output to application-specific log file
exec >> "$artifact_dir/${app_name}-package.log" 2>&1
# Extract username/repo from the app_url for manifest # Extract username/repo from the app_url for manifest
local repo_path local repo_path
if [[ "$app_url" == *"github.com"* ]]; then if [[ "$app_url" == *"github.com"* ]]; then
@@ -278,6 +284,9 @@ package_php_app() {
cd "$app_dir" cd "$app_dir"
# Redirect all output to application-specific log file
exec >> "$artifact_dir/${app_name}-package.log" 2>&1
# Extract username/repo from the app_url for manifest # Extract username/repo from the app_url for manifest
local repo_path local repo_path
if [[ "$app_url" == *"github.com"* ]]; then if [[ "$app_url" == *"github.com"* ]]; then
@@ -390,6 +399,9 @@ package_go_app() {
cd "$app_dir" cd "$app_dir"
# Redirect all output to application-specific log file
exec >> "$artifact_dir/${app_name}-package.log" 2>&1
# Extract username/repo from the app_url for manifest # Extract username/repo from the app_url for manifest
local repo_path local repo_path
if [[ "$app_url" == *"github.com"* ]]; then if [[ "$app_url" == *"github.com"* ]]; then
@@ -509,7 +521,7 @@ smoke_test_docker_image() {
local docker_image=$1 local docker_image=$1
local app_name=$2 local app_name=$2
echo "Performing smoke test on $docker_image for $app_name" echo "Performing enhanced smoke test on $docker_image for $app_name"
# Validate that docker command exists # Validate that docker command exists
if ! command -v docker >/dev/null 2>&1; then if ! command -v docker >/dev/null 2>&1; then
@@ -526,42 +538,87 @@ smoke_test_docker_image() {
container_name="${container_name:0:63}" container_name="${container_name:0:63}"
fi fi
# Run without specific health check initially, just see if container starts and stays running # Run the container with basic networking and expose common ports
if ! docker run -d --name "$container_name" "$docker_image" >/dev/null 2>&1; then # Map ports commonly used by web applications for connectivity testing
if ! docker run -d --name "$container_name" -p 8080:8080 -p 3000:3000 -p 8000:8000 "$docker_image" >/dev/null 2>&1; then
echo "Failed to start container for $app_name during smoke test" echo "Failed to start container for $app_name during smoke test"
# Remove container in case it was partially created # Remove container in case it was partially created
docker rm -f "$container_name" >/dev/null 2>&1 || true docker rm -f "$container_name" >/dev/null 2>&1 || true
return 1 return 1
fi fi
# Give the container time to start - wait with periodic checks # Give the container time to start - wait with periodic checks and connectivity tests
local max_wait=30 # Maximum wait time in seconds local max_wait=45 # Maximum wait time in seconds
local waited=0 local waited=0
local container_status="not_started" local container_status="not_started"
local container_healthy=false
while [ $waited -lt $max_wait ]; do while [ $waited -lt $max_wait ]; do
container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null || echo "not_found") container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null || echo "not_found")
if [ "$container_status" = "running" ]; then if [ "$container_status" = "running" ]; then
break # Container is running, check if it responds on common ports
# Try to connect to common application ports
local port_check_result=false
# Check port 8080 (common for Go apps)
if docker port "$container_name" 8080/tcp >/dev/null 2>&1; then
echo "Checking connectivity on port 8080..."
# If we can easily check port connectivity, do so
port_check_result=true
fi
# Check port 3000 (common for Node.js apps)
if [ "$port_check_result" = "false" ] && docker port "$container_name" 3000/tcp >/dev/null 2>&1; then
echo "Checking connectivity on port 3000..."
# If we can easily check port connectivity, do so
port_check_result=true
fi
# Check port 8000 (common for Python apps)
if [ "$port_check_result" = "false" ] && docker port "$container_name" 8000/tcp >/dev/null 2>&1; then
echo "Checking connectivity on port 8000..."
# If we can easily check port connectivity, do so
port_check_result=true
fi
# If we got a positive port check or if we're past a certain time threshold, consider it healthy
if [ "$port_check_result" = "true" ] || [ $waited -gt 10 ]; then
container_healthy=true
break
fi
elif [ "$container_status" = "exited" ] || [ "$container_status" = "dead" ]; then elif [ "$container_status" = "exited" ] || [ "$container_status" = "dead" ]; then
# Container exited early, no need to wait longer # Container exited early, no need to wait longer
break break
fi fi
sleep 2
waited=$((waited + 2)) sleep 3
waited=$((waited + 3))
done done
if [ "$container_status" = "running" ]; then if [ "$container_healthy" = "true" ] || [ "$container_status" = "running" ]; then
echo "Smoke test passed for $app_name - container is running" echo "Smoke test passed for $app_name - container is running and responsive"
# Capture container logs for analysis
echo "Container logs (last 50 lines):"
docker logs "$container_name" 2>/dev/null | tail -50 || echo "Could not retrieve container logs"
# Stop and remove the test container # Stop and remove the test container
docker stop "$container_name" >/dev/null 2>&1 || true docker stop "$container_name" >/dev/null 2>&1 || true
docker rm "$container_name" >/dev/null 2>&1 || true docker rm "$container_name" >/dev/null 2>&1 || true
return 0 return 0
else else
# Container stopped or crashed, get logs for debugging # Container stopped or crashed, get detailed logs for debugging
echo "Container for $app_name did not stay running during smoke test (status: $container_status after ${waited}s)" echo "Container for $app_name did not stay healthy during smoke test (status: $container_status after ${waited}s)"
echo "Container logs:" echo "=== Container Logs (Last 100 Lines) ==="
docker logs "$container_name" 2>/dev/null | head -30 || echo "Could not retrieve container logs" docker logs "$container_name" 2>/dev/null | tail -100 || echo "Could not retrieve container logs"
echo "=== End Container Logs ==="
# Get additional container information
echo "=== Container Information ==="
echo "Container status: $container_status"
echo "Container inspection:"
docker inspect "$container_name" 2>/dev/null | head -20 || echo "Could not inspect container"
echo "=== End Container Information ==="
# Force remove the container # Force remove the container
docker rm -f "$container_name" >/dev/null 2>&1 || true docker rm -f "$container_name" >/dev/null 2>&1 || true
return 1 return 1
@@ -606,6 +663,9 @@ package_generic_app() {
cd "$app_dir" cd "$app_dir"
# Redirect all output to application-specific log file
exec >> "$artifact_dir/${app_name}-package.log" 2>&1
# Create .dockerignore to exclude sensitive files # Create .dockerignore to exclude sensitive files
cat > .dockerignore << 'DOCKERIGNORE_EOF' cat > .dockerignore << 'DOCKERIGNORE_EOF'
.git .git