diff --git a/.github/action/build-bake-publish/action.yml b/.github/action/build-bake-publish/action.yml index c619e89..c21a185 100644 --- a/.github/action/build-bake-publish/action.yml +++ b/.github/action/build-bake-publish/action.yml @@ -1,10 +1,12 @@ name: 'Build and Publish' -description: 'Builds Image and pushes' +description: 'Builds and publishes one PHP minor image family using Namespace' inputs: - targets: - description: 'Targets' + php-version: + description: 'PHP minor version to build' + required: true + family: + description: 'Image family: fpm or frankenphp' required: true - default: '' docker_hub_username: description: 'Docker Hub username' required: true @@ -17,28 +19,94 @@ inputs: runs: using: "composite" steps: + - name: Validate image family + shell: bash + env: + FAMILY: ${{ inputs.family }} + run: | + case "$FAMILY" in + fpm|frankenphp) ;; + *) echo "Unsupported image family: $FAMILY" >&2; exit 1 ;; + esac + - name: Install and configure Namespace CLI - uses: namespacelabs/nscloud-setup@v0 + uses: namespacelabs/nscloud-setup@v0.0.12 - name: Configure Namespace powered Buildx - uses: namespacelabs/nscloud-setup-buildx-action@v0 + uses: namespacelabs/nscloud-setup-buildx-action@v0.0.23 - name: Login into Docker Hub shell: bash - run: echo "${{ inputs.docker_hub_password }}" | docker login -u ${{ inputs.docker_hub_username }} --password-stdin + env: + DOCKER_HUB_USERNAME: ${{ inputs.docker_hub_username }} + DOCKER_HUB_PASSWORD: ${{ inputs.docker_hub_password }} + run: printf '%s' "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_USERNAME" --password-stdin - name: Login into Github Docker Registry shell: bash - run: echo "${{ inputs.github_token }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + env: + GH_TOKEN: ${{ inputs.github_token }} + run: printf '%s' "$GH_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin + + - name: Build and push base images + uses: docker/bake-action@v7.5.0 + with: + push: true + files: | + docker-bake.hcl + docker-bake.${{ inputs.family }}.hcl + targets: ${{ inputs.family }} + env: + DOCKER_BUILD_RECORD_UPLOAD: false + DOCKER_BUILD_SUMMARY: false + phpMinor: ${{ inputs.php-version }} + imageSuffix: ${{ github.event_name == 'pull_request' && '-ci-test' || '' }} + tagPrefix: ${{ github.event_name == 'pull_request' && format('{0}-', github.event.number) || '' }} + + # Derived targets reuse internal build stages, excluding the final OS upgrade. + - name: Build and push OpenTelemetry and webserver images + uses: docker/bake-action@v7.5.0 + with: + push: true + files: | + docker-bake.hcl + docker-bake.${{ inputs.family }}.hcl + targets: ${{ inputs.family == 'fpm' && 'fpm-otel,caddy,nginx' || 'frankenphp-otel' }} + env: + DOCKER_BUILD_RECORD_UPLOAD: false + DOCKER_BUILD_SUMMARY: false + phpMinor: ${{ inputs.php-version }} + imageSuffix: ${{ github.event_name == 'pull_request' && '-ci-test' || '' }} + tagPrefix: ${{ github.event_name == 'pull_request' && format('{0}-', github.event.number) || '' }} + + - name: Build and push OpenTelemetry webserver images + if: inputs.family == 'fpm' + uses: docker/bake-action@v7.5.0 + with: + push: true + files: | + docker-bake.hcl + docker-bake.fpm.hcl + targets: caddy-otel,nginx-otel + env: + DOCKER_BUILD_RECORD_UPLOAD: false + DOCKER_BUILD_SUMMARY: false + phpMinor: ${{ inputs.php-version }} + imageSuffix: ${{ github.event_name == 'pull_request' && '-ci-test' || '' }} + tagPrefix: ${{ github.event_name == 'pull_request' && format('{0}-', github.event.number) || '' }} - - name: Build and push - uses: docker/bake-action@v6 + - name: Build and push dev images + if: inputs.family == 'fpm' + uses: docker/bake-action@v7.5.0 with: push: true - targets: ${{ inputs.targets }} - no-cache: true + files: | + docker-bake.hcl + docker-bake.fpm.hcl + targets: caddy-dev,nginx-dev env: DOCKER_BUILD_RECORD_UPLOAD: false DOCKER_BUILD_SUMMARY: false + phpMinor: ${{ inputs.php-version }} imageSuffix: ${{ github.event_name == 'pull_request' && '-ci-test' || '' }} tagPrefix: ${{ github.event_name == 'pull_request' && format('{0}-', github.event.number) || '' }} diff --git a/.github/action/test-webserver/action.yml b/.github/action/test-webserver/action.yml new file mode 100644 index 0000000..2191413 --- /dev/null +++ b/.github/action/test-webserver/action.yml @@ -0,0 +1,53 @@ +name: Test webserver image +description: Run the example Shopware application against a published image +inputs: + php-version: + description: PHP minor version to test + required: true + webserver: + description: Webserver to test + required: true +runs: + using: composite + steps: + # Application containers run on this runner, not the remote Namespace builder. + - name: Set up local Docker Buildx + uses: docker/setup-buildx-action@v4.4.1 + + - name: Checkout example repository + uses: actions/checkout@v7.0.1 + with: + repository: shopwareLabs/example-docker-repository + path: .smoke-test + + - name: Build and test application + shell: bash + working-directory: .smoke-test + env: + BASE_IMAGE: ghcr.io/shopware/docker-base${{ github.event_name == 'pull_request' && '-ci-test' || '' }}:${{ github.event_name == 'pull_request' && format('{0}-', github.event.number) || '' }}${{ inputs.php-version }}-${{ inputs.webserver }} + run: | + # Always collect logs and remove test containers/volumes before the next server. + cleanup() { + set +e + docker compose -p image-smoke-test logs + docker compose -p image-smoke-test down --volumes + } + trap cleanup EXIT + + docker compose -p image-smoke-test build --build-arg BASE_IMAGE="$BASE_IMAGE" + docker compose -p image-smoke-test up -d --wait + + attempt_counter=0 + max_attempts=5 + until curl --output /dev/null --silent --head --fail localhost:8000/admin; do + if [ "$attempt_counter" -eq "$max_attempts" ]; then + echo "Max attempts reached" + exit 1 + fi + printf '.' + attempt_counter=$((attempt_counter+1)) + sleep 5 + done + + curl --fail localhost:8000/admin + curl --fail localhost:8000 diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock new file mode 100644 index 0000000..3063f29 --- /dev/null +++ b/.github/workflows/actions.lock @@ -0,0 +1,108 @@ +# This file is machine-generated by `gh actions-lock`. +# Do not edit by hand; run `gh actions-lock` to update. +# Docs: https://gh.io/actions-lockfile +version: 'v0.0.3' +workflows: + '.github/workflows/build-fpm.yml': + - 'actions/checkout@v7.0.1' + - 'docker/bake-action@v7.5.0' + - 'docker/setup-buildx-action@v4.4.1' + - 'jaxxstorm/action-install-gh-release@v3.0.0' + - 'namespacelabs/nscloud-setup-buildx-action@v0.0.23' + - 'namespacelabs/nscloud-setup@v0.0.12' + '.github/workflows/build-frankenphp.yml': + - 'actions/checkout@v7.0.1' + - 'docker/bake-action@v7.5.0' + - 'docker/setup-buildx-action@v4.4.1' + - 'namespacelabs/nscloud-setup-buildx-action@v0.0.23' + - 'namespacelabs/nscloud-setup@v0.0.12' + '.github/workflows/cleanup.yml': + - 'dataaxiom/ghcr-cleanup-action@v1.2.2' + '.github/workflows/hub.yml': + - 'actions/checkout@v7.0.1' + - 'peter-evans/dockerhub-description@v5.0.0' + '.github/workflows/lint.yml': + - 'actions/checkout@v7.0.1' + - 'hadolint/hadolint-action@v3.5.0' + '.github/workflows/security.yml': + - 'actions/checkout@v7.0.1' + - 'crazy-max/ghaction-container-scan@v4.1.0' + - 'github/codeql-action@v4.39.1' + '.github/workflows/shell-lint.yml': + - 'actions/checkout@v7.0.1' + - 'ludeeus/action-shellcheck@2.0.0' + '.github/workflows/update-php-matrix.yml': + - 'actions/checkout@v7.0.1' + - 'octo-sts/action@v1.1.1' + - 'peter-evans/create-pull-request@v8.1.1' +dependencies: + 'actions/checkout@v7.0.1': + ref: 'v7.0.1' + commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1' + owner_id: 44036562 + repo_id: 197814629 + 'crazy-max/ghaction-container-scan@v4.1.0': + ref: 'v4.1.0' + commit: 'sha1-ffcba8deb5cb3531954cbedbbcd0179d79edf510' + owner_id: 1951866 + repo_id: 414171338 + 'dataaxiom/ghcr-cleanup-action@v1.2.2': + ref: 'v1.2.2' + commit: 'sha1-d52806a0dc70b430571a37da1fde39733ffd640f' + owner_id: 131044173 + repo_id: 799711900 + 'docker/bake-action@v7.5.0': + ref: 'v7.5.0' + commit: 'sha1-59cb1203cd42bcefd40a1b6d73b589e48c86040e' + owner_id: 5429470 + repo_id: 301684204 + 'docker/setup-buildx-action@v4.4.1': + ref: 'v4.4.1' + commit: 'sha1-f87e5991a6d7451dcb8d9637bfbc97413f497069' + owner_id: 5429470 + repo_id: 288485773 + 'github/codeql-action@v4.39.1': + ref: 'v4.39.1' + commit: 'sha1-9b3254085494b55a0f7c4c2b3d2d52cc712ce370' + owner_id: 9919 + repo_id: 259445878 + 'hadolint/hadolint-action@v3.5.0': + ref: 'v3.5.0' + commit: 'sha1-06be81baf89a55ffd0e24b8f04a4185738dd3387' + owner_id: 34047791 + repo_id: 212438777 + 'jaxxstorm/action-install-gh-release@v3.0.0': + ref: 'v3.0.0' + commit: 'sha1-25e24d2d23ae098373794ef1d6faecb48ee52da8' + owner_id: 1622940 + repo_id: 265029375 + 'ludeeus/action-shellcheck@2.0.0': + ref: '2.0.0' + commit: 'sha1-00cae500b08a931fb5698e11e79bfbd38e612a38' + owner_id: 15093472 + repo_id: 174679242 + 'namespacelabs/nscloud-setup-buildx-action@v0.0.23': + ref: 'v0.0.23' + commit: 'sha1-d059ed7184f0bc7c8b27e8810cea153d02bcc6dd' + owner_id: 90391633 + repo_id: 613929575 + 'namespacelabs/nscloud-setup@v0.0.12': + ref: 'v0.0.12' + commit: 'sha1-df198f982fcecfb8264bea3f1274b56a61b6dfdc' + owner_id: 90391633 + repo_id: 610758328 + 'octo-sts/action@v1.1.1': + ref: 'v1.1.1' + commit: 'sha1-f603d3be9d8dd9871a265776e625a27b00effe05' + owner_id: 160145231 + repo_id: 749429568 + 'peter-evans/create-pull-request@v8.1.1': + ref: 'v8.1.1' + commit: 'sha1-5f6978faf089d4d20b00c7766989d076bb2fc7f1' + owner_id: 18365890 + repo_id: 197176365 + 'peter-evans/dockerhub-description@v5.0.0': + ref: 'v5.0.0' + commit: 'sha1-1b9a80c056b620d92cedb9d9b5a223409c68ddfa' + owner_id: 18365890 + repo_id: 193685475 diff --git a/.github/workflows/build-fpm.yml b/.github/workflows/build-fpm.yml new file mode 100644 index 0000000..5500bba --- /dev/null +++ b/.github/workflows/build-fpm.yml @@ -0,0 +1,111 @@ +name: Build FPM Images +on: + workflow_dispatch: + push: + branches: + - main + paths: + - 'docker-bake.hcl' + - 'docker-bake.fpm.hcl' + - '.github/workflows/build-fpm.yml' + - '.github/action/test-webserver/**' + - '.github/action/build-bake-publish/**' + - 'fpm/**' + - 'fpm-otel/**' + - 'caddy/**' + - 'nginx/**' + - 'dev/**' + pull_request: + paths: + - 'docker-bake.hcl' + - 'docker-bake.fpm.hcl' + - '.github/workflows/build-fpm.yml' + - '.github/action/test-webserver/**' + - '.github/action/build-bake-publish/**' + - 'fpm/**' + - 'fpm-otel/**' + - 'caddy/**' + - 'nginx/**' + - 'dev/**' + schedule: + - cron: '10 4 * * *' + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +permissions: + contents: read + id-token: write + packages: write + +jobs: + prepare: + name: PHP versions + runs-on: ubuntu-26.04 + outputs: + versions: ${{ steps.php-versions.outputs.versions }} + steps: + - name: Checkout + uses: actions/checkout@v7.0.1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4.4.1 + + - name: Read PHP versions from Bake + id: php-versions + run: | + versions=$(docker buildx bake -f docker-bake.hcl -f docker-bake.fpm.hcl --print fpm | jq -c '.group["fpm"].targets | map(ltrimstr("fpm-") | gsub("-"; "."))') + echo "versions=$versions" >> "$GITHUB_OUTPUT" + + build: + name: PHP ${{ matrix.php-version }} + needs: [prepare] + runs-on: ubuntu-26.04 + strategy: + fail-fast: false + matrix: + php-version: ${{ fromJSON(needs.prepare.outputs.versions) }} + steps: + - name: Checkout + uses: actions/checkout@v7.0.1 + + - name: Build and publish FPM images + uses: $/.github/action/build-bake-publish + with: + php-version: ${{ matrix.php-version }} + family: fpm + docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} + docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Test Caddy image + if: matrix.php-version == '8.3' + uses: $/.github/action/test-webserver + with: + php-version: ${{ matrix.php-version }} + webserver: caddy + + - name: Test Nginx image + if: matrix.php-version == '8.3' + uses: $/.github/action/test-webserver + with: + php-version: ${{ matrix.php-version }} + webserver: nginx + + - name: Install container structure test + if: matrix.php-version == '8.4' + uses: jaxxstorm/action-install-gh-release@v3.0.0 + with: + repo: GoogleContainerTools/container-structure-test + extension-matching: disable + rename-to: container-structure-test + chmod: 0755 + + - name: Test dev image + if: matrix.php-version == '8.4' + env: + IMAGE_TAG: ghcr.io/shopware/docker-dev${{ github.event_name == 'pull_request' && '-ci-test' || '' }}:${{ github.event_name == 'pull_request' && format('{0}-', github.event.number) || '' }}php${{ matrix.php-version }}-node24-caddy + run: | + docker pull "$IMAGE_TAG" + container-structure-test test --config dev/config.yaml --image "$IMAGE_TAG" diff --git a/.github/workflows/build-frankenphp.yml b/.github/workflows/build-frankenphp.yml new file mode 100644 index 0000000..e9eb52e --- /dev/null +++ b/.github/workflows/build-frankenphp.yml @@ -0,0 +1,72 @@ +name: Build FrankenPHP Images +on: + workflow_dispatch: + push: + branches: + - main + paths: + - 'docker-bake.hcl' + - 'docker-bake.frankenphp.hcl' + - '.github/workflows/build-frankenphp.yml' + - '.github/action/build-bake-publish/**' + - 'frankenphp/**' + - 'frankenphp-otel/**' + pull_request: + paths: + - 'docker-bake.hcl' + - 'docker-bake.frankenphp.hcl' + - '.github/workflows/build-frankenphp.yml' + - '.github/action/build-bake-publish/**' + - 'frankenphp/**' + - 'frankenphp-otel/**' + schedule: + - cron: '10 4 * * *' + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +permissions: + contents: read + id-token: write + packages: write + +jobs: + prepare: + name: PHP versions + runs-on: ubuntu-26.04 + outputs: + versions: ${{ steps.php-versions.outputs.versions }} + steps: + - name: Checkout + uses: actions/checkout@v7.0.1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4.4.1 + + - name: Read PHP versions from Bake + id: php-versions + run: | + versions=$(docker buildx bake -f docker-bake.hcl -f docker-bake.frankenphp.hcl --print frankenphp | jq -c '.group["frankenphp"].targets | map(ltrimstr("frankenphp-") | gsub("-"; "."))') + echo "versions=$versions" >> "$GITHUB_OUTPUT" + + build: + name: PHP ${{ matrix.php-version }} + needs: [prepare] + runs-on: ubuntu-26.04 + strategy: + fail-fast: false + matrix: + php-version: ${{ fromJSON(needs.prepare.outputs.versions) }} + steps: + - name: Checkout + uses: actions/checkout@v7.0.1 + + - name: Build and publish FrankenPHP images + uses: $/.github/action/build-bake-publish + with: + php-version: ${{ matrix.php-version }} + family: frankenphp + docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} + docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 325d2ab..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,337 +0,0 @@ -name: Build Base Images -on: - workflow_dispatch: - push: - branches: - - main - pull_request: - schedule: - - cron: '10 4 * * *' - -concurrency: - group: "${{ github.ref }}" - cancel-in-progress: true - -env: - DOCKER_BUILDKIT: 1 - COSIGN_EXPERIMENTAL: 1 - -permissions: - contents: write - id-token: write - packages: write - pull-requests: write - -jobs: - frankenphp: - name: FrankenPHP - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - frankenphp*/** - - - name: Build - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/action/build-bake-publish - with: - targets: frankenphp - docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} - docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - github_token: ${{ secrets.GITHUB_TOKEN }} - - frankenphp-otel: - name: FrankenPHP with OpenTelemetry - runs-on: namespace-profile-default - needs: [frankenphp] - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - frankenphp*/** - - - name: Build - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/action/build-bake-publish - with: - targets: frankenphp-otel - docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} - docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - github_token: ${{ secrets.GITHUB_TOKEN }} - - fpm: - name: FPM - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - fpm*/** - nginx/** - caddy/** - dev/** - - - name: Build - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/action/build-bake-publish - with: - targets: fpm - docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} - docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - github_token: ${{ secrets.GITHUB_TOKEN }} - - fpm-otel: - name: FPM with OpenTelemetry - runs-on: ubuntu-latest - needs: [fpm] - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - fpm*/** - nginx/** - caddy/** - dev/** - - - name: Build - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/action/build-bake-publish - with: - targets: fpm-otel - docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} - docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - github_token: ${{ secrets.GITHUB_TOKEN }} - - webserver: - name: ${{ matrix.webserver }} - runs-on: ubuntu-latest - needs: [fpm] - strategy: - fail-fast: false - matrix: - webserver: [ caddy, nginx ] - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - fpm/** - ${{ matrix.webserver }}/** - dev/** - - - name: Build - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/action/build-bake-publish - with: - targets: ${{ matrix.webserver}} - docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} - docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - github_token: ${{ secrets.GITHUB_TOKEN }} - - webserver-otel: - name: ${{ matrix.webserver }} with OpenTelemetry - runs-on: ubuntu-latest - needs: [fpm-otel] - strategy: - fail-fast: false - matrix: - webserver: [ caddy, nginx ] - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - fpm/** - ${{ matrix.webserver }}/** - dev/** - - - name: Build - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/action/build-bake-publish - with: - targets: ${{ matrix.webserver}}-otel - docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} - docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - github_token: ${{ secrets.GITHUB_TOKEN }} - - dev: - name: Dev ${{ matrix.webserver }} - runs-on: ubuntu-latest - needs: [webserver-otel] - strategy: - fail-fast: false - matrix: - webserver: [ caddy, nginx ] - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - fpm/** - ${{ matrix.webserver }}/** - dev/** - - - name: Build - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/action/build-bake-publish - with: - targets: ${{ matrix.webserver }}-dev - docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} - docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - github_token: ${{ secrets.GITHUB_TOKEN }} - - dev-check: - name: Check Dev Image - runs-on: ubuntu-latest - needs: [dev] - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - docker-bake.hcl - fpm/** - nginx/** - caddy/** - dev/** - - - name: Install a binary from GitHub releases - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: jaxxstorm/action-install-gh-release@v3.0.0 - with: - repo: GoogleContainerTools/container-structure-test - extension-matching: disable - rename-to: container-structure-test - chmod: 0755 - - - name: Determine image tag - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - id: image-tag - run: | - if [[ "${{ github.event_name }}" == "pull_request" ]]; then - echo "IMAGE_TAG=ghcr.io/shopware/docker-dev-ci-test:${{ github.event.number }}-php8.4-node24-caddy" >> $GITHUB_OUTPUT - else - echo "IMAGE_TAG=ghcr.io/shopware/docker-dev:php8.4-node24-caddy" >> $GITHUB_OUTPUT - fi - - - name: Pull image - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - run: docker pull ${{ steps.image-tag.outputs.IMAGE_TAG }} - - - name: Test Dev Image - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - run: container-structure-test test --config dev/config.yaml --image ${{ steps.image-tag.outputs.IMAGE_TAG }} - - check: - name: Test Image with Webserver ${{ matrix.webserver }} - runs-on: ubuntu-latest - needs: [webserver] - strategy: - matrix: - webserver: - - caddy - - nginx - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Checkout - uses: actions/checkout@v7 - - - name: Get all changed files - id: changed-files - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v46 - with: - files: | - ${{ matrix.webserver }}/** - - - name: Checkout example repo - uses: actions/checkout@v7 - with: - repository: shopwareLabs/example-docker-repository - - - name: Build main branch - if: github.ref == 'refs/heads/main' && (steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main') - run: docker compose build --build-arg BASE_IMAGE=ghcr.io/shopware/docker-base:8.3-caddy - - - name: Build PR - if: github.ref != 'refs/heads/main' && (steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main') - run: docker compose build --build-arg BASE_IMAGE=ghcr.io/shopware/docker-base-ci-test:${{ github.event.number }}-8.3-${{ matrix.webserver}} - - - name: Run image - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - run: docker compose up -d --wait - - - name: Wait for Webserver reachable - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - run: | - attempt_counter=0 - max_attempts=5 - - until $(curl --output /dev/null --silent --head --fail localhost:8000/admin); do - if [ ${attempt_counter} -eq ${max_attempts} ];then - echo "Max attempts reached" - exit 1 - fi - - printf '.' - attempt_counter=$(($attempt_counter+1)) - sleep 5 - done - - - name: Check if shopware admin is running - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - run: curl --fail localhost:8000/admin - - - name: Check if shopware is running - if: steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main' - run: curl --fail localhost:8000 - - # output logs if failed - - name: Output logs - if: always() && (steps.changed-files.outputs.any_changed == 'true' || github.event_name == 'schedule' || github.event_name == 'push' && github.ref == 'refs/heads/main') - run: docker compose logs diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml index 7d809fe..c060452 100644 --- a/.github/workflows/cleanup.yml +++ b/.github/workflows/cleanup.yml @@ -9,10 +9,10 @@ permissions: jobs: cleanup: name: Cleanup GHCR - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 steps: - name: Cleanup GHCR - uses: dataaxiom/ghcr-cleanup-action@d52806a0dc70b430571a37da1fde39733ffd640f # ratchet:dataaxiom/ghcr-cleanup-action@v1 + uses: dataaxiom/ghcr-cleanup-action@v1.2.2 with: packages: docker-base-ci-test,docker-dev-ci-test,demo-ci-test older-than: 1 day diff --git a/.github/workflows/hub.yml b/.github/workflows/hub.yml index ec7e2d0..c95fe3b 100644 --- a/.github/workflows/hub.yml +++ b/.github/workflows/hub.yml @@ -9,13 +9,13 @@ on: jobs: sync: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 - name: Docker Hub Description - uses: peter-evans/dockerhub-description@v5 + uses: peter-evans/dockerhub-description@v5.0.0 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_PASSWORD }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f3ccf0c..533ec7b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -11,19 +11,19 @@ on: jobs: lint: name: Lint Dockerfiles - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 - name: Lint FPM - uses: hadolint/hadolint-action@master + uses: hadolint/hadolint-action@v3.5.0 with: dockerfile: ./fpm/Dockerfile ignore: DL3018 - name: Lint Caddy - uses: hadolint/hadolint-action@master + uses: hadolint/hadolint-action@v3.5.0 with: dockerfile: ./caddy/Dockerfile ignore: DL3018 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 0f0c596..2b5ebc9 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -11,7 +11,7 @@ permissions: jobs: scan: name: 'Image Scan (PHP: ${{ matrix.php-version }}, Variant: ${{ matrix.variant.name }})' - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 strategy: fail-fast: false matrix: @@ -39,7 +39,7 @@ jobs: dockerfile: frankenphp-otel/Dockerfile steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 - name: Pull image run: docker pull shopware/docker-base:${{ matrix.php-version }}-${{ matrix.variant.name }} @@ -49,14 +49,14 @@ jobs: - name: Scan for vulnerabilities id: scan - uses: crazy-max/ghaction-container-scan@v4 + uses: crazy-max/ghaction-container-scan@v4.1.0 with: image: shopware/docker-base:${{ matrix.php-version }}-${{ matrix.variant.name }} dockerfile: ./${{ matrix.variant.dockerfile }} - name: Upload SARIF file if: ${{ steps.scan.outputs.sarif != '' }} - uses: github/codeql-action/upload-sarif@v4.39.0 + uses: github/codeql-action/upload-sarif@v4.39.1 with: sarif_file: ${{ steps.scan.outputs.sarif }} category: ${{ matrix.php-version }}-${{ matrix.variant.name }} diff --git a/.github/workflows/shell-lint.yml b/.github/workflows/shell-lint.yml index c720163..955bb61 100644 --- a/.github/workflows/shell-lint.yml +++ b/.github/workflows/shell-lint.yml @@ -10,10 +10,10 @@ permissions: jobs: lint: name: Shell Lint - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 - name: Run ShellCheck - uses: ludeeus/action-shellcheck@master + uses: ludeeus/action-shellcheck@2.0.0 diff --git a/.github/workflows/update-php-matrix.yml b/.github/workflows/update-php-matrix.yml index 031a677..d96bc5f 100644 --- a/.github/workflows/update-php-matrix.yml +++ b/.github/workflows/update-php-matrix.yml @@ -12,7 +12,7 @@ permissions: jobs: update-php-matrix: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 steps: - name: Generate GitHub token via octo-sts id: generate-token @@ -22,7 +22,7 @@ jobs: identity: update-php-matrix - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 with: token: ${{ steps.generate-token.outputs.token }} @@ -33,17 +33,17 @@ jobs: id: changes run: | if git diff --quiet; then - echo "changed=false" >> $GITHUB_OUTPUT + echo "changed=false" >> "$GITHUB_OUTPUT" echo "No changes detected" else - echo "changed=true" >> $GITHUB_OUTPUT + echo "changed=true" >> "$GITHUB_OUTPUT" echo "Changes detected" git diff fi - name: Create Pull Request if: steps.changes.outputs.changed == 'true' - uses: peter-evans/create-pull-request@v8 + uses: peter-evans/create-pull-request@v8.1.1 with: token: ${{ steps.generate-token.outputs.token }} commit-message: 'chore: update PHP matrix to latest patch versions' @@ -51,9 +51,10 @@ jobs: body: | This PR automatically updates the PHP matrix versions to the latest patch releases. - The following matrices have been updated: - - `phpMatrix`: All supported PHP versions including 8.1 - - `frankenphpMatrix`: All supported PHP versions excluding 8.1 + The shared and family-specific Bake files have been updated: + - `docker-bake.hcl`: Pinned docker-library/php commit + - `docker-bake.fpm.hcl`: Supported PHP patch versions and Alpine version + - `docker-bake.frankenphp.hcl`: Supported PHP patch versions Changes were detected by the automated PHP matrix update workflow. diff --git a/README.md b/README.md index 09ff9a7..0cd3ca6 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,69 @@ This repository contains a base image with Alpine + PHP + (Caddy or Nginx), whic [Documentation can be found here](https://developer.shopware.com/docs/guides/hosting/installation-updates/docker.html) The Nginx, Caddy and FrankenPHP configurations send `script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'` for static SVG files and existing HTML files under `public/media` and `public/thumbnail`. Application-rendered HTML and bundled HTML applications retain their own response policies. Custom static documents must work without scripts, embedded documents, base URL overrides or form submissions; images and styles remain permitted. Development images inherit the corresponding server configuration. + +## Building images + +Bake settings are split into shared variables in `docker-bake.hcl` and targets +in `docker-bake.fpm.hcl` and `docker-bake.frankenphp.hcl`. Load the shared file +alongside the family you want to build: + +```sh +docker buildx bake -f docker-bake.hcl -f docker-bake.fpm.hcl fpm +docker buildx bake -f docker-bake.hcl -f docker-bake.frankenphp.hcl frankenphp +``` + +FPM targets include `fpm`, `fpm-otel`, `caddy`, `caddy-otel`, `nginx`, +`nginx-otel`, `caddy-dev` and `nginx-dev`. FrankenPHP targets are `frankenphp` +and `frankenphp-otel`. Add `--print` to inspect the build configuration. + +Derived images use internal Bake targets that select the Dockerfiles' `build` +stages. Bake builds these dependencies automatically; publishing base images first +is not required. Internal `*-build` targets are not published. + +Every published image ends with a `runtime` stage that upgrades installed OS +packages using `apk upgrade` or `apt-get upgrade --with-new-pkgs`. Bake passes the +current UTC date as `OS_PACKAGES_REFRESH`, refreshing this layer once per day while +reusing the PHP, gRPC and other extension compilation layers. Derived images use +the stages before this upgrade, so a daily refresh does not invalidate their +compilation cache either. Changes to other build inputs can still rebuild these +layers. + +To force another package refresh on the same day, override `osPackagesRefresh`: + +```sh +osPackagesRefresh="$(date -u +%Y-%m-%d)-2" phpMinor=8.4 \ + docker buildx bake -f docker-bake.hcl -f docker-bake.fpm.hcl fpm +``` + +When invoking `docker buildx build` directly, pass +`--build-arg OS_PACKAGES_REFRESH="$(date -u +%Y-%m-%d)"` explicitly. OS upgrades +add replacement files over the cached layers, increasing image size. They do not +update source-built PHP/extensions or libraries statically linked into them; +those still require rebuilding their compilation stages. Compiled extensions must +remain compatible with upgraded runtime libraries. + +The FPM and FrankenPHP workflows build independently when their files change. +Changes to shared Bake settings or the publishing action trigger both families. +Both workflows also support manual runs and daily rebuilds. + +Each workflow derives its PHP minor-version matrix from Bake and runs an independent +build chain per minor version. Failures in one PHP version do not block the others. +Both CPU architectures remain in each build. The existing application smoke tests +run on PHP 8.3, and the dev image check runs on PHP 8.4. + +To build only one PHP minor version locally: + +```sh +phpMinor=8.4 docker buildx bake -f docker-bake.hcl -f docker-bake.fpm.hcl fpm +phpMinor=8.4 docker buildx bake -f docker-bake.hcl -f docker-bake.frankenphp.hcl frankenphp +``` + +CI uses the shared `.github/action/build-bake-publish` composite action, rather than +reusable workflows. Each PHP minor runs in a single job, setting up Namespace's +remote builder once with layer caching enabled. Sequential Bake steps publish each +image group, reusing internal build stages across steps. Both CPU +architectures and dev Node variants stay together in Bake. Tags and registry +destinations come directly from the Bake files. The FPM job also runs the existing +checks for the applicable PHP minor, sharing application smoke-test steps through +`.github/action/test-webserver`. diff --git a/caddy/Dockerfile b/caddy/Dockerfile index 9cdb48e..43061c5 100644 --- a/caddy/Dockerfile +++ b/caddy/Dockerfile @@ -1,6 +1,6 @@ -#syntax=docker/dockerfile:1.4 +#syntax=docker/dockerfile:1 -FROM base +FROM base AS build USER root @@ -16,3 +16,13 @@ WORKDIR /var/www/html ENV FPM_LISTEN=/tmp/php-fpm.sock ENTRYPOINT [ "/usr/bin/supervisord", "-c", "/etc/supervisord.conf" ] + +# Derived images use the build stage so this refresh cannot invalidate compilation. +FROM build AS runtime + +USER root +ARG OS_PACKAGES_REFRESH +RUN echo "Refreshing OS packages: ${OS_PACKAGES_REFRESH}" \ + && apk upgrade --no-cache + +USER www-data diff --git a/dev/Dockerfile b/dev/Dockerfile index 8806e07..28fe718 100644 --- a/dev/Dockerfile +++ b/dev/Dockerfile @@ -2,7 +2,7 @@ ARG NODE_VERSION=22 FROM node:${NODE_VERSION}-alpine AS node -FROM base +FROM base AS build ARG NODE_VERSION @@ -68,3 +68,13 @@ ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 \ ENTRYPOINT [ "/entrypoint" ] CMD [ "/usr/bin/supervisord", "-c", "/etc/supervisord.conf" ] + +# Derived images use the build stage so this refresh cannot invalidate compilation. +FROM build AS runtime + +USER root +ARG OS_PACKAGES_REFRESH +RUN echo "Refreshing OS packages: ${OS_PACKAGES_REFRESH}" \ + && apk upgrade --no-cache + +USER www-data diff --git a/docker-bake.fpm.hcl b/docker-bake.fpm.hcl new file mode 100644 index 0000000..f9cdf88 --- /dev/null +++ b/docker-bake.fpm.hcl @@ -0,0 +1,258 @@ +variable "phpMatrix" { + default = [ "8.2.35", "8.3.36", "8.4.27", "8.5.12" ] +} + +variable "alpineVersion" { + default = "3.24" +} + +# PHP built from source with the upstream docker-library/php Dockerfiles + +target "php-fpm-alpine" { + name = "php-fpm-alpine-${replace(substr(php, 0, 3), ".", "-")}" + context = "https://github.com/docker-library/php.git#${phpLibraryRef}:${substr(php, 0, 3)}/alpine${alpineVersion}/fpm" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + platforms = [ "linux/amd64", "linux/arm64" ] +} + +# FPM + +target "fpm" { + inherits = [ "_package-refresh" ] + name = "fpm-${replace(substr(php, 0, 3), ".", "-")}" + context = "./fpm" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:php-fpm-alpine-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm" + ] +} + +target "fpm-otel" { + inherits = [ "_package-refresh" ] + name = "fpm-otel-${replace(substr(php, 0, 3), ".", "-")}" + context = "./fpm-otel" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:fpm-build-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm-otel", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel" + ] +} + +# Caddy + +target "caddy" { + inherits = [ "_package-refresh" ] + name = "caddy-${replace(substr(php, 0, 3), ".", "-")}" + context = "./caddy" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:fpm-build-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy" + ] +} + +target "caddy-otel" { + inherits = [ "_package-refresh" ] + name = "caddy-otel-${replace(substr(php, 0, 3), ".", "-")}" + context = "./caddy" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:fpm-otel-build-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy-otel" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy-otel", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy-otel", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy-otel" + ] +} + +target "caddy-dev" { + inherits = [ "_package-refresh" ] + name = "caddy-dev-${replace(substr(php, 0, 3), ".", "-")}-${node}" + context = "./dev" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + "node" = [ "22", "24" ] + } + contexts = { + base = "target:caddy-otel-build-${replace(substr(php, 0, 3), ".", "-")}" + } + args = { + "NODE_VERSION" = node + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = [ + "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${substr(php, 0, 3)}-node${node}-caddy", + "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${php}-node${node}-caddy" + ] +} + +# Nginx + +target "nginx" { + inherits = [ "_package-refresh" ] + name = "nginx-${replace(substr(php, 0, 3), ".", "-")}" + context = "./nginx" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:fpm-build-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx" + ] +} + +target "nginx-otel" { + inherits = [ "_package-refresh" ] + name = "nginx-otel-${replace(substr(php, 0, 3), ".", "-")}" + context = "./nginx" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:fpm-otel-build-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx-otel" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx-otel", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx-otel", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx-otel" + ] +} + +target "nginx-dev" { + inherits = [ "_package-refresh" ] + name = "nginx-dev-${replace(substr(php, 0, 3), ".", "-")}-${node}" + context = "./dev" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + "node" = [ "22", "24" ] + } + contexts = { + base = "target:nginx-otel-build-${replace(substr(php, 0, 3), ".", "-")}" + } + args = { + "NODE_VERSION" = node + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = [ + "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${substr(php, 0, 3)}-node${node}-nginx", + "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${php}-node${node}-nginx" + ] +} + +# Internal stages exclude the daily upgrade and are never published. + +target "fpm-build" { + name = "fpm-build-${replace(substr(php, 0, 3), ".", "-")}" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + inherits = [ "fpm-${replace(substr(php, 0, 3), ".", "-")}" ] + target = "build" + tags = [] + args = { + OS_PACKAGES_REFRESH = "" + } +} + +target "fpm-otel-build" { + name = "fpm-otel-build-${replace(substr(php, 0, 3), ".", "-")}" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + inherits = [ "fpm-otel-${replace(substr(php, 0, 3), ".", "-")}" ] + target = "build" + tags = [] + args = { + OS_PACKAGES_REFRESH = "" + } +} + +target "caddy-otel-build" { + name = "caddy-otel-build-${replace(substr(php, 0, 3), ".", "-")}" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + inherits = [ "caddy-otel-${replace(substr(php, 0, 3), ".", "-")}" ] + target = "build" + tags = [] + args = { + OS_PACKAGES_REFRESH = "" + } +} + +target "nginx-otel-build" { + name = "nginx-otel-build-${replace(substr(php, 0, 3), ".", "-")}" + matrix = { + "php" = [for php in phpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + inherits = [ "nginx-otel-${replace(substr(php, 0, 3), ".", "-")}" ] + target = "build" + tags = [] + args = { + OS_PACKAGES_REFRESH = "" + } +} diff --git a/docker-bake.frankenphp.hcl b/docker-bake.frankenphp.hcl new file mode 100644 index 0000000..3dcfdf3 --- /dev/null +++ b/docker-bake.frankenphp.hcl @@ -0,0 +1,102 @@ +variable "frankenphpMatrix" { + default = [ "8.2.35", "8.3.36", "8.4.27", "8.5.12" ] +} + +variable "frankenphpRef" { + default = "v1.13.1" +} + +variable "goVersion" { + default = "1.27" +} + +# PHP built from source with the upstream docker-library/php Dockerfiles + +target "php-zts-trixie" { + name = "php-zts-trixie-${replace(substr(php, 0, 3), ".", "-")}" + context = "https://github.com/docker-library/php.git#${phpLibraryRef}:${substr(php, 0, 3)}/trixie/zts" + matrix = { + "php" = [for php in frankenphpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + platforms = [ "linux/amd64", "linux/arm64" ] +} + +target "frankenphp-upstream" { + name = "frankenphp-upstream-${replace(substr(php, 0, 3), ".", "-")}" + context = "https://github.com/php/frankenphp.git#${frankenphpRef}" + target = "runner" + matrix = { + "php" = [for php in frankenphpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + php-base = "target:php-zts-trixie-${replace(substr(php, 0, 3), ".", "-")}" + golang-base = "docker-image://docker.io/library/golang:${goVersion}-trixie" + } + args = { + "FRANKENPHP_VERSION" = frankenphpRef + } + platforms = [ "linux/amd64", "linux/arm64" ] +} + +# Frankenphp + +target "frankenphp" { + inherits = [ "_package-refresh" ] + name = "frankenphp-${replace(substr(php, 0, 3), ".", "-")}" + context = "./frankenphp" + matrix = { + "php" = [for php in frankenphpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:frankenphp-upstream-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp" + ] +} + +target "frankenphp-otel" { + inherits = [ "_package-refresh" ] + name = "frankenphp-otel-${replace(substr(php, 0, 3), ".", "-")}" + context = "./frankenphp-otel" + matrix = { + "php" = [for php in frankenphpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + contexts = { + base = "target:frankenphp-build-${replace(substr(php, 0, 3), ".", "-")}" + } + platforms = [ "linux/amd64", "linux/arm64" ] + tags = imageSuffix != "" ? [ + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp-otel" + ] : [ + "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp-otel", + "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp-otel", + + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp-otel", + "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp-otel" + ] +} + +# Internal stages exclude the daily upgrade and are never published. + +target "frankenphp-build" { + name = "frankenphp-build-${replace(substr(php, 0, 3), ".", "-")}" + matrix = { + "php" = [for php in frankenphpMatrix : php if phpMinor == "" || substr(php, 0, 3) == phpMinor] + } + inherits = [ "frankenphp-${replace(substr(php, 0, 3), ".", "-")}" ] + target = "build" + tags = [] + args = { + OS_PACKAGES_REFRESH = "" + } +} diff --git a/docker-bake.hcl b/docker-bake.hcl index 88e200e..1f89f09 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -1,3 +1,5 @@ +# Shared settings; load with docker-bake.fpm.hcl or docker-bake.frankenphp.hcl. + variable "imageSuffix" { default = "" } @@ -6,287 +8,23 @@ variable "tagPrefix" { default = "" } -variable "phpMatrix" { - default = [ "8.2.35", "8.3.36", "8.4.27", "8.5.12" ] -} - -variable "frankenphpMatrix" { - default = [ "8.2.35", "8.3.36", "8.4.27", "8.5.12" ] -} - variable "phpLibraryRef" { default = "e3eaff845f7a9f7259c31da54dce0320b47a3bbd" } -variable "alpineVersion" { - default = "3.24" -} - -variable "frankenphpRef" { - default = "v1.13.1" -} - -variable "goVersion" { - default = "1.27" -} - -# PHP built from source with the upstream docker-library/php Dockerfiles - -target "php-fpm-alpine" { - name = "php-fpm-alpine-${replace(substr(php, 0, 3), ".", "-")}" - context = "https://github.com/docker-library/php.git#${phpLibraryRef}:${substr(php, 0, 3)}/alpine${alpineVersion}/fpm" - matrix = { - "php" = phpMatrix - } - platforms = [ "linux/amd64", "linux/arm64" ] -} - -target "php-zts-trixie" { - name = "php-zts-trixie-${replace(substr(php, 0, 3), ".", "-")}" - context = "https://github.com/docker-library/php.git#${phpLibraryRef}:${substr(php, 0, 3)}/trixie/zts" - matrix = { - "php" = frankenphpMatrix - } - platforms = [ "linux/amd64", "linux/arm64" ] -} - -target "frankenphp-upstream" { - name = "frankenphp-upstream-${replace(substr(php, 0, 3), ".", "-")}" - context = "https://github.com/php/frankenphp.git#${frankenphpRef}" - target = "runner" - matrix = { - "php" = frankenphpMatrix - } - contexts = { - php-base = "target:php-zts-trixie-${replace(substr(php, 0, 3), ".", "-")}" - golang-base = "docker-image://docker.io/library/golang:${goVersion}-trixie" - } - args = { - "FRANKENPHP_VERSION" = frankenphpRef - } - platforms = [ "linux/amd64", "linux/arm64" ] -} - -# Frankenphp - -target "frankenphp" { - name = "frankenphp-${replace(substr(php, 0, 3), ".", "-")}" - context = "./frankenphp" - matrix = { - "php" = frankenphpMatrix - } - contexts = { - base = "target:frankenphp-upstream-${replace(substr(php, 0, 3), ".", "-")}" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp" - ] -} - -target "frankenphp-otel" { - name = "frankenphp-otel-${replace(substr(php, 0, 3), ".", "-")}" - context = "./frankenphp-otel" - matrix = { - "php" = frankenphpMatrix - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp-otel" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp-otel", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp-otel", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-frankenphp-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-frankenphp-otel" - ] -} - -# FPM - -target "fpm" { - name = "fpm-${replace(substr(php, 0, 3), ".", "-")}" - context = "./fpm" - matrix = { - "php" = phpMatrix - } - contexts = { - base = "target:php-fpm-alpine-${replace(substr(php, 0, 3), ".", "-")}" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm" - ] -} - -target "fpm-otel" { - name = "fpm-otel-${replace(substr(php, 0, 3), ".", "-")}" - context = "./fpm-otel" - matrix = { - "php" = phpMatrix - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm-otel", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-fpm-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel" - ] -} - -# Caddy - -target "caddy" { - name = "caddy-${replace(substr(php, 0, 3), ".", "-")}" - context = "./caddy" - matrix = { - "php" = phpMatrix - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy" - ] -} - -target "caddy-otel" { - name = "caddy-otel-${replace(substr(php, 0, 3), ".", "-")}" - context = "./caddy" - matrix = { - "php" = phpMatrix - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy-otel" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy-otel", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy-otel", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-caddy-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy-otel" - ] -} - -target "caddy-dev" { - name = "caddy-dev-${replace(substr(php, 0, 3), ".", "-")}-${node}" - context = "./dev" - matrix = { - "php" = phpMatrix - "node" = [ "22", "24" ] - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-caddy-otel" - } - args = { - "NODE_VERSION" = node - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = [ - "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${substr(php, 0, 3)}-node${node}-caddy", - "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${php}-node${node}-caddy" - ] -} - -# Nginx - -target "nginx" { - name = "nginx-${replace(substr(php, 0, 3), ".", "-")}" - context = "./nginx" - matrix = { - "php" = phpMatrix - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx" - ] +# Leave empty to build all supported PHP minor versions. +variable "phpMinor" { + default = "" } -target "nginx-otel" { - name = "nginx-otel-${replace(substr(php, 0, 3), ".", "-")}" - context = "./nginx" - matrix = { - "php" = phpMatrix - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-fpm-otel" - } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = imageSuffix != "" ? [ - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx-otel" - ] : [ - "shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx-otel", - "shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx-otel", - - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${substr(php, 0, 3)}-nginx-otel", - "ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx-otel" - ] +# Refresh installed OS packages once per UTC day without rebuilding extensions. +# Override this value to force another refresh within the same day. +variable "osPackagesRefresh" { + default = formattimestamp("YYYY-MM-DD", timestamp()) } -target "nginx-dev" { - name = "nginx-dev-${replace(substr(php, 0, 3), ".", "-")}-${node}" - context = "./dev" - matrix = { - "php" = phpMatrix - "node" = [ "22", "24" ] - } - contexts = { - base = "docker-image://ghcr.io/shopware/docker-base${imageSuffix}:${tagPrefix}${php}-nginx-otel" - } +target "_package-refresh" { args = { - "NODE_VERSION" = node + OS_PACKAGES_REFRESH = osPackagesRefresh } - platforms = [ "linux/amd64", "linux/arm64" ] - tags = [ - "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${substr(php, 0, 3)}-node${node}-nginx", - "ghcr.io/shopware/docker-dev${imageSuffix}:${tagPrefix}php${php}-node${node}-nginx" - ] } diff --git a/fpm-otel/Dockerfile b/fpm-otel/Dockerfile index 6f5f1f8..983bc7a 100644 --- a/fpm-otel/Dockerfile +++ b/fpm-otel/Dockerfile @@ -1,6 +1,6 @@ -#syntax=docker/dockerfile:1.4 +#syntax=docker/dockerfile:1 -FROM base +FROM base AS build USER root @@ -27,3 +27,13 @@ RUN --mount=type=bind,from=ghcr.io/php/pie:bin,source=/pie,target=/usr/local/bin EOF USER www-data + +# Derived images use the build stage so this refresh cannot invalidate compilation. +FROM build AS runtime + +USER root +ARG OS_PACKAGES_REFRESH +RUN echo "Refreshing OS packages: ${OS_PACKAGES_REFRESH}" \ + && apk upgrade --no-cache + +USER www-data diff --git a/fpm/Dockerfile b/fpm/Dockerfile index 80e4d9b..7851a1e 100644 --- a/fpm/Dockerfile +++ b/fpm/Dockerfile @@ -1,6 +1,6 @@ -#syntax=docker/dockerfile:1.4 +#syntax=docker/dockerfile:1 -FROM base +FROM base AS build ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ @@ -8,7 +8,6 @@ RUN < `"${v}"`).join(', ')} ]`; - hclContent = replaceVariable(hclContent, 'phpMatrix', matrix); - hclContent = replaceVariable(hclContent, 'frankenphpMatrix', matrix); - hclContent = replaceVariable(hclContent, 'phpLibraryRef', `"${phpLibraryRef}"`); - hclContent = replaceVariable(hclContent, 'alpineVersion', `"${alpineVersion}"`); + const updates = { + 'docker-bake.hcl': { phpLibraryRef: `"${phpLibraryRef}"` }, + 'docker-bake.fpm.hcl': { phpMatrix: matrix, alpineVersion: `"${alpineVersion}"` }, + 'docker-bake.frankenphp.hcl': { frankenphpMatrix: matrix }, + }; + + for (const [hclPath, variables] of Object.entries(updates)) { + let hclContent = await fs.readFile(hclPath, 'utf8'); + for (const [name, value] of Object.entries(variables)) { + hclContent = replaceVariable(hclContent, name, value); + } - await fs.writeFile(hclPath, hclContent); - console.log('Successfully updated docker-bake.hcl'); + await fs.writeFile(hclPath, hclContent); + console.log(`Successfully updated ${hclPath}`); + } console.log('PHP versions:', phpVersions); console.log('docker-library/php ref:', phpLibraryRef); console.log('Alpine version:', alpineVersion); @@ -80,4 +85,4 @@ async function updateBakeFile(phpVersions, phpLibraryRef, alpineVersion) { const phpLibraryRef = await fetchPhpLibraryRef(); const versions = await fetchVersions(phpLibraryRef); -await updateBakeFile(getPhpVersions(versions), phpLibraryRef, getLatestAlpineVersion(versions)); +await updateBakeFiles(getPhpVersions(versions), phpLibraryRef, getLatestAlpineVersion(versions));