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
This commit is contained in:
rcourtman 2025-12-14 18:07:46 +00:00
parent 7b54326889
commit bc82c4a144
4 changed files with 70 additions and 23 deletions

View file

@ -493,6 +493,34 @@ jobs:
echo "✓ Docker publish workflow dispatched" echo "✓ Docker publish workflow dispatched"
- name: Trigger floating tag promotion
if: ${{ github.event.inputs.draft_only != 'true' }}
continue-on-error: true # Non-fatal if dispatch fails
env:
GH_TOKEN: ${{ secrets.WORKFLOW_PAT }}
run: |
TAG="${{ needs.extract_version.outputs.tag }}"
IS_PRERELEASE="${{ needs.extract_version.outputs.is_prerelease }}"
echo "Triggering floating tag promotion for ${TAG} (prerelease: ${IS_PRERELEASE})..."
gh workflow run promote-floating-tags.yml -f tag="${TAG}" -f prerelease="${IS_PRERELEASE}"
echo "✓ Floating tag promotion workflow dispatched"
- name: Trigger Helm chart release
if: ${{ github.event.inputs.draft_only != 'true' }}
continue-on-error: true # Non-fatal if dispatch fails
env:
GH_TOKEN: ${{ secrets.WORKFLOW_PAT }}
run: |
TAG="${{ needs.extract_version.outputs.tag }}"
VERSION="${TAG#v}"
echo "Triggering Helm chart release for ${VERSION}..."
gh workflow run helm-pages.yml -f chart_version="${VERSION}"
echo "✓ Helm chart release workflow dispatched"
- name: Trigger demo server update - name: Trigger demo server update
if: ${{ github.event.inputs.draft_only != 'true' }} if: ${{ github.event.inputs.draft_only != 'true' }}
continue-on-error: true # Non-fatal if dispatch fails continue-on-error: true # Non-fatal if dispatch fails

View file

@ -1,8 +1,8 @@
name: Release Helm Chart to GitHub Pages name: Release Helm Chart to GitHub Pages
# Only triggered manually or by create-release.yml
# Removing release: published trigger prevents race conditions
on: on:
release:
types: [published]
workflow_dispatch: workflow_dispatch:
inputs: inputs:
chart_version: chart_version:
@ -45,26 +45,19 @@ jobs:
helm-docs helm-docs
# Commit if README changed # Commit if README changed
if [ "${GITHUB_EVENT_NAME}" != "release" ] && ! git diff --quiet README.md; then if ! git diff --quiet README.md; then
git config user.name "$GITHUB_ACTOR" git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com" git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add README.md git add README.md
git commit -m "Auto-update Helm chart documentation" git commit -m "Auto-update Helm chart documentation"
git push git push
elif [ "${GITHUB_EVENT_NAME}" = "release" ] && ! git diff --quiet README.md; then
echo "README.md updated by helm-docs but skipping commit because release workflows checkout a detached HEAD."
fi fi
cd ../../.. cd ../../..
- name: Determine chart version - name: Determine chart version
id: version id: version
run: | run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then VERSION="${{ inputs.chart_version }}"
VERSION="${{ inputs.chart_version }}"
else
VERSION="${{ github.event.release.tag_name }}"
VERSION="${VERSION#v}"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT" echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Update Chart.yaml version - name: Update Chart.yaml version
@ -73,15 +66,13 @@ jobs:
sed -i "s/^version: .*/version: $VERSION/" deploy/helm/pulse/Chart.yaml sed -i "s/^version: .*/version: $VERSION/" deploy/helm/pulse/Chart.yaml
sed -i "s/^appVersion: .*/appVersion: \"$VERSION\"/" deploy/helm/pulse/Chart.yaml sed -i "s/^appVersion: .*/appVersion: \"$VERSION\"/" deploy/helm/pulse/Chart.yaml
# Commit only on workflow_dispatch (release runs are detached HEAD) # Commit if Chart.yaml changed
if [ "${GITHUB_EVENT_NAME}" != "release" ] && ! git diff --quiet deploy/helm/pulse/Chart.yaml; then if ! git diff --quiet deploy/helm/pulse/Chart.yaml; then
git config user.name "$GITHUB_ACTOR" git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com" git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add deploy/helm/pulse/Chart.yaml git add deploy/helm/pulse/Chart.yaml
git commit -m "Auto-update Helm chart version to $VERSION" git commit -m "Auto-update Helm chart version to $VERSION"
git push git push
elif [ "${GITHUB_EVENT_NAME}" = "release" ] && ! git diff --quiet deploy/helm/pulse/Chart.yaml; then
echo "Chart.yaml updated for packaging, skipping commit (detached HEAD on release event)."
fi fi
- name: Validate Helm chart - name: Validate Helm chart

View file

@ -1,8 +1,19 @@
name: Promote Floating Tags name: Promote Floating Tags
# Only triggered by create-release.yml after Docker images are published
# This prevents race conditions with release: published event
on: on:
release: workflow_dispatch:
types: [published] inputs:
tag:
description: 'Release tag (e.g., v5.0.0)'
required: true
type: string
prerelease:
description: 'Is this a prerelease?'
required: true
type: boolean
default: false
jobs: jobs:
promote-images: promote-images:
@ -12,8 +23,8 @@ jobs:
packages: write packages: write
env: env:
OWNER: ${{ github.repository_owner }} OWNER: ${{ github.repository_owner }}
TAG: ${{ github.event.release.tag_name }} TAG: ${{ inputs.tag }}
PRERELEASE: ${{ github.event.release.prerelease }} PRERELEASE: ${{ inputs.prerelease }}
steps: steps:
- name: Log in to Docker Hub - name: Log in to Docker Hub
@ -29,6 +40,23 @@ jobs:
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Wait for Docker image to be available
run: |
echo "Waiting for rcourtman/pulse:${TAG} to be available..."
MAX_ATTEMPTS=30
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
if docker manifest inspect rcourtman/pulse:${TAG} > /dev/null 2>&1; then
echo "Image rcourtman/pulse:${TAG} is available!"
exit 0
fi
ATTEMPT=$((ATTEMPT + 1))
echo "Attempt $ATTEMPT/$MAX_ATTEMPTS - Image not yet available, waiting 10s..."
sleep 10
done
echo "Timeout waiting for Docker image"
exit 1
- name: Promote Pulse server image tags - name: Promote Pulse server image tags
run: | run: |
set -euo pipefail set -euo pipefail

View file

@ -1,8 +1,8 @@
name: Publish Docker Images name: Publish Docker Images
# Only triggered by create-release.yml after staging images are built
# Removing release: published trigger prevents race conditions
on: on:
release:
types: [published]
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
@ -11,7 +11,7 @@ on:
type: string type: string
concurrency: concurrency:
group: docker-publish-${{ github.event.release.tag_name || inputs.tag }} group: docker-publish-${{ inputs.tag }}
cancel-in-progress: false cancel-in-progress: false
jobs: jobs:
@ -26,7 +26,7 @@ jobs:
- name: Extract version from release tag - name: Extract version from release tag
id: version id: version
run: | run: |
TAG="${{ github.event.release.tag_name || inputs.tag }}" TAG="${{ inputs.tag }}"
VERSION="${TAG#v}" VERSION="${TAG#v}"
# Detect if this is a prerelease (RC, alpha, beta) # Detect if this is a prerelease (RC, alpha, beta)