diff --git a/.env b/.env index 82ae482..f088539 100644 --- a/.env +++ b/.env @@ -2,10 +2,8 @@ export XDG_CONFIG_HOME=$HOME/.config export XDG_DATA_HOME=$HOME/.data export XDG_CACHE_HOME=$HOME/.cache export XDG_STATE_HOME=$HOME/.state -export PNPM_STORE_PATH=$HOME/.pnpm-store -export ZSH="$HOME/.oh-my-zsh" -mkdir -p $XDG_CONFIG_HOME $XDG_DATA_HOME $XDG_CACHE_HOME $XDG_STATE_HOME $PNPM_STORE_PATH +mkdir -p "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" alias pint="./vendor/bin/pint" alias pa="php artisan" diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 921980a..a13d7ac 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -20,186 +20,35 @@ permissions: env: IMAGE_NAME: "ghcr.io/prvious/frankenphp" + REFRESH: ${{ github.event_name == 'schedule' && github.run_id || '' }} + SHA: ${{ github.sha }} jobs: prepare: runs-on: ubuntu-24.04 outputs: - # Push if it's a scheduled job, a tag, or if we're committing to the main branch - push: ${{ github.event_name == 'schedule' || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request') }} variants: ${{ steps.matrix.outputs.variants }} platforms: ${{ steps.matrix.outputs.platforms }} metadata: ${{ steps.matrix.outputs.metadata }} - php_version: ${{ steps.check.outputs.php_version }} - latest_version: ${{ steps.check.outputs.latest_version }} - skip: ${{ steps.check.outputs.skip }} steps: - - name: Check PHP versions - id: check - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Fetch the latest PHP versions from GitHub releases using gh CLI - echo "๐Ÿ” Fetching latest PHP versions from GitHub releases..." - - # Get all PHP 8.x releases and extract version numbers - ALL_PHP_VERSIONS=$(gh api repos/php/php-src/releases --paginate | jq -r '.[].tag_name' | grep -E '^php-8\.[0-9]+\.[0-9]+$' | sed 's/^php-//' | sort -V) - - if [[ -z "${ALL_PHP_VERSIONS}" ]]; then - echo "โŒ Failed to fetch PHP versions from GitHub" - exit 1 - fi - - echo "๐Ÿ“‹ All PHP 8.x versions found:" - echo "${ALL_PHP_VERSIONS}" - - # Extract unique minor versions (8.3, 8.4, etc.) and get the latest patch for each - declare -A LATEST_MINOR_VERSIONS - - while IFS= read -r version; do - if [[ -n "$version" ]]; then - minor_version=$(echo "$version" | cut -d. -f1,2) - LATEST_MINOR_VERSIONS["$minor_version"]="$version" - fi - done <<< "$ALL_PHP_VERSIONS" - - # Get the last 2 minor versions - mapfile -t MINOR_VERSIONS_SORTED < <(printf '%s\n' "${!LATEST_MINOR_VERSIONS[@]}" | sort -V | tail -2) - - if [[ ${#MINOR_VERSIONS_SORTED[@]} -lt 2 ]]; then - echo "โŒ Could not find 2 different minor versions" - exit 1 - fi - - PHP_VERSION_1="${MINOR_VERSIONS_SORTED[0]}" - PHP_VERSION_2="${MINOR_VERSIONS_SORTED[1]}" - - echo "โœ… Selected PHP minor versions: ${PHP_VERSION_1} and ${PHP_VERSION_2}" - echo " Latest patches: ${LATEST_MINOR_VERSIONS[$PHP_VERSION_1]} and ${LATEST_MINOR_VERSIONS[$PHP_VERSION_2]}" - - - echo "๐Ÿ” Checking FrankenPHP images for PHP ${PHP_VERSION_1} and ${PHP_VERSION_2}..." - - # Check if FrankenPHP images exist and get their PHP versions - PHP_1_LATEST="" - PHP_2_LATEST="" - - # For FrankenPHP, we need to check if images exist for these minor versions - # and get the exact PHP version from the image environment - if skopeo inspect "docker://docker.io/dunglas/frankenphp:php${PHP_VERSION_1}" --override-os linux --override-arch amd64 >/dev/null 2>&1; then - PHP_1_LATEST=$(skopeo inspect "docker://docker.io/dunglas/frankenphp:php${PHP_VERSION_1}" --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")') - echo "โœ… Found FrankenPHP image for PHP ${PHP_VERSION_1}: ${PHP_1_LATEST}" - else - echo "โš ๏ธ No FrankenPHP image found for PHP ${PHP_VERSION_1}" - fi - - if skopeo inspect "docker://docker.io/dunglas/frankenphp:php${PHP_VERSION_2}" --override-os linux --override-arch amd64 >/dev/null 2>&1; then - PHP_2_LATEST=$(skopeo inspect "docker://docker.io/dunglas/frankenphp:php${PHP_VERSION_2}" --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")') - echo "โœ… Found FrankenPHP image for PHP ${PHP_VERSION_2}: ${PHP_2_LATEST}" - else - echo "โš ๏ธ No FrankenPHP image found for PHP ${PHP_VERSION_2}" - fi - - # Only proceed if we have at least one valid version - if [[ -z "${PHP_1_LATEST}" ]] && [[ -z "${PHP_2_LATEST}" ]]; then - echo "โŒ No valid FrankenPHP images found for the latest PHP versions" - exit 1 - fi - - # Build the php_version string (comma-separated) - PHP_VERSION_OUTPUT="" - if [[ -n "${PHP_1_LATEST}" ]]; then - PHP_VERSION_OUTPUT="${PHP_1_LATEST}" - fi - if [[ -n "${PHP_2_LATEST}" ]]; then - if [[ -n "${PHP_VERSION_OUTPUT}" ]]; then - PHP_VERSION_OUTPUT="${PHP_VERSION_OUTPUT},${PHP_2_LATEST}" - else - PHP_VERSION_OUTPUT="${PHP_2_LATEST}" - fi - fi - - # Determine which is the latest version - LATEST_VERSION="${PHP_2_LATEST:-$PHP_1_LATEST}" - - { - echo php_version="${PHP_VERSION_OUTPUT}" - echo latest_version="${LATEST_VERSION}" - } >> "${GITHUB_OUTPUT}" - - echo "๐Ÿ“ค Output variables set:" - echo " php_version=${PHP_VERSION_OUTPUT}" - echo " latest_version=${LATEST_VERSION}" - - # Check if the Docker images must be rebuilt - if [[ "${GITHUB_EVENT_NAME}" != "schedule" ]]; then - echo skip=false >> "${GITHUB_OUTPUT}" - exit 0 - fi - - # For scheduled runs, check if our images are up to date - echo "๐Ÿ” Checking if our FrankenPHP images need rebuilding..." - NEED_REBUILD=false - - if [[ -n "${PHP_1_LATEST}" ]]; then - if skopeo inspect "docker://ghcr.io/prvious/frankenphp:php${PHP_VERSION_1}" --override-os linux --override-arch amd64 >/dev/null 2>&1; then - FRANKENPHP_1_LATEST=$(skopeo inspect "docker://ghcr.io/prvious/frankenphp:php${PHP_VERSION_1}" --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")') - if [[ "${FRANKENPHP_1_LATEST}" != "${PHP_1_LATEST}" ]]; then - echo "๐Ÿ”„ PHP ${PHP_VERSION_1} needs rebuild: ${FRANKENPHP_1_LATEST} -> ${PHP_1_LATEST}" - NEED_REBUILD=true - fi - else - echo "๐Ÿ†• PHP ${PHP_VERSION_1} image doesn't exist, needs build" - NEED_REBUILD=true - fi - fi - - if [[ -n "${PHP_2_LATEST}" ]]; then - if skopeo inspect "docker://ghcr.io/prvious/frankenphp:php${PHP_VERSION_2}" --override-os linux --override-arch amd64 >/dev/null 2>&1; then - FRANKENPHP_2_LATEST=$(skopeo inspect "docker://ghcr.io/prvious/frankenphp:php${PHP_VERSION_2}" --override-os linux --override-arch amd64 | jq -r '.Env[] | select(test("^PHP_VERSION=")) | sub("^PHP_VERSION="; "")') - if [[ "${FRANKENPHP_2_LATEST}" != "${PHP_2_LATEST}" ]]; then - echo "๐Ÿ”„ PHP ${PHP_VERSION_2} needs rebuild: ${FRANKENPHP_2_LATEST} -> ${PHP_2_LATEST}" - NEED_REBUILD=true - fi - else - echo "๐Ÿ†• PHP ${PHP_VERSION_2} image doesn't exist, needs build" - NEED_REBUILD=true - fi - fi - - if [[ "${NEED_REBUILD}" == "true" ]]; then - echo skip=false >> "${GITHUB_OUTPUT}" - echo "๐Ÿš€ Images need rebuilding" - else - echo skip=true >> "${GITHUB_OUTPUT}" - echo "โœ… All images are up to date" - fi - - uses: actions/checkout@v4 - if: ${{ !fromJson(steps.check.outputs.skip) }} - name: Set up Docker Buildx - if: ${{ !fromJson(steps.check.outputs.skip) }} uses: docker/setup-buildx-action@v3 - name: Create variants matrix - if: ${{ !fromJson(steps.check.outputs.skip) }} id: matrix shell: bash run: | set -e - # Print metadata for all targets so we capture all expanded runner-* targets METADATA="$(docker buildx bake --print | jq -c)" { echo metadata="${METADATA}" echo variants="$(jq -c '[.target | keys[] | select(startswith("runner-")) | sub("^runner-"; "")] | unique' <<< "${METADATA}")" echo platforms="$(jq -c 'first(.target[]) | .platforms' <<< "${METADATA}")" } >> "${GITHUB_OUTPUT}" - env: - PHP_VERSION: ${{ steps.check.outputs.php_version }} - LATEST: ${{ steps.check.outputs.latest_version }} - SHA: ${{ github.sha }} + build: runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} needs: @@ -207,7 +56,6 @@ jobs: permissions: contents: read packages: write - if: ${{ !fromJson(needs.prepare.outputs.skip) }} strategy: fail-fast: false matrix: @@ -229,7 +77,7 @@ jobs: platforms: ${{ matrix.platform }} - name: Login to ghcr.io - if: fromJson(needs.prepare.outputs.push) + if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ghcr.io @@ -243,10 +91,9 @@ jobs: id: build uses: docker/bake-action@v6 with: - push: ${{ fromJson(needs.prepare.outputs.push) }} + push: ${{ github.event_name != 'pull_request' }} targets: runner-${{ matrix.variant }} set: | - ${{ (github.event_name == 'pull_request') && '*.args.NO_COMPRESS=1' || '' }} *.tags= *.platform=${{ matrix.platform }} *.cache-from=type=gha,scope=${{ matrix.variant }}-${{ github.ref }}-${{ matrix.platform }} @@ -261,12 +108,8 @@ jobs: *.cache-to=type=gha,scope=${{ matrix.variant }}-${{ github.ref }},mode=max,ignore-error=true *.cache-to=type=gha,scope=base-${{ matrix.platform }},mode=max,ignore-error=true *.cache-to=type=gha,scope=base,mode=max,ignore-error=true - *.output=type=docker,dest=/tmp/images/runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }}.tar - ${{ fromJson(needs.prepare.outputs.push) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }} - env: - PHP_VERSION: ${{ needs.prepare.outputs.php_version }} - LATEST: ${{ needs.prepare.outputs.latest_version }} - SHA: ${{ github.sha }} + *.output=type=docker,name=frankenphp:test,dest=/tmp/images/runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }}.tar + ${{ github.event_name != 'pull_request' && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }} - name: Upload image artifact uses: actions/upload-artifact@v4 @@ -274,12 +117,12 @@ jobs: name: image-runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }} path: /tmp/images/runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }}.tar if-no-files-found: error - compression-level: 9 + compression-level: 0 retention-days: 1 - # Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600 name: Export metadata - if: fromJson(needs.prepare.outputs.push) + if: github.event_name != 'pull_request' run: | mkdir -p /tmp/metadata/runner runnerDigest=$(jq -r '."runner-${{ matrix.variant }}"."containerimage.digest"' <<< "${METADATA}") @@ -288,7 +131,7 @@ jobs: METADATA: ${{ steps.build.outputs.metadata }} - name: Upload runner metadata - if: fromJson(needs.prepare.outputs.push) + if: github.event_name != 'pull_request' uses: actions/upload-artifact@v4 with: name: metadata-runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }} @@ -301,7 +144,6 @@ jobs: needs: - prepare - build - if: ${{ !fromJson(needs.prepare.outputs.skip) }} strategy: fail-fast: false matrix: @@ -317,9 +159,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Download built image uses: actions/download-artifact@v4 with: @@ -327,44 +166,7 @@ jobs: path: /tmp/images - name: Load image from tarball - run: | - TARBALL="/tmp/images/runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }}.tar" - - echo "Loading image from tarball: ${TARBALL}" - - # Verify tarball exists - if [[ ! -f "${TARBALL}" ]]; then - echo "Error: Tarball not found!" - ls -la /tmp/images/ - exit 1 - fi - - # Check tarball size - SIZE=$(stat -f%z "${TARBALL}" 2>/dev/null || stat -c%s "${TARBALL}") - echo "Tarball size: $((SIZE / 1024 / 1024))MB" - - # Load the image and capture the output - echo "Loading image into Docker..." - LOAD_OUTPUT=$(docker load < "${TARBALL}") - echo "${LOAD_OUTPUT}" - - # Extract the image ID from the load output - LOADED_IMAGE_ID=$(echo "${LOAD_OUTPUT}" | grep "Loaded image ID:" | cut -d' ' -f4) - echo "โœ… Loaded image ID: ${LOADED_IMAGE_ID}" - - if [[ -z "${LOADED_IMAGE_ID}" ]]; then - echo "โŒ Error: Could not extract image ID from docker load output!" - echo "Load output was: ${LOAD_OUTPUT}" - exit 1 - fi - - # Export the image ID for use in the test step - echo "LOADED_IMAGE_ID=${LOADED_IMAGE_ID}" >> "$GITHUB_ENV" - - # Verify image is available - echo "Image loaded successfully:" - docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Size}}" | head -1 - docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Size}}" | grep "${LOADED_IMAGE_ID#sha256:}" || echo "Image ID: ${LOADED_IMAGE_ID}" + run: docker load --input "/tmp/images/runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }}.tar" - name: Test image environment run: | @@ -374,13 +176,8 @@ jobs: *) ENV_TYPE="production" ;; esac - echo "๐Ÿงช Testing ${ENV_TYPE} environment in image: ${LOADED_IMAGE_ID}" - - # Run our test script inside the container using the loaded image ID - docker run --rm -v "$PWD/test.php:/test.php:ro" -e FORCE_COLOR=1 "${LOADED_IMAGE_ID}" php /test.php "${ENV_TYPE}" - env: - PHP_VERSION: ${{ needs.prepare.outputs.php_version }} - LATEST: ${{ needs.prepare.outputs.latest_version }} + echo "๐Ÿงช Testing ${ENV_TYPE} environment" + docker run --rm -v "$PWD/test.php:/test.php:ro" -e FORCE_COLOR=1 frankenphp:test php /test.php "${ENV_TYPE}" push: runs-on: ubuntu-24.04 @@ -388,7 +185,7 @@ jobs: - prepare - build - test - if: fromJson(needs.prepare.outputs.push) + if: github.event_name != 'pull_request' permissions: contents: read packages: write @@ -396,12 +193,11 @@ jobs: fail-fast: false matrix: variant: ${{ fromJson(needs.prepare.outputs.variants) }} - target: ["runner"] steps: - name: Download metadata uses: actions/download-artifact@v4 with: - pattern: metadata-${{ matrix.target }}-${{ matrix.variant }}-* + pattern: metadata-runner-${{ matrix.variant }}-* path: /tmp/metadata merge-multiple: true @@ -420,7 +216,7 @@ jobs: run: | set -x # shellcheck disable=SC2046,SC2086 - docker buildx imagetools create $(jq -cr '.target."${{ matrix.target }}-${{ matrix.variant }}".tags | map("-t " + .) | join(" ")' <<< ${METADATA}) \ + docker buildx imagetools create $(jq -cr '.target."runner-${{ matrix.variant }}".tags | map("-t " + .) | join(" ")' <<< "${METADATA}") \ $(printf "${IMAGE_NAME}@sha256:%s " *) env: METADATA: ${{ needs.prepare.outputs.metadata }} @@ -428,6 +224,6 @@ jobs: - name: Inspect image run: | # shellcheck disable=SC2046,SC2086 - docker buildx imagetools inspect $(jq -cr '.target."${{ matrix.target }}-${{ matrix.variant }}".tags | first' <<< ${METADATA}) + docker buildx imagetools inspect $(jq -cr '.target."runner-${{ matrix.variant }}".tags | first' <<< "${METADATA}") env: METADATA: ${{ needs.prepare.outputs.metadata }} diff --git a/.zshrc b/.zshrc index fa86117..ff02b40 100644 --- a/.zshrc +++ b/.zshrc @@ -1,41 +1,31 @@ # Environment . /etc/profile.d/.env -# Path configuration (must be before tools that depend on it) -export PATH="$HOME/.local/bin:$HOME/.fzf/bin:$HOME/.opencode/bin:$PNPM_HOME:$PATH" +# Path configuration +export PATH="$HOME/.local/bin:$PATH" if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi -# Load the build-pinned Zinit installation -ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git" -if [[ ! -r "$ZINIT_HOME/zinit.zsh" ]]; then - print -u2 "Missing pinned Zinit installation: $ZINIT_HOME" +# Load the development shell framework +export ZSH="$HOME/.oh-my-zsh" +if [[ ! -r "$ZSH/oh-my-zsh.sh" ]]; then + print -u2 "Missing Oh My Zsh installation: $ZSH" return 1 fi -source "${ZINIT_HOME}/zinit.zsh" -# Initialize completion before sourcing Oh My Zsh plugins that register compdefs -autoload -Uz compinit -compinit - -# Essential plugins (loaded immediately) -zinit ice ver"85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5" -zinit light zsh-users/zsh-autosuggestions -zinit ice ver"24105b15714bfec37989ed5c5b6e60f572253019" -zinit light Aloxaf/fzf-tab - -# Build-pinned Oh My Zsh libraries and plugins -source "$ZSH/lib/git.zsh" -source "$ZSH/lib/completion.zsh" -source "$ZSH/plugins/git/git.plugin.zsh" -source "$ZSH/plugins/aws/aws.plugin.zsh" -source "$ZSH/plugins/gh/gh.plugin.zsh" - -# Syntax highlighting (load last, with turbo) -zinit wait lucid ver"3d574ccf48804b10dca52625df13da5edae7f553" for \ - zdharma-continuum/fast-syntax-highlighting +ZSH_THEME="" +zstyle ':omz:update' mode disabled +plugins=( + git + aws + gh + zsh-autosuggestions + fzf-tab + fast-syntax-highlighting +) +source "$ZSH/oh-my-zsh.sh" # Tool initializations (synchronous - needed for prompt) eval "$(starship init zsh)" @@ -89,7 +79,7 @@ zstyle ':completion:*' menu select # FZF-tab styling zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'eza --color --icons $realpath' zstyle ':fzf-tab:complete:cd:*' fzf-preview 'eza -1 --color=always --icons $realpath' -zstyle ':fzf-tab:complete:(ls|l|ll|la|lt|eza):*' fzf-preview '[[ -d $realpath ]] && eza -1 --color=always --icons $realpath || bat --color=always --style=numbers $realpath 2>/dev/null || cat $realpath' +zstyle ':fzf-tab:complete:(ls|l|ll|la|lt|eza):*' fzf-preview '[[ -d $realpath ]] && eza -1 --color=always --icons $realpath || cat $realpath' zstyle ':fzf-tab:*' fzf-flags --color=fg:1,fg+:2 --bind=tab:accept zstyle ':fzf-tab:*' use-fzf-default-opts yes zstyle ':fzf-tab:*' switch-group '<' '>' diff --git a/.zshrc.prod b/.zshrc.prod index 937f2d3..95075dc 100644 --- a/.zshrc.prod +++ b/.zshrc.prod @@ -5,30 +5,10 @@ if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi -# Load the build-pinned Zinit installation -ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git" -if [[ ! -r "$ZINIT_HOME/zinit.zsh" ]]; then - print -u2 "Missing pinned Zinit installation: $ZINIT_HOME" - return 1 -fi -source "${ZINIT_HOME}/zinit.zsh" - -# Initialize completion before sourcing Oh My Zsh plugins that register compdefs +# Initialize the standard Zsh completion system autoload -Uz compinit compinit -# Minimal plugins for production (loaded immediately) -zinit ice ver"85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5" -zinit light zsh-users/zsh-autosuggestions - -# Build-pinned Oh My Zsh library and git plugin -source "$ZSH/lib/git.zsh" -source "$ZSH/plugins/git/git.plugin.zsh" - -# Syntax highlighting (load last) -zinit wait lucid ver"3d574ccf48804b10dca52625df13da5edae7f553" for \ - zdharma-continuum/fast-syntax-highlighting - # Basic aliases alias ll='ls -lah' alias la='ls -a' diff --git a/AGENTS.md b/AGENTS.md index a41951b..3aa07f4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ This repository builds the `ghcr.io/prvious/frankenphp` development and producti - `docker build --build-arg VERSION=8.5-trixie --target dev -t frankenphp:dev .` builds the local development image. - `docker build --build-arg VERSION=8.5-trixie --target prod -t frankenphp:prod .` builds the production image. -- `docker buildx bake --print` inspects the default PHP 8.4/8.5 matrix; override `PHP_VERSION`, `SHA`, and `LATEST` to reproduce CI inputs. +- `docker buildx bake --print` inspects the default PHP 8.4/8.5 minor-version matrix; override `PHP_VERSION`, `LATEST`, `SHA`, and `REFRESH` when testing matrix or dependency-refresh changes. - `docker buildx bake` builds all configured variants and architectures. - `docker run --rm -v "$PWD/test.php:/app/test.php" frankenphp:dev php /app/test.php dev` validates extensions, binaries, and pnpm configuration. Substitute the production image and `production` for that target. diff --git a/Dockerfile b/Dockerfile index 239139b..b37cc5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,140 +2,17 @@ ARG VERSION FROM dunglas/frankenphp:php${VERSION} AS frankenphp-base #--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -# BUILDER STAGE: Download pinned binaries and tools +# BUILDER STAGES: Follow supported major release channels #--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -FROM debian:bookworm-slim AS binaries-builder +FROM node:26-bookworm-slim AS node-builder -ARG TARGETARCH -ARG NODE_VERSION=26.5.1 -ARG PNPM_VERSION=11.18.0 -ARG SVGO_VERSION=4.0.2 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates \ - curl \ - gzip \ - libatomic1 \ - tar \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /tmp/binaries - -# Download Node.js without npm and verify the pinned archive -RUN case "${TARGETARCH}" in \ - amd64) NODE_ARCH="x64"; NODE_SHA256="2b07f09c218d473a26442bff5a90151f53f7b7c0a23bad244eda2c26303a2ba7" ;; \ - arm64) NODE_ARCH="arm64"; NODE_SHA256="21194bbf41c18d9ec277545c4d14cce8597d57a9d9f494c323d8121a25de33e8" ;; \ - *) echo "Unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ - esac \ - && NODE_ARCHIVE="node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.gz" \ - && curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/${NODE_ARCHIVE}" -o "${NODE_ARCHIVE}" \ - && echo "${NODE_SHA256} ${NODE_ARCHIVE}" | sha256sum -c - \ - && tar -xzf "${NODE_ARCHIVE}" \ - && mkdir -p /tmp/binaries/node/bin \ - && mv "node-v${NODE_VERSION}-linux-${NODE_ARCH}/bin/node" /tmp/binaries/node/bin/ \ - && rm -rf "${NODE_ARCHIVE}" "node-v${NODE_VERSION}-linux-${NODE_ARCH}" - -# Download pnpm's architecture-independent package and verify the pinned archive -RUN PNPM_ARCHIVE="pnpm-${PNPM_VERSION}.tgz" \ - && curl -fsSL "https://registry.npmjs.org/pnpm/-/${PNPM_ARCHIVE}" -o "${PNPM_ARCHIVE}" \ - && echo "29c35ca8d2a287988fdee3e0f36e07d9b93783f567b579b7fd5b798a4563dd81 ${PNPM_ARCHIVE}" | sha256sum -c - \ - && mkdir -p /tmp/binaries/pnpm \ - && tar -xzf "${PNPM_ARCHIVE}" -C /tmp/binaries/pnpm --strip-components=1 \ - && ln -s bin/pnpm.mjs /tmp/binaries/pnpm/pnpm \ - && rm -f "${PNPM_ARCHIVE}" - -# Install a pinned svgo release using the verified Node.js and pnpm binaries -RUN mkdir -p /tmp/binaries/pnpm/bin /tmp/binaries/pnpm-global \ - && export PATH="/tmp/binaries/node/bin:/tmp/binaries/pnpm:/tmp/binaries/pnpm/bin:$PATH" \ - && export PNPM_HOME=/tmp/binaries/pnpm \ - && pnpm config set store-dir /tmp/pnpm-store --global \ - && pnpm config set global-dir /tmp/binaries/pnpm-global --global \ - && pnpm config set global-bin-dir /tmp/binaries/pnpm/bin --global \ - && pnpm add -g "svgo@${SVGO_VERSION}" +ARG REFRESH -# Download and verify development-only binaries -FROM binaries-builder AS dev-binaries-builder +RUN echo "${REFRESH}" > /dev/null \ + && npm install --global pnpm@11 svgo -ARG EZA_VERSION=0.23.5 -ARG FZF_VERSION=0.74.1 -ARG GH_VERSION=2.96.0 -ARG OPENCODE_VERSION=1.18.9 -ARG STARSHIP_VERSION=1.26.0 -ARG ZOXIDE_VERSION=0.10.0 - -RUN mkdir -p /tmp/binaries/dev \ - && case "${TARGETARCH}" in \ - amd64) \ - EZA_ARCH="x86_64"; EZA_SHA256="35c70c5c43c29108075e58b893234c67ef585f0b53a7eaf8e9e7d4eec9f339b4"; \ - FZF_ARCH="amd64"; FZF_SHA256="df53438be5f51e151bb4044d78fda72bdfe209e3ecd2baecae48e8dea370c81b"; \ - GH_ARCH="amd64"; GH_SHA256="83d5c2ccad5498f58bf6368acb1ab32588cf43ab3a4b1c301bf36328b1c8bd60"; \ - OPENCODE_ARCH="x64"; OPENCODE_SHA256="a0fa4b7b8bdacbd013e79a5f69d4220d36b545cd3ea296ba765f3016fa501b5b"; \ - STARSHIP_ARCH="x86_64"; STARSHIP_SHA256="b7c232b0e8249d8e55a40beb79c5c43a7d370f3f9408bd215deb0170daeaadf3"; \ - ZOXIDE_ARCH="x86_64"; ZOXIDE_SHA256="2d93385b99f3e82cf2701609a1bffcad863fbeb75aa3fe7eb6be4d29be68b1ae" \ - ;; \ - arm64) \ - EZA_ARCH="aarch64"; EZA_SHA256="40b87ae8628aa2ff0f0d2dc24ab52f689631366385c3da630bae745671fd71ec"; \ - FZF_ARCH="arm64"; FZF_SHA256="f22204dd1a091d43e102268d062fd53b47133c8d8581671ee5eb225b75e31183"; \ - GH_ARCH="arm64"; GH_SHA256="06f86ec7103d41993b76cd78072f43595c34aaa56506d971d9860e67140bf909"; \ - OPENCODE_ARCH="arm64"; OPENCODE_SHA256="b16bd7593ea960a25d9c6849b3023bcd9b9244a6f51675341fd2052043b0670f"; \ - STARSHIP_ARCH="aarch64"; STARSHIP_SHA256="dc30189378d2f2e287384e8a692d3f95ad1df64cf0e8c36aa9201516028aed6b"; \ - ZOXIDE_ARCH="aarch64"; ZOXIDE_SHA256="f1f16c5d6298d63dee467eedea1cdcd8490e43e493bea43acd416dc9033ef641" \ - ;; \ - *) echo "Unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ - esac \ - && EZA_ARCHIVE="eza_${EZA_ARCH}-unknown-linux-gnu.tar.gz" \ - && curl -fsSL "https://github.com/eza-community/eza/releases/download/v${EZA_VERSION}/${EZA_ARCHIVE}" -o "${EZA_ARCHIVE}" \ - && echo "${EZA_SHA256} ${EZA_ARCHIVE}" | sha256sum -c - \ - && tar -xzf "${EZA_ARCHIVE}" -C /tmp/binaries/dev \ - && FZF_ARCHIVE="fzf-${FZF_VERSION}-linux_${FZF_ARCH}.tar.gz" \ - && curl -fsSL "https://github.com/junegunn/fzf/releases/download/v${FZF_VERSION}/${FZF_ARCHIVE}" -o "${FZF_ARCHIVE}" \ - && echo "${FZF_SHA256} ${FZF_ARCHIVE}" | sha256sum -c - \ - && tar -xzf "${FZF_ARCHIVE}" -C /tmp/binaries/dev \ - && GH_ARCHIVE="gh_${GH_VERSION}_linux_${GH_ARCH}.tar.gz" \ - && curl -fsSL "https://github.com/cli/cli/releases/download/v${GH_VERSION}/${GH_ARCHIVE}" -o "${GH_ARCHIVE}" \ - && echo "${GH_SHA256} ${GH_ARCHIVE}" | sha256sum -c - \ - && tar -xzf "${GH_ARCHIVE}" \ - && mv "gh_${GH_VERSION}_linux_${GH_ARCH}/bin/gh" /tmp/binaries/dev/gh \ - && OPENCODE_ARCHIVE="opencode-linux-${OPENCODE_ARCH}.tar.gz" \ - && curl -fsSL "https://github.com/anomalyco/opencode/releases/download/v${OPENCODE_VERSION}/${OPENCODE_ARCHIVE}" -o "${OPENCODE_ARCHIVE}" \ - && echo "${OPENCODE_SHA256} ${OPENCODE_ARCHIVE}" | sha256sum -c - \ - && tar -xzf "${OPENCODE_ARCHIVE}" -C /tmp/binaries/dev \ - && STARSHIP_ARCHIVE="starship-${STARSHIP_ARCH}-unknown-linux-musl.tar.gz" \ - && curl -fsSL "https://github.com/starship/starship/releases/download/v${STARSHIP_VERSION}/${STARSHIP_ARCHIVE}" -o "${STARSHIP_ARCHIVE}" \ - && echo "${STARSHIP_SHA256} ${STARSHIP_ARCHIVE}" | sha256sum -c - \ - && tar -xzf "${STARSHIP_ARCHIVE}" -C /tmp/binaries/dev \ - && ZOXIDE_ARCHIVE="zoxide-${ZOXIDE_VERSION}-${ZOXIDE_ARCH}-unknown-linux-musl.tar.gz" \ - && curl -fsSL "https://github.com/ajeetdsouza/zoxide/releases/download/v${ZOXIDE_VERSION}/${ZOXIDE_ARCHIVE}" -o "${ZOXIDE_ARCHIVE}" \ - && echo "${ZOXIDE_SHA256} ${ZOXIDE_ARCHIVE}" | sha256sum -c - \ - && mkdir -p /tmp/zoxide \ - && tar -xzf "${ZOXIDE_ARCHIVE}" -C /tmp/zoxide \ - && mv /tmp/zoxide/zoxide /tmp/binaries/dev/zoxide \ - && chmod 755 /tmp/binaries/dev/* \ - && rm -rf ./*.tar.gz ./gh_* /tmp/zoxide - -#--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -# BUILDER STAGE: Pin the shell framework without executing a remote installer -#--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -FROM debian:bookworm-slim AS shell-builder - -ARG ZINIT_COMMIT=429ab136312dfce68ad7d87a0ecb08c5063e7287 -ARG OH_MY_ZSH_COMMIT=7ea697fd8138550ddf7262456d412f0dcd1cbf84 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates \ - git \ - && rm -rf /var/lib/apt/lists/* - -RUN git clone --filter=blob:none https://github.com/zdharma-continuum/zinit.git /tmp/zinit \ - && git -C /tmp/zinit checkout "${ZINIT_COMMIT}" \ - && test "$(git -C /tmp/zinit rev-parse HEAD)" = "${ZINIT_COMMIT}" \ - && git clone --filter=blob:none https://github.com/ohmyzsh/ohmyzsh.git /tmp/oh-my-zsh \ - && git -C /tmp/oh-my-zsh checkout "${OH_MY_ZSH_COMMIT}" \ - && test "$(git -C /tmp/oh-my-zsh rev-parse HEAD)" = "${OH_MY_ZSH_COMMIT}" - -FROM composer:2.10.2@sha256:5946476338742b200bb9ff88f8be56275ddae4b3949c72305cb0dbf10cfcb760 AS composer-builder +FROM composer:2 AS composer-builder #--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- # BASE STAGE: FrankenPHP base with minimal dependencies @@ -151,16 +28,16 @@ LABEL org.opencontainers.image.source="https://github.com/prvious/frankenphp" ARG WWWGROUP=1000 ARG WWWUSER=1000 ARG USER=deploy +ARG REFRESH ENV TZ=UTC ENV SERVER_NAME=:80 ENV DEBIAN_FRONTEND=noninteractive -ENV PNPM_HOME=/usr/local/share/pnpm -ENV PATH=$PNPM_HOME:$PATH ENV pnpm_config_store_dir=/home/${USER}/.pnpm-store # Install shared runtime packages and image tools from the target Debian suite -RUN apt-get update \ +RUN echo "${REFRESH}" > /dev/null \ + && apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ @@ -208,25 +85,23 @@ RUN install-php-extensions \ exif \ ftp \ xml \ - pdo_sqlsrv-5.13.1 \ - sqlsrv-5.13.1 \ - sockets \ - && cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" + pdo_sqlsrv \ + sqlsrv \ + sockets -# Copy runtime configuration and verified artifacts after the expensive package layers +# Copy runtime configuration and major-channel artifacts after the expensive package layers COPY ./.env /etc/profile.d/.env COPY --chown=0:0 --chmod=755 ./usr/local/bin/* /usr/local/bin/ COPY --from=composer-builder --chown=0:0 --chmod=755 /usr/bin/composer /usr/bin/composer -COPY --from=binaries-builder --chown=0:0 /tmp/binaries/node /usr/local/node -COPY --from=binaries-builder --chown=0:0 /tmp/binaries/pnpm /usr/local/share/pnpm -COPY --from=binaries-builder --chown=0:0 /tmp/binaries/pnpm-global /usr/local/share/pnpm-global -COPY --from=binaries-builder --chown=0:0 /tmp/pnpm-store /usr/local/pnpm-store - -# Add Node.js, pnpm, and global packages to PATH -ENV PATH=/usr/local/node/bin:/usr/local/share/pnpm:/usr/local/share/pnpm/bin:/usr/local/share/pnpm-global/bin:$PATH +COPY --from=node-builder --chown=0:0 --chmod=755 /usr/local/bin/node /usr/local/bin/node +COPY --from=node-builder --chown=0:0 /usr/local/lib/node_modules/pnpm /usr/local/lib/node_modules/pnpm +COPY --from=node-builder --chown=0:0 /usr/local/lib/node_modules/svgo /usr/local/lib/node_modules/svgo # User creation and permissions -RUN groupadd --non-unique -g "${WWWGROUP}" "${USER}" \ +RUN ln -s ../lib/node_modules/pnpm/bin/pnpm.mjs /usr/local/bin/pnpm \ + && ln -s ../lib/node_modules/pnpm/bin/pnpx.mjs /usr/local/bin/pnpx \ + && ln -s ../lib/node_modules/svgo/bin/svgo.js /usr/local/bin/svgo \ + && groupadd --non-unique -g "${WWWGROUP}" "${USER}" \ && useradd -m --no-user-group -o -g "${WWWGROUP}" -u "${WWWUSER}" -s /bin/zsh "${USER}" \ && setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp \ && mkdir -p \ @@ -234,8 +109,8 @@ RUN groupadd --non-unique -g "${WWWGROUP}" "${USER}" \ "/home/${USER}/.local/bin" \ "/home/${USER}/.pnpm-store" \ /app \ - /config/opencode \ /data/opencode \ + /config/opencode \ && chown -R "${USER}:${USER}" \ "/home/${USER}" \ /app \ @@ -250,35 +125,66 @@ RUN groupadd --non-unique -g "${WWWGROUP}" "${USER}" \ FROM base AS dev -# Copy verified development binaries -COPY --from=dev-binaries-builder --chown=0:0 --chmod=755 /tmp/binaries/dev/* /usr/local/bin/ +ARG REFRESH +ARG TARGETARCH -# Minimal development packages -RUN apt-get update \ +# Install current development tools through their supported release channels +RUN echo "${REFRESH}" > /dev/null \ + && apt-get update \ && apt-get install -y --no-install-recommends \ + gnupg \ htop \ nano \ + && install -d -m 0755 /etc/apt/keyrings \ + && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list \ + && curl -fsSL https://raw.githubusercontent.com/eza-community/eza/main/deb.asc \ + | gpg --dearmor -o /etc/apt/keyrings/eza.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/eza.gpg] http://deb.gierens.de stable main" > /etc/apt/sources.list.d/eza.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + eza \ + gh \ + && git clone --depth 1 https://github.com/junegunn/fzf.git /tmp/fzf \ + && /tmp/fzf/install --bin \ + && install -m 0755 /tmp/fzf/bin/fzf /usr/local/bin/fzf \ + && curl -fsSL https://raw.githubusercontent.com/starship/starship/master/install/install.sh \ + | sh -s -- --yes --bin-dir /usr/local/bin \ + && curl -fsSL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh \ + | sh -s -- --bin-dir /usr/local/bin --man-dir /usr/local/share/man \ + && case "${TARGETARCH}" in \ + amd64) OPENCODE_ARCH="x64" ;; \ + arm64) OPENCODE_ARCH="arm64" ;; \ + *) echo "Unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ + esac \ + && curl -fsSL "https://github.com/anomalyco/opencode/releases/latest/download/opencode-linux-${OPENCODE_ARCH}.tar.gz" \ + | tar -xz -C /usr/local/bin \ && apt-get clean \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /tmp/fzf /var/lib/apt/lists/* # Development PHP extensions -RUN install-php-extensions xdebug +RUN install-php-extensions xdebug \ + && cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" -# Copy the pinned shell frameworks and development configuration -COPY --from=shell-builder --chown=${USER}:${USER} /tmp/zinit /home/${USER}/.data/zinit/zinit.git -COPY --from=shell-builder --chown=${USER}:${USER} /tmp/oh-my-zsh /home/${USER}/.oh-my-zsh +# Copy development shell configuration COPY --chown=${USER}:${USER} ./.zshrc /home/${USER}/.zshrc -# Switch to the runtime user and pre-download pinned shell plugins +# Switch to the runtime user and install the development shell plugins USER ${USER} -ENV PATH=/home/${USER}/.local/bin:/home/${USER}/.opencode/bin:$PATH - -RUN starship preset no-nerd-font -o "/home/${USER}/.config/starship.toml" \ +RUN git clone --depth 1 https://github.com/ohmyzsh/ohmyzsh.git "/home/${USER}/.oh-my-zsh" \ + && git clone --depth 1 https://github.com/zsh-users/zsh-autosuggestions.git "/home/${USER}/.oh-my-zsh/custom/plugins/zsh-autosuggestions" \ + && git clone --depth 1 https://github.com/Aloxaf/fzf-tab.git "/home/${USER}/.oh-my-zsh/custom/plugins/fzf-tab" \ + && git clone --depth 1 https://github.com/zdharma-continuum/fast-syntax-highlighting.git "/home/${USER}/.oh-my-zsh/custom/plugins/fast-syntax-highlighting" \ + && starship preset no-nerd-font -o "/home/${USER}/.config/starship.toml" \ && zsh -i -c 'exit 0' \ - && test "$(git -C "/home/${USER}/.data/zinit/plugins/zsh-users---zsh-autosuggestions" rev-parse HEAD)" = "85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5" \ - && test "$(git -C "/home/${USER}/.data/zinit/plugins/Aloxaf---fzf-tab" rev-parse HEAD)" = "24105b15714bfec37989ed5c5b6e60f572253019" \ - && test "$(git -C "/home/${USER}/.data/zinit/plugins/zdharma-continuum---fast-syntax-highlighting" rev-parse HEAD)" = "3d574ccf48804b10dca52625df13da5edae7f553" + && gh --version \ + && eza --version \ + && fzf --version \ + && opencode --version \ + && starship --version \ + && zoxide --version WORKDIR /app @@ -294,15 +200,9 @@ RUN cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" # Copy production zshrc COPY --chown=${USER}:${USER} ./.zshrc.prod /home/${USER}/.zshrc -# Copy the pinned shell frameworks -COPY --from=shell-builder --chown=${USER}:${USER} /tmp/zinit /home/${USER}/.data/zinit/zinit.git -COPY --from=shell-builder --chown=${USER}:${USER} /tmp/oh-my-zsh /home/${USER}/.oh-my-zsh - -# Switch to the runtime user and pre-download pinned shell plugins +# Switch to the runtime user and validate the plain production shell USER ${USER} -RUN zsh -i -c 'exit 0' \ - && test "$(git -C "/home/${USER}/.data/zinit/plugins/zsh-users---zsh-autosuggestions" rev-parse HEAD)" = "85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5" \ - && test "$(git -C "/home/${USER}/.data/zinit/plugins/zdharma-continuum---fast-syntax-highlighting" rev-parse HEAD)" = "3d574ccf48804b10dca52625df13da5edae7f553" +RUN zsh -i -c 'exit 0' WORKDIR /app diff --git a/README.md b/README.md index c57129d..e52436f 100644 --- a/README.md +++ b/README.md @@ -22,17 +22,17 @@ docker pull ghcr.io/prvious/frankenphp:php8.5 - **Database Clients**: PostgreSQL 17, MySQL - **Image Tools**: jpegoptim, optipng, pngquant, gifsicle, avifenc, svgo, ffmpeg - **Process Manager**: Supervisor -- **Shell**: Zsh with zinit +- **Shell**: Zsh ### Dev Only - **PHP**: Xdebug - **Tools**: GitHub CLI, OpenCode, htop, nano, fzf, zoxide, eza -- **Shell**: Starship prompt, syntax highlighting, autosuggestions, fzf-tab +- **Shell**: Oh My Zsh, Starship prompt, syntax highlighting, autosuggestions, fzf-tab ## Available Tags -The entries below illustrate the dynamically selected PHP minor tag format: +The entries below illustrate the configured PHP minor tag format: | Tag | Description | |-----|-------------| @@ -43,7 +43,7 @@ The entries below illustrate the dynamically selected PHP minor tag format: | `latest` | Latest supported PHP production | | `latest-dev` | Latest supported PHP development | -The workflow discovers and publishes the two newest stable PHP minor lines. Unqualified tags use Debian Trixie. For Debian Bookworm, insert `-bookworm` before the optional `-dev` suffix: `php8.5-bookworm`, `php8.5-bookworm-dev`, `latest-bookworm`, or `latest-bookworm-dev`. All images support `linux/amd64` and `linux/arm64`. +The workflow publishes the configured PHP 8.4 and 8.5 minor lines and follows their latest FrankenPHP patch releases. Unqualified tags use Debian Trixie. For Debian Bookworm, insert `-bookworm` before the optional `-dev` suffix: `php8.5-bookworm`, `php8.5-bookworm-dev`, `latest-bookworm`, or `latest-bookworm-dev`. All images support `linux/amd64` and `linux/arm64`. ## Usage with Laravel @@ -93,11 +93,11 @@ docker build --build-arg VERSION=8.5-trixie --target dev -t frankenphp:dev . # Build prod image docker build --build-arg VERSION=8.5-trixie --target prod -t frankenphp:prod . -# Build the default PHP 8.4/8.5 matrix +# Build the default PHP 8.4/8.5 minor-version matrix docker buildx bake -# Build an explicit version set and label it with the current commit -PHP_VERSION=8.4.23,8.5.8 SHA="$(git rev-parse HEAD)" LATEST=8.5.8 docker buildx bake +# Build an explicit minor-version set and label it with the current commit +PHP_VERSION=8.4,8.5 SHA="$(git rev-parse HEAD)" LATEST=8.5 docker buildx bake ``` ## Configuration diff --git a/docker-bake.hcl b/docker-bake.hcl index 71c6e84..05d0567 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -3,8 +3,8 @@ variable "IMAGE_NAME" { } variable "PHP_VERSION" { - description = "Comma-separated list of exact PHP versions to build, e.g. '8.4.23,8.5.8'." - default = "8.4.23,8.5.8" + description = "Comma-separated list of PHP minor versions to build, e.g. '8.4,8.5'." + default = "8.4,8.5" } variable "SHA" { @@ -13,89 +13,54 @@ variable "SHA" { } variable "LATEST" { - description = "The latest PHP version to use for tagging the 'latest' tag." - default = "8.5.8" + description = "The PHP minor version to publish under the latest aliases." + default = "8.5" } -function "clean_tag" { - params = [tag] - result = substr(regex_replace(regex_replace(tag, "[^\\w.-]", "-"), "^([^\\w])", "r$0"), 0, 127) -} - -function "stripOS" { - params = [tag] - result = replace(tag, "-trixie", "") +variable "REFRESH" { + description = "Optional cache-busting value for floating upstream dependencies." + default = "" } function "tag" { - params = [php_version, os, variant, version] - result = distinct(flatten([ - for pv in php_version(php_version) : flatten([ - // Base tags with OS and variant - ["${IMAGE_NAME}:php${pv}-${os}${variant == "dev" ? "-dev" : ""}"], - // Latest tags for the LATEST PHP version - pv == LATEST ? ["${IMAGE_NAME}:latest-${os}${variant == "dev" ? "-dev" : ""}"] : [], - // Semver tags with OS and variant (only if version is not empty and semver returns results) - [for v in (semver(version)) : "${IMAGE_NAME}:php${v}-${os}${variant == "dev" ? "-dev" : ""}" if v != split(".", version)[0] || php_version == LATEST], - ]) - ])) -} - -function "semver" { - params = [rev] - result = __semver(_semver(regexall("^v?(?P0|[1-9]\\d*)\\.(?P0|[1-9]\\d*)\\.(?P0|[1-9]\\d*)(?:-(?P(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?P[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", rev))) -} - -function "_semver" { - params = [matches] - result = length(matches) == 0 ? {} : matches[0] -} - -function "__semver" { - params = [v] - result = v.prerelease == null ? [v.major, "${v.major}.${v.minor}", "${v.major}.${v.minor}.${v.patch}"] : ["${v.major}.${v.minor}.${v.patch}-${v.prerelease}"] -} - -function "php_version" { - params = [v] - result = _php_version(v, regexall("(?P\\d+)\\.(?P\\d+)", v)[0]) -} - -function "_php_version" { - params = [v, m] - result = [v, "${m.major}.${m.minor}"] + params = [name, os, variant] + result = "${IMAGE_NAME}:${name}${os == "trixie" ? "" : "-${os}"}${variant == "dev" ? "-dev" : ""}" } target "default" { - name = "${tgt}-php-${replace(php_version, ".", "-")}-${os}${variant == "dev" ? "-dev" : "-production"}" + name = "runner-php-${replace(php_version, ".", "-")}-${os}-${variant}" matrix = { php_version = split(",", replace(PHP_VERSION, " ", "")) os = ["bookworm", "trixie"] - tgt = ["runner"] variant = ["prod", "dev"] } dockerfile = "Dockerfile" context = "./" - contexts = { - php-base = "docker-image://php:${php_version}-zts-${os}" - } platforms = [ "linux/amd64", "linux/arm64" ] - + target = variant + pull = true + + tags = distinct(concat( + [tag("php${php_version}", os, variant)], + php_version == LATEST ? [ + tag("php${split(".", php_version)[0]}", os, variant), + tag("latest", os, variant), + ] : [], + )) - tags = [for t in tag(php_version, os, variant, clean_tag(php_version)) : stripOS(t)] - args = { - VERSION = "${clean_tag(php_version)}-${os}" + VERSION = "${php_version}-${os}" + REFRESH = REFRESH } - + labels = { "org.opencontainers.image.description" = variant == "dev" ? "FrankenPHP Docker images (${os}) with supervisor, Node.js 26, pnpm, sqlsrv, Xdebug, and development tools." : "FrankenPHP Docker images (${os}) with supervisor, Node.js 26, pnpm, sqlsrv, and image tools." "org.opencontainers.image.created" = "${timestamp()}" - "org.opencontainers.image.version" = variant == "dev" ? "${clean_tag(php_version)}-${os}-dev" : "${clean_tag(php_version)}-${os}" + "org.opencontainers.image.version" = variant == "dev" ? "${php_version}-${os}-dev" : "${php_version}-${os}" "org.opencontainers.image.revision" = SHA } } diff --git a/usr/local/bin/wip b/usr/local/bin/wip deleted file mode 100644 index cd3a7c1..0000000 --- a/usr/local/bin/wip +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/zsh - -git add . -git commit -m "wip" -git push origin "$(git_current_branch)" \ No newline at end of file diff --git a/usr/local/bin/x b/usr/local/bin/x deleted file mode 100644 index 200d992..0000000 --- a/usr/local/bin/x +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/zsh - -set -e - -exec "$@" \ No newline at end of file