Skip to content

Mirror to Docker Hub #28

Mirror to Docker Hub

Mirror to Docker Hub #28

name: Mirror to Docker Hub
on:
workflow_dispatch:
inputs:
tag:
description: 'Specific tag to mirror (leave empty for all tags)'
required: false
type: string
workflow_run:
workflows: ["Release Docker Build"]
types:
- completed
permissions:
contents: read
packages: read
jobs:
mirror:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- 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 }}
- name: Mirror images
shell: bash
run: |
set -euo pipefail
DOCKERHUB_USER="${{ secrets.DOCKERHUB_USERNAME }}"
GH_OWNER="${{ github.repository_owner }}"
SPECIFIC_TAG="${{ inputs.tag }}"
TRACKING_TAGS="latest main"
# Function to get image digest
get_digest() {
local image="$1"
docker buildx imagetools inspect "$image" | grep -i "Digest:" | awk '{print $2}'
}
# Function to process tracking tags
process_tracking_tag() {
local tag="$1"
SOURCE_IMAGE="ghcr.io/$GH_OWNER/streammaster:$tag"
TARGET_IMAGE="$DOCKERHUB_USER/streammaster:$tag"
# Always check tracking tag digest
SOURCE_DIGEST=$(get_digest "$SOURCE_IMAGE")
if curl -sSfL "https://hub.docker.com/v2/repositories/$DOCKERHUB_USER/streammaster/tags/$tag/" >/dev/null 2>&1; then
TARGET_DIGEST=$(get_digest "$TARGET_IMAGE")
if [ "$SOURCE_DIGEST" != "$TARGET_DIGEST" ]; then
echo "$tag tag differs, updating..."
docker buildx imagetools create -t "$TARGET_IMAGE" "$SOURCE_IMAGE"
sleep 5 # Rate limit protection
else
echo "$tag tag is up to date"
fi
else
echo "$tag tag doesn't exist in Docker Hub, creating..."
docker buildx imagetools create -t "$TARGET_IMAGE" "$SOURCE_IMAGE"
sleep 5 # Rate limit protection
fi
}
if [ -n "$SPECIFIC_TAG" ]; then
echo "Processing single tag: $SPECIFIC_TAG"
TAGS="$SPECIFIC_TAG"
else
# Get all tags with pagination
page=1
TAGS=""
while true; do
response=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/users/$GH_OWNER/packages/container/streammaster/versions?per_page=100&page=$page")
current_tags=$(echo "$response" | jq -r '.[] | .metadata.container.tags[]')
if [ -z "$current_tags" ]; then
break
fi
TAGS+=$'\n'"$current_tags"
((page++))
done
# Remove duplicates and empty lines
TAGS=$(echo "$TAGS" | sort -u | sed '/^$/d')
fi
echo "Discovered tags:"
echo "$TAGS"
# Process tracking tags first
for tracking_tag in $TRACKING_TAGS; do
if echo "$TAGS" | grep -q "^$tracking_tag$"; then
process_tracking_tag "$tracking_tag"
# Remove tracking tag from TAGS to avoid processing it twice
TAGS=$(echo "$TAGS" | grep -v "^$tracking_tag$")
fi
done
# Process remaining tags
for TAG in $TAGS; do
# Check existence using Docker Hub API
if ! curl -sSfL "https://hub.docker.com/v2/repositories/$DOCKERHUB_USER/streammaster/tags/$TAG/" >/dev/null 2>&1; then
echo "Mirroring tag: ${TAG}"
SOURCE_IMAGE="ghcr.io/$GH_OWNER/streammaster:${TAG}"
TARGET_IMAGE="$DOCKERHUB_USER/streammaster:${TAG}"
# Pull and create the target image directly
docker buildx imagetools create -t "$TARGET_IMAGE" "$SOURCE_IMAGE"
sleep 5 # Rate limit protection
else
echo "Tag $TAG already exists in Docker Hub, skipping"
fi
done
- name: Checkout repository
uses: actions/checkout@v4
- name: Docker Hub Description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
repository: ${{ secrets.DOCKERHUB_USERNAME }}/streammaster