diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 149bfd8..a8f191b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,14 +30,29 @@ jobs: tests: strategy: matrix: - ddev_version: [stable, HEAD] + # Each job builds one PHP version, which takes 10-15 minutes + ddev_version: [HEAD] + php: ["8.1", "8.4", "8.5", "8.6"] + runner: [ubuntu-latest] + include: + - ddev_version: stable + php: "8.5" + runner: ubuntu-latest + # Smoke tests on arm64, where users most need to build PHP themselves + - ddev_version: HEAD + php: "8.5" + runner: ubuntu-24.04-arm + - ddev_version: HEAD + php: "8.6" + runner: ubuntu-24.04-arm fail-fast: false - runs-on: ubuntu-latest + runs-on: ${{ matrix.runner }} env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + STATIC_PHP_TEST_MINOR: ${{ matrix.php }} steps: - uses: ddev/github-action-add-on-test@v2 diff --git a/README.md b/README.md index 8b6e56c..35dfe9b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This **experimental** add-on tries to address that need, although there are a number of caveats: -1. The build done using this process uses the technique from [static-php-cli](https://github.com/crazywhalecc/static-php-cli) and full details are available there. It supports all the versions supported in the upstream repository, currently PHP 7.3-8.5. +1. The build done using this process uses the technique from [static-php-cli](https://github.com/crazywhalecc/static-php-cli) and full details are available there. It builds PHP 8.1 and later, including PHP 8.6 pre-releases, see [Pre-release versions](#pre-release-versions). static-php-cli doesn't support PHP 7.x, and support for 8.0 and 8.1 is best-effort. The tests cover 8.1, 8.4, 8.5 and 8.6. 2. The build does not match the build done using the official DDEV php packages (which actually come from [deb.sury.org](https://deb.sury.org/). 3. It does not provide Xdebug, so `ddev xdebug` doesn't work. `xhprof` isn't built by default, and `ddev xhprof` hasn't been tested with it. See [extension support](https://static-php.dev/en/guide/extension-notes.html). 4. The resultant PHP binaries built here do not have the exact same extensions as the official DDEV PHP binaries, see [Extensions](#extensions). @@ -27,7 +27,7 @@ This **experimental** add-on tries to address that need, although there are a nu ## Installation ```bash -# Set your desired PHP version, when prompted, e.g., 8.0.10 +# Set your desired PHP version, when prompted, e.g., 8.4.10 ddev add-on get rfay/ddev-php-patch-build ddev restart ``` @@ -65,12 +65,27 @@ These are not available: * `xdebug`: see the caveats above. * `xmlrpc`: not supported by static-php-cli. +## Pre-release versions + +You can build the current release candidate of a PHP version that isn't released yet, such as `8.6.0RC4`: + +```bash +ddev config --php-version=8.6 +ddev dotenv set .ddev/.env.php-patch-build --static-php-version=8.6.0RC4 +ddev add-on get rfay/ddev-php-patch-build +ddev restart +``` + +Only the current pre-release listed on [php.net](https://www.php.net/pre-release-builds.php) can be downloaded, so update `--static-php-version` when a new one comes out. + +For PHP 8.6, APCu is built from an unreleased commit because the latest APCu release doesn't support PHP 8.6. If your DDEV version doesn't support `php_version: 8.6`, use `8.5`; it only affects which `php.ini` is used. + ## Advanced Customization You can choose a different PHP version with: ```bash -ddev dotenv set .ddev/.env.php-patch-build --static-php-version=8.0.10 +ddev dotenv set .ddev/.env.php-patch-build --static-php-version=8.4.10 ddev add-on get rfay/ddev-php-patch-build ddev restart ``` diff --git a/install.yaml b/install.yaml index d5b515b..a2ca72f 100644 --- a/install.yaml +++ b/install.yaml @@ -14,7 +14,7 @@ pre_install_actions: post_install_actions: - | if [ "${STATIC_PHP_VERSION:-}" = "" ]; then - printf "\n\nPlease enter the PHP patch version you want to use, like 7.4.23 or 8.0.10:" + printf "\n\nPlease enter the PHP patch version you want to use, like 8.4.10 or 8.5.12:" fi - | #ddev-description:Set PHP patch version diff --git a/tests/test.bats b/tests/test.bats index 6ae5928..1cebd24 100644 --- a/tests/test.bats +++ b/tests/test.bats @@ -9,6 +9,8 @@ # bats ./tests/test.bats # To exclude release tests: # bats ./tests/test.bats --filter-tags '!release' +# To test another PHP minor version (default 8.5), as the CI matrix does: +# STATIC_PHP_TEST_MINOR=8.6 bats ./tests/test.bats # For debugging: # bats ./tests/test.bats --show-output-of-passing-tests --verbose-run --print-output-on-failure @@ -37,7 +39,11 @@ setup() { run ddev start -y assert_success - export CUSTOM_PHP_MINOR_VERSION="8.3.19" + # The PHP minor version to test is set by the CI matrix; build its newest release or pre-release + export STATIC_PHP_TEST_MINOR="${STATIC_PHP_TEST_MINOR:-8.5}" + export STATIC_PHP_TEST_VERSION="$(latest_php_version "${STATIC_PHP_TEST_MINOR}")" + assert [ -n "${STATIC_PHP_TEST_VERSION}" ] + echo "# Testing PHP ${STATIC_PHP_TEST_VERSION}" >&3 printf "index.php assert_file_exist index.php printf "ini.php @@ -45,18 +51,39 @@ setup() { printf "upload_max_filesize = 7M\n" >.ddev/php/test.ini } +# The project's web URL, which includes the router port when it isn't the default +web_url() { + ddev describe -j | jq -r .raw.primary_url +} + +# The newest release of a PHP minor version, or its current pre-release if there's no release yet +latest_php_version() { + local version + version="$(curl -fsSL "https://www.php.net/releases/index.php?json&version=$1" | jq -r '.version // empty')" + if [ -z "${version}" ]; then + version="$(curl -fsSL "https://www.php.net/pre-release-builds.php?format=json" | jq -r --arg minor "$1." '.[] | objects | .release | objects | select((.version // "") | startswith($minor)) | .version' | head -n 1)" + fi + echo "${version}" +} + +# Match DDEV's php_version to the static PHP so its php.ini and php-fpm configuration are used +set_php_version() { + # DDEV v1.25.4 and older don't support php_version 8.6; 8.5 only changes which php.ini is used + ddev config --php-version="${STATIC_PHP_TEST_MINOR}" >/dev/null 2>&1 || ddev config --php-version=8.5 +} + health_checks() { run ddev php --version assert_success - assert_output --partial "PHP ${CUSTOM_PHP_MINOR_VERSION}" + assert_output --partial "PHP ${STATIC_PHP_TEST_VERSION}" - run curl -sf https://${PROJNAME}.ddev.site/ + run curl -sf "$(web_url)/" assert_success - assert_output --partial "${CUSTOM_PHP_MINOR_VERSION}" + assert_output --partial "${STATIC_PHP_TEST_VERSION}" run ddev describe assert_success - assert_output --partial "Static PHP: ${CUSTOM_PHP_MINOR_VERSION}" + assert_output --partial "Static PHP: ${STATIC_PHP_TEST_VERSION}" run ddev php -m assert_success @@ -87,7 +114,7 @@ unreleased_checks() { assert_success assert_output "-1 7M 1" - run curl -sf https://${PROJNAME}.ddev.site/ini.php + run curl -sf "$(web_url)/ini.php" assert_success assert_output "1024M 7M 1" @@ -114,7 +141,8 @@ teardown() { @test "install from directory" { set -eu -o pipefail - run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${CUSTOM_PHP_MINOR_VERSION}" + set_php_version + run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${STATIC_PHP_TEST_VERSION}" assert_file_exist .ddev/.env.php-patch-build echo "# ddev add-on get ${DIR} with project ${PROJNAME} in $(pwd)" >&3 @@ -130,7 +158,12 @@ teardown() { @test "install from release" { set -eu -o pipefail - run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${CUSTOM_PHP_MINOR_VERSION}" + # One release test is enough; the CI matrix runs it only in the default PHP job + if [ "${STATIC_PHP_TEST_MINOR}" != "8.5" ]; then + skip "release test only runs for PHP 8.5" + fi + set_php_version + run ddev dotenv set .ddev/.env.php-patch-build --static-php-version="${STATIC_PHP_TEST_VERSION}" assert_file_exist .ddev/.env.php-patch-build echo "# ddev add-on get ${GITHUB_REPO} with project ${PROJNAME} in $(pwd)" >&3 diff --git a/web-build/Dockerfile.php-patch-build b/web-build/Dockerfile.php-patch-build index 8f310fc..74cb0cb 100644 --- a/web-build/Dockerfile.php-patch-build +++ b/web-build/Dockerfile.php-patch-build @@ -31,9 +31,29 @@ chmod +x bin/spc bin/spc doctor --auto-fix rm -rf source/* buildroot/* +PHP_SRC_URL="https://www.php.net/distributions/php-${STATIC_PHP_VERSION}.tar.gz" +if ! curl -fsIL --retry 3 -o /dev/null "${PHP_SRC_URL}"; then + # Pre-release versions like 8.6.0RC4 are on downloads.php.net, listed by php.net + PHP_SRC_URL="$(curl -fsSL --retry 3 "https://www.php.net/pre-release-builds.php?format=json" | jq -r --arg v "${STATIC_PHP_VERSION}" '.[] | objects | .release | objects | select(.version == $v) | .files.gz.path' | head -n 1)" + if [ -z "${PHP_SRC_URL}" ]; then + echo "PHP ${STATIC_PHP_VERSION} not found on php.net, or not the current pre-release" >&2 + exit 1 + fi +fi + +IFS=. read -r PHP_MAJOR PHP_MINOR _ <<<"${STATIC_PHP_VERSION}" +PHP_86_OR_LATER=false +if (( PHP_MAJOR > 8 || (PHP_MAJOR == 8 && PHP_MINOR >= 6) )); then PHP_86_OR_LATER=true; fi + +CUSTOM_URLS=(-U "php-src:${PHP_SRC_URL}") +if [ "${PHP_86_OR_LATER}" = true ] && [[ ",${STATIC_PHP_EXTENSIONS}," == *,apcu,* ]]; then + # The latest APCu release (5.1.28) doesn't build with PHP 8.6; this commit does + CUSTOM_URLS+=(-U "apcu:https://github.com/krakjoe/apcu/archive/ebbcd3d153df21eaee3395413de515a30b48ef05.tar.gz") +fi + # Retry because GitHub API release lookups fail intermittently; already-downloaded sources are skipped for attempt in 1 2 3; do - if bin/spc download --prefer-pre-built --for-extensions="${STATIC_PHP_EXTENSIONS}" -U "php-src:https://www.php.net/distributions/php-${STATIC_PHP_VERSION}.tar.gz"; then + if bin/spc download --prefer-pre-built --for-extensions="${STATIC_PHP_EXTENSIONS}" "${CUSTOM_URLS[@]}"; then break fi if [ "${attempt}" -eq 3 ]; then @@ -47,8 +67,20 @@ done # opcache would normally be here but build fails: https://github.com/crazywhalecc/static-php-cli/issues/192 if [[ ${STATIC_PHP_VERSION} =~ ^[89] ]]; then export STATIC_PHP_EXTENSIONS="${STATIC_PHP_EXTENSIONS},opcache"; fi +# Skip patches for the micro SAPI, which isn't built; static-php-cli applies its PHP 8.0 patches to unknown versions like 8.6 +export SPC_MICRO_PATCHES="" + +# PHP 8.6 rejects the --with-pic option static-php-cli passes to configure, and needs --enable-pic instead +if [ "${PHP_86_OR_LATER}" = true ]; then + export SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --disable-shared --enable-static --disable-all --disable-phpdbg --enable-pic" +fi + # Scan our own conf.d and the project's .ddev/php directory for additional ini files -bin/spc build "${STATIC_PHP_EXTENSIONS}" --build-cli --build-fpm --with-config-file-scan-dir=/usr/local/etc/php/conf.d:/mnt/ddev_config/php +if ! bin/spc build "${STATIC_PHP_EXTENSIONS}" --build-cli --build-fpm --with-config-file-scan-dir=/usr/local/etc/php/conf.d:/mnt/ddev_config/php; then + # static-php-cli doesn't print the failing command's output, so show it here + tail -n 60 log/spc.shell.log >&2 || true + exit 1 +fi chown -R "${uid}:${gid}" /usr/local/src/static-php-cli EOF