Skip to content

Build PHP Extensions #33

Build PHP Extensions

Build PHP Extensions #33

Workflow file for this run

name: Build PHP Extensions
on:
workflow_dispatch:
inputs:
max_extensions:
description: 'Maximum number of extensions to process at once'
required: false
default: '200'
type: string
extensions:
description: 'Comma-separated extension names to process (optional)'
required: false
default: ''
type: string
jobs:
compile-extensions:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Process Extensions
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MAX_COUNT: ${{ github.event.inputs.max_extensions }}
EXTENSIONS: ${{ github.event.inputs.extensions }}
run: |
#!/bin/bash
# Locale for correct UTF-8 rendering
export LC_ALL=C.UTF-8
export LANG=C.UTF-8
# Strict mode (without command tracing)
set -e
echo "▶️ Start: compile all extensions (max: ${MAX_COUNT:-200})"
[ -n "${EXTENSIONS// }" ] && echo "📝 Requested extensions: ${EXTENSIONS}"
# Function to trigger workflow for a single extension
trigger_extension_workflow() {
local extension_name="$1"
local php_versions="$2"
# Ensure matrix.json is present
if [ ! -f "extension/BuildPhpExtension/config/matrix.json" ]; then
echo "❌ matrix.json not found"
return 1
fi
# Read extension source
local repo
repo=$(jq -r ".$extension_name.source // empty" "extension/BuildPhpExtension/config/matrix.json" 2>/dev/null || echo "")
if [ -z "$repo" ] || [ "$repo" = "null" ]; then
echo "❌ Source for $extension_name not found"
return 1
fi
# Group by extension version (one ext version → list of compatible PHP versions)
IFS=',' read -ra php_version_list <<< "$php_versions"
declare -A ext_groups
invalid_versions=()
for php_version in "${php_version_list[@]}"; do
php_version=$(echo "$php_version" | xargs)
local ext_version
ext_version=$(jq -r ".$extension_name.ver.\"$php_version\" // empty" "extension/BuildPhpExtension/config/matrix.json" 2>/dev/null || echo "")
if [ -z "$ext_version" ] || [ "$ext_version" = "null" ]; then
invalid_versions+=("$php_version")
else
if [ -z "${ext_groups[$ext_version]+_}" ]; then
ext_groups[$ext_version]="$php_version"
else
ext_groups[$ext_version]="${ext_groups[$ext_version]},$php_version"
fi
fi
done
if [ ${#ext_groups[@]} -eq 0 ]; then
echo "⚠️ $extension_name — no valid PHP versions in matrix.json"
return 1
fi
# Trigger workflow for each extension version
local total_workflows=0
for ext_version in "${!ext_groups[@]}"; do
php_versions_for_ext="${ext_groups[$ext_version]}"
# ts/nts by extension name
if [[ "$extension_name" == *"parallel"* ]]; then
ts_list="ts"
elif [[ "$extension_name" == *"wincache"* ]]; then
ts_list="nts"
else
ts_list="nts,ts"
fi
# Choose parameter name: URL or source name
if [[ "$repo" =~ ^https?:// ]]; then
param_name="extension-url"
param_value="$repo"
else
param_name="extension-name"
param_value="$repo"
fi
json_payload="{
\"ref\": \"master\",
\"inputs\": {
\"$param_name\": \"$param_value\",
\"extension-ref\": \"$ext_version\",
\"php-version-list\": \"$php_versions_for_ext\",
\"arch-list\": \"x64\",
\"ts-list\": \"$ts_list\"
}
}"
# GitHub API request (quiet)
response=$(curl -s -w "\n%{http_code}" \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/OSPanel/php-windows-builder/actions/workflows/pecl.yml/dispatches \
-d "$json_payload")
http_code=$(echo "$response" | tail -n1)
if [ "$http_code" = "204" ]; then
echo " ✅ $extension_name @ $ext_version → PHP [$php_versions_for_ext]"
((total_workflows++))
else
response_body=$(echo "$response" | head -n -1)
echo " ❌ $extension_name @ $ext_version → API $http_code"
[ -n "$response_body" ] && echo " ↳ $response_body"
return 1
fi
# Small delay between versions of the same extension
if [ $total_workflows -lt ${#ext_groups[@]} ]; then
sleep 1
fi
done
# Warn about skipped PHP versions
if [ ${#invalid_versions[@]} -gt 0 ]; then
invalid_versions_string=$(IFS=', '; echo "${invalid_versions[*]}")
echo " ⚠️ Skipped PHP versions: $invalid_versions_string"
fi
return 0
}
# Main logic
matrix_path="extension/BuildPhpExtension/config/matrix.json"
max_count="${MAX_COUNT:-200}"
# Validate inputs and matrix.json
if ! [[ "$max_count" =~ ^[0-9]+$ ]]; then
echo "❌ max_extensions must be a number, got: $max_count"
exit 1
fi
if [ ! -f "$matrix_path" ]; then
echo "❌ File not found: $matrix_path"
exit 1
fi
# Read all extension keys from matrix
all_extensions=$(jq -r 'keys[]' "$matrix_path" 2>/dev/null || echo "")
if [ -z "$all_extensions" ]; then
echo "❌ Failed to read extensions list from matrix.json"
exit 1
fi
readarray -t all_extensions_array <<< "$all_extensions"
if [ ${#all_extensions_array[@]} -eq 0 ]; then
echo "❌ No extensions found in matrix.json"
exit 1
fi
# Build processing list
to_process=()
if [ -n "${EXTENSIONS// }" ]; then
declare -a selected=()
declare -a unknown=()
IFS=',' read -ra requested <<< "$EXTENSIONS"
for name in "${requested[@]}"; do
name="$(echo "$name" | xargs)"
[ -z "$name" ] && continue
if jq -e --arg n "$name" 'has($n)' "$matrix_path" >/dev/null; then
selected+=("$name")
else
unknown+=("$name")
fi
done
if [ ${#unknown[@]} -gt 0 ]; then
echo "⚠️ Unknown extensions (skipped): ${unknown[*]}"
fi
if [ ${#selected[@]} -eq 0 ]; then
echo "❌ No valid extensions supplied in 'extensions' input"
exit 1
fi
# Apply max limit
to_process=("${selected[@]:0:$max_count}")
else
# Fallback to previous behavior (first N from matrix)
to_process=("${all_extensions_array[@]:0:$max_count}")
fi
total_extensions=${#to_process[@]}
echo "📦 Extensions to process: $total_extensions"
echo "🧾 List: ${to_process[*]}"
# Prepare
successfully_processed=()
failed_extensions=()
versions="7.2,7.3,7.4,8.0,8.1,8.2,8.3,8.4"
current_extension=0
# Do not fail the entire job on a single iteration error
set +e
for extension in "${to_process[@]}"; do
((current_extension++)) || true
echo "➡️ [$current_extension/$total_extensions] $extension"
trigger_extension_workflow "$extension" "$versions"
rc=$?
if [ $rc -eq 0 ]; then
successfully_processed+=("$extension")
else
failed_extensions+=("$extension")
fi
# Delay between extensions for API friendliness
if [ $current_extension -lt $total_extensions ]; then
sleep 2
fi
done
set -e
# Summary
echo "—"
echo "✅ Succeeded: ${#successfully_processed[@]}"
echo "❌ Failed: ${#failed_extensions[@]}"
if [ ${#failed_extensions[@]} -gt 0 ]; then
echo "🔁 Failed list: ${failed_extensions[*]}"
fi
# Fail only if everything failed
if [ ${#successfully_processed[@]} -eq 0 ] && [ ${#to_process[@]} -gt 0 ]; then
echo "❌ All extensions failed"
exit 1
fi
echo "🎉 Done!"