From 4c1b7d69402110b112d14dc7c97a6b61a2942257 Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 14:45:45 +0200 Subject: [PATCH 1/8] feat: build docker image via github actions --- .github/workflows/docker-image.yml | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/docker-image.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 00000000..3c3e3ea3 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,58 @@ +name: Docker Image CI + +on: + push: + tags: + - "[0-9]+.[0-9]+.[0-9]+" + workflow_dispatch: + inputs: + tag: + description: "Version tag to use for the Docker image" + required: true + +jobs: + build-and-push: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Log in to GitHub Packages + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Lower case docker image name + id: docker_image + uses: ASzc/change-string-case-action@v8 + with: + string: ${{ github.repository }} + + - name: Build and push latest + uses: docker/build-push-action@v7 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ghcr.io/${{ steps.docker_image.outputs.lowercase }}:latest + + - name: Build and push version tag + uses: docker/build-push-action@v7 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ghcr.io/${{ steps.docker_image.outputs.lowercase }}:${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} From c50b887e7350ee0993b5897d468f7090a4ccda80 Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 15:29:48 +0200 Subject: [PATCH 2/8] ci: add upstream tag support, GHA layer cache and conditional version tag push --- .github/workflows/docker-image.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 3c3e3ea3..a566084e 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -6,9 +6,9 @@ on: - "[0-9]+.[0-9]+.[0-9]+" workflow_dispatch: inputs: - tag: - description: "Version tag to use for the Docker image" - required: true + upstream_tag: + description: "Upstream tag of nextcloud/notify_push to build" + required: false jobs: build-and-push: @@ -21,6 +21,9 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v6 + with: + repository: ${{ inputs.upstream_tag && 'nextcloud/notify_push' || github.repository }} + ref: ${{ inputs.upstream_tag || github.ref_name }} - name: Log in to GitHub Packages uses: docker/login-action@v4 @@ -48,11 +51,16 @@ jobs: push: true platforms: linux/amd64,linux/arm64 tags: ghcr.io/${{ steps.docker_image.outputs.lowercase }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max - name: Build and push version tag + if: github.ref_type == 'tag' || inputs.upstream_tag != '' uses: docker/build-push-action@v7 with: context: . push: true platforms: linux/amd64,linux/arm64 - tags: ghcr.io/${{ steps.docker_image.outputs.lowercase }}:${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} + tags: ghcr.io/${{ steps.docker_image.outputs.lowercase }}:${{ inputs.upstream_tag || github.ref_name }} + cache-from: type=gha + cache-to: type=gha,mode=max From 0937b93207c877b107991183df384f1db6ac3ad9 Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 15:55:11 +0200 Subject: [PATCH 3/8] ci: use metadata-action for tag management, strip v prefix from upstream_tag --- .github/workflows/docker-image.yml | 107 +++++++++++++++-------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index a566084e..cbf0b1ec 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,66 +1,67 @@ name: Docker Image CI on: - push: - tags: - - "[0-9]+.[0-9]+.[0-9]+" - workflow_dispatch: - inputs: - upstream_tag: - description: "Upstream tag of nextcloud/notify_push to build" - required: false + push: + tags: + - "[0-9]+.[0-9]+.[0-9]+" + workflow_dispatch: + inputs: + upstream_tag: + description: "Upstream tag of nextcloud/notify_push to build" + required: false jobs: - build-and-push: - runs-on: ubuntu-latest + build-and-push: + runs-on: ubuntu-latest - permissions: - contents: read - packages: write + permissions: + contents: read + packages: write - steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - repository: ${{ inputs.upstream_tag && 'nextcloud/notify_push' || github.repository }} - ref: ${{ inputs.upstream_tag || github.ref_name }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + repository: ${{ inputs.upstream_tag && 'nextcloud/notify_push' || github.repository }} + ref: ${{ inputs.upstream_tag || github.ref_name }} - - name: Log in to GitHub Packages - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Log in to GitHub Packages + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 - - name: Lower case docker image name - id: docker_image - uses: ASzc/change-string-case-action@v8 - with: - string: ${{ github.repository }} + - name: Sanitize upstream tag + if: inputs.upstream_tag != '' + id: tag + run: echo "value=${INPUT_TAG#v}" >> $GITHUB_OUTPUT + env: + INPUT_TAG: ${{ inputs.upstream_tag }} - - name: Build and push latest - uses: docker/build-push-action@v7 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: ghcr.io/${{ steps.docker_image.outputs.lowercase }}:latest - cache-from: type=gha - cache-to: type=gha,mode=max + - name: Extract metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=tag + type=raw,value=latest + type=raw,value=${{ steps.tag.outputs.value }},enable=${{ inputs.upstream_tag != '' }} - - name: Build and push version tag - if: github.ref_type == 'tag' || inputs.upstream_tag != '' - uses: docker/build-push-action@v7 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: ghcr.io/${{ steps.docker_image.outputs.lowercase }}:${{ inputs.upstream_tag || github.ref_name }} - cache-from: type=gha - cache-to: type=gha,mode=max + - name: Build and push + uses: docker/build-push-action@v7 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max From 90e3808fcdb627634f354565cce1563c7fbf5dad Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 16:29:26 +0200 Subject: [PATCH 4/8] ci: use native runners matrix to eliminate QEMU overhead Thanks to https://github.com/sredevopsorg/multi-arch-docker-github-workflow --- .github/workflows/docker-image.yml | 116 ++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index cbf0b1ec..f604c29f 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,3 +1,4 @@ +# Inspired by https://github.com/sredevopsorg/multi-arch-docker-github-workflow name: Docker Image CI on: @@ -11,13 +12,22 @@ on: required: false jobs: - build-and-push: - runs-on: ubuntu-latest + build: + runs-on: ${{ matrix.runner }} permissions: contents: read packages: write + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm + steps: - name: Checkout code uses: actions/checkout@v6 @@ -32,9 +42,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 @@ -55,13 +62,100 @@ jobs: type=raw,value=latest type=raw,value=${{ steps.tag.outputs.value }},enable=${{ inputs.upstream_tag != '' }} - - name: Build and push + - name: Build and push by digest + id: build uses: docker/build-push-action@v7 with: context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} + platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + outputs: type=image,name=ghcr.io/${{ github.repository }},push-by-digest=true,name-canonical=true,push=true + cache-from: type=gha,scope=${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=${{ matrix.platform }} + + - name: Export digest + run: | + mkdir -p /tmp/digests + touch "/tmp/digests/${DIGEST#sha256:}" + env: + DIGEST: ${{ steps.build.outputs.digest }} + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: build + + permissions: + contents: read + packages: write + + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Log in to GitHub Packages + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Sanitize upstream tag + if: inputs.upstream_tag != '' + id: tag + run: echo "value=${INPUT_TAG#v}" >> $GITHUB_OUTPUT + env: + INPUT_TAG: ${{ inputs.upstream_tag }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=tag + type=raw,value=latest + type=raw,value=${{ steps.tag.outputs.value }},enable=${{ inputs.upstream_tag != '' }} + + - name: Get timestamp + id: timestamp + run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT + + - name: Create and push manifest + id: manifest + working-directory: /tmp/digests + continue-on-error: true + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + --annotation='index:org.opencontainers.image.description=${{ github.event.repository.description }}' \ + --annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \ + --annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \ + --annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \ + $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) + + - name: Create and push manifest (without annotations) + if: steps.manifest.outcome == 'failure' + working-directory: /tmp/digests + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) + + - name: Inspect manifest + run: | + docker buildx imagetools inspect 'ghcr.io/${{ github.repository }}:${{ steps.meta.outputs.version }}' From 077da13293b98eb66cd12335d0a860bd4f9463dd Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 16:37:56 +0200 Subject: [PATCH 5/8] ci: fix lower casing --- .github/workflows/docker-image.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index f604c29f..35967b83 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -45,6 +45,12 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 + - name: Lower case docker image name + id: image + uses: ASzc/change-string-case-action@v8 + with: + string: ${{ github.repository }} + - name: Sanitize upstream tag if: inputs.upstream_tag != '' id: tag @@ -69,7 +75,7 @@ jobs: context: . platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=ghcr.io/${{ github.repository }},push-by-digest=true,name-canonical=true,push=true + outputs: type=image,name=ghcr.io/${{ steps.image.outputs.lowercase }},push-by-digest=true,name-canonical=true,push=true cache-from: type=gha,scope=${{ matrix.platform }} cache-to: type=gha,mode=max,scope=${{ matrix.platform }} @@ -114,6 +120,12 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 + - name: Lower case docker image name + id: image + uses: ASzc/change-string-case-action@v8 + with: + string: ${{ github.repository }} + - name: Sanitize upstream tag if: inputs.upstream_tag != '' id: tag @@ -146,7 +158,7 @@ jobs: --annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \ --annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \ --annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \ - $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) + $(printf 'ghcr.io/${{ steps.image.outputs.lowercase }}@sha256:%s ' *) - name: Create and push manifest (without annotations) if: steps.manifest.outcome == 'failure' @@ -154,8 +166,8 @@ jobs: run: | docker buildx imagetools create \ $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) + $(printf 'ghcr.io/${{ steps.image.outputs.lowercase }}@sha256:%s ' *) - name: Inspect manifest run: | - docker buildx imagetools inspect 'ghcr.io/${{ github.repository }}:${{ steps.meta.outputs.version }}' + docker buildx imagetools inspect 'ghcr.io/${{ steps.image.outputs.lowercase }}:${{ steps.meta.outputs.version }}' From 55f70d0320a3d003e81acf55e439439267ab493e Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 16:40:35 +0200 Subject: [PATCH 6/8] chore: indentation --- .github/workflows/docker-image.yml | 334 ++++++++++++++--------------- 1 file changed, 167 insertions(+), 167 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 35967b83..c234098b 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -2,172 +2,172 @@ name: Docker Image CI on: - push: - tags: - - "[0-9]+.[0-9]+.[0-9]+" - workflow_dispatch: - inputs: - upstream_tag: - description: "Upstream tag of nextcloud/notify_push to build" - required: false + push: + tags: + - "[0-9]+.[0-9]+.[0-9]+" + workflow_dispatch: + inputs: + upstream_tag: + description: "Upstream tag of nextcloud/notify_push to build" + required: false jobs: - build: - runs-on: ${{ matrix.runner }} - - permissions: - contents: read - packages: write - - strategy: - fail-fast: false - matrix: - include: - - platform: linux/amd64 - runner: ubuntu-latest - - platform: linux/arm64 - runner: ubuntu-24.04-arm - - steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - repository: ${{ inputs.upstream_tag && 'nextcloud/notify_push' || github.repository }} - ref: ${{ inputs.upstream_tag || github.ref_name }} - - - name: Log in to GitHub Packages - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Lower case docker image name - id: image - uses: ASzc/change-string-case-action@v8 - with: - string: ${{ github.repository }} - - - name: Sanitize upstream tag - if: inputs.upstream_tag != '' - id: tag - run: echo "value=${INPUT_TAG#v}" >> $GITHUB_OUTPUT - env: - INPUT_TAG: ${{ inputs.upstream_tag }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v6 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=ref,event=tag - type=raw,value=latest - type=raw,value=${{ steps.tag.outputs.value }},enable=${{ inputs.upstream_tag != '' }} - - - name: Build and push by digest - id: build - uses: docker/build-push-action@v7 - with: - context: . - platforms: ${{ matrix.platform }} - labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=ghcr.io/${{ steps.image.outputs.lowercase }},push-by-digest=true,name-canonical=true,push=true - cache-from: type=gha,scope=${{ matrix.platform }} - cache-to: type=gha,mode=max,scope=${{ matrix.platform }} - - - name: Export digest - run: | - mkdir -p /tmp/digests - touch "/tmp/digests/${DIGEST#sha256:}" - env: - DIGEST: ${{ steps.build.outputs.digest }} - - - name: Upload digest - uses: actions/upload-artifact@v4 - with: - name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - merge: - runs-on: ubuntu-latest - needs: build - - permissions: - contents: read - packages: write - - steps: - - name: Download digests - uses: actions/download-artifact@v4 - with: - path: /tmp/digests - pattern: digests-* - merge-multiple: true - - - name: Log in to GitHub Packages - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Lower case docker image name - id: image - uses: ASzc/change-string-case-action@v8 - with: - string: ${{ github.repository }} - - - name: Sanitize upstream tag - if: inputs.upstream_tag != '' - id: tag - run: echo "value=${INPUT_TAG#v}" >> $GITHUB_OUTPUT - env: - INPUT_TAG: ${{ inputs.upstream_tag }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v6 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=ref,event=tag - type=raw,value=latest - type=raw,value=${{ steps.tag.outputs.value }},enable=${{ inputs.upstream_tag != '' }} - - - name: Get timestamp - id: timestamp - run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT - - - name: Create and push manifest - id: manifest - working-directory: /tmp/digests - continue-on-error: true - run: | - docker buildx imagetools create \ - $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - --annotation='index:org.opencontainers.image.description=${{ github.event.repository.description }}' \ - --annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \ - --annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \ - --annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \ - $(printf 'ghcr.io/${{ steps.image.outputs.lowercase }}@sha256:%s ' *) - - - name: Create and push manifest (without annotations) - if: steps.manifest.outcome == 'failure' - working-directory: /tmp/digests - run: | - docker buildx imagetools create \ - $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf 'ghcr.io/${{ steps.image.outputs.lowercase }}@sha256:%s ' *) - - - name: Inspect manifest - run: | - docker buildx imagetools inspect 'ghcr.io/${{ steps.image.outputs.lowercase }}:${{ steps.meta.outputs.version }}' + build: + runs-on: ${{ matrix.runner }} + + permissions: + contents: read + packages: write + + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + repository: ${{ inputs.upstream_tag && 'nextcloud/notify_push' || github.repository }} + ref: ${{ inputs.upstream_tag || github.ref_name }} + + - name: Log in to GitHub Packages + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Lower case docker image name + id: image + uses: ASzc/change-string-case-action@v8 + with: + string: ${{ github.repository }} + + - name: Sanitize upstream tag + if: inputs.upstream_tag != '' + id: tag + run: echo "value=${INPUT_TAG#v}" >> $GITHUB_OUTPUT + env: + INPUT_TAG: ${{ inputs.upstream_tag }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=tag + type=raw,value=latest + type=raw,value=${{ steps.tag.outputs.value }},enable=${{ inputs.upstream_tag != '' }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v7 + with: + context: . + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,name=ghcr.io/${{ steps.image.outputs.lowercase }},push-by-digest=true,name-canonical=true,push=true + cache-from: type=gha,scope=${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=${{ matrix.platform }} + + - name: Export digest + run: | + mkdir -p /tmp/digests + touch "/tmp/digests/${DIGEST#sha256:}" + env: + DIGEST: ${{ steps.build.outputs.digest }} + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: build + + permissions: + contents: read + packages: write + + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Log in to GitHub Packages + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Lower case docker image name + id: image + uses: ASzc/change-string-case-action@v8 + with: + string: ${{ github.repository }} + + - name: Sanitize upstream tag + if: inputs.upstream_tag != '' + id: tag + run: echo "value=${INPUT_TAG#v}" >> $GITHUB_OUTPUT + env: + INPUT_TAG: ${{ inputs.upstream_tag }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=tag + type=raw,value=latest + type=raw,value=${{ steps.tag.outputs.value }},enable=${{ inputs.upstream_tag != '' }} + + - name: Get timestamp + id: timestamp + run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT + + - name: Create and push manifest + id: manifest + working-directory: /tmp/digests + continue-on-error: true + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + --annotation='index:org.opencontainers.image.description=${{ github.event.repository.description }}' \ + --annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \ + --annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \ + --annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \ + $(printf 'ghcr.io/${{ steps.image.outputs.lowercase }}@sha256:%s ' *) + + - name: Create and push manifest (without annotations) + if: steps.manifest.outcome == 'failure' + working-directory: /tmp/digests + run: | + docker buildx imagetools create \ + $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf 'ghcr.io/${{ steps.image.outputs.lowercase }}@sha256:%s ' *) + + - name: Inspect manifest + run: | + docker buildx imagetools inspect 'ghcr.io/${{ steps.image.outputs.lowercase }}:${{ steps.meta.outputs.version }}' From bb43000682a2b2f90f6aa0317bfbd7c1828ce8ea Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 16:47:29 +0200 Subject: [PATCH 7/8] ci: actions update --- .github/workflows/docker-image.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index c234098b..637f09a4 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -87,7 +87,7 @@ jobs: DIGEST: ${{ steps.build.outputs.digest }} - name: Upload digest - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} path: /tmp/digests/* @@ -104,7 +104,7 @@ jobs: steps: - name: Download digests - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: path: /tmp/digests pattern: digests-* From fd479e60f1f86e4ca8943146fa7bad0d2360ecf5 Mon Sep 17 00:00:00 2001 From: rizlas Date: Fri, 10 Apr 2026 20:45:57 +0200 Subject: [PATCH 8/8] ci: fix tag naming pattern --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 637f09a4..bbd94e7d 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -4,7 +4,7 @@ name: Docker Image CI on: push: tags: - - "[0-9]+.[0-9]+.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+" workflow_dispatch: inputs: upstream_tag: