Pulse/.github/workflows/publish-docker.yml
rcourtman 8bea6c6b99 fix: prevent race conditions in release workflows
- Remove 'release: published' triggers from publish-docker, promote-floating-tags, and helm-pages workflows
- All these workflows now only run via workflow_dispatch, triggered by create-release.yml in sequence
- Add image availability check in promote-floating-tags to wait for Docker images
- create-release.yml now dispatches: publish-docker, promote-floating-tags, helm-pages, update-demo-server
- This prevents the race condition where workflows triggered by release event run before Docker images are ready
2025-12-14 18:07:46 +00:00

152 lines
6 KiB
YAML

name: Publish Docker Images
# Only triggered by create-release.yml after staging images are built
# Removing release: published trigger prevents race conditions
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag (e.g., v4.34.0)'
required: true
type: string
concurrency:
group: docker-publish-${{ inputs.tag }}
cancel-in-progress: false
jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
packages: write
steps:
- name: Extract version from release tag
id: version
run: |
TAG="${{ inputs.tag }}"
VERSION="${TAG#v}"
# Detect if this is a prerelease (RC, alpha, beta)
IS_PRERELEASE="false"
if [[ "$VERSION" =~ -rc\.[0-9]+$ ]] || [[ "$VERSION" =~ -alpha\.[0-9]+$ ]] || [[ "$VERSION" =~ -beta\.[0-9]+$ ]]; then
IS_PRERELEASE="true"
echo "Detected prerelease version - will NOT update :latest tag"
fi
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "is_prerelease=${IS_PRERELEASE}" >> $GITHUB_OUTPUT
echo "Publishing Docker images for ${TAG} (prerelease: ${IS_PRERELEASE})"
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Copy staging images to final tags
run: |
TAG="${{ steps.version.outputs.tag }}"
VERSION="${{ steps.version.outputs.version }}"
STAGING_TAG="staging-${TAG}"
# Retry function for transient Docker Hub failures
retry_push() {
local cmd="$1"
local max_attempts=3
local attempt=1
local delay=10
while [ $attempt -le $max_attempts ]; do
echo "Attempt $attempt of $max_attempts..."
if eval "$cmd"; then
return 0
fi
echo "Attempt $attempt failed"
if [ $attempt -lt $max_attempts ]; then
echo "Waiting ${delay}s before retry..."
sleep $delay
delay=$((delay * 2))
fi
attempt=$((attempt + 1))
done
echo "All $max_attempts attempts failed"
return 1
}
IS_PRERELEASE="${{ steps.version.outputs.is_prerelease }}"
echo "Copying pulse staging image to final tags..."
if [ "$IS_PRERELEASE" = "true" ]; then
# For prereleases, only tag with version - do NOT update :latest
retry_push "docker buildx imagetools create \
--tag rcourtman/pulse:${TAG} \
--tag rcourtman/pulse:${VERSION} \
--tag ghcr.io/${{ github.repository_owner }}/pulse:${TAG} \
--tag ghcr.io/${{ github.repository_owner }}/pulse:${VERSION} \
ghcr.io/${{ github.repository_owner }}/pulse:${STAGING_TAG}"
else
# For stable releases, also update :latest
retry_push "docker buildx imagetools create \
--tag rcourtman/pulse:${TAG} \
--tag rcourtman/pulse:${VERSION} \
--tag rcourtman/pulse:latest \
--tag ghcr.io/${{ github.repository_owner }}/pulse:${TAG} \
--tag ghcr.io/${{ github.repository_owner }}/pulse:${VERSION} \
--tag ghcr.io/${{ github.repository_owner }}/pulse:latest \
ghcr.io/${{ github.repository_owner }}/pulse:${STAGING_TAG}"
fi
echo "Copying pulse-docker-agent staging image to final tags..."
if [ "$IS_PRERELEASE" = "true" ]; then
# For prereleases, only tag with version - do NOT update :latest
retry_push "docker buildx imagetools create \
--tag rcourtman/pulse-docker-agent:${TAG} \
--tag rcourtman/pulse-docker-agent:${VERSION} \
--tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${TAG} \
--tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${VERSION} \
ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${STAGING_TAG}"
else
# For stable releases, also update :latest
retry_push "docker buildx imagetools create \
--tag rcourtman/pulse-docker-agent:${TAG} \
--tag rcourtman/pulse-docker-agent:${VERSION} \
--tag rcourtman/pulse-docker-agent:latest \
--tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${TAG} \
--tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${VERSION} \
--tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:latest \
ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${STAGING_TAG}"
fi
- name: Output image information
run: |
IS_PRERELEASE="${{ steps.version.outputs.is_prerelease }}"
echo "✅ Docker images published successfully!"
echo ""
echo "Server images:"
echo " - rcourtman/pulse:${{ steps.version.outputs.tag }}"
echo " - rcourtman/pulse:${{ steps.version.outputs.version }}"
if [ "$IS_PRERELEASE" != "true" ]; then
echo " - rcourtman/pulse:latest"
fi
echo ""
echo "Agent images:"
echo " - rcourtman/pulse-docker-agent:${{ steps.version.outputs.tag }}"
echo " - rcourtman/pulse-docker-agent:${{ steps.version.outputs.version }}"
if [ "$IS_PRERELEASE" != "true" ]; then
echo " - rcourtman/pulse-docker-agent:latest"
fi
echo ""
if [ "$IS_PRERELEASE" = "true" ]; then
echo "Note: :latest tags were NOT updated (this is a prerelease)"
fi