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
176 changes: 176 additions & 0 deletions .github/workflows/build-php-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# 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 <package>-<version> release as
# <package>-<version>-build<N>-<platform>.tar.gz:
# php bin/php and bin/php-fpm (build number: php.linux.build)
# frankenphp bin/frankenphp with the same PHP embedded, thread-safe (frankenphp.linux.build,
# FrankenPHP release: frankenphp.version)
# Both get the compiled-in extensions and the shared ones in ext/ from php.linux in versions.json.
# 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
package:
type: string
default: php
platform:
type: string
required: true
publish:
type: boolean
default: false
# FrankenPHP on a PHP release candidate: a failure is a warning (release.yml tries again the next day).
optional:
type: boolean
default: false
workflow_dispatch:
inputs:
version:
description: PHP version (major.minor.patch)
required: true
package:
description: What to build
type: choice
options: [php, frankenphp]
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 }}
PKG: ${{ inputs.package }}
PLATFORM: ${{ inputs.platform }}

jobs:
build:
name: build ${{ inputs.package }} ${{ inputs.version }} ${{ inputs.platform }}
runs-on: ${{ inputs.platform == 'linux-arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
timeout-minutes: 150
continue-on-error: ${{ inputs.optional == true }}
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"
case "$PKG" in
php) build="$(jq -r .php.linux.build versions.json)" ;;
frankenphp)
build="$(jq -r .frankenphp.linux.build versions.json)"
echo "TARGET=frankenphp" >> "$GITHUB_ENV"
echo "FRANKENPHP_VERSION=$(jq -r .frankenphp.version versions.json)" >> "$GITHUB_ENV" ;;
*) echo "::error::unknown package $PKG"; exit 1 ;;
esac
echo "BUILD=$build" >> "$GITHUB_ENV"
asset="$PKG-$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.package }}-${{ 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 "$PKG" out

- name: Package
run: |
jq -n --arg package "$PKG" --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 frankenphp "${FRANKENPHP_VERSION:-}" --arg built "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'{package: $package, 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(","))}}
+ (if $frankenphp != "" then {frankenphp: $frankenphp} else {} end)' \
> 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"
- if: failure() && inputs.optional
run: echo "::warning::$PKG for PHP $VERSION (a release candidate) didn't build; the next release run tries again"

# The oldest glibc the build targets, without anything the runner has installed.
portable:
name: run ${{ inputs.package }} ${{ 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' }}
continue-on-error: ${{ inputs.optional == true }}
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 -e VERSION centos:7 \
bash scripts/smoke-php-package.sh "$PKG" 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 "$PKG" "$VERSION" "$ASSET"
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
21 changes: 20 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 and FrankenPHP 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,23 @@ 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 }}
package: ${{ matrix.package }}
platform: ${{ matrix.platform }}
publish: true
optional: ${{ matrix.optional == true }}

php-exts-windows:
needs: plan
if: needs.plan.outputs.php_exts_windows != '[]'
Expand Down Expand Up @@ -132,7 +151,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
55 changes: 35 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,44 @@ signed manifest, so nothing has to be compiled on your machine.

## What we publish

Platforms are macOS on Apple Silicon (`macos-arm64`, macOS 13+) and Windows x64 (`windows-x64`).
Platforms are macOS on Apple Silicon (`macos-arm64`, macOS 13+), Windows x64 (`windows-x64`) and,
for some packages so far, Linux on x86-64 and arm64 (`linux-x64`, `linux-arm64`).
Every package is either **built** here from verified upstream source, or **mirrored**: the
vendor's own binaries, checked against the vendor's checksum or signature.

| Package | macOS arm64 | Windows x64 | Versions (`versions.json`) |
|---|---|---|---|
| `php` | built: cli + fpm, extensions compiled in, optional ones in `ext/` | mirrored: the official thread-safe build from windows.php.net | macOS 8.1–8.5, Windows 7.4–8.5 |
| `php-exts` | – | built: extension DLLs for the Windows build (below) | one pack per Windows minor |
| `frankenphp` | built: FrankenPHP with the same PHP and extensions as `php` | built: FrankenPHP next to the official PHP build it links against | PHP 8.2–8.5 |
| `postgres` | built: server, client tools (psql, pg_dump, …), contrib | built | 14–18 |
| `mariadb` | built | mirrored | 10.11, 11.4, 11.8, 12.3 |
| `mysql` | mirrored | mirrored | 8.0, 8.4, 9.7 |
| `mongodb` | mirrored | mirrored | 7.0, 8.0, 9.0 |
| `valkey` | built | built with MSYS2 (`fork()` for persistence) | 9.1 |
| `redis` | built | – (Valkey only) | 7.2, 7.4, 8.4, 8.10 |
| `meilisearch` | mirrored (Community Edition) | mirrored (Community Edition) | 1 |
| `typesense` | mirrored | – (no Windows build upstream) | 29, 30 |
| `rustfs` | mirrored | mirrored | 1 |
| `node` | mirrored | mirrored | 16, 18, 20, 22, 24, 26 |
| Package | macOS arm64 | Windows x64 | Linux x64, arm64 | Versions (`versions.json`) |
|---|---|---|---|---|
| `php` | built: cli + fpm, extensions compiled in, optional ones in `ext/` | mirrored: the official thread-safe build from windows.php.net | built, like macOS (glibc 2.17+, see below) | macOS 8.1–8.5, Linux 8.2–8.5, Windows 7.4–8.5 |
| `php-exts` | – | built: extension DLLs for the Windows build (below) | – | one pack per Windows minor |
| `frankenphp` | built: FrankenPHP with the same PHP and extensions as `php` | built: FrankenPHP next to the official PHP build it links against | built, like macOS | PHP 8.2–8.5 |
| `postgres` | built: server, client tools (psql, pg_dump, …), contrib | built | – | 14–18 |
| `mariadb` | built | mirrored | – | 10.11, 11.4, 11.8, 12.3 |
| `mysql` | mirrored | mirrored | – | 8.0, 8.4, 9.7 |
| `mongodb` | mirrored | mirrored | – | 7.0, 8.0, 9.0 |
| `valkey` | built | built with MSYS2 (`fork()` for persistence) | – | 9.1 |
| `redis` | built | – (Valkey only) | – | 7.2, 7.4, 8.4, 8.10 |
| `meilisearch` | mirrored (Community Edition) | mirrored (Community Edition) | mirrored (Community Edition) | 1 |
| `typesense` | mirrored | – (no Windows build upstream) | mirrored | 29, 30 |
| `rustfs` | mirrored | mirrored | mirrored (static musl build) | 1 |
| `node` | mirrored | mirrored | mirrored | 16, 18, 20, 22, 24, 26 |

The versions column lists release lines: every day the newest upstream release of each line is
looked up (`tools/flockrel/upstream.go`, php.net and windows.php.net for PHP) and built or mirrored
when it isn't published yet. Patch releases come in on their own; a new line (PostgreSQL 19, Node.js
28, PHP 8.6) is one entry in `versions.json`.

### PHP for Linux

`php` for `linux-x64` and `linux-arm64` is built like the macOS one, with static-php-cli and the
same extensions (`php.linux`), but in static-php-cli's glibc container (`bin/spc-gnu-docker`: CentOS
7, glibc 2.17). Every library but glibc's is compiled in, and unlike a fully static musl build, PHP
loads the shared extensions in `ext/`. Before publishing, `scripts/verify-linux.sh` checks that no
binary needs a newer glibc or another shared library, and the smoke test runs again in a `centos:7`
container. Linux starts at PHP 8.2: 8.1 had reached its end of life, and its headers need
`_GNU_SOURCE`, which the mongodb extension's `-std=c17` build doesn't get from 8.1's `php_config.h`.
FrankenPHP is built the same way, thread-safe with PHP embedded (`TARGET=frankenphp`,
`frankenphp.linux.build`).

### PHP release candidates

A PHP minor in `versions.json` that has no release yet gets its release candidates instead
Expand Down Expand Up @@ -75,16 +88,16 @@ read its configure option from, so `--enable-opentelemetry` is passed explicitly

### Package layouts

Archives are `.tar.gz` on macOS and `.zip` on Windows. Mirrored packages keep the vendor's layout,
Archives are `.tar.gz` on macOS and Linux and `.zip` on Windows. Mirrored packages keep the vendor's layout,
usually one top-level folder (`mysql-8.4.11-macos15-arm64/bin/mysqld`); unpack and drop it. What we
build has `flock-package.json` at the top (what it is, how it was built) and `LICENSES/`.

| Package | Layout |
|---|---|
| `php` (macOS) | `bin/php`, `bin/php-fpm`, `ext/*.so` |
| `php` (macOS, Linux) | `bin/php`, `bin/php-fpm`, `ext/*.so` |
| `php` (Windows) | the official zip: `php.exe`, `php-cgi.exe`, `ext/` |
| `php-exts` | `ext/php_<name>.dll` into PHP's `ext\`; `*.dll` next to `php.exe` (ImageMagick) |
| `frankenphp` (macOS) | `bin/frankenphp`, `ext/*.so` |
| `frankenphp` (macOS, Linux) | `bin/frankenphp`, `ext/*.so` |
| `frankenphp` (Windows) | `frankenphp.exe` next to the official PHP build of the same version |
| `postgres` | `bin/`, `lib/`, `share/` (relocatable) |
| `mariadb` (macOS) | `bin/`, `scripts/mariadb-install-db`, `share/`, `lib/plugin/`; run with `--basedir` |
Expand Down Expand Up @@ -126,6 +139,7 @@ the same version.
| `promote.yml` | records a channel decision (promote, hold, yank) in `channels.json` |
| `check.yml` | weekly: new release lines, end of life, newer pinned versions as issues |
| `build-php-macos.yml` | `php` and `frankenphp` for macOS (static-php-cli) |
| `build-php-linux.yml` | `php` and `frankenphp` for Linux (static-php-cli, glibc container) |
| `build-php-exts-windows.yml` | `php-exts` for one PHP minor |
| `build-frankenphp-windows.yml` | `frankenphp` for Windows |
| `build-service.yml` | PostgreSQL, MariaDB (macOS), Valkey, Redis from source |
Expand Down Expand Up @@ -162,7 +176,7 @@ Every published build is in one of three channels, and each channel has its own
listing the builds at its level or above:

| Channel | Manifest | Who | Contains |
|---|---|---|---|
|---|---|---|---|---|
| stable | `manifest.json` | every Flock installation | what has been promoted |
| beta | `manifest-beta.json` | opt-in in Flock | stable, patches in their waiting time, approved new lines, pre-releases |
| experimental | `manifest-experimental.json` | testing before promotion | everything published |
Expand Down Expand Up @@ -268,5 +282,6 @@ scripts/publish.sh upload a package (and its sources) to its relea
scripts/ready-issue.sh keep the Ready for testing issue up to date
scripts/upstream-issues.sh turn the weekly check's findings into issues
scripts/verify-macos.sh fails when a Mach-O file links outside macOS or targets macOS > 13
scripts/verify-linux.sh fails when an ELF file needs a library beyond glibc's or glibc > 2.17
scripts/smoke-*.sh smoke tests run against every package before it is published
```
2 changes: 2 additions & 0 deletions packages/meilisearch/mirror.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ V="$1"; PLATFORM="$2"; OUT="$3"
case "$PLATFORM" in
macos-arm64) asset=meilisearch-macos-apple-silicon; bin=meilisearch ;;
windows-x64) asset=meilisearch-windows-amd64.exe; bin=meilisearch.exe ;;
linux-x64) asset=meilisearch-linux-amd64; bin=meilisearch ;;
linux-arm64) asset=meilisearch-linux-aarch64; bin=meilisearch ;;
esac
dir="$(mktemp -d)"
fetch "https://github.com/meilisearch/meilisearch/releases/download/v$V/$asset" "$dir/$bin"
Expand Down
2 changes: 2 additions & 0 deletions packages/node/mirror.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ V="$1"; PLATFORM="$2"; OUT="$3"
case "$PLATFORM" in
macos-arm64) name="node-v$V-darwin-arm64.tar.gz" ;;
windows-x64) name="node-v$V-win-x64.zip" ;;
linux-x64) name="node-v$V-linux-x64.tar.gz" ;;
linux-arm64) name="node-v$V-linux-arm64.tar.gz" ;;
esac
tmp="$(mktemp -d)"
base="https://nodejs.org/dist/v$V"
Expand Down
Loading