Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions .github/workflows/build-php-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Builds one PHP release for Linux (x86-64 or arm64) with static-php-cli in its glibc container,
# tests it, and publishes it on the php-<version> release as php-<version>-build<N>-<platform>.tar.gz:
# bin/php and bin/php-fpm with the compiled-in extensions and the shared ones in ext/ from
# php.linux in versions.json (build number: php.linux.build).
# Called by release.yml for every version without that build yet; run it by hand to test a build
# without publishing. Nothing is published unless every check passed, and a published asset is
# never replaced.
name: Build PHP Linux

on:
workflow_call:
inputs:
version:
type: string
required: true
platform:
type: string
required: true
publish:
type: boolean
default: false
workflow_dispatch:
inputs:
version:
description: PHP version (major.minor.patch)
required: true
platform:
description: Platform
type: choice
options: [linux-x64, linux-arm64]
publish:
description: Publish the package as a release asset
type: boolean
default: false

permissions:
contents: read

env:
VERSION: ${{ inputs.version }}
PLATFORM: ${{ inputs.platform }}

jobs:
build:
name: build php ${{ inputs.version }} ${{ inputs.platform }}
runs-on: ${{ inputs.platform == 'linux-arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
timeout-minutes: 150
outputs:
asset: ${{ steps.config.outputs.asset }}
ok: ${{ steps.done.outputs.ok }}
env:
GITHUB_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v7

- name: Read versions.json
id: config
run: |
jq -r '.php.linux | "SPC_VERSION=\(.spc)\nMIN_GLIBC=\(.min_glibc)\nSTATIC_EXTS=\(.static_extensions)\nSHARED_EXTS=\(.shared_extensions)"' versions.json >> "$GITHUB_ENV"
echo "MINOR=$(cut -d. -f1-2 <<<"$VERSION")" >> "$GITHUB_ENV"
build="$(jq -r .php.linux.build versions.json)"
echo "BUILD=$build" >> "$GITHUB_ENV"
asset="php-$VERSION-build$build-$PLATFORM.tar.gz"
echo "ASSET=$asset" >> "$GITHUB_ENV"
echo "asset=$asset" >> "$GITHUB_OUTPUT"

- name: Install patchelf
run: sudo apt-get update -q && sudo apt-get install -yq patchelf

- name: Cache static-php-cli downloads
uses: actions/cache@v6
with:
path: spc-src/downloads
key: spc-linux-downloads-${{ env.SPC_VERSION }}-${{ inputs.platform }}-${{ inputs.version }}-${{ hashFiles('versions.json') }}
restore-keys: spc-linux-downloads-${{ env.SPC_VERSION }}-${{ inputs.platform }}-${{ env.MINOR }}

- name: Build
run: bash packages/php/linux/build.sh "$VERSION" out

- name: Portability (readelf)
run: bash scripts/verify-linux.sh out "$MIN_GLIBC" | tee -a "$GITHUB_STEP_SUMMARY"

# Every shared extension in versions.json has to build and load for a release.
- name: Smoke test
run: bash scripts/smoke-php-package.sh php out

- name: Package
run: |
jq -n --arg version "$VERSION" --argjson build "$BUILD" --arg platform "$PLATFORM" --arg commit "$GITHUB_SHA" \
--arg spc "$SPC_VERSION" --arg min_glibc "$MIN_GLIBC" --arg static "$STATIC_EXTS" --arg shared "$SHARED_EXTS" \
--arg built "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'{package: "php", version: $version, build: $build, platform: $platform, min_glibc: $min_glibc,
built: $built, commit: $commit, static_php_cli: $spc,
extensions: {compiled_in: ($static | split(",")), shared: ($shared | split(","))}}' \
> out/flock-package.json
tar -C out -czf "$ASSET" .
sha256sum "$ASSET" | tee -a "$GITHUB_STEP_SUMMARY"

- uses: actions/upload-artifact@v7
with:
name: ${{ env.ASSET }}
path: ${{ env.ASSET }}
retention-days: 7
- id: done
run: echo ok=true >> "$GITHUB_OUTPUT"

# The oldest glibc the build targets, without anything the runner has installed.
portable:
name: run php ${{ inputs.version }} ${{ inputs.platform }} on CentOS 7 (glibc 2.17)
needs: build
if: needs.build.outputs.ok == 'true'
runs-on: ${{ inputs.platform == 'linux-arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
outputs:
ok: ${{ steps.done.outputs.ok }}
env:
ASSET: ${{ needs.build.outputs.asset }}
steps:
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
with:
name: ${{ env.ASSET }}
- name: Read versions.json
run: jq -r '.php.linux | "STATIC_EXTS=\(.static_extensions)\nSHARED_EXTS=\(.shared_extensions)"' versions.json >> "$GITHUB_ENV"
# In a container: the runner's own glibc and libraries would hide what the package lacks. As
# the runner's user, like PHP-FPM on a user's machine (as root it wants a pool user).
- name: Smoke test
run: |
mkdir pkg && tar -C pkg -xzf "$ASSET"
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/w" -w /w -e STATIC_EXTS -e SHARED_EXTS centos:7 \
bash scripts/smoke-php-package.sh php pkg
- id: done
run: echo ok=true >> "$GITHUB_OUTPUT"

publish:
needs: [build, portable]
if: inputs.publish && needs.portable.outputs.ok == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
ASSET: ${{ needs.build.outputs.asset }}
steps:
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
with:
name: ${{ env.ASSET }}
- run: bash scripts/publish.sh php "$VERSION" "$ASSET"
42 changes: 36 additions & 6 deletions .github/workflows/build-service.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Builds one release of a service (PostgreSQL, MariaDB, Valkey, Redis) from source for one
# platform with packages/<package>/<os>/build.*, checks it (portability on macOS), smoke-tests it
# on a clean runner, and publishes it as <package>-<version>-build<N>-<platform>.<ext> on the
# platform with packages/<package>/<os>/build.* (Linux: in the manylinux_2_28 container, glibc
# 2.28), checks it (portability on macOS and Linux), smoke-tests it on a clean runner (Linux: an
# almalinux:8 container), and publishes it as <package>-<version>-build<N>-<platform>.<ext> on the
# <package>-<version> release, next to the upstream source when the license asks for it.
# Called by release.yml for every version without that build yet; run it by hand to test.
# Nothing is published unless every check passed, and a published asset is never replaced.
Expand Down Expand Up @@ -32,7 +33,7 @@ on:
platform:
description: Platform
type: choice
options: [macos-arm64, windows-x64]
options: [macos-arm64, windows-x64, linux-x64, linux-arm64]
publish:
description: Publish the package as a release asset
type: boolean
Expand All @@ -49,7 +50,7 @@ env:
jobs:
build:
name: build ${{ inputs.package }} ${{ inputs.version }} ${{ inputs.platform }}
runs-on: ${{ inputs.platform == 'windows-x64' && 'windows-2022' || 'macos-15' }}
runs-on: ${{ fromJSON('{"windows-x64":"windows-2022","linux-x64":"ubuntu-24.04","linux-arm64":"ubuntu-24.04-arm"}')[inputs.platform] || 'macos-15' }}
timeout-minutes: 180
outputs:
asset: ${{ steps.config.outputs.asset }}
Expand Down Expand Up @@ -85,6 +86,27 @@ jobs:
if: runner.os == 'macOS'
run: bash scripts/verify-macos.sh out "$MIN_OS" | tee -a "$GITHUB_STEP_SUMMARY"

# Linux: the static OpenSSL only changes with its version.
- name: Cache OpenSSL
if: runner.os == 'Linux' && env.OPENSSL_VERSION != ''
uses: actions/cache@v6
with:
path: ${{ inputs.package }}-work/openssl
key: openssl-${{ env.OPENSSL_VERSION }}-${{ inputs.platform }}-manylinux_2_28-no-dso

# Linux: in the manylinux_2_28 container (AlmaLinux 8), so the binaries run on glibc 2.28+.
- name: Build
if: runner.os == 'Linux'
run: |
arch=x86_64; [[ "$PLATFORM" == linux-arm64 ]] && arch=aarch64
docker run --rm -v "$PWD:/w" -w /w -e OPENSSL_VERSION -e GITHUB_TOKEN \
"quay.io/pypa/manylinux_2_28_$arch" bash "packages/$PKG/linux/build.sh" "$VERSION" out
sudo chown -R "$(id -u):$(id -g)" .

- name: Portability (readelf)
if: runner.os == 'Linux'
run: bash scripts/verify-linux.sh out "$MIN_GLIBC" | tee -a "$GITHUB_STEP_SUMMARY"

# Windows Valkey: MSYS2 provides fork() (packages/valkey/windows/build.sh).
- uses: msys2/setup-msys2@v2
if: runner.os == 'Windows' && inputs.package == 'valkey'
Expand Down Expand Up @@ -156,11 +178,12 @@ jobs:
retention-days: 7

# A clean runner: on macOS the oldest Apple Silicon image with Homebrew moved away (closest to
# a user's Mac); on Windows without MSYS2 runtimes on PATH, so only the bundled DLLs are used.
# a user's Mac); on Windows without MSYS2 runtimes on PATH, so only the bundled DLLs are used;
# on Linux an almalinux:8 container (the oldest glibc the build targets, nothing installed).
test:
name: run ${{ inputs.package }} ${{ inputs.version }} ${{ inputs.platform }}
needs: build
runs-on: ${{ inputs.platform == 'windows-x64' && 'windows-2022' || 'macos-14' }}
runs-on: ${{ fromJSON('{"windows-x64":"windows-2022","linux-x64":"ubuntu-24.04","linux-arm64":"ubuntu-24.04-arm"}')[inputs.platform] || 'macos-14' }}
timeout-minutes: 20
env:
ASSET: ${{ needs.build.outputs.asset }}
Expand All @@ -175,6 +198,13 @@ jobs:
- name: Smoke test
if: runner.os == 'macOS'
run: bash scripts/smoke-service.sh "$PKG" "$ASSET"
# As the runner's user, known to the container (initdb looks it up): PostgreSQL refuses root.
- name: Smoke test
if: runner.os == 'Linux'
run: |
docker run --rm --user "$(id -u):$(id -g)" -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
-v "$PWD:/w" -w /w almalinux:8 \
bash scripts/smoke-service.sh "$PKG" "$ASSET"
- name: Remove other MSYS runtimes from PATH
if: runner.os == 'Windows'
shell: pwsh
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ jobs:
- name: Check
run: |
go -C tools/flockrel run . check -versions ../../versions.json -php-build ../../packages/php/macos/build.sh \
-out "$RUNNER_TEMP/findings.json" 2>&1 | tee -a "$GITHUB_STEP_SUMMARY"
-php-build-linux ../../packages/php/linux/build.sh -out "$RUNNER_TEMP/findings.json" 2>&1 | tee -a "$GITHUB_STEP_SUMMARY"
- name: Issues
run: bash scripts/upstream-issues.sh "$RUNNER_TEMP/findings.json" | tee -a "$GITHUB_STEP_SUMMARY"
6 changes: 3 additions & 3 deletions .github/workflows/mirror.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ on:
platform:
description: Platform
type: choice
options: [macos-arm64, windows-x64]
options: [macos-arm64, windows-x64, linux-x64, linux-arm64]
publish:
description: Publish the package as a release asset
type: boolean
Expand Down Expand Up @@ -86,7 +86,7 @@ jobs:
test:
name: run ${{ inputs.package }} ${{ inputs.version }} ${{ inputs.platform }}
needs: fetch
runs-on: ${{ inputs.platform == 'windows-x64' && 'windows-2022' || 'macos-15' }}
runs-on: ${{ fromJSON('{"windows-x64":"windows-2022","linux-x64":"ubuntu-24.04","linux-arm64":"ubuntu-24.04-arm"}')[inputs.platform] || 'macos-15' }}
timeout-minutes: 20
env:
ASSET: ${{ needs.fetch.outputs.asset }}
Expand All @@ -103,7 +103,7 @@ jobs:
if: runner.os == 'macOS'
run: sudo mv /opt/homebrew /opt/homebrew.hidden
- name: Smoke test
if: runner.os == 'macOS'
if: runner.os != 'Windows'
run: bash scripts/smoke-service.sh "$PKG" "$ASSET"
- name: Smoke test
if: runner.os == 'Windows'
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Flock downloads https://github.com/<repo>/releases/download/manifest/manifest.json (+ .sig), or
# manifest-beta.json / manifest-experimental.json for those channels.
# php-macos PHP and FrankenPHP for macOS (build-php-macos.yml)
# php-linux PHP for Linux, x86-64 and arm64 (build-php-linux.yml)
# php-exts-windows extension packs for Windows PHP, one per minor (build-php-exts-windows.yml)
# frankenphp-windows FrankenPHP for Windows (build-frankenphp-windows.yml)
# builds services built from source: PostgreSQL, MariaDB (macOS), Valkey, Redis (build-service.yml)
Expand Down Expand Up @@ -34,6 +35,7 @@ jobs:
outputs:
any: ${{ steps.plan.outputs.any }}
php_macos: ${{ steps.plan.outputs.php_macos }}
php_linux: ${{ steps.plan.outputs.php_linux }}
php_exts_windows: ${{ steps.plan.outputs.php_exts_windows }}
frankenphp_windows: ${{ steps.plan.outputs.frankenphp_windows }}
builds: ${{ steps.plan.outputs.builds }}
Expand Down Expand Up @@ -67,6 +69,21 @@ jobs:
publish: true
optional: ${{ matrix.optional == true }}

php-linux:
needs: plan
if: needs.plan.outputs.php_linux != '[]'
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.plan.outputs.php_linux) }}
permissions:
contents: write
uses: ./.github/workflows/build-php-linux.yml
with:
version: ${{ matrix.version }}
platform: ${{ matrix.platform }}
publish: true

php-exts-windows:
needs: plan
if: needs.plan.outputs.php_exts_windows != '[]'
Expand Down Expand Up @@ -132,7 +149,7 @@ jobs:
publish: true

manifest:
needs: [plan, php-macos, php-exts-windows, frankenphp-windows, builds, mirrors]
needs: [plan, php-macos, php-linux, php-exts-windows, frankenphp-windows, builds, mirrors]
# Also after failed builds: whatever did get published belongs in the manifests.
if: always() && needs.plan.result == 'success'
permissions:
Expand Down
Loading