diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 07d0f77..41d3cdd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,3 +21,7 @@ updates: directory: "/" schedule: interval: "daily" + groups: + specsnl-github-actions: + patterns: + - "specsnl/github-actions" diff --git a/.github/prompts/update-project.prompt.md b/.github/prompts/update-project.prompt.md new file mode 100644 index 0000000..7fcae01 --- /dev/null +++ b/.github/prompts/update-project.prompt.md @@ -0,0 +1,211 @@ +--- +description: Safely update this project's Dockerfile dependencies and tooling in isolated commits +name: update-project +--- + +# Goal + +Perform a full dependency update across all three Dockerfile variants (fpm, apache, frankenphp) in a safe, +reproducible way. + +**Critical rule:** Any version that appears in more than one Dockerfile must be updated across all affected +Dockerfiles in a single commit. Never update a shared version in only one Dockerfile. + +If any step fails, STOP immediately and report the error. + +## Phase 1 --- Repository Safety Checks + +1. Verify the current branch is `main`. If not, abort and instruct the user to switch to `main` first. +2. Ensure the working (git) tree is clean: + - No staged changes + - No unstaged changes + - No untracked files + - If not clean: Abort immediately — inform the user to commit or stash changes. +3. Synchronize with remote: `git fetch --prune` +4. Prepare branch `updates`: + - If branch does not exist → create from `origin/main` + - If branch exists: + - If fully merged into `main` → delete locally and recreate from `origin/main`. + - If behind `main` and has NO unique commits → reset `updates` to `origin/main`. + - If it contains unique commits → abort and notify user. +5. Check if the branch does not already exist on the remote. If it does, abort and inform the user to delete +the remote branch first. + +Always branch from latest `origin/main`. + +## Phase 2 --- PHP Base Image Updates + +The three Dockerfiles use different base images but all track the same PHP 8.4.x patch series: + +- `fpm/Dockerfile`: `FROM php:-fpm-trixie` +- `apache/Dockerfile`: `FROM php:-apache-trixie` +- `frankenphp/Dockerfile`: `FROM dunglas/frankenphp:-php-trixie` + +1. Check Docker Hub for the latest `php:8.4.x-fpm-trixie` tag. Only consider patch updates within the +`8.4.x` series — do not update to a different minor or major PHP version. +2. Check Docker Hub for the latest `dunglas/frankenphp` tag that matches the pattern +`x.x.x-php8.4.x-trixie`. Only consider updates that keep the PHP 8.4.x series. +3. Update the `FROM` lines in all three Dockerfiles if newer versions are available. +4. Check `git status`. Commit all three Dockerfiles together in a single commit if there are any changes. + Commit message: `chore(deps): Update PHP base image versions`. +5. If there are no changes, skip the commit and move on. + +Abort on any failure. + +## Phase 3 --- Pie Tool Update + +All three Dockerfiles pin the same Pie version via: + +``` +COPY --from=ghcr.io/php/pie:-bin /pie /usr/bin/pie +``` + +1. Check the GitHub Releases API for the latest release of `php/pie`. +2. If a newer version is available, update the `ghcr.io/php/pie:-bin` reference in all three +Dockerfiles. +3. Check `git status`. Commit all three Dockerfiles together in a single commit if there are any changes. + Commit message: `chore(deps): Update Pie version`. +4. If there are no changes, skip the commit and move on. + +Abort on any failure. + +## Phase 4 --- PHP Runtime Extension Updates + +All three Dockerfiles share the same versions for the following PHP extensions (runtime stage ARGs): + +- `PHP_EVENT_VERSION` — `osmanov/pecl-event` on Packagist +- `PHP_IGBINARY_VERSION` — `igbinary/igbinary` on Packagist +- `PHP_REDIS_VERSION` — `phpredis/phpredis` on Packagist +- `PHP_AMQP_VERSION` — `php-amqp/php-amqp` on Packagist + +Process each extension individually and in order: + +1. Query the Packagist API for the latest stable release of the extension. +2. If a newer version is available, update the corresponding `ARG` in all three Dockerfiles. +3. Commit all three Dockerfiles together in a single commit. + Commit message: `chore(deps): Update to `. + For example: `chore(deps): Update phpredis/phpredis to 6.4.0`. +4. If there is no update for this extension, skip the commit and move on to the next extension. + +Repeat for every extension. Each updated extension gets its own commit. + +Abort on any failure. + +## Phase 5 --- Builder Stage Tool Updates + +All three Dockerfiles share the same versions for the following builder-stage tools: + +- `PHIVE_VERSION` — check the GitHub Releases API for `phar-io/phive` +- `COMPOSER_VERSION` — check `https://getcomposer.org/download/` or the GitHub Releases API for +`composer/composer` +- `XDEBUG_VERSION` — `xdebug/xdebug` on Packagist +- `PCOV_VERSION` — `pecl/pcov` on Packagist + +Process each tool individually and in order: + +1. Look up the latest stable release of the tool. +2. If a newer version is available, update the corresponding `ARG` in all three Dockerfiles. +3. Commit all three Dockerfiles together in a single commit. + Commit message: `chore(deps): Update to `. + For example: `chore(deps): Update Composer to 2.10.0`. +4. If there is no update for this tool, skip the commit and move on to the next tool. + +Repeat for every tool. Each updated tool gets its own commit. + +Abort on any failure. + +## Phase 6 --- Node.js Major Version Update + +All three Dockerfiles pin `ARG NODE_MAJOR=` for the `builder_nodejs` stage. + +1. Check the Node.js release schedule at `https://nodejs.org/en/about/previous-releases` to find the +current Active LTS major version. +2. Only update `NODE_MAJOR` if a newer **Active LTS** major version is available. Do not update to a +Current (non-LTS) release. +3. If a newer Active LTS major is available, update `NODE_MAJOR` in all three Dockerfiles. +4. Check `git status`. Commit all three Dockerfiles together in a single commit if there are any changes. + Commit message: `chore(deps): Update Node.js major version to `. +5. If there are no changes, skip the commit and move on. + +Abort on any failure. + +## Phase 7 --- Hadolint Version Update + +The `Taskfile.dist.yml` pins the Hadolint Docker image version via the `HADOLINT_TAG_VERSION` variable. + +1. Check the GitHub Releases API for the latest release of `hadolint/hadolint`. +2. If a newer version is available, update `HADOLINT_TAG_VERSION` in `Taskfile.dist.yml`. +3. Check `git status`. Commit if there are any changes. + Commit message: `chore(deps): Update Hadolint version`. +4. If there are no changes, skip the commit and move on. + +Abort on any failure. + +## Phase 8 --- GitHub Actions Updates + +1. Scan the following files for pinned `uses:` action references: + - `.github/workflows/*.yml` +2. For each external action (e.g. `specsnl/github-actions/.github/workflows/build-php.yml@1.1.1`), use +the GitHub Releases API to find the latest release tag. Check every action individually — do not assume +a version is already current. + - If the reference uses a floating major-version tag (e.g. `@v6`) and that major version is already + the latest, leave it as-is. + - If the reference is pinned to a specific semver tag (e.g. `@1.1.1`, `@v2.5.0`) and a newer version + exists, update it to the latest release tag. + - If the reference is pinned to a commit SHA, leave it as-is. +3. Update any outdated action versions in-place across all scanned files. +4. Check `git status`. Commit separately if there are any changes. + Commit message: `chore(deps): Update GitHub Actions versions`. +5. If there are no changes, skip the commit and move on. + +Abort on any failure. + +## Phase 9 --- License Year Update + +1. Check if the `LICENSE` file contains a year range (e.g. `2020-2025`) or a single year (e.g. `2024`). +2. If the current year (2026) is not already the end year: + - Single year (e.g. `2024`) → update to `2026`. + - Year range (e.g. `2020-2025`) → update the end year to `2026`. +3. Commit separately if there are any changes. + Commit message: `chore: Update copyright year`. +4. If there are no changes, skip the commit and move on. + +------------------------------------------------------------------------ + +## Final State + +Abort if there are no changes after all update steps, and inform the user that everything is already up +to date. + +- There could be up to 14 commits on the `updates` branch: + 1. PHP base image versions + 2. Pie tool version + 3. PHP runtime extension: osmanov/pecl-event + 4. PHP runtime extension: igbinary/igbinary + 5. PHP runtime extension: phpredis/phpredis + 6. PHP runtime extension: php-amqp/php-amqp + 7. Builder tool: Phive + 8. Builder tool: Composer + 9. Builder tool: Xdebug + 10. Builder tool: pcov + 11. Node.js major version + 12. Hadolint version + 13. GitHub Actions versions + 14. Copyright year +- Branch: `updates` +- Based on latest `origin/main`. +- The working tree should be clean. +- Push the branch to the remote and create a pull request for review and merging targeting `origin/main`. + The title should be `chore: Update dependencies`. +- Add a Pull Request description that lists the changes based on the commits that were made. Stick to the + commit messages but remove the "chore" prefix. For example: + +```md +Updated the following dependencies: + +- Updated PHP base image versions +- Updated Pie version +- Updated PHP runtime extension versions +- Updated builder stage tool versions +- Updated GitHub Actions versions +``` diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8d4bcfd..18557b3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ concurrency: jobs: build: - uses: Ilyes512/github-actions/.github/workflows/build-php.yml@1.0.12 + uses: specsnl/github-actions/.github/workflows/build-php.yml@1.1.1 strategy: fail-fast: false matrix: @@ -38,7 +38,7 @@ jobs: dockerfile: ${{ matrix.docker.dockerfile }} merge: - uses: Ilyes512/github-actions/.github/workflows/merge-php.yml@1.0.12 + uses: specsnl/github-actions/.github/workflows/merge-php.yml@1.1.1 needs: build strategy: matrix: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index fd07965..2f6b1df 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -14,7 +14,7 @@ concurrency: jobs: build: - uses: Ilyes512/github-actions/.github/workflows/build-php.yml@1.0.12 + uses: specsnl/github-actions/.github/workflows/build-php.yml@1.1.1 strategy: fail-fast: false matrix: @@ -37,7 +37,7 @@ jobs: dockerfile: ${{ matrix.docker.dockerfile }} merge: - uses: Ilyes512/github-actions/.github/workflows/merge-php.yml@1.0.12 + uses: specsnl/github-actions/.github/workflows/merge-php.yml@1.1.1 needs: build strategy: matrix: diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 16d8c3e..3c2ce0b 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -15,7 +15,7 @@ concurrency: jobs: build: - uses: Ilyes512/github-actions/.github/workflows/build-php.yml@1.0.12 + uses: specsnl/github-actions/.github/workflows/build-php.yml@1.1.1 strategy: fail-fast: false matrix: @@ -38,7 +38,7 @@ jobs: dockerfile: ${{ matrix.docker.dockerfile }} merge: - uses: Ilyes512/github-actions/.github/workflows/merge-php.yml@1.0.12 + uses: specsnl/github-actions/.github/workflows/merge-php.yml@1.1.1 needs: build strategy: matrix: diff --git a/LICENSE b/LICENSE index 4d86acf..7559929 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Ilyes Ahidar +Copyright (c) 2026 Ilyes Ahidar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Taskfile.dist.yml b/Taskfile.dist.yml index 9f72a70..859dd6a 100644 --- a/Taskfile.dist.yml +++ b/Taskfile.dist.yml @@ -20,6 +20,13 @@ tasks: - task: build:apache - task: build:frankenphp + lint: + desc: Apply a Dockerfile linter to all Dockerfiles + cmds: + - task: lint:fpm + - task: lint:apache + - task: lint:frankenphp + build:fpm: desc: Build all PHP Docker image targets of the FPM variant deps: [lint:fpm] @@ -110,22 +117,23 @@ tasks: lint:fpm: desc: Apply a Dockerfile linter (https://github.com/hadolint/hadolint) cmds: - - task: lint + - task: do:lint vars: { DOCKERFILE_PATH: fpm/Dockerfile } lint:apache: desc: Apply a Dockerfile linter (https://github.com/hadolint/hadolint) cmds: - - task: lint + - task: do:lint vars: { DOCKERFILE_PATH: apache/Dockerfile } lint:frankenphp: desc: Apply a Dockerfile linter (https://github.com/hadolint/hadolint) cmds: - - task: lint + - task: do:lint vars: { DOCKERFILE_PATH: frankenphp/Dockerfile } - lint: + do:lint: + internal: true cmds: - docker run --interactive diff --git a/apache/Dockerfile b/apache/Dockerfile index d511178..1e655fb 100644 --- a/apache/Dockerfile +++ b/apache/Dockerfile @@ -1,3 +1,6 @@ +# syntax=docker/dockerfile:1 +# check=error=true + # Latest version of PHP base image: https://hub.docker.com/_/php/tags FROM php:8.4.19-apache-trixie AS runtime @@ -16,8 +19,6 @@ ARG PHP_EVENT_VERSION=3.1.5 ARG PHP_IGBINARY_VERSION=3.2.17RC1 # Latest version of redis-extension: https://packagist.org/packages/phpredis/phpredis ARG PHP_REDIS_VERSION=6.3.0 -# Latest version of memcached-extension: https://pecl.php.net/package/memcached -ARG PHP_MEMCACHED_VERSION=3.4.0 # Latest version of amqp-extension: https://packagist.org/packages/php-amqp/php-amqp ARG PHP_AMQP_VERSION=2.2.0 @@ -27,7 +28,7 @@ ENV SMTPEHLO=localhost WORKDIR /var/www # Latest version of Pie: https://github.com/php/pie/releases -COPY --from=ghcr.io/php/pie:1.3.9-bin /pie /usr/bin/pie +COPY --from=ghcr.io/php/pie:1.3.10-bin /pie /usr/bin/pie RUN apt-get update \ && apt-get install --assume-yes --no-install-recommends \ @@ -56,9 +57,6 @@ RUN apt-get update \ librabbitmq4 \ # Dependency of PHP xsl-extension libxslt1.1 \ - # Dependency of PHP memcached-extension - libmemcached11t64 \ - zlib1g \ # Install packages that are needed for building PHP extensions && apt-get install --assume-yes --no-install-recommends \ $PHPIZE_DEPS \ @@ -82,9 +80,6 @@ RUN apt-get update \ librabbitmq-dev \ # Dependency of PHP xsl-extension libxslt1-dev \ - # Dependency of PHP memcached-extension - libmemcached-dev \ - zlib1g-dev \ # Configure PHP gd-extension && docker-php-ext-configure gd \ --enable-gd \ @@ -109,12 +104,10 @@ RUN apt-get update \ && pie install --skip-enable-extension igbinary/igbinary:$PHP_IGBINARY_VERSION \ && pie install --skip-enable-extension php-amqp/php-amqp:$PHP_AMQP_VERSION \ && pie install --skip-enable-extension phpredis/phpredis:$PHP_REDIS_VERSION --enable-redis-igbinary \ - && pecl install --configureoptions 'enable-memcached-igbinary="yes"' "memcached-$PHP_MEMCACHED_VERSION" \ && docker-php-ext-enable --ini-name docker-php-ext-zz-custom.ini \ event \ igbinary \ redis \ - memcached \ amqp \ && cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \ # Purge packages that where only needed for building php extensions @@ -132,8 +125,6 @@ RUN apt-get update \ libpq-dev \ librabbitmq-dev \ libxslt1-dev \ - libmemcached-dev \ - zlib1g-dev \ && mkdir -p \ $XDG_CONFIG_HOME \ $XDG_DATA_HOME \ diff --git a/fpm/Dockerfile b/fpm/Dockerfile index 345b4ea..43100af 100644 --- a/fpm/Dockerfile +++ b/fpm/Dockerfile @@ -1,3 +1,6 @@ +# syntax=docker/dockerfile:1 +# check=error=true + # Latest version of PHP base image: https://hub.docker.com/_/php/tags FROM php:8.4.19-fpm-trixie AS runtime @@ -16,8 +19,6 @@ ARG PHP_EVENT_VERSION=3.1.5 ARG PHP_IGBINARY_VERSION=3.2.17RC1 # Latest version of redis-extension: https://packagist.org/packages/phpredis/phpredis ARG PHP_REDIS_VERSION=6.3.0 -# Latest version of memcached-extension: https://pecl.php.net/package/memcached -ARG PHP_MEMCACHED_VERSION=3.4.0 # Latest version of amqp-extension: https://packagist.org/packages/php-amqp/php-amqp ARG PHP_AMQP_VERSION=2.2.0 @@ -27,7 +28,7 @@ ENV SMTPEHLO=localhost WORKDIR /var/www # Latest version of Pie: https://github.com/php/pie/releases -COPY --from=ghcr.io/php/pie:1.3.9-bin /pie /usr/bin/pie +COPY --from=ghcr.io/php/pie:1.3.10-bin /pie /usr/bin/pie RUN apt-get update \ && apt-get install --assume-yes --no-install-recommends \ @@ -56,9 +57,6 @@ RUN apt-get update \ librabbitmq4 \ # Dependency of PHP xsl-extension libxslt1.1 \ - # Dependency of PHP memcached-extension - libmemcached11t64 \ - zlib1g \ # Install packages that are needed for building PHP extensions && apt-get install --assume-yes --no-install-recommends \ $PHPIZE_DEPS \ @@ -82,9 +80,6 @@ RUN apt-get update \ librabbitmq-dev \ # Dependency of PHP xsl-extension libxslt1-dev \ - # Dependency of PHP memcached-extension - libmemcached-dev \ - zlib1g-dev \ # Configure PHP gd-extension && docker-php-ext-configure gd \ --enable-gd \ @@ -109,12 +104,10 @@ RUN apt-get update \ && pie install --skip-enable-extension igbinary/igbinary:$PHP_IGBINARY_VERSION \ && pie install --skip-enable-extension php-amqp/php-amqp:$PHP_AMQP_VERSION \ && pie install --skip-enable-extension phpredis/phpredis:$PHP_REDIS_VERSION --enable-redis-igbinary \ - && pecl install --configureoptions 'enable-memcached-igbinary="yes"' "memcached-$PHP_MEMCACHED_VERSION" \ && docker-php-ext-enable --ini-name docker-php-ext-zz-custom.ini \ event \ igbinary \ redis \ - memcached \ amqp \ && cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \ # Purge packages that where only needed for building php extensions @@ -132,8 +125,6 @@ RUN apt-get update \ libpq-dev \ librabbitmq-dev \ libxslt1-dev \ - libmemcached-dev \ - zlib1g-dev \ && mkdir -p \ $XDG_CONFIG_HOME \ $XDG_DATA_HOME \ diff --git a/frankenphp/Dockerfile b/frankenphp/Dockerfile index 01c3a46..4d42acf 100644 --- a/frankenphp/Dockerfile +++ b/frankenphp/Dockerfile @@ -1,3 +1,6 @@ +# syntax=docker/dockerfile:1 +# check=error=true + # Latest version of FrankenPHP base image: https://hub.docker.com/r/dunglas/frankenphp/tags FROM dunglas/frankenphp:1.12.1-php8.4-trixie AS runtime @@ -29,7 +32,7 @@ ENV FRANKENPHP_CONFIG="" WORKDIR /var/www # Latest version of Pie: https://github.com/php/pie/releases -COPY --from=ghcr.io/php/pie:1.3.9-bin /pie /usr/bin/pie +COPY --from=ghcr.io/php/pie:1.3.10-bin /pie /usr/bin/pie RUN apt-get update \ && apt-get install --assume-yes --no-install-recommends \