#!/usr/bin/env sh set -eu suite="${1:-}" case "$suite" in unit|integration|api|legacy|all) ;; *) echo "Usage: $0 " >&2 exit 2 ;; esac script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" repo_root="$(CDPATH= cd -- "$script_dir/.." && pwd)" cd "$repo_root" compose_files="-f docker-compose.yml -f .github/docker-compose.ci.yml" project_suffix="$(date +%s)-$$" export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-php-local-${suite}-${project_suffix}}" export COMPOSE_PROFILES="${COMPOSE_PROFILES:-dev}" log_dir=".tmp/ci-logs/$suite" mkdir -p "$log_dir" env_backup_dir=".tmp/php-ci-env-backup-$project_suffix" mkdir -p "$env_backup_dir" had_env=0 had_env_staging=0 if [ -f .env ]; then cp .env "$env_backup_dir/env" had_env=1 fi if [ -f .env.staging ]; then cp .env.staging "$env_backup_dir/env.staging" had_env_staging=1 fi cp .github/ci.env .env cp .github/ci.env.staging .env.staging collect_logs() { status="$1" if [ "$status" -eq 0 ]; then return fi mkdir -p "$log_dir" docker compose $compose_files ps > "$log_dir/docker-compose-ps.txt" 2>&1 || true docker compose $compose_files logs --no-color > "$log_dir/docker-compose.log" 2>&1 || true docker compose $compose_files cp php1:/var/www/html/build/logs "$log_dir/app-build-logs" >/dev/null 2>&1 || true docker compose $compose_files cp php1:/var/log/php "$log_dir/php-logs" >/dev/null 2>&1 || true } retry_command() { max_attempts="$1" shift attempt=1 while :; do "$@" && return 0 status="$?" if [ "$attempt" -ge "$max_attempts" ]; then return "$status" fi sleep_seconds=$((attempt * 5)) echo "Command failed with status $status; retrying in ${sleep_seconds}s (attempt $((attempt + 1))/$max_attempts): $*" >&2 sleep "$sleep_seconds" attempt=$((attempt + 1)) done } composer_install() { dist_attempts="${PHP_CI_COMPOSER_RETRIES:-3}" source_attempts="${PHP_CI_COMPOSER_SOURCE_RETRIES:-2}" if retry_command "$dist_attempts" \ docker compose $compose_files exec -T php1 sh -lc \ 'cd /var/www/html && composer install --no-interaction --prefer-dist --no-progress'; then return 0 fi echo "Composer dist install failed after ${dist_attempts} attempts; retrying with --prefer-source." >&2 retry_command "$source_attempts" \ docker compose $compose_files exec -T php1 sh -lc \ 'cd /var/www/html && composer install --no-interaction --prefer-source --no-progress' } configure_ci_docker_subnet() { if [ -n "${CI_DOCKER_SUBNET:-}" ]; then return fi checksum="$(printf '%s' "$COMPOSE_PROJECT_NAME" | cksum | awk '{print $1}')" subnet_second=$((64 + ((checksum / 256) % 64))) subnet_third=$((checksum % 256)) export CI_DOCKER_SUBNET="10.${subnet_second}.${subnet_third}.0/24" } cleanup() { status="$?" collect_logs "$status" docker compose $compose_files down -v >/dev/null 2>&1 || true if [ "$had_env" -eq 1 ]; then cp "$env_backup_dir/env" .env else rm -f .env fi if [ "$had_env_staging" -eq 1 ]; then cp "$env_backup_dir/env.staging" .env.staging else rm -f .env.staging fi rm -rf "$env_backup_dir" exit "$status" } trap cleanup EXIT INT TERM configure_ci_docker_subnet sh scripts/ci-docker-compose-up.sh redis mysql-debug php1 docker compose $compose_files exec -T php1 sh -lc ' set -eu for i in $(seq 1 90); do if MYSQL_PWD="${CONFIG_DB_PASSWORD:-debug_root_password}" mysqladmin \ -h "${CONFIG_DB_HOST:-mysql-debug}" \ -P "${CONFIG_DB_PORT:-3306}" \ -u "${CONFIG_DB_USER:-root}" \ ping --silent >/dev/null 2>&1; then exit 0 fi sleep 1 done echo "Timed out waiting for mysql-debug" >&2 exit 1 ' tar \ --exclude='./vendor' \ --exclude='./.phpunit.cache' \ --exclude='./build/logs' \ -C services/nginx/app -cf - . \ | docker compose $compose_files exec -T php1 tar --no-same-owner -C /var/www/html -xf - docker compose $compose_files exec -T php1 sh -lc 'rm -rf /var/www/repo-root && mkdir -p /var/www/repo-root' tar \ -cf - \ Dockerfile \ Dockerfile.coolify-api \ docker-compose.yml \ docker-compose.example.yml \ docker-compose.prod.standalone.yml \ scripts/bird-control-plane-auto-activate.php \ scripts/bird-control-plane-bootstrap-local.sh \ services/coolify/api/start.sh \ services/php/Dockerfile \ services/php/php-fpm-pool.conf \ | docker compose $compose_files exec -T php1 tar --no-same-owner -C /var/www/repo-root -xf - composer_install docker compose $compose_files exec -T php1 sh -lc \ "cd /var/www/html && PLENO_REPO_ROOT_FOR_TESTS=/var/www/repo-root composer test:ci:$suite"