name: Docker Build, Test & Push on: push: branches-ignore: - main - default workflow_dispatch: # ============================================================================== # KONFIGURATION (Für andere Repositories einfach hier oben anpassen) # ============================================================================== env: # Registry & Image-Name (CUSTOM_IMAGE_NAME leer lassen = automatisch /) REGISTRY: git.dsit.me CUSTOM_IMAGE_NAME: "" # 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: PKG_TOKEN: ${{ secrets.PACKAGE_TOKEN }} FALLBACK_TOKEN: ${{ gitea.token }} run: | if [ -n "${PKG_TOKEN}" ]; then echo "Nutze hinterlegtes Secret PACKAGE_TOKEN für Registry-Login..." TOKEN="${PKG_TOKEN}" else echo "WARNUNG: Secret PACKAGE_TOKEN ist leer/nicht gesetzt! Versuche Fallback auf gitea.token..." TOKEN="${FALLBACK_TOKEN}" fi echo "${TOKEN}" | docker login "${REGISTRY}" -u "${{ gitea.actor }}" --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