Files
VoiceStudio/.github/workflows/docker.yml
T
Palash DebnathandClaude Opus 4.8 d674084510 fix(ci): make Docker Hub description sync non-fatal (#414)
The image build+push succeeds, but the "Update Docker Hub description" step
403s (Forbidden) — DOCKERHUB_TOKEN can push yet lacks description-edit scope, a
common limitation of fine-grained Docker Hub tokens. That cosmetic overview
sync was failing the whole Docker (GHCR) run on main.

Mark the step continue-on-error so a creds-scope mismatch no longer reds-out an
otherwise-successful build. To actually sync the overview, the token needs
read/write (incl. description) scope, or use the account password.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 14:59:32 +05:30

139 lines
6.1 KiB
YAML

# Publish Docker images to GitHub Container Registry (GHCR).
#
# Triggers:
# - push of a tag matching `v*` (e.g. `v0.3.0`) → :0.3.0, :0.3, :latest, :sha-
# - push to main branch → :main, :sha- (rolling "edge" build)
# - workflow_dispatch → :sha- only (ad-hoc test build)
#
# Tag ↔ image mapping (versioning hard rule, owner-set 2026-06-11:
# :latest IS the preview channel; stable users pin :stable or a version tag)
# :latest — rolling preview: latest commit on main (always last release + 1 dev)
# :main — alias of the same rolling main build (kept for back-compat)
# :stable — most recent versioned release (set on every v* tag push)
# :0.3.6 — exact version from the git tag
# :0.3 — major.minor floating tag (updated on every patch within the minor)
# :sha-xxxx — specific commit SHA; produced by workflow_dispatch
#
# Images land at: ghcr.io/debpalash/omnivoice-studio AND docker.io/palashdeb/omnivoice-studio
# (Docker Hub push gated on the DOCKERHUB_USERNAME/DOCKERHUB_TOKEN secrets;
# if unset the build still pushes to GHCR.)
#
# On main pushes the Docker Hub repository overview is also synced from
# deploy/dockerhub-overview.md (source of truth for the hub.docker.com page).
#
# NOTE: the Docker image is the headless web-server build of OmniVoice (FastAPI
# backend + pre-built React frontend served over HTTP). The Tauri desktop
# auto-updater and its update-channel toggle are desktop-only features; they do
# NOT apply to the Docker image.
name: Docker (GHCR)
on:
push:
tags: ['v*']
branches: [main]
workflow_dispatch:
permissions:
contents: read
packages: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
DOCKERHUB_IMAGE: palashdeb/omnivoice-studio
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
build-and-push:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
# QEMU enables cross-platform builds (arm64 on x64 runner).
# Skipped for now — only building linux/amd64.
# - 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 }}
# Docker Hub login — only when the secret is present, so forks / runs
# without the credential still publish to GHCR.
- name: Check Docker Hub credentials
id: dockerhub
run: echo "enabled=${{ secrets.DOCKERHUB_TOKEN != '' }}" >> "$GITHUB_OUTPUT"
- name: Log in to Docker Hub
if: steps.dockerhub.outputs.enabled == 'true'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Tag strategy (`:sha-<short>` is emitted on every trigger):
# v0.3.6 tag push → :0.3.6, :0.3, :stable, :sha-
# main branch push → :latest, :main, :sha-
# workflow_dispatch → :sha- only
#
# All mutable-tag rules stay gated on `github.event_name == 'push'` so a
# manual workflow_dispatch can only ever produce a throwaway `:sha-` tag
# (the stale-:latest fix from #249/#251). :stable excludes prerelease
# tags (those contain a `-`) so a prerelease can't clobber it.
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
# Same tag set applied to both registries. The Docker Hub line is
# blank when the secret is unset, so metadata-action emits GHCR-only
# tags in that case.
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
${{ steps.dockerhub.outputs.enabled == 'true' && env.DOCKERHUB_IMAGE || '' }}
tags: |
type=semver,pattern={{version}},enable=${{ github.event_name == 'push' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name == 'push' }}
type=raw,value=stable,enable=${{ github.event_name == 'push' && github.ref_type == 'tag' && !contains(github.ref, '-') }}
type=raw,value=latest,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
type=raw,value=main,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
type=sha,prefix=sha-,format=short
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: deploy/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Sync the Docker Hub repository overview from deploy/dockerhub-overview.md.
# Only on main pushes (the overview tracks the rolling preview) and only
# when Docker Hub creds are present, mirroring the push gating above.
#
# continue-on-error: the overview text is cosmetic, and the description
# PATCH 403s unless DOCKERHUB_TOKEN carries description-edit scope (many
# fine-grained Docker Hub tokens that can push still can't edit the
# description). The image build+push is what matters — a creds-scope
# mismatch on this cosmetic step must not fail the whole Docker run. To
# actually sync the overview, use a token with read/write (incl.
# description) scope, or the account password.
- name: Update Docker Hub description
if: steps.dockerhub.outputs.enabled == 'true' && github.event_name == 'push' && github.ref == 'refs/heads/main'
continue-on-error: true
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ env.DOCKERHUB_IMAGE }}
short-description: "Local ElevenLabs alternative: voice cloning, design & video dubbing in 646 languages. No API keys."
readme-filepath: ./deploy/dockerhub-overview.md