Skip to content

Retry Failed Docker Builds #48

Retry Failed Docker Builds

Retry Failed Docker Builds #48

name: Retry Failed Docker Builds
on:
workflow_run:
workflows:
- Docker Build Smoke Tests
- Docker Compose Build Latest Main Image Tag (Manual Dispatch)
- Docker Dev Branch Images Build
- Docker Dev Images Build
- Docker Dev Staging Images Build
- Docker Images Build on Tag
types:
- completed
permissions:
actions: write
contents: read
jobs:
retry-failed-jobs:
name: Re-run failed jobs
if: >
(github.event.workflow_run.conclusion == 'failure' ||
github.event.workflow_run.conclusion == 'timed_out') &&
github.event.workflow_run.run_attempt < 3
runs-on: ubuntu-latest
steps:
- name: Check failed run is still current
id: current-run
env:
GH_TOKEN: ${{ github.token }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
RUN_EVENT: ${{ github.event.workflow_run.event }}
RUN_ID: ${{ github.event.workflow_run.id }}
WORKFLOW_ID: ${{ github.event.workflow_run.workflow_id }}
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
run: |
set -euo pipefail
encode_uri() {
jq -nr --arg value "$1" '$value | @uri'
}
workflow_runs_path="repos/${GITHUB_REPOSITORY}/actions/workflows/${WORKFLOW_ID}/runs"
query="per_page=1&exclude_pull_requests=false"
if [ "$WORKFLOW_NAME" = "Docker Images Build on Tag" ]; then
if [ -z "$HEAD_BRANCH" ]; then
echo "No tag name found for ${WORKFLOW_NAME}; skipping retry."
echo "should_retry=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if ! tag_ref=$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/$(encode_uri "$HEAD_BRANCH")" --jq '.object'); then
echo "Tag ${HEAD_BRANCH} no longer exists; skipping retry."
echo "should_retry=false" >> "$GITHUB_OUTPUT"
exit 0
fi
tag_object_type=$(jq -r '.type' <<< "$tag_ref")
tag_object_sha=$(jq -r '.sha' <<< "$tag_ref")
if [ "$tag_object_type" = "tag" ]; then
tag_head_sha=$(gh api "repos/${GITHUB_REPOSITORY}/git/tags/${tag_object_sha}" --jq '.object.sha')
else
tag_head_sha="$tag_object_sha"
fi
if [ "$tag_head_sha" = "$HEAD_SHA" ]; then
echo "should_retry=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Skipping retry for stale ${WORKFLOW_NAME} run ${RUN_ID}; tag ${HEAD_BRANCH} now points to ${tag_head_sha}."
echo "should_retry=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ -n "$RUN_EVENT" ]; then
query="${query}&event=$(encode_uri "$RUN_EVENT")"
fi
if [ -n "$HEAD_BRANCH" ]; then
query_with_ref="${query}&branch=$(encode_uri "$HEAD_BRANCH")"
latest_run=$(gh api "${workflow_runs_path}?${query_with_ref}" --jq '.workflow_runs[0] // empty')
else
latest_run=""
fi
if [ -z "$latest_run" ]; then
latest_run=$(gh api "${workflow_runs_path}?${query}" --jq '.workflow_runs[0] // empty')
fi
if [ -z "$latest_run" ]; then
echo "No matching workflow runs found for ${WORKFLOW_NAME}; skipping retry."
echo "should_retry=false" >> "$GITHUB_OUTPUT"
exit 0
fi
latest_run_id=$(jq -r '.id' <<< "$latest_run")
latest_head_sha=$(jq -r '.head_sha' <<< "$latest_run")
if [ "$latest_run_id" = "$RUN_ID" ] || [ "$latest_head_sha" = "$HEAD_SHA" ]; then
echo "should_retry=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Skipping retry for stale ${WORKFLOW_NAME} run ${RUN_ID}; newer run ${latest_run_id} is at ${latest_head_sha}."
echo "should_retry=false" >> "$GITHUB_OUTPUT"
- name: Re-run failed Docker jobs
if: steps.current-run.outputs.should_retry == 'true'
env:
GH_TOKEN: ${{ github.token }}
RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
RUN_ID: ${{ github.event.workflow_run.id }}
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
run: |
set -euo pipefail
cancelled_jobs=$(gh api --paginate "repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/jobs?per_page=100" \
| jq -s '[.[].jobs[]? | select(.conclusion == "cancelled")] | length')
if [ "$cancelled_jobs" -gt 0 ]; then
endpoint="rerun"
echo "Found ${cancelled_jobs} cancelled job(s); re-running the full workflow run."
else
endpoint="rerun-failed-jobs"
echo "Re-running failed jobs only."
fi
echo "Retrying ${WORKFLOW_NAME} (run ${RUN_ID}, attempt ${RUN_ATTEMPT})."
gh api \
--method POST \
"repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/${endpoint}"