diff --git a/.github/workflows/static.yaml b/.github/workflows/static.yaml index 81f772eb..b17ea1d3 100644 --- a/.github/workflows/static.yaml +++ b/.github/workflows/static.yaml @@ -16,22 +16,61 @@ on: required: false type: string schedule: - - cron: '0 0 * * *' + - cron: '0 0 * * *' jobs: prepare: runs-on: ubuntu-latest outputs: - ref: ${{ steps.ref.outputs.ref || (github.event_name == 'workflow_dispatch' && inputs.version) || '' }} + push: ${{ toJson((steps.check.outputs.ref || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')) && true || false) }} + platforms: ${{ steps.matrix.outputs.platforms }} + metadata: ${{ steps.matrix.outputs.metadata }} + ref: ${{ steps.check.outputs.ref }} steps: - - name: Get latest release - id: ref + name: Get version + id: check if: github.event_name == 'schedule' - run: echo ref="$(gh release view --repo dunglas/frankenphp --json tagName --jq '.tagName')" >> "${GITHUB_OUTPUT}" + run: | + ref="${{ (github.ref_type == 'tag' && github.ref_name) || (github.event_name == 'workflow_dispatch' && inputs.version) || '' }}" + if [[ -z "${ref}" ]]; then + ref="$(gh release view --repo dunglas/frankenphp --json tagName --jq '.tagName')" + fi + + echo "ref=${ref}" >> "${GITHUB_OUTPUT}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - + uses: actions/checkout@v4 + with: + ref: ${{ steps.check.outputs.ref }} + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + version: latest + - + name: Create platforms matrix + id: matrix + run: | + METADATA="$(docker buildx bake --print static-builder | jq -c)" + { + echo metadata="${METADATA}" + echo platforms="$(jq -c 'first(.target[]) | .platforms' <<< "${METADATA}")" + } >> "${GITHUB_OUTPUT}" + env: + SHA: ${{ github.sha }} + VERSION: ${{ steps.check.outputs.ref || github.sha }} build-linux: - name: Build Linux x86_64 binary + strategy: + fail-fast: false + matrix: + platform: ${{ fromJson(needs.prepare.outputs.platforms) }} + include: + - race: "" + qemu: true + - platform: linux/amd64 + qemu: false + name: Build ${{ matrix.platform }} static binary runs-on: ubuntu-latest needs: [ prepare ] steps: @@ -39,55 +78,133 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ needs.prepare.outputs.ref }} + - + name: Set up QEMU + if: matrix.qemu + uses: docker/setup-qemu-action@v3 + with: + platforms: ${{ matrix.platform }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: + platforms: ${{ matrix.platform }} version: latest - name: Login to DockerHub - if: needs.prepare.outputs.ref || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request') + if: ${{ fromJson(needs.prepare.outputs.push) }} uses: docker/login-action@v3 with: - username: ${{secrets.REGISTRY_USERNAME}} - password: ${{secrets.REGISTRY_PASSWORD}} + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} - name: Build id: build uses: docker/bake-action@v4 with: pull: true - load: ${{ (!needs.prepare.outputs.ref && !startsWith(github.ref, 'refs/tags/') && (github.ref != 'refs/heads/main' || github.event_name == 'pull_request')) && true || false }} - push: ${{ (needs.prepare.outputs.ref || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')) && true || false }} + load: ${{ !fromJson(needs.prepare.outputs.push) }} targets: static-builder set: | - *.cache-from=type=gha,scope=${{needs.prepare.outputs.ref || github.ref}}-static-builder + *.platform=${{ matrix.platform }} + *.cache-from=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder *.cache-from=type=gha,scope=refs/heads/main-static-builder - *.cache-to=type=gha,scope=${{needs.prepare.outputs.ref || github.ref}}-static-builder,ignore-error=true + *.cache-to=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder,ignore-error=true + ${{ fromJson(needs.prepare.outputs.push) && '*.output=type=image,name=dunglas/frankenphp,push-by-digest=true,name-canonical=true,push=true' || '' }} env: - SHA: ${{github.sha}} + SHA: ${{ github.sha }} VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || github.sha}} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Pull Docker image - if: needs.prepare.outputs.ref || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request') - run: docker pull dunglas/frankenphp:static-builder + # Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600 + name: Export metadata + if: fromJson(needs.prepare.outputs.push) + run: | + mkdir -p /tmp/metadata + + # shellcheck disable=SC2086 + digest=$(jq -r '."static-builder"."containerimage.digest"' <<< ${METADATA}) + touch "/tmp/metadata/${digest#sha256:}" + env: + METADATA: ${{ steps.build.outputs.metadata }} + - + name: Upload metadata + if: fromJson(needs.prepare.outputs.push) + uses: actions/upload-artifact@v3 + with: + name: metadata-static-builder + path: /tmp/metadata/* + if-no-files-found: error + retention-days: 1 - name: Copy binary - run: docker cp "$(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-x86_64" frankenphp-linux-x86_64 ; docker rm static-builder + if: ${{ !fromJson(needs.prepare.outputs.push) }} + run: | + tag=$(jq -cr '.target."static-builder".tags | first' <<< "${METADATA}") + container=$(docker create --platform=${{ matrix.platform }} --name static-builder "${tag}") + docker cp "${container}:/go/src/app/dist/${BINARY}" "${BINARY}" + env: + METADATA: ${{ needs.prepare.outputs.metadata }} + BINARY: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }} + - + name: Upload artifact + if: ${{ !fromJson(needs.prepare.outputs.push) }} + uses: actions/upload-artifact@v3 + with: + name: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }} + path: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }} + # Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/ + push: + runs-on: ubuntu-latest + needs: + - prepare + - build-linux + if: fromJson(needs.prepare.outputs.push) + #if: fromJson(needs.prepare.outputs.push) && (needs.prepare.outputs.ref || github.ref_type == 'tag') + steps: + - + name: Download metadata + uses: actions/download-artifact@v3 + with: + name: metadata-static-builder + path: /tmp/metadata + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + version: latest + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} + - + name: Create manifest list and push + working-directory: /tmp/metadata + run: | + # shellcheck disable=SC2046,SC2086 + docker buildx imagetools create $(jq -cr '.target."static-builder".tags | map("-t " + .) | join(" ")' <<< ${METADATA}) \ + $(printf 'dunglas/frankenphp@sha256:%s ' *) + env: + METADATA: ${{ needs.prepare.outputs.metadata }} + - + name: Inspect image + run: | + # shellcheck disable=SC2046,SC2086 + docker buildx imagetools inspect static-builder + - + name: Copy binary + run: | + tag=$(jq -cr '.target."static-builder".tags | first' <<< "${METADATA}") + docker cp "$(docker create --platform=linux/amd64 --name static-builder "${tag}"):/go/src/app/dist/frankenphp-linux-x86_64" frankenphp-linux-x86_64 ; docker rm static-builder + docker cp "$(docker create --platform=linux/arm64 --name static-builder "${tag}"):/go/src/app/dist/frankenphp-linux-aarch64" frankenphp-linux-aarch64 ; docker rm static-builder - name: Upload asset if: needs.prepare.outputs.ref || github.ref_type == 'tag' - run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" frankenphp-linux-x86_64 --repo dunglas/frankenphp --clobber + run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" frankenphp-linux-x86_64 frankenphp-linux-aarch64 --repo dunglas/frankenphp --clobber env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Upload artifact - if: github.ref_type == 'branch' - uses: actions/upload-artifact@v3 - with: - name: frankenphp-linux-x86_64 - path: frankenphp-linux-x86_64 build-mac: name: Build macOS x86_64 binaries runs-on: macos-latest diff --git a/docker-bake.hcl b/docker-bake.hcl index 5ed2f3a5..17b92e89 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -123,6 +123,10 @@ target "static-builder" { } dockerfile = "static-builder.Dockerfile" context = "./" + platforms = [ + "linux/amd64", + "linux/arm64", + ] tags = distinct(flatten([ LATEST ? "${IMAGE_NAME}:static-builder" : "", SHA == "" ? "" : "${IMAGE_NAME}:static-builder-sha-${substr(SHA, 0, 7)}",