Mirror to Docker Hub #28
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |