name: Docker Release on: workflow_dispatch: inputs: platforms: type: choice description: 'Build Platforms' required: true default: 'linux/amd64' options: - 'linux/amd64' - 'linux/amd64,linux/arm64' docker_tags: type: string description: 'Docker Tags' required: true default: 'dev' push: branches: - master release: types: - published # Prevent concurrent releases - queue them instead concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false env: REGISTRY: ghcr.io permissions: contents: read packages: write jobs: # Determine which platforms to build based on trigger type prepare: runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} is_multi_arch: ${{ steps.set-matrix.outputs.is_multi_arch }} steps: - name: Determine build matrix id: set-matrix run: | # Release events always build both architectures # Push to master only builds amd64 (for speed) # workflow_dispatch uses the selected platforms input if [[ "${{ github.event_name }}" == "release" ]]; then echo 'matrix={"include":[{"platform":"linux/amd64","runner":"ubuntu-latest"},{"platform":"linux/arm64","runner":"ubuntu-24.04-arm"}]}' >> "$GITHUB_OUTPUT" echo "is_multi_arch=true" >> "$GITHUB_OUTPUT" elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then PLATFORMS="${{ inputs.platforms }}" if [[ "$PLATFORMS" == *"arm64"* ]]; then echo 'matrix={"include":[{"platform":"linux/amd64","runner":"ubuntu-latest"},{"platform":"linux/arm64","runner":"ubuntu-24.04-arm"}]}' >> "$GITHUB_OUTPUT" echo "is_multi_arch=true" >> "$GITHUB_OUTPUT" else echo 'matrix={"include":[{"platform":"linux/amd64","runner":"ubuntu-latest"}]}' >> "$GITHUB_OUTPUT" echo "is_multi_arch=false" >> "$GITHUB_OUTPUT" fi else # Push to master - only amd64 for faster dev builds echo 'matrix={"include":[{"platform":"linux/amd64","runner":"ubuntu-latest"}]}' >> "$GITHUB_OUTPUT" echo "is_multi_arch=false" >> "$GITHUB_OUTPUT" fi build: needs: prepare runs-on: ${{ matrix.runner }} timeout-minutes: 45 strategy: fail-fast: false matrix: ${{ fromJson(needs.prepare.outputs.matrix) }} steps: - name: Prepare environment run: | platform="${{ matrix.platform }}" echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV" echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Login to GitHub Container Registry uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata for Docker id: meta uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Build and push by digest id: build uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 with: context: . file: ./docker/selfhosted.Dockerfile platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true cache-from: type=gha,scope=build-${{ env.PLATFORM_PAIR }} cache-to: type=gha,scope=build-${{ env.PLATFORM_PAIR }},mode=max sbom: true provenance: true - name: Export digest run: | mkdir -p /tmp/digests digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" - name: Upload digest uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: digests-${{ env.PLATFORM_PAIR }} path: /tmp/digests/* if-no-files-found: error retention-days: 1 merge: needs: [prepare, build] runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Prepare environment run: | echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" - name: Download digests uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: pattern: digests-* path: /tmp/digests merge-multiple: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Login to GitHub Container Registry uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata for Docker id: meta uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # All non-release actions will be tagged as `dev` (ie: push, workflow_dispatch) tags: | type=ref,event=tag type=raw,value=dev,enable=${{ github.event_name != 'release' && github.event_name != 'workflow_dispatch' }} type=raw,value=${{ inputs.docker_tags }},enable=${{ github.event_name == 'workflow_dispatch' }} flavor: | latest=auto - name: Create manifest list and push working-directory: /tmp/digests run: | # shellcheck disable=SC2046 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 }}:${{ steps.meta.outputs.version }}