From 2fba3236ad8629e8a3bc1a7f81ba0330b4b2c3e8 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Fri, 31 Oct 2025 23:57:24 +0100 Subject: [PATCH] Add GHCR build/publish workflow --- .github/workflows/docker-publish.yml | 197 +++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..be92a4b --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,197 @@ +name: Build & Publish Images + +on: + push: + branches: [ main, dev ] + tags: + - '*' + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_BACKEND: papercrate-dms/papercrate-backend + IMAGE_FRONTEND: papercrate-dms/papercrate-frontend + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + component: [backend, frontend] + platform: [linux/amd64, linux/arm64] + + permissions: + contents: read + packages: write + id-token: write + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set component metadata + run: | + if [ "${{ matrix.component }}" = "backend" ]; then + echo "COMPONENT_CONTEXT=./backend" >> "$GITHUB_ENV" + echo "COMPONENT_IMAGE=${{ env.IMAGE_BACKEND }}" >> "$GITHUB_ENV" + else + echo "COMPONENT_CONTEXT=./frontend" >> "$GITHUB_ENV" + echo "COMPONENT_IMAGE=${{ env.IMAGE_FRONTEND }}" >> "$GITHUB_ENV" + fi + echo "COMPONENT_NAME=${{ matrix.component }}" >> "$GITHUB_ENV" + + - name: Compute tags + env: + GITHUB_SHA: ${{ github.sha }} + GITHUB_REF: ${{ github.ref }} + REGISTRY: ${{ env.REGISTRY }} + PLATFORM: ${{ matrix.platform }} + run: | + ARCH=${PLATFORM#*/} + TAGS=("${GITHUB_SHA::7}") + + BRANCH=${GITHUB_REF##*/} + if [ "$BRANCH" = "dev" ]; then + TAGS+=("${GITHUB_SHA::7}-dev") + fi + + if [[ "$GITHUB_REF" == refs/tags/* ]]; then + TAGS+=("${GITHUB_REF#refs/tags/}") + fi + + UNIQUE=() + for tag in "${TAGS[@]}"; do + [[ -z "$tag" ]] && continue + skip=false + for seen in "${UNIQUE[@]}"; do + if [ "$tag" = "$seen" ]; then + skip=true + break + fi + done + if [ "$skip" = false ]; then + UNIQUE+=("$tag") + fi + done + + { + echo "BASE_TAGS<> "$GITHUB_ENV" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build & push ${{ env.COMPONENT_NAME }} (${{ matrix.platform }}) + uses: docker/build-push-action@v5 + with: + context: ${{ env.COMPONENT_CONTEXT }} + push: true + platforms: ${{ matrix.platform }} + tags: ${{ env.IMAGE_TAGS }} + + manifest: + runs-on: ubuntu-latest + needs: build + strategy: + matrix: + component: [backend, frontend] + + permissions: + contents: read + packages: write + + env: + REGISTRY: ghcr.io + ARCHES: amd64 arm64 + + steps: + - name: Set component metadata + run: | + if [ "${{ matrix.component }}" = "backend" ]; then + echo "COMPONENT_IMAGE=${{ env.IMAGE_BACKEND }}" >> "$GITHUB_ENV" + else + echo "COMPONENT_IMAGE=${{ env.IMAGE_FRONTEND }}" >> "$GITHUB_ENV" + fi + echo "COMPONENT_NAME=${{ matrix.component }}" >> "$GITHUB_ENV" + + - name: Compute base tags + env: + GITHUB_SHA: ${{ github.sha }} + GITHUB_REF: ${{ github.ref }} + run: | + TAGS=("${GITHUB_SHA::7}") + + BRANCH=${GITHUB_REF##*/} + if [ "$BRANCH" = "dev" ]; then + TAGS+=("${GITHUB_SHA::7}-dev") + fi + + if [[ "$GITHUB_REF" == refs/tags/* ]]; then + TAGS+=("${GITHUB_REF#refs/tags/}") + fi + + UNIQUE=() + for tag in "${TAGS[@]}"; do + [[ -z "$tag" ]] && continue + skip=false + for seen in "${UNIQUE[@]}"; do + if [ "$tag" = "$seen" ]; then + skip=true + break + fi + done + if [ "$skip" = false ]; then + UNIQUE+=("$tag") + fi + done + + { + echo "BASE_TAGS<> "$GITHUB_ENV" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create manifests for ${{ env.COMPONENT_NAME }} + run: | + while IFS= read -r tag; do + [ -n "$tag" ] || continue + args=() + for arch in $ARCHES; do + args+=("$REGISTRY/$COMPONENT_IMAGE:${tag}-${arch}") + done + docker buildx imagetools create \ + --tag "$REGISTRY/$COMPONENT_IMAGE:$tag" \ + "${args[@]}" + done <<< "$BASE_TAGS"