Skip to content

fix/feat: v7.0.6 — CodeQL security fixes (7 alerts), tag chip UI, upg… #141

fix/feat: v7.0.6 — CodeQL security fixes (7 alerts), tag chip UI, upg…

fix/feat: v7.0.6 — CodeQL security fixes (7 alerts), tag chip UI, upg… #141

name: Build & Push (Smart) — GHCR + Docker Hub
on:
push:
branches: [main]
tags: ['v*']
paths:
- 'app/**'
- 'templates/**'
- 'static/favicon.ico'
- 'static/icon.png'
- 'Dockerfile'
- 'requirements.txt'
- 'VERSION'
schedule:
- cron: "0 3 * * 1" # Weekly Monday 03:00 UTC — catches base image updates
workflow_dispatch:
permissions:
contents: read
packages: write
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# ── Extract base image from Dockerfile ───────────────────────────
- name: Get base image
id: base
run: |
IMAGE=$(grep -i '^FROM ' Dockerfile | head -n1 | awk '{print $2}')
echo "image=$IMAGE" >> $GITHUB_OUTPUT
# ── Pull & get current digest ────────────────────────────────────
- name: Get remote digest
id: digest
run: |
docker pull ${{ steps.base.outputs.image }} > /dev/null 2>&1
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ${{ steps.base.outputs.image }})
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
# ── Restore last cached digest ───────────────────────────────────
- name: Restore cached digest
id: cache
uses: actions/cache@v4
with:
path: .base-digest
key: base-digest-${{ runner.os }}
# ── Compare: skip scheduled build if nothing changed ─────────────
- name: Compare digest
id: compare
run: |
OLD=$(cat .base-digest 2>/dev/null || echo "none")
NEW="${{ steps.digest.outputs.digest }}"
echo "old=$OLD new=$NEW"
if [ "$OLD" = "$NEW" ] && [ "${{ github.event_name }}" = "schedule" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Skip build (no base image change)
if: steps.compare.outputs.skip == 'true'
run: echo "Base image unchanged — skipping build." && exit 0
# ── Save new digest to cache ─────────────────────────────────────
- name: Save digest
run: echo "${{ steps.digest.outputs.digest }}" > .base-digest
- name: Cache new digest
uses: actions/cache@v4
with:
path: .base-digest
key: base-digest-${{ runner.os }}
# ── Docker meta (tags + OCI labels) ─────────────────────────────
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/kroeberd/mediastarr
kroeberd/mediastarr
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=weekly,enable=${{ github.event_name == 'schedule' }}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=sha-,format=short
# ── Multi-arch build setup ───────────────────────────────────────
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# ── Registry logins ──────────────────────────────────────────────
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# ── Build & Push ─────────────────────────────────────────────────
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
no-cache: ${{ github.event_name == 'schedule' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ── Update Docker Hub README ─────────────────────────────────────
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: kroeberd/mediastarr
readme-filepath: ./README.md
short-description: "Automated media search for Sonarr & Radarr — multi-instance, Discord, SQLite, DE/EN | mediastarr.de"