diff --git a/.github/bin/cancel-merge-queue-workflow.sh b/.github/bin/cancel-merge-queue-workflow.sh new file mode 100755 index 000000000000..3b1dfd2c3a02 --- /dev/null +++ b/.github/bin/cancel-merge-queue-workflow.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -euo pipefail + +name="$1" + +echo "::error::Requesting merge queue workflow cancellation because ${name} failed" +if ! gh workflow run cancel-merge-queue-workflow.yml \ + --repo "${GITHUB_REPOSITORY}" \ + --ref "${GITHUB_REF_NAME}" \ + -f run_id="${GITHUB_RUN_ID}" \ + -f run_attempt="${GITHUB_RUN_ATTEMPT}" +then + echo "::warning::Failed to dispatch cancel-merge-queue-workflow.yml" +fi diff --git a/.github/workflows/cancel-merge-queue-workflow.yml b/.github/workflows/cancel-merge-queue-workflow.yml new file mode 100644 index 000000000000..6f4817cd8bea --- /dev/null +++ b/.github/workflows/cancel-merge-queue-workflow.yml @@ -0,0 +1,57 @@ +name: Cancel merge queue workflow + +on: + workflow_dispatch: + inputs: + run_id: + description: Workflow run to cancel + required: true + run_attempt: + description: Workflow run attempt to cancel + required: true + +defaults: + run: + shell: bash --noprofile --norc -euo pipefail {0} + +permissions: + actions: write + +jobs: + cancel: + runs-on: ubuntu-latest + steps: + - name: Cancel merge queue workflow after failure is recorded + env: + GH_TOKEN: ${{ github.token }} + RUN_ID: ${{ inputs.run_id }} + RUN_ATTEMPT: ${{ inputs.run_attempt }} + run: | + # Wait until GitHub records the failed job before cancelling the workflow, so the + # failing job keeps the failure conclusion instead of being finalized as cancelled. + for attempt in {1..30}; do + failed_jobs=$(gh api --paginate "/repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/attempts/${RUN_ATTEMPT}/jobs" \ + --jq '.jobs[] | select(.status == "completed" and .conclusion == "failure") | .name' \ + | paste -sd ',' - \ + | sed 's/,/, /g') + if [[ -n "${failed_jobs}" ]]; then + echo "::notice::Cancelling merge queue workflow after failed jobs were recorded: ${failed_jobs}" + run_status=$(gh api "/repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}" --jq .status) + if [[ "${run_status}" == "completed" ]]; then + echo "::notice::Workflow run ${RUN_ID} is already completed" + exit 0 + fi + if ! gh run cancel "${RUN_ID}" --repo "${GITHUB_REPOSITORY}"; then + run_status=$(gh api "/repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}" --jq .status) + if [[ "${run_status}" == "completed" ]]; then + echo "::notice::Workflow run ${RUN_ID} completed before it could be cancelled" + exit 0 + fi + exit 1 + fi + exit 0 + fi + sleep 2 + done + echo "::warning::Failed to find a job with conclusion=failure for run ${RUN_ID} attempt ${RUN_ATTEMPT}; not cancelling workflow" + exit 1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 029ddb0c4cbd..3e32390ccfd5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,9 +103,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because maven-checks ${{ matrix.java-version }} failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "maven-checks ${{ matrix.java-version }}" artifact-checks: needs: path-filters @@ -145,9 +143,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because artifact-checks failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "artifact-checks" check-commits-dispatcher: needs: path-filters @@ -237,9 +233,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because error-prone-checks failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "error-prone-checks" test-jdbc-compatibility: needs: path-filters @@ -286,9 +280,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because test-jdbc-compatibility failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "test-jdbc-compatibility" hive-tests: needs: path-filters @@ -351,9 +343,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because hive-tests (${{ matrix.config }}) failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "hive-tests (${{ matrix.config }})" test-other-modules: needs: path-filters @@ -446,9 +436,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because test-other-modules failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "test-other-modules" build-test-matrix: needs: path-filters @@ -569,9 +557,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because build-test-matrix failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "build-test-matrix" test: runs-on: 'ubuntu-latest' @@ -876,9 +862,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because test (${{ matrix.modules }}, ${{ matrix.profile }}, ${{ matrix.jdk }}) failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "test (${{ matrix.modules }}, ${{ matrix.profile }}, ${{ matrix.jdk }})" build-pt: needs: path-filters @@ -1079,9 +1063,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because build-pt failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "build-pt" pt: runs-on: 'ubuntu-latest' @@ -1176,9 +1158,7 @@ jobs: if: ${{ failure() && github.event_name == 'merge_group' }} env: GH_TOKEN: ${{ github.token }} - run: | - echo "::error::Cancelling merge queue workflow because pt (${{ matrix.config }}, ${{ matrix.suite }}, ${{ matrix.jdk }}) failed" - gh run cancel "${GITHUB_RUN_ID}" --repo "${GITHUB_REPOSITORY}" + run: .github/bin/cancel-merge-queue-workflow.sh "pt (${{ matrix.config }}, ${{ matrix.suite }}, ${{ matrix.jdk }})" build-success: if: ${{ always() }} # if `failure()` would not work for cancellations, `!success()` would not work for skipped jobs