# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json on: workflow_call: inputs: org-slug: description: Buildkite organization slug required: true type: string pipeline-slug: description: Slug of the Buildkite pipeline to be run required: true type: string retry-step-key: description: Key of the Buildkite job to be retried required: true type: string build-commit-sha: description: Commit to check for running Buildkite Builds on. Usually github.event.pull_request.head.sha . required: true type: string cancel-running-github-jobs: description: Cancel currently in progress Github jobs when new ones are added. default: true type: boolean required: false secrets: buildkite-api-token: required: true concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ inputs.cancel-running-github-jobs }} jobs: retry-buildkite-job: runs-on: ubuntu-latest steps: - name: đ Retry job on the latest Buildkite Build env: READ_ONLY_MODE: ${{ github.event.pull_request.head.repo.fork || github.actor == 'dependabot[bot]' }} run: | [ "$READ_ONLY_MODE" = true ] && { echo "âšī¸ Cannot retry a Buildkite job from GitHub when running in read-only mode (from a fork or a Dependabot Pull Request). Please find the Buildkite job and retry manually."; exit 0; } ORG_SLUG="${{ inputs.org-slug }}" PIPELINE_SLUG="${{ inputs.pipeline-slug }}" RETRY_STEP_KEY="${{ inputs.retry-step-key }}" BUILDKITE_API_ACCESS_TOKEN="${{ secrets.buildkite-api-token }}" COMMIT_SHA="${{ inputs.build-commit-sha }}" # Performs a Buildkite request using a http method ($1) and an api path ($2) perform_buildkite_request() { local METHOD=$1 local BUILDKITE_API_PATH=$2 local BUILDKITE_API_URL="https://api.buildkite.com/v2/organizations/$ORG_SLUG/pipelines/$PIPELINE_SLUG/$BUILDKITE_API_PATH" local RAW_RESPONSE RAW_RESPONSE=$( curl \ --fail-with-body \ --silent \ --show-error \ -X "$METHOD" \ -H "Authorization: Bearer $BUILDKITE_API_ACCESS_TOKEN" \ "$BUILDKITE_API_URL" ) echo "$RAW_RESPONSE" | jq } # Gets the build(s) associated with the commit get_buildkite_build() { perform_buildkite_request "GET" "builds?commit=$COMMIT_SHA" } # Given a build id ($1) and a job id ($2), retry the given job retry_buildkite_job() { local BUILD_ID=$1 local JOB_ID=$2 perform_buildkite_request "PUT" "builds/$BUILD_ID/jobs/$JOB_ID/retry" } # Validates a Buildkite response ($1) check_buildkite_error() { local RESPONSE=$1 # Check if the response is empty if [ -z "$RESPONSE" ] || [ "$(echo "$RESPONSE" | jq 'length')" -eq 0 ]; then echo "â Buildkite API call returned an empty response." exit 1 fi # Check if the response contains an error message RESPONSE_ERROR=$(echo "$RESPONSE" | jq .message 2>/dev/null || true) if [[ -n "$RESPONSE_ERROR" && "$RESPONSE_ERROR" != 'null' ]]; then echo "â Buildkite API call failed: $RESPONSE_ERROR" exit 1 fi } BUILDKITE_GET_BUILD_RESPONSE=$(get_buildkite_build) check_buildkite_error "$BUILDKITE_GET_BUILD_RESPONSE" LATEST_BUILD=$(echo "$BUILDKITE_GET_BUILD_RESPONSE" | jq -r '.[0]') LATEST_BUILD_NUMBER=$(echo "$LATEST_BUILD" | jq -r '.number') SELECTED_JOB=$(echo "$LATEST_BUILD" | jq -r --arg step_key "$RETRY_STEP_KEY" '.jobs[] | select(.step_key == $step_key)') SELECTED_JOB_ID=$(echo "$SELECTED_JOB" | jq -r '.id') SELECTED_JOB_STATE=$(echo "$SELECTED_JOB" | jq -r '.state') echo "âšī¸ Build Number: $LATEST_BUILD_NUMBER" echo "âšī¸ Job ID for step '$RETRY_STEP_KEY': $SELECTED_JOB_ID" echo "âšī¸ Current job state for step '$RETRY_STEP_KEY': $SELECTED_JOB_STATE" # all states: running, scheduled, passed, failing, failed, blocked, canceled, canceling, skipped, not_run, finished ALLOWED_JOB_STATES=("passed" "failed" "canceled" "finished") if [[ " ${ALLOWED_JOB_STATES[*]} " =~ [[:space:]]${SELECTED_JOB_STATE}[[:space:]] ]]; then BUILDKITE_RETRY_JOB_RESPONSE=$(retry_buildkite_job "$LATEST_BUILD_NUMBER" "$SELECTED_JOB_ID") check_buildkite_error "$BUILDKITE_RETRY_JOB_RESPONSE" JOB_WEB_URL=$(echo "$BUILDKITE_RETRY_JOB_RESPONSE" | jq -r '.web_url') echo "â Job succesfully retried: $JOB_WEB_URL" elif [[ "$SELECTED_JOB_STATE" == "running" || "$SELECTED_JOB_STATE" == "scheduled" ]]; then echo "â ī¸ Job is already in state '$SELECTED_JOB_STATE', no need to retry." else echo "â Cannot retry job in state '$SELECTED_JOB_STATE'" fi