diff --git a/.github/workflows/php-fpm.yml b/.github/workflows/php-fpm.yml index 24720df..0e185b2 100644 --- a/.github/workflows/php-fpm.yml +++ b/.github/workflows/php-fpm.yml @@ -3,159 +3,130 @@ name: php-fpm-build on: push: branches: [main] + paths: + - "php-fpm/**" + - "shared/php-fpm/**" + - ".github/workflows/php-fpm.yml" pull_request: branches: [main] + paths: + - "php-fpm/**" + - "shared/php-fpm/**" + - ".github/workflows/php-fpm.yml" workflow_dispatch: inputs: lane: - description: 'Lane to build (e.g. 7.4). Use "all" to build all lanes.' + description: 'Lane to build (e.g. 7.4). Use "all" to build all lanes. Leave blank to build based on changes' required: false default: "" - workflow_call: - secrets: - REGISTRY_TOKEN: - required: true - description: "Token for registry authentication." jobs: - plan: + build: runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.compute.outputs.matrix }} - should_build: ${{ steps.compute.outputs.should_build }} + strategy: + fail-fast: false + matrix: + # This matrix will be dynamically populated by the 'lanes' job + lane: [] steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 with: + # Fetch all history for accurate change detection fetch-depth: 0 - - id: compute - shell: bash - run: | - set -euo pipefail + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - # discover lanes under php-fpm/* that contain a Dockerfile - mapfile -t ALL_LANES < <(find php-fpm -mindepth 1 -maxdepth 1 -type d | sort) - FILTERED=() - for d in "${ALL_LANES[@]}"; do - if [[ -f "${d}/Dockerfile" ]]; then - FILTERED+=("${d}") - fi - done - ALL_LANES=("${FILTERED[@]}") - - if [[ ${#ALL_LANES[@]} -eq 0 ]]; then - echo "No php-fpm lanes found. Nothing to do." - echo "should_build=false" >> $GITHUB_OUTPUT - echo 'matrix={"dir":[]}' >> $GITHUB_OUTPUT - exit 0 - fi - - # allow workflow_dispatch lane selection - SELECTED=() - REQ_LANE="${{ github.event.inputs.lane || '' }}" - if [[ -n "$REQ_LANE" ]]; then - if [[ "$REQ_LANE" == "all" ]]; then - SELECTED=("${ALL_LANES[@]}") - else - candidate="php-fpm/$REQ_LANE" - if [[ -d "$candidate" && -f "$candidate/Dockerfile" ]]; then - SELECTED=("$candidate") - else - echo "ERROR: Requested lane '$REQ_LANE' not found under php-fpm/" >&2 - exit 1 - fi - fi - else - # Determine changed files - if [[ "${{ github.event_name }}" == "push" ]]; then - BASE_SHA="$(git rev-parse HEAD~1 2>/dev/null || true)" - HEAD_SHA="$(git rev-parse HEAD 2>/dev/null || true)" - elif [[ "${{ github.event_name }}" == "pull_request" ]]; then - BASE_SHA="${{ github.event.pull_request.base.sha }}" - HEAD_SHA="${{ github.event.pull_request.head.sha }}" - else - BASE_SHA="" - HEAD_SHA="$(git rev-parse HEAD 2>/dev/null || true)" - fi - - if [[ -n "$BASE_SHA" ]]; then - CHANGED=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA") - else - CHANGED=$(git ls-files) - fi - - # If workflow files changed, rebuild all lanes - if grep -q "^.github/workflows/" <<< "$CHANGED"; then - SELECTED=("${ALL_LANES[@]}") - else - for d in "${ALL_LANES[@]}"; do - if grep -q "^${d}/" <<< "$CHANGED"; then - SELECTED+=("${d}") - fi - done - fi - fi - - # Dedupe and validate - mapfile -t SELECTED < <(printf "%s\n" "${SELECTED[@]}" | awk 'NF && !x[$0]++') - if [[ ${#SELECTED[@]} -eq 0 ]]; then - echo "No php-fpm lanes to build." - echo "should_build=false" >> $GITHUB_OUTPUT - echo 'matrix={"dir":[]}' >> $GITHUB_OUTPUT - exit 0 - fi - - JSON=$(jq -nc --argjson arr "$(printf '%s\n' "${SELECTED[@]}" | jq -R . | jq -s .)" '{dir: $arr}') - echo "Matrix: $JSON" - echo "should_build=true" >> $GITHUB_OUTPUT - echo "matrix=$JSON" >> $GITHUB_OUTPUT - - build: - needs: plan - if: needs.plan.outputs.should_build == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: docker/setup-buildx-action@v3 - - - uses: docker/login-action@v3 + - name: Log in to the Container Registry + uses: docker/login-action@v3 with: registry: gitea.auvem.com username: ${{ vars.REGISTRY_USER || github.actor }} password: ${{ secrets.REGISTRY_TOKEN }} - - name: Show plan matrix - run: | - echo "Plan matrix: $MATRIX_JSON" - jq -C . dir <<< "$MATRIX_JSON" 2>/dev/null || true - env: - MATRIX_JSON: ${{ needs.plan.outputs.matrix }} + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: gitea.auvem.com/auvem/wordpress-docker/php-fpm + tags: | + type=raw,value={{matrix.lane}}-stable + type=raw,value={{matrix.lane}}-{{sha}} - - name: Build lanes - shell: bash - env: - MATRIX_JSON: ${{ needs.plan.outputs.matrix }} - GIT_SHA_SHORT: ${GITHUB_SHA::7} + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./php-fpm/${{ matrix.lane }}/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64 + + lanes: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get all PHP lanes + id: get-lanes run: | - set -euo pipefail - lanes=$(jq -r '.dir[]' <<< "$MATRIX_JSON") - for lane in $lanes; do - echo "Building lane: $lane" - if [[ ! -f "$lane/Dockerfile" ]]; then - echo "ERROR: missing Dockerfile for $lane" >&2 - exit 1 + lanes=$(find php-fpm -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | jq -R . | jq -s .) + echo "lanes=$lanes" >> $GITHUB_OUTPUT + shell: bash + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v44 + with: + files: | + php-fpm/** + shared/php-fpm/** + .github/workflows/php-fpm.yml + + - name: Determine lanes to build + id: set-matrix + run: | + all_lanes='${{ steps.get-lanes.outputs.lanes }}' + req_lane="${{ github.event.inputs.lane }}" + + build_all="false" + + # Handle workflow_dispatch input + if [[ -n "$req_lane" ]]; then + if [[ "$req_lane" == "all" ]]; then + build_all="true" + else + # Build only the requested lane + matrix="{\"lane\":[\"$req_lane\"]}" + echo "matrix=$matrix" >> $GITHUB_OUTPUT + exit 0 fi - NAME=$(basename "$lane") - if [[ ! "$NAME" =~ ^([0-9]+\.?[0-9]*)$ ]]; then - echo "ERROR: php-fpm lane name '$NAME' is not a numeric version" >&2 - exit 1 - fi - IMAGE="gitea.auvem.com/auvem/wordpress-docker/php-fpm" - TAG="$NAME" - echo "Computed: image=${IMAGE}, tags=${IMAGE}:${TAG},${IMAGE}:git-${GIT_SHA_SHORT}" - docker buildx build --push --platform linux/amd64 \ - --tag "${IMAGE}:${TAG}" \ - --tag "${IMAGE}:git-${GIT_SHA_SHORT}" \ - --file "$lane/Dockerfile" . - done + fi + + # Rebuild all if workflow or shared files changed + if [[ "${{ steps.changed-files.outputs.any_changed }}" == "true" ]]; then + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + if [[ "$file" == ".github/workflows/php-fpm.yml" || "$file" == shared/php-fpm/* ]]; then + build_all="true" + break + fi + done + fi + + if [[ "$build_all" == "true" ]]; then + matrix="{\"lane\":$all_lanes}" + else + # Determine changed lanes from php-fpm directory + changed_lanes=$(echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ' ' '\n' | grep '^php-fpm/' | cut -d'/' -f2 | sort -u | jq -R . | jq -s .) + matrix="{\"lane\":$changed_lanes}" + fi + + echo "matrix=$matrix" >> $GITHUB_OUTPUT + shell: bash