diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e41af7f..083f2e9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -16,22 +16,11 @@ env: REGISTRY: ghcr.io jobs: - build-and-push: + prepare-tags-and-names: runs-on: ubuntu-latest - strategy: - matrix: - service: - - name: frontend - image: librislog - dockerfile: ./frontend/Dockerfile - context: ./frontend - - name: backend - image: librislog-api - dockerfile: ./backend/Dockerfile - context: ./backend + permissions: contents: read - packages: write steps: - name: Checkout repository @@ -59,6 +48,54 @@ jobs: SANITIZED="$(echo "$SANITIZED" | sed 's/^[^a-zA-Z0-9_]\+//')" echo "sanitized_tag=${SANITIZED:0:128}" >> "$GITHUB_OUTPUT" + - name: Normalize repository name + id: repo + uses: actions/github-script@v7 + with: + result-encoding: string + script: return `${context.repo.owner}/${context.repo.repo}`.toLowerCase() + + outputs: + version: ${{ steps.version.outputs.version }} + sha_short: ${{ steps.version.outputs.sha_short }} + sanitized_tag: ${{ steps.sanitize.outputs.sanitized_tag }} + repository: ${{ steps.repo.outputs.result }} + + build-and-push: + runs-on: ${{ matrix.runner }} + needs: prepare-tags-and-names + strategy: + fail-fast: false + matrix: + service: + - name: frontend + image: librislog + dockerfile: ./frontend/Dockerfile + context: ./frontend + - name: backend + image: librislog-api + dockerfile: ./backend/Dockerfile + context: ./backend + + arch: [amd64, arm64] + + include: + - arch: amd64 + runner: ubuntu-latest + - arch: arm64 + runner: ubuntu-24.04-arm + + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: ${{ github.event.inputs.branch || github.ref }} + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 @@ -72,14 +109,14 @@ jobs: - name: Generate image tags id: tags run: | - IMAGE="${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service.image }}" - SHA_SHORT="${{ steps.version.outputs.sha_short }}" + IMAGE="${{ env.REGISTRY }}/${{ needs.prepare-tags-and-names.outputs.repository }}/${{ matrix.service.image }}" + SHA_SHORT="${{ needs.prepare-tags-and-names.outputs.sha_short }}" if [ "${{ github.event_name }}" = "release" ]; then - SANITIZED="${{ steps.sanitize.outputs.sanitized_tag }}" - TAGS="${IMAGE}:${SANITIZED},${IMAGE}:latest" + SANITIZED="${{ needs.prepare-tags-and-names.outputs.sanitized_tag }}" + TAGS="${IMAGE}:${SANITIZED}-${{ matrix.arch }},${IMAGE}:latest-${{ matrix.arch }}" else - TAGS="${IMAGE}:develop,${IMAGE}:${SHA_SHORT}" + TAGS="${IMAGE}:develop-${{ matrix.arch }},${IMAGE}:${SHA_SHORT}-${{ matrix.arch }}" fi echo "tags=${TAGS}" >> "$GITHUB_OUTPUT" @@ -90,11 +127,51 @@ jobs: context: ${{ matrix.service.context }} file: ${{ matrix.service.dockerfile }} push: true - platforms: linux/amd64 + platforms: linux/${{ matrix.arch }} tags: ${{ steps.tags.outputs.tags }} build-args: | - APP_VERSION=${{ steps.version.outputs.version }} + APP_VERSION=${{ needs.prepare-tags-and-names.outputs.version }} GIT_SHA=${{ github.sha }} ${{ matrix.service.name == 'frontend' && 'PUBLIC_DEFAULT_LOCALE=en' || '' }} cache-from: type=gha cache-to: type=gha,mode=max + + create-manifest: + needs: [prepare-tags-and-names, build-and-push] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + service: + - name: frontend + image: librislog + - name: backend + image: librislog-api + + permissions: + packages: write + + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create multi-arch manifest + run: | + IMAGE="${{ env.REGISTRY }}/${{ needs.prepare-tags-and-names.outputs.repository }}/${{ matrix.service.image }}" + SHA_SHORT="${{ needs.prepare-tags-and-names.outputs.sha_short }}" + + if [ "${{ github.event_name }}" = "release" ]; then + SANITIZED="${{ needs.prepare-tags-and-names.outputs.sanitized_tag }}" + docker buildx imagetools create -t "${IMAGE}:${SANITIZED}" "${IMAGE}:${SANITIZED}-amd64" "${IMAGE}:${SANITIZED}-arm64" + docker buildx imagetools create -t "${IMAGE}:latest" "${IMAGE}:latest-amd64" "${IMAGE}:latest-arm64" + else + docker buildx imagetools create -t "${IMAGE}:develop" "${IMAGE}:develop-amd64" "${IMAGE}:develop-arm64" + docker buildx imagetools create -t "${IMAGE}:${SHA_SHORT}" "${IMAGE}:${SHA_SHORT}-amd64" "${IMAGE}:${SHA_SHORT}-arm64" + fi