name: Publish PHP Apache image on: push: workflow_dispatch: schedule: # Refresh the rolling Arch Linux base weekly. - cron: "13 3 * * 1" env: IMAGE: registry.brunner.ninja/feedc0de/php-apache GITOPS_REPOSITORY: feedc0de/homelab-gitops jobs: publish: name: Build, test and push runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Check out source and tags uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Helm uses: azure/setup-helm@v4 with: version: v4.2.2 - name: Validate Helm chart run: | set -euo pipefail helm lint helm/php-homepage helm template ci-test helm/php-homepage > /dev/null - name: Log in to Quay uses: docker/login-action@v3 with: registry: registry.brunner.ninja username: ${{ secrets.QUAY_USERNAME }} password: ${{ secrets.QUAY_TOKEN }} - name: Build image env: COMMIT_SHA: ${{ gitea.sha }} run: | set -euo pipefail docker build \ --pull \ --load \ --label "org.opencontainers.image.revision=${COMMIT_SHA}" \ --label "org.opencontainers.image.source=https://code.brunner.ninja/feedc0de/php-apache" \ --tag "${IMAGE}:${COMMIT_SHA}" \ . - name: Test Apache and PHP extensions env: COMMIT_SHA: ${{ gitea.sha }} run: | set -euo pipefail docker run --rm --entrypoint httpd "${IMAGE}:${COMMIT_SHA}" -t docker run --rm \ --env APACHE_SERVER_ADMIN=ci@example.invalid \ --entrypoint /bin/bash \ "${IMAGE}:${COMMIT_SHA}" \ -euc ' httpd php -r '\'' $status = file_get_contents("http://127.0.0.1:8080/server-status?auto"); if ($status === false || !str_contains($status, "ServerVersion:")) { fwrite(STDERR, "Apache server-status smoke test failed.\n"); exit(1); } echo "Apache server-status smoke test passed.\n"; '\'' httpd -k stop ' docker run --rm --entrypoint php "${IMAGE}:${COMMIT_SHA}" -r ' foreach (["exif", "gd", "iconv", "imagick", "intl", "Zend OPcache", "pgsql", "pdo_pgsql"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } } $info = gd_info(); foreach (["JPEG Support", "PNG Support", "WebP Support"] as $feature) { if (empty($info[$feature])) { fwrite(STDERR, "Missing GD feature: {$feature}\n"); exit(1); } } $image = imagecreatetruecolor(8, 8); $scaled = imagescale($image, 4, 4); if ($scaled === false || imagesx($scaled) !== 4 || imagesy($scaled) !== 4) { fwrite(STDERR, "GD resize smoke test failed.\n"); exit(1); } $imagick = new Imagick(); $imagick->newImage(8, 8, "white", "png"); $imagick->resizeImage(4, 4, Imagick::FILTER_LANCZOS, 1); if ($imagick->getImageWidth() !== 4 || $imagick->getImageHeight() !== 4) { fwrite(STDERR, "Imagick resize smoke test failed.\n"); exit(1); } if (iconv("UTF-8", "ASCII//TRANSLIT", "Grüße") === false) { fwrite(STDERR, "Iconv smoke test failed.\n"); exit(1); } echo "GD resize smoke test passed.\n"; echo "Imagick and Iconv smoke tests passed.\n"; ' - name: Determine version tag env: COMMIT_SHA: ${{ gitea.sha }} run: | set -euo pipefail apache_version="$( docker run --rm --entrypoint httpd "${IMAGE}:${COMMIT_SHA}" -v \ | sed -n 's#^Server version: Apache/\([0-9.]*\).*$#\1#p' )" php_version="$( docker run --rm --entrypoint php "${IMAGE}:${COMMIT_SHA}" \ -r 'echo PHP_VERSION;' )" test -n "${apache_version}" test -n "${php_version}" version_tag="${apache_version}-${php_version}" printf 'VERSION_TAG=%s\n' "${version_tag}" >> "${GITHUB_ENV}" chart_version="$(./scripts/chart-version.sh)" printf 'CHART_VERSION=%s\n' "${chart_version}" >> "${GITHUB_ENV}" - name: Push commit tag if: gitea.event_name == 'push' env: COMMIT_SHA: ${{ gitea.sha }} run: docker push "${IMAGE}:${COMMIT_SHA}" - name: Push main tags if: gitea.ref == 'refs/heads/main' || gitea.event_name == 'schedule' env: COMMIT_SHA: ${{ gitea.sha }} run: | set -euo pipefail docker tag "${IMAGE}:${COMMIT_SHA}" "${IMAGE}:${VERSION_TAG}" docker tag "${IMAGE}:${COMMIT_SHA}" "${IMAGE}:latest" docker push "${IMAGE}:${VERSION_TAG}" docker push "${IMAGE}:latest" - name: Publish Helm chart if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' env: COMMIT_SHA: ${{ gitea.sha }} PACKAGE_USERNAME: ${{ secrets.PACKAGE_USERNAME }} PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }} run: | set -euo pipefail test -n "${PACKAGE_USERNAME}" test -n "${PACKAGE_TOKEN}" install -d .chart-packages helm package helm/php-homepage \ --destination .chart-packages \ --version "${CHART_VERSION}" \ --app-version "${COMMIT_SHA}" chart_file=".chart-packages/php-homepage-${CHART_VERSION}.tgz" test -f "${chart_file}" curl --fail --silent --show-error \ --user "${PACKAGE_USERNAME}:${PACKAGE_TOKEN}" \ --request POST \ --upload-file "${chart_file}" \ https://code.brunner.ninja/api/packages/feedc0de/helm/api/charts - name: Check that this is still current main if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' env: COMMIT_SHA: ${{ gitea.sha }} run: | git fetch --no-tags origin main test "$(git rev-parse FETCH_HEAD)" = "${COMMIT_SHA}" - name: Check out GitOps repository if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' uses: actions/checkout@v4 with: repository: ${{ env.GITOPS_REPOSITORY }} ref: main token: ${{ secrets.GITOPS_TOKEN }} path: homelab-gitops - name: Promote the exact chart to every homepage application if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' working-directory: homelab-gitops run: | set -euo pipefail for application in \ brgkepler-com brunner-ninja gschissenes-equipment \ immich-crack pfostendynamics-com watschn-studio; do ./scripts/update-chart-version.sh "${application}" "${CHART_VERSION}" git add "bootstrap/${application}.yaml" done git config user.name "feedc0de" git config user.email "feedc0de@users.noreply.code.brunner.ninja" if git diff --cached --quiet; then exit 0; fi git commit -m "Deploy php-homepage chart ${CHART_VERSION}" for attempt in 1 2 3; do if git push origin HEAD:main; then exit 0 fi if [ "${attempt}" = 3 ]; then echo "GitOps promotion failed after three attempts" >&2 exit 1 fi git fetch origin main git rebase origin/main done