From 2183976b85db1c77ede744d5775403765f5d8b43 Mon Sep 17 00:00:00 2001 From: Abdussamet Kocak Date: Thu, 8 Oct 2026 21:29:16 +0200 Subject: [PATCH] ci: Add multi-arch Docker build/publish and tagged release workflow Build and push linux/amd64 + linux/arm64 images to GHCR on every push to master and on v* tags. On v* tags, also generate a changelog from conventional commits and create a GitHub release. --- .github/generate_changelog.sh | 45 ++++++++++++++ .github/workflows/docker-publish.yml | 88 ++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100755 .github/generate_changelog.sh create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/generate_changelog.sh b/.github/generate_changelog.sh new file mode 100755 index 0000000..0130be7 --- /dev/null +++ b/.github/generate_changelog.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: ./generate_changelog.sh [] +# +# Groups commits by their conventional-commit prefix (feat, fix, ...) into +# sections. Commits within each section are sorted oldest-first. Commits +# that don't match a known prefix land in an "Other" section. + +range="${1:-}" + +types="feat fix refactor perf docs test ci build chore" + +label_for() { + case "$1" in + feat) echo "Features" ;; + fix) echo "Fixes" ;; + refactor) echo "Refactoring" ;; + perf) echo "Performance" ;; + docs) echo "Documentation" ;; + test) echo "Tests" ;; + ci) echo "CI" ;; + build) echo "Build" ;; + chore) echo "Chores" ;; + *) echo "Other" ;; + esac +} + +commits=$(git log ${range} --reverse --pretty='format:%s') +known_pattern="^(feat|fix|refactor|perf|docs|test|ci|build|chore): " + +first_section=1 +for type in $types other; do + if [ "$type" = "other" ]; then + entries=$(printf '%s\n' "$commits" | grep -v -E "$known_pattern" | sed 's/^/- /' || true) + else + entries=$(printf '%s\n' "$commits" | grep -E "^${type}: " | sed -E "s/^${type}: /- /" || true) + fi + + [ -z "$entries" ] && continue + [ "$first_section" -eq 0 ] && echo + first_section=0 + + printf '### %s\n\n%s\n' "$(label_for "$type")" "$entries" +done diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..4575acb --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,88 @@ +name: Docker build & release + +on: + push: + branches: [master] + tags: ["v*"] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - 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: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=sha,format=short + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + release: + needs: build-and-push + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Generate changelog + id: changelog + run: | + prev_tag=$(git describe --tags --abbrev=0 "${{ github.ref_name }}^" 2>/dev/null || true) + if [ -n "$prev_tag" ]; then + range="${prev_tag}..${{ github.ref_name }}" + else + range="" + fi + .github/generate_changelog.sh "$range" > /tmp/changelog.md + cat /tmp/changelog.md + + - name: Create GitHub release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "${{ github.ref_name }}" \ + --title "${{ github.ref_name }}" \ + --notes-file /tmp/changelog.md