Skip to content

Build and upload Alpine APK packages to Forgejo #177

Build and upload Alpine APK packages to Forgejo

Build and upload Alpine APK packages to Forgejo #177

name: Build and upload Alpine APK packages to Forgejo
on:
workflow_dispatch:
inputs:
iteration:
description: "Optional: override package iteration (integer). Leave empty for auto"
required: false
default: ""
php_versions:
description: "Optional: PHP versions (comma-separated, e.g., 8.2,8.5). Leave empty for all"
required: false
default: ""
architectures:
description: "Optional: Architectures (comma-separated, e.g., x86_64,aarch64). Leave empty for all"
required: false
default: ""
packages:
description: "Optional: override packages list. Leave empty for default"
required: false
default: ""
debug_tmate:
description: "Open tmate session on failure"
type: boolean
required: false
default: false
repository_dispatch:
types: [spc-download]
permissions:
contents: read
packages: read
jobs:
setup-matrix:
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
libs-pairs: ${{ steps.set-matrix.outputs.libs-pairs }}
php-versions: ${{ steps.set-matrix.outputs.php-versions }}
steps:
- name: Set up matrix
id: set-matrix
run: |
default_php='["8.2","8.3","8.4","8.5"]'
default_arch='["x86_64","aarch64"]'
if [[ -n "${INPUTS_PHP_VERSIONS}" ]]; then
php_versions=$(echo "${INPUTS_PHP_VERSIONS}" | jq -Rc 'split(",") | map(gsub("^\\s+|\\s+$";""))')
else
php_versions=$default_php
fi
if [[ -n "${INPUTS_ARCHITECTURES}" ]]; then
arch_versions=$(echo "${INPUTS_ARCHITECTURES}" | jq -Rc 'split(",") | map(gsub("^\\s+|\\s+$";""))')
else
arch_versions=$default_arch
fi
libs_pairs=$(jq -nc --argjson arch "$arch_versions" '{include: [$arch[] as $r | {arch: $r}]}')
echo "libs-pairs=$libs_pairs" >> $GITHUB_OUTPUT
echo "php-versions=$php_versions" >> $GITHUB_OUTPUT
env:
INPUTS_PHP_VERSIONS: ${{ inputs.php_versions }}
INPUTS_ARCHITECTURES: ${{ inputs.architectures }}
build-libs:
needs: setup-matrix
name: Build libs (${{ matrix.arch }})
runs-on: ${{ matrix.arch == 'x86_64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
container:
image: ghcr.io/static-php/packages-builder-alpine:latest
permissions:
contents: write
packages: read
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup-matrix.outputs.libs-pairs) }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Compute buildroot cache key
id: cache-key
run: |
set -euo pipefail
WEEK=$(date -u +%G-%V)
echo "key=buildroot-apk-${{ matrix.arch }}-${WEEK}" >> $GITHUB_OUTPUT
- name: Restore buildroot cache
id: cache
uses: ./.github/actions/buildroot-cache
with:
mode: restore
key: ${{ steps.cache-key.outputs.key }}
- name: Prepare cache directories
if: steps.cache.outputs.cache-hit != 'true'
run: composer config -g cache-dir
- name: Cache Composer downloads
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.cache/composer
key: composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
composer-
- name: Install vendor
if: steps.cache.outputs.cache-hit != 'true'
run: composer install --no-interaction --prefer-dist --no-progress
- name: Download artifact from spc-download.yml
if: steps.cache.outputs.cache-hit != 'true'
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11
with:
workflow: spc-download.yml
name: downloads-tarball
branch: master
search_artifacts: true
- name: Extract with permissions
if: steps.cache.outputs.cache-hit != 'true'
run: |
mkdir -p downloads
tar -xzf downloads.tar.gz -C downloads
rm downloads.tar.gz
- name: Build libs
if: steps.cache.outputs.cache-hit != 'true'
run: bin/spp build --target="native-native-musl -dynamic" --phpv=8.5 --type=apk --libs-only
- name: Pack buildroot
if: steps.cache.outputs.cache-hit != 'true'
run: tar --zstd -cf buildroot.tar.zst buildroot
- name: Save buildroot cache
if: steps.cache.outputs.cache-hit != 'true'
uses: ./.github/actions/buildroot-cache
with:
mode: save
key: ${{ steps.cache-key.outputs.key }}
- name: Upload logs on failure
if: ${{ failure() }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: build-logs-libs-${{ matrix.arch }}
path: log
- name: Setup tmate session
if: ${{ failure() && inputs.debug_tmate == true }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3
timeout-minutes: 30
compute-build-matrix:
needs: [setup-matrix, build-libs]
runs-on: ubuntu-24.04
if: ${{ !cancelled() }}
permissions:
actions: read
outputs:
matrix: ${{ steps.filter.outputs.matrix }}
any: ${{ steps.filter.outputs.any }}
steps:
- name: Filter build matrix to arches with successful libs
id: filter
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PHP_VERSIONS: ${{ needs.setup-matrix.outputs.php-versions }}
run: |
set -euo pipefail
succeeded=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/jobs" --paginate \
--jq '.jobs[] | select(.conclusion == "success" and (.name | test("^Build libs \\("))) | .name' \
| sed -E 's/^Build libs \(([^)]+)\)$/\1/' \
| sort -u)
echo "Successful libs arches:"
printf '%s\n' "$succeeded"
include=$(jq -nc --arg s "$succeeded" --argjson p "$PHP_VERSIONS" '
($s | split("\n") | map(select(length > 0) | {arch: .})) as $arches |
[ $arches[] as $a | $p[] as $php | $a + {"php-version": $php} ]
')
count=$(jq 'length' <<< "$include")
echo "Filtered combos: $count"
printf '%s\n' "$include" | jq .
if [[ "$count" -gt 0 ]]; then
echo "any=true" >> $GITHUB_OUTPUT
else
echo "any=false" >> $GITHUB_OUTPUT
fi
echo "matrix={\"include\":$include}" >> $GITHUB_OUTPUT
build:
needs: [compute-build-matrix]
if: ${{ !cancelled() && needs.compute-build-matrix.outputs.any == 'true' }}
name: Build for ${{ matrix.arch }} PHP ${{ matrix.php-version }}
runs-on: ${{ matrix.arch == 'x86_64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
container:
image: ghcr.io/static-php/packages-builder-alpine:latest
permissions:
contents: read
packages: read
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.compute-build-matrix.outputs.matrix) }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ITERATION: ${{ inputs.iteration || '' }}
PACKAGES: ${{ inputs.packages || '' }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Set PHP version short
run: |
# Convert "8.5" to "85"
PHP_VERSION_SHORT=$(echo "${{ matrix.php-version }}" | tr -d '.')
echo "PHP_VERSION_SHORT=$PHP_VERSION_SHORT" >> $GITHUB_ENV
- name: Prepare cache directories
run: composer config -g cache-dir
- name: Cache Composer downloads
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.cache/composer
key: composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
composer-
- name: Install vendor
run: composer install --no-interaction --prefer-dist --no-progress
- name: Download artifact from spc-download.yml
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11
with:
workflow: spc-download.yml
name: downloads-tarball
branch: master
search_artifacts: true
- name: Extract with permissions
run: |
mkdir -p downloads
tar -xzf downloads.tar.gz -C downloads
rm downloads.tar.gz
- name: Compute buildroot cache key
id: cache-key
run: |
set -euo pipefail
WEEK=$(date -u +%G-%V)
echo "key=buildroot-apk-${{ matrix.arch }}-${WEEK}" >> $GITHUB_OUTPUT
- name: Restore buildroot cache
uses: ./.github/actions/buildroot-cache
with:
mode: restore
key: ${{ steps.cache-key.outputs.key }}
fail-on-cache-miss: true
- name: Extract buildroot
run: |
tar --zstd -xf buildroot.tar.zst
rm buildroot.tar.zst
- name: Build PHP packages
run: |
PACKAGES_FLAG=""
if [[ -n "${{ env.PACKAGES }}" ]]; then
PACKAGES_FLAG="--packages=${{ env.PACKAGES }}"
fi
ITERATION_FLAG=""
if [[ -n "${ITERATION}" ]]; then
ITERATION_FLAG="--iteration=${ITERATION}"
fi
php bin/spp all --target="native-native-musl -dynamic" --phpv=${{ matrix.php-version }} --prefix="-zts" --type=apk $ITERATION_FLAG $PACKAGES_FLAG
- name: Upload logs on failure
if: ${{ failure() }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: build-logs-${{ matrix.arch }}-php${{ matrix.php-version }}
path: log
- name: Upload to Forgejo Host 1
working-directory: dist/apk
run: |
echo "listing from host 1"
../../bin/forgejo-helper list alpine "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.apk"
echo "uploading to host 1"
../../bin/forgejo-helper upload alpine "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.apk"
- name: Upload to Forgejo Host 2
working-directory: dist/apk
continue-on-error: true
run: |
echo "listing from host 2"
../../bin/forgejo-helper --host=2 list alpine "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.apk"
echo "uploading to host 2"
../../bin/forgejo-helper --host=2 upload alpine "${{ env.PHP_VERSION_SHORT }}" "${{ secrets.FORGEJO_PASSWORD }}" "*.apk"
- name: Setup tmate session
if: ${{ failure() && inputs.debug_tmate == true }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3
timeout-minutes: 30