name: Docker (GHCR)
on:
push:
branches: [main]
paths-ignore:
- "docs/**"
- "mobile/**"
- "changelog.d/**"
- "CHANGELOG.md"
- ".github/ISSUE_TEMPLATE/**"
- ".github/*.md"
release:
types: [published]
workflow_dispatch:
inputs:
backfill_release:
description: Copy an existing release into canonical GHCR/Docker Hub tags
type: boolean
default: false
release_ref:
description: Release tag to build when backfilling (for example v0.5.6)
type: string
required: false
promote_stable:
description: Also move stable tags to this backfilled release
type: boolean
default: false
permissions:
contents: read
packages: write
concurrency:
group: docker-${{ github.event_name == 'push' && 'main-push' || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'push' }}
env:
REGISTRY: ghcr.io
IMAGE_NAME: debpalash/voicestudio
LEGACY_IMAGE_NAME: debpalash/omnivoice-studio
DOCKERHUB_IMAGE: palashdeb/omnivoice-studio
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
BUILDCACHE_IMAGE: ghcr.io/debpalash/voicestudio-buildcache
jobs:
build-and-push:
if: github.event_name != 'release' || startsWith(github.event.release.tag_name, 'v')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
ref: ${{ inputs.backfill_release && inputs.release_ref || github.sha }}
- name: Validate release backfill ref
if: inputs.backfill_release
shell: bash
env:
RELEASE_REF: ${{ inputs.release_ref }}
run: |
[[ "$RELEASE_REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-beta\.[0-9]+)?$ ]]
test "$(git rev-parse HEAD)" = "$(git rev-parse "refs/tags/${RELEASE_REF}^{commit}")"
TAG_VERSION="${RELEASE_REF#v}"
PACKAGE_VERSION="$(python3 -c 'import json; print(json.load(open("package.json"))["version"])')"
if [[ "$(printf '%s\n' "$TAG_VERSION" '0.5.6' | sort -V | tail -n1)" == '0.5.6' ]]; then
test "$PACKAGE_VERSION" = '1.0.0'
else
test "$PACKAGE_VERSION" = "$TAG_VERSION"
fi
- name: Resolve image source commit
id: source
shell: bash
run: |
echo "short_sha=$(git rev-parse --short=7 HEAD)" >> "$GITHUB_OUTPUT"
echo "commit=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Free runner disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/.ghcup /opt/hostedtoolcache /usr/share/swift \
/usr/local/share/boost /usr/local/lib/node_modules
sudo docker image prune --all --force
sudo apt-get clean
df -h /
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- name: Log in to GHCR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- 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@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY }}/${{ env.LEGACY_IMAGE_NAME }}
${{ steps.dockerhub.outputs.enabled == 'true' && env.DOCKERHUB_IMAGE || '' }}
flavor: |
latest=false
tags: |
type=semver,pattern={{version}},enable=${{ github.event_name == 'release' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name == 'release' && !contains(github.ref, '-') }}
type=raw,value=beta,enable=${{ github.event_name == 'release' && github.event.release.prerelease && contains(github.ref, '-beta.') }}
type=raw,value=stable,enable=${{ github.event_name == 'release' && !github.event.release.prerelease && !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=raw,value=sha-${{ steps.source.outputs.short_sha }}
- name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
with:
context: .
file: deploy/Dockerfile
build-args: |
BUILD_COMMIT=${{ steps.source.outputs.commit }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.BUILDCACHE_IMAGE }}:buildkit
cache-to: type=registry,ref=${{ env.BUILDCACHE_IMAGE }}:buildkit,mode=max,ignore-error=true
- name: Backfill canonical GHCR release tags
if: inputs.backfill_release
shell: bash
env:
DOCKERHUB_ENABLED: ${{ steps.dockerhub.outputs.enabled }}
PROMOTE_STABLE: ${{ inputs.promote_stable }}
RELEASE_REF: ${{ inputs.release_ref }}
SOURCE_TAG: sha-${{ steps.source.outputs.short_sha }}
run: |
VERSION="${RELEASE_REF#v}"
if [[ "$VERSION" == *-beta.* ]]; then
# A beta never moves :stable or the floating major.minor tag.
test "$PROMOTE_STABLE" != "true"
TAGS=("$VERSION" beta)
else
MINOR="${VERSION%.*}"
TAGS=("$VERSION" "$MINOR")
if [[ "$PROMOTE_STABLE" == "true" ]]; then TAGS=(stable "${TAGS[@]}"); fi
fi
for IMAGE in "$IMAGE_NAME" "$LEGACY_IMAGE_NAME"; do
for TAG in "${TAGS[@]}"; do
docker buildx imagetools create \
--tag "${REGISTRY}/${IMAGE}:${TAG}" \
"${REGISTRY}/${IMAGE}:${SOURCE_TAG}"
done
done
if [[ "$DOCKERHUB_ENABLED" == "true" ]]; then
for TAG in "${TAGS[@]}"; do
docker buildx imagetools create \
--tag "${DOCKERHUB_IMAGE}:${TAG}" \
"${DOCKERHUB_IMAGE}:${SOURCE_TAG}"
done
fi
- 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@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77
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
build-and-push-rocm:
if: github.event_name != 'release' || startsWith(github.event.release.tag_name, 'v')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
ref: ${{ inputs.backfill_release && inputs.release_ref || github.sha }}
- name: Validate release backfill ref
if: inputs.backfill_release
shell: bash
env:
RELEASE_REF: ${{ inputs.release_ref }}
run: |
[[ "$RELEASE_REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-beta\.[0-9]+)?$ ]]
test "$(git rev-parse HEAD)" = "$(git rev-parse "refs/tags/${RELEASE_REF}^{commit}")"
TAG_VERSION="${RELEASE_REF#v}"
PACKAGE_VERSION="$(python3 -c 'import json; print(json.load(open("package.json"))["version"])')"
if [[ "$(printf '%s\n' "$TAG_VERSION" '0.5.6' | sort -V | tail -n1)" == '0.5.6' ]]; then
test "$PACKAGE_VERSION" = '1.0.0'
else
test "$PACKAGE_VERSION" = "$TAG_VERSION"
fi
- name: Resolve image source commit
id: source
shell: bash
run: |
echo "short_sha=$(git rev-parse --short=7 HEAD)" >> "$GITHUB_OUTPUT"
echo "commit=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Free runner disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/.ghcup /opt/hostedtoolcache /usr/share/swift \
/usr/local/share/boost /usr/local/lib/node_modules
sudo docker image prune --all --force
sudo apt-get clean
df -h /
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- name: Log in to GHCR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- 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@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY }}/${{ env.LEGACY_IMAGE_NAME }}
${{ steps.dockerhub.outputs.enabled == 'true' && env.DOCKERHUB_IMAGE || '' }}
flavor: |
latest=false
tags: |
type=semver,pattern={{version}},suffix=-rocm,enable=${{ github.event_name == 'release' }}
type=semver,pattern={{major}}.{{minor}},suffix=-rocm,enable=${{ github.event_name == 'release' && !contains(github.ref, '-') }}
type=raw,value=beta-rocm,enable=${{ github.event_name == 'release' && github.event.release.prerelease && contains(github.ref, '-beta.') }}
type=raw,value=stable-rocm,enable=${{ github.event_name == 'release' && !github.event.release.prerelease && !contains(github.ref, '-') }}
type=raw,value=rocm,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
type=raw,value=sha-${{ steps.source.outputs.short_sha }}-rocm
- name: Build and push (ROCm)
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
with:
context: .
file: deploy/Dockerfile
build-args: |
BASE_IMAGE=rocm/pytorch:rocm7.2.4_ubuntu24.04_py3.12_pytorch_release_2.8.0
GPU_FLAVOR=rocm
BUILD_COMMIT=${{ steps.source.outputs.commit }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.BUILDCACHE_IMAGE }}:buildkit
- name: Backfill canonical GHCR release tags (ROCm)
if: inputs.backfill_release
shell: bash
env:
DOCKERHUB_ENABLED: ${{ steps.dockerhub.outputs.enabled }}
PROMOTE_STABLE: ${{ inputs.promote_stable }}
RELEASE_REF: ${{ inputs.release_ref }}
SOURCE_TAG: sha-${{ steps.source.outputs.short_sha }}-rocm
run: |
VERSION="${RELEASE_REF#v}"
if [[ "$VERSION" == *-beta.* ]]; then
# A beta never moves :stable-rocm or the floating major.minor tag.
test "$PROMOTE_STABLE" != "true"
TAGS=("${VERSION}-rocm" beta-rocm)
else
MINOR="${VERSION%.*}"
TAGS=("${VERSION}-rocm" "${MINOR}-rocm")
if [[ "$PROMOTE_STABLE" == "true" ]]; then TAGS=(stable-rocm "${TAGS[@]}"); fi
fi
for IMAGE in "$IMAGE_NAME" "$LEGACY_IMAGE_NAME"; do
for TAG in "${TAGS[@]}"; do
docker buildx imagetools create \
--tag "${REGISTRY}/${IMAGE}:${TAG}" \
"${REGISTRY}/${IMAGE}:${SOURCE_TAG}"
done
done
if [[ "$DOCKERHUB_ENABLED" == "true" ]]; then
for TAG in "${TAGS[@]}"; do
docker buildx imagetools create \
--tag "${DOCKERHUB_IMAGE}:${TAG}" \
"${DOCKERHUB_IMAGE}:${SOURCE_TAG}"
done
fi
build-and-push-cuda-arm64:
if: github.event_name != 'release' || startsWith(github.event.release.tag_name, 'v')
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
ref: ${{ inputs.backfill_release && inputs.release_ref || github.sha }}
- name: Validate release backfill ref
if: inputs.backfill_release
shell: bash
env:
RELEASE_REF: ${{ inputs.release_ref }}
run: |
[[ "$RELEASE_REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-beta\.[0-9]+)?$ ]]
test "$(git rev-parse HEAD)" = "$(git rev-parse "refs/tags/${RELEASE_REF}^{commit}")"
TAG_VERSION="${RELEASE_REF#v}"
PACKAGE_VERSION="$(python3 -c 'import json; print(json.load(open("package.json"))["version"])')"
if [[ "$(printf '%s\n' "$TAG_VERSION" '0.5.6' | sort -V | tail -n1)" == '0.5.6' ]]; then
test "$PACKAGE_VERSION" = '1.0.0'
else
test "$PACKAGE_VERSION" = "$TAG_VERSION"
fi
- name: Resolve image source commit
id: source
shell: bash
run: |
echo "short_sha=$(git rev-parse --short=7 HEAD)" >> "$GITHUB_OUTPUT"
echo "commit=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Free runner disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/.ghcup /opt/hostedtoolcache /usr/share/swift \
/usr/local/share/boost /usr/local/lib/node_modules
sudo docker image prune --all --force
sudo apt-get clean
df -h /
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- name: Log in to GHCR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- 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@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY }}/${{ env.LEGACY_IMAGE_NAME }}
${{ steps.dockerhub.outputs.enabled == 'true' && env.DOCKERHUB_IMAGE || '' }}
flavor: |
latest=false
tags: |
type=semver,pattern={{version}},suffix=-cuda-arm64,enable=${{ github.event_name == 'release' }}
type=semver,pattern={{major}}.{{minor}},suffix=-cuda-arm64,enable=${{ github.event_name == 'release' && !contains(github.ref, '-') }}
type=raw,value=beta-cuda-arm64,enable=${{ github.event_name == 'release' && github.event.release.prerelease && contains(github.ref, '-beta.') }}
type=raw,value=stable-cuda-arm64,enable=${{ github.event_name == 'release' && !github.event.release.prerelease && !contains(github.ref, '-') }}
type=raw,value=cuda-arm64,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
type=raw,value=sha-${{ steps.source.outputs.short_sha }}-cuda-arm64
- name: Build and push (CUDA arm64)
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
with:
context: .
file: deploy/Dockerfile
platforms: linux/arm64
build-args: |
BASE_IMAGE=cuda-arm64-base
GPU_FLAVOR=cuda
BUILD_COMMIT=${{ steps.source.outputs.commit }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.BUILDCACHE_IMAGE }}:buildkit-cuda-arm64
cache-to: type=registry,ref=${{ env.BUILDCACHE_IMAGE }}:buildkit-cuda-arm64,mode=max,ignore-error=true
- name: Backfill canonical GHCR release tags (CUDA arm64)
if: inputs.backfill_release
shell: bash
env:
DOCKERHUB_ENABLED: ${{ steps.dockerhub.outputs.enabled }}
PROMOTE_STABLE: ${{ inputs.promote_stable }}
RELEASE_REF: ${{ inputs.release_ref }}
SOURCE_TAG: sha-${{ steps.source.outputs.short_sha }}-cuda-arm64
run: |
VERSION="${RELEASE_REF#v}"
if [[ "$VERSION" == *-beta.* ]]; then
# A beta never moves :stable-cuda-arm64 or the floating major.minor tag.
test "$PROMOTE_STABLE" != "true"
TAGS=("${VERSION}-cuda-arm64" beta-cuda-arm64)
else
MINOR="${VERSION%.*}"
TAGS=("${VERSION}-cuda-arm64" "${MINOR}-cuda-arm64")
if [[ "$PROMOTE_STABLE" == "true" ]]; then TAGS=(stable-cuda-arm64 "${TAGS[@]}"); fi
fi
for IMAGE in "$IMAGE_NAME" "$LEGACY_IMAGE_NAME"; do
for TAG in "${TAGS[@]}"; do
docker buildx imagetools create \
--tag "${REGISTRY}/${IMAGE}:${TAG}" \
"${REGISTRY}/${IMAGE}:${SOURCE_TAG}"
done
done
if [[ "$DOCKERHUB_ENABLED" == "true" ]]; then
for TAG in "${TAGS[@]}"; do
docker buildx imagetools create \
--tag "${DOCKERHUB_IMAGE}:${TAG}" \
"${DOCKERHUB_IMAGE}:${SOURCE_TAG}"
done
fi