Build PHP Extensions #33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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!" | |