From 4067a6a74f055f56a91d008701c8df2e5f4d3fa7 Mon Sep 17 00:00:00 2001 From: nfebe Date: Sun, 8 Mar 2026 18:35:08 +0100 Subject: [PATCH] enh: Make laravel.mk extensible and add multi-arch builds Added hook variables (EXTRA_PORTS_SCRIPT, EXTRA_UP_INFO, TEST_CMD, LINT_CMD) so projects can customize behavior via include without overriding targets. Fixed DC variable to strip comments from .ports file and help target to deduplicate entries across multiple Makefiles. Added QEMU and linux/amd64,linux/arm64 platforms to the publish workflow so images work on Apple Silicon. --- .github/workflows/publish.yml | 87 +++++++++++++++++++++++++++++------ README.md | 37 +++++++++++++++ laravel.mk | 26 ++++++++--- 3 files changed, 131 insertions(+), 19 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 24a73d9..6664f2a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,8 +12,8 @@ env: IMAGE_NAME: whilesmartphp/laravel-dev jobs: - build-and-push: - runs-on: ubuntu-latest + build: + runs-on: ${{ matrix.runner }} permissions: contents: read packages: write @@ -21,6 +21,11 @@ jobs: strategy: matrix: php_version: ['8.2', '8.4'] + include: + - runner: ubuntu-latest + platform: linux/amd64 + - runner: ubuntu-24.04-arm + platform: linux/arm64 steps: - name: Checkout @@ -36,6 +41,64 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + context: . + platforms: ${{ matrix.platform }} + build-args: | + PHP_VERSION=${{ matrix.php_version }} + cache-from: type=gha,scope=${{ matrix.php_version }}-${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=${{ matrix.php_version }}-${{ matrix.platform }} + outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + + - name: Export digest + if: github.event_name != 'pull_request' + run: | + mkdir -p /tmp/digests/${{ matrix.php_version }} + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${{ matrix.php_version }}/${digest#sha256:}" + + - name: Upload digest + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: digest-${{ matrix.php_version }}-${{ matrix.runner }} + path: /tmp/digests/${{ matrix.php_version }} + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + needs: build + permissions: + contents: read + packages: write + + strategy: + matrix: + php_version: ['8.2', '8.4'] + + steps: + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Download digests + uses: actions/download-artifact@v4 + with: + pattern: digest-${{ matrix.php_version }}-* + merge-multiple: true + path: /tmp/digests + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Extract metadata id: meta uses: docker/metadata-action@v5 @@ -45,14 +108,12 @@ jobs: type=raw,value=${{ matrix.php_version }} type=raw,value=${{ matrix.php_version }}-{{sha}} - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - PHP_VERSION=${{ matrix.php_version }} - cache-from: type=gha - cache-to: type=gha,mode=max + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ matrix.php_version }} diff --git a/README.md b/README.md index 926adc7..10b42a9 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,43 @@ include laravel.mk Port resolution is automatic — `make up` finds available ports starting from 8000 and stores them in `.ports`. +### Customizing for Your Project + +`laravel.mk` exposes hook variables you can set **before** the `include` to customize behavior without overriding targets: + +```makefile +# Extra port defaults +DEFAULT_DB_PORT ?= 3306 +DEFAULT_PMA_PORT ?= 8080 + +# Add extra ports to .ports file +EXTRA_PORTS_SCRIPT = \ + DB_PORT=$$(port=$(DEFAULT_DB_PORT); while nc -z 127.0.0.1 $$port 2>/dev/null || lsof -i :$$port >/dev/null 2>&1; do port=$$((port + 1)); done; echo $$port); \ + PMA_PORT=$$(port=$(DEFAULT_PMA_PORT); while nc -z 127.0.0.1 $$port 2>/dev/null || lsof -i :$$port >/dev/null 2>&1; do port=$$((port + 1)); done; echo $$port); \ + echo "FORWARD_DB_PORT=$$DB_PORT" >> $(PORTS_FILE); \ + echo "PMA_PORT=$$PMA_PORT" >> $(PORTS_FILE); + +# Show extra service URLs on 'make up' +EXTRA_UP_INFO = \ + echo " phpMyAdmin: http://localhost:$$PMA_PORT" && \ + echo " MySQL: localhost:$$FORWARD_DB_PORT" + +# Custom test and lint commands +TEST_CMD = php artisan test --coverage +LINT_CMD = composer phpcs:test && composer phpmd && composer pint:test + +include laravel.mk + +# Add project-specific targets below +``` + +| Variable | Default | Description | +|----------|---------|-------------| +| `EXTRA_PORTS_SCRIPT` | *(empty)* | Shell script appended to `.ports` generation | +| `EXTRA_UP_INFO` | *(empty)* | Extra `echo` commands shown after `make up` | +| `TEST_CMD` | `php artisan test` | Command used by `make test` | +| `LINT_CMD` | `composer pint:test` | Command used by `make lint` | + ### Available Targets | Target | Description | diff --git a/laravel.mk b/laravel.mk index d1573dc..6a6e540 100644 --- a/laravel.mk +++ b/laravel.mk @@ -12,6 +12,18 @@ define find_port $(shell port=$(1); while nc -z 127.0.0.1 $$port 2>/dev/null || lsof -i :$$port >/dev/null 2>&1; do port=$$((port + 1)); done; echo $$port) endef +# Projects can define EXTRA_PORTS_SCRIPT to add additional port assignments. +# Example: EXTRA_PORTS_SCRIPT = DB_PORT=$$(call find_port,3306); echo "DB_PORT=$$DB_PORT" >> $(PORTS_FILE); +EXTRA_PORTS_SCRIPT ?= + +# Projects can define EXTRA_UP_INFO to show additional service URLs after 'make up'. +# Example: EXTRA_UP_INFO = echo " MySQL: localhost:$$FORWARD_DB_PORT" +EXTRA_UP_INFO ?= + +# Projects can override TEST_CMD and LINT_CMD for custom test/lint behavior. +TEST_CMD ?= php artisan test +LINT_CMD ?= composer pint:test + .ports: @echo "Finding available ports..." @echo "# Auto-generated port assignments" > $(PORTS_FILE) @@ -20,17 +32,19 @@ endef MAILHOG_UI_PORT=$(call find_port,$(DEFAULT_MAILHOG_UI_PORT)); \ echo "APP_PORT=$$APP_PORT" >> $(PORTS_FILE); \ echo "MAILHOG_SMTP_PORT=$$MAILHOG_SMTP_PORT" >> $(PORTS_FILE); \ - echo "MAILHOG_UI_PORT=$$MAILHOG_UI_PORT" >> $(PORTS_FILE) + echo "MAILHOG_UI_PORT=$$MAILHOG_UI_PORT" >> $(PORTS_FILE); \ + $(EXTRA_PORTS_SCRIPT) @echo "Port assignments saved to $(PORTS_FILE)" -DC = $(shell if [ -f $(PORTS_FILE) ]; then cat $(PORTS_FILE) | tr '\n' ' '; fi) HOST_UID=$(HOST_UID) HOST_GID=$(HOST_GID) docker compose +DC = $(shell if [ -f $(PORTS_FILE) ]; then grep -v "^\#" $(PORTS_FILE) | xargs; fi) HOST_UID=$(HOST_UID) HOST_GID=$(HOST_GID) docker compose EXEC = $(DC) exec --user www-data app up: .ports ## Start the application @. ./$(PORTS_FILE) && $(DC) up -d @. ./$(PORTS_FILE) && echo "Services running on:" && \ echo " App: http://localhost:$$APP_PORT" && \ - echo " MailHog: http://localhost:$$MAILHOG_UI_PORT" + echo " MailHog: http://localhost:$$MAILHOG_UI_PORT" && \ + $(if $(EXTRA_UP_INFO),$(EXTRA_UP_INFO),:) setup: up composer-install ## First-time setup $(EXEC) php artisan key:generate @@ -59,10 +73,10 @@ composer-update: ## Update composer dependencies $(EXEC) composer update test: ## Run tests - $(EXEC) php artisan test + $(EXEC) $(TEST_CMD) lint: ## Check code formatting - $(EXEC) composer pint:test + $(EXEC) $(LINT_CMD) lint-fix: ## Fix code formatting $(EXEC) composer pint @@ -108,4 +122,4 @@ help: ## Show this help message @echo 'Usage: make [target]' @echo '' @echo 'Targets:' - @egrep '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' + @egrep '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sed 's/^[^:]*://' | sort -u | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'