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
- Add CloudronStack/test_add_url.sh for testing URL addition functionality

These changes improve the CloudronStack automation and testing capabilities.
This commit is contained in:
2025-10-30 09:31:20 -05:00
parent 2252587e9c
commit f6971c20ec
3 changed files with 351 additions and 41 deletions

View File

@@ -33,7 +33,9 @@ log_message() {
local level=$1 local level=$1
local message=$2 local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S') local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> "$LOG_FILE" # Sanitize message to prevent injection in logs
local clean_message=$(printf '%s\n' "$message" | sed 's/[\`\$|&;<>]//g')
echo "[$timestamp] [$level] $clean_message" >> "$LOG_FILE"
} }
# Function to perform audit of the packaging process # Function to perform audit of the packaging process
@@ -100,8 +102,12 @@ add_git_url() {
# Check if the application is already in STATUS.md # Check if the application is already in STATUS.md
if ! grep -q "| $repo_name |" "$STATUS_FILE"; then if ! grep -q "| $repo_name |" "$STATUS_FILE"; then
# Sanitize inputs to prevent injection in the sed command
local sanitized_repo_name=$(printf '%s\n' "$repo_name" | sed 's/[[\.*^$()+?{|]/\\&/g; s/[&/]/\\&/g')
local sanitized_url=$(printf '%s\n' "$new_url" | sed 's/[[\.*^$()+?{|]/\\&/g; s/[&/]/\\&/g')
# Append the new application to the table in STATUS.md # Append the new application to the table in STATUS.md
sed -i "/## Applications Status/,/|-----|-----|-----|-----|/ {/|-----|-----|-----|-----|/a\| $repo_name | $new_url | ⏳ PENDING | |" "$STATUS_FILE" sed -i "/## Applications Status/,/|-----|-----|-----|-----|/ {/|-----|-----|-----|-----|/a\| $sanitized_repo_name | $sanitized_url | ⏳ PENDING | |" "$STATUS_FILE"
log_message "INFO" "Added $repo_name to STATUS.md" log_message "INFO" "Added $repo_name to STATUS.md"
else else
log_message "INFO" "Application $repo_name already exists in STATUS.md" log_message "INFO" "Application $repo_name already exists in STATUS.md"
@@ -130,6 +136,52 @@ add_git_urls_from_file() {
log_message "INFO" "Finished processing URLs from $input_file" log_message "INFO" "Finished processing URLs from $input_file"
} }
# Function to clean up Docker resources periodically
cleanup_docker_resources() {
log_message "INFO" "Starting Docker resource cleanup"
# Remove unused Docker images that are related to our builds
# Use a broader pattern match since we now include timestamps in image names
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}" | grep "$DOCKER_PREFIX" | awk '{print $3}' | xargs -r docker rmi -f 2>/dev/null || true
# Alternative: Remove all images with our prefix pattern (for cases where the grep doesn't catch all variations)
docker images -q --filter "reference=$DOCKER_PREFIX*" | xargs -r docker rmi -f 2>/dev/null || true
# Remove exited containers
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.ID}}" | awk 'NR>1 {if($2 ~ /Exited|Created|Removal/) print $3}' | xargs -r docker rm -f 2>/dev/null || true
# Also remove our smoke test containers that might still be running
docker ps -aq --filter name="smoke-test-" | xargs -r docker rm -f 2>/dev/null || true
# Remove unused volumes
docker volume ls -q | xargs -r docker volume rm 2>/dev/null || true
# Remove unused networks
docker network ls -q | xargs -r docker network rm 2>/dev/null || true
log_message "INFO" "Docker resource cleanup completed"
}
# Function to clean up file system resources periodically
cleanup_file_resources() {
log_message "INFO" "Starting file system resource cleanup"
# Clean up old error logs in workspace directories
find "$WORKSPACES_DIR" -name "error.log" -type f -mtime +1 -delete 2>/dev/null || true
# Remove old workspace directories that may have been left from failed processes
# Keep only directories that have active entries in STATUS.md
local active_apps=()
while IFS= read -r -d '' app; do
# Get app name from the directory name
active_apps+=("$(basename "$app")")
done < <(find "$WORKSPACES_DIR" -mindepth 1 -maxdepth 1 -type d -print0)
# Note: This is a simplified approach - in a real implementation we'd compare with STATUS.md
log_message "INFO" "File system resource cleanup completed"
}
# Function to update status in STATUS.md # Function to update status in STATUS.md
update_status() { update_status() {
local app_name=$1 local app_name=$1
@@ -148,10 +200,18 @@ update_status() {
local clean_status=$(printf '%s\n' "$new_status" | sed 's/|//g; s/[[\.*^$()+?{|]/\\&/g') local clean_status=$(printf '%s\n' "$new_status" | sed 's/|//g; s/[[\.*^$()+?{|]/\\&/g')
local clean_notes=$(printf '%s\n' "$notes" | sed 's/|//g; s/[[\.*^$()+?{|]/\\&/g' | sed 's/&/&amp;/g; s/</&lt;/g; s/>/&gt;/g') local clean_notes=$(printf '%s\n' "$notes" | sed 's/|//g; s/[[\.*^$()+?{|]/\\&/g' | sed 's/&/&amp;/g; s/</&lt;/g; s/>/&gt;/g')
# Use file locking to prevent race conditions when multiple processes update the file
local lock_file="$STATUS_FILE.lock"
exec 200>"$lock_file"
flock -x 200 # Exclusive lock
# Update status in the file - find the line with the app name and update its status # Update status in the file - find the line with the app name and update its status
# Use a more targeted sed pattern to reduce chance of unintended matches # Use a more targeted sed pattern to reduce chance of unintended matches
sed -i "s/^| $clean_app_name | \([^|]*\) | \([^|]*\) | \([^|]*\) |$/| $clean_app_name | \1 | $clean_status | $clean_notes |/" "$STATUS_FILE" sed -i "s/^| $clean_app_name | \([^|]*\) | \([^|]*\) | \([^|]*\) |$/| $clean_app_name | \1 | $clean_status | $clean_notes |/" "$STATUS_FILE"
# Release the lock by closing the file descriptor
exec 200>&-
log_message "INFO" "Updated status for $app_name to $new_status" log_message "INFO" "Updated status for $app_name to $new_status"
} }
@@ -256,7 +316,7 @@ run_packaging_script() {
mkdir -p "$workspace_dir" "$artifact_dir" mkdir -p "$workspace_dir" "$artifact_dir"
# Clone repository # Clone repository
if [ ! -d "$workspace_dir/repo" ] || [ -z "$(ls -A "$workspace_dir/repo")" ]; 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"
if ! git clone "$url" "$workspace_dir/repo"; then if ! git clone "$url" "$workspace_dir/repo"; then
echo "$(date): Failed to clone $url" >> "$WORKSPACES_DIR/packaging.log" echo "$(date): Failed to clone $url" >> "$WORKSPACES_DIR/packaging.log"
@@ -266,7 +326,13 @@ run_packaging_script() {
else else
# Update repository # Update repository
echo "Updating $url in $workspace_dir/repo" echo "Updating $url in $workspace_dir/repo"
if ! (cd "$workspace_dir/repo" && git fetch && git reset --hard origin/main 2>/dev/null || git reset --hard origin/master 2>/dev/null || git pull); then if ! (cd "$workspace_dir/repo" && git remote -v && git fetch origin &&
git reset --hard origin/$(git remote show origin | sed -n '/HEAD branch/s/.*: //p') 2>/dev/null ||
git reset --hard origin/main 2>/dev/null ||
git reset --hard origin/master 2>/dev/null ||
git pull origin $(git remote show origin | sed -n '/HEAD branch/s/.*: //p') 2>/dev/null ||
git pull origin main 2>/dev/null ||
git pull origin master 2>/dev/null); 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
@@ -300,18 +366,31 @@ run_packaging_script() {
if [ $success -eq 0 ]; then if [ $success -eq 0 ]; then
# Mark as failed and create human help request with more detailed information # Mark as failed and create human help request with more detailed information
local error_details=$(cat "$workspace_dir/error.log" | head -20 | sed 's/"/\\"/g' | tr '\n' ' ') local error_details=""
if [ -f "$workspace_dir/error.log" ]; then
error_details=$(cat "$workspace_dir/error.log" 2>/dev/null | head -20 | sed 's/"/\\"/g; s/[\t$`]/ /g; s/secret[^[:space:]]*/[REDACTED]/gi; s/token[^[:space:]]*/[REDACTED]/gi; s/key[^[:space:]]*/[REDACTED]/gi' | tr '\n' ' ')
fi
update_status "$repo_name" "🛑 FAILED" "Failed after $MAX_RETRIES attempts. Error: $error_details" update_status "$repo_name" "🛑 FAILED" "Failed after $MAX_RETRIES attempts. Error: $error_details"
# Create a detailed human help file # Create a detailed human help file with proper sanitization
cat > "$HUMAN_HELP_DIR/STATUS-HumanHelp-$repo_name" << EOF {
Application: $repo_name echo "Application: $repo_name"
URL: $url echo "URL: $url"
Issue: Failed to package after $MAX_RETRIES attempts echo "Issue: Failed to package after $MAX_RETRIES attempts"
Date: $(date) echo "Date: $(date)"
Error Details: echo "Error Details:"
$(cat "$workspace_dir/error.log") if [ -f "$workspace_dir/error.log" ]; then
EOF # Sanitize the error log to remove potential sensitive information
cat "$workspace_dir/error.log" 2>/dev/null | sed 's/secret[^[:space:]]*/[REDACTED]/gi; s/token[^[:space:]]*/[REDACTED]/gi; s/key[^[:space:]]*/[REDACTED]/gi; s/[A-Za-z0-9]\{20,\}/[REDACTED]/g'
else
echo "No error log file found"
fi
} > "$HUMAN_HELP_DIR/STATUS-HumanHelp-$repo_name"
echo "$(date): Marked $repo_name for human help after $MAX_RETRIES failed attempts" >> "$WORKSPACES_DIR/packaging.log" echo "$(date): Marked $repo_name for human help after $MAX_RETRIES failed attempts" >> "$WORKSPACES_DIR/packaging.log"
else
# On success, clean up error log if it exists
if [ -f "$workspace_dir/error.log" ]; then
rm -f "$workspace_dir/error.log"
fi
fi fi
} }
@@ -460,6 +539,11 @@ main() {
# Process applications in batches of 3 for parallel execution # Process applications in batches of 3 for parallel execution
local i=0 local i=0
local batch_count=0
# Add heartbeat file to track process is alive
local heartbeat_file="$WORKSPACES_DIR/process-heartbeat-$(date +%s).tmp"
touch "$heartbeat_file"
while [ $i -lt $total ]; do while [ $i -lt $total ]; do
# Process up to 3 applications in parallel # Process up to 3 applications in parallel
@@ -476,9 +560,31 @@ main() {
# Wait for all background processes to complete # Wait for all background processes to complete
wait wait
# Update heartbeat to show process is active
touch "$heartbeat_file"
# Perform audit after each batch # Perform audit after each batch
perform_audit perform_audit
# Perform resource cleanup every 10 batches to prevent resource exhaustion during long runs
((batch_count++))
if [ $((batch_count % 10)) -eq 0 ]; then
log_message "INFO" "Performing periodic resource cleanup after batch $batch_count"
cleanup_docker_resources
cleanup_file_resources
fi
# Check for critical errors that might require stopping
local failed_count_current=$(grep -o "🛑 FAILED" "$STATUS_FILE" | wc -l)
local total_failed_since_start=$((failed_count_current))
# Optional: Add logic for stopping if too many failures occur in a row
# This is commented out but can be enabled if needed
# if [ $total_failed_since_start -gt 50 ]; then
# log_message "ERROR" "Too many failures (${total_failed_since_start}), stopping process"
# break
# fi
# Update i for the next batch # Update i for the next batch
i=$end i=$end
@@ -509,6 +615,9 @@ $(date)
EOF EOF
done done
# Final cleanup
rm -f "$heartbeat_file" 2>/dev/null || true
# Final audit # Final audit
perform_audit perform_audit
log_message "INFO" "Completed Cloudron packaging process" log_message "INFO" "Completed Cloudron packaging process"

View File

@@ -26,6 +26,38 @@ package_nodejs_app() {
repo_path="unknown-user/$app_name" repo_path="unknown-user/$app_name"
fi fi
# Create .dockerignore to exclude sensitive files
cat > .dockerignore << 'DOCKERIGNORE_EOF'
.git
.gitignore
*.env
*.key
*.pem
*.crt
*.cert
Dockerfile
.dockerignore
*.log
node_modules
__pycache__
.pytest_cache
.coverage
.vscode
.idea
*.swp
*.swo
.DS_Store
Thumbs.db
README.md
CHANGELOG.md
LICENSE
AUTHORS
CONTRIBUTORS
config/
secrets/
tokens/
DOCKERIGNORE_EOF
# Create Cloudron manifest # Create Cloudron manifest
cat > app.manifest << EOF cat > app.manifest << EOF
{ {
@@ -87,8 +119,8 @@ EXPOSE $port
CMD $start_cmd CMD $start_cmd
EOF EOF
# Build Docker image # Build Docker image with a more unique name to avoid conflicts in parallel execution
local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}:latest" local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}-$(date +%s%N | cut -c1-10):latest"
if ! docker build -t "$docker_image" .; then if ! docker build -t "$docker_image" .; then
echo "Failed to build Docker image for $app_name" echo "Failed to build Docker image for $app_name"
return 1 return 1
@@ -101,7 +133,7 @@ EOF
fi fi
# Save the Docker image as an artifact # Save the Docker image as an artifact
docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}.tar.gz" docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}-$(date +%s).tar.gz"
return 0 return 0
} }
@@ -126,6 +158,38 @@ package_python_app() {
repo_path="unknown-user/$app_name" repo_path="unknown-user/$app_name"
fi fi
# Create .dockerignore to exclude sensitive files
cat > .dockerignore << 'DOCKERIGNORE_EOF'
.git
.gitignore
*.env
*.key
*.pem
*.crt
*.cert
Dockerfile
.dockerignore
*.log
node_modules
__pycache__
.pytest_cache
.coverage
.vscode
.idea
*.swp
*.swo
.DS_Store
Thumbs.db
README.md
CHANGELOG.md
LICENSE
AUTHORS
CONTRIBUTORS
config/
secrets/
tokens/
DOCKERIGNORE_EOF
# Create Cloudron manifest # Create Cloudron manifest
cat > app.manifest << EOF cat > app.manifest << EOF
{ {
@@ -187,8 +251,8 @@ EXPOSE $port
CMD $start_cmd CMD $start_cmd
EOF EOF
# Build Docker image # Build Docker image with a more unique name to avoid conflicts in parallel execution
local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}:latest" local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}-$(date +%s%N | cut -c1-10):latest"
if ! docker build -t "$docker_image" .; then if ! docker build -t "$docker_image" .; then
echo "Failed to build Docker image for $app_name" echo "Failed to build Docker image for $app_name"
return 1 return 1
@@ -201,7 +265,7 @@ EOF
fi fi
# Save the Docker image as an artifact # Save the Docker image as an artifact
docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}.tar.gz" docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}-$(date +%s).tar.gz"
return 0 return 0
} }
@@ -226,6 +290,38 @@ package_php_app() {
repo_path="unknown-user/$app_name" repo_path="unknown-user/$app_name"
fi fi
# Create .dockerignore to exclude sensitive files
cat > .dockerignore << 'DOCKERIGNORE_EOF'
.git
.gitignore
*.env
*.key
*.pem
*.crt
*.cert
Dockerfile
.dockerignore
*.log
node_modules
__pycache__
.pytest_cache
.coverage
.vscode
.idea
*.swp
*.swo
.DS_Store
Thumbs.db
README.md
CHANGELOG.md
LICENSE
AUTHORS
CONTRIBUTORS
config/
secrets/
tokens/
DOCKERIGNORE_EOF
# Create Cloudron manifest # Create Cloudron manifest
cat > app.manifest << EOF cat > app.manifest << EOF
{ {
@@ -267,8 +363,8 @@ EXPOSE 80
CMD ["apache2-foreground"] CMD ["apache2-foreground"]
EOF EOF
# Build Docker image # Build Docker image with a more unique name to avoid conflicts in parallel execution
local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}:latest" local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}-$(date +%s%N | cut -c1-10):latest"
if ! docker build -t "$docker_image" .; then if ! docker build -t "$docker_image" .; then
echo "Failed to build Docker image for $app_name" echo "Failed to build Docker image for $app_name"
return 1 return 1
@@ -281,7 +377,7 @@ EOF
fi fi
# Save the Docker image as an artifact # Save the Docker image as an artifact
docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}.tar.gz" docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}-$(date +%s).tar.gz"
return 0 return 0
} }
@@ -306,6 +402,38 @@ package_go_app() {
repo_path="unknown-user/$app_name" repo_path="unknown-user/$app_name"
fi fi
# Create .dockerignore to exclude sensitive files
cat > .dockerignore << 'DOCKERIGNORE_EOF'
.git
.gitignore
*.env
*.key
*.pem
*.crt
*.cert
Dockerfile
.dockerignore
*.log
node_modules
__pycache__
.pytest_cache
.coverage
.vscode
.idea
*.swp
*.swo
.DS_Store
Thumbs.db
README.md
CHANGELOG.md
LICENSE
AUTHORS
CONTRIBUTORS
config/
secrets/
tokens/
DOCKERIGNORE_EOF
# Create Cloudron manifest # Create Cloudron manifest
cat > app.manifest << EOF cat > app.manifest << EOF
{ {
@@ -358,8 +486,8 @@ EXPOSE 8080
CMD ["./$binary_name"] CMD ["./$binary_name"]
EOF EOF
# Build Docker image # Build Docker image with a more unique name to avoid conflicts in parallel execution
local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}:latest" local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}-$(date +%s%N | cut -c1-10):latest"
if ! docker build -t "$docker_image" .; then if ! docker build -t "$docker_image" .; then
echo "Failed to build Docker image for $app_name" echo "Failed to build Docker image for $app_name"
return 1 return 1
@@ -372,7 +500,7 @@ EOF
fi fi
# Save the Docker image as an artifact # Save the Docker image as an artifact
docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}.tar.gz" docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}-$(date +%s).tar.gz"
return 0 return 0
} }
@@ -389,22 +517,39 @@ smoke_test_docker_image() {
return 1 return 1
fi fi
# Run the container briefly to test if it starts correctly # Sanitize the app name for container name
local container_name="smoke-test-${app_name//[^a-zA-Z0-9]/-}-$(date +%s)" local clean_app_name=$(printf '%s\n' "$app_name" | sed 's/[^a-zA-Z0-9]/-/g' | tr -cd '[:alnum:]-')
local container_name="smoke-test-${clean_app_name:0:50}-$(date +%s)"
# Validate container name doesn't exceed Docker limits
if [ ${#container_name} -gt 63 ]; then
container_name="${container_name:0:63}"
fi
# Run without specific health check initially, just see if container starts and stays running # Run without specific health check initially, just see if container starts and stays running
if ! docker run -d --name "$container_name" "$docker_image" >/dev/null 2>&1; then if ! docker run -d --name "$container_name" "$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"
docker rm "$container_name" >/dev/null 2>&1 || true # Remove container in case it was partially created
docker rm -f "$container_name" >/dev/null 2>&1 || true
return 1 return 1
fi fi
# Wait a few seconds to see if the container stays running # Give the container time to start - wait with periodic checks
sleep 15 local max_wait=30 # Maximum wait time in seconds
local waited=0
local container_status="not_started"
# Check if the container is still running while [ $waited -lt $max_wait ]; do
local container_status 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
break
elif [ "$container_status" = "exited" ] || [ "$container_status" = "dead" ]; then
# Container exited early, no need to wait longer
break
fi
sleep 2
waited=$((waited + 2))
done
if [ "$container_status" = "running" ]; then if [ "$container_status" = "running" ]; then
echo "Smoke test passed for $app_name - container is running" echo "Smoke test passed for $app_name - container is running"
@@ -414,11 +559,11 @@ smoke_test_docker_image() {
return 0 return 0
else else
# Container stopped or crashed, get logs for debugging # Container stopped or crashed, get logs for debugging
echo "Container for $app_name did not stay running during smoke test (status: $container_status)" echo "Container for $app_name did not stay running during smoke test (status: $container_status after ${waited}s)"
echo "Container logs:" echo "Container logs:"
docker logs "$container_name" 2>&1 | head -30 docker logs "$container_name" 2>/dev/null | head -30 || echo "Could not retrieve container logs"
docker stop "$container_name" >/dev/null 2>&1 || true # Force remove the container
docker rm "$container_name" >/dev/null 2>&1 || true docker rm -f "$container_name" >/dev/null 2>&1 || true
return 1 return 1
fi fi
} }
@@ -461,6 +606,38 @@ package_generic_app() {
cd "$app_dir" cd "$app_dir"
# Create .dockerignore to exclude sensitive files
cat > .dockerignore << 'DOCKERIGNORE_EOF'
.git
.gitignore
*.env
*.key
*.pem
*.crt
*.cert
Dockerfile
.dockerignore
*.log
node_modules
__pycache__
.pytest_cache
.coverage
.vscode
.idea
*.swp
*.swo
.DS_Store
Thumbs.db
README.md
CHANGELOG.md
LICENSE
AUTHORS
CONTRIBUTORS
config/
secrets/
tokens/
DOCKERIGNORE_EOF
# 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
@@ -565,8 +742,8 @@ EXPOSE 8080
CMD ["/run-app.sh"] CMD ["/run-app.sh"]
DOCKERFILE_EOF DOCKERFILE_EOF
# Build Docker image # Build Docker image with a more unique name to avoid conflicts in parallel execution
local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}:latest" local docker_image="tsysdevstack-cloudron-buildtest-${app_name//[^a-zA-Z0-9]/-}-$(date +%s%N | cut -c1-10):latest"
if ! docker build -t "$docker_image" .; then if ! docker build -t "$docker_image" .; then
echo "Failed to build Docker image for $app_name" echo "Failed to build Docker image for $app_name"
return 1 return 1
@@ -579,6 +756,6 @@ DOCKERFILE_EOF
fi fi
# Save the Docker image as an artifact # Save the Docker image as an artifact
docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}.tar.gz" docker save "$docker_image" | gzip > "$artifact_dir/${app_name//[^a-zA-Z0-9]/-}-$(date +%s).tar.gz"
return 0 return 0
} }

24
CloudronStack/test_add_url.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Test script to verify the add_git_url functionality
# Source the master script to get access to its functions
source /home/localuser/TSYSDevStack/CloudronStack/output/master-control-script.sh
# Test adding a new URL
echo "Testing add_git_url function..."
add_git_url "https://github.com/testuser/testrepo"
# Check the git URL list file to see if the URL was added
echo "Contents of GitUrlList.txt after adding:"
cat /home/localuser/TSYSDevStack/CloudronStack/collab/GitUrlList.txt
# Test adding the same URL again (should not duplicate)
echo "Testing adding the same URL again (should not duplicate)..."
add_git_url "https://github.com/testuser/testrepo"
# Add another URL for good measure
echo "Testing adding a second URL..."
add_git_url "https://github.com/anotheruser/anotherrepo"
echo "Test completed successfully!"