name: Docker Build, Test & Push on: push: branches-ignore: - main - default workflow_dispatch: # ============================================================================== # KONFIGURATION (Für andere Repositories einfach hier oben anpassen) # ============================================================================== env: # Registry, Benutzer & Image-Name (leer lassen = automatisch aus Gitea-Kontext) REGISTRY: git.dsit.me REGISTRY_USER: "sandrodach" CUSTOM_IMAGE_NAME: "container/webhost" # Pfad zum Build-Kontext und Dockerfile BUILD_CONTEXT: ./dockerfile DOCKERFILE: ./dockerfile/Dockerfile # Name des temporären Test-Containers & Start-Timeout (in Sekunden) CONTAINER_NAME: ci-test-container STARTUP_TIMEOUT: 15 # Umgebungsvariablen für den Test-Container (leer lassen falls nicht benötigt) CONTAINER_ENV: >- -e SMTP_HOST=127.0.0.1 -e SMTP_PORT=2525 -e SMTP_USER=testuser@example.com -e SMTP_PASS=supersecret -e SMTP_FROM=noreply@example.com -e SMTP_TLS=off -e SMTP_STARTTLS=off # Optionale Checks im Container (jeweils leer "" lassen zum Überspringen) READINESS_CMD: "apache2ctl -t" REQUIRED_PHP_EXTENSIONS: "mysqli gd imagick intl zip exif" REQUIRED_APACHE_MODULES: "ssl_module rewrite_module" TEST_HTTP_PORT: "80" TEST_HTTPS_PORT: "443" WEBROOT_DIR: "/var/www/html" jobs: build-test-push: name: Build, Test & Push (${{ gitea.ref_name }}) runs-on: ubuntu-latest if: gitea.ref_name != 'main' && gitea.ref_name != 'default' steps: - name: Checkout Repository uses: actions/checkout@v4 - name: Prepare Image Tag from Branch id: meta run: | if [ -n "${CUSTOM_IMAGE_NAME}" ]; then IMAGE_REPO=$(echo "${CUSTOM_IMAGE_NAME}" | tr '[:upper:]' '[:lower:]') else IMAGE_REPO=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]') fi # Branch-Namen als Docker-Tag nutzen (Schrägstriche durch Bindestriche ersetzen) BRANCH_TAG=$(echo "${{ gitea.ref_name }}" | sed 's/[^a-zA-Z0-9._-]/-/g') FULL_TAG="${REGISTRY}/${IMAGE_REPO}:${BRANCH_TAG}" echo "Target Image Tag: ${FULL_TAG}" echo "image_tag=${FULL_TAG}" >> "$GITEA_OUTPUT" - name: Build Docker Image run: | docker build \ -f "${DOCKERFILE}" \ -t "${{ steps.meta.outputs.image_tag }}" \ "${BUILD_CONTEXT}" - name: Start Container & Wait for Readiness run: | docker rm -f "${CONTAINER_NAME}" 2>/dev/null || true # shellcheck disable=SC2086 docker run -d \ --name "${CONTAINER_NAME}" \ ${CONTAINER_ENV} \ "${{ steps.meta.outputs.image_tag }}" echo "Waiting up to ${STARTUP_TIMEOUT}s for container to become ready..." for i in $(seq 1 "${STARTUP_TIMEOUT}"); do if [ "$(docker inspect -f '{{.State.Running}}' "${CONTAINER_NAME}" 2>/dev/null)" = "true" ]; then if [ -z "${READINESS_CMD}" ] || docker exec "${CONTAINER_NAME}" sh -c "${READINESS_CMD}" >/dev/null 2>&1; then echo "Container is running and ready." break fi fi if [ "$i" -eq "${STARTUP_TIMEOUT}" ]; then echo "Container failed readiness check!" docker logs "${CONTAINER_NAME}" exit 1 fi sleep 1 done - name: Verify PHP Extensions if: env.REQUIRED_PHP_EXTENSIONS != '' run: | docker exec "${CONTAINER_NAME}" php -v docker exec -e REQUIRED_EXTS="${REQUIRED_PHP_EXTENSIONS}" "${CONTAINER_NAME}" php -r ' $required = preg_split("/\s+/", trim(getenv("REQUIRED_EXTS")), -1, PREG_SPLIT_NO_EMPTY); $missing = []; foreach ($required as $ext) { if (!extension_loaded($ext)) { $missing[] = $ext; } } if (!empty($missing)) { fwrite(STDERR, "Missing PHP extensions: " . implode(", ", $missing) . PHP_EOL); exit(1); } echo "Verified PHP extensions: " . implode(", ", $required) . PHP_EOL; ' - name: Verify Apache Modules if: env.REQUIRED_APACHE_MODULES != '' run: | MODULES=$(docker exec "${CONTAINER_NAME}" apache2ctl -M) for mod in ${REQUIRED_APACHE_MODULES}; do echo "$MODULES" | grep -q "$mod" || { echo "Missing Apache module: $mod"; exit 1; } done echo "Verified Apache modules: ${REQUIRED_APACHE_MODULES}" - name: Verify HTTP / HTTPS Response if: env.TEST_HTTP_PORT != '' || env.TEST_HTTPS_PORT != '' run: | if [ -n "${WEBROOT_DIR}" ]; then docker exec "${CONTAINER_NAME}" sh -c " mkdir -p '${WEBROOT_DIR}' && if [ ! -f '${WEBROOT_DIR}/index.php' ] && [ ! -f '${WEBROOT_DIR}/index.html' ]; then echo 'OK' > '${WEBROOT_DIR}/index.html' fi " fi if [ -n "${TEST_HTTP_PORT}" ]; then echo "Testing HTTP on port ${TEST_HTTP_PORT}..." docker exec "${CONTAINER_NAME}" curl -fsS "http://127.0.0.1:${TEST_HTTP_PORT}/" >/dev/null echo "HTTP check passed." fi if [ -n "${TEST_HTTPS_PORT}" ]; then echo "Testing HTTPS on port ${TEST_HTTPS_PORT}..." docker exec "${CONTAINER_NAME}" curl -fsSk "https://127.0.0.1:${TEST_HTTPS_PORT}/" >/dev/null echo "HTTPS check passed." fi - name: Login to Gitea Container Registry if: success() && gitea.event_name != 'pull_request' env: SECRET_TOKEN: ${{ secrets.PACKAGE_TOKEN }} VAR_TOKEN: ${{ vars.PACKAGE_TOKEN }} DEFAULT_TOKEN: ${{ gitea.token }} ACTOR_NAME: ${{ gitea.actor }} OWNER_NAME: ${{ gitea.repository_owner }} run: | # Benutzername bestimmen (REGISTRY_USER -> gitea.actor -> gitea.repository_owner) LOGIN_USER="${REGISTRY_USER:-${ACTOR_NAME:-${OWNER_NAME}}}" echo "Registry-Login Benutzer: '${LOGIN_USER}'" # Token bestimmen (Secrets -> Variables -> gitea.token) if [ -n "${SECRET_TOKEN}" ]; then echo "Token-Quelle: secrets.PACKAGE_TOKEN (Länge: ${#SECRET_TOKEN} Zeichen)" RAW_TOKEN="${SECRET_TOKEN}" elif [ -n "${VAR_TOKEN}" ]; then echo "Token-Quelle: vars.PACKAGE_TOKEN (Länge: ${#VAR_TOKEN} Zeichen)" RAW_TOKEN="${VAR_TOKEN}" else echo "WARNUNG: Weder secrets.PACKAGE_TOKEN noch vars.PACKAGE_TOKEN gefunden! Nutze gitea.token (Länge: ${#DEFAULT_TOKEN} Zeichen)" RAW_TOKEN="${DEFAULT_TOKEN}" fi # Eventuelle Leerzeichen/Zeilenumbrüche entfernen CLEAN_TOKEN=$(printf '%s' "${RAW_TOKEN}" | tr -d '\r\n ') printf '%s\n' "${CLEAN_TOKEN}" | docker login "${REGISTRY}" -u "${LOGIN_USER}" --password-stdin - name: Push Docker Image if: success() && gitea.event_name != 'pull_request' run: | docker push "${{ steps.meta.outputs.image_tag }}" - name: Cleanup if: always() run: | echo "--- Container Logs ---" docker logs "${CONTAINER_NAME}" || true docker rm -f "${CONTAINER_NAME}" || true docker logout "${REGISTRY}" 2>/dev/null || true